home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 375.lha / MRARPFile_v1.1 / MRARPFile.c < prev    next >
C/C++ Source or Header  |  1990-05-02  |  17KB  |  572 lines

  1. /*  File support routines to complement ARP.
  2.  *  Author: Mark R. Rinfret
  3.  *          Usenet:     mrr@amanpt1.Newport.RI.US
  4.  *          BIX:        markr
  5.  *          CIS:        72017, 136 (good luck!)
  6.  *
  7.  *          348 Indian Avenue
  8.  *          Portsmouth, RI 02871
  9.  *          401-846-7639 (home)
  10.  *          401-849-9390 (work)       
  11.  *
  12.  *  This package was written primarily because of _one_ missing element
  13.  *  in ARP: FGets. ARGH! ARPFFFT! It extends ARP by adding buffering to
  14.  *  the basic file type (FileHandle) and defining a new type, named
  15.  *  ARPFileHandle (hope this is OK with the ARP guys). Also, I've used the
  16.  *  convention of embedding ARP (vs. Arp in MicroSmith's stuff) in all type
  17.  *  and function names to (hopefully) avoid naming collisions.
  18.  *
  19.  *  This package (as far as I am concerned) is public domain. Use it any
  20.  *  way you like. Some comments on the "MR" prefix: it isn't short for
  21.  *  "Mister", it comprises the initials of my first and last names.
  22.  *  I use it primarily to avoid name collisions with stuff by other
  23.  *  authors. If any other authors whose initials are "MR" start doing
  24.  *  this, we'll probably have to appeal to Electronic Arts to dole out
  25.  *  "author codes" along the lines of those issued for IFF :-). I hereby
  26.  *  stake a claim to 'MRR_'.
  27.  *
  28.  *  A word of warning:
  29.  *
  30.  *  DO NOT INTERMIX STANDARD AMIGADOS FILE SUPPORT CALLS WITH CALLS TO
  31.  *  THIS PACKAGE ON FILES USING THIS FILE METHOD!
  32.  *
  33.  *  Obviously, the system doesn't know about the buffering added here
  34.  *  and will cause unpredictable results if you mix calls to this package
  35.  *  with calls to Read/Write/Seek, etc. (unless, of course, you take care 
  36.  * to maintain the ARPFileHandle information).
  37.  */
  38.  
  39.  
  40. #if __STDC__
  41. #include <stdlib.h>
  42. #endif
  43.  
  44. #include "MRARPFile.h"
  45. #include <exec/memory.h>
  46. #include <string.h>
  47. #include <functions.h>
  48.  
  49. #ifndef min
  50. #define min(a,b) ((a) <= (b) ? (a) : (b))
  51. #define max(a,b) ((a) >= (b) ? (a) : (b))
  52. #endif
  53.  
  54. /* struct DefaultTracker *StoreTracker __PARMS( (void) ); */
  55.  
  56. static LONG FillARPFileBuffer __PARMS( (ARPFileHandle *file) );
  57. static LONG FlushARPFileBuffer __PARMS( (ARPFileHandle *file) );
  58.  
  59. /*  FUNCTION
  60.  *      FGetsARP - get string from a buffered ARP file.
  61.  *
  62.  *  SYNOPSIS
  63.  *      #include <MRARPFile.h>
  64.  *
  65.  *      char *FGetsARP(s, length, file)
  66.  *                     UBYTE         *s;
  67.  *                     LONG           length;
  68.  *                     ARPFileHandle *file;
  69.  *
  70.  *  DESCRIPTION
  71.  *      FGetsARP models the behavior of the "standard" fgets, except that
  72.  *      it is used with a buffered ARP file. The data is read from <file>
  73.  *      and transfered to string <s>. Up to length-1 characters will be
  74.  *      read. Reading is also terminated upon receipt of a newline
  75.  *      or detection of end-of-file. 
  76.  *
  77.  *      If the <file> was opened without a buffer, one of MaxInputBuf
  78.  *      bytes will be allocated.
  79.  *
  80.  *      If end of file or an error is detected, the return value will be
  81.  *      NULL. Otherwise, the return value will be <s>. <s> will be 
  82.  *      terminated with a null byte.
  83.  */
  84. char *
  85. FGetsARP(s, length, file)
  86.     char            *s;
  87.     LONG            length;
  88.     ARPFileHandle   *file;
  89. {
  90.     LONG    bytesNeeded = length - 1;
  91.     LONG    bytesRead = 0;
  92.     char    c;
  93.     char    *s1 = s;
  94.  
  95.     /* Set string initially empty to protect user from failure to check
  96.      * return value.
  97.      */
  98.     *s1 = '\0';    
  99.     if (file->mode != MODE_OLDFILE)
  100.         file->lastError = ERROR_READ_PROTECTED;
  101.          
  102.     if (file->lastError) {
  103. dangit:
  104.         return NULL;
  105.     }
  106.     if (! file->buf ) {                 /* Ohmigosh! No buffer? */
  107.         file->buf = ArpAlloc(MaxInputBuf);
  108.         if (! file->buf ) {
  109.             file->lastError = ERROR_NO_FREE_STORE;
  110.             goto dangit;
  111.         }
  112.         file->bufSize = MaxInputBuf;    /* bufLength, bufPos are zero. */
  113.     }
  114.     while (bytesNeeded) {
  115.         if (file->bufPos >= file->bufLength) {
  116.             if (FillARPFileBuffer(file) < 0) goto dangit;
  117.             if (file->bufLength == 0) break;
  118.         }
  119.         c = file->buf[file->bufPos++];
  120.         ++bytesRead;
  121.         if (c == '\n') break;
  122.         *s1++ = c;
  123.         --bytesNeeded; 
  124.     }
  125.     *s1 = '\0';
  126.     return (bytesRead ? s : NULL);
  127. }
  128.  
  129. /*  FUNCTION
  130.  *      FillARPFileBuffer - read data into ARPFile buffer.
  131.  *
  132.  *  SYNOPSIS
  133.  *      #include <MRARPFile.h>
  134.  *
  135.  *      static LONG FillARPFileBuffer(file)
  136.  *                                    ARPFileHandle *file;
  137.  *
  138.  *  DESCRIPTION
  139.  *      Attempt to fill the buffer associated with <file> by reading
  140.  *      data from the associated external file. The return value will
  141.  *      be one of the following:
  142.  *          >0  => number of bytes read
  143.  *           0  => end of file
  144.  *          -1  => a Bad Thing happened (error code in file->lastError) 
  145.  *
  146.  *      Note: this is a local routine and is thus declared as "static".
  147.  *      Please inform the author if this is a hardship.
  148.  */
  149. static LONG
  150. FillARPFileBuffer(file)
  151.     ARPFileHandle *file;
  152. {
  153.     /* Remember where we were. The user might want to try error
  154.      * recovery. Of course, this probably isn't enough info, but
  155.      * it's a start.
  156.      */
  157.     file->lastPosition = Seek(file->fh, 0L, OFFSET_CURRENT);
  158.     file->bufPos = 0;
  159.     file->bufLength = Read(file->fh, file->buf, file->bufSize);
  160.     if (file->bufLength == -1) {    /* We got trubble! */
  161.         file->lastError = IoErr();
  162.     }
  163.     else if (file->bufLength == 0) {
  164.         file->endOfFile = TRUE;
  165.     }
  166.     return file->bufLength;
  167.  
  168. /*  FUNCTION
  169.  *      FlushARPFileBuffer - write file buffer contents to disk.
  170.  *
  171.  *  SYNOPSIS
  172.  *      #include <MRARPFile.h>
  173.  *
  174.  *      static LONG FlushARPFileBuffer(ARPFileHandle *file);
  175.  *
  176.  *  DESCRIPTION
  177.  *      FlushARPFileBuffer writes the contents of <file>'s buffer
  178.  *      (if any) to disk and resets the buffer information. The
  179.  *      return value may be any of:
  180.  *
  181.  *          >0 =>   number of bytes written
  182.  *           0 =>   nothing in buffer
  183.  *          <0 =>   negated error code
  184.  *
  185.  *      Note: it is assumed that this function will only be used locally
  186.  *      and therefore need not be public. If you disagree, please contact
  187.  *      the author.
  188.  */
  189.  
  190. static LONG
  191. FlushARPFileBuffer(file)
  192.     ARPFileHandle *file;
  193. {
  194.     LONG    bytesWritten = 0;
  195.  
  196.     /* This operation is only allowed for output files. */
  197.  
  198.     if (file->mode != MODE_NEWFILE) {
  199.         file->lastError = ERROR_WRITE_PROTECTED;
  200. badstuff:
  201.         return -file->lastError;
  202.     }
  203.  
  204.     if (file->lastError) goto badstuff; /* Residual error? */
  205.  
  206.     if (file->bufLength) {
  207.         file->lastPosition = Seek(file->fh, 0L, OFFSET_CURRENT);
  208.         bytesWritten = Write(file->fh, (const char *) file->buf, file->bufLength);
  209.         if (bytesWritten != file->bufLength) {
  210.             file->lastError = IoErr();
  211.             goto badstuff;
  212.         }
  213.         else {
  214.             file->bufLength = 0;
  215.             file->bufPos = 0;
  216.         }
  217.     }
  218.     return bytesWritten;
  219. }
  220.  
  221. /*  FUNCTION
  222.  *      FPutsARP - write a string to a buffered ARP file.
  223.  *
  224.  *  SYNOPSIS
  225.  *      #include <MRARPFile.h>
  226.  *
  227.  *      LONG FPutsARP(s, file)
  228.  *                    char          *s;
  229.  *                    ARPFileHandle *file;
  230.  *
  231.  *  DESCRIPTION
  232.  *      FPutsARP writes the contents of string <s> to the specified <file>.
  233.  *      If successful, it returns 0. On failure, it returns the negated
  234.  *      system error code. 
  235.  */
  236. LONG
  237. FPutsARP(s, file)
  238.     char          *s;
  239.     ARPFileHandle *file;
  240. {
  241.     LONG    bytesLeft, bytesUsed;
  242.     char    *s1 = s;
  243.  
  244.     if (file->mode != MODE_NEWFILE) 
  245.         file->lastError = ERROR_WRITE_PROTECTED;
  246.  
  247.     if (file->lastError) {
  248. shucks:
  249.         return -file->lastError;
  250.     }
  251.  
  252.     bytesLeft = strlen(s);
  253.  
  254.     /* Attempt to be smart about this transfer. Copy the string to the
  255.      * buffer in chunks. There is a possibility that the string is bigger
  256.      * than the size of the buffer.
  257.      */
  258.     while (bytesLeft) {
  259.         if (file->bufPos >= file->bufSize) {
  260.             if (FlushARPFileBuffer(file) <= 0) goto shucks;
  261.         }
  262.         bytesUsed = min(file->bufSize - file->bufPos, bytesLeft);
  263.         CopyMem(s1, &file->buf[file->bufPos], bytesUsed);
  264.         s1 += bytesUsed;
  265.         file->bufLength = (file->bufPos += bytesUsed);
  266.         bytesLeft -= bytesUsed;
  267.     }
  268.     return 0;
  269. }
  270.  
  271. /*  FUNCTION
  272.  *      ReadARPFile - read from a buffered ARP file.
  273.  *
  274.  *  SYNOPSIS
  275.  *      #include <MRARPFile.h>
  276.  *
  277.  *      LONG ReadARPFile(ARPFileHandle *file, char *buffer, LONG length);
  278.  *
  279.  *  DESCRIPTION
  280.  *      ReadARPFile attempts to read <length> bytes from <file>, transferring
  281.  *      the data to <buffer>. 
  282.  *
  283.  *      The return value may be any of the following:
  284.  *
  285.  *          >0      number of bytes transferred
  286.  *          0       end of file
  287.  *         <0       negated error code
  288.  *
  289.  *      Note: if the lastError field of the <file> descriptor contains a
  290.  *            non-zero value, its negated value will be returned and no
  291.  *            attempt will be made to read the file. If you attempt error
  292.  *            recovery, you must clear this field to zero.
  293.  */
  294. LONG
  295. ReadARPFile(file, buffer, length)
  296.     ARPFileHandle   *file;
  297.     char            *buffer;
  298.     LONG            length;
  299. {
  300.     LONG            bytesLeft;
  301.     LONG            bytesRead = 0;
  302.     LONG            needBytes = length;
  303.     LONG            pos = 0;
  304.     LONG            usedBytes = 0;
  305.  
  306.     /* Prevent read if this file opened for writing. */
  307.  
  308.     if (file->mode != MODE_OLDFILE)
  309.         file->lastError = ERROR_READ_PROTECTED;
  310.  
  311.     if (file->lastError) {          /* Have residual error? */
  312. boofar:
  313.         return -file->lastError;
  314.     }
  315.  
  316.     if ( ! file->buf ) {            /* No buffer? */
  317.         bytesRead = Read(file->fh, buffer, length);
  318.         if (bytesRead == -1) {
  319.             file->lastError = IoErr();
  320.             goto boofar;
  321.         }
  322.     }
  323.     else while (needBytes) {
  324.         if (file->bufLength - file->bufPos <= 0) {
  325.             if (FillARPFileBuffer(file) == -1) goto boofar;
  326.             if (file->bufLength == 0) break;
  327.         }
  328.         bytesLeft = file->bufLength - file->bufPos;
  329.         usedBytes = min(bytesLeft, length);
  330.         CopyMem(&file->buf[file->bufPos], &buffer[pos], usedBytes);
  331.         file->bufPos += usedBytes;
  332.         pos += usedBytes;
  333.         bytesRead += usedBytes;
  334.         needBytes -= usedBytes;
  335.     }
  336.     return bytesRead;   
  337. }
  338.  
  339. /*  FUNCTION
  340.  *      CloseARPFile - close buffered ARP file.
  341.  *
  342.  *  SYNOPSIS
  343.  *      #include <MRARPFile.h>
  344.  *
  345.  *      LONG CloseARPFile(file)
  346.  *                        ARPFileHandle *file;
  347.  *
  348.  *  DESCRIPTION
  349.  *      CloseARPFile closes the file described by <file> which MUST have
  350.  *      been opened by OpenARPFile. It releases all tracked items
  351.  *      associated with <file>, as well.
  352.  *
  353.  *      The return value is only meaningful for output files. If, upon
  354.  *      flushing the buffer, a write error is detected, a system error
  355.  *      code (ERROR_DISK_FULL, etc.) will be returned.
  356.  */
  357.  
  358. LONG
  359. CloseARPFile(file)
  360.     ARPFileHandle *file;
  361. {
  362.     LONG        result = 0;
  363.  
  364.     if (file) {                     /* Just in case... */
  365.         if (file->fileTracker) {
  366.             /* Any left-over stuff in the buffer? If so, we must flush
  367.              * it to disk. However, if an error was detected in the
  368.              * previous operation, punt. 
  369.              */
  370.             if ( ( file->mode == MODE_NEWFILE) && 
  371.                    ! file->lastError &&
  372.                    file->bufLength) {
  373.                 if (Write(file->fh, (const char *) file->buf, file->bufLength) !=
  374.                     file->bufLength)
  375.                     result = IoErr();
  376.             }
  377.             FreeTrackedItem(file->fileTracker);
  378.         }
  379.  
  380.         FreeTrackedItem((struct DefaultTracker *) file->buf);
  381.         FreeTrackedItem((struct DefaultTracker *) file);
  382.     }
  383.     return result;
  384. }
  385.  
  386. /*  FUNCTION
  387.  *      OpenARPFile - open a buffered ARP file
  388.  *
  389.  *  SYNOPSIS
  390.  *      #include <MRARPFile.h>
  391.  *
  392.  *      struct MRARPFile *OpenARPFile(name, accessMode, bytes)
  393.  *                                    char *name;
  394.  *                                    LONG accessMode, bytes;
  395.  *
  396.  *  DESCRIPTION
  397.  *      OpenARPFile opens the file <name>, with the given <accessMode>
  398.  *      (MODE_OLDFILE, MODE_NEWFILE only!) for buffered access. The
  399.  *      size of the local buffer is specified by <bytes>.
  400.  *
  401.  *      A zero value for <bytes> is OK and is sometimes appropriate, as
  402.  *      when performing file copy operations, etc. However, if a file
  403.  *      opened with a zero length buffer is then passed to the
  404.  *      FGetsARP function, "spontaneous buffer allocation" will occur.
  405.  *      No biggy, really, just something you should know. The ARP constant,
  406.  *      MaxInputBuf will be used for the buffer size, in this case.
  407.  *
  408.  *      If successful, a pointer to the file tracking structure is 
  409.  *      returned. Otherwise, the return value will be NULL.
  410.  *
  411.  *      OpenARPFile uses full resource tracking for all information
  412.  *      associated with the file.
  413.  *
  414.  */
  415.  
  416. ARPFileHandle *
  417. OpenARPFile(name, accessMode, bytes)
  418.     char *name;
  419.     LONG accessMode, bytes;
  420. {
  421.     BPTR                  fh;
  422.     ARPFileHandle         *theFile = NULL;
  423.     struct DefaultTracker *lastTracker;
  424.  
  425.     /* This package does not support READ/WRITE access! */
  426.  
  427.     if ( (accessMode != MODE_OLDFILE) && (accessMode != MODE_NEWFILE))
  428.         return NULL;
  429.  
  430.     theFile = ArpAlloc((LONG) sizeof(ARPFileHandle));
  431.     if (theFile) {
  432.         theFile->mode = accessMode;
  433.         fh = ArpOpen(name, accessMode);
  434.         lastTracker = LastTracker;
  435.         if (!fh) {
  436. fungu:
  437.             CloseARPFile(theFile);  /* Don't worry - it's "smart". */
  438.             theFile = NULL;
  439.         }
  440.         theFile->fileTracker = lastTracker;
  441.         theFile->fh = fh;
  442.         if ( bytes) {               /* Does user want a buffer? */
  443.             theFile->buf = ArpAlloc(bytes);
  444.             if (!theFile->buf) goto fungu;
  445.             theFile->bufSize = bytes;
  446.         }
  447.     }
  448.     return theFile;  
  449. }
  450.  
  451. /*  FUNCTION
  452.  *      SeekARPFile - move to new logical position in file.
  453.  *
  454.  *  SYNOPSIS
  455.  *      #include <MRARPFile.h>
  456.  *
  457.  *      LONG SeekARPFile(file, position, mode)
  458.  *                       ARPFileHandle *file;
  459.  *                       LONG           position;
  460.  *                       LONG           mode;
  461.  *
  462.  *  DESCRIPTION
  463.  *      SeekARPFile attempts to position the <file> to a new logical
  464.  *      position or report it's current position. The <position>
  465.  *      parameter represets a signed offset. The <mode> parameter may
  466.  *      be one of:
  467.  *
  468.  *          OFFSET_BEGINNING (-1) => from beginning of file
  469.  *          OFFSET_CURRENT (0)    => from current position
  470.  *          OFFSET_END (-1)       => from end of file
  471.  *
  472.  *      On output files, the current buffer contents, if any, are
  473.  *      written to disk.
  474.  *
  475.  *      The return value will either be a positive displacement >=0) or
  476.  *      a negated system error code.
  477.  */
  478. LONG
  479. SeekARPFile(file, position, mode)
  480.             ARPFileHandle *file;
  481.             LONG           position;
  482.             LONG           mode;
  483. {
  484.     LONG    newPosition;
  485.  
  486.     if (file->mode == MODE_NEWFILE && file->bufLength) {
  487.         if (FlushARPFileBuffer(file) < 0) {
  488. farboo:
  489.             return -file->lastError;
  490.         }
  491.     }
  492.     /* Remember our last position. */
  493.     file->lastPosition = Seek(file->fh, 0L, OFFSET_CURRENT);
  494.     if ((newPosition = Seek(file->fh, position, mode)) == -1) {
  495.         file->lastError = IoErr();
  496.         goto farboo;
  497.     }
  498.     return newPosition;
  499. }  
  500.  
  501. /*  FUNCTION
  502.  *      WriteARPFile - write data to a buffered ARP file.
  503.  *
  504.  *  SYNOPSIS
  505.  *      #include <MRARPFile.h>
  506.  *
  507.  *      LONG WriteARPFile(ARPFileHandle *file, const char *buffer, LONG length);
  508.  *
  509.  *  DESCRIPTION
  510.  *      WriteARPFile attempts to write <length> bytes from <buffer> to
  511.  *      the buffered ARP file, <file>. The file MUST have been opened
  512.  *      with OpenARPFile for MODE_NEWFILE access.
  513.  *
  514.  *      WriteARPFile will not write to a file if the lastError field is
  515.  *      non-zero, or if the file was opened for input.
  516.  *
  517.  *      If successful, WriteARPFile will return the <length> parameter.
  518.  *      Otherwise, it will return a negated system error code.
  519.  */
  520. LONG
  521. WriteARPFile(file, buffer, length)
  522.     ARPFileHandle   *file;
  523.     const char      *buffer;
  524.     LONG            length;
  525. {
  526.     LONG    bufferBytes;
  527.     LONG    bytesLeft = length;
  528.     LONG    pos = 0;
  529.     LONG    usedBytes = 0;
  530.  
  531.     if (file->mode != MODE_NEWFILE)
  532.         file->lastError = ERROR_WRITE_PROTECTED;
  533.  
  534.     if (file->lastError) {           /* Catches mode and residual errors. */
  535. sumbidge:
  536.         return -(file->lastError);
  537.     }
  538.  
  539.     if ( ! file->buf ) {             /* No buffer? */
  540.         if (Write(file->fh, buffer, length) != length) {
  541.             file->lastError = IoErr();
  542.             goto sumbidge;
  543.         }
  544.     }
  545.     else while (bytesLeft) {
  546.         /* Need to flush the file's buffer? */
  547.         if (file->bufPos >= file->bufSize) {
  548.             if (FlushARPFileBuffer(file) < 0) {
  549.                 goto sumbidge;
  550.             }
  551.         }
  552.         bufferBytes = file->bufSize - file->bufPos;
  553.         usedBytes = min(bufferBytes, bytesLeft);
  554.         CopyMem(&buffer[pos], &file->buf[file->bufPos], usedBytes);
  555.         file->bufLength = (file->bufPos += usedBytes);
  556.         pos += usedBytes;
  557.         bytesLeft -= usedBytes;
  558.     }
  559.     return length;
  560. }
  561.  
  562. /*  Embedded documentation template (cut & paste): */
  563.  
  564. /*  FUNCTION
  565.  *
  566.  *  SYNOPSIS
  567.  *
  568.  *  DESCRIPTION
  569.  *
  570.  */
  571.