uud.c

Go to the documentation of this file.
00001 /* uud - bulletproof version of uudecode */
00002 
00003 /*
00004  * Uud -- decode a uuencoded file back to binary form.
00005  *
00006  * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
00007  * The Atari GEMDOS version compiled with MWC 2.x.
00008  * The MSDOS version with TurboC.
00009  * The Unix version with cc.
00010  * this version is made: 25 Nov 1988.
00011  * Jan 2 1990: Change system definition and change MSDOS to open the output
00012  *             file for write binary do cr/lf replacement.
00013  */
00014 
00015 #define UNIX  1         /* define one of: UNIX (Minix too!), MSDOS, or GEMDOS */ 
00016 
00017 #ifdef GEMDOS
00018 #define SYSNAME "gemdos"
00019 #define SMALL 1
00020 #endif
00021 #ifdef MSDOS
00022 #define SYSNAME "msdos"
00023 #define SMALL 1
00024 #endif
00025 #ifdef UNIX
00026 #define SYSNAME "unix"
00027 #endif
00028 
00029 #include <sys/types.h>
00030 #include <stdarg.h>
00031 #include <string.h>
00032 #include <stdlib.h>
00033 #include <unistd.h>
00034 #include <sys/stat.h>
00035 #include <stdio.h>
00036 
00037 #ifdef GEMDOS
00038 #include <osbind.h>
00039 #define Error(n)  { Bconin(2); exit(n); }
00040 #else
00041 #define Error(n)  exit(n)
00042 #endif
00043 #ifdef UNIX
00044 #define WRITE     "w"
00045 #else
00046 #define WRITE     "wb"          /* for both MSDOS and GEMDOS!   */
00047 #endif
00048 
00049 #define loop    while (1)
00050 
00051 #define NCHARS  256
00052 #define LINELEN 256
00053 #define FILELEN 64
00054 #define NORMLEN 60      /* allows for 80 encoded chars per line */
00055 
00056 #define SEQMAX 'z'
00057 #define SEQMIN 'a'
00058 char seqc;
00059 int first, secnd, check, numl;
00060 
00061 FILE *in, *out;
00062 char *pos;
00063 char ifname[FILELEN], ofname[FILELEN];
00064 char *source = NULL, *target = NULL;
00065 char blank, part = '\0';
00066 int partn, lens;
00067 int debug = 0, nochk = 0, onedone = 0;
00068 int chtbl[NCHARS], cdlen[NORMLEN + 3];
00069 
00070 _PROTOTYPE(int main, (int argc, char **argv));
00071 _PROTOTYPE(char *getnword, (char *str, int n));
00072 _PROTOTYPE(void gettable, (void));
00073 _PROTOTYPE(void decode, (void));
00074 _PROTOTYPE(void getfile, (char *buf));
00075 _PROTOTYPE(void format, (char *fp, ...));
00076 _PROTOTYPE(void doprnt, (char *fp, char *ap));
00077 _PROTOTYPE(void puti, (unsigned int i, unsigned int r));
00078 _PROTOTYPE(void outc, (int c));
00079 
00080 int main(argc, argv) int argc; char *argv[];
00081 {
00082         int mode;
00083         register int i, j;
00084         char *curarg;
00085         char dest[FILELEN], buf[LINELEN];
00086 
00087         while ((curarg = argv[1]) != NULL && curarg[0] == '-') {
00088                 if (((curarg[1] == 'd') || (curarg[1] == 'D')) &&
00089                     (curarg[2] == '\0')) {
00090                         debug = 1;
00091                 } else if (((curarg[1] == 'n') || (curarg[1] == 'N')) &&
00092                            (curarg[2] == '\0')) {
00093                         nochk = 1;
00094                 } else if (((curarg[1] == 't') || (curarg[1] == 'T')) &&
00095                            (curarg[2] == '\0')) {
00096                         argv++;
00097                         argc--;
00098                         if (argc < 2) {
00099                                 format("uud: Missing target directory.\n");
00100                                 Error(15);
00101                         }
00102                         target = argv[1];
00103                         if (debug)
00104                                 format("Target dir = %s\n",target);
00105                 } else if (((curarg[1] == 's') || (curarg[1] == 'S')) &&
00106                            (curarg[2] == '\0')) {
00107                         argv++;
00108                         argc--;
00109                         if (argc < 2) {
00110                                 format("uud: Missing source directory.\n");
00111                                 Error(15);
00112                         }
00113                         source = argv[1];
00114                         if (debug)
00115                                 format("Source dir = %s\n",source);
00116                 } else if (curarg[1] != '\0') {
00117                         format("Usage: uud [-n] [-d] [-s dir] [-t dir] [input-file]\n");
00118                         Error(1);
00119                 } else
00120                         break;
00121                 argv++;
00122                 argc--;
00123         }
00124 
00125         if (curarg == NULL || ((curarg[0] == '-') && (curarg[1] == '\0'))) {
00126                 in = stdin;
00127                 strcpy(ifname, "<stdin>");
00128         } else {
00129                 if (source != NULL) {
00130                         strcpy(ifname, source);
00131                         strcat(ifname, curarg);
00132                 } else
00133                         strcpy(ifname, curarg);
00134                 if ((in = fopen(ifname, "r")) == NULL) {
00135                         format("uud: Can't open %s\n", ifname);
00136                         Error(2);
00137                 }
00138                 numl = 0;
00139         }
00140 
00141 /*
00142  * Set up the default translation table.
00143  */
00144         for (i = 0; i < ' '; i++) chtbl[i] = -1;
00145         for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
00146         for (i = ' ' + 64; i < NCHARS; i++) chtbl[i] = -1;
00147         chtbl['`'] = chtbl[' '];        /* common mutation */
00148         chtbl['~'] = chtbl['^'];        /* an other common mutation */
00149         blank = ' ';
00150 /*
00151  * set up the line length table, to avoid computing lotsa * and / ...
00152  */
00153         cdlen[0] = 1;
00154         for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
00155                 cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
00156 /*
00157  * search for header or translation table line.
00158  */
00159         loop {  /* master loop for multiple decodes in one file */
00160                 partn = 'a';
00161                 loop {
00162                         if (fgets(buf, sizeof buf, in) == NULL) {
00163                                 if (onedone) {
00164                                         if (debug) format("End of file.\n");
00165                                         exit(0);
00166                                 } else {
00167                                         format("uud: No begin line.\n");
00168                                         Error(3);
00169                                 }
00170                         }
00171                         numl++;
00172                         if (strncmp(buf, "table", (size_t)5) == 0) {
00173                                 gettable();
00174                                 continue;
00175                         }
00176                         if (strncmp(buf, "begin", (size_t)5) == 0) {
00177                                 break;
00178                         }
00179                 }
00180                 lens = strlen(buf);
00181                 if (lens) buf[--lens] = '\0';
00182 #ifdef SMALL
00183                 if ((pos = getnword(buf, 3))) {
00184                         strcpy(dest, pos);
00185                 } else
00186 #else
00187                 if(sscanf(buf,"begin%o%s", &mode, dest) != 2)
00188 #endif
00189                 {
00190                         format("uud: Missing filename in begin line.\n");
00191                         Error(10);
00192                 }
00193 
00194                 if (target != NULL) {
00195                         strcpy(ofname, target);
00196                         strcat(ofname, dest);
00197                 } else
00198                         strcpy(ofname, dest);
00199 
00200                 if((out = fopen(ofname, WRITE)) == NULL) {
00201                         format("uud: Cannot open output file: %s\n", ofname);
00202                         Error(4);
00203                 }
00204                 if (debug) format("Begin uudecoding: %s\n", ofname);
00205                 seqc = SEQMAX;
00206                 check = nochk ? 0 : 1;
00207                 first = 1;
00208                 secnd = 0;
00209                 decode();
00210                 fclose(out);
00211 #ifdef UNIX
00212                 chmod(ofname, mode);
00213 #endif
00214                 onedone = 1;
00215                 if (debug) format("End uudecoding: %s\n", ofname);
00216         }       /* master loop for multiple decodes in one file */
00217 }
00218 
00219 /*
00220  * Bring back a pointer to the start of the nth word.
00221  */
00222 char *getnword(str, n) register char *str; register int n;
00223 {
00224         while((*str == '\t') || (*str == ' ')) str++;
00225         if (! *str) return NULL;
00226         while(--n) {
00227                 while ((*str != '\t') && (*str != ' ') && (*str)) str++;
00228                 if (! *str) return NULL;
00229                 while((*str == '\t') || (*str == ' ')) str++;
00230                 if (! *str) return NULL;
00231         }
00232         return str;
00233 }
00234 
00235 /*
00236  * Install the table in memory for later use.
00237  */
00238 void gettable()
00239 {
00240         char buf[LINELEN];
00241         register int c, n = 0;
00242         register char *cpt;
00243 
00244         for (c = 0; c < NCHARS; c++) chtbl[c] = -1;
00245 
00246 again:  if (fgets(buf, sizeof buf, in) == NULL) {
00247                 format("uud: EOF while in translation table.\n");
00248                 Error(5);
00249         }
00250         numl++;
00251         if (strncmp(buf, "begin", (size_t)5) == 0) {
00252                 format("uud: Incomplete translation table.\n");
00253                 Error(6);
00254         }
00255         cpt = buf + strlen(buf) - 1;
00256         *cpt = ' ';
00257         while (*(cpt) == ' ') {
00258                 *cpt = 0;
00259                 cpt--;
00260         }
00261         cpt = buf;
00262         while (c = *cpt) {
00263                 if (chtbl[c] != -1) {
00264                         format("uud: Duplicate char in translation table.\n");
00265                         Error(7);
00266                 }
00267                 if (n == 0) blank = c;
00268                 chtbl[c] = n++;
00269                 if (n >= 64) return;
00270                 cpt++;
00271         }
00272         goto again;
00273 }
00274 
00275 /*
00276  * copy from in to out, decoding as you go along.
00277  */
00278 
00279 void decode()
00280 {
00281         char buf[LINELEN], outl[LINELEN];
00282         register char *bp, *ut;
00283         register int *trtbl = chtbl;
00284         register int n, c, rlen;
00285         register unsigned int len;
00286 
00287         loop {
00288                 if (fgets(buf, sizeof buf, in) == NULL) {
00289                         format("uud: EOF before end.\n");
00290                         fclose(out);
00291                         Error(8);
00292                 }
00293                 numl++;
00294                 len = strlen(buf);
00295                 if (len) buf[--len] = '\0';
00296 /*
00297  * Is it an unprotected empty line before the end line ?
00298  */
00299                 if (len == 0) continue;
00300 /*
00301  * Get the binary line length.
00302  */
00303                 n = trtbl[*buf];
00304                 if (n >= 0) goto decod;
00305 /*
00306  * end of uuencoded file ?
00307  */
00308                 if (strncmp(buf, "end", (size_t)3) == 0) return;
00309 /*
00310  * end of current file ? : get next one.
00311  */
00312                 if (strncmp(buf, "include", (size_t)7) == 0) {
00313                         getfile(buf);
00314                         continue;
00315                 }
00316                 format("uud: Bad prefix line %d in file: %s\n",numl, ifname);
00317                 if (debug) format("Bad line =%s\n",buf);
00318                 Error(11);
00319 /*
00320  * Sequence checking ?
00321  */
00322 decod:          rlen = cdlen[n];
00323 /*
00324  * Is it the empty line before the end line ?
00325  */
00326                 if (n == 0) continue;
00327 /*
00328  * Pad with blanks.
00329  */
00330                 for (bp = &buf[c = len];
00331                         c < rlen; c++, bp++) *bp = blank;
00332 /*
00333  * Verify if asked for.
00334  */
00335                 if (debug) {
00336                         for (len = 0, bp = buf; len < rlen; len++) {
00337                                 if (trtbl[*bp] < 0) {
00338                                         format(
00339         "Non uuencoded char <%c>, line %d in file: %s\n", *bp, numl, ifname);
00340                                         format("Bad line =%s\n",buf);
00341                                         Error(16);
00342                                 }
00343                                 bp++;
00344                         }
00345                 }
00346 /*
00347  * All this just to check for uuencodes that append a 'z' to each line....
00348  */
00349                 if (secnd && check) {
00350                         secnd = 0;
00351                         if (buf[rlen] == SEQMAX) {
00352                                 check = 0;
00353                                 if (debug) format("Sequence check turned off (2).\n");
00354                         } else
00355                                 if (debug) format("Sequence check on (2).\n");
00356                 } else if (first && check) {
00357                         first = 0;
00358                         secnd = 1;
00359                         if (buf[rlen] != SEQMAX) {
00360                                 check = 0;
00361                                 if (debug) format("No sequence check (1).\n");
00362                         } else
00363                                 if (debug) format("Sequence check on (1).\n");
00364                 }
00365 /*
00366  * There we check.
00367  */
00368                 if (check) {
00369                         if (buf[rlen] != seqc) {
00370                                 format("uud: Wrong sequence line %d in %s\n",
00371                                         numl, ifname);
00372                                 if (debug)
00373                                         format(
00374         "Sequence char is <%c> instead of <%c>.\n", buf[rlen], seqc);
00375                                 Error(18);
00376                         }
00377                         seqc--;
00378                         if (seqc < SEQMIN) seqc = SEQMAX;
00379                 }
00380 /*
00381  * output a group of 3 bytes (4 input characters).
00382  * the input chars are pointed to by p, they are to
00383  * be output to file f.n is used to tell us not to
00384  * output all of them at the end of the file.
00385  */
00386                 ut = outl;
00387                 len = n;
00388                 bp = &buf[1];
00389                 while (n > 0) {
00390                         *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
00391                         n--;
00392                         if (n) {
00393                                 *(ut++) = (trtbl[bp[1]] << 4) |
00394                                           (trtbl[bp[2]] >> 2);
00395                                 n--;
00396                         }
00397                         if (n) {
00398                                 *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
00399                                 n--;
00400                         }
00401                         bp += 4;
00402                 }
00403                 if ((n = fwrite(outl, (size_t)1, (size_t)len, out)) <= 0) {
00404                         format("uud: Error on writing decoded file.\n");
00405                         Error(18);
00406                 }
00407         }
00408 }
00409 
00410 /*
00411  * Find the next needed file, if existing, otherwise try further
00412  * on next file.
00413  */
00414 void getfile(buf) register char *buf;
00415 {
00416         if ((pos = getnword(buf, 2)) == NULL) {
00417                 format("uud: Missing include file name.\n");
00418                 Error(17);
00419         } else
00420                 if (source != NULL) {
00421                         strcpy(ifname, source);
00422                         strcat(ifname, pos);
00423                 } else
00424                         strcpy(ifname, pos);
00425 #ifdef GEMDOS
00426         if (Fattrib(ifname, 0, 0) < 0)
00427 #else
00428         if (access(ifname, 04))
00429 #endif
00430         {
00431                 if (debug) {
00432                         format("Cant find: %s\n", ifname);
00433                         format("Continuing to read same file.\n");
00434                 }
00435         }
00436         else {
00437                 if (freopen(ifname, "r", in) == in) {
00438                         numl = 0;
00439                         if (debug) 
00440                                 format("Reading next section from: %s\n", ifname);
00441                 } else {
00442                         format("uud: Freopen abort: %s\n", ifname);
00443                         Error(9);
00444                 }
00445         }
00446         loop {
00447                 if (fgets(buf, LINELEN, in) == NULL) {
00448                         format("uud: No begin line after include: %s\n", ifname);
00449                         Error(12);
00450                 }
00451                 numl++;
00452                 if (strncmp(buf, "table", (size_t)5) == 0) {
00453                         gettable();
00454                         continue;
00455                 }
00456                 if (strncmp(buf, "begin", (size_t)5) == 0) break;
00457         }
00458         lens = strlen(buf);
00459         if (lens) buf[--lens] = '\0';
00460 /*
00461  * Check the part suffix.
00462  */
00463         if ((pos = getnword(buf, 3)) == NULL ) {
00464                 format("uud: Missing part name, in included file: %s\n", ifname);
00465                 Error(13);
00466         } else {
00467                 part = *pos;
00468                 partn++;
00469                 if (partn > 'z') partn = 'a';
00470                 if (part != partn) {
00471                         format("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
00472                                 part, partn);
00473                         Error(14);
00474                 }
00475                 if (debug) format("Reading part %c\n", *pos);
00476         }
00477 }
00478 
00479 /*
00480  * Printf style formatting. (Borrowed from MicroEmacs by Dave Conroy.) 
00481  * A lot smaller than the full fledged printf.
00482  */
00483 #ifdef __STDC__
00484 void format(char *fp, ...)
00485 {
00486   va_list args;
00487 
00488   va_start (args, fp);
00489   doprnt(fp, (char *)&args);
00490   va_end(args);
00491 }
00492 #else
00493 /* VARARGS1 */
00494 void format(fp, args) char *fp;
00495 {
00496         doprnt(fp, (char *)&args);
00497 }
00498 #endif
00499 
00500 void doprnt(fp, ap)
00501 register char   *fp;
00502 register char   *ap;
00503 {
00504         register int    c, k;
00505         register char   *s;
00506 
00507         while ((c = *fp++) != '\0') {
00508                 if (c != '%')
00509                         outc(c);
00510                 else {
00511                         c = *fp++;
00512                         switch (c) {
00513                         case 'd':
00514                                 puti(*(int *)ap, 10);
00515                                 ap += sizeof(int);
00516                                 break;
00517 
00518                         case 's':
00519                                 s = *(char **)ap;
00520                                 while ((k = *s++) != '\0')
00521                                         outc(k);
00522                                 ap += sizeof(char *);
00523                                 break;
00524 
00525                         case 'c':
00526                                 outc(*(int *)ap);
00527                                 ap += sizeof(int);
00528                                 break;
00529 
00530                         default:
00531                                 outc(c);
00532                         }
00533                 }
00534         }
00535 }
00536 
00537 /*
00538  * Put integer, in radix "r".
00539  */
00540 void puti(i, r)
00541 register unsigned int   i;
00542 register unsigned int   r;
00543 {
00544         register unsigned int   q, s;
00545 
00546         if ((q = i / r) != 0)
00547                 puti(q, r);
00548         s = i % r;
00549         if (s <= 9)
00550                 outc(s + '0');
00551         else
00552                 outc(s - 10 + 'A');
00553 }
00554 void outc(c) register char c;
00555 {
00556 #ifdef GEMDOS
00557         if (c == '\n') Bconout(2, '\r');
00558         Bconout(2, c);
00559 #else
00560         putchar(c);
00561 #endif
00562 }

Generated on Fri Apr 14 22:57:13 2006 for minix by  doxygen 1.4.6