home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
keyboard
/
keymacro_398
/
mrarpfile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-11-01
|
17KB
|
691 lines
/* 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"
/* System includes. */
#include <exec/memory.h>
#include <clib/macros.h>
#include <functions.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.
*/
#asm
public _StoreTracker
_StoreTracker:
move.l a1,d0
rts
#endasm
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);
}