home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8709 / 6 / uudecode.c next >
Encoding:
C/C++ Source or Header  |  1987-09-11  |  6.3 KB  |  290 lines

  1. /* #ifndef lint
  2. static char sccsid[] = "@(#)uudecode.c  5.3-1 (Berkeley) 9/1/87";
  3. #endif */
  4.  
  5. /* Written by Mark Horton */
  6. /* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */
  7. /* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
  8.    compatibility */
  9. /* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
  10.    error message on the Amiga port, to fix a bug that prevented decoding
  11.    certain files, to work even if trailing spaces have been removed from a
  12.    file, to check the filesize (if present), to add some error checking, to
  13.    loop for multiple decodes from a single file, and to handle common
  14.    BITNET mangling.  Also kludged around a missing string function in Aztec
  15.    C */
  16.  
  17. /*
  18.  * uudecode [input]
  19.  *
  20.  * Decode a file encoded with uuencode.  WIll extract multiple encoded
  21.  * modules from a single file.    Can deal with most mangled files, including
  22.  * BITNET.
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27.  
  28. #ifdef AMIGA
  29. #define AMIGA_LATTICE        /* Set for Amiga Lattice C */
  30. #define MCH_AMIGA
  31. #define MPU68000
  32. #endif
  33.  
  34. #ifdef unix
  35. #include <pwd.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #endif
  39.  
  40. #define SUMSIZE 64
  41. #define DEC(c)    (((c) - ' ') & 077)    /* single character decode */
  42.  
  43. main(argc, argv)
  44. char **argv;
  45. {
  46. FILE    *in, *out;
  47. int    through_loop=0; /* Dejavu indicator */
  48. int    mode;        /* file's mode (from header) */
  49. long    filesize;    /* theoretical file size (from header) */
  50. char    dest[128];
  51. char    buf[80];
  52.  
  53. #ifdef AMIGA_LATTICE
  54. extern    int Enable_Abort;
  55.     Enable_Abort=1;
  56. #endif
  57.  
  58.     /* A filename can be specified to be uudecoded, or nothing can
  59.     be specified, and the input will come from STDIN */
  60.  
  61.     switch (argc)
  62.     {
  63.     case 1:
  64.     in=stdin;
  65.     break;
  66.  
  67.     case 2:
  68.     if ((in = fopen(argv[1], "r")) == NULL)
  69.         {
  70.         fprintf(stderr, "ERROR: can't find %s\n", argv[1]);
  71.         fprintf(stderr, "USAGE: uudecode [infile]\n");
  72.         exit(10);
  73.         }
  74.     break;
  75.  
  76.     default:
  77.     fprintf(stderr, "USAGE: uudecode [infile]\n");
  78.     exit(11);
  79.     break;
  80.     }
  81.  
  82.     /* Loop through file, searching for headers.  Decode anything with a
  83.        header, complain if there where no headers. */
  84.  
  85. for (;;)
  86. {
  87.     /* search file for header line */
  88.     for (;;)
  89.     {
  90.     if (fgets(buf, sizeof buf, in) == NULL)
  91.         {
  92.         if (!through_loop)
  93.         {
  94.         fprintf(stderr, "ERROR: no `begin' line!\n");
  95.         exit(12);
  96.         }
  97.         else
  98.         {
  99.         exit(0);
  100.         }
  101.         }
  102.     if (strncmp(buf, "begin ", 6) == 0)
  103.         break;
  104.     }
  105.     sscanf(buf, "begin %o %s", &mode, dest);
  106.  
  107. #ifdef unix
  108.     /* handle ~user/file format */
  109.     if (dest[0] == '~')
  110.     {
  111.     char *sl;
  112.     struct passwd *getpwnam();
  113.     char *index();
  114.     struct passwd *user;
  115.     char dnbuf[100];
  116.  
  117.     sl = index(dest, '/');
  118.     if (sl == NULL)
  119.         {
  120.         fprintf(stderr, "Illegal ~user\n");
  121.         exit(13);
  122.         }
  123.     *sl++ = 0;
  124.     user = getpwnam(dest+1);
  125.     if (user == NULL)
  126.         {
  127.         fprintf(stderr, "No such user as %s\n", dest);
  128.         exit(14);
  129.         }
  130.     strcpy(dnbuf, user->pw_dir);
  131.     strcat(dnbuf, "/");
  132.     strcat(dnbuf, sl);
  133.     strcpy(dest, dnbuf);
  134.     }
  135. #endif
  136.  
  137.     /* create output file */
  138.     if ((out = fopen(dest, "w")) == NULL)
  139.     {
  140.     fprintf(stderr, "ERROR: can't open output file %s\n", dest);
  141.     exit(15);
  142.     }
  143. #ifdef unix
  144.     chmod(dest, mode);
  145. #endif
  146.  
  147.     decode(in, out, dest);
  148.  
  149.     if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
  150.     {           /* don't be overly picky about newline ^ */
  151.     fprintf(stderr, "ERROR: no `end' line\n");
  152.     exit(16);
  153.     }
  154.  
  155.     if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
  156.     {
  157.     sscanf(buf, "size %ld", &filesize);
  158.     if (ftell(out) != filesize)
  159.         {
  160.         fprintf(stderr, "ERROR: file should have been %ld bytes long but was %ld.\n", filesize, ftell(out));
  161.         exit(17);
  162.         }
  163.     }
  164.     through_loop = 1;
  165. }   /* forever */
  166. }   /* main */
  167.  
  168. /*
  169.  * Copy from in to out, decoding as you go.
  170.  * If a return or newline is encountered too early in a line, it is
  171.  * assumed that means that some editor has truncated trailing spaces.
  172.  */
  173. decode(in, out, dest)
  174. FILE *in;
  175. FILE *out;
  176. char *dest;
  177. {
  178. char buf[81];
  179. char *bp;
  180. int nosum=0;
  181. #ifndef unix
  182. extern errno;
  183. #endif
  184. register int j;
  185. register int n;
  186. int checksum, line;
  187.  
  188.     for (line = 1; ; line++)    /* for each input line */
  189.     {
  190.     if (fgets(buf, sizeof buf, in) == NULL)
  191.         {
  192.         fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  193.         exit(18);
  194.         }
  195.  
  196.     /* Pad end of lines in case some editor truncated trailing
  197.        spaces */
  198.  
  199.     for (n=0;n<79;n++)  /* search for first \r, \n or \000 */
  200.         {
  201.         if (buf[n]=='\176')     /* If BITNET made a twiddle, */
  202.         buf[n]='\136';     /* we make a caret           */
  203.         if (buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000')
  204.         break;
  205.         }
  206.     for (;n<79;n++)     /* when found, fill rest of line with space */
  207.         {
  208.         buf[n]=' ';
  209.         }
  210.     buf[79]=0;        /* terminate new string */
  211.  
  212.     checksum = 0;
  213.     n = DEC(buf[0]);
  214.     if (n <= 0)
  215.         break;    /* 0 bytes on a line??    Must be the last line */
  216.  
  217.     bp = &buf[1];
  218.  
  219.     /* FOUR input characters go into each THREE output charcters */
  220.  
  221.     while (n >= 4)
  222.         {
  223.         j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; putc(j, out); checksum += j;
  224.         j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; putc(j, out); checksum += j;
  225.         j = DEC(bp[2]) << 6 | DEC(bp[3]);       putc(j, out); checksum += j;
  226.         checksum = checksum % SUMSIZE;
  227.         bp += 4;
  228.         n -= 3;
  229.         }
  230.  
  231.         j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
  232.         checksum += j;
  233.         if (n >= 1)
  234.             putc(j, out);
  235.         j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
  236.         checksum += j;
  237.         if (n >= 2)
  238.             putc(j, out);
  239.         j = DEC(bp[2]) << 6 | DEC(bp[3]);
  240.         checksum += j;
  241.         if (n >= 3)
  242.             putc(j, out);
  243.         checksum = checksum % SUMSIZE;
  244.         bp += 4;
  245.         n -= 3;
  246.  
  247. #ifndef unix
  248.      /* Error checking under UNIX??? You must be kidding... */
  249.      /* Check if an error occured while writing to that last line */
  250.     if (errno)
  251.         {
  252.         fprintf(stderr, "ERROR: error writing to %s\n",dest);
  253.         exit(19);
  254.         }
  255. #endif
  256.  
  257.     /* The line has been decoded; now check that sum */
  258.  
  259.     nosum |= !isspace(*bp);
  260.     if (nosum)            /* Is there a checksum at all?? */
  261.         {
  262.         if (checksum != DEC(*bp))    /* Does that checksum match? */
  263.         {
  264.         fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line);
  265.         }
  266.         }    /* sum */
  267.     }    /* line */
  268. }   /* function */
  269.  
  270. #ifdef unix
  271. /*
  272.  * Return the ptr in sp at which the character c appears;
  273.  * 0 if not found
  274.  */
  275. char *
  276. index(sp, c)
  277. register char *sp, c;
  278. {
  279.     do
  280.     {
  281.     if (*sp == c)
  282.         return(sp);
  283.     }
  284.     while (*sp++);
  285.  
  286.     return(0);
  287. }
  288. #endif unix
  289.  
  290.