home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / FLOPPIES / CHUNK.ZIP / CHUNK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-17  |  15.7 KB  |  440 lines

  1. /* 
  2. CHUNK.C
  3.  
  4. Program to chunk large text files up into nice little morsels for transmission
  5. over packet radio channels.  The default morsel size is 5k.
  6.  
  7. Invocation:
  8.  
  9. chunk file.ext [-sxxx] [-b] [-z] [-m]     where:
  10.     file.ext    is the file name to be processed
  11.     -s          is a size toggle
  12.     xx          is the size in bytes of each chunk.
  13.     -b or -z    is a control-z zapper
  14.     -m          is put message in chunkfile
  15.  
  16. Chunk creates up to 26 (a-z) chunk files  Each file will have the name 
  17. file.xpk        where x is a letter a-z.  While not infinite, this format will 
  18. allow files up to 130k to be transmitted using the default 5k size.  Though 
  19. the size can be increased by using the -s option, the mechanics of packet 
  20. transmission probably renders the proposition void.  
  21.  
  22. The program checks the size of the input file before commencing processing to 
  23. ensure this size limit has not been violated.
  24.  
  25. This program is written for Microsoft c v4.0.  With the exception of the file 
  26. size function names, it should be portable to other environments, though
  27. no testing has been done.
  28.  
  29. EXIT CODES:
  30.  
  31. 0   OK
  32. 1   No file name specified.
  33. 2   Not enough ram.
  34. 3   Bad file name
  35. 4   Failed opening an output file name.
  36. 5   Failed writing an output file.
  37. 6   Too many chunkfiles
  38. 7   *DELETED*  -  V1.3
  39. 8   Internal error - Written bytes not equal to read bytes.
  40.  
  41. CHUNK REVISION HISTORY:
  42.  
  43. v1.0    03/01/87    John De Armond WD4OQC 
  44.     Initial creation
  45. v1.1    03/02/87    John De Armond
  46.     Changed header token from ||| to ~~~.  Had interaction with TNC-2 
  47.     streamsw command.
  48. v1.2    03/05/87    John De Armond
  49.     Changed header to contain original file size as an integrety check for glue.
  50.     Also put in an additional error check that compares the original filesize in
  51.     in bytes to the actual number of bytes written in all the chunkfiles.  reports a 
  52.     new error #8 if sized disagree. Small cosmetic changes to improve the user 
  53.     presentation.  Changed the memory allocation function so that in the event 
  54.     there is insufficient ram, requested size is reduced in 10% increments instead 
  55.     of by half.  To fix a subtle bug, reduced the possible chunkfiles to 26, A-Z,
  56.     eliminating 0-9.  Fixed a subtle bug that occured when a file ended precisely
  57.     on a chunkfile boundary.  In this case, an extra empty chunkfile was called.
  58.     Now test for this and trap it.
  59.     Placed a minimum chunksize limit of 500 bytes.  Any less is thrashing.
  60.  
  61. v1.3    03/11/87    John De Armond
  62.     User-requested changes.  Placed an fseek() call in the file size routine  
  63.     because some older compilers did not position to the end of file on 
  64.     append.  Changed default chunksize to 5k.  Made bragline optional via a 
  65.     command line switch.  Added my call to the header line instead.  Changed 
  66.     alogrithm so chunksize defaults to 5k anytime an error in chunksize 
  67.     specification is made.
  68.  
  69. v1.4    03/15/87    John De Armond
  70.     Added option to zap control Z's in the input file.  This will somewhat
  71.     slow the chunking process so use sparingly.  Also added the option to 
  72.     include a memo in the beginning of the first chunkfile. Eliminated the
  73.     bragline option.  Not used much.  Made Zapping Zee's the default option.
  74.     Set up patching area so debugger or sector patcher can be used to change
  75.     the defaults of the Zee-Zapper and memo messages.
  76.  
  77. v1.5    03/21/87    John De Armond
  78.     Fixed a subtle bug that would occur in conjuction with the w0rli bbs 
  79.     system whenever a chunk ended with a cr-lf pair split across chunks.
  80.     BBS system would attach the needed character to make a complete cr-lf
  81.     pair on each chunk, therefore making a 2 byte error in the 2 chunks.  
  82.     Now if NOT in z-zap mode, look at last byte in chunk and if a CR, read
  83.     the next byte in which should be a LF and put it in the chunk.
  84.  
  85. v1.6    04/17/87    John De Armond
  86.     Fixed another subtle bug that arose when the straggler adjustment routine
  87.     corrected the chunksize to the extent that one or more whole chunkfiles was 
  88.     eliminated.  Program FUBAR'd on that.  Corrected the problem.. also 
  89.     modified the straggler algorithm so that it now defines a straggler as 
  90.     20% of a chunk size rather than a fixed 500 bytes.  Thus straggler 
  91.     elimination is now proportional to chunk size.
  92. *************************************************************************/ 
  93.     
  94. #include <stdio.h>
  95. #include <string.h>
  96. #include <malloc.h>
  97.  
  98. #define VERSION "\nCHUNK version 1.6 04/17/87\n(c) 1987 John De Armond, WD4OQC\nAll rights reserved\n"
  99. #define VERS "1.6"
  100.  
  101. char zaphdr[] = "ZAPFLAG";
  102. int zap = 1;                    /* default to zapping */
  103. char memohdr[] = "MEMOFLAG";
  104. char memo=0;
  105. FILE *infile,*outfile;
  106.  
  107. main(argc,argv)
  108. int argc;
  109. char **argv;
  110. {
  111.     char *optnptr;
  112.     int infound;
  113.     int i,j,k;
  114.     unsigned int optneval(char *);
  115.     char *basename(char *);
  116.     char infilename[100],outfilename[20],workfilename[20];
  117.     void oops();
  118.     char *heap;
  119.     unsigned int heapsize=5000,li,lj,workheap;
  120.     int finished= 0,numchunks;
  121.     char bustcntr = 'A';
  122.     char maxcntr='A';
  123.     long unsigned filesize,totbytes=0,remainder;
  124.     char tempstring[82], *strptr;
  125.     int first=1;
  126.     int loop=1;
  127.     int getmemo(FILE *);
  128.  
  129.     printf(VERSION);
  130.  
  131.     if (argc < 2) {
  132.         oops();
  133.         exit(1);
  134.     }
  135.  
  136. /* check the command line for parameters */
  137.  
  138.     infound = 0;
  139.     for (i=1;i<argc;i++) {
  140.         if ( *(optnptr = &argv[i][0]) == '-') {
  141.             switch (*++optnptr) {
  142.                 case 's':
  143.                 case 'S':
  144.                 heapsize = optneval(optnptr);    /* evaluate the option and return */
  145.                 if (heapsize > 32767) {
  146.                     heapsize = 5000;               /* arbitrary limit!     */
  147.                     printf("\n*** WARNING - Specified ChunkSize > 32767 bytes - Using 5,000 bytes");
  148.                 }
  149.  
  150.                 if (heapsize < 500) {
  151.                     printf("\n\n*** WARNING - Chunksize cannot be less than 500 bytes - Using 5,000 bytes");
  152.                     heapsize = 5000;
  153.                 }
  154.                 break;
  155.  
  156.  
  157.                 case 'm':
  158.                 case 'M':
  159.                 if (memo) 
  160.                     memo = 0;
  161.                 else
  162.                     memo = 1;
  163.                 break;
  164.  
  165.                 case 'b':   /* the option KILLS zapping for processing */
  166.                 case 'B':   /* binary files */
  167.                 case 'z':
  168.                 case 'Z':
  169.                 if (zap)
  170.                     zap = 0;    /* toggle the value */
  171.                 else
  172.                     zap = 1;
  173.                 break;
  174.  
  175.                 default:
  176.                 printf("\n\n*** WARNING - Bad option on command line - %c - Ignored",*optnptr);
  177.                 break;
  178.             } /*switch*/
  179.  
  180.         } else {
  181.             if (!infound) {                     /* if we have not yet gotten a file name */
  182.                 strcpy(infilename,argv[i]);     /* and the arguement is not an */
  183.                 infound = 1;                    /* option then it is the input */
  184.             }                                   /* file name */
  185.         }
  186.     }
  187.  
  188.     if (!infound) {     /* if we did not fine a good file name in the command */
  189.         oops();         /* line then exit bitching all the way */
  190.         exit(1);
  191.     }
  192.  
  193.     if ((infile = fopen(infilename,"rb")) == (FILE *) NULL) {
  194.         printf("\n\n*** ERROR 3 - Filename >> %s << not found",infilename);
  195.         printf("\nExiting ...");
  196.         exit(3);
  197.     } else {
  198.         fclose(infile);
  199.         infile = fopen(infilename,"ab");    /* open for append which seeks to the EOF */
  200.         fseek(infile,0L,SEEK_END);          /* make sure we're at the end of the file */
  201.         filesize = ftell(infile);           /* get the file length */
  202.         fclose(infile);
  203.         infile = fopen(infilename,"rb");    /* now open for reading */
  204.     }
  205.  
  206.  
  207.     /* now parse file name to use for embedded name and output file name */
  208.  
  209.     strcpy(outfilename,basename(infilename));  /* first get rid of path and drive names */
  210.     i = 0;
  211.     while ((outfilename[i] != '.') && (outfilename[i])) /* look for the dot or end of name */
  212.         i++;
  213.     outfilename[i++] = '.';     /* put a dot if not one */
  214.     outfilename[i] = '\0';
  215.  
  216.  
  217.     printf("\n\n Processing input file >> %s <<",infilename);
  218.     printf("\n The input file size is %lu bytes",filesize);
  219.     printf("\n The requested Chunkfile size is %u bytes",heapsize);
  220.  
  221.     /* now check to see if we have a straggler file */
  222.     if ((remainder = filesize % (long unsigned) heapsize) < (heapsize / 5L)) {  /* frag is 20% of chunksize */
  223.         heapsize += remainder+1;
  224.     }
  225.     numchunks = (int) (filesize/(long unsigned) heapsize);        /* figure out how many */ 
  226.  
  227.     /* Now allocate a heap to read the input file into.  If possible, 
  228.      *allocate enuf heap to hold the whole chunksize.  If not, will have to 
  229.      *process in pieces (fragmented processing not implemented) */
  230.  
  231.     while ((heap =  malloc(heapsize+2)) == (unsigned char *) NULL)
  232.         heapsize -= heapsize/10;    /* reduce the heapsize in 10% increments til there is enuf */
  233.                                     /* memory */
  234.     if (heapsize < 500) {
  235.         printf ("\n\n*** ERROR 2 - Not enough ram to proceed. - Exiting ... ");
  236.         exit(2);
  237.     }
  238.  
  239.     printf ("\n Adjusted ChunkFile size = %u bytes",heapsize);
  240.     if (zap) {
  241.         printf("\n Zapping ^Z's - TEXT mode.");
  242.     } else {
  243.         printf("\n BINARY processing mode.");
  244.     }
  245.  
  246.     if (numchunks > 25) {                                    
  247.         printf("\n\n*** ERROR 6 - Chunksize selected will result in too many files - Increase");
  248.         printf("\nchunksize and try again - Exiting ...");
  249.         exit(6);
  250.     }
  251.  
  252.     /* this fixes a problem if the file ends exactly on a chunkfile boundary */
  253.     if ( (!(filesize % (long unsigned) heapsize)) && numchunks >1 )
  254.         numchunks--;
  255.  
  256.     printf("\n Creating %d Chunkfiles\n\n",numchunks+1);
  257.  
  258.     maxcntr += (char) numchunks;                    
  259.  
  260.     
  261.     /* Main processing loop - process data from input til EOF */
  262.     while (1) {
  263.         /* read the input file into the heap. */
  264.         workheap = fread(heap,sizeof(char),heapsize,infile);
  265.         if (workheap == 0) 
  266.             break;                  /* end of file */
  267.  
  268.         if (zap) {                          /* if we are to zap ^Z's */
  269.             for(lj=0L;lj<workheap;lj++) {
  270.                 if (heap[lj] == '\x1a') {
  271.                     heap[lj] = ' ';         /* replace it with a space */
  272.                 }
  273.             }
  274.             if (heap[workheap-1] == '\r') {       /* if we have a cr, get */
  275.                 heap[workheap++] = fgetc(infile); /* the next char which  */
  276.                 if (heap[workheap-1] != '\n') {   /* should be a LF       */
  277.                     printf("\n*** WARNING - A <CR> without a <LF> was found at the end of chunk %c\n",bustcntr);
  278.                 }
  279.             }
  280.         }
  281.  
  282.  
  283.         /* got some input so lets creat a chunk filename  and open it */
  284.     
  285.         strcpy(workfilename, outfilename);  /* filename.chx starting with */
  286.         strcat(workfilename,"CH");
  287.         j = strlen(workfilename);           /* x = A */
  288.         workfilename[j++] = bustcntr;
  289.         workfilename[j] = '\0';
  290.         bustcntr++;                 /* for next loop */
  291.  
  292.         if ((outfile = fopen(workfilename,"wb")) == (FILE *) NULL) {
  293.             printf("\n\n*** ERROR 4 - Can't open >> %s << - Disk full?? - Exiting ...",workfilename);
  294.             exit(4);
  295.         }
  296.  
  297.         if (first && memo) {
  298.             first = 0;
  299.             printf("\n\n*****************************************************************************");
  300.             printf("\n             Enter a memo to appear in the beginning of %s",workfilename);
  301.             printf("\n             End memo with a ^Z\n");
  302.             getmemo(outfile);
  303.             printf("\n");
  304.         }
  305.  
  306.  
  307.         printf("\rProcessing Chunkfile >> %s <<",workfilename);
  308.  
  309.         fprintf(outfile,"~~~ FcHuNk WD4OQC Vers %s File %c of %c, %s %u %lu\r\n",
  310.           VERS,bustcntr-1,maxcntr,basename(infilename),workheap,filesize);
  311.  
  312.         if ((li = fwrite(heap,sizeof(char),workheap,outfile)) < workheap) {
  313.             printf("\n\n*** ERROR 5 - Writing file >> %s << - Disk full??? - exiting ",workfilename);
  314.             exit(5);
  315.         }
  316.  
  317.         totbytes += (long unsigned) workheap;       /* for a double check of file integrety */
  318.  
  319.         fprintf(outfile,"\r\n~~~ EnDfChUnK Vers %s\r\n",VERS);
  320.         fclose(outfile);
  321.  
  322.     } /* while */
  323.  
  324.     if (totbytes != filesize) {
  325.         printf("\n*** ERROR 8 - Total bytes written to chunk file not equal to ");
  326.         printf("\n              original file size.  Original file - %lu bytes,");
  327.         printf("\n              Total of chunkfiles - %lu", filesize,totbytes);
  328.         exit(8);
  329.     }
  330.  
  331.     fcloseall();
  332.     exit(0);
  333.  
  334. } /* main */
  335. /************************* end of main program *********************/
  336.  
  337. void oops()
  338. {
  339.     printf("\n\n*** ERROR 1 - File name must be specified on command line");
  340.     printf("\nUsage:\n");
  341.     printf("CHUNK FILENAME.EXT [-sXXXX] [-b] [-m] [-z]  Where:");
  342.     printf("\n  -sxxxx    is an optional file chunk length, default 5k");
  343.     if (!memo) {
  344.         printf("\n  -m        Enter a memo message in the beginning of the first chunkfile.");
  345.     } else {
  346.         printf("\n  -m        Turn OFF memo message option.");
  347.     }
  348.     if (!zap) {
  349.         printf("\n  -z or -b  ZAP control-z's in the input - Use this option for text files.");
  350.     } else {
  351.         printf("\n  -z or -b  Turns control-z zapping off. - use this option for binary files.");
  352.     }
  353.     printf("\n\nEXITING ...");
  354.     return;
  355. }
  356.  
  357. unsigned int optneval(ptr)
  358. char *ptr;
  359. {
  360.     ++ptr;      /* point to next char after option letter which should be */
  361.                 /* a space or a number */
  362.     return ((unsigned int) atol(ptr)); /* so now convert the ascii number to an int */
  363. }
  364.  
  365.  
  366. /******** Return pointer to directory-less file name: *****/
  367. char *basename(cc)
  368.  char *cc;
  369. {
  370.     char *dd;
  371.     dd = cc;
  372.     for (;*cc;++cc) 
  373.        if ((*cc == '/') || (*cc == '\\') || (*cc == ':'))   
  374.            dd = cc+1;                           
  375.     return (dd);                                  
  376. }
  377.  
  378.  
  379. /* get a memo field */
  380. int getmemo(file)
  381. FILE *file;
  382. {
  383.     char c = '\0';
  384.     int count = 0;
  385.     int flag;
  386.     char buff[80];
  387.  
  388.     printf("\n>");
  389.  
  390.     while (1) {
  391.         buff[count] = getch();
  392.  
  393.         switch (buff[count]) {
  394.             case '\x1a':        /* ^z */
  395.                 printf("^Z\n");
  396.                 buff[count] = '\0';
  397.                 flag = fprintf(file,"%s\r\n",buff);
  398.                 buff[0] = '\0';
  399.                 if (flag)
  400.                     return(0);      /* ok writing string */
  401.                 else
  402.                     return(1);      /*error in writing string */
  403.                 break;
  404.  
  405.             case '\r':
  406.             case '\n':
  407.                 buff[count] = '\0';
  408.                 if (!(flag = fprintf(file,"%s\r\n",buff)))
  409.                     return(1);      /* error in writing line */
  410.  
  411.                 printf("\n>");
  412.                 buff[0] = '\0';
  413.                 count = 0;
  414.                 break;
  415.  
  416.             case '\b':
  417.                 count--;
  418.                 printf("\b \b");
  419.                 break;
  420.  
  421.             default:
  422.                 if (count == 78) {
  423.                     printf("\a");
  424.                     continue;
  425.                 } else {
  426.                     putchar(buff[count]);
  427.                     count++;
  428.                 }
  429.  
  430.         }
  431.     }
  432. }
  433.  
  434. /************* end of file ***************/
  435.  
  436.  
  437.  
  438.  
  439.  
  440.