[comp.sources.amiga] v90i175: MRARPFile 1.1 - routines to enhance ARP file-handling, Part02/02

Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (06/04/90)

Submitted-by: mrr@amanpt1.Newport.RI.US (Mark Rinfret)
Posting-number: Volume 90, Issue 175
Archive-name: examples/mrarpfile-1.1/part02

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  MRARPFile.c
# Wrapped by tadguy@xanth on Sun Jun  3 19:29:31 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MRARPFile.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MRARPFile.c'\"
else
echo shar: Extracting \"'MRARPFile.c'\" \(17486 characters\)
sed "s/^X//" >'MRARPFile.c' <<'END_OF_FILE'
X/*  File support routines to complement ARP.
X *  Author: Mark R. Rinfret
X *          Usenet:     mrr@amanpt1.Newport.RI.US
X *          BIX:        markr
X *          CIS:        72017, 136 (good luck!)
X *
X *          348 Indian Avenue
X *          Portsmouth, RI 02871
X *          401-846-7639 (home)
X *          401-849-9390 (work)       
X *
X *  This package was written primarily because of _one_ missing element
X *  in ARP: FGets. ARGH! ARPFFFT! It extends ARP by adding buffering to
X *  the basic file type (FileHandle) and defining a new type, named
X *  ARPFileHandle (hope this is OK with the ARP guys). Also, I've used the
X *  convention of embedding ARP (vs. Arp in MicroSmith's stuff) in all type
X *  and function names to (hopefully) avoid naming collisions.
X *
X *  This package (as far as I am concerned) is public domain. Use it any
X *  way you like. Some comments on the "MR" prefix: it isn't short for
X *  "Mister", it comprises the initials of my first and last names.
X *  I use it primarily to avoid name collisions with stuff by other
X *  authors. If any other authors whose initials are "MR" start doing
X *  this, we'll probably have to appeal to Electronic Arts to dole out
X *  "author codes" along the lines of those issued for IFF :-). I hereby
X *  stake a claim to 'MRR_'.
X *
X *  A word of warning:
X *
X *  DO NOT INTERMIX STANDARD AMIGADOS FILE SUPPORT CALLS WITH CALLS TO
X *  THIS PACKAGE ON FILES USING THIS FILE METHOD!
X *
X *  Obviously, the system doesn't know about the buffering added here
X *  and will cause unpredictable results if you mix calls to this package
X *  with calls to Read/Write/Seek, etc. (unless, of course, you take care 
X * to maintain the ARPFileHandle information).
X */
X
X
X#if __STDC__
X#include <stdlib.h>
X#endif
X
X#include "MRARPFile.h"
X#include <exec/memory.h>
X#include <string.h>
X#include <functions.h>
X
X#ifndef min
X#define min(a,b) ((a) <= (b) ? (a) : (b))
X#define max(a,b) ((a) >= (b) ? (a) : (b))
X#endif
X
X/* struct DefaultTracker *StoreTracker __PARMS( (void) ); */
X
Xstatic LONG FillARPFileBuffer __PARMS( (ARPFileHandle *file) );
Xstatic LONG FlushARPFileBuffer __PARMS( (ARPFileHandle *file) );
X
X/*  FUNCTION
X *      FGetsARP - get string from a buffered ARP file.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      char *FGetsARP(s, length, file)
X *                     UBYTE         *s;
X *                     LONG           length;
X *                     ARPFileHandle *file;
X *
X *  DESCRIPTION
X *      FGetsARP models the behavior of the "standard" fgets, except that
X *      it is used with a buffered ARP file. The data is read from <file>
X *      and transfered to string <s>. Up to length-1 characters will be
X *      read. Reading is also terminated upon receipt of a newline
X *      or detection of end-of-file. 
X *
X *      If the <file> was opened without a buffer, one of MaxInputBuf
X *      bytes will be allocated.
X *
X *      If end of file or an error is detected, the return value will be
X *      NULL. Otherwise, the return value will be <s>. <s> will be 
X *      terminated with a null byte.
X */
Xchar *
XFGetsARP(s, length, file)
X    char            *s;
X    LONG            length;
X    ARPFileHandle   *file;
X{
X    LONG    bytesNeeded = length - 1;
X    LONG    bytesRead = 0;
X    char    c;
X    char    *s1 = s;
X
X    /* Set string initially empty to protect user from failure to check
X     * return value.
X     */
X    *s1 = '\0';    
X    if (file->mode != MODE_OLDFILE)
X        file->lastError = ERROR_READ_PROTECTED;
X         
X    if (file->lastError) {
Xdangit:
X        return NULL;
X    }
X    if (! file->buf ) {                 /* Ohmigosh! No buffer? */
X        file->buf = ArpAlloc(MaxInputBuf);
X        if (! file->buf ) {
X            file->lastError = ERROR_NO_FREE_STORE;
X            goto dangit;
X        }
X        file->bufSize = MaxInputBuf;    /* bufLength, bufPos are zero. */
X    }
X    while (bytesNeeded) {
X        if (file->bufPos >= file->bufLength) {
X            if (FillARPFileBuffer(file) < 0) goto dangit;
X            if (file->bufLength == 0) break;
X        }
X        c = file->buf[file->bufPos++];
X        ++bytesRead;
X        if (c == '\n') break;
X        *s1++ = c;
X        --bytesNeeded; 
X    }
X    *s1 = '\0';
X    return (bytesRead ? s : NULL);
X}
X
X/*  FUNCTION
X *      FillARPFileBuffer - read data into ARPFile buffer.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      static LONG FillARPFileBuffer(file)
X *                                    ARPFileHandle *file;
X *
X *  DESCRIPTION
X *      Attempt to fill the buffer associated with <file> by reading
X *      data from the associated external file. The return value will
X *      be one of the following:
X *          >0  => number of bytes read
X *           0  => end of file
X *          -1  => a Bad Thing happened (error code in file->lastError) 
X *
X *      Note: this is a local routine and is thus declared as "static".
X *      Please inform the author if this is a hardship.
X */
Xstatic LONG
XFillARPFileBuffer(file)
X    ARPFileHandle *file;
X{
X    /* Remember where we were. The user might want to try error
X     * recovery. Of course, this probably isn't enough info, but
X     * it's a start.
X     */
X    file->lastPosition = Seek(file->fh, 0L, OFFSET_CURRENT);
X    file->bufPos = 0;
X    file->bufLength = Read(file->fh, file->buf, file->bufSize);
X    if (file->bufLength == -1) {    /* We got trubble! */
X        file->lastError = IoErr();
X    }
X    else if (file->bufLength == 0) {
X        file->endOfFile = TRUE;
X    }
X    return file->bufLength;
X} 
X
X/*  FUNCTION
X *      FlushARPFileBuffer - write file buffer contents to disk.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      static LONG FlushARPFileBuffer(ARPFileHandle *file);
X *
X *  DESCRIPTION
X *      FlushARPFileBuffer writes the contents of <file>'s buffer
X *      (if any) to disk and resets the buffer information. The
X *      return value may be any of:
X *
X *          >0 =>   number of bytes written
X *           0 =>   nothing in buffer
X *          <0 =>   negated error code
X *
X *      Note: it is assumed that this function will only be used locally
X *      and therefore need not be public. If you disagree, please contact
X *      the author.
X */
X
Xstatic LONG
XFlushARPFileBuffer(file)
X    ARPFileHandle *file;
X{
X    LONG    bytesWritten = 0;
X
X    /* This operation is only allowed for output files. */
X
X    if (file->mode != MODE_NEWFILE) {
X        file->lastError = ERROR_WRITE_PROTECTED;
Xbadstuff:
X        return -file->lastError;
X    }
X
X    if (file->lastError) goto badstuff; /* Residual error? */
X
X    if (file->bufLength) {
X        file->lastPosition = Seek(file->fh, 0L, OFFSET_CURRENT);
X        bytesWritten = Write(file->fh, (const char *) file->buf, file->bufLength);
X        if (bytesWritten != file->bufLength) {
X            file->lastError = IoErr();
X            goto badstuff;
X        }
X        else {
X            file->bufLength = 0;
X            file->bufPos = 0;
X        }
X    }
X    return bytesWritten;
X}
X
X/*  FUNCTION
X *      FPutsARP - write a string to a buffered ARP file.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      LONG FPutsARP(s, file)
X *                    char          *s;
X *                    ARPFileHandle *file;
X *
X *  DESCRIPTION
X *      FPutsARP writes the contents of string <s> to the specified <file>.
X *      If successful, it returns 0. On failure, it returns the negated
X *      system error code. 
X */
XLONG
XFPutsARP(s, file)
X    char          *s;
X    ARPFileHandle *file;
X{
X    LONG    bytesLeft, bytesUsed;
X    char    *s1 = s;
X
X    if (file->mode != MODE_NEWFILE) 
X        file->lastError = ERROR_WRITE_PROTECTED;
X
X    if (file->lastError) {
Xshucks:
X        return -file->lastError;
X    }
X
X    bytesLeft = strlen(s);
X
X    /* Attempt to be smart about this transfer. Copy the string to the
X     * buffer in chunks. There is a possibility that the string is bigger
X     * than the size of the buffer.
X     */
X    while (bytesLeft) {
X        if (file->bufPos >= file->bufSize) {
X            if (FlushARPFileBuffer(file) <= 0) goto shucks;
X        }
X        bytesUsed = min(file->bufSize - file->bufPos, bytesLeft);
X        CopyMem(s1, &file->buf[file->bufPos], bytesUsed);
X        s1 += bytesUsed;
X        file->bufLength = (file->bufPos += bytesUsed);
X        bytesLeft -= bytesUsed;
X    }
X    return 0;
X}
X
X/*  FUNCTION
X *      ReadARPFile - read from a buffered ARP file.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      LONG ReadARPFile(ARPFileHandle *file, char *buffer, LONG length);
X *
X *  DESCRIPTION
X *      ReadARPFile attempts to read <length> bytes from <file>, transferring
X *      the data to <buffer>. 
X *
X *      The return value may be any of the following:
X *
X *          >0      number of bytes transferred
X *          0       end of file
X *         <0       negated error code
X *
X *      Note: if the lastError field of the <file> descriptor contains a
X *            non-zero value, its negated value will be returned and no
X *            attempt will be made to read the file. If you attempt error
X *            recovery, you must clear this field to zero.
X */
XLONG
XReadARPFile(file, buffer, length)
X    ARPFileHandle   *file;
X    char            *buffer;
X    LONG            length;
X{
X    LONG            bytesLeft;
X    LONG            bytesRead = 0;
X    LONG            needBytes = length;
X    LONG            pos = 0;
X    LONG            usedBytes = 0;
X
X    /* Prevent read if this file opened for writing. */
X
X    if (file->mode != MODE_OLDFILE)
X        file->lastError = ERROR_READ_PROTECTED;
X
X    if (file->lastError) {          /* Have residual error? */
Xboofar:
X        return -file->lastError;
X    }
X
X    if ( ! file->buf ) {            /* No buffer? */
X        bytesRead = Read(file->fh, buffer, length);
X        if (bytesRead == -1) {
X            file->lastError = IoErr();
X            goto boofar;
X        }
X    }
X    else while (needBytes) {
X        if (file->bufLength - file->bufPos <= 0) {
X            if (FillARPFileBuffer(file) == -1) goto boofar;
X            if (file->bufLength == 0) break;
X        }
X        bytesLeft = file->bufLength - file->bufPos;
X        usedBytes = min(bytesLeft, length);
X        CopyMem(&file->buf[file->bufPos], &buffer[pos], usedBytes);
X        file->bufPos += usedBytes;
X        pos += usedBytes;
X        bytesRead += usedBytes;
X        needBytes -= usedBytes;
X    }
X    return bytesRead;   
X}
X
X/*  FUNCTION
X *      CloseARPFile - close buffered ARP file.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      LONG CloseARPFile(file)
X *                        ARPFileHandle *file;
X *
X *  DESCRIPTION
X *      CloseARPFile closes the file described by <file> which MUST have
X *      been opened by OpenARPFile. It releases all tracked items
X *      associated with <file>, as well.
X *
X *      The return value is only meaningful for output files. If, upon
X *      flushing the buffer, a write error is detected, a system error
X *      code (ERROR_DISK_FULL, etc.) will be returned.
X */
X
XLONG
XCloseARPFile(file)
X    ARPFileHandle *file;
X{
X    LONG        result = 0;
X
X    if (file) {                     /* Just in case... */
X        if (file->fileTracker) {
X            /* Any left-over stuff in the buffer? If so, we must flush
X             * it to disk. However, if an error was detected in the
X             * previous operation, punt. 
X             */
X            if ( ( file->mode == MODE_NEWFILE) && 
X                   ! file->lastError &&
X                   file->bufLength) {
X                if (Write(file->fh, (const char *) file->buf, file->bufLength) !=
X                    file->bufLength)
X                    result = IoErr();
X            }
X            FreeTrackedItem(file->fileTracker);
X        }
X
X        FreeTrackedItem((struct DefaultTracker *) file->buf);
X        FreeTrackedItem((struct DefaultTracker *) file);
X    }
X    return result;
X}
X
X/*  FUNCTION
X *      OpenARPFile - open a buffered ARP file
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      struct MRARPFile *OpenARPFile(name, accessMode, bytes)
X *                                    char *name;
X *                                    LONG accessMode, bytes;
X *
X *  DESCRIPTION
X *      OpenARPFile opens the file <name>, with the given <accessMode>
X *      (MODE_OLDFILE, MODE_NEWFILE only!) for buffered access. The
X *      size of the local buffer is specified by <bytes>.
X *
X *      A zero value for <bytes> is OK and is sometimes appropriate, as
X *      when performing file copy operations, etc. However, if a file
X *      opened with a zero length buffer is then passed to the
X *      FGetsARP function, "spontaneous buffer allocation" will occur.
X *      No biggy, really, just something you should know. The ARP constant,
X *      MaxInputBuf will be used for the buffer size, in this case.
X *
X *      If successful, a pointer to the file tracking structure is 
X *      returned. Otherwise, the return value will be NULL.
X *
X *      OpenARPFile uses full resource tracking for all information
X *      associated with the file.
X *
X */
X
XARPFileHandle *
XOpenARPFile(name, accessMode, bytes)
X    char *name;
X    LONG accessMode, bytes;
X{
X    BPTR                  fh;
X    ARPFileHandle         *theFile = NULL;
X    struct DefaultTracker *lastTracker;
X
X    /* This package does not support READ/WRITE access! */
X
X    if ( (accessMode != MODE_OLDFILE) && (accessMode != MODE_NEWFILE))
X        return NULL;
X
X    theFile = ArpAlloc((LONG) sizeof(ARPFileHandle));
X    if (theFile) {
X        theFile->mode = accessMode;
X        fh = ArpOpen(name, accessMode);
X        lastTracker = LastTracker;
X        if (!fh) {
Xfungu:
X            CloseARPFile(theFile);  /* Don't worry - it's "smart". */
X            theFile = NULL;
X        }
X        theFile->fileTracker = lastTracker;
X        theFile->fh = fh;
X        if ( bytes) {               /* Does user want a buffer? */
X            theFile->buf = ArpAlloc(bytes);
X            if (!theFile->buf) goto fungu;
X            theFile->bufSize = bytes;
X        }
X    }
X    return theFile;  
X}
X
X/*  FUNCTION
X *      SeekARPFile - move to new logical position in file.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      LONG SeekARPFile(file, position, mode)
X *                       ARPFileHandle *file;
X *                       LONG           position;
X *                       LONG           mode;
X *
X *  DESCRIPTION
X *      SeekARPFile attempts to position the <file> to a new logical
X *      position or report it's current position. The <position>
X *      parameter represets a signed offset. The <mode> parameter may
X *      be one of:
X *
X *          OFFSET_BEGINNING (-1) => from beginning of file
X *          OFFSET_CURRENT (0)    => from current position
X *          OFFSET_END (-1)       => from end of file
X *
X *      On output files, the current buffer contents, if any, are
X *      written to disk.
X *
X *      The return value will either be a positive displacement >=0) or
X *      a negated system error code.
X */
XLONG
XSeekARPFile(file, position, mode)
X            ARPFileHandle *file;
X            LONG           position;
X            LONG           mode;
X{
X    LONG    newPosition;
X
X    if (file->mode == MODE_NEWFILE && file->bufLength) {
X        if (FlushARPFileBuffer(file) < 0) {
Xfarboo:
X            return -file->lastError;
X        }
X    }
X    /* Remember our last position. */
X    file->lastPosition = Seek(file->fh, 0L, OFFSET_CURRENT);
X    if ((newPosition = Seek(file->fh, position, mode)) == -1) {
X        file->lastError = IoErr();
X        goto farboo;
X    }
X    return newPosition;
X}  
X
X/*  FUNCTION
X *      WriteARPFile - write data to a buffered ARP file.
X *
X *  SYNOPSIS
X *      #include <MRARPFile.h>
X *
X *      LONG WriteARPFile(ARPFileHandle *file, const char *buffer, LONG length);
X *
X *  DESCRIPTION
X *      WriteARPFile attempts to write <length> bytes from <buffer> to
X *      the buffered ARP file, <file>. The file MUST have been opened
X *      with OpenARPFile for MODE_NEWFILE access.
X *
X *      WriteARPFile will not write to a file if the lastError field is
X *      non-zero, or if the file was opened for input.
X *
X *      If successful, WriteARPFile will return the <length> parameter.
X *      Otherwise, it will return a negated system error code.
X */
XLONG
XWriteARPFile(file, buffer, length)
X    ARPFileHandle   *file;
X    const char      *buffer;
X    LONG            length;
X{
X    LONG    bufferBytes;
X    LONG    bytesLeft = length;
X    LONG    pos = 0;
X    LONG    usedBytes = 0;
X
X    if (file->mode != MODE_NEWFILE)
X        file->lastError = ERROR_WRITE_PROTECTED;
X
X    if (file->lastError) {           /* Catches mode and residual errors. */
Xsumbidge:
X        return -(file->lastError);
X    }
X
X    if ( ! file->buf ) {             /* No buffer? */
X        if (Write(file->fh, buffer, length) != length) {
X            file->lastError = IoErr();
X            goto sumbidge;
X        }
X    }
X    else while (bytesLeft) {
X        /* Need to flush the file's buffer? */
X        if (file->bufPos >= file->bufSize) {
X            if (FlushARPFileBuffer(file) < 0) {
X                goto sumbidge;
X            }
X        }
X        bufferBytes = file->bufSize - file->bufPos;
X        usedBytes = min(bufferBytes, bytesLeft);
X        CopyMem(&buffer[pos], &file->buf[file->bufPos], usedBytes);
X        file->bufLength = (file->bufPos += usedBytes);
X        pos += usedBytes;
X        bytesLeft -= usedBytes;
X    }
X    return length;
X}
X
X/*  Embedded documentation template (cut & paste): */
X
X/*  FUNCTION
X *
X *  SYNOPSIS
X *
X *  DESCRIPTION
X *
X */
END_OF_FILE
if test 17486 -ne `wc -c <'MRARPFile.c'`; then
    echo shar: \"'MRARPFile.c'\" unpacked with wrong size!
fi
# end of 'MRARPFile.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@cs.odu.edu>.
Mail comments to the moderator at <amiga-request@cs.odu.edu>.
Post requests for sources, and general discussion to comp.sys.amiga.