home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
375.lha
/
MRARPFile_v1.1
/
MRARPFile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-02
|
17KB
|
572 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 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
*
*/