home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / text / misc / cvt / source / filecopy.c < prev    next >
C/C++ Source or Header  |  1995-03-02  |  7KB  |  311 lines

  1. /*
  2.  *  FILECOPY.C
  3.  *
  4.  *  (c)Copyright 1990,93 by Tobias Ferber,  All Rights Reserved.
  5.  */
  6.  
  7. #include "filecopy.h"
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. #ifdef AMIGA
  12. #include <exec/types.h>
  13. #include <exec/memory.h>
  14. #endif /* AMIGA */
  15.  
  16. /* private statics */
  17. static unsigned char *copybuffer= (unsigned char *)0L;
  18. static unsigned long buffersize= 0L;
  19.  
  20. static char rcs_id[]= "$Id: filecopy.c,v 1.1 1994/06/06 16:44:36 tf Exp $";
  21.  
  22. /*
  23.  *
  24.  * FUNCTION
  25.  *
  26.  *   fc_setbuf -- allocate or free a copy buffer for filecopy()
  27.  *
  28.  * SYNOPSIS
  29.  *   #include "filecopy.h"
  30.  *
  31.  *   result= fc_setbuf(numbytes)
  32.  *   unsigned long result;
  33.  *   unsigned long numbytes;
  34.  *
  35.  * DESCRIPTION
  36.  *
  37.  *   This function tries to allocate 'numbytes' bytes for the local
  38.  *   copy buffer.  If you pass 0L with the 'numbytes' parameter the
  39.  *   actual copy buffer will be free()d.
  40.  *   The current size of the copy buffer will be returned.
  41.  *
  42.  * NOTE
  43.  *
  44.  *   It is absolutely legal to re-size your copy buffer by calling this
  45.  *   function only once (with your new buffer size) instead of calling
  46.  *   it twice (with numbytes==0L first)
  47.  *   Note also that this function does *NOT* check whether 'numbytes'
  48.  *   is larger than the local limit. (see "filecopy.h")
  49.  *
  50.  * SEE ALSO
  51.  *
  52.  *   filecopy(), "filecopy.h"
  53.  *
  54.  */
  55.  
  56. unsigned long fc_setbuf(numbytes)
  57. unsigned long numbytes;
  58. {
  59. #ifdef AMIGA
  60.   if(copybuffer && buffersize)
  61.     FreeMem(copybuffer, buffersize);
  62.  
  63. #else /* !AMIGA */
  64.   if(copybuffer)
  65.     free(copybuffer);
  66.  
  67. #endif /* AMIGA */
  68.  
  69.   copybuffer= (unsigned char *)0L;
  70.   buffersize= 0L;
  71.  
  72.  
  73.   if(numbytes)
  74.   {
  75.  
  76. #ifdef AMIGA
  77.     copybuffer= (unsigned char *)AllocMem(numbytes*sizeof(unsigned char), MEMF_PUBLIC);
  78.  
  79. #else /* !AMIGA */
  80.     copybuffer= (unsigned char *)malloc(numbytes*sizeof(unsigned char));
  81.  
  82. #endif /* AMIGA */
  83.  
  84.     if(copybuffer)
  85.       buffersize= numbytes*sizeof(unsigned char);
  86.   }
  87.   return buffersize;
  88. }
  89.  
  90. /*
  91. */
  92.  
  93. #ifdef DEBUG
  94. /* My favorite way of reporting that we're alive: */
  95. static void turn(on)
  96. int on;
  97. {
  98.   static char bars[]= "|/-\\|/-\\";
  99.   static int b= 0;
  100.  
  101.   if(on)
  102.   {
  103.     fprintf(stderr,"%c\b",bars[b++]);
  104.  
  105.     if(b >= sizeof(bars)-1)
  106.       b= 0;
  107.   }
  108.   else fprintf(stderr," \b");
  109.  
  110.   fflush(stderr);
  111. }
  112.  
  113. #endif /* DEBUG */
  114.  
  115.  
  116. /*
  117.  *
  118.  * FUNCTION
  119.  *
  120.  *   filecopy -- copy n bytes of data from one file pointer to another
  121.  *
  122.  * SYNOPSIS
  123.  *   #include "filecopy.h"
  124.  *
  125.  *   result= filecopy(src, dst, n)
  126.  *   long result;
  127.  *   long n;
  128.  *   FILE *src, *dst;
  129.  *
  130.  * DESCRIPTION
  131.  *
  132.  *   This function tries to copy 'n' bytes from given source stream 'src'
  133.  *   to the destination 'dst'.
  134.  *   If 'n' is == 0 then filecopy() will compute this value assuming that
  135.  *   all data following the current position of 'src' is ment to be copied.
  136.  *   If a copy buffer has been allocated successfully via fc_setbuf() then
  137.  *   filecopy() will take advantage of of it.  On the other hand, if no
  138.  *   buffer was allocated it will do so on it's own and tries to get either
  139.  *   'n' or (if 'n' is too large) MAXIMUM_BUFFERSIZE bytes.  (See the notes
  140.  *   about this value in "filecopy.h".)
  141.  *   If the allocation fails then filecopy() will copy your data byte for
  142.  *   byte.  Normally the number of written bytes will be returned but
  143.  *
  144.  * NOTE
  145.  *
  146.  *   This function tries to be very careful concerning errors.  If an error
  147.  *   occurs it will exit immediately returning either -1L in case of a read
  148.  *   error in the 'src' file or -2L in case of a write error with the 'dst'
  149.  *   file pointer.
  150.  *   Also filecopy() will *NOT* print out anything, even not if there was
  151.  *   an error.  (There may of course be some output if your OS feels a need
  152.  *   to do so.) It's up to the caller to use perror() or sth. similar to
  153.  *   inform the user about what went wrong.
  154.  *
  155.  * NOTE ALSO
  156.  *
  157.  *   This function assumes 'src' not to be a tty; especially not if you pass
  158.  *   n=0 with the arguments.  In other words, filecopy() will fail if seeking
  159.  *   with 'src' is impossible.
  160.  *   You can however pass a value n<0 in order to force a byte for byte
  161.  *   transfer without seeking.
  162.  *
  163.  */
  164.  
  165. long filecopy(src, dst, n)
  166. long n;
  167. FILE *src, *dst;
  168. {
  169.   long result= 0L;             /* The value returned by this function:
  170.                                 * if non-negative the #of bytes written,
  171.                                 * -1 = read error,  -2 = write error */
  172.  
  173.   unsigned long remember= 0L;  /* #of bytes allocated by *this* function */
  174.   long bytesleft= 0L;          /* #of bytes left for copying */
  175.  
  176.   if(n==0)
  177.   {
  178.     /* Compute the #of bytes left for copying */
  179.  
  180. #ifdef BUGGY_FTELL
  181.  
  182.     do {
  183.  
  184.       (void)fgetc(src);
  185.  
  186.       if(!feof(src))
  187.         ++bytesleft;
  188.  
  189.     } while(!feof(src) || ferror(src))
  190.  
  191. #else /* ftell() works fine */
  192.  
  193.     if( fseek(src,0L,2L) >= 0) /* 2 == OFFSET_END */
  194.       bytesleft= ftell(src);
  195.  
  196.     else
  197.       result= -1L;
  198.  
  199. #endif /* BUGGY_FTELL */
  200.  
  201.     if(!ferror(src) && bytesleft>0)
  202.     { 
  203.       if(fseek(src,-bytesleft,1L) < 0) /* 1 == OFFSET_CURRENT */
  204.         result= -1L;
  205.     }
  206.     else result= -1L;
  207.   }
  208.   else /* n!=0 */
  209.     bytesleft= (n > 0) ? n : 0L;
  210.  
  211.  
  212.   if(!result)
  213.   {
  214.     long nbytes= 0L;
  215.  
  216.     if(!copybuffer && bytesleft>0)
  217.     {
  218.       remember= fc_setbuf( (bytesleft > MAXIMUM_BUFFERSIZE) ?
  219.         MAXIMUM_BUFFERSIZE : bytesleft );
  220.     }
  221.  
  222.     /* If the allocation failed (or if n was negative) then we'll copy
  223.      * the data byte for byte which of course is hyper slow ;)
  224.      */
  225.  
  226.     if(!copybuffer || buffersize < 2L)
  227.     {
  228.       unsigned char c;
  229.       int done= 0;
  230.  
  231.       do {
  232.         c= fgetc(src);
  233.  
  234.         if(!feof(src))
  235.         {
  236.           fputc(c,dst);
  237.           nbytes++;
  238.  
  239.           if(n>0 && nbytes>=n)
  240.             done= 1;
  241.  
  242. #ifdef DEBUG
  243.           turn(1);
  244. #endif /* DEBUG */
  245.  
  246.         }
  247.       } while(!done && !feof(src) && !ferror(src) && !ferror(dst));
  248.  
  249.       /* This might change later when checking ferror(): */
  250.       result= nbytes;
  251.     }
  252.  
  253.     else /* use the buffer */
  254.     {
  255.       long psize;  /* packet size */
  256.  
  257.       do {
  258.         psize= (bytesleft > buffersize) ? buffersize : bytesleft;
  259.         bytesleft-= psize;
  260.  
  261.         /* I think it's a good idea to use fread() and fwrite() with
  262.          * psize packets of size 1 here instead of 1 packet of size psize
  263.          * because these functions return the number of *complete* packets
  264.          * that were read (or written).  This way we can also handle
  265.          * partial packets if needed. */
  266.  
  267.         nbytes= fread(copybuffer, 1L, psize, src);
  268.  
  269.         if(!ferror(src))
  270.         {
  271.           /* write exactly as many bytes as we read before */
  272.  
  273.           nbytes= fwrite(copybuffer, 1L, nbytes, dst);
  274.           result += nbytes;
  275.         }
  276.  
  277.         /* A partial read or written packet indicates that we're done,
  278.          * it does however not neccessarily mean that there was an error.
  279.          * Changing the result to a negative value can be done later
  280.          * by testing ferror(). */
  281.  
  282.         if(nbytes!=psize)
  283.           bytesleft= 0;
  284.  
  285. #ifdef DEBUG
  286.         turn(1);
  287. #endif
  288.  
  289.       } while(bytesleft>0 && !ferror(src) && !ferror(dst));
  290.     }
  291.  
  292.     if(ferror(src))
  293.       result= -1L;
  294.  
  295.     else if(ferror(dst))
  296.       result= -2L;
  297.   }
  298.  
  299.   /* free the copy buffer if it was allocated by us */
  300.   if(remember)
  301.     fc_setbuf(0L);
  302.  
  303. #ifdef DEBUG
  304.   turn(0);
  305. #endif
  306.  
  307.   return result;
  308. }
  309.  
  310.  
  311.