home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 410.lha / UUJoin_v1.01 / uujoin.c < prev    next >
C/C++ Source or Header  |  1990-09-05  |  9KB  |  364 lines

  1. /*
  2.  * uujoin [ -r ] [ {-amiga | -mac | -pc} ] file(s)...
  3.  * join and decode Usenet encoded binary files.
  4.  *
  5.  * Author:  Mark R. Rinfret
  6.  * Date:    08-15-90
  7.  * 
  8.  * Public Domain - Use as you wish.
  9.  *
  10.  * Notes:   The uudecode portion was adapted from uudecode.c, packaged
  11.  *          with Matt Dillon's UUCP implementation.
  12.  *
  13.  *          The Macintosh mode simply filters and joins the files. It
  14.  *          doesn't decode the BinHex format (got a de-binhexer I can
  15.  *          have?).
  16.  *
  17.  *          The delimiter strings used to extract the encoded segments
  18.  *          may change over time. Just edit the assignments to the
  19.  *          string variables "start" and "stop", as appropriate.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <FileScan.h>
  26. #include <functions.h>
  27.  
  28. extern int unlink(const char *fileName);
  29.  
  30. extern int errno;
  31.  
  32. /* single character decode */
  33. #define DEC(c)    (((c) - ' ') & 077)
  34.  
  35. char    *versionString = 
  36.             "uujoin 1.01 - join and decode Usenet encoded binary files.";
  37.  
  38. int decode(FILE *in, FILE *out);
  39. int outdec(char *p, FILE *f, int n);
  40. int fr(FILE *fd, char *buf, int cnt);
  41.  
  42. #define AMI     0
  43. #define MAC     1
  44. #define PC      2
  45.  
  46. int     fileCount;                          /* set by FileScan() */
  47. char    **fileNames;                        /* allocated by FileScan() */
  48. int     fileNumber;                         /* index into fileNames */
  49. char    line[256];                          /* allows for long Usenet lines */
  50. int     machine;                            /* machine type */
  51. int     removeFiles = 0;                    /* 1 => remove originals */
  52. char    tempName[L_tmpnam];                 /* temporary file name */
  53.  
  54. int
  55. DecodeHexFile(void)
  56. {
  57.     char    newName[128];
  58.     char    *s;
  59.     int     status = 0;
  60.  
  61.     /* Eventually, the code to de-binhex the file will be placed here.
  62.      * for now, just rename the temp file as <newName>.hex.
  63.      */
  64.     
  65.     /* Use first filename as the base for the new filename. */
  66.     strcpy(newName, fileNames[0]);
  67.     s = strrchr(newName, '.');              /* Find rightmost period. */
  68.     if (s) *s = '\0';                       /* Drop current suffix. */
  69.     strcat(newName,".hex");                 /* Add ".hex" suffix. */
  70.     if (! Rename(tempName, newName)) {      /* Rename the file. */
  71.         status = IoErr();
  72.         fprintf(stderr,"Could not rename '%s' to '%s'; error %ld\n",
  73.                 tempName, newName, (LONG) status);
  74.     }
  75.     return status;
  76. }
  77.  
  78. int
  79. DecodeMergedFile(void)
  80. {
  81.     char    dest[128];
  82.  
  83.     FILE    *in = NULL, *out = NULL;
  84.     int     mode;                               /* file protection */
  85.  
  86.     in = fopen(tempName, "r");
  87.     if (! in ) {
  88.         fprintf(stderr,"Could not reopen merged file: '%s'\n", tempName);
  89.         exit(1);
  90.     }
  91.  
  92.     /* Search for header line */
  93.     for (;;) {
  94.         if (fgets(line, sizeof line, in) == NULL) {
  95.             fprintf(stderr, "No begin line\n");
  96.             exit(1);
  97.         }
  98.         if (strncmp(line, "begin ", 6) == 0)
  99.             break;
  100.     }
  101.  
  102.     sscanf(line, "begin %o %s", &mode, dest);
  103.  
  104.     /* create output file */
  105.     out = fopen(dest, "w");
  106.     if (out == NULL) {
  107.         perror(dest);
  108.         exit(1);
  109.     }
  110.  
  111.     decode(in, out);
  112.  
  113.     if (fgets(line, sizeof line, in) == NULL || strcmp(line, "end\n")) {
  114.         fprintf(stderr, "No end line\n");
  115.         exit(5);
  116.     }
  117.     fclose(in);
  118.  
  119.     return 0;
  120. }
  121.  
  122. int
  123. JoinFiles(void)
  124. {
  125.     char    *fName;                         /* current file name */
  126.     FILE    *inFile = NULL;
  127.     char    *p;                             /* adjusted line pointer */
  128.     char    *start, *stop;                  /* pattern matching strings */
  129.     int     startLeng, stopLeng;            /* pattern lengths */
  130.     int     status = 0;
  131.     FILE    *tempFile = NULL;
  132.  
  133.     tmpnam(tempName);
  134.     tempFile = fopen(tempName, "w");
  135.     if (!tempFile) {
  136.         perror(tempName);
  137.         status = errno;
  138.         goto done;
  139.     }
  140.  
  141.     /* Set up pattern strings according to machine type. Patterns are
  142.      * matched from beginning of line through number of chars in pattern. 
  143.      */
  144.  
  145.     if (machine == MAC) {
  146.         start = "---";
  147.         stop = "--- end";
  148.     }        
  149.     else if (machine == PC) {
  150.         start = "BEGIN";
  151.         stop = "END--";
  152.     }
  153.     else {                              /* AMIGA */
  154.         start = "sed";
  155.         stop = "SHAR_EOF";
  156.     }
  157.     
  158.     /* Compute the lengths of the match strings. */
  159.  
  160.     startLeng = strlen(start);
  161.     stopLeng = strlen(stop);
  162.  
  163.     /* The Amiga binaries are packaged as shar files and therefore have a
  164.      * leading 'X' which must be tossed. Other formats (so far) are not
  165.      * packed as shar files and thus, the whole line is used.
  166.      */
  167.     p = (machine == AMI ? (line + 1) : line);
  168.  
  169.     while (fileNumber < fileCount) {
  170.         fName = fileNames[fileNumber];  /* For programming convenience. */
  171.         inFile = fopen(fName, "r");
  172.         if (! inFile) {
  173.             perror(fName);
  174.             status = errno;
  175.             goto done;
  176.         }
  177.  
  178.         /*  Attempt to find the start of this file. */
  179.  
  180.         if (startLeng) {
  181.             while (1) {
  182.                 fgets(line, sizeof(line), inFile);
  183.                 if ( feof(inFile) ) {
  184. eof_err:
  185.                     fprintf(stderr,"uujoin: unexpected EOF in file '%s'!\n", fName);
  186.                     status = EOF;
  187.                     goto done;
  188.                 }
  189.                 if (strncmp(start, line, startLeng) == 0)
  190.                     break;                      /* We found the beginning. */
  191.             }
  192.         }
  193.  
  194.         while (1) {
  195.             fgets(line, sizeof(line), inFile);
  196.             if ( feof(inFile) ) {
  197.                 if (stopLeng == 0) 
  198.                     break;
  199.                 else
  200.                     goto eof_err;
  201.             }
  202.  
  203.             if ( (*line != '\n') && (strncmp(stop, line, stopLeng) == 0) )
  204.                 break;                      /* We found the end. */
  205.         
  206.             if ( fputs(p, tempFile) ) {     /* Write the _adjusted_ line. */
  207.                 status = EOF;
  208.                 fprintf(stderr,"uujoin: error writing to temp file '%s'\n", 
  209.                         tempName);
  210.                 exit(1);
  211.             }
  212.         }
  213.         fclose(inFile);
  214.         ++fileNumber;
  215.     }
  216.  
  217. done:
  218.     if (tempFile) fclose(tempFile);
  219.     if (inFile) fclose(inFile);
  220.     return status;
  221. }
  222.  
  223. main(int argc, char **argv)
  224. {
  225.  
  226.     if (argc < 2) {
  227. usage:
  228.         puts(versionString);
  229.         puts("Usage:   uujoin [options] file1 [... filen]");
  230.         puts("    where [options] may be:");
  231.         puts("\t-amiga  -> uuencoded files wrapped with shar");
  232.         puts("\t-mac    -> Macintosh binhex files (not decoded in this release)");
  233.         puts("\t-pc     -> uuencoded files enclosed in BEGIN/END pairs");
  234.         puts("\t-r      -> remove original files when done");
  235.         puts("\n\tUnix-style wildcards may be used in file specifications.");
  236.         puts("\n\tExample: uujoin -amiga -r program.??");
  237.         puts("\n\tMark R. Rinfret, August 1990.");
  238.         puts("\tContributed to the public domain.");
  239.         exit(1);
  240.     }
  241.     
  242.     --argc;                                 /* Skip over program name. */
  243.     ++argv;
  244.  
  245.     while (**argv == '-') {
  246.         if (strcmp(*argv,"-mac") == 0) {
  247.             machine = MAC;
  248. bump:
  249.             --argc;                         /* Skip this arg. */
  250.             ++argv;
  251.         }
  252.         else if (strcmp(*argv, "-pc") == 0) {
  253.             machine = PC;
  254.             goto bump;
  255.         }
  256.         else if (strcmp(*argv,"-amiga") == 0) {
  257.             machine = AMI;
  258.             goto bump;
  259.         }
  260.         else if (strcmp(*argv,"-r") == 0) {
  261.             removeFiles = 1;
  262.             goto bump;
  263.         }
  264.         else
  265.             goto usage;
  266.     }
  267.  
  268.     fileNames = FileScan(argv, argc, &fileCount, 1);
  269.     if (! fileNames) {
  270.         printf("Filename expansion failed - abort!\n");
  271.         exit(1);
  272.     }
  273.  
  274.     if (JoinFiles()) exit(1);                   /* Attempt to join files. */
  275.  
  276.     if (machine == MAC) {
  277.         if (DecodeHexFile()) exit(1);
  278.     }
  279.     else {
  280.         if (DecodeMergedFile()) exit(1);
  281.     }
  282.  
  283.     unlink(tempName);
  284.     if (removeFiles) {
  285.         while (--fileCount >= 0) {
  286.             unlink(fileNames[fileCount]);
  287.         }
  288.     }
  289.     exit(0);
  290. }
  291.  
  292. /*
  293.  * copy from in to out, decoding as you go along.
  294.  */
  295. decode(in, out)
  296. FILE *in;
  297. FILE *out;
  298. {
  299.     char buf[80];
  300.     char *bp;
  301.     int n;
  302.  
  303.     for (;;) {
  304.         /* for each input line */
  305.         if (fgets(buf, sizeof buf, in) == NULL) {
  306.             printf("Short file\n");
  307.             exit(10);
  308.         }
  309.         n = DEC(buf[0]);
  310.         if (n <= 0)
  311.             break;
  312.  
  313.         bp = &buf[1];
  314.         while (n > 0) {
  315.             outdec(bp, out, n);
  316.             bp += 4;
  317.             n -= 3;
  318.         }
  319.     }
  320. }
  321.  
  322. /*
  323.  * output a group of 3 bytes (4 input characters).
  324.  * the input chars are pointed to by p, they are to
  325.  * be output to file f.  n is used to tell us not to
  326.  * output all of them at the end of the file.
  327.  */
  328. outdec(p, f, n)
  329. char *p;
  330. FILE *f;
  331. {
  332.     int c1, c2, c3;
  333.  
  334.     c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
  335.     c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
  336.     c3 = DEC(p[2]) << 6 | DEC(p[3]);
  337.     if (n >= 1)
  338.         fputc(c1, f);
  339.     if (n >= 2)
  340.         fputc(c2, f);
  341.     if (n >= 3)
  342.         fputc(c3, f);
  343. }
  344.  
  345.  
  346. /* fr: like read but stdio */
  347. int
  348. fr(fd, buf, cnt)
  349. FILE *fd;
  350. char *buf;
  351. int cnt;
  352. {
  353.     int c, i;
  354.  
  355.     for (i=0; i<cnt; i++) {
  356.         c = fgetc(fd);
  357.         if (c == EOF)
  358.             return(i);
  359.         buf[i] = c;
  360.     }
  361.     return (cnt);
  362. }
  363.  
  364.