home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Snippets / File Access Examples 1.0 / FileRoutines.c < prev    next >
Encoding:
Text File  |  1994-10-25  |  11.6 KB  |  413 lines  |  [TEXT/KAHL]

  1. /* File Access Functions
  2.  *
  3.  * A collection of routines that should make it a bit easier to access
  4.  * Macintosh files AFTER they're open.
  5.  *
  6.  * This code is Copyright 1994 by Ken Worley. All Rights Reserved.
  7.  *
  8.  * You may use this code for any purpose you like and you do not
  9.  * need to credit me in any way. However, if you redistribute
  10.  * this source code, I must be identified as the author.
  11.  * If you modify the routines and redistribute the code, it
  12.  * must be identified as having been modified from my original.
  13.  *
  14.  * In general, the routines in this file make it easier to access
  15.  * byte, short int, and long int sized data (as well as larger data
  16.  * blocks) by simply specifying a record number. The data can be
  17.  * read or written just as easily in simple sequential order using
  18.  * the same routines. The routines are more efficient than the
  19.  * Toolbox high level routines because they use static parameter
  20.  * blocks and low level routines for file access, but they retain
  21.  * a very simple interface.
  22.  *
  23.  * By the way, I'm Ken Worley of Apt Ideas Software. I can be reached
  24.  * on America Online or eWorld at KNEworley or via the internet at
  25.  * KNEworley@eworld.com.
  26.  *
  27.  * The routines in this file view files as collections of numbered
  28.  * records that are all the same size with the first record being
  29.  * record number zero just like in a C array. Access is accomplished
  30.  * by specifying a file reference number (of an open file), a record
  31.  * number, and a pointer to the data to be written or storage for
  32.  * data to be read. Most of the functions are Boolean indicating
  33.  * whether or not they were successful. If you're interested in the
  34.  * specific error when a function fails, you can call LastFileError
  35.  * to retrieve it.
  36.  *
  37.  * Now, to the specifics of the routines provided in this file:
  38.  *
  39.  * Here's an important define used in the routines:
  40.  *
  41.  *        #define kSequential    -1        Used to indicate that a read or
  42.  *                                    write operation should be done
  43.  *                                    at the current file position
  44.  *                                    when passed as the record #.
  45.  *
  46.  * Here are the routines contained in this file along with explanations
  47.  * as to their functions:
  48.  *
  49.  *        Boolean ReadByte( short fileRef, long recordNo, char* buffer );
  50.  *                            Reads a byte sized record
  51.  *
  52.  *        Boolean WriteByte( short fileRef, long recordNo, char buffer );
  53.  *                            Writes a byte sized record
  54.  *
  55.  *        Boolean ReadShort( short fileRef, long recordNo, short* buffer );
  56.  *                            Reads a short int sized record (2 bytes)
  57.  *
  58.  *        Boolean WriteShort( short fileRef, long recordNo, short buffer );
  59.  *                            Writes a short int sized record (2 bytes)
  60.  *
  61.  *        Boolean ReadLong( short fileRef, long recordNo, long* buffer );
  62.  *                            Reads a long int sized record (4 bytes)
  63.  *
  64.  *        Boolean WriteLong( short fileRef, long recordNo, long buffer );
  65.  *                            Writes a long int sized record (4 bytes)
  66.  *
  67.  *
  68.  *        Boolean ReadRecord( short fileRef, long recordNo, void* buffer );
  69.  *                            Reads a record that is whatever size
  70.  *                            the storage allocated for the data is.
  71.  *
  72.  *        Boolean WriteRecord( short fileRef, long recordNo, void* buffer );
  73.  *                            Writes a record whatever size it is.
  74.  *
  75.  *
  76.  *        Boolean ReadBlock( short fileRef, long filePos,
  77.  *                                long bytesRequested, void* buffer );
  78.  *                            Called by the other routines - the low
  79.  *                            level interface to the toolbox routines
  80.  *                            for reading from the file.
  81.  *
  82.  *        Boolean WriteBlock( short fileRef, long filePos,
  83.  *                                long bytesRequested, void* buffer );
  84.  *                            Called by the other routines - the low
  85.  *                            level interface to the toolbox routines
  86.  *                            for writing to the file.
  87.  *
  88.  *        long    RemainingSpace( short vRefNum );
  89.  *                            Returns the number of bytes free on
  90.  *                            the volume specified.
  91.  *
  92.  *
  93.  *        long    RecordsInFile( short refNum, short recordSize );
  94.  *                            Returns the current number of records
  95.  *                            in the file based on the file size and
  96.  *                            record size.
  97.  *
  98.  *
  99.  *        long    GetCurrentRecord( short refNum, short recordSize );
  100.  *                            Returns the record number that would be
  101.  *                            read or written if kSequential were
  102.  *                            sent as the record number in the next
  103.  *                            call to one of the file access routines.
  104.  *
  105.  *        Boolean    SetCurrentRecord( short refNum, long recordNo,
  106.  *                                                short recordSize );
  107.  *                            Sets the file mark so that the specified
  108.  *                            record would be read or written
  109.  *                            if kSequential were sent as the record
  110.  *                            number in the next call to one of the
  111.  *                            file access routines.
  112.  *
  113.  *
  114.  *        short    LastFileError( void );
  115.  *                            Get the error number of the last
  116.  *                            function call.
  117.  */
  118.  
  119. #include "FileRoutines.h"
  120.  
  121. static ParamBlockRec    PB;        /* This is the parameter block */
  122.                                 /* used to pass info back and */
  123.                                 /* forth to/from the low level */
  124.                                 /* toolbox routines. */
  125.     
  126. static short             gFileError;    /* This global holds the error */
  127.                                     /* number of the last call. */
  128.  
  129. Boolean ReadByte( short fileRef, long recordNo, char* buffer )
  130. {
  131.     return ReadBlock( fileRef, recordNo, 1, buffer );
  132. }
  133.  
  134.  
  135. Boolean WriteByte( short fileRef, long recordNo, char buffer )
  136. {
  137.     char value;
  138.     
  139.     value = buffer;
  140.     return WriteBlock( fileRef, recordNo, 1, &value );
  141. }
  142.  
  143.  
  144.  
  145. Boolean ReadShort( short fileRef, long recordNo, short* buffer )
  146. {
  147.     long    filePos;
  148.     
  149.     if ( recordNo == kSequential )
  150.         filePos = kSequential;
  151.     else
  152.         filePos = ( 2 * recordNo );
  153.     
  154.     return ReadBlock( fileRef, filePos, 2, buffer );
  155. }
  156.  
  157.  
  158. Boolean WriteShort( short fileRef, long recordNo, short buffer )
  159. {
  160.     long    filePos;
  161.     short    value;
  162.     
  163.     value = buffer;
  164.     
  165.     if ( recordNo == kSequential )
  166.         filePos = kSequential;
  167.     else
  168.         filePos = ( 2 * recordNo );
  169.     
  170.     return WriteBlock( fileRef, filePos, 2, &value );
  171. }
  172.  
  173.  
  174.  
  175. Boolean ReadLong( short fileRef, long recordNo, long* buffer )
  176. {
  177.     long    filePos;
  178.     
  179.     if ( recordNo == kSequential )
  180.         filePos = kSequential;
  181.     else
  182.         filePos = ( 4 * recordNo );
  183.     
  184.     return ReadBlock( fileRef, filePos, 4, buffer );
  185. }
  186.  
  187.  
  188. Boolean WriteLong( short fileRef, long recordNo, long buffer )
  189. {
  190.     long    filePos;
  191.     long    value;
  192.     
  193.     value = buffer;
  194.     
  195.     if ( recordNo == kSequential )
  196.         filePos = kSequential;
  197.     else
  198.         filePos = ( 4 * recordNo );
  199.     
  200.     return WriteBlock( fileRef, filePos, 4, &value );
  201. }
  202.  
  203.  
  204.  
  205. Boolean ReadRecord( short fileRef, long recordNo, void* buffer )
  206. {
  207.     long    filePos;
  208.     long    bytes;
  209.     
  210.     bytes = GetPtrSize( buffer );
  211.     
  212.     if ( recordNo == kSequential )
  213.         filePos = kSequential;
  214.     else
  215.         filePos = ( bytes * recordNo );
  216.  
  217.     return ReadBlock( fileRef, filePos, bytes, buffer );
  218. }
  219.  
  220.  
  221. Boolean WriteRecord( short fileRef, long recordNo, void* buffer )
  222. {
  223.     long    filePos;
  224.     long    bytes;
  225.     
  226.     bytes = GetPtrSize( buffer );
  227.     
  228.     if ( recordNo == kSequential )
  229.         filePos = kSequential;
  230.     else
  231.         filePos = ( bytes * recordNo );
  232.  
  233.     return WriteBlock( fileRef, filePos, bytes, buffer );
  234. }
  235.  
  236.  
  237.  
  238. Boolean ReadBlock( short fileRef, long filePos, long bytesRequested,
  239.                                                         void* buffer )
  240. {
  241. /* This routine sets up an i/o parameter block and calls PBRead      */
  242. /* to read in the specified amount of data at the specified position */
  243. /* in the file. If filePos is kSequential, then the data is read     */
  244. /* at the file's current mark position. After the read operation,    */
  245. /* PBRead leaves the file's mark at the end of the data read.        */
  246.  
  247.     /* Prepare the parameter block for the read function call */
  248.     
  249.     PB.ioParam.ioCompletion = NULL;        /* no completion routine */
  250.     PB.ioParam.ioRefNum = fileRef;        /* file reference number */
  251.     PB.ioParam.ioBuffer = (Ptr)buffer;    /* data storage */
  252.     PB.ioParam.ioReqCount = bytesRequested;
  253.                                         /* bytes we reqested read */
  254.     if ( filePos == kSequential )
  255.     {
  256.         PB.ioParam.ioPosMode = fsAtMark;    /* read at current mark */
  257.         PB.ioParam.ioPosOffset = 0;            /* not used in this case */
  258.     }
  259.     else
  260.     {
  261.         PB.ioParam.ioPosMode = fsFromStart;    /* read at offset from bof */
  262.         PB.ioParam.ioPosOffset = filePos;    /* where in file to read */
  263.     }
  264.     
  265.     /* Now call PBRead to read the data in */
  266.     
  267.     PBRead( &PB, false );            /* false is to force */
  268.                                     /* synchronous operation */
  269.     
  270.     gFileError = PB.ioParam.ioResult;    /* store error code in global */
  271.     
  272.     if ( PB.ioParam.ioResult == noErr )
  273.         return true;
  274.     else
  275.         return false;
  276. }
  277.  
  278.  
  279. Boolean WriteBlock( short fileRef, long filePos, long bytesRequested,
  280.                                                         void* buffer )
  281. {
  282. /* This routine sets up an i/o parameter block and calls PBWrite    */
  283. /* to write the specified amount of data to the specified position  */
  284. /* in the file. If filePos is kSequential, then the data is written */
  285. /* at the file's current mark position. After the write operation,  */
  286. /* PBWrite leaves the file's mark at the end of the data written.   */
  287.  
  288.     /* Prepare the parameter block for the write function call */
  289.     
  290.     PB.ioParam.ioCompletion = NULL;        /* no completion routine */
  291.     PB.ioParam.ioRefNum = fileRef;        /* file reference number */
  292.     PB.ioParam.ioBuffer = (Ptr)buffer;    /* data storage */
  293.     PB.ioParam.ioReqCount = bytesRequested;
  294.                                         /* bytes we reqested written */
  295.     if ( filePos == kSequential )
  296.     {
  297.         PB.ioParam.ioPosMode = fsAtMark;    /* write at current mark */
  298.         PB.ioParam.ioPosOffset = 0;            /* not used in this case */
  299.     }
  300.     else
  301.     {
  302.         PB.ioParam.ioPosMode = fsFromStart;    /* write at offset from bof */
  303.         PB.ioParam.ioPosOffset = filePos;    /* where in file to write */
  304.     }
  305.     
  306.     /* Now call PBWrite to write the data out to the file */
  307.     
  308.     PBWrite( &PB, false );            /* false is to force */
  309.                                     /* synchronous operation */
  310.     
  311.     gFileError = PB.ioParam.ioResult;    /* store error code in global */
  312.     
  313.     if ( PB.ioParam.ioResult == noErr )
  314.         return true;
  315.     else
  316.         return false;
  317. }
  318.  
  319.  
  320. long    RemainingSpace( short vRefNum )
  321. {
  322. /* Returns the amount of space remaining on the volume specified */
  323.  
  324.     HParamBlockRec    pb;
  325.     
  326.     pb.volumeParam.ioCompletion = NULL;    /* no completion routine */
  327.     pb.volumeParam.ioNamePtr = NULL;    /* not using this now */
  328.     pb.volumeParam.ioVRefNum = vRefNum;    /* volume reference # */
  329.     pb.volumeParam.ioVolIndex = 0;        /* use ioVRefNum */
  330.     
  331.     PBHGetVInfo( &pb, false );    /* false forces synch operation */
  332.     
  333.     gFileError = pb.volumeParam.ioResult;
  334.     
  335.     if ( gFileError == noErr )
  336.         return (pb.volumeParam.ioVAlBlkSiz *
  337.                                 pb.volumeParam.ioVFrBlk);
  338.     else
  339.         return -1L;
  340. }
  341.  
  342.  
  343. long    RecordsInFile( short refNum, short recordSize )
  344. {
  345.     long    logicalEOF;
  346.     
  347.     PB.ioParam.ioCompletion = NULL;        /* no completion routine */
  348.     PB.ioParam.ioRefNum = refNum;        /* file reference # */
  349.     
  350.     PBGetEOF( &PB, false );        /* false forces synchronous call */
  351.     
  352.     gFileError = PB.ioParam.ioResult;
  353.     
  354.     if ( gFileError == noErr )
  355.     {
  356.         logicalEOF = (long)PB.ioParam.ioMisc;
  357.         return (logicalEOF / recordSize);
  358.     }
  359.     else
  360.         return -1L;
  361. }
  362.  
  363.  
  364. long    GetCurrentRecord( short refNum, short recordSize )
  365. {
  366.     PB.ioParam.ioCompletion = NULL;        /* no completion routine */
  367.     PB.ioParam.ioRefNum = refNum;        /* file reference # */
  368.     
  369.     PBGetFPos( &PB, false );    /* false forces synchronous call */
  370.     
  371.     gFileError = PB.ioParam.ioResult;
  372.     
  373.     if ( gFileError == noErr )
  374.         return (PB.ioParam.ioPosOffset / recordSize);
  375.     else
  376.         return -1L;
  377. }
  378.  
  379.  
  380. Boolean    SetCurrentRecord( short refNum, long recordNo,
  381.                                             short recordSize )
  382. {
  383.     /* NOTE - If you specify a record beyond the end of the file, */
  384.     /* this routine will return false and the file mark will be   */
  385.     /* set to the logical end of file. If you specify the record  */
  386.     /* that is just past the end of file, no error is returned.   */
  387.     /* At that point, writing a record sequentially would extend  */
  388.     /* the file, but attempting to read a record would return an  */
  389.     /* error. */
  390.     
  391.     PB.ioParam.ioCompletion = NULL;        /* no completion routine */
  392.     PB.ioParam.ioRefNum = refNum;        /* file reference # */
  393.     PB.ioParam.ioPosMode = fsFromStart;    /* offset from beg of file */
  394.     PB.ioParam.ioPosOffset =
  395.         ( recordSize * recordNo );        /* where to put the file mark */
  396.     
  397.     PBSetFPos( &PB, false );    /* false forces synchronous call */
  398.     
  399.     gFileError = PB.ioParam.ioResult;
  400.     
  401.     if ( gFileError == noErr )
  402.         return true;
  403.     else
  404.         return false;
  405. }
  406.  
  407.  
  408. short    LastFileError( void )
  409. {
  410.     return gFileError;
  411. }
  412.  
  413.