home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / nuudecode < prev    next >
Text File  |  1989-02-03  |  13KB  |  494 lines

  1. Path: xanth!mcnc!decvax!decwrl!purdue!umd5!ames!necntc!ncoast!allbery
  2. From: art@felix.UUCP (Art Dederick)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i051: comp.sources.misc posting request
  5. Message-ID: <8805222336.AA07991@fritz.UUCP>
  6. Date: 12 Jun 88 22:01:56 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: art@felix.UUCP (Art Dederick)
  9. Lines: 482
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. comp.sources.misc: Volume 3, Issue 51
  13. Submitted-By: "Art Dederick" <art@felix.UUCP>
  14. Archive-Name: nuudecode
  15.  
  16. [I installed a patch and wrapped it in a shar.  ++bsa]
  17.  
  18.     Here is the full source to the uudecode program last submitted
  19.     with the best features I could find that have been posted for the
  20.     last five years.  I added the ability to process sectionized
  21.     encoded files created by Richard Marks' v2.13 UUDECODE.  He seems
  22.     to be using a different checksum algorithm than the standard one
  23.     so if I detect a sectioned encoded file I ignore the checksum.  If
  24.     I get the algorithm Richard is using I will add it to this version.
  25.  
  26.     If one wishes to decode one of Richard's sectioned postings, cat
  27.     all the postings in the proper sequence and pipe to this version
  28.     of uudecode.  Alternatively, just cat all sections, again in the
  29.     proper order, into a file then pass to uudecode.  The former is
  30.     easier on disk space.
  31.  
  32. Art Dederick
  33. {trwrb,hplabs,oliveb}!felix!art
  34. FileNet Corp.
  35. 3565 Harbor Blvd.
  36. Costa Mesa, CA 92626
  37. (714) 966-3618
  38.  
  39. #--------------------------------CUT HERE-------------------------------------
  40. #! /bin/sh
  41. #
  42. # This is a shell archive.  Save this into a file, edit it
  43. # and delete all lines above this comment.  Then give this
  44. # file to sh by executing the command "sh file".  The files
  45. # will be extracted into the current directory owned by
  46. # you with default permissions.
  47. #
  48. # The files contained herein are:
  49. #
  50. # -rw-r--r--   1 allbery  System     10483 Jun 12 17:57 uudecode.c
  51. #
  52. echo 'x - uudecode.c'
  53. if test -f uudecode.c; then echo 'shar: not overwriting uudecode.c'; else
  54. sed 's/^X//' << '________This_Is_The_END________' > uudecode.c
  55. X/* #ifndef lint
  56. Xstatic char sccsid[] = "@(#)uudecode.c  5.3-1 (Berkeley) 9/1/87";
  57. X#endif */
  58. X
  59. X/* Written by Mark Horton */
  60. X/* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */
  61. X/* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
  62. X   compatibility */
  63. X/* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
  64. X   error message on the Amiga port, to fix a bug that prevented decoding
  65. X   certain files, to work even if trailing spaces have been removed from a
  66. X   file, to check the filesize (if present), to add some error checking, to
  67. X   loop for multiple decodes from a single file, and to handle common
  68. X   BITNET mangling.  Also kludged around a missing string function in Aztec
  69. X   C */
  70. X/* Modified by drw (Dale Worley, drw@math.mit.edu) to add the -f switch, which
  71. X   forces the output to be on stdout.  This makes uudecode into a filter, and
  72. X   frees the user from perversions in the file name and mode given in the
  73. X   input file. These changes Copyright (C) 1987 Dale R. Worley, and are hereby
  74. X   put in the public domain. */
  75. X/* Modified by art (Art Dederick, {trwrb,oliveb,hplabs}!felix!art) to scan
  76. X   for sectionized encoded files created by Richard Marks' v2.13 UUDECODE
  77. X   program.  Cat all sections in the proper order then pass to uudecode.
  78. X   Added a more manageable method for assigning exit error codes. */
  79. X
  80. X/*
  81. X * uudecode [-f] [input]
  82. X *
  83. X * Decode a file encoded with uuencode.  WIll extract multiple encoded
  84. X * modules from a single file.    Can deal with most mangled files, including
  85. X * BITNET.  Will handle sectioned encoded files also.
  86. X */
  87. X
  88. X#include <stdio.h>
  89. X#include <ctype.h>
  90. X
  91. X#ifdef AMIGA
  92. X#define AMIGA_LATTICE        /* Set for Amiga Lattice C */
  93. X#define MCH_AMIGA
  94. X#define MPU68000
  95. X#endif
  96. X
  97. X#ifdef unix
  98. X#include <pwd.h>
  99. X#include <sys/types.h>
  100. X#include <sys/stat.h>
  101. X#endif
  102. X
  103. X/* Exit error codes */
  104. X#define err_ok            0
  105. X#define err_dest_open        1
  106. X#define err_dest_write        2
  107. X#define err_eof            3
  108. X#define err_in_open        4
  109. X#define err_no_begin        5
  110. X#define err_no_end        6
  111. X#define err_no_user        7
  112. X#define err_out_close        8
  113. X#define err_sect_seq        9
  114. X#define err_sect_size        10
  115. X#define err_size        11
  116. X#define err_tilda_user        12
  117. X#define err_usage        13
  118. X
  119. Xchar section_str[] = "======= [ remove this line";
  120. X#define section_str_sz (sizeof(section_str) - 1)
  121. X
  122. Xint    section = 0;    /* section flag and next section to get */
  123. Xlong    written_size;    /* number of bytes written to output, used instead of
  124. X               ftell, because ftell doesn't work with -f */
  125. X
  126. X#define SUMSIZE 64
  127. X#define DEC(c)    (((c) - ' ') & 077)    /* single character decode */
  128. X
  129. Xmain(argc, argv)
  130. Xchar **argv;
  131. X{
  132. XFILE    *in, *out;
  133. Xint    through_loop=0; /* Dejavu indicator */
  134. Xint    mode;        /* file's mode (from header) */
  135. Xlong    filesize;    /* theoretical file size (from header) */
  136. Xchar    dest[128];
  137. Xchar    buf[80];
  138. Xint    f_option = 0;    /* set to 1 if -f option is present */
  139. X
  140. X#ifdef AMIGA_LATTICE
  141. Xextern    int Enable_Abort;
  142. X    Enable_Abort=1;
  143. X#endif
  144. X
  145. X    /* First, check for the -f option */
  146. X    if (argc >= 2 && strcmp(argv[1], "-f") == 0)
  147. X        {
  148. X        f_option = 1;
  149. X        argc--; argv++;
  150. X        }
  151. X
  152. X    /* A filename can be specified to be uudecoded, or nothing can
  153. X    be specified, and the input will come from STDIN */
  154. X
  155. X    switch (argc)
  156. X    {
  157. X    case 1:
  158. X    in=stdin;
  159. X    break;
  160. X
  161. X    case 2:
  162. X    if ((in = fopen(argv[1], "r")) == NULL)
  163. X        {
  164. X        fprintf(stderr, "ERROR: can't find %s\n", argv[1]);
  165. X        fprintf(stderr, "USAGE: uudecode [-f] [infile]\n");
  166. X        exit(err_in_open);
  167. X        }
  168. X    break;
  169. X
  170. X    default:
  171. X    fprintf(stderr, "USAGE: uudecode [-f] [infile]\n");
  172. X    exit(err_usage);
  173. X    break;
  174. X    }
  175. X
  176. X    /* Loop through file, searching for headers.  Decode anything with a
  177. X       header, complain if there where no headers. */
  178. X
  179. Xfor (;;)
  180. X{
  181. X    /* search file for header line */
  182. X    for (;;)
  183. X    {
  184. X    if (fgets(buf, sizeof buf, in) == NULL)
  185. X        {
  186. X        if (!through_loop)
  187. X        {
  188. X        fprintf(stderr, "ERROR: no `begin' line!\n");
  189. X        exit(err_no_begin);
  190. X        }
  191. X        else
  192. X        {
  193. X        exit(err_ok);
  194. X        }
  195. X        }
  196. X    if (strncmp(buf, "section 1 of uuencode", 21) == 0)
  197. X        section = 1;
  198. X    else if (strncmp(buf, "begin ", 6) == 0)
  199. X        break;
  200. X    }
  201. X    sscanf(buf, "begin %o %s", &mode, dest);
  202. X
  203. X    /* set up the output file */
  204. X    if (f_option)
  205. X        {
  206. X        /* the -f option is used, so use stdout */
  207. X    out = stdout;
  208. X        }
  209. X    else
  210. X        {
  211. X        /* the -f option is not used, so use the filename (and mode) in the
  212. X         * begin line */
  213. X#ifdef unix
  214. X    /* handle ~user/file format */
  215. X    if (dest[0] == '~')
  216. X        {
  217. X        char *sl;
  218. X        struct passwd *getpwnam();
  219. X        char *index();
  220. X        struct passwd *user;
  221. X        char dnbuf[100];
  222. X
  223. X        sl = index(dest, '/');
  224. X        if (sl == NULL)
  225. X        {
  226. X        fprintf(stderr, "Illegal ~user\n");
  227. X            exit(err_tilda_user);
  228. X        }
  229. X        *sl++ = 0;
  230. X        user = getpwnam(dest+1);
  231. X        if (user == NULL)
  232. X        {
  233. X        fprintf(stderr, "No such user as %s\n", dest);
  234. X        exit(err_no_user);
  235. X        }
  236. X        strcpy(dnbuf, user->pw_dir);
  237. X        strcat(dnbuf, "/");
  238. X        strcat(dnbuf, sl);
  239. X        strcpy(dest, dnbuf);
  240. X        }
  241. X#endif
  242. X
  243. X    /* create output file */
  244. X    if ((out = fopen(dest, "w")) == NULL)
  245. X        {
  246. X        fprintf(stderr, "ERROR: can't open output file %s\n", dest);
  247. X        exit(err_dest_open);
  248. X        }
  249. X#ifdef unix
  250. X    chmod(dest, mode);
  251. X#endif
  252. X       }
  253. X
  254. X    /* actually decode the data */
  255. X    decode(in, out, dest);
  256. X
  257. X    if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
  258. X    {           /* don't be overly picky about newline ^ */
  259. X    fprintf(stderr, "ERROR: no `end' line\n");
  260. X    exit(err_no_end);
  261. X    }
  262. X
  263. X    if (section) {
  264. X    /* suck up the section trailer before the size line */
  265. X    if (fgets(buf,sizeof buf,in) == NULL) {
  266. X        fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  267. X        exit(err_eof);
  268. X    }
  269. X    }
  270. X    if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
  271. X    {
  272. X    sscanf(buf, "size %ld", &filesize);
  273. X    if (written_size != filesize)
  274. X        {
  275. X        fprintf(stderr,
  276. X        "ERROR: file should have been %ld bytes long but was %ld.\n",
  277. X        filesize, written_size);
  278. X        exit(err_size);
  279. X        }
  280. X    }
  281. X
  282. X    /* close the output file */
  283. X    if (!f_option)
  284. X        if (fclose(out) != 0)
  285. X            {
  286. X        fprintf(stderr, "ERROR: error closing file %s.\n", dest);
  287. X        exit(err_out_close);
  288. X        }
  289. X
  290. X    through_loop = 1;
  291. X}   /* forever */
  292. X}   /* main */
  293. X
  294. X/*
  295. X * Copy from in to out, decoding as you go.
  296. X * If a return or newline is encountered too early in a line, it is
  297. X * assumed that means that some editor has truncated trailing spaces.
  298. X */
  299. Xdecode(in, out, dest)
  300. XFILE *in;
  301. XFILE *out;
  302. Xchar *dest;
  303. X{
  304. Xchar buf[81];
  305. Xchar *bp;
  306. Xint nosum=0;
  307. X#ifndef unix
  308. Xextern errno;
  309. X#endif
  310. Xint j;
  311. Xregister int n;
  312. Xint checksum, line, section_size;
  313. X
  314. X    /* zero the byte count and initial section size*/
  315. X    section_size = written_size = 0;
  316. X
  317. X    for (line = 1; ; line++)    /* for each input line */
  318. X    {
  319. X    if (fgets(buf, sizeof buf, in) == NULL)
  320. X        {
  321. X        fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  322. X        exit(err_eof);
  323. X        }
  324. X
  325. X    /* Is this section finished? */
  326. X    if (section &&
  327. X        ((strncmp(buf, section_str, section_str_sz) == 0)
  328. X        || buf[0] == '\n' || buf[0] == '\r')) {
  329. X        long size;
  330. X
  331. X        /* Scan for section size */
  332. X        do {
  333. X        line++;
  334. X            if (fgets(buf, sizeof buf, in) == NULL) {
  335. X            fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  336. X            exit(err_eof);
  337. X            }
  338. X        n = sscanf(buf, "section size %ld", &size);
  339. X        } while (n != 1);
  340. X        line++;
  341. X        if (section_size != size) {
  342. X        fprintf(stderr, "ERROR: section size wrong!\n");
  343. X        exit(err_sect_size);
  344. X        }
  345. X        section_size = 0;
  346. X        section++;
  347. X        /* Scan for start of next section */
  348. X        for (n = 0; n != 1;) {
  349. X        line++;
  350. X        if (fgets(buf, sizeof buf, in) == NULL) {
  351. X            fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  352. X            exit(err_eof);
  353. X        }
  354. X        n = sscanf(buf, "section %d of uuencode", &j);
  355. X        }
  356. X        if (section != j) {
  357. X        fprintf(stderr, "ERROR: section %d out of sequence!\n", j);
  358. X        exit(err_sect_seq);
  359. X        }
  360. X        while (buf[0] != 'M') {
  361. X        line++;
  362. X        if (fgets(buf, sizeof buf, in) == NULL) {
  363. X            fprintf(stderr, "ERROR: input ended unexpectedly!\n");
  364. X            exit(err_eof);
  365. X        }
  366. X        }
  367. X    }
  368. X    /* Pad end of lines in case some editor truncated trailing
  369. X       spaces */
  370. X
  371. X    for (n=0;n<79;n++)  /* search for first \r, \n or \000 */
  372. X        {
  373. X        if (buf[n]=='\176')     /* If BITNET made a twiddle, */
  374. X        buf[n]='\136';     /* we make a caret           */
  375. X        if (buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000')
  376. X        break;
  377. X        }
  378. X    for (;n<79;n++)     /* when found, fill rest of line with space */
  379. X        {
  380. X        buf[n]=' ';
  381. X        }
  382. X    buf[79]=0;        /* terminate new string */
  383. X
  384. X    checksum = 0;
  385. X    n = DEC(buf[0]);
  386. X    if (n <= 0)
  387. X        break;    /* 0 bytes on a line??    Must be the last line */
  388. X
  389. X    bp = &buf[1];
  390. X
  391. X    /* FOUR input characters go into each THREE output characters */
  392. X
  393. X    while (n >= 4)
  394. X        {
  395. X        j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
  396. X        putc(j, out);
  397. X        checksum += j;
  398. X        written_size++;
  399. X        section_size++;
  400. X
  401. X        j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
  402. X        putc(j, out);
  403. X        checksum += j;
  404. X        written_size++;
  405. X        section_size++;
  406. X
  407. X        j = DEC(bp[2]) << 6 | DEC(bp[3]);
  408. X        putc(j, out);
  409. X        checksum += j;
  410. X        written_size++;
  411. X        section_size++;
  412. X
  413. X        checksum = checksum % SUMSIZE;
  414. X        bp += 4;
  415. X        n -= 3;
  416. X        }
  417. X
  418. X        j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
  419. X        checksum += j;
  420. X        if (n >= 1)
  421. X            {
  422. X            putc(j, out);
  423. X            written_size++;
  424. X            section_size++;
  425. X            }
  426. X        j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
  427. X        checksum += j;
  428. X        if (n >= 2)
  429. X            {
  430. X            putc(j, out);
  431. X            written_size++;
  432. X            section_size++;
  433. X            }
  434. X        j = DEC(bp[2]) << 6 | DEC(bp[3]);
  435. X        checksum += j;
  436. X        if (n >= 3)
  437. X            {
  438. X            putc(j, out);
  439. X            written_size++;
  440. X            section_size++;
  441. X            }
  442. X        checksum = checksum % SUMSIZE;
  443. X        bp += 4;
  444. X        n -= 3;
  445. X
  446. X#ifndef unix
  447. X     /* Error checking under UNIX??? You must be kidding... */
  448. X     /* Check if an error occured while writing to that last line */
  449. X    if (errno)
  450. X        {
  451. X        fprintf(stderr, "ERROR: error writing to %s\n",dest);
  452. X        exit(err_dest_write);
  453. X        }
  454. X#endif
  455. X
  456. X    /* The line has been decoded; now check that sum */
  457. X
  458. X    nosum |= !isspace(*bp);
  459. X    if (nosum && !section)            /* Is there a checksum at all?? */
  460. X        {
  461. X        if (checksum != DEC(*bp))    /* Does that checksum match? */
  462. X        {
  463. X        fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line);
  464. X        }
  465. X        }    /* sum */
  466. X    }    /* line */
  467. X}   /* function */
  468. X
  469. X#ifdef unix
  470. X/*
  471. X * Return the ptr in sp at which the character c appears;
  472. X * 0 if not found
  473. X */
  474. Xchar *
  475. Xindex(sp, c)
  476. Xregister char *sp, c;
  477. X{
  478. X    do
  479. X    {
  480. X    if (*sp == c)
  481. X        return(sp);
  482. X    }
  483. X    while (*sp++);
  484. X
  485. X    return(0);
  486. X}
  487. X#endif unix
  488. ________This_Is_The_END________
  489. if test `wc -c < uudecode.c` -ne 10483; then
  490.     echo 'shar: uudecode.c was damaged during transit (should have been 10483 bytes)'
  491. fi
  492. fi        ; : end of overwriting check
  493. exit 0
  494.