Corso di AmigaOS

Torna all'elenco delle lezioniPer dubbi, consigli o richieste, potete mandare un'e-mail ad Andrea Carolfi.
Ringraziamo Amiga Transactor Mailing List per questo tangibile contributo!


Le Procedure (Settima lezione)

Eccoci dunque arrivati a trattare le procedure/funzioni che interagiscono con il file system, ovvero che ci permetto nella fattispecie di creare/scrivere/leggere/cancellare un file.
Bisogna ricordare, che il tipo del puntatore alla struttura che descrive un file, sotto AmigaDOS è un BPTR (e non come potrebbe pensare qualcuno FILE *), ovvero una longword.
Perchè essendo un tempo programmato in BCPL, tutti i puntatori dovevano essere lw.
Vediamo dunque le procedure/funzioni che vedremo in questa puntata:

  • 1. BPTR Open( STRPTR name, long accessMode );
  • 2. LONG Close( BPTR file );
  • 3. LONG Read( BPTR file, APTR buffer, long length );
  • 4. LONG Write( BPTR file, APTR buffer, long length );
  • 5. BPTR Input( void );
  • 6. BPTR Output( void );
  • 7. LONG Seek( BPTR file, long position, long offset );
  • 8. LONG DeleteFile( STRPTR name );
  • 9. LONG Rename( STRPTR oldName, STRPTR newName );
  • 10. BPTR Lock( STRPTR name, long type );
  • 11. void UnLock( BPTR lock );
  • 12. BPTR DupLock( BPTR lock );
  • 13. LONG Info( BPTR lock, struct InfoData *parameterBlock );
  • 14. BPTR CreateDir( STRPTR name );
  • 15. BPTR CurrentDir( BPTR lock );
  • 16. LONG IoErr( void );
  • 17. BPTR ParentDir( BPTR lock );
-- Buffered File IO --
  • 1. BPTR SelectInput( BPTR fh );
  • 2. BPTR SelectOutput( BPTR fh );
  • 3. LONG FGetC( BPTR fh );
  • 4. LONG FPutC( BPTR fh, long ch );
  • 5. LONG FRead( BPTR fh, APTR block, unsigned long blocklen,
  • 6. unsigned long number );
  • 7. LONG FWrite( BPTR fh, APTR block, unsigned long blocklen,
  • 8. unsigned long number );
  • 9. STRPTR FGets( BPTR fh, STRPTR buf, unsigned long buflen );
  • 10. LONG FPuts( BPTR fh, STRPTR str );
  • 11. LONG Flush( BPTR fh );

Il primo blocco, sono funzioni non bufferizzate, il secondo blocco, sono funzioni bufferizzate.
Vediamole con ordine. Prima di tutto la Open, che ovviamente richiede il nome del file da aprire e la modalità di accesso. Notare che un file, una volta aperto può indifferentemente letto o scritto a piacimento. Le varie modalità sono:

  • MODE_OLDFILE Apre un file esistente posizionandosi all'inizio
  • MODE_NEWFILE Crea un file (cancellando quello vecchio) con lock esclusivo
  • MODE_READWRITE Apre un file esistente con un lock condiviso. Crea il file se non esiste.

Una volta aperto un file, possiamo leggerlo con la Read, scriverlo con la Write e chiuderlo con la Close. Possiamo anche utilizzare le procedure bufferizzate, a seconda dei nostri scopi.
Vediamo uno stralcio di programma:

