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.