[comp.sources.misc] v03i051: comp.sources.misc posting request

art@felix.UUCP (Art Dederick) (06/13/88)

comp.sources.misc: Volume 3, Issue 51
Submitted-By: "Art Dederick" <art@felix.UUCP>
Archive-Name: nuudecode

[I installed a patch and wrapped it in a shar.  ++bsa]

    Here is the full source to the uudecode program last submitted
    with the best features I could find that have been posted for the
    last five years.  I added the ability to process sectionized
    encoded files created by Richard Marks' v2.13 UUDECODE.  He seems
    to be using a different checksum algorithm than the standard one
    so if I detect a sectioned encoded file I ignore the checksum.  If
    I get the algorithm Richard is using I will add it to this version.

    If one wishes to decode one of Richard's sectioned postings, cat
    all the postings in the proper sequence and pipe to this version
    of uudecode.  Alternatively, just cat all sections, again in the
    proper order, into a file then pass to uudecode.  The former is
    easier on disk space.

Art Dederick
{trwrb,hplabs,oliveb}!felix!art
FileNet Corp.
3565 Harbor Blvd.
Costa Mesa, CA 92626
(714) 966-3618

#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r--   1 allbery  System     10483 Jun 12 17:57 uudecode.c
#
echo 'x - uudecode.c'
if test -f uudecode.c; then echo 'shar: not overwriting uudecode.c'; else
sed 's/^X//' << '________This_Is_The_END________' > uudecode.c
X/* #ifndef lint
Xstatic char sccsid[] = "@(#)uudecode.c  5.3-1 (Berkeley) 9/1/87";
X#endif */
X
X/* Written by Mark Horton */
X/* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */
X/* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
X   compatibility */
X/* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
X   error message on the Amiga port, to fix a bug that prevented decoding
X   certain files, to work even if trailing spaces have been removed from a
X   file, to check the filesize (if present), to add some error checking, to
X   loop for multiple decodes from a single file, and to handle common
X   BITNET mangling.  Also kludged around a missing string function in Aztec
X   C */
X/* Modified by drw (Dale Worley, drw@math.mit.edu) to add the -f switch, which
X   forces the output to be on stdout.  This makes uudecode into a filter, and
X   frees the user from perversions in the file name and mode given in the
X   input file. These changes Copyright (C) 1987 Dale R. Worley, and are hereby
X   put in the public domain. */
X/* Modified by art (Art Dederick, {trwrb,oliveb,hplabs}!felix!art) to scan
X   for sectionized encoded files created by Richard Marks' v2.13 UUDECODE
X   program.  Cat all sections in the proper order then pass to uudecode.
X   Added a more manageable method for assigning exit error codes. */
X
X/*
X * uudecode [-f] [input]
X *
X * Decode a file encoded with uuencode.  WIll extract multiple encoded
X * modules from a single file.	Can deal with most mangled files, including
X * BITNET.  Will handle sectioned encoded files also.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef AMIGA
X#define AMIGA_LATTICE	    /* Set for Amiga Lattice C */
X#define MCH_AMIGA
X#define MPU68000
X#endif
X
X#ifdef unix
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#endif
X
X/* Exit error codes */
X#define err_ok			0
X#define err_dest_open		1
X#define err_dest_write		2
X#define err_eof			3
X#define err_in_open		4
X#define err_no_begin		5
X#define err_no_end		6
X#define err_no_user		7
X#define err_out_close		8
X#define err_sect_seq		9
X#define err_sect_size		10
X#define err_size		11
X#define err_tilda_user		12
X#define err_usage		13
X
Xchar section_str[] = "======= [ remove this line";
X#define section_str_sz (sizeof(section_str) - 1)
X
Xint	section = 0;	/* section flag and next section to get */
Xlong	written_size;	/* number of bytes written to output, used instead of
X			   ftell, because ftell doesn't work with -f */
X
X#define SUMSIZE 64
X#define DEC(c)	(((c) - ' ') & 077)    /* single character decode */
X
Xmain(argc, argv)
Xchar **argv;
X{
XFILE	*in, *out;
Xint	through_loop=0; /* Dejavu indicator */
Xint	mode;		/* file's mode (from header) */
Xlong	filesize;	/* theoretical file size (from header) */
Xchar	dest[128];
Xchar	buf[80];
Xint	f_option = 0;	/* set to 1 if -f option is present */
X
X#ifdef AMIGA_LATTICE
Xextern	int Enable_Abort;
X	Enable_Abort=1;
X#endif
X
X    /* First, check for the -f option */
X    if (argc >= 2 && strcmp(argv[1], "-f") == 0)
X        {
X        f_option = 1;
X        argc--; argv++;
X        }
X
X    /* A filename can be specified to be uudecoded, or nothing can
X    be specified, and the input will come from STDIN */
X
X    switch (argc)
X	{
X	case 1:
X	in=stdin;
X	break;
X
X	case 2:
X	if ((in = fopen(argv[1], "r")) == NULL)
X	    {
X	    fprintf(stderr, "ERROR: can't find %s\n", argv[1]);
X	    fprintf(stderr, "USAGE: uudecode [-f] [infile]\n");
X	    exit(err_in_open);
X	    }
X	break;
X
X	default:
X	fprintf(stderr, "USAGE: uudecode [-f] [infile]\n");
X	exit(err_usage);
X	break;
X	}
X
X    /* Loop through file, searching for headers.  Decode anything with a
X       header, complain if there where no headers. */
X
Xfor (;;)
X{
X    /* search file for header line */
X    for (;;)
X	{
X	if (fgets(buf, sizeof buf, in) == NULL)
X	    {
X	    if (!through_loop)
X		{
X		fprintf(stderr, "ERROR: no `begin' line!\n");
X		exit(err_no_begin);
X		}
X	    else
X		{
X		exit(err_ok);
X		}
X	    }
X	if (strncmp(buf, "section 1 of uuencode", 21) == 0)
X	    section = 1;
X	else if (strncmp(buf, "begin ", 6) == 0)
X	    break;
X	}
X    sscanf(buf, "begin %o %s", &mode, dest);
X
X    /* set up the output file */
X    if (f_option)
X        {
X        /* the -f option is used, so use stdout */
X	out = stdout;
X        }
X    else
X        {
X        /* the -f option is not used, so use the filename (and mode) in the
X         * begin line */
X#ifdef unix
X	/* handle ~user/file format */
X	if (dest[0] == '~')
X	    {
X	    char *sl;
X	    struct passwd *getpwnam();
X	    char *index();
X	    struct passwd *user;
X	    char dnbuf[100];
X
X	    sl = index(dest, '/');
X	    if (sl == NULL)
X		{
X		fprintf(stderr, "Illegal ~user\n");
X		    exit(err_tilda_user);
X		}
X	    *sl++ = 0;
X	    user = getpwnam(dest+1);
X	    if (user == NULL)
X		{
X		fprintf(stderr, "No such user as %s\n", dest);
X		exit(err_no_user);
X		}
X	    strcpy(dnbuf, user->pw_dir);
X	    strcat(dnbuf, "/");
X	    strcat(dnbuf, sl);
X	    strcpy(dest, dnbuf);
X	    }
X#endif
X
X	/* create output file */
X	if ((out = fopen(dest, "w")) == NULL)
X	    {
X	    fprintf(stderr, "ERROR: can't open output file %s\n", dest);
X	    exit(err_dest_open);
X	    }
X#ifdef unix
X	chmod(dest, mode);
X#endif
X       }
X
X    /* actually decode the data */
X    decode(in, out, dest);
X
X    if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
X	{	       /* don't be overly picky about newline ^ */
X	fprintf(stderr, "ERROR: no `end' line\n");
X	exit(err_no_end);
X	}
X
X    if (section) {
X	/* suck up the section trailer before the size line */
X	if (fgets(buf,sizeof buf,in) == NULL) {
X	    fprintf(stderr, "ERROR: input ended unexpectedly!\n");
X	    exit(err_eof);
X	}
X    }
X    if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
X	{
X	sscanf(buf, "size %ld", &filesize);
X	if (written_size != filesize)
X	    {
X	    fprintf(stderr,
X		"ERROR: file should have been %ld bytes long but was %ld.\n",
X		filesize, written_size);
X	    exit(err_size);
X	    }
X	}
X
X    /* close the output file */
X    if (!f_option)
X        if (fclose(out) != 0)
X            {
X	    fprintf(stderr, "ERROR: error closing file %s.\n", dest);
X	    exit(err_out_close);
X	    }
X
X    through_loop = 1;
X}   /* forever */
X}   /* main */
X
X/*
X * Copy from in to out, decoding as you go.
X * If a return or newline is encountered too early in a line, it is
X * assumed that means that some editor has truncated trailing spaces.
X */
Xdecode(in, out, dest)
XFILE *in;
XFILE *out;
Xchar *dest;
X{
Xchar buf[81];
Xchar *bp;
Xint nosum=0;
X#ifndef unix
Xextern errno;
X#endif
Xint j;
Xregister int n;
Xint checksum, line, section_size;
X
X    /* zero the byte count and initial section size*/
X    section_size = written_size = 0;
X
X    for (line = 1; ; line++)	/* for each input line */
X	{
X	if (fgets(buf, sizeof buf, in) == NULL)
X	    {
X	    fprintf(stderr, "ERROR: input ended unexpectedly!\n");
X	    exit(err_eof);
X	    }
X
X	/* Is this section finished? */
X	if (section &&
X		((strncmp(buf, section_str, section_str_sz) == 0)
X		|| buf[0] == '\n' || buf[0] == '\r')) {
X	    long size;
X
X	    /* Scan for section size */
X	    do {
X		line++;
X	        if (fgets(buf, sizeof buf, in) == NULL) {
X		    fprintf(stderr, "ERROR: input ended unexpectedly!\n");
X		    exit(err_eof);
X	        }
X		n = sscanf(buf, "section size %ld", &size);
X	    } while (n != 1);
X	    line++;
X	    if (section_size != size) {
X		fprintf(stderr, "ERROR: section size wrong!\n");
X		exit(err_sect_size);
X	    }
X	    section_size = 0;
X	    section++;
X	    /* Scan for start of next section */
X	    for (n = 0; n != 1;) {
X		line++;
X		if (fgets(buf, sizeof buf, in) == NULL) {
X		    fprintf(stderr, "ERROR: input ended unexpectedly!\n");
X		    exit(err_eof);
X		}
X		n = sscanf(buf, "section %d of uuencode", &j);
X	    }
X	    if (section != j) {
X		fprintf(stderr, "ERROR: section %d out of sequence!\n", j);
X		exit(err_sect_seq);
X	    }
X	    while (buf[0] != 'M') {
X		line++;
X		if (fgets(buf, sizeof buf, in) == NULL) {
X		    fprintf(stderr, "ERROR: input ended unexpectedly!\n");
X		    exit(err_eof);
X		}
X	    }
X	}
X	/* Pad end of lines in case some editor truncated trailing
X	   spaces */
X
X	for (n=0;n<79;n++)  /* search for first \r, \n or \000 */
X	    {
X	    if (buf[n]=='\176')     /* If BITNET made a twiddle, */
X		buf[n]='\136';     /* we make a caret           */
X	    if (buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000')
X		break;
X	    }
X	for (;n<79;n++)     /* when found, fill rest of line with space */
X	    {
X	    buf[n]=' ';
X	    }
X	buf[79]=0;	    /* terminate new string */
X
X	checksum = 0;
X	n = DEC(buf[0]);
X	if (n <= 0)
X	    break;	/* 0 bytes on a line??	Must be the last line */
X
X	bp = &buf[1];
X
X	/* FOUR input characters go into each THREE output characters */
X
X	while (n >= 4)
X	    {
X	    j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
X	    putc(j, out);
X	    checksum += j;
X	    written_size++;
X	    section_size++;
X
X	    j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
X	    putc(j, out);
X	    checksum += j;
X	    written_size++;
X	    section_size++;
X
X	    j = DEC(bp[2]) << 6 | DEC(bp[3]);
X	    putc(j, out);
X	    checksum += j;
X	    written_size++;
X	    section_size++;
X
X	    checksum = checksum % SUMSIZE;
X	    bp += 4;
X	    n -= 3;
X	    }
X
X	    j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
X		checksum += j;
X		if (n >= 1)
X		    {
X		    putc(j, out);
X		    written_size++;
X		    section_size++;
X		    }
X	    j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
X		checksum += j;
X		if (n >= 2)
X		    {
X		    putc(j, out);
X		    written_size++;
X		    section_size++;
X		    }
X	    j = DEC(bp[2]) << 6 | DEC(bp[3]);
X		checksum += j;
X		if (n >= 3)
X		    {
X		    putc(j, out);
X		    written_size++;
X		    section_size++;
X		    }
X	    checksum = checksum % SUMSIZE;
X	    bp += 4;
X	    n -= 3;
X
X#ifndef unix
X	 /* Error checking under UNIX??? You must be kidding... */
X	 /* Check if an error occured while writing to that last line */
X	if (errno)
X	    {
X	    fprintf(stderr, "ERROR: error writing to %s\n",dest);
X	    exit(err_dest_write);
X	    }
X#endif
X
X	/* The line has been decoded; now check that sum */
X
X	nosum |= !isspace(*bp);
X	if (nosum && !section)			/* Is there a checksum at all?? */
X	    {
X	    if (checksum != DEC(*bp))	/* Does that checksum match? */
X		{
X		fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line);
X		}
X	    }	/* sum */
X    }	/* line */
X}   /* function */
X
X#ifdef unix
X/*
X * Return the ptr in sp at which the character c appears;
X * 0 if not found
X */
Xchar *
Xindex(sp, c)
Xregister char *sp, c;
X{
X    do
X	{
X	if (*sp == c)
X	    return(sp);
X	}
X    while (*sp++);
X
X    return(0);
X}
X#endif unix
________This_Is_The_END________
if test `wc -c < uudecode.c` -ne 10483; then
	echo 'shar: uudecode.c was damaged during transit (should have been 10483 bytes)'
fi
fi		; : end of overwriting check
exit 0