home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 3
/
goldfish_volume_3.bin
/
files
/
text
/
misc
/
cvt
/
source
/
filecopy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-02
|
7KB
|
311 lines
/*
* FILECOPY.C
*
* (c)Copyright 1990,93 by Tobias Ferber, All Rights Reserved.
*/
#include "filecopy.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef AMIGA
#include <exec/types.h>
#include <exec/memory.h>
#endif /* AMIGA */
/* private statics */
static unsigned char *copybuffer= (unsigned char *)0L;
static unsigned long buffersize= 0L;
static char rcs_id[]= "$Id: filecopy.c,v 1.1 1994/06/06 16:44:36 tf Exp $";
/*
*
* FUNCTION
*
* fc_setbuf -- allocate or free a copy buffer for filecopy()
*
* SYNOPSIS
* #include "filecopy.h"
*
* result= fc_setbuf(numbytes)
* unsigned long result;
* unsigned long numbytes;
*
* DESCRIPTION
*
* This function tries to allocate 'numbytes' bytes for the local
* copy buffer. If you pass 0L with the 'numbytes' parameter the
* actual copy buffer will be free()d.
* The current size of the copy buffer will be returned.
*
* NOTE
*
* It is absolutely legal to re-size your copy buffer by calling this
* function only once (with your new buffer size) instead of calling
* it twice (with numbytes==0L first)
* Note also that this function does *NOT* check whether 'numbytes'
* is larger than the local limit. (see "filecopy.h")
*
* SEE ALSO
*
* filecopy(), "filecopy.h"
*
*/
unsigned long fc_setbuf(numbytes)
unsigned long numbytes;
{
#ifdef AMIGA
if(copybuffer && buffersize)
FreeMem(copybuffer, buffersize);
#else /* !AMIGA */
if(copybuffer)
free(copybuffer);
#endif /* AMIGA */
copybuffer= (unsigned char *)0L;
buffersize= 0L;
if(numbytes)
{
#ifdef AMIGA
copybuffer= (unsigned char *)AllocMem(numbytes*sizeof(unsigned char), MEMF_PUBLIC);
#else /* !AMIGA */
copybuffer= (unsigned char *)malloc(numbytes*sizeof(unsigned char));
#endif /* AMIGA */
if(copybuffer)
buffersize= numbytes*sizeof(unsigned char);
}
return buffersize;
}
/*
*/
#ifdef DEBUG
/* My favorite way of reporting that we're alive: */
static void turn(on)
int on;
{
static char bars[]= "|/-\\|/-\\";
static int b= 0;
if(on)
{
fprintf(stderr,"%c\b",bars[b++]);
if(b >= sizeof(bars)-1)
b= 0;
}
else fprintf(stderr," \b");
fflush(stderr);
}
#endif /* DEBUG */
/*
*
* FUNCTION
*
* filecopy -- copy n bytes of data from one file pointer to another
*
* SYNOPSIS
* #include "filecopy.h"
*
* result= filecopy(src, dst, n)
* long result;
* long n;
* FILE *src, *dst;
*
* DESCRIPTION
*
* This function tries to copy 'n' bytes from given source stream 'src'
* to the destination 'dst'.
* If 'n' is == 0 then filecopy() will compute this value assuming that
* all data following the current position of 'src' is ment to be copied.
* If a copy buffer has been allocated successfully via fc_setbuf() then
* filecopy() will take advantage of of it. On the other hand, if no
* buffer was allocated it will do so on it's own and tries to get either
* 'n' or (if 'n' is too large) MAXIMUM_BUFFERSIZE bytes. (See the notes
* about this value in "filecopy.h".)
* If the allocation fails then filecopy() will copy your data byte for
* byte. Normally the number of written bytes will be returned but
*
* NOTE
*
* This function tries to be very careful concerning errors. If an error
* occurs it will exit immediately returning either -1L in case of a read
* error in the 'src' file or -2L in case of a write error with the 'dst'
* file pointer.
* Also filecopy() will *NOT* print out anything, even not if there was
* an error. (There may of course be some output if your OS feels a need
* to do so.) It's up to the caller to use perror() or sth. similar to
* inform the user about what went wrong.
*
* NOTE ALSO
*
* This function assumes 'src' not to be a tty; especially not if you pass
* n=0 with the arguments. In other words, filecopy() will fail if seeking
* with 'src' is impossible.
* You can however pass a value n<0 in order to force a byte for byte
* transfer without seeking.
*
*/
long filecopy(src, dst, n)
long n;
FILE *src, *dst;
{
long result= 0L; /* The value returned by this function:
* if non-negative the #of bytes written,
* -1 = read error, -2 = write error */
unsigned long remember= 0L; /* #of bytes allocated by *this* function */
long bytesleft= 0L; /* #of bytes left for copying */
if(n==0)
{
/* Compute the #of bytes left for copying */
#ifdef BUGGY_FTELL
do {
(void)fgetc(src);
if(!feof(src))
++bytesleft;
} while(!feof(src) || ferror(src))
#else /* ftell() works fine */
if( fseek(src,0L,2L) >= 0) /* 2 == OFFSET_END */
bytesleft= ftell(src);
else
result= -1L;
#endif /* BUGGY_FTELL */
if(!ferror(src) && bytesleft>0)
{
if(fseek(src,-bytesleft,1L) < 0) /* 1 == OFFSET_CURRENT */
result= -1L;
}
else result= -1L;
}
else /* n!=0 */
bytesleft= (n > 0) ? n : 0L;
if(!result)
{
long nbytes= 0L;
if(!copybuffer && bytesleft>0)
{
remember= fc_setbuf( (bytesleft > MAXIMUM_BUFFERSIZE) ?
MAXIMUM_BUFFERSIZE : bytesleft );
}
/* If the allocation failed (or if n was negative) then we'll copy
* the data byte for byte which of course is hyper slow ;)
*/
if(!copybuffer || buffersize < 2L)
{
unsigned char c;
int done= 0;
do {
c= fgetc(src);
if(!feof(src))
{
fputc(c,dst);
nbytes++;
if(n>0 && nbytes>=n)
done= 1;
#ifdef DEBUG
turn(1);
#endif /* DEBUG */
}
} while(!done && !feof(src) && !ferror(src) && !ferror(dst));
/* This might change later when checking ferror(): */
result= nbytes;
}
else /* use the buffer */
{
long psize; /* packet size */
do {
psize= (bytesleft > buffersize) ? buffersize : bytesleft;
bytesleft-= psize;
/* I think it's a good idea to use fread() and fwrite() with
* psize packets of size 1 here instead of 1 packet of size psize
* because these functions return the number of *complete* packets
* that were read (or written). This way we can also handle
* partial packets if needed. */
nbytes= fread(copybuffer, 1L, psize, src);
if(!ferror(src))
{
/* write exactly as many bytes as we read before */
nbytes= fwrite(copybuffer, 1L, nbytes, dst);
result += nbytes;
}
/* A partial read or written packet indicates that we're done,
* it does however not neccessarily mean that there was an error.
* Changing the result to a negative value can be done later
* by testing ferror(). */
if(nbytes!=psize)
bytesleft= 0;
#ifdef DEBUG
turn(1);
#endif
} while(bytesleft>0 && !ferror(src) && !ferror(dst));
}
if(ferror(src))
result= -1L;
else if(ferror(dst))
result= -2L;
}
/* free the copy buffer if it was allocated by us */
if(remember)
fc_setbuf(0L);
#ifdef DEBUG
turn(0);
#endif
return result;
}