home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / flex254.zip / MISC / MVS / MVS.uudecode / uudecode.c
Encoding:
C/C++ Source or Header  |  1990-07-19  |  7.3 KB  |  291 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
  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.\
  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.  
  291.