home *** CD-ROM | disk | FTP | other *** search
- /*
- CHUNK.C
-
- Program to chunk large text files up into nice little morsels for transmission
- over packet radio channels. The default morsel size is 5k.
-
- Invocation:
-
- chunk file.ext [-sxxx] [-b] [-z] [-m] where:
- file.ext is the file name to be processed
- -s is a size toggle
- xx is the size in bytes of each chunk.
- -b or -z is a control-z zapper
- -m is put message in chunkfile
-
- Chunk creates up to 26 (a-z) chunk files Each file will have the name
- file.xpk where x is a letter a-z. While not infinite, this format will
- allow files up to 130k to be transmitted using the default 5k size. Though
- the size can be increased by using the -s option, the mechanics of packet
- transmission probably renders the proposition void.
-
- The program checks the size of the input file before commencing processing to
- ensure this size limit has not been violated.
-
- This program is written for Microsoft c v4.0. With the exception of the file
- size function names, it should be portable to other environments, though
- no testing has been done.
-
- EXIT CODES:
-
- 0 OK
- 1 No file name specified.
- 2 Not enough ram.
- 3 Bad file name
- 4 Failed opening an output file name.
- 5 Failed writing an output file.
- 6 Too many chunkfiles
- 7 *DELETED* - V1.3
- 8 Internal error - Written bytes not equal to read bytes.
-
- CHUNK REVISION HISTORY:
-
- v1.0 03/01/87 John De Armond WD4OQC
- Initial creation
- v1.1 03/02/87 John De Armond
- Changed header token from ||| to ~~~. Had interaction with TNC-2
- streamsw command.
- v1.2 03/05/87 John De Armond
- Changed header to contain original file size as an integrety check for glue.
- Also put in an additional error check that compares the original filesize in
- in bytes to the actual number of bytes written in all the chunkfiles. reports a
- new error #8 if sized disagree. Small cosmetic changes to improve the user
- presentation. Changed the memory allocation function so that in the event
- there is insufficient ram, requested size is reduced in 10% increments instead
- of by half. To fix a subtle bug, reduced the possible chunkfiles to 26, A-Z,
- eliminating 0-9. Fixed a subtle bug that occured when a file ended precisely
- on a chunkfile boundary. In this case, an extra empty chunkfile was called.
- Now test for this and trap it.
- Placed a minimum chunksize limit of 500 bytes. Any less is thrashing.
-
- v1.3 03/11/87 John De Armond
- User-requested changes. Placed an fseek() call in the file size routine
- because some older compilers did not position to the end of file on
- append. Changed default chunksize to 5k. Made bragline optional via a
- command line switch. Added my call to the header line instead. Changed
- alogrithm so chunksize defaults to 5k anytime an error in chunksize
- specification is made.
-
- v1.4 03/15/87 John De Armond
- Added option to zap control Z's in the input file. This will somewhat
- slow the chunking process so use sparingly. Also added the option to
- include a memo in the beginning of the first chunkfile. Eliminated the
- bragline option. Not used much. Made Zapping Zee's the default option.
- Set up patching area so debugger or sector patcher can be used to change
- the defaults of the Zee-Zapper and memo messages.
-
- v1.5 03/21/87 John De Armond
- Fixed a subtle bug that would occur in conjuction with the w0rli bbs
- system whenever a chunk ended with a cr-lf pair split across chunks.
- BBS system would attach the needed character to make a complete cr-lf
- pair on each chunk, therefore making a 2 byte error in the 2 chunks.
- Now if NOT in z-zap mode, look at last byte in chunk and if a CR, read
- the next byte in which should be a LF and put it in the chunk.
-
- v1.6 04/17/87 John De Armond
- Fixed another subtle bug that arose when the straggler adjustment routine
- corrected the chunksize to the extent that one or more whole chunkfiles was
- eliminated. Program FUBAR'd on that. Corrected the problem.. also
- modified the straggler algorithm so that it now defines a straggler as
- 20% of a chunk size rather than a fixed 500 bytes. Thus straggler
- elimination is now proportional to chunk size.
- *************************************************************************/
-
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
-
- #define VERSION "\nCHUNK version 1.6 04/17/87\n(c) 1987 John De Armond, WD4OQC\nAll rights reserved\n"
- #define VERS "1.6"
-
- char zaphdr[] = "ZAPFLAG";
- int zap = 1; /* default to zapping */
- char memohdr[] = "MEMOFLAG";
- char memo=0;
- FILE *infile,*outfile;
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- char *optnptr;
- int infound;
- int i,j,k;
- unsigned int optneval(char *);
- char *basename(char *);
- char infilename[100],outfilename[20],workfilename[20];
- void oops();
- char *heap;
- unsigned int heapsize=5000,li,lj,workheap;
- int finished= 0,numchunks;
- char bustcntr = 'A';
- char maxcntr='A';
- long unsigned filesize,totbytes=0,remainder;
- char tempstring[82], *strptr;
- int first=1;
- int loop=1;
- int getmemo(FILE *);
-
- printf(VERSION);
-
- if (argc < 2) {
- oops();
- exit(1);
- }
-
- /* check the command line for parameters */
-
- infound = 0;
- for (i=1;i<argc;i++) {
- if ( *(optnptr = &argv[i][0]) == '-') {
- switch (*++optnptr) {
- case 's':
- case 'S':
- heapsize = optneval(optnptr); /* evaluate the option and return */
- if (heapsize > 32767) {
- heapsize = 5000; /* arbitrary limit! */
- printf("\n*** WARNING - Specified ChunkSize > 32767 bytes - Using 5,000 bytes");
- }
-
- if (heapsize < 500) {
- printf("\n\n*** WARNING - Chunksize cannot be less than 500 bytes - Using 5,000 bytes");
- heapsize = 5000;
- }
- break;
-
-
- case 'm':
- case 'M':
- if (memo)
- memo = 0;
- else
- memo = 1;
- break;
-
- case 'b': /* the option KILLS zapping for processing */
- case 'B': /* binary files */
- case 'z':
- case 'Z':
- if (zap)
- zap = 0; /* toggle the value */
- else
- zap = 1;
- break;
-
- default:
- printf("\n\n*** WARNING - Bad option on command line - %c - Ignored",*optnptr);
- break;
- } /*switch*/
-
- } else {
- if (!infound) { /* if we have not yet gotten a file name */
- strcpy(infilename,argv[i]); /* and the arguement is not an */
- infound = 1; /* option then it is the input */
- } /* file name */
- }
- }
-
- if (!infound) { /* if we did not fine a good file name in the command */
- oops(); /* line then exit bitching all the way */
- exit(1);
- }
-
- if ((infile = fopen(infilename,"rb")) == (FILE *) NULL) {
- printf("\n\n*** ERROR 3 - Filename >> %s << not found",infilename);
- printf("\nExiting ...");
- exit(3);
- } else {
- fclose(infile);
- infile = fopen(infilename,"ab"); /* open for append which seeks to the EOF */
- fseek(infile,0L,SEEK_END); /* make sure we're at the end of the file */
- filesize = ftell(infile); /* get the file length */
- fclose(infile);
- infile = fopen(infilename,"rb"); /* now open for reading */
- }
-
-
- /* now parse file name to use for embedded name and output file name */
-
- strcpy(outfilename,basename(infilename)); /* first get rid of path and drive names */
- i = 0;
- while ((outfilename[i] != '.') && (outfilename[i])) /* look for the dot or end of name */
- i++;
- outfilename[i++] = '.'; /* put a dot if not one */
- outfilename[i] = '\0';
-
-
- printf("\n\n Processing input file >> %s <<",infilename);
- printf("\n The input file size is %lu bytes",filesize);
- printf("\n The requested Chunkfile size is %u bytes",heapsize);
-
- /* now check to see if we have a straggler file */
- if ((remainder = filesize % (long unsigned) heapsize) < (heapsize / 5L)) { /* frag is 20% of chunksize */
- heapsize += remainder+1;
- }
- numchunks = (int) (filesize/(long unsigned) heapsize); /* figure out how many */
-
- /* Now allocate a heap to read the input file into. If possible,
- *allocate enuf heap to hold the whole chunksize. If not, will have to
- *process in pieces (fragmented processing not implemented) */
-
- while ((heap = malloc(heapsize+2)) == (unsigned char *) NULL)
- heapsize -= heapsize/10; /* reduce the heapsize in 10% increments til there is enuf */
- /* memory */
- if (heapsize < 500) {
- printf ("\n\n*** ERROR 2 - Not enough ram to proceed. - Exiting ... ");
- exit(2);
- }
-
- printf ("\n Adjusted ChunkFile size = %u bytes",heapsize);
- if (zap) {
- printf("\n Zapping ^Z's - TEXT mode.");
- } else {
- printf("\n BINARY processing mode.");
- }
-
- if (numchunks > 25) {
- printf("\n\n*** ERROR 6 - Chunksize selected will result in too many files - Increase");
- printf("\nchunksize and try again - Exiting ...");
- exit(6);
- }
-
- /* this fixes a problem if the file ends exactly on a chunkfile boundary */
- if ( (!(filesize % (long unsigned) heapsize)) && numchunks >1 )
- numchunks--;
-
- printf("\n Creating %d Chunkfiles\n\n",numchunks+1);
-
- maxcntr += (char) numchunks;
-
-
- /* Main processing loop - process data from input til EOF */
- while (1) {
- /* read the input file into the heap. */
- workheap = fread(heap,sizeof(char),heapsize,infile);
- if (workheap == 0)
- break; /* end of file */
-
- if (zap) { /* if we are to zap ^Z's */
- for(lj=0L;lj<workheap;lj++) {
- if (heap[lj] == '\x1a') {
- heap[lj] = ' '; /* replace it with a space */
- }
- }
- if (heap[workheap-1] == '\r') { /* if we have a cr, get */
- heap[workheap++] = fgetc(infile); /* the next char which */
- if (heap[workheap-1] != '\n') { /* should be a LF */
- printf("\n*** WARNING - A <CR> without a <LF> was found at the end of chunk %c\n",bustcntr);
- }
- }
- }
-
-
- /* got some input so lets creat a chunk filename and open it */
-
- strcpy(workfilename, outfilename); /* filename.chx starting with */
- strcat(workfilename,"CH");
- j = strlen(workfilename); /* x = A */
- workfilename[j++] = bustcntr;
- workfilename[j] = '\0';
- bustcntr++; /* for next loop */
-
- if ((outfile = fopen(workfilename,"wb")) == (FILE *) NULL) {
- printf("\n\n*** ERROR 4 - Can't open >> %s << - Disk full?? - Exiting ...",workfilename);
- exit(4);
- }
-
- if (first && memo) {
- first = 0;
- printf("\n\n*****************************************************************************");
- printf("\n Enter a memo to appear in the beginning of %s",workfilename);
- printf("\n End memo with a ^Z\n");
- getmemo(outfile);
- printf("\n");
- }
-
-
- printf("\rProcessing Chunkfile >> %s <<",workfilename);
-
- fprintf(outfile,"~~~ FcHuNk WD4OQC Vers %s File %c of %c, %s %u %lu\r\n",
- VERS,bustcntr-1,maxcntr,basename(infilename),workheap,filesize);
-
- if ((li = fwrite(heap,sizeof(char),workheap,outfile)) < workheap) {
- printf("\n\n*** ERROR 5 - Writing file >> %s << - Disk full??? - exiting ",workfilename);
- exit(5);
- }
-
- totbytes += (long unsigned) workheap; /* for a double check of file integrety */
-
- fprintf(outfile,"\r\n~~~ EnDfChUnK Vers %s\r\n",VERS);
- fclose(outfile);
-
- } /* while */
-
- if (totbytes != filesize) {
- printf("\n*** ERROR 8 - Total bytes written to chunk file not equal to ");
- printf("\n original file size. Original file - %lu bytes,");
- printf("\n Total of chunkfiles - %lu", filesize,totbytes);
- exit(8);
- }
-
- fcloseall();
- exit(0);
-
- } /* main */
- /************************* end of main program *********************/
-
- void oops()
- {
- printf("\n\n*** ERROR 1 - File name must be specified on command line");
- printf("\nUsage:\n");
- printf("CHUNK FILENAME.EXT [-sXXXX] [-b] [-m] [-z] Where:");
- printf("\n -sxxxx is an optional file chunk length, default 5k");
- if (!memo) {
- printf("\n -m Enter a memo message in the beginning of the first chunkfile.");
- } else {
- printf("\n -m Turn OFF memo message option.");
- }
- if (!zap) {
- printf("\n -z or -b ZAP control-z's in the input - Use this option for text files.");
- } else {
- printf("\n -z or -b Turns control-z zapping off. - use this option for binary files.");
- }
- printf("\n\nEXITING ...");
- return;
- }
-
- unsigned int optneval(ptr)
- char *ptr;
- {
- ++ptr; /* point to next char after option letter which should be */
- /* a space or a number */
- return ((unsigned int) atol(ptr)); /* so now convert the ascii number to an int */
- }
-
-
- /******** Return pointer to directory-less file name: *****/
- char *basename(cc)
- char *cc;
- {
- char *dd;
- dd = cc;
- for (;*cc;++cc)
- if ((*cc == '/') || (*cc == '\\') || (*cc == ':'))
- dd = cc+1;
- return (dd);
- }
-
-
- /* get a memo field */
- int getmemo(file)
- FILE *file;
- {
- char c = '\0';
- int count = 0;
- int flag;
- char buff[80];
-
- printf("\n>");
-
- while (1) {
- buff[count] = getch();
-
- switch (buff[count]) {
- case '\x1a': /* ^z */
- printf("^Z\n");
- buff[count] = '\0';
- flag = fprintf(file,"%s\r\n",buff);
- buff[0] = '\0';
- if (flag)
- return(0); /* ok writing string */
- else
- return(1); /*error in writing string */
- break;
-
- case '\r':
- case '\n':
- buff[count] = '\0';
- if (!(flag = fprintf(file,"%s\r\n",buff)))
- return(1); /* error in writing line */
-
- printf("\n>");
- buff[0] = '\0';
- count = 0;
- break;
-
- case '\b':
- count--;
- printf("\b \b");
- break;
-
- default:
- if (count == 78) {
- printf("\a");
- continue;
- } else {
- putchar(buff[count]);
- count++;
- }
-
- }
- }
- }
-
- /************* end of file ***************/
-
-
-
-
-
-