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