#include 
#include 
#include 
#include 
#include 
struct DosLibrary *DOSBase;
void main(void)
{
    BPTR file;
    struct Mia
    {
        int ver;
        char data[6];
    }mia;

    if((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",0)))
    {
        if((file = Open("RAM:temp",MODE_NEWFILE)))
        {
            mia.uno = 56;
            strcpy(mia.due,"290798");
            if(Write(file,&mia,sizeof(struct Mia) == -1)
                PrintFault(IoErr(),"Impossibile scrivere sul file RAM:temp
perchè");

            Delay(50);

            if(Read(file,&mia,sizeof(struct Mia) == -1)
                PrintFault(IoErr(),"Impossibile leggere dal file RAM:temp
perchè");
            else
            {
                LONG param[2];
                param[0] = (LONG)mia.ver;
                param[1] = (long)mia.data;
                VPrintf("Ho letto %ld e %s\n",param);
            }
            /* Se la versione e >= 36 possiamo controllare anche il valore di
*/
            /* ritorno della Close */
            if(DOSBase -> dl_lib.lib_Version >= 36)
            {
                if(!Close(file))
                    PrintFault(IoErr(),"Impossibile chiudere il file RAM:temp
perchè");
            }
            else
                Close(file);
        }
        else
        {
            PrintFault(IoErr(),"Impossibile aprire il file RAM:temp perchè");
        }
        CloseLibrary(struct Library *)DOSBase);
    }
}

Se invece della Read e della Write, avessi usato la FRead e la FWrite, avrei ottenuto una versione bufferizzata del programma. Non ci vuole molto a cambiare la struttura del programma, per usare le varie funzioni di lettura/scrittura al posto di Read e Write.
Per esempio per scrivere/leggere una stringa, può essere comodo usare FPuts/FGets.
Una nota merita la funzione Flush, che un pò come il comando 'sync' di unix forza la scrittura dei buffer accodati.

La funzione Seek, è molto utile con i file di record, per saltare ad un determinato record ed eseguire quindi un accesso non sequenziale al file.
Per esempio, se il nostro file RAM:temp, contenesse dieci strutture di tipo Mia, per leggere la 5 basterebbe:


    [...]

    Seek(file,sizeof(struct Mia) * 4,OFFSET_BEGINNING);
Ovviamente, 4 e non 5 perchè con il valore zero si torna all'inizio del file.
Il terzo parametro può assumere i seguenti valori (come la fseek di unix):

  • OFFSET_BEGINNING spiazzamento relativo all'inizio del file
  • OFFSET_CURRENT spiazzamento relativo alla posizione attuale
  • OFFSET_END spiazzamento relativo alla fine del file

In questo modo possiamo saltare al terz'ultimo record di un file, oppure saltare ai prossimi cinque record, ai tre precedenti o altro, specificando anche valori negativi (che fanno tornare indietro il puntatore alla posizione).
Inutile dire che questi spiazzamenti devo essere fatti tutti all'interno del file, altrimenti non funzioneranno e saremo piazzati o all'inizio o alla fine del file.

Le funzioni Input, Output, SelectInput e SelectOutput, servono le prime due per ricevere il puntatore al file di standard input e standard output e le seconde due per impostarli su file di nostro interesse. Per esempio, se nel nostro programma, avessimo chiamato:


    [...]

    BPTR old_fh;

    [...]

    old_fh = SelectOutput(file);

    [...]

    SelectOutput(old_fh);

    [...]

avremmo rediretto l'output del nostro programma sul file RAM:temp. Una cosa del genere, può essere utile per creare file di log, per esempio.

Le funzioni DeleteFile e Rename servono per cancellare un file od una directory (a patto che sia vuota) e per rinominare un file od una directory.

Le funzioni Lock e la sua corrispettiva UnLock, servono per bloccare e sbloccare l'accesso ad altri processi ad un file che stiamo manipolando. Le modalità accettate dalla Lock sono:

  • ACCESS_READ crea un lock condiviso (altri processi possono leggere)
  • ACCESS_WRITE crea un lock esclusivo (nessun processo può accedere)

La funzione DupLock, serve per ottenere una copia di un lock (solo quelli condivisi). Può essere utile in un sistema di produttori/consumatori.

La funzione Info, molto semplicemente restituisce una struttura

/* returned by Info(), must be on a 4 byte boundary */
struct InfoData {
    LONG    id_NumSoftErrors;  /* number of soft errors on disk */
    LONG    id_UnitNumber;  /* Which unit disk is (was) mounted on */
    LONG    id_DiskState;      /* See defines below */
    LONG    id_NumBlocks;      /* Number of blocks on disk */
    LONG    id_NumBlocksUsed;  /* Number of block in use */
    LONG    id_BytesPerBlock;
    LONG    id_DiskType;    /* Disk Type code */
    BPTR    id_VolumeNode;  /* BCPL pointer to volume node */
    LONG    id_InUse;    /* Flag, zero if not in use */
}; /* InfoData */
riempita con i valori del dispositivo che contiene il file passatole (il BPTR).

La funzione CreateDir serve per creare un cassetto. Le funzioni CurrentDir e ParentDir, servono per ottenere la directory contenente il lock passato o il cassetto genitore.

Bene, nell'ottava puntata vedremo altre procedure della dos.library e nella nona, cominceremo a vedere intuition. Ovviamente, se avete qualcosa da chiedermi, sono a vostra disposizione.

Lezione precedente Indice delle lezioni Lezione successiva
Copyright AMiWoRLD Ph0ton