home *** CD-ROM | disk | FTP | other *** search
- /* File support routines to complement ARP.
- * Author: Mark R. Rinfret
- * Usenet: mrr@amanpt1.Newport.RI.US
- * BIX: markr
- * CIS: 72017, 136 (good luck!)
- *
- * 348 Indian Avenue
- * Portsmouth, RI 02871
- * 401-846-7639 (home)
- * 401-849-9390 (work)
- *
- * This package was written primarily because of _one_ missing element
- * in ARP: FGets. ARGH! ARPFFFT! It extends ARP by adding buffering to
- * the basic file type (FileHandle) and defining a new type, named
- * ARPFileHandle (hope this is OK with the ARP guys). Also, I've used the
- * convention of embedding ARP (vs. Arp in MicroSmith's stuff) in all type
- * and function names to (hopefully) avoid naming collisions.
- *
- * This package (as far as I am concerned) is public domain. Use it any
- * way you like. Some comments on the "MR" prefix: it isn't short for
- * "Mister", it comprises the initials of my first and last names;
- * I use it primarily to avoid name collisions with stuff by other
- * authors. If any other authors whose initials are "MR" start doing
- * this, we'll probably have to appeal to Electronic Arts to dole out
- * "author codes" along the lines of those issued for IFF :-). I hereby
- * stake a claim to 'MRR_'.
- *
- * A word of warning:
- *
- * DO NOT INTERMIX STANDARD AMIGADOS FILE SUPPORT CALLS WITH CALLS TO
- * THIS PACKAGE ON FILES USING THIS FILE METHOD!
- *
- * Obviously, the system doesn't know about the buffering added here
- * and will cause unpredictable results (unless, of course, you
- * take care to maintain the ARPFileHandle information).
- */
-
- /* Olsen: In order to adapt the code to ANSI some declarations and
- * function calls were rearranged. I also fixed two parts of
- * code which appeared not to work correctly.
- */
-
- /* Skip prototypes. */
-
- #define _MRARPFILE_PRIVATE 1
-
- #include "MRARPFile.h"
-
- /* StoreTracker is my attempt to fix an apparent bug in ARP 1.3. I have
- * found that the LastTracker kludge (via IoErr()) doesn't work reliably.
- * StoreTracker simply stuffs A1 into D0 and returns . It *MUST* be
- * called immediately after any ARP call which allocates a tracker to
- * assure that the value is correct.
- */
-
- struct DefaultTracker * StoreTracker(VOID);
-
- char * FGetsARP(char *s,LONG length,ARPFileHandle *file);
- static LONG FillARPFileBuffer(ARPFileHandle *file);
- static LONG FlushARPFileBuffer(ARPFileHandle *file);
- LONG FPutsARP(char *s,ARPFileHandle *file);
- LONG ReadARPFile(ARPFileHandle *file,UBYTE *buffer,LONG length);
- LONG CloseARPFile(ARPFileHandle *file);
- ARPFileHandle * OpenARPFile(char *name,LONG accessMode,LONG bytes);
- LONG SeekARPFile(ARPFileHandle *file,LONG position,LONG mode);
- LONG WriteARPFile(ARPFileHandle *file,UBYTE *buffer,LONG length);
-
- /* FUNCTION
- * FGetsARP - get string from a buffered ARP file.
- *
- * SYNOPSIS
- * char *FGetsARP(s, length, file)
- * UBYTE *s;
- * LONG length;
- * ARPFileHandle *file;
- *
- * DESCRIPTION
- * FGetsARP models the behavior of the "standard" fgets, except that
- * it is used with a buffered ARP file. The data is read from <file>
- * and transfered to string <s>. Up to length-1 characters will be
- * read. Reading is also terminated upon receipt of a newline
- * or detection of end-of-file.
- *
- * If the <file> was opened without a buffer, one of MaxInputBuf
- * bytes will be allocated.
- *
- * If end of file or an error is detected, the return value will be
- * NULL. Otherwise, the return value will be <s>. <s> will be
- * terminated with a null byte.
- */
-
- char *
- FGetsARP(char *s,LONG length,ARPFileHandle *file)
- {
- struct DefaultTracker *tracker;
- LONG bytesNeeded = length - 1;
- LONG bytesRead = 0;
- char c;
- char *s1 = s;
-
- /* Set string initially empty to protect user from failure to check
- * return value.
- */
-
- *s1 = '\0';
-
- if(file -> mode != MODE_OLDFILE)
- file -> lastError = ERROR_READ_PROTECTED;
-
- if(file -> lastError)
- {
- dangit: return(NULL);
- }
-
- /* Ohmigosh! No buffer? */
-
- if(!file -> buf)
- {
- file -> buf = ArpAllocMem(MaxInputBuf, MEMF_CLEAR | MEMF_PUBLIC);
-
- tracker = StoreTracker();
-
- if(!file -> buf)
- {
- file -> lastError = ERROR_NO_FREE_STORE;
- goto dangit;
- }
-
- file -> bufSize = MaxInputBuf; /* bufLength, bufPos are zero. */
- file -> bufTracker = tracker;
- }
-
- while(bytesNeeded)
- {
- if(file -> bufPos >= file -> bufLength)
- {
- if(FillARPFileBuffer(file) < 0)
- goto dangit;
-
- if(!file -> bufLength)
- break;
- }
-
- c = file -> buf[file -> bufPos++];
-
- ++bytesRead;
-
- if(c == '\n')
- break;
-
- *s1++ = c;
-
- --bytesNeeded;
- }
-
- *s1 = '\0';
-
- return(bytesRead ? s : NULL);
- }
-
- /* FUNCTION
- * FillARPFileBuffer - read data into ARPFile buffer.
- *
- * SYNOPSIS
- * static LONG FillARPFileBuffer(file)
- * ARPFileHandle *file;
- *
- * DESCRIPTION
- * Attempt to fill the buffer associated with <file> by reading
- * data from the associated external file. The return value will
- * be one of the following:
- * >0 => number of bytes read
- * 0 => end of file
- * -1 => a Bad Thing happened (error code in file -> lastError)
- *
- * Note: this is a local routine and is thus declared as "static".
- * Please inform the author if this is a hardship.
- */
-
- static LONG
- FillARPFileBuffer(ARPFileHandle *file)
- {
- /* Remember where we were. The user might want to try error
- * recovery. Of course, this probably isn't enough info, but
- * it's a start.
- */
-
- file -> lastPosition = Seek(file -> fh, 0L, OFFSET_CURRENT);
- file -> bufPos = 0;
- file -> bufLength = Read(file -> fh, file -> buf, file -> bufSize);
-
- /* We got trubble! */
-
- if(file -> bufLength == -1)
- file -> lastError = IoErr();
- else
- {
- if(!file -> bufLength)
- file -> endOfFile = TRUE;
- }
-
- return(file -> bufLength);
- }
-
- /* FUNCTION
- * FlushARPFileBuffer - write file buffer contents to disk.
- *
- * SYNOPSIS
- * static LONG FlushARPFileBuffer(file)
- * ARPFileHandle *file;
- * DESCRIPTION
- * FlushARPFileBuffer writes the contents of <file>'s buffer
- * (if any) to disk and resets the buffer information. The
- * return value may be any of:
- *
- * >0 => number of bytes written
- * 0 => nothing in buffer
- * <0 => negated error code
- *
- * Note: it is assumed that this function will only be used locally
- * and therefore need not be public. If you disagree, please contact
- * the author.
- */
-
- static LONG
- FlushARPFileBuffer(ARPFileHandle *file)
- {
- LONG bytesWritten = 0;
-
- /* This operation is only allowed for output files. */
-
- if(file -> mode != MODE_NEWFILE)
- {
- file -> lastError = ERROR_WRITE_PROTECTED;
-
- badstuff: return(-file -> lastError);
- }
-
- if(file -> lastError)
- goto badstuff; /* Residual error? */
-
- if(file -> bufLength)
- {
- file -> lastPosition = Seek(file -> fh, 0L, OFFSET_CURRENT);
-
- bytesWritten = Write(file -> fh, file -> buf, file -> bufLength);
-
- if(bytesWritten != file -> bufLength)
- {
- file -> lastError = IoErr();
- goto badstuff;
- }
- else
- {
- file -> bufLength = 0;
- file -> bufPos = 0;
- }
- }
-
- return(bytesWritten);
- }
-
- /* FUNCTION
- * FPutsARP - write a string to a buffered ARP file.
- *
- * SYNOPSIS
- * LONG FPutsARP(s, file)
- * char *s;
- * ARPFileHandle *file;
- *
- * DESCRIPTION
- * FPutsARP writes the contents of string <s> to the specified <file>.
- * If successful, it returns 0. On failure, it returns the negated
- * system error code.
- */
-
- LONG
- FPutsARP(char *s,ARPFileHandle *file)
- {
- LONG bytesLeft, bytesUsed;
- char *s1 = s;
-
- if(file -> mode != MODE_NEWFILE)
- file -> lastError = ERROR_WRITE_PROTECTED;
-
- if(file -> lastError)
- {
- shucks: return(-file -> lastError);
- }
-
- bytesLeft = strlen(s);
-
- /* Attempt to be smart about this transfer. Copy the string to the
- * buffer in chunks. There is a possibility that the string is bigger
- * than the size of the buffer.
- */
-
- while(bytesLeft)
- {
- if(file -> bufPos >= file -> bufSize)
- {
- if(FlushARPFileBuffer(file) <= 0)
- goto shucks;
- }
-
- bytesUsed = MIN(file -> bufSize - file -> bufPos, bytesLeft);
-
- CopyMem(s1, &file -> buf[file -> bufPos], bytesUsed);
-
- s1 += bytesUsed;
-
- file -> bufLength = (file -> bufPos += bytesUsed);
-
- bytesLeft -= bytesUsed;
- }
-
- return(0);
- }
-
- /* FUNCTION
- * ReadARPFile - read from a buffered ARP file.
- *
- * SYNOPSIS
- * LONG ReadARPFile(file, buffer, length)
- * ARPFile *file;
- * UBYTE *buffer;
- * LONG length;
- *
- * DESCRIPTION
- * ReadARPFile attempts to read <length> bytes from <file>, transferring
- * the data to <buffer>.
- *
- * The return value may be any of the following:
- *
- * >0 number of bytes transferred
- * 0 end of file
- * <0 negated error code
- *
- * Note: if the lastError field of the <file> descriptor contains a
- * non-zero value, its negated value will be returned and no
- * attempt will be made to read the file. If you attempt error
- * recovery, you must clear this field to zero.
- */
-
- LONG
- ReadARPFile(ARPFileHandle *file,UBYTE *buffer,LONG length)
- {
- LONG bytesLeft;
- LONG bytesRead = 0;
- LONG needBytes = length;
- LONG pos = 0;
- LONG usedBytes = 0;
-
- /* Prevent read if this file opened for writing. */
-
- if(file -> mode != MODE_OLDFILE)
- file -> lastError = ERROR_READ_PROTECTED;
-
- /* Have residual error? */
-
- if(file -> lastError)
- {
- boofar: return(-file -> lastError);
- }
-
- /* No buffer? */
-
- if(!file -> buf )
- {
- bytesRead = Read(file -> fh, buffer, length);
-
- if(bytesRead == -1)
- {
- file -> lastError = IoErr();
- goto boofar;
- }
- }
- else
- {
- while(needBytes)
- {
- if(file -> bufLength - file -> bufPos <= 0)
- {
- if(FillARPFileBuffer(file) == -1)
- goto boofar;
-
- if(!file -> bufLength)
- break;
- }
-
- bytesLeft = file -> bufLength - file -> bufPos;
-
- usedBytes = MIN(bytesLeft, length);
-
- CopyMem(&file -> buf[file -> bufPos], &buffer[pos], usedBytes);
-
- file -> bufPos += usedBytes;
-
- pos += usedBytes;
-
- bytesRead += usedBytes;
- needBytes -= usedBytes;
- }
- }
-
- return(bytesRead);
- }
-
- /* FUNCTION
- * CloseARPFile - close buffered ARP file.
- *
- * SYNOPSIS
- * LONG CloseARPFile(file)
- * ARPFileHandle *file;
- *
- * DESCRIPTION
- * CloseARPFile closes the file described by <file> which MUST have
- * been opened by OpenARPFile. It releases all tracked items
- * associated with <file>, as well.
- *
- * The return value is only meaningful for output files. If, upon
- * flushing the buffer, a write error is detected, a system error
- * code (ERROR_DISK_FULL, etc.) will be returned.
- */
-
- LONG
- CloseARPFile(ARPFileHandle *file)
- {
- LONG result = 0;
-
- /* Just in case... */
-
- if(file)
- {
- if(file -> fileTracker)
- {
- /* Any left-over stuff in the buffer? If so, we must flush
- * it to disk. However, if an error was detected in the
- * previous operation, punt.
- */
-
- if((file -> mode == MODE_NEWFILE) && ! file -> lastError && file -> bufLength)
- {
- if(Write(file -> fh, file -> buf, file -> bufLength) != file -> bufLength)
- result = IoErr();
- }
-
- FreeTrackedItem(file -> fileTracker);
- }
-
- if(file -> bufTracker)
- FreeTrackedItem(file -> bufTracker);
-
- FreeTrackedItem(file -> myTracker);
- }
-
- return(result);
- }
-
- /* FUNCTION
- * OpenARPFile - open a buffered ARP file
- *
- * SYNOPSIS
- * struct MRARPFile *OpenARPFile(name, accessMode, bytes)
- * char *name;
- * LONG accessMode, bytes;
- *
- * DESCRIPTION
- * OpenARPFile opens the file <name>, with the given <accessMode>
- * (MODE_OLDFILE, MODE_NEWFILE only!) for buffered access. The
- * size of the local buffer is specified by <bytes>.
- *
- * A zero value for <bytes> is OK and is sometimes appropriate, as
- * when performing file copy operations, etc. However, if a file
- * opened with a zero length buffer is then passed to the
- * FGetsARP function, "spontaneous buffer allocation" will occur.
- * No biggy, really, just something you should know. The ARP constant,
- * MaxInputBuf will be used for the buffer size, in this case.
- *
- * If successful, a pointer to the file tracking structure is
- * returned. Otherwise, the return value will be NULL.
- *
- * OpenARPFile uses full resource tracking for all information
- * associated with the file.
- *
- */
-
- ARPFileHandle *
- OpenARPFile(char *name,LONG accessMode,LONG bytes)
- {
- struct DefaultTracker *lastTracker;
- ARPFileHandle *theFile = NULL;
- BPTR fh;
-
- /* This package does not support READ/WRITE access! */
-
- if((accessMode != MODE_OLDFILE) && (accessMode != MODE_NEWFILE))
- return(NULL);
-
- /*
- * Note: I'm using ArpAllocMem vs. ArpAlloc here because it appears
- * that ArpAlloc gives me a bad tracker pointer (?).
- */
-
- theFile = ArpAllocMem((LONG) sizeof(ARPFileHandle), MEMF_PUBLIC | MEMF_CLEAR);
-
- lastTracker = StoreTracker();
-
- if(theFile)
- {
- theFile -> myTracker = lastTracker;
- theFile -> mode = accessMode;
-
- fh = ArpOpen(name, accessMode);
-
- lastTracker = StoreTracker();
-
- if(!fh)
- {
- fungu: CloseARPFile(theFile); /* Don't worry - it's "smart". */
- theFile = NULL;
-
- return(NULL); /* This one was missing -Olsen */
- }
-
- theFile -> fileTracker = lastTracker;
- theFile -> fh = fh;
-
- /* Does user want a buffer? */
-
- if(bytes)
- {
- theFile -> buf = ArpAllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR);
-
- lastTracker = StoreTracker();
-
- if(!theFile -> buf)
- goto fungu;
-
- theFile -> bufSize = bytes;
- theFile -> bufTracker = lastTracker;
- }
- }
-
- return(theFile);
- }
-
- /* FUNCTION
- * SeekARPFile - move to new logical position in file.
- *
- * SYNOPSIS
- * LONG SeekARPFile(file, position, mode)
- * ARPFileHandle *file;
- * LONG position;
- * LONG mode;
- *
- * DESCRIPTION
- * SeekARPFile attempts to position the <file> to a new logical
- * position or report it's current position. The <position>
- * parameter represets a signed offset. The <mode> parameter may
- * be one of:
- *
- * OFFSET_BEGINNING (-1) => from beginning of file
- * OFFSET_CURRENT (0) => from current position
- * OFFSET_END (-1) => from end of file
- *
- * On output files, the current buffer contents, if any, are
- * written to disk.
- *
- * The return value will either be a positive displacement >=0) or
- * a negated system error code.
- */
-
- LONG
- SeekARPFile(ARPFileHandle *file,LONG position,LONG mode)
- {
- LONG newPosition;
-
- if(file -> mode == MODE_NEWFILE && file -> bufLength)
- {
- if(FlushARPFileBuffer(file) < 0)
- {
- farboo: return(-file -> lastError);
- }
- }
-
- /* Remember our last position. Seek(file,...) fixed
- * to use Seek(file -> fh,...) -Olsen.
- */
-
- file -> lastPosition = Seek(file -> fh, 0L, OFFSET_CURRENT);
-
- if((newPosition = Seek(file -> fh, position, mode)) == -1)
- {
- file -> lastError = IoErr();
- goto farboo;
- }
-
- return(newPosition);
- }
-
- /* FUNCTION
- * WriteARPFile - write data to a buffered ARP file.
- *
- * SYNOPSIS
- * LONG WriteARPFile(file, buffer, length)
- * ARPFileHandle *file;
- * UBYTE *buffer;
- * LONG length;
- *
- * DESCRIPTION
- * WriteARPFile attempts to write <length> bytes from <buffer> to
- * the buffered ARP file, <file>. The file MUST have been opened
- * with OpenARPFile for MODE_NEWFILE access.
- *
- * WriteARPFile will not write to a file if the lastError field is
- * non-zero, or if the file was opened for input.
- *
- * If successful, WriteARPFile will return the <length> parameter.
- * Otherwise, it will return a negated system error code.
- */
-
- LONG
- WriteARPFile(ARPFileHandle *file,UBYTE *buffer,LONG length)
- {
- LONG bufferBytes;
- LONG bytesLeft = length;
- LONG pos = 0;
- LONG usedBytes = 0;
-
- if(file -> mode != MODE_NEWFILE)
- file -> lastError = ERROR_WRITE_PROTECTED;
-
- /* Catches mode and residual errors. */
-
- if(file -> lastError)
- {
- sumbidge: return(-file -> lastError);
- }
-
- /* No buffer? */
-
- if(!file -> buf)
- {
- if(Write(file -> fh, buffer, length) != length)
- {
- file -> lastError = IoErr();
- goto sumbidge;
- }
- }
- else
- {
- while(bytesLeft)
- {
- /* Need to flush the file's buffer? */
-
- if(file -> bufPos >= file -> bufSize)
- if(FlushARPFileBuffer(file) < 0)
- goto sumbidge;
-
- bufferBytes = file -> bufSize - file -> bufPos;
-
- usedBytes = MIN(bufferBytes, bytesLeft);
-
- CopyMem(&buffer[pos], &file -> buf[file -> bufPos], usedBytes);
-
- file -> bufLength = (file -> bufPos += usedBytes);
-
- pos += usedBytes;
-
- bytesLeft -= usedBytes;
- }
- }
-
- return(length);
- }
-