home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / FLOPPIES / CHUNK.ZIP / GLUE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-03-22  |  14.4 KB  |  416 lines

  1. /* 
  2. GLUE.C
  3.  
  4. Program to glue CHUNKed Chunkfiles back together inot the original large text 
  5. files.  Program designed to work with CHUNK.c
  6.  
  7. Invocation:
  8.  
  9. glue file.ext   where:
  10.     file.ext    is the file name to be processed.  Note: the .ext is ignored.
  11.                 Glue supplies the proper .ext
  12.  
  13. Glue checks to see of all chunkfiles are present before proceeding.
  14.  
  15.  
  16. This program is written for Microsoft c v4.0.  With the exception of the file 
  17. size function names, it should be portable to other environments, though
  18. no testing has been done.
  19.  
  20. EXIT CODES:
  21.  
  22. 0   OK
  23. 1   No file name specified.
  24. 2   Not enough ram.
  25. 3   Bad file name
  26. 4   Failed opening an output file name.
  27. 5   Failed writing an output file.
  28. 6   no header
  29. 7   Bad opening header
  30. 8   Corrupted Chunkfile
  31. 9   Header file size disagrees with actual file size
  32.  
  33. GLUE REVISION HISTORY:
  34.  
  35. v1.0    03/01/87    John De Armond WD4OQC 
  36.     Initial creation
  37. v1.1    03/03/87    John De Armond
  38.     Changed the beginning token from ||| to ~~~ to fix an interaction with
  39.     the TNC-2 streamsw character.
  40. v1.2    03/05/87    John De Armond
  41.     Added the ability to check the original file size from a new header added
  42.     to the header.  Also changed the processing algorithm so that memory buffers
  43.     are now allocated for each file instead of only at the beginning.. this 
  44.     will allow the processing of files in which the first file may be smaller
  45.     than the subsequence ones..  To fix a subtle bug and make life easier for
  46.     me, reduced the possible chunkfiles to 26, A-Z, eliminating 0-9.
  47. v1.3    03/11/87    John De Armond
  48.     Changed the header parser to recognize the new v1.3 chunker headerline.
  49.     Maintained compatibility with v1.2 files. Added the ability to specify 
  50.     an outfile name on the command line.  This overrides the filename in
  51.     the chunkfile header.  Cleaned up some misc garbage in source file.
  52. v1.4    03/14/87    John De Armond
  53.     Added a "force" option that will allow the user to force decoding and
  54.     ignore errors. specified with a -i option for "ignore" errors.  GLUE
  55.     also now displays any text it finds before the opening token in the 
  56.     first chunkfile.  This is to allow the user to read any message that
  57.     may be attached to the beginning of the chunkfile series
  58.  
  59. *************************************************************************/
  60.  
  61. #include <stdio.h>
  62. #include <string.h>
  63. #include <malloc.h>
  64.  
  65. #define VERSION "\nGlue version 1.4 03/15/87\n(c) 1987 John De Armond, WD4OQC\nAll rights reserved\n"
  66. #define VERS "1.4"
  67. #define EXIT 1
  68. #define NOEXIT 0
  69.  
  70.  
  71. #define LINT_ARGS
  72. FILE *infile,*outfile;
  73. char instring[250];
  74.  
  75. main(argc,argv)
  76. int argc;
  77. char **argv;
  78. {
  79.     char *optnptr;
  80.     int infound;
  81.     int i,j,k;
  82.     char *basename(char *);
  83.     char infilename[100],outfilename[100],workfilename[20];
  84.     void oops();
  85.     char *heap;
  86.     unsigned int heapsize,li,workheap;
  87.     int finished= 0,numchunks;
  88.     char bustcntr = 'A';
  89.     char maxcntr='A';
  90.     long filesize;
  91.     char temp,getche(),c,d;
  92.     char chunkvers[5];
  93.     long unsigned orgsize,totbytes=0;
  94.     int tempi,outarg;
  95.     long current;
  96.     static char chkvers[]= VERS;
  97.     int ignore = 0;
  98.     void qexit(int,int);
  99.  
  100.  
  101.     printf(VERSION);
  102.  
  103.     if (argc < 2) {
  104.         oops();
  105.         exit(1);
  106.     }
  107.  
  108.     /* check the command line for parameters */
  109.     infound = 0;
  110.     for (i=1;i<argc;i++) {
  111.         if ( (optnptr = strchr(argv[i],'-')) != (char *) NULL) {
  112.             switch (argv[i][1]) {
  113.             case 'i':
  114.             case 'I':
  115.                 ignore = 1;
  116.                 printf("\n\n*** CAUTION - Ignoring any possible errors in chunkfiles");
  117.                 break;
  118.             }
  119.         } else {                                /* is not a "-" option */
  120.             if (!infound) {                     /* if we have not yet gotten a file name */
  121.                 strcpy(infilename,argv[i]);     /* and the arguement is not an */
  122.                 infound = 1;                    /* option then it is the input */
  123.                 outarg = 0;                     /* file name */
  124.             } else {                            
  125.                 outarg = i;                     /* flag this argv as an outfile name override*/
  126.             }
  127.         }
  128.     }
  129.  
  130.     if (!infound) {     /* if we did not fine a good file name in the command */
  131.         oops();         /* line then exit bitching all the way */
  132.         qexit(1,EXIT);
  133.     }
  134.  
  135.     /* now parse file name to use for embedded name and output file name */
  136.     i = 0;
  137.     while ((infilename[i] != '.') && (infilename[i]))
  138.         i++;
  139.     infilename[i++] = '.';
  140.     infilename[i] = '\0';
  141.  
  142.     printf("\n\nChecking for Chunkfiles - Standby ...\n\n");
  143.     
  144.     /* check to see if the first chunkfile, CHA, is present */
  145.     strcpy(workfilename,infilename);
  146.     strcat(workfilename,"CHA");
  147.     if ((infile = fopen(workfilename,"rb")) == (FILE *) NULL) {
  148.         printf("\n\n*** ERROR 3 - First chunkfile,>> %s << not found",workfilename);
  149.         printf("\nExiting ...");
  150.         qexit(3,EXIT);
  151.     } 
  152.  
  153.     printf("******* Memo ******\n");
  154.     /* step thru the file til the opening token, ~, is found */
  155.     while (((temp = fgetc(infile)) != '~') && (temp != EOF)) {
  156.         putch((int)temp);   /* will display any messages attached to the first chunkfile */
  157.     }
  158.     if (feof(infile)) {
  159.         printf("\n\n*** ERROR 6 - Opening header not found - Maybe not a CHUNK file? - Exiting ...");
  160.         qexit(6,EXIT);
  161.     }  
  162.  
  163.  
  164.     /* if here, then we've found the opening token so lets parse it.        */
  165.     /* NOTE: this algorithm is designed to maintain compatability with      */
  166.     /* version 1.2 CHUNK.  It first checks for the current version header   */
  167.     /* and if not found, then rechecks for v1.2.  If neither are found,     */
  168.     /* it exits with a gripe.  Version 1.2 is the transition between header */
  169.     /* structures                                                           */
  170.  
  171.     current = ftell(infile);    /* we'll need this for later */
  172.     if ((tempi = fscanf(infile,"~~ FcHuNk WD4OQC Vers %s File %c of %c, %s %ui",
  173.                   chunkvers,&bustcntr,&maxcntr,outfilename,&heapsize)) != 5 ) {
  174.         fseek(infile,current,SEEK_SET); /* go back to where we were */
  175.         strcpy(chkvers,"1.2");
  176.         if ((tempi = fscanf(infile,"~~ FcHuNk Vers %s File %c of %c, %s %ui",
  177.                   chunkvers,&bustcntr,&maxcntr,outfilename,&heapsize)) != 5 ) {
  178.             printf("\n\n*** ERROR 8a - Invalid Beginning token found in first file - Exiting ...");
  179.             qexit(8,EXIT);
  180.         }
  181.     }
  182.  
  183.     /* workaround for an apparent bug in fscanf().  Refuses to scan more than*/
  184.     /*  5 variables at a time, so must scan in 2 passes. This code is common */
  185.     /*  to both v1.2 and subsequent releases                                 */
  186.     if ((tempi = fscanf(infile," %lu",&orgsize)) != 1 ) {
  187.         printf("\n\n*** ERROR 8b - Invalid original file size found");
  188.         if (ignore) {
  189.             qexit(8,NOEXIT);
  190.             while (fgetc(infile) != '\n')   /* dump rest of header that */
  191.                 ;                           /* scanf would have missed  */
  192.         } else {
  193.             qexit(8,EXIT);
  194.         }
  195.     }
  196.     fclose(infile);     /* will reopen as part of the loop below */
  197.  
  198.     /* code version comparison routine here */
  199.  
  200.     /* lets see if all the chunkfiles are here */
  201.     k = 0;
  202.     for (c=bustcntr;c<=maxcntr;) {
  203.         strcpy(workfilename, infilename);  /* filename.chx starting with */
  204.         strcat(workfilename,"CH");
  205.         j = strlen(workfilename);           /* x = A */
  206.         workfilename[j++] = c;
  207.         workfilename[j] = '\0';
  208.         c++;                     /* for next loop */
  209.  
  210.         if ((infile = fopen(workfilename,"rb")) == (FILE *) NULL) {
  211.             printf("\n*** ERROR 3 - Chunkfile >> %s << not found",workfilename);
  212.             k = 1;
  213.         } else 
  214.             fclose(infile);
  215.     }
  216.  
  217.     if (k) {
  218.         exit(3,EXIT);
  219.     }
  220.  
  221.     printf("\n\nChunkfiles ok ...");
  222.     printf("\nProcessing Chunk Version %s files",chunkvers);
  223.  
  224.  
  225.     /* if out filename specified on command line, override the chunkfile name */
  226.     if (outarg) {
  227.         strcpy(outfilename,argv[outarg]);
  228.     }
  229.  
  230.     /* check for duplicate output name and grouse if so */
  231.     while ((outfile = fopen(outfilename,"r")) != (FILE *) NULL) {
  232.         printf("\nOutput file >> %s << exists, overwrite (Y/N)?",outfilename);
  233.         temp = getche();
  234.         if ((temp == 'y') || (temp == 'Y')) {
  235.             fclose(outfile);
  236.             break;
  237.         } else {
  238.             fclose(outfile);
  239.             printf("\n Enter new output filename -->");
  240.             gets(outfilename);
  241.         }
  242.     }
  243.  
  244.     
  245.     /* open outfile */
  246.     if ((outfile = fopen(outfilename,"wb")) == (FILE *) NULL) {
  247.         printf("\n*** ERROR 4 - Can't open output file >> %s << - Disk full???",outfilename);
  248.         qexit(4,EXIT);
  249.     }
  250.  
  251.     printf("\n\nRecreating >> %s <<",outfilename);
  252.     printf("\nOriginal filesize is %lu\n\n", orgsize);
  253.  
  254.     /* main processing loop */
  255.     for (c='A';c<=maxcntr;) {
  256.  
  257.         strcpy(workfilename, infilename);  /* filename.chx starting with */
  258.         strcat(workfilename,"CH");
  259.         j = strlen(workfilename);          /* x = A */
  260.         workfilename[j++] = c;
  261.         workfilename[j] = '\0';
  262.         c++;                               /* for next loop */
  263.  
  264.         if ((infile = fopen(workfilename,"rb")) == (FILE *) NULL) {
  265.             printf("\n\n*** ERROR 3 - Chunkfile >> %s << not found",workfilename);
  266.             qexit(3,EXIT);
  267.         } 
  268.  
  269.         /* step thru the file til the opening token, | is found */
  270.         while (((temp = fgetc(infile)) != '~') && (temp != EOF)) 
  271.             ;
  272.         if (feof(infile)) {
  273.             printf("\n\n*** ERROR 8 - Opening header not found - Maybe not a CHUNK file?");
  274.             qexit(6,EXIT);
  275.         }
  276.  
  277.         /* if here, then we've found the opening token so lets parse it. */
  278.         fgets(instring,249,infile);
  279.         if (!strcmp(chkvers,VERS)) {     /* handle version 1.2 header */
  280.             if (sscanf(instring,"~~ FcHuNk WD4OQC Vers %s File %*c of %*c, %*s %ui",chunkvers,&heapsize) != 2 ) {
  281.                 printf("\n\n*** ERROR - 8c Invalid Beginning token found.");
  282.                 qexit(8,EXIT);
  283.             }
  284.         } else {
  285.             if (sscanf(instring,"~~ FcHuNk Vers %s File %*c of %*c, %*s %ui",chunkvers,&heapsize) != 2 ) {
  286.                 printf("\n\n*** ERROR - 8c Invalid Beginning token found.");
  287.                 qexit(8,EXIT);
  288.             }
  289.         }
  290.  
  291.         /* code version conversion routine here */
  292.  
  293.  
  294.         /* Now allocate a heap to read the input file into.  Must have enough heap
  295.            space to hold the whole chunksize.  */
  296.  
  297.         if ((heap = malloc(heapsize)) == (unsigned char *) NULL) {
  298.             printf ("\n\n*** ERROR 2 - Not enough ram to proceed.");
  299.             qexit(2,EXIT);
  300.         }
  301.  
  302.         printf("\rProcessing file >> %s <<, chunksize = %6.u ",workfilename,heapsize);
  303.  
  304.         /* read the input file into the heap. */
  305.         workheap = fread(heap,sizeof(char),heapsize,infile);
  306.         if (workheap != heapsize) {
  307.             printf("\n*** ERROR 9 - Chunkfile >> %s << appears to be corrupted, file too short.",workfilename);
  308.             if (ignore) {
  309.                 qexit(9,NOEXIT);
  310.             } else {
  311.                 qexit(9,EXIT);
  312.             }
  313.         }
  314.  
  315.         totbytes += (long unsigned) workheap;   /* yet another error check */
  316.  
  317.         /* write that little puppy out */
  318.         if ((li = fwrite(heap,sizeof(char),workheap,outfile)) < workheap) {
  319.             printf("\n\n*** ERROR 5 - Writing file >> %s << - Disk full???",workfilename);
  320.             qexit(5,EXIT);
  321.         }
  322.  
  323.         /* now check for end token */
  324.         d = fgetc(infile); 
  325.         d = fgetc(infile);   /* skip over the \r\n immediately before end token */
  326.  
  327.         if ((k = fscanf(infile,"~~~ EnDfChUnK Vers %s",instring)) == 0) {
  328.             printf("\n*** ERROR 10 - Chunkfile >> %s << appears to be corrupted,",workfilename);
  329.             printf("\n               File too long.");
  330.             if (ignore) {
  331.                 qexit(10,NOEXIT);
  332.                 while ((temp = fgetc(infile)) != EOF) {  /* push everything out til */
  333.                     fputc(outfile);                     /* end of chunkfile        */
  334.                     totbytes++;                         /* and count them          */
  335.                 }
  336.             } else {
  337.                 qexit(10,EXIT);
  338.             }
  339.         }
  340.  
  341.         fclose(infile);
  342.  
  343.         free(heap);
  344.  
  345.     } /* while */
  346.  
  347.     if (totbytes != orgsize) {
  348.         printf("\n*** ERROR 11 - Total bytes read from chunk file not equal to ");
  349.         printf("\n               original file size.  Original file - %lu bytes,",orgsize);
  350.         printf("\n               Total of chunkfiles - %lu",totbytes);
  351.     }
  352.  
  353.     fcloseall();
  354.     exit(0);
  355.  
  356. } /* main */
  357. /************************* end of main program *********************/
  358.  
  359. /*queried exit */
  360. void qexit(code,mode)
  361. int code,mode;
  362. {
  363.     char temp;
  364.     if (mode) {
  365.         printf("\n EXITING ...");
  366.         fcloseall();
  367.         exit(code);
  368.     }
  369.  
  370.     while (1) {
  371.         printf("\n\n Do you want to (A)bort or (C)ontinue? ");
  372.         temp = getche();
  373.         if (toupper(temp) == 'A') {
  374.             printf("\n\n EXITING ...");
  375.             fcloseall();
  376.             exit(code);
  377.         }
  378.         if (toupper(temp) == 'C') {
  379.             return;
  380.         }
  381.     }
  382. }
  383.  
  384.  
  385. void oops()
  386. {
  387.     printf("\n\n*** ERROR 1 - File name must be specified on command line");
  388.     printf("\n Usage:\n");
  389.     printf(" GLUE FILENAME [OUTFILE] [-i]  Where:");
  390.     printf("\n  FILENAME is the CHUNKed file's chunkfile name");
  391.     printf("\n  OUTFILE  is an optional output file name that will override the name");
  392.     printf("\n           embedded in the chunkfiles.");
  393.     printf("\n  -i       Tells GLUE to ignore any errors it may find in the chunkfiles");
  394.     printf("\n  Any file extension on FILENAME is ignored. The chunkfiles must end in CHx");
  395.     printf("\n\nEXITING ...\n");
  396.     return;
  397. }
  398.  
  399.  
  400. /* Return pointer to directory-less file name:*/
  401. char *basename(cc)
  402.  char *cc;
  403. {
  404.     char *dd;
  405.     dd = cc;
  406.     for (;*cc;++cc) 
  407.        if ((*cc == '/') || (*cc == '\\') || (*cc == ':'))   
  408.            dd = cc+1;                           
  409.     return (dd);                                  
  410. }
  411.  
  412.  
  413. /************* end of file ***************/
  414. 
  415.  
  416.