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.