home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / OS2MNX1.ZIP / UUD.C < prev    next >
C/C++ Source or Header  |  1989-12-26  |  13KB  |  584 lines

  1. /* uud - bulletproof version of uudecode */
  2. /* $Header: D:/RCS/RCS/uud.c 1.1 89/12/26 23:22:10 RCA Exp $
  3.  * $Log:    uud.c $
  4.  * Revision 1.1  89/12/26  23:22:10  RCA
  5.  * Initial revision
  6.  * 
  7.  */
  8.  
  9. /*
  10.  * Uud -- decode a uuencoded file back to binary form.
  11.  *
  12.  * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  13.  * The Atari GEMDOS version compiled with MWC 2.x.
  14.  * The MSDOS version with TurboC.
  15.  * The Unix version with cc.
  16.  * this version is made: 25 Nov 1988.
  17.  */
  18.  
  19. /*
  20.  * Be sure to have the proper symbol at this point. (GEMDOS, MSDOS, UNIX...)
  21.  */
  22. /*
  23. #define MSDOS
  24.  
  25. #ifndef GEMDOS
  26. #define GEMDOS 1
  27. #endif
  28.  */
  29. #ifndef UNIX
  30. #define UNIX 1
  31. #endif
  32. /*
  33. #ifndef MSDOS
  34. #define MSDOS 1
  35. #endif
  36.  */
  37.  
  38. #ifdef GEMDOS
  39. #define SYSNAME "gemdos"
  40. #define SMALL 1
  41. #endif
  42. #ifdef MSDOS
  43. #define SYSNAME "msdos"
  44. #define SMALL 1
  45. #endif
  46. #ifdef UNIX
  47. #define SYSNAME "unix"
  48. #endif
  49.  
  50. #include <stdio.h>
  51.  
  52. #ifdef GEMDOS
  53. #include <osbind.h>
  54. #define Error(n)  { Bconin(2); exit(n); }
  55. #define WRITE      "wb"
  56. #else
  57. #define Error(n)  exit(n)
  58. #define WRITE      "w"
  59. #endif
  60.  
  61. #define loop    while (1)
  62.  
  63. extern FILE *fopen();
  64. extern char *strcpy();
  65. extern char *strcat();
  66.  
  67. char *getnword();
  68.  
  69. #define NCHARS  256
  70. #define LINELEN 256
  71. #define FILELEN 64
  72. #define NORMLEN 60    /* allows for 80 encoded chars per line */
  73.  
  74. #define SEQMAX 'z'
  75. #define SEQMIN 'a'
  76. char seqc;
  77. int first, secnd, check, numl;
  78.  
  79. FILE *in, *out;
  80. char *pos;
  81. char ifname[FILELEN], ofname[FILELEN];
  82. char *source = NULL, *target = NULL;
  83. char blank, part = '\0';
  84. int partn, lens;
  85. int debug = 0, nochk = 0, onedone = 0;
  86. int chtbl[NCHARS], cdlen[NORMLEN + 3];
  87.  
  88. main(argc, argv) int argc; char *argv[];
  89. {
  90.     int mode;
  91.     register int i, j;
  92.     char *curarg;
  93.     char dest[FILELEN], buf[LINELEN];
  94.  
  95.     if (argc < 2) {
  96.             format("█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█\n");
  97.             format("█ UUD (UUDecode)                            $Author: RCA $ █\n");
  98.             format("█          $Date: 89/12/26 23:22:10 $     $Revision: 1.1 $ █\n");
  99.             format("█ Usage:   uud [-n] [-d] [-s dir] [-t dir] inputfile       █\n");
  100.             format("█ Purpose: Decodes UUEncoded files - returns to binary     █\n");
  101.             format("█          format.                                         █\n");
  102.             format("█ Options: -n: no sequence check                           █\n");
  103.             format("█          -d: debug                                       █\n");
  104.             format("█          -s dir: source directory (end with backslash)   █\n");
  105.             format("█          -t dir: target directory (end with backslash)   █\n");
  106.             format("█ OS       DOS or OS/2                                     █\n");
  107.             format("█ Credits: MSD, RDR, JPHD, WLS                             █\n");
  108.             format("█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█\n");
  109.             Error(1);
  110.     }
  111.  
  112.     curarg = argv[1];
  113.     
  114.     while (curarg[0] == '-') {
  115.         if (((curarg[1] == 'd') || (curarg[1] == 'D')) &&
  116.             (curarg[2] == '\0')) {
  117.             debug = 1;
  118.         } else if (((curarg[1] == 'n') || (curarg[1] == 'N')) &&
  119.                (curarg[2] == '\0')) {
  120.             nochk = 1;
  121.         } else if (((curarg[1] == 't') || (curarg[1] == 'T')) &&
  122.                (curarg[2] == '\0')) {
  123.             argv++;
  124.             argc--;
  125.             if (argc < 2) {
  126.                 format("uud: Missing target directory.\n");
  127.                 Error(15);
  128.             }
  129.             target = argv[1];
  130.             if (debug)
  131.                 format("Target dir = %s\n",target);
  132.         } else if (((curarg[1] == 's') || (curarg[1] == 'S')) &&
  133.                (curarg[2] == '\0')) {
  134.             argv++;
  135.             argc--;
  136.             if (argc < 2) {
  137.                 format("uud: Missing source directory.\n");
  138.                 Error(15);
  139.             }
  140.             source = argv[1];
  141.             if (debug)
  142.                 format("Source dir = %s\n",source);
  143.         } else if (curarg[1] != '\0') {
  144.             format("uud: Unknown option <%s>\n", curarg);
  145.             Error(15);
  146.         } else
  147.             break;
  148.         argv++;
  149.         argc--;
  150.         if (argc < 2) {
  151.             format("uud: Missing file name.\n");
  152.             Error(15);
  153.         }
  154.         curarg = argv[1];
  155.     }
  156.  
  157.     if ((curarg[0] == '-') && (curarg[1] == '\0')) {
  158.         in = stdin;
  159.         strcpy(ifname, "<stdin>");
  160.     } else {
  161.         if (source != NULL) {
  162.             strcpy(ifname, source);
  163.             strcat(ifname, curarg);
  164.         } else
  165.             strcpy(ifname, curarg);
  166.         if ((in = fopen(ifname, "r")) == NULL) {
  167.             format("uud: Can't open %s\n", ifname);
  168.             Error(2);
  169.         }
  170.         numl = 0;
  171.     }
  172.  
  173. /*
  174.  * Set up the default translation table.
  175.  */
  176.     for (i = 0; i < ' '; i++) chtbl[i] = -1;
  177.     for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
  178.     for (i = ' ' + 64; i < NCHARS; i++) chtbl[i] = -1;
  179.     chtbl['`'] = chtbl[' '];    /* common mutation */
  180.     chtbl['~'] = chtbl['^'];    /* an other common mutation */
  181.     blank = ' ';
  182. /*
  183.  * set up the line length table, to avoid computing lotsa * and / ...
  184.  */
  185.     cdlen[0] = 1;
  186.     for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  187.         cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  188. /*
  189.  * search for header or translation table line.
  190.  */
  191.     loop {    /* master loop for multiple decodes in one file */
  192.         partn = 'a';
  193.         loop {
  194.             if (fgets(buf, sizeof buf, in) == NULL) {
  195.                 if (onedone) {
  196.                     if (debug) format("End of file.\n");
  197.                     exit(0);
  198.                 } else {
  199.                     format("uud: No begin line.\n");
  200.                     Error(3);
  201.                 }
  202.             }
  203.             numl++;
  204.             if (strncmp(buf, "table", 5) == 0) {
  205.                 gettable();
  206.                 continue;
  207.             }
  208.             if (strncmp(buf, "begin", 5) == 0) {
  209.                 break;
  210.             }
  211.         }
  212.         lens = strlen(buf);
  213.         if (lens) buf[--lens] = '\0';
  214. #ifdef SMALL
  215.         if ((pos = getnword(buf, 3))) {
  216.             strcpy(dest, pos);
  217.         } else
  218. #else
  219.         if(sscanf(buf,"begin%o%s", &mode, dest) != 2)
  220. #endif
  221.         {
  222.             format("uud: Missing filename in begin line.\n");
  223.             Error(10);
  224.         }
  225.  
  226.         if (target != NULL) {
  227.             strcpy(ofname, target);
  228.             strcat(ofname, dest);
  229.         } else
  230.             strcpy(ofname, dest);
  231.  
  232.         if((out = fopen(ofname, WRITE)) == NULL) {
  233.             format("uud: Cannot open output file: %s\n", ofname);
  234.             Error(4);
  235.         }
  236.         if (debug) format("Begin uudecoding: %s\n", ofname);
  237.         seqc = SEQMAX;
  238.         check = nochk ? 0 : 1;
  239.         first = 1;
  240.         secnd = 0;
  241.         decode();
  242.         fclose(out);
  243. #ifdef UNIX
  244.         chmod(ofname, mode);
  245. #endif
  246.         onedone = 1;
  247.         if (debug) format("End uudecoding: %s\n", ofname);
  248.     }    /* master loop for multiple decodes in one file */
  249. }
  250.  
  251. /*
  252.  * Bring back a pointer to the start of the nth word.
  253.  */
  254. char *getnword(str, n) register char *str; register int n;
  255. {
  256.     while((*str == '\t') || (*str == ' ')) str++;
  257.     if (! *str) return NULL;
  258.     while(--n) {
  259.         while ((*str != '\t') && (*str != ' ') && (*str)) str++;
  260.         if (! *str) return NULL;
  261.         while((*str == '\t') || (*str == ' ')) str++;
  262.         if (! *str) return NULL;
  263.     }
  264.     return str;
  265. }
  266.  
  267. /*
  268.  * Install the table in memory for later use.
  269.  */
  270. gettable()
  271. {
  272.     char buf[LINELEN];
  273.     register int c, n = 0;
  274.     register char *cpt;
  275.  
  276.     for (c = 0; c < NCHARS; c++) chtbl[c] = -1;
  277.  
  278. again:    if (fgets(buf, sizeof buf, in) == NULL) {
  279.         format("uud: EOF while in translation table.\n");
  280.         Error(5);
  281.     }
  282.     numl++;
  283.     if (strncmp(buf, "begin", 5) == 0) {
  284.         format("uud: Incomplete translation table.\n");
  285.         Error(6);
  286.     }
  287.     cpt = buf + strlen(buf) - 1;
  288.     *cpt = ' ';
  289.     while (*(cpt) == ' ') {
  290.         *cpt = 0;
  291.         cpt--;
  292.     }
  293.     cpt = buf;
  294.     while (c = *cpt) {
  295.         if (chtbl[c] != -1) {
  296.             format("uud: Duplicate char in translation table.\n");
  297.             Error(7);
  298.         }
  299.         if (n == 0) blank = c;
  300.         chtbl[c] = n++;
  301.         if (n >= 64) return;
  302.         cpt++;
  303.     }
  304.     goto again;
  305. }
  306.  
  307. /*
  308.  * copy from in to out, decoding as you go along.
  309.  */
  310.  
  311. decode()
  312. {
  313.     char buf[LINELEN], outl[LINELEN];
  314.     register char *bp, *ut;
  315.     register int *trtbl = chtbl;
  316.     register int n, c, rlen;
  317.     register unsigned int len;
  318.  
  319.     loop {
  320.         if (fgets(buf, sizeof buf, in) == NULL) {
  321.             format("uud: EOF before end.\n");
  322.             fclose(out);
  323.             Error(8);
  324.         }
  325.         numl++;
  326.         len = strlen(buf);
  327.         if (len) buf[--len] = '\0';
  328. /*
  329.  * Is it an unprotected empty line before the end line ?
  330.  */
  331.         if (len == 0) continue;
  332. /*
  333.  * Get the binary line length.
  334.  */
  335.         n = trtbl[*buf];
  336.         if (n >= 0) goto decod;
  337. /*
  338.  * end of uuencoded file ?
  339.  */
  340.         if (strncmp(buf, "end", 3) == 0) return;
  341. /*
  342.  * end of current file ? : get next one.
  343.  */
  344.         if (strncmp(buf, "include", 7) == 0) {
  345.             getfile(buf);
  346.             continue;
  347.         }
  348.         format("uud: Bad prefix line %d in file: %s\n",numl, ifname);
  349.         if (debug) format("Bad line =%s\n",buf);
  350.         Error(11);
  351. /*
  352.  * Sequence checking ?
  353.  */
  354. decod:        rlen = cdlen[n];
  355. /*
  356.  * Is it the empty line before the end line ?
  357.  */
  358.         if (n == 0) continue;
  359. /*
  360.  * Pad with blanks.
  361.  */
  362.         for (bp = &buf[c = len];
  363.             c < rlen; c++, bp++) *bp = blank;
  364. /*
  365.  * Verify if asked for.
  366.  */
  367.         if (debug) {
  368.             for (len = 0, bp = buf; len < rlen; len++) {
  369.                 if (trtbl[*bp] < 0) {
  370.                     format(
  371.     "Non uuencoded char <%c>, line %d in file: %s\n", *bp, numl, ifname);
  372.                     format("Bad line =%s\n",buf);
  373.                     Error(16);
  374.                 }
  375.                 bp++;
  376.             }
  377.         }
  378. /*
  379.  * All this just to check for uuencodes that append a 'z' to each line....
  380.  */
  381.         if (secnd && check) {
  382.             secnd = 0;
  383.             if (buf[rlen] == SEQMAX) {
  384.                 check = 0;
  385.                 if (debug) format("Sequence check turned off (2).\n");
  386.             } else
  387.                 if (debug) format("Sequence check on (2).\n");
  388.         } else if (first && check) {
  389.             first = 0;
  390.             secnd = 1;
  391.             if (buf[rlen] != SEQMAX) {
  392.                 check = 0;
  393.                 if (debug) format("No sequence check (1).\n");
  394.             } else
  395.                 if (debug) format("Sequence check on (1).\n");
  396.         }
  397. /*
  398.  * There we check.
  399.  */
  400.         if (check) {
  401.             if (buf[rlen] != seqc) {
  402.                 format("uud: Wrong sequence line %d in %s\n",
  403.                     numl, ifname);
  404.                 if (debug)
  405.                     format(
  406.     "Sequence char is <%c> instead of <%c>.\n", buf[rlen], seqc);
  407.                 Error(18);
  408.             }
  409.             seqc--;
  410.             if (seqc < SEQMIN) seqc = SEQMAX;
  411.         }
  412. /*
  413.  * output a group of 3 bytes (4 input characters).
  414.  * the input chars are pointed to by p, they are to
  415.  * be output to file f.n is used to tell us not to
  416.  * output all of them at the end of the file.
  417.  */
  418.         ut = outl;
  419.         len = n;
  420.         bp = &buf[1];
  421.         while (n > 0) {
  422.             *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  423.             n--;
  424.             if (n) {
  425.                 *(ut++) = (trtbl[bp[1]] << 4) |
  426.                       (trtbl[bp[2]] >> 2);
  427.                 n--;
  428.             }
  429.             if (n) {
  430.                 *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  431.                 n--;
  432.             }
  433.             bp += 4;
  434.         }
  435.         if ((n = fwrite(outl, 1, len, out)) <= 0) {
  436.             format("uud: Error on writing decoded file.\n");
  437.             Error(18);
  438.         }
  439.     }
  440. }
  441.  
  442. /*
  443.  * Find the next needed file, if existing, otherwise try further
  444.  * on next file.
  445.  */
  446. getfile(buf) register char *buf;
  447. {
  448.     if ((pos = getnword(buf, 2)) == NULL) {
  449.         format("uud: Missing include file name.\n");
  450.         Error(17);
  451.     } else
  452.         if (source != NULL) {
  453.             strcpy(ifname, source);
  454.             strcat(ifname, pos);
  455.         } else
  456.             strcpy(ifname, pos);
  457. #ifdef GEMDOS
  458.     if (Fattrib(ifname, 0, 0) < 0)
  459. #else
  460.     if (access(ifname, 04))
  461. #endif
  462.     {
  463.         if (debug) {
  464.             format("Cant find: %s\n", ifname);
  465.             format("Continuing to read same file.\n");
  466.         }
  467.     }
  468.     else {
  469.         if (freopen(ifname, "r", in) == in) {
  470.             numl = 0;
  471.             if (debug) 
  472.                 format("Reading next section from: %s\n", ifname);
  473.         } else {
  474.             format("uud: Freopen abort: %s\n", ifname);
  475.             Error(9);
  476.         }
  477.     }
  478.     loop {
  479.         if (fgets(buf, LINELEN, in) == NULL) {
  480.             format("uud: No begin line after include: %s\n", ifname);
  481.             Error(12);
  482.         }
  483.         numl++;
  484.         if (strncmp(buf, "table", 5) == 0) {
  485.             gettable();
  486.             continue;
  487.         }
  488.         if (strncmp(buf, "begin", 5) == 0) break;
  489.     }
  490.     lens = strlen(buf);
  491.     if (lens) buf[--lens] = '\0';
  492. /*
  493.  * Check the part suffix.
  494.  */
  495.     if ((pos = getnword(buf, 3)) == NULL ) {
  496.         format("uud: Missing part name, in included file: %s\n", ifname);
  497.         Error(13);
  498.     } else {
  499.         part = *pos;
  500.         partn++;
  501.         if (partn > 'z') partn = 'a';
  502.         if (part != partn) {
  503.             format("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
  504.                 part, partn);
  505.             Error(14);
  506.         }
  507.         if (debug) format("Reading part %c\n", *pos);
  508.     }
  509. }
  510.  
  511. /*
  512.  * Printf style formatting. (Borrowed from MicroEmacs by Dave Conroy.) 
  513.  * A lot smaller than the full fledged printf.
  514.  */
  515. /* VARARGS1 */
  516. format(fp, args) char *fp;
  517. {
  518.     doprnt(fp, (char *)&args);
  519. }
  520.  
  521. doprnt(fp, ap)
  522. register char    *fp;
  523. register char    *ap;
  524. {
  525.     register int    c, k;
  526.     register char    *s;
  527.  
  528.     while ((c = *fp++) != '\0') {
  529.         if (c != '%')
  530.             outc(c);
  531.         else {
  532.             c = *fp++;
  533.             switch (c) {
  534.             case 'd':
  535.                 puti(*(int *)ap, 10);
  536.                 ap += sizeof(int);
  537.                 break;
  538.  
  539.             case 's':
  540.                 s = *(char **)ap;
  541.                 while ((k = *s++) != '\0')
  542.                     outc(k);
  543.                 ap += sizeof(char *);
  544.                 break;
  545.  
  546.             case 'c':
  547.                 outc(*(int *)ap);
  548.                 ap += sizeof(int);
  549.                 break;
  550.  
  551.             default:
  552.                 outc(c);
  553.             }
  554.         }
  555.     }
  556. }
  557.  
  558. /*
  559.  * Put integer, in radix "r".
  560.  */
  561. puti(i, r)
  562. register unsigned int    i;
  563. register unsigned int    r;
  564. {
  565.     register unsigned int    q, s;
  566.  
  567.     if ((q = i / r) != 0)
  568.         puti(q, r);
  569.     s = i % r;
  570.     if (s <= 9)
  571.         outc(s + '0');
  572.     else
  573.         outc(s - 10 + 'A');
  574. }
  575. outc(c) register char c;
  576. {
  577. #ifdef GEMDOS
  578.     if (c == '\n') Bconout(2, '\r');
  579.     Bconout(2, c);
  580. #else
  581.     putchar(c);
  582. #endif
  583. }
  584.