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 if you mix calls to this package
- * with calls to Read/Write/Seek, etc. (unless, of course, you take care
- * to maintain the ARPFileHandle information).
- */
-
-
- #if __STDC__
- #include <stdlib.h>
- #endif
-
- #include "MRARPFile.h"
- #include <exec/memory.h>
- #include <string.h>
- #include <functions.h>
-
- #ifndef min
- #define min(a,b) ((a) <= (b) ? (a) : (b))
- #define max(a,b) ((a) >= (b) ? (a) : (b))
- #endif
-
- /* struct DefaultTracker *StoreTracker __PARMS( (void) ); */
-
- static LONG FillARPFileBuffer __PARMS( (ARPFileHandle *file) );
- static LONG FlushARPFileBuffer __PARMS( (ARPFileHandle *file) );
-
- /* FUNCTION
- * FGetsARP - get string from a buffered ARP file.
- *
- * SYNOPSIS
- * #include <MRARPFile.h>
- *
- * 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(s, length, file)
- char *s;
- LONG length;
- ARPFileHandle *file;
- {
- 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;
- }
- if (! file->buf ) { /* Ohmigosh! No buffer? */
- file->buf = ArpAlloc(MaxInputBuf);
- if (! file->buf ) {
- file->lastError = ERROR_NO_FREE_STORE;
- goto dangit;
- }
- file->bufSize = MaxInputBuf; /* bufLength, bufPos are zero. */
- }
- while (bytesNeeded) {
- if (file->bufPos >= file->bufLength) {
- if (FillARPFileBuffer(file) < 0) goto dangit;
- if (file->bufLength == 0) 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
- * #include <MRARPFile.h>
- *
- * 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(file)
- 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);
- if (file->bufLength == -1) { /* We got trubble! */
- file->lastError = IoErr();
- }
- else if (file->bufLength == 0) {
- file->endOfFile = TRUE;
- }
- return file->bufLength;
- }
-
- /* FUNCTION
- * FlushARPFileBuffer - write file buffer contents to disk.
- *
- * SYNOPSIS
- * #include <MRARPFile.h>
- *
- * static LONG FlushARPFileBuffer(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(file)
- 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, (const char *) 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
- * #include <MRARPFile.h>
- *
- * 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(s, file)
- 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
- * #include <MRARPFile.h>
- *
- * LONG ReadARPFile(ARPFileHandle *file, char *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(file, buffer, length)
- ARPFileHandle *file;
- char *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;
-
- if (file->lastError) { /* Have residual error? */
- boofar:
- return -file->lastError;
- }
-
- if ( ! file->buf ) { /* No buffer? */
- 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 == 0) 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
- * #include <MRARPFile.h>
- *
- * 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(file)
- ARPFileHandle *file;
- {
- LONG result = 0;
-
- if (file) { /* Just in case... */
- 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, (const char *) file->buf, file->bufLength) !=
- file->bufLength)
- result = IoErr();
- }
- FreeTrackedItem(file->fileTracker);
- }
-
- FreeTrackedItem((struct DefaultTracker *) file->buf);
- FreeTrackedItem((struct DefaultTracker *) file);
- }
- return result;
- }
-
- /* FUNCTION
- * OpenARPFile - open a buffered ARP file
- *
- * SYNOPSIS
- * #include <MRARPFile.h>
- *
- * 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(name, accessMode, bytes)
- char *name;
- LONG accessMode, bytes;
- {
- BPTR fh;
- ARPFileHandle *theFile = NULL;
- struct DefaultTracker *lastTracker;
-
- /* This package does not support READ/WRITE access! */
-
- if ( (accessMode != MODE_OLDFILE) && (accessMode != MODE_NEWFILE))
- return NULL;
-
- theFile = ArpAlloc((LONG) sizeof(ARPFileHandle));
- if (theFile) {
- theFile->mode = accessMode;
- fh = ArpOpen(name, accessMode);
- lastTracker = LastTracker;
- if (!fh) {
- fungu:
- CloseARPFile(theFile); /* Don't worry - it's "smart". */
- theFile = NULL;
- }
- theFile->fileTracker = lastTracker;
- theFile->fh = fh;
- if ( bytes) { /* Does user want a buffer? */
- theFile->buf = ArpAlloc(bytes);
- if (!theFile->buf) goto fungu;
- theFile->bufSize = bytes;
- }
- }
- return theFile;
- }
-
- /* FUNCTION
- * SeekARPFile - move to new logical position in file.
- *
- * SYNOPSIS
- * #include <MRARPFile.h>
- *
- * 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(file, position, mode)
- 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. */
- 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
- * #include <MRARPFile.h>
- *
- * LONG WriteARPFile(ARPFileHandle *file, const char *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(file, buffer, length)
- ARPFileHandle *file;
- const char *buffer;
- LONG length;
- {
- LONG bufferBytes;
- LONG bytesLeft = length;
- LONG pos = 0;
- LONG usedBytes = 0;
-
- if (file->mode != MODE_NEWFILE)
- file->lastError = ERROR_WRITE_PROTECTED;
-
- if (file->lastError) { /* Catches mode and residual errors. */
- sumbidge:
- return -(file->lastError);
- }
-
- if ( ! file->buf ) { /* No buffer? */
- 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;
- }
-
- /* Embedded documentation template (cut & paste): */
-
- /* FUNCTION
- *
- * SYNOPSIS
- *
- * DESCRIPTION
- *
- */
-