home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2607 / myuud.c next >
Encoding:
C/C++ Source or Header  |  1991-01-25  |  14.5 KB  |  711 lines

  1. /*
  2.  * Uud -- decode a uuencoded file back to binary form.
  3.  *
  4.  * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
  5.  * The Atari GEMDOS version compiled with MWC 2.x.
  6.  * The MSDOS version with TurboC.
  7.  * The Unix version with cc.
  8.  * this version is made: 25 Nov 1988.
  9.  * Mods :
  10.  * ------ 24 Jan 1991 ------ maman@cosinus.inria.fr ------
  11.  *    No use of ceil. (cdlen[] is already there).
  12.  *    valid_char, valid_length and valid_chars used.
  13.  *    verify flag added for more tests and more verbose,
  14.  *    exactly the way I like it ;-)
  15.  * ------ 23 Jan 1991 ------ maman@cosinus.inria.fr ------
  16.  *    I've taken this from ftp at sics.se:/mailserver/uudecode.shar
  17.  *    It was said Wrapped by Edwin Kremer <edwin@zlotty> on \
  18.  *    Wed Dec 20 17:06:37 1989
  19.  *
  20.  *    Checks the declared length and the effective length
  21.  *    in order to skip the header/signature of different
  22.  *    files and test the range validity of one character
  23.  *    in the middle of the buffer.
  24.  *    Works almost all the time.
  25.  *    Tolerate one more byte at the end for another count
  26.  *    (should be given as a parameter ?).
  27.  *    UNIX compilation: cc [-O] -o uud uud.c
  28.  */
  29.  
  30. /*
  31.  * Be sure to have the proper symbol at this point. (GEMDOS, MSDOS, UNIX...)
  32.  */
  33. /*
  34. #ifndef GEMDOS
  35. #define GEMDOS 1
  36. #endif
  37.  */
  38. #ifndef UNIX
  39. #define UNIX 1
  40. #endif
  41. /*
  42. #ifndef MSDOS
  43. #define MSDOS 1
  44. #endif
  45.  */
  46.  
  47. #undef GWMDOS
  48. #undef MSDOS
  49.  
  50. #ifdef GEMDOS
  51. #define SYSNAME "gemdos"
  52. #define SMALL 1
  53. #endif
  54. #ifdef MSDOS
  55. #define SYSNAME "msdos"
  56. #define SMALL 1
  57. #endif
  58. #ifdef UNIX
  59. #define SYSNAME "unix"
  60. #define format printf
  61. #define TEST_LENGTH
  62. #endif
  63.  
  64. #include <stdio.h>
  65.  
  66. #ifdef GEMDOS
  67. #include <osbind.h>
  68. #define Error(n)  { Bconin(2); exit(n); }
  69. #define WRITE      "wb"
  70. #else
  71. #define Error(n)  exit(n)
  72. #define WRITE      "w"
  73. #endif
  74.  
  75. #define loop    while (1)
  76.  
  77. extern FILE *fopen();
  78. extern char *strcpy();
  79. extern char *strcat();
  80.  
  81. char *getnword();
  82.  
  83. #define MAXCHAR 256
  84. #define LINELEN 256
  85. #define FILELEN 64
  86. #define NORMLEN 60    /* allows for 80 encoded chars per line */
  87.  
  88. #define SEQMAX 'z'
  89. #define SEQMIN 'a'
  90. char seqc;
  91. int first, secnd, check, numl;
  92. #ifdef TEST_LENGTH
  93. int numlbad = -1;
  94. #endif
  95.  
  96. FILE *in, *out;
  97. char *pos;
  98. char ifname[FILELEN], ofname[FILELEN];
  99. char *source = NULL, *target = NULL;
  100. char blank, part = '\0';
  101. int partn, lens;
  102. int debug = 0, nochk = 0, onedone = 0, verify = 0;
  103. int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
  104.  
  105. main(argc, argv) int argc; char *argv[];
  106. {
  107.     int mode;
  108.     register int i, j;
  109.     char *curarg;
  110.     char dest[FILELEN], buf[LINELEN];
  111.  
  112.     if (argc < 2) {
  113.         format("Almost foolproof uudecode v3.4 (%s) 25-Nov-88\n",
  114.             SYSNAME);
  115.         format("\n");
  116.         format("Usage: uud [-n] [-d] [-v] [-s dir] [-t dir] input-file\n");
  117.         format("\n");
  118.         format("Option: -n -> No line sequence check\n");
  119.         format("Option: -d -> Debug/verbose mode\n");
  120.         format("Option: -v -> Verify all chars\n");
  121.         format("Option: -s + Source directory for all input files\n");
  122.         format("  (MUST be terminated by directory separator)\n");
  123.         format("Option: -t + Target directory for all output files\n");
  124.         format("  (MUST be terminated by directory separator)\n");
  125.         format("If input-file is - then stdin is used as input-file\n");
  126.         Error(1);
  127.     }
  128.  
  129.     curarg = argv[1];
  130.     
  131.     while (curarg[0] == '-') {
  132.         if (((curarg[1] == 'd') || (curarg[1] == 'D')) &&
  133.             (curarg[2] == '\0')) {
  134.             debug = 1;
  135.         } else if (((curarg[1] == 'v') || (curarg[1] == 'V')) &&
  136.                (curarg[2] == '\0')) {
  137.             verify = 1;
  138.         } else if (((curarg[1] == 'n') || (curarg[1] == 'N')) &&
  139.                (curarg[2] == '\0')) {
  140.             nochk = 1;
  141.         } else if (((curarg[1] == 't') || (curarg[1] == 'T')) &&
  142.                (curarg[2] == '\0')) {
  143.             argv++;
  144.             argc--;
  145.             if (argc < 2) {
  146.                 format("uud: Missing target directory.\n");
  147.                 Error(15);
  148.             }
  149.             target = argv[1];
  150.             if (debug||verify)
  151.                 format("Target dir = %s\n",target);
  152.         } else if (((curarg[1] == 's') || (curarg[1] == 'S')) &&
  153.                (curarg[2] == '\0')) {
  154.             argv++;
  155.             argc--;
  156.             if (argc < 2) {
  157.                 format("uud: Missing source directory.\n");
  158.                 Error(15);
  159.             }
  160.             source = argv[1];
  161.             if (debug||verify)
  162.                 format("Source dir = %s\n",source);
  163.         } else if (curarg[1] != '\0') {
  164.             format("uud: Unknown option <%s>\n", curarg);
  165.             Error(15);
  166.         } else
  167.             break;
  168.         argv++;
  169.         argc--;
  170.         if (argc < 2) {
  171.             format("uud: Missing file name.\n");
  172.             Error(15);
  173.         }
  174.         curarg = argv[1];
  175.     }
  176.  
  177.     if ((curarg[0] == '-') && (curarg[1] == '\0')) {
  178.         in = stdin;
  179.         strcpy(ifname, "<stdin>");
  180.     } else {
  181.         if (source != NULL) {
  182.             strcpy(ifname, source);
  183.             strcat(ifname, curarg);
  184.         } else
  185.             strcpy(ifname, curarg);
  186.         if ((in = fopen(ifname, "r")) == NULL) {
  187.             format("uud: Can't open %s\n", ifname);
  188.             Error(2);
  189.         }
  190.         numl = 0;
  191.     }
  192.  
  193. /*
  194.  * Set up the default translation table.
  195.  */
  196.     for (i = 0; i < ' '; i++) chtbl[i] = -1;
  197.     for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
  198.     for (i = ' ' + 64; i < MAXCHAR; i++) chtbl[i] = -1;
  199.     chtbl['`'] = chtbl[' '];    /* common mutation */
  200.     chtbl['~'] = chtbl['^'];    /* an other common mutation */
  201.     blank = ' ';
  202. /*
  203.  * set up the line length table, to avoid computing lotsa * and / ...
  204.  */
  205.     cdlen[0] = 1;
  206.     for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
  207.         cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
  208. /*
  209.  * search for header or translation table line.
  210.  */
  211.     loop {    /* master loop for multiple decodes in one file */
  212.         partn = 'a';
  213.         loop {
  214.             if (fgets(buf, sizeof buf, in) == NULL) {
  215.                 if (onedone) {
  216.                     if (debug||verify)
  217.                        format("End of file.\n");
  218.                     exit(0);
  219.                 } else {
  220.                     format("uud: No begin line.\n");
  221.                     Error(3);
  222.                 }
  223.             }
  224.             numl++;
  225.             if (strncmp(buf, "table", 5) == 0) {
  226.                 gettable();
  227.                 continue;
  228.             }
  229.             if (strncmp(buf, "begin", 5) == 0) {
  230.                 break;
  231.             }
  232.         }
  233.         lens = strlen(buf);
  234.         if (lens) buf[--lens] = '\0';
  235. #ifdef SMALL
  236.         if ((pos = getnword(buf, 3))) {
  237.             strcpy(dest, pos);
  238.         } else
  239. #else
  240.         if(sscanf(buf,"begin%o%s", &mode, dest) != 2)
  241. #endif
  242.         {
  243.             format("uud: Missing filename in begin line.\n");
  244.             Error(10);
  245.         }
  246.  
  247.         if (target != NULL) {
  248.             strcpy(ofname, target);
  249.             strcat(ofname, dest);
  250.         } else
  251.             strcpy(ofname, dest);
  252.  
  253.         if((out = fopen(ofname, WRITE)) == NULL) {
  254.             format("uud: Cannot open output file: %s\n", ofname);
  255.             Error(4);
  256.         }
  257.         if (debug||verify) format("Begin uudecoding: %s\n", ofname);
  258.         seqc = SEQMAX;
  259.         check = nochk ? 0 : 1;
  260.         first = 1;
  261.         secnd = 0;
  262.         decode();
  263.         fclose(out);
  264. #ifdef UNIX
  265.         chmod(ofname, mode);
  266. #endif
  267.         onedone = 1;
  268.         if (debug||verify) format("End uudecoding: %s\n", ofname);
  269.     }    /* master loop for multiple decodes in one file */
  270. }
  271.  
  272. /*
  273.  * Bring back a pointer to the start of the nth word.
  274.  */
  275. char *getnword(str, n) register char *str; register int n;
  276. {
  277.     while((*str == '\t') || (*str == ' ')) str++;
  278.     if (! *str) return NULL;
  279.     while(--n) {
  280.         while ((*str != '\t') && (*str != ' ') && (*str)) str++;
  281.         if (! *str) return NULL;
  282.         while((*str == '\t') || (*str == ' ')) str++;
  283.         if (! *str) return NULL;
  284.     }
  285.     return str;
  286. }
  287.  
  288. /*
  289.  * Install the table in memory for later use.
  290.  */
  291. gettable()
  292. {
  293.     char buf[LINELEN];
  294.     register int c, n = 0;
  295.     register char *cpt;
  296.  
  297.     if(debug) format("Getting new table.\n")
  298.  
  299.     for (c = 0; c <= MAXCHAR; c++) chtbl[c] = -1;
  300.  
  301. again:    if (fgets(buf, sizeof buf, in) == NULL) {
  302.         format("uud: EOF while in translation table.\n");
  303.         Error(5);
  304.     }
  305.     numl++;
  306.     if (strncmp(buf, "begin", 5) == 0) {
  307.         format("uud: Incomplete translation table.\n");
  308.         Error(6);
  309.     }
  310.     cpt = buf + strlen(buf) - 1;
  311.     *cpt = ' ';
  312.     while (*(cpt) == ' ') {
  313.         *cpt = 0;
  314.         cpt--;
  315.     }
  316.     cpt = buf;
  317.     while (c = *cpt) {
  318.         if (chtbl[c] != -1) {
  319.             format("uud: Duplicate char in translation table.\n");
  320.             Error(7);
  321.         }
  322.         if (n == 0) blank = c;
  323.         chtbl[c] = n++;
  324.         if (n >= 64)
  325.         {
  326.             if(debug) format("End of getting table.\n")
  327.             return;
  328.         }
  329.         cpt++;
  330.     }
  331.     goto again;
  332. }
  333.  
  334. /*
  335.  * Testing functions
  336.  */
  337.  
  338. #ifdef TEST_LENGTH
  339. valid_length(l,n)
  340.      int l,n;
  341. {
  342.     int k, resp;
  343.     k = cdlen[n];
  344.     /*    k = n % 3;
  345.      *    k = ( n + (k ? 3-k : 0) )*4/3;
  346.      */
  347.     resp = ( (l-k >= 0) && (l-k <= 1) );
  348.     if(debug && !resp && !verify)
  349.     format("Bad length at line %d\n", numl);
  350.     return(resp);
  351. }
  352.  
  353. valid_char(c)
  354.      char c;
  355. {
  356.     int resp;
  357.     /*
  358.      * DON'T FORGET TO MODIFY THE TEST IN valid_chars TOO !
  359.      */
  360.     resp = ( (chtbl[c]<0) ? 0 : 1 );
  361.     if(debug && !resp && !verify)
  362.     format("Bad char <%c> at line %d\n", c, numl);
  363.     return(resp);
  364. }
  365. #endif
  366.  
  367. valid_chars(s,l)
  368.      char *s;
  369.      int l;
  370. {
  371.     int resp, k = 0;
  372.     /*
  373.      * DON'T FORGET TO MODIFY THE TEST IN valid_char TOO !
  374.      */
  375.     while( (k<l) && (chtbl[s[k]]>=0) ) k++;
  376.     resp = (k==l);
  377.     if(debug && !resp) format("%d char bad <%c> at line %d\n",
  378.                   k, s[k], numl);
  379.     return( resp );
  380. }
  381.  
  382. /*
  383.  * copy from in to out, decoding as you go along.
  384.  */
  385.  
  386. decode()
  387. {
  388.     char buf[LINELEN], outl[LINELEN];
  389.     register char *bp, *ut;
  390.     register int *trtbl = chtbl;
  391.     register int n, c, rlen;
  392.     register unsigned int len;
  393. #ifdef TEST_LENGTH
  394.     int efflen;
  395. #endif
  396.  
  397.     loop {
  398.         if (fgets(buf, sizeof buf, in) == NULL) {
  399.             format("uud: EOF before end.\n");
  400.             fclose(out);
  401.             Error(8);
  402.         }
  403.         numl++;
  404.         len = strlen(buf);
  405.         if (len) buf[--len] = '\0';
  406. /*
  407.  * Is it an unprotected empty line before the end line ?
  408.  */
  409.         if (len == 0) continue;
  410. /*
  411.  * Get the binary line length.
  412.  */
  413.         n = trtbl[buf[0]];
  414. /*
  415.  * end of uuencoded file ?
  416.  */
  417.         if (strncmp(buf, "end", 3) == 0) return;
  418. /*
  419.  * end of current file ? : get next one.
  420.  */
  421.         if (strncmp(buf, "include", 7) == 0) {
  422.             getfile(buf);
  423.             continue;
  424.         }
  425. #ifdef TEST_LENGTH
  426. /*
  427.  * good length ?
  428.  */
  429.         efflen = len;
  430.  
  431.         /* Suppress bad chars at the end */
  432.         while(   (n >= 0)
  433.               && (efflen > 0)
  434.               && ! valid_char(buf[efflen-1])
  435.               ) efflen--;
  436.  
  437.         if(   (n >= 0)
  438.            && (efflen > 0)
  439.            && valid_length(efflen,n)
  440.            && ((debug||verify)
  441.                ? valid_chars(buf,efflen)
  442.                : valid_char(buf[efflen/2]))
  443.            )
  444.         {
  445.             if (debug||verify) {
  446.             if((numlbad!=-1) && (numlbad<numl-1))
  447.             {
  448.                 format("Bad lines %d--%d\n",
  449.                    numlbad, numl-1);
  450.             }
  451.             }
  452.             numlbad = -1;
  453.             goto decod;
  454.         }
  455.  
  456.         if(numlbad<0) {
  457.             numlbad = numl;
  458.             if (debug)
  459.             {
  460.             format("Bad line %d =%s\n", numl, buf);
  461.             format("n=%d --> %d, len=%d\n", n, cdlen[n], len);
  462.             }
  463.         }
  464.         continue;
  465. #else /* !TEST_LENGTH */
  466.         if (n >= 0) goto decod;
  467.         format("uud: Bad prefix line %d in file: %s\n",numl, ifname);
  468.         if (debug) format("Bad line =%s\n",buf);
  469.         Error(11);
  470. #endif /* TEST_LENGTH */
  471. /*
  472.  * Sequence checking ?
  473.  */
  474. decod:        rlen = cdlen[n];
  475. /*
  476.  * Is it the empty line before the end line ?
  477.  */
  478.         if (n == 0) continue;
  479. /*
  480.  * Pad with blanks.
  481.  */
  482.         for (bp = &buf[c = len];
  483.             c < rlen; c++, bp++) *bp = blank;
  484.  
  485. #if  !defined(TEST_LENGTH)
  486. /*
  487.  * Verify if asked for.
  488.  */
  489.         if (debug||verify) {
  490.             for (len = 0, bp = buf; len < rlen; len++) {
  491.                 if (trtbl[*bp] < 0) {
  492.                     format(
  493.     "Non uuencoded char <%c>, line %d in file: %s\n", *bp, numl, ifname);
  494.                     format("Bad line =%s\n",buf);
  495.                     Error(16);
  496.                 }
  497.                 bp++;
  498.             }
  499.         }
  500. #endif
  501.  
  502. /*
  503.  * All this just to check for uuencodes that append a 'z' to each line....
  504.  */
  505.         if (secnd && check) {
  506.             secnd = 0;
  507.             if (buf[rlen] == SEQMAX) {
  508.                 check = 0;
  509.                 if (debug) format("Sequence check turned off (2).\n");
  510.             } else
  511.                 if (debug) format("Sequence check on (2).\n");
  512.         } else if (first && check) {
  513.             first = 0;
  514.             secnd = 1;
  515.             if (buf[rlen] != SEQMAX) {
  516.                 check = 0;
  517.                 if (debug) format("No sequence check (1).\n");
  518.             } else
  519.                 if (debug) format("Sequence check on (1).\n");
  520.         }
  521. /*
  522.  * There we check.
  523.  */
  524.         if (check) {
  525.             if (buf[rlen] != seqc) {
  526.                 format("uud: Wrong sequence line %d in %s\n",
  527.                     numl, ifname);
  528.                 if (debug)
  529.                     format(
  530.     "Sequence char is <%c> instead of <%c>.\n", buf[rlen], seqc);
  531.                 Error(18);
  532.             }
  533.             seqc--;
  534.             if (seqc < SEQMIN) seqc = SEQMAX;
  535.         }
  536. /*
  537.  * output a group of 3 bytes (4 input characters).
  538.  * the input chars are pointed to by p, they are to
  539.  * be output to file f.n is used to tell us not to
  540.  * output all of them at the end of the file.
  541.  */
  542.         ut = outl;
  543.         len = n;
  544.         bp = &buf[1];
  545.         while (n > 0) {
  546.             *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
  547.             n--;
  548.             if (n) {
  549.                 *(ut++) = (trtbl[bp[1]] << 4) |
  550.                       (trtbl[bp[2]] >> 2);
  551.                 n--;
  552.             }
  553.             if (n) {
  554.                 *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
  555.                 n--;
  556.             }
  557.             bp += 4;
  558.         }
  559.         if ((n = fwrite(outl, 1, len, out)) <= 0) {
  560.             format("uud: Error on writing decoded file.\n");
  561.             Error(18);
  562.         }
  563.     }
  564. }
  565.  
  566. /*
  567.  * Find the next needed file, if existing, otherwise try further
  568.  * on next file.
  569.  */
  570. getfile(buf) register char *buf;
  571. {
  572.     if ((pos = getnword(buf, 2)) == NULL) {
  573.         format("uud: Missing include file name.\n");
  574.         Error(17);
  575.     } else
  576.         if (source != NULL) {
  577.             strcpy(ifname, source);
  578.             strcat(ifname, pos);
  579.         } else
  580.             strcpy(ifname, pos);
  581. #ifdef GEMDOS
  582.     if (Fattrib(ifname, 0, 0) < 0)
  583. #else
  584.     if (access(ifname, 04))
  585. #endif
  586.     {
  587.         if (debug) {
  588.             format("Cant find: %s\n", ifname);
  589.             format("Continuing to read same file.\n");
  590.         }
  591.     }
  592.     else {
  593.         if (freopen(ifname, "r", in) == in) {
  594.             numl = 0;
  595.             if (debug||verify) 
  596.                 format("Reading next section from: %s\n", ifname);
  597.         } else {
  598.             format("uud: Freopen abort: %s\n", ifname);
  599.             Error(9);
  600.         }
  601.     }
  602.     loop {
  603.         if (fgets(buf, LINELEN, in) == NULL) {
  604.             format("uud: No begin line after include: %s\n", ifname);
  605.             Error(12);
  606.         }
  607.         numl++;
  608.         if (strncmp(buf, "table", 5) == 0) {
  609.             gettable();
  610.             continue;
  611.         }
  612.         if (strncmp(buf, "begin", 5) == 0) break;
  613.     }
  614.     lens = strlen(buf);
  615.     if (lens) buf[--lens] = '\0';
  616. /*
  617.  * Check the part suffix.
  618.  */
  619.     if ((pos = getnword(buf, 3)) == NULL ) {
  620.         format("uud: Missing part name, in included file: %s\n", ifname);
  621.         Error(13);
  622.     } else {
  623.         part = *pos;
  624.         partn++;
  625.         if (partn > 'z') partn = 'a';
  626.         if (part != partn) {
  627.             format("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
  628.                 part, partn);
  629.             Error(14);
  630.         }
  631.         if (debug||verify) format("Reading part %c\n", *pos);
  632.     }
  633. }
  634.  
  635. #ifndef UNIX
  636. /*
  637.  * Printf style formatting. (Borrowed from MicroEmacs by Dave Conroy.) 
  638.  * A lot smaller than the full fledged printf.
  639.  */
  640. /* VARARGS1 */
  641. format(fp, args) char *fp;
  642. {
  643.     doprnt(fp, (char *)&args);
  644. }
  645.  
  646. doprnt(fp, ap)
  647. register char    *fp;
  648. register char    *ap;
  649. {
  650.     register int    c, k;
  651.     register char    *s;
  652.  
  653.     while ((c = *fp++) != '\0') {
  654.         if (c != '%')
  655.             outc(c);
  656.         else {
  657.             c = *fp++;
  658.             switch (c) {
  659.             case 'd':
  660.                 puti(*(int *)ap, 10);
  661.                 ap += sizeof(int);
  662.                 break;
  663.  
  664.             case 's':
  665.                 s = *(char **)ap;
  666.                 while ((k = *s++) != '\0')
  667.                     outc(k);
  668.                 ap += sizeof(char *);
  669.                 break;
  670.  
  671.             case 'c':
  672.                 outc(*(int *)ap);
  673.                 ap += sizeof(int);
  674.                 break;
  675.  
  676.             default:
  677.                 outc(c);
  678.             }
  679.         }
  680.     }
  681. }
  682.  
  683. /*
  684.  * Put integer, in radix "r".
  685.  */
  686. puti(i, r)
  687. register unsigned int    i;
  688. register unsigned int    r;
  689. {
  690.     register unsigned int    q, s;
  691.  
  692.     if ((q = i / r) != 0)
  693.         puti(q, r);
  694.     s = i % r;
  695.     if (s <= 9)
  696.         outc(s + '0');
  697.     else
  698.         outc(s - 10 + 'A');
  699. }
  700. outc(c) register char c;
  701. {
  702. #ifdef GEMDOS
  703.     if (c == '\n') Bconout(2, '\r');
  704.     Bconout(2, c);
  705. #else
  706.     putchar(c);
  707. #endif
  708. }
  709.  
  710. #endif
  711.