home *** CD-ROM | disk | FTP | other *** search
- /*
- GLUE.C
-
- Program to glue CHUNKed Chunkfiles back together inot the original large text
- files. Program designed to work with CHUNK.c
-
- Invocation:
-
- glue file.ext where:
- file.ext is the file name to be processed. Note: the .ext is ignored.
- Glue supplies the proper .ext
-
- Glue checks to see of all chunkfiles are present before proceeding.
-
-
- 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 no header
- 7 Bad opening header
- 8 Corrupted Chunkfile
- 9 Header file size disagrees with actual file size
-
- GLUE REVISION HISTORY:
-
- v1.0 03/01/87 John De Armond WD4OQC
- Initial creation
- v1.1 03/03/87 John De Armond
- Changed the beginning token from ||| to ~~~ to fix an interaction with
- the TNC-2 streamsw character.
- v1.2 03/05/87 John De Armond
- Added the ability to check the original file size from a new header added
- to the header. Also changed the processing algorithm so that memory buffers
- are now allocated for each file instead of only at the beginning.. this
- will allow the processing of files in which the first file may be smaller
- than the subsequence ones.. To fix a subtle bug and make life easier for
- me, reduced the possible chunkfiles to 26, A-Z, eliminating 0-9.
- v1.3 03/11/87 John De Armond
- Changed the header parser to recognize the new v1.3 chunker headerline.
- Maintained compatibility with v1.2 files. Added the ability to specify
- an outfile name on the command line. This overrides the filename in
- the chunkfile header. Cleaned up some misc garbage in source file.
- v1.4 03/14/87 John De Armond
- Added a "force" option that will allow the user to force decoding and
- ignore errors. specified with a -i option for "ignore" errors. GLUE
- also now displays any text it finds before the opening token in the
- first chunkfile. This is to allow the user to read any message that
- may be attached to the beginning of the chunkfile series
-
- *************************************************************************/
-
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
-
- #define VERSION "\nGlue version 1.4 03/15/87\n(c) 1987 John De Armond, WD4OQC\nAll rights reserved\n"
- #define VERS "1.4"
- #define EXIT 1
- #define NOEXIT 0
-
-
- #define LINT_ARGS
- FILE *infile,*outfile;
- char instring[250];
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- char *optnptr;
- int infound;
- int i,j,k;
- char *basename(char *);
- char infilename[100],outfilename[100],workfilename[20];
- void oops();
- char *heap;
- unsigned int heapsize,li,workheap;
- int finished= 0,numchunks;
- char bustcntr = 'A';
- char maxcntr='A';
- long filesize;
- char temp,getche(),c,d;
- char chunkvers[5];
- long unsigned orgsize,totbytes=0;
- int tempi,outarg;
- long current;
- static char chkvers[]= VERS;
- int ignore = 0;
- void qexit(int,int);
-
-
- printf(VERSION);
-
- if (argc < 2) {
- oops();
- exit(1);
- }
-
- /* check the command line for parameters */
- infound = 0;
- for (i=1;i<argc;i++) {
- if ( (optnptr = strchr(argv[i],'-')) != (char *) NULL) {
- switch (argv[i][1]) {
- case 'i':
- case 'I':
- ignore = 1;
- printf("\n\n*** CAUTION - Ignoring any possible errors in chunkfiles");
- break;
- }
- } else { /* is not a "-" option */
- 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 */
- outarg = 0; /* file name */
- } else {
- outarg = i; /* flag this argv as an outfile name override*/
- }
- }
- }
-
- if (!infound) { /* if we did not fine a good file name in the command */
- oops(); /* line then exit bitching all the way */
- qexit(1,EXIT);
- }
-
- /* now parse file name to use for embedded name and output file name */
- i = 0;
- while ((infilename[i] != '.') && (infilename[i]))
- i++;
- infilename[i++] = '.';
- infilename[i] = '\0';
-
- printf("\n\nChecking for Chunkfiles - Standby ...\n\n");
-
- /* check to see if the first chunkfile, CHA, is present */
- strcpy(workfilename,infilename);
- strcat(workfilename,"CHA");
- if ((infile = fopen(workfilename,"rb")) == (FILE *) NULL) {
- printf("\n\n*** ERROR 3 - First chunkfile,>> %s << not found",workfilename);
- printf("\nExiting ...");
- qexit(3,EXIT);
- }
-
- printf("******* Memo ******\n");
- /* step thru the file til the opening token, ~, is found */
- while (((temp = fgetc(infile)) != '~') && (temp != EOF)) {
- putch((int)temp); /* will display any messages attached to the first chunkfile */
- }
- if (feof(infile)) {
- printf("\n\n*** ERROR 6 - Opening header not found - Maybe not a CHUNK file? - Exiting ...");
- qexit(6,EXIT);
- }
-
-
- /* if here, then we've found the opening token so lets parse it. */
- /* NOTE: this algorithm is designed to maintain compatability with */
- /* version 1.2 CHUNK. It first checks for the current version header */
- /* and if not found, then rechecks for v1.2. If neither are found, */
- /* it exits with a gripe. Version 1.2 is the transition between header */
- /* structures */
-
- current = ftell(infile); /* we'll need this for later */
- if ((tempi = fscanf(infile,"~~ FcHuNk WD4OQC Vers %s File %c of %c, %s %ui",
- chunkvers,&bustcntr,&maxcntr,outfilename,&heapsize)) != 5 ) {
- fseek(infile,current,SEEK_SET); /* go back to where we were */
- strcpy(chkvers,"1.2");
- if ((tempi = fscanf(infile,"~~ FcHuNk Vers %s File %c of %c, %s %ui",
- chunkvers,&bustcntr,&maxcntr,outfilename,&heapsize)) != 5 ) {
- printf("\n\n*** ERROR 8a - Invalid Beginning token found in first file - Exiting ...");
- qexit(8,EXIT);
- }
- }
-
- /* workaround for an apparent bug in fscanf(). Refuses to scan more than*/
- /* 5 variables at a time, so must scan in 2 passes. This code is common */
- /* to both v1.2 and subsequent releases */
- if ((tempi = fscanf(infile," %lu",&orgsize)) != 1 ) {
- printf("\n\n*** ERROR 8b - Invalid original file size found");
- if (ignore) {
- qexit(8,NOEXIT);
- while (fgetc(infile) != '\n') /* dump rest of header that */
- ; /* scanf would have missed */
- } else {
- qexit(8,EXIT);
- }
- }
- fclose(infile); /* will reopen as part of the loop below */
-
- /* code version comparison routine here */
-
- /* lets see if all the chunkfiles are here */
- k = 0;
- for (c=bustcntr;c<=maxcntr;) {
- strcpy(workfilename, infilename); /* filename.chx starting with */
- strcat(workfilename,"CH");
- j = strlen(workfilename); /* x = A */
- workfilename[j++] = c;
- workfilename[j] = '\0';
- c++; /* for next loop */
-
- if ((infile = fopen(workfilename,"rb")) == (FILE *) NULL) {
- printf("\n*** ERROR 3 - Chunkfile >> %s << not found",workfilename);
- k = 1;
- } else
- fclose(infile);
- }
-
- if (k) {
- exit(3,EXIT);
- }
-
- printf("\n\nChunkfiles ok ...");
- printf("\nProcessing Chunk Version %s files",chunkvers);
-
-
- /* if out filename specified on command line, override the chunkfile name */
- if (outarg) {
- strcpy(outfilename,argv[outarg]);
- }
-
- /* check for duplicate output name and grouse if so */
- while ((outfile = fopen(outfilename,"r")) != (FILE *) NULL) {
- printf("\nOutput file >> %s << exists, overwrite (Y/N)?",outfilename);
- temp = getche();
- if ((temp == 'y') || (temp == 'Y')) {
- fclose(outfile);
- break;
- } else {
- fclose(outfile);
- printf("\n Enter new output filename -->");
- gets(outfilename);
- }
- }
-
-
- /* open outfile */
- if ((outfile = fopen(outfilename,"wb")) == (FILE *) NULL) {
- printf("\n*** ERROR 4 - Can't open output file >> %s << - Disk full???",outfilename);
- qexit(4,EXIT);
- }
-
- printf("\n\nRecreating >> %s <<",outfilename);
- printf("\nOriginal filesize is %lu\n\n", orgsize);
-
- /* main processing loop */
- for (c='A';c<=maxcntr;) {
-
- strcpy(workfilename, infilename); /* filename.chx starting with */
- strcat(workfilename,"CH");
- j = strlen(workfilename); /* x = A */
- workfilename[j++] = c;
- workfilename[j] = '\0';
- c++; /* for next loop */
-
- if ((infile = fopen(workfilename,"rb")) == (FILE *) NULL) {
- printf("\n\n*** ERROR 3 - Chunkfile >> %s << not found",workfilename);
- qexit(3,EXIT);
- }
-
- /* step thru the file til the opening token, | is found */
- while (((temp = fgetc(infile)) != '~') && (temp != EOF))
- ;
- if (feof(infile)) {
- printf("\n\n*** ERROR 8 - Opening header not found - Maybe not a CHUNK file?");
- qexit(6,EXIT);
- }
-
- /* if here, then we've found the opening token so lets parse it. */
- fgets(instring,249,infile);
- if (!strcmp(chkvers,VERS)) { /* handle version 1.2 header */
- if (sscanf(instring,"~~ FcHuNk WD4OQC Vers %s File %*c of %*c, %*s %ui",chunkvers,&heapsize) != 2 ) {
- printf("\n\n*** ERROR - 8c Invalid Beginning token found.");
- qexit(8,EXIT);
- }
- } else {
- if (sscanf(instring,"~~ FcHuNk Vers %s File %*c of %*c, %*s %ui",chunkvers,&heapsize) != 2 ) {
- printf("\n\n*** ERROR - 8c Invalid Beginning token found.");
- qexit(8,EXIT);
- }
- }
-
- /* code version conversion routine here */
-
-
- /* Now allocate a heap to read the input file into. Must have enough heap
- space to hold the whole chunksize. */
-
- if ((heap = malloc(heapsize)) == (unsigned char *) NULL) {
- printf ("\n\n*** ERROR 2 - Not enough ram to proceed.");
- qexit(2,EXIT);
- }
-
- printf("\rProcessing file >> %s <<, chunksize = %6.u ",workfilename,heapsize);
-
- /* read the input file into the heap. */
- workheap = fread(heap,sizeof(char),heapsize,infile);
- if (workheap != heapsize) {
- printf("\n*** ERROR 9 - Chunkfile >> %s << appears to be corrupted, file too short.",workfilename);
- if (ignore) {
- qexit(9,NOEXIT);
- } else {
- qexit(9,EXIT);
- }
- }
-
- totbytes += (long unsigned) workheap; /* yet another error check */
-
- /* write that little puppy out */
- if ((li = fwrite(heap,sizeof(char),workheap,outfile)) < workheap) {
- printf("\n\n*** ERROR 5 - Writing file >> %s << - Disk full???",workfilename);
- qexit(5,EXIT);
- }
-
- /* now check for end token */
- d = fgetc(infile);
- d = fgetc(infile); /* skip over the \r\n immediately before end token */
-
- if ((k = fscanf(infile,"~~~ EnDfChUnK Vers %s",instring)) == 0) {
- printf("\n*** ERROR 10 - Chunkfile >> %s << appears to be corrupted,",workfilename);
- printf("\n File too long.");
- if (ignore) {
- qexit(10,NOEXIT);
- while ((temp = fgetc(infile)) != EOF) { /* push everything out til */
- fputc(outfile); /* end of chunkfile */
- totbytes++; /* and count them */
- }
- } else {
- qexit(10,EXIT);
- }
- }
-
- fclose(infile);
-
- free(heap);
-
- } /* while */
-
- if (totbytes != orgsize) {
- printf("\n*** ERROR 11 - Total bytes read from chunk file not equal to ");
- printf("\n original file size. Original file - %lu bytes,",orgsize);
- printf("\n Total of chunkfiles - %lu",totbytes);
- }
-
- fcloseall();
- exit(0);
-
- } /* main */
- /************************* end of main program *********************/
-
- /*queried exit */
- void qexit(code,mode)
- int code,mode;
- {
- char temp;
- if (mode) {
- printf("\n EXITING ...");
- fcloseall();
- exit(code);
- }
-
- while (1) {
- printf("\n\n Do you want to (A)bort or (C)ontinue? ");
- temp = getche();
- if (toupper(temp) == 'A') {
- printf("\n\n EXITING ...");
- fcloseall();
- exit(code);
- }
- if (toupper(temp) == 'C') {
- return;
- }
- }
- }
-
-
- void oops()
- {
- printf("\n\n*** ERROR 1 - File name must be specified on command line");
- printf("\n Usage:\n");
- printf(" GLUE FILENAME [OUTFILE] [-i] Where:");
- printf("\n FILENAME is the CHUNKed file's chunkfile name");
- printf("\n OUTFILE is an optional output file name that will override the name");
- printf("\n embedded in the chunkfiles.");
- printf("\n -i Tells GLUE to ignore any errors it may find in the chunkfiles");
- printf("\n Any file extension on FILENAME is ignored. The chunkfiles must end in CHx");
- printf("\n\nEXITING ...\n");
- return;
- }
-
-
- /* 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);
- }
-
-
- /************* end of file ***************/
-
-