[comp.sources.atari.st] v02i024: uuduue -- Dumas uuencode/decode programs

koreth@ssyx.ucsc.edu (Steven Grimm) (03/12/89)

Submitted-by: uunet!mcvax!unido!klute (Rainer Klute)
Posting-number: Volume 2, Issue 24
Archive-name: uuduue

Here are the latest sources of Dumas' UUD/UUE package. They
were posted a while ago here in europe. They are *not*
uuencoded to give you a chance to retrieve them.

  Rainer Klute                  ----   klute@irb.informatik.uni-dortmund.de
  Universitaet Dortmund, IRB    |)|/   klute@unido.uucp, klute@unido.bitnet
  Postfach 500500               |\|\   ...uunet!mcvax!unido!klute
D-4600 Dortmund 50              ----   Tel.: +49 231 7554663


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	UUD.C
#	UUE.C
# This archive created: Wed Feb  8 10:57:34 1989
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'UUD.C'
then
	echo shar: "will not over-write existing file 'UUD.C'"
else
cat << \SHAR_EOF > 'UUD.C'
/*
 * Uud -- decode a uuencoded file back to binary form.
 *
 * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
 * The Atari GEMDOS version compiled with MWC 2.x.
 * The MSDOS version with TurboC.
 * The Unix version with cc.
 * this version is made: 25 Nov 1988.
 */

/*
 * Be sure to have the proper symbol at this point. (GEMDOS, MSDOS, UNIX...)
 */

#ifndef GEMDOS
#define GEMDOS 1
#endif
/*
#ifndef UNIX
#define UNIX 1
#endif
*/
/*
#ifndef MSDOS
#define MSDOS 1
#endif
 */

#ifdef GEMDOS
#define SYSNAME "gemdos"
#define SMALL 1
#endif
#ifdef MSDOS
#define SYSNAME "msdos"
#define SMALL 1
#endif
#ifdef UNIX
#define SYSNAME "unix"
#endif

#include <stdio.h>

#ifdef GEMDOS
#include <osbind.h>
#define Error(n)  { Bconin(2); exit(n); }
#define WRITE	  "wb"
#else
#define Error(n)  exit(n)
#define WRITE	  "w"
#endif

#define loop	while (1)

extern FILE *fopen();
extern char *strcpy();
extern char *strcat();

char *getnword();

#define MAXCHAR 256
#define LINELEN 256
#define FILELEN 64
#define NORMLEN 60	/* allows for 80 encoded chars per line */

#define SEQMAX 'z'
#define SEQMIN 'a'
char seqc;
int first, secnd, check, numl;

FILE *in, *out;
char *pos;
char ifname[FILELEN], ofname[FILELEN];
char *source = NULL, *target = NULL;
char blank, part = '\0';
int partn, lens;
int debug = 0, nochk = 0, onedone = 0;
int chtbl[MAXCHAR], cdlen[NORMLEN + 3];

main(argc, argv) int argc; char *argv[];
{
	int mode;
	register int i, j;
	char *curarg;
	char dest[FILELEN], buf[LINELEN];

	if (argc < 2) {
		format("Almost foolproof uudecode v3.4 (%s) 25-Nov-88\n",
			SYSNAME);
		format("\n");
		format("Usage: uud [-n] [-d] [-s dir] [-t dir] input-file\n");
		format("\n");
		format("Option: -n -> No line sequence check\n");
		format("Option: -d -> Debug/verbose mode\n");
		format("Option: -s + Source directory for all input files\n");
		format("  (MUST be terminated by directory separator)\n");
		format("Option: -t + Target directory for all output files\n");
		format("  (MUST be terminated by directory separator)\n");
		format("If input-file is - then stdin is used as input-file\n");
		Error(1);
	}

	curarg = argv[1];
	
	while (curarg[0] == '-') {
		if (((curarg[1] == 'd') || (curarg[1] == 'D')) &&
		    (curarg[2] == '\0')) {
			debug = 1;
		} else if (((curarg[1] == 'n') || (curarg[1] == 'N')) &&
			   (curarg[2] == '\0')) {
			nochk = 1;
		} else if (((curarg[1] == 't') || (curarg[1] == 'T')) &&
			   (curarg[2] == '\0')) {
			argv++;
			argc--;
			if (argc < 2) {
				format("uud: Missing target directory.\n");
				Error(15);
			}
			target = argv[1];
			if (debug)
				format("Target dir = %s\n",target);
		} else if (((curarg[1] == 's') || (curarg[1] == 'S')) &&
			   (curarg[2] == '\0')) {
			argv++;
			argc--;
			if (argc < 2) {
				format("uud: Missing source directory.\n");
				Error(15);
			}
			source = argv[1];
			if (debug)
				format("Source dir = %s\n",source);
		} else if (curarg[1] != '\0') {
			format("uud: Unknown option <%s>\n", curarg);
			Error(15);
		} else
			break;
		argv++;
		argc--;
		if (argc < 2) {
			format("uud: Missing file name.\n");
			Error(15);
		}
		curarg = argv[1];
	}

	if ((curarg[0] == '-') && (curarg[1] == '\0')) {
		in = stdin;
		strcpy(ifname, "<stdin>");
	} else {
		if (source != NULL) {
			strcpy(ifname, source);
			strcat(ifname, curarg);
		} else
			strcpy(ifname, curarg);
		if ((in = fopen(ifname, "r")) == NULL) {
			format("uud: Can't open %s\n", ifname);
			Error(2);
		}
		numl = 0;
	}

/*
 * Set up the default translation table.
 */
	for (i = 0; i < ' '; i++) chtbl[i] = -1;
	for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j;
	for (i = ' ' + 64; i < MAXCHAR; i++) chtbl[i] = -1;
	chtbl['`'] = chtbl[' '];	/* common mutation */
	chtbl['~'] = chtbl['^'];	/* an other common mutation */
	blank = ' ';
/*
 * set up the line length table, to avoid computing lotsa * and / ...
 */
	cdlen[0] = 1;
	for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
		cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
/*
 * search for header or translation table line.
 */
	loop {	/* master loop for multiple decodes in one file */
		partn = 'a';
		loop {
			if (fgets(buf, sizeof buf, in) == NULL) {
				if (onedone) {
					if (debug) format("End of file.\n");
					exit(0);
				} else {
					format("uud: No begin line.\n");
					Error(3);
				}
			}
			numl++;
			if (strncmp(buf, "table", 5) == 0) {
				gettable();
				continue;
			}
			if (strncmp(buf, "begin", 5) == 0) {
				break;
			}
		}
		lens = strlen(buf);
		if (lens) buf[--lens] = '\0';
#ifdef SMALL
		if ((pos = getnword(buf, 3))) {
			strcpy(dest, pos);
		} else
#else
		if(sscanf(buf,"begin%o%s", &mode, dest) != 2)
#endif
		{
			format("uud: Missing filename in begin line.\n");
			Error(10);
		}

		if (target != NULL) {
			strcpy(ofname, target);
			strcat(ofname, dest);
		} else
			strcpy(ofname, dest);

		if((out = fopen(ofname, WRITE)) == NULL) {
			format("uud: Cannot open output file: %s\n", ofname);
			Error(4);
		}
		if (debug) format("Begin uudecoding: %s\n", ofname);
		seqc = SEQMAX;
		check = nochk ? 0 : 1;
		first = 1;
		secnd = 0;
		decode();
		fclose(out);
#ifdef UNIX
		chmod(ofname, mode);
#endif
		onedone = 1;
		if (debug) format("End uudecoding: %s\n", ofname);
	}	/* master loop for multiple decodes in one file */
}

/*
 * Bring back a pointer to the start of the nth word.
 */
char *getnword(str, n) register char *str; register int n;
{
	while((*str == '\t') || (*str == ' ')) str++;
	if (! *str) return NULL;
	while(--n) {
		while ((*str != '\t') && (*str != ' ') && (*str)) str++;
		if (! *str) return NULL;
		while((*str == '\t') || (*str == ' ')) str++;
		if (! *str) return NULL;
	}
	return str;
}

/*
 * Install the table in memory for later use.
 */
gettable()
{
	char buf[LINELEN];
	register int c, n = 0;
	register char *cpt;

	for (c = 0; c <= MAXCHAR; c++) chtbl[c] = -1;

again:	if (fgets(buf, sizeof buf, in) == NULL) {
		format("uud: EOF while in translation table.\n");
		Error(5);
	}
	numl++;
	if (strncmp(buf, "begin", 5) == 0) {
		format("uud: Incomplete translation table.\n");
		Error(6);
	}
	cpt = buf + strlen(buf) - 1;
	*cpt = ' ';
	while (*(cpt) == ' ') {
		*cpt = 0;
		cpt--;
	}
	cpt = buf;
	while (c = *cpt) {
		if (chtbl[c] != -1) {
			format("uud: Duplicate char in translation table.\n");
			Error(7);
		}
		if (n == 0) blank = c;
		chtbl[c] = n++;
		if (n >= 64) return;
		cpt++;
	}
	goto again;
}

/*
 * copy from in to out, decoding as you go along.
 */

decode()
{
	char buf[LINELEN], outl[LINELEN];
	register char *bp, *ut;
	register int *trtbl = chtbl;
	register int n, c, rlen;
	register unsigned int len;

	loop {
		if (fgets(buf, sizeof buf, in) == NULL) {
			format("uud: EOF before end.\n");
			fclose(out);
			Error(8);
		}
		numl++;
		len = strlen(buf);
		if (len) buf[--len] = '\0';
/*
 * Is it an unprotected empty line before the end line ?
 */
		if (len == 0) continue;
/*
 * Get the binary line length.
 */
		n = trtbl[*buf];
		if (n >= 0) goto decod;
/*
 * end of uuencoded file ?
 */
		if (strncmp(buf, "end", 3) == 0) return;
/*
 * end of current file ? : get next one.
 */
		if (strncmp(buf, "include", 7) == 0) {
			getfile(buf);
			continue;
		}
		format("uud: Bad prefix line %d in file: %s\n",numl, ifname);
		if (debug) format("Bad line =%s\n",buf);
		Error(11);
/*
 * Sequence checking ?
 */
decod:		rlen = cdlen[n];
/*
 * Is it the empty line before the end line ?
 */
		if (n == 0) continue;
/*
 * Pad with blanks.
 */
		for (bp = &buf[c = len];
			c < rlen; c++, bp++) *bp = blank;
/*
 * Verify if asked for.
 */
		if (debug) {
			for (len = 0, bp = buf; len < rlen; len++) {
				if (trtbl[*bp] < 0) {
					format(
	"Non uuencoded char <%c>, line %d in file: %s\n", *bp, numl, ifname);
					format("Bad line =%s\n",buf);
					Error(16);
				}
				bp++;
			}
		}
/*
 * All this just to check for uuencodes that append a 'z' to each line....
 */
		if (secnd && check) {
			secnd = 0;
			if (buf[rlen] == SEQMAX) {
				check = 0;
				if (debug) format("Sequence check turned off (2).\n");
			} else
				if (debug) format("Sequence check on (2).\n");
		} else if (first && check) {
			first = 0;
			secnd = 1;
			if (buf[rlen] != SEQMAX) {
				check = 0;
				if (debug) format("No sequence check (1).\n");
			} else
				if (debug) format("Sequence check on (1).\n");
		}
/*
 * There we check.
 */
		if (check) {
			if (buf[rlen] != seqc) {
				format("uud: Wrong sequence line %d in %s\n",
					numl, ifname);
				if (debug)
					format(
	"Sequence char is <%c> instead of <%c>.\n", buf[rlen], seqc);
				Error(18);
			}
			seqc--;
			if (seqc < SEQMIN) seqc = SEQMAX;
		}
/*
 * output a group of 3 bytes (4 input characters).
 * the input chars are pointed to by p, they are to
 * be output to file f.n is used to tell us not to
 * output all of them at the end of the file.
 */
		ut = outl;
		len = n;
		bp = &buf[1];
		while (n > 0) {
			*(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
			n--;
			if (n) {
				*(ut++) = (trtbl[bp[1]] << 4) |
					  (trtbl[bp[2]] >> 2);
				n--;
			}
			if (n) {
				*(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
				n--;
			}
			bp += 4;
		}
		if ((n = fwrite(outl, 1, len, out)) <= 0) {
			format("uud: Error on writing decoded file.\n");
			Error(18);
		}
	}
}

/*
 * Find the next needed file, if existing, otherwise try further
 * on next file.
 */
getfile(buf) register char *buf;
{
	if ((pos = getnword(buf, 2)) == NULL) {
		format("uud: Missing include file name.\n");
		Error(17);
	} else
		if (source != NULL) {
			strcpy(ifname, source);
			strcat(ifname, pos);
		} else
			strcpy(ifname, pos);
#ifdef GEMDOS
	if (Fattrib(ifname, 0, 0) < 0)
#else
	if (access(ifname, 04))
#endif
	{
		if (debug) {
			format("Cant find: %s\n", ifname);
			format("Continuing to read same file.\n");
		}
	}
	else {
		if (freopen(ifname, "r", in) == in) {
			numl = 0;
			if (debug) 
				format("Reading next section from: %s\n", ifname);
		} else {
			format("uud: Freopen abort: %s\n", ifname);
			Error(9);
		}
	}
	loop {
		if (fgets(buf, LINELEN, in) == NULL) {
			format("uud: No begin line after include: %s\n", ifname);
			Error(12);
		}
		numl++;
		if (strncmp(buf, "table", 5) == 0) {
			gettable();
			continue;
		}
		if (strncmp(buf, "begin", 5) == 0) break;
	}
	lens = strlen(buf);
	if (lens) buf[--lens] = '\0';
/*
 * Check the part suffix.
 */
	if ((pos = getnword(buf, 3)) == NULL ) {
		format("uud: Missing part name, in included file: %s\n", ifname);
		Error(13);
	} else {
		part = *pos;
		partn++;
		if (partn > 'z') partn = 'a';
		if (part != partn) {
			format("uud: Part suffix mismatch: <%c> instead of <%c>.\n",
				part, partn);
			Error(14);
		}
		if (debug) format("Reading part %c\n", *pos);
	}
}

/*
 * Printf style formatting. (Borrowed from MicroEmacs by Dave Conroy.) 
 * A lot smaller than the full fledged printf.
 */
/* VARARGS1 */
format(fp, args) char *fp;
{
	doprnt(fp, (char *)&args);
}

doprnt(fp, ap)
register char	*fp;
register char	*ap;
{
	register int	c, k;
	register char	*s;

	while ((c = *fp++) != '\0') {
		if (c != '%')
			outc(c);
		else {
			c = *fp++;
			switch (c) {
			case 'd':
				puti(*(int *)ap, 10);
				ap += sizeof(int);
				break;

			case 's':
				s = *(char **)ap;
				while ((k = *s++) != '\0')
					outc(k);
				ap += sizeof(char *);
				break;

			case 'c':
				outc(*(int *)ap);
				ap += sizeof(int);
				break;

			default:
				outc(c);
			}
		}
	}
}

/*
 * Put integer, in radix "r".
 */
puti(i, r)
register unsigned int	i;
register unsigned int	r;
{
	register unsigned int	q, s;

	if ((q = i / r) != 0)
		puti(q, r);
	s = i % r;
	if (s <= 9)
		outc(s + '0');
	else
		outc(s - 10 + 'A');
}
outc(c) register char c;
{
#ifdef GEMDOS
	if (c == '\n') Bconout(2, '\r');
	Bconout(2, c);
#else
	putchar(c);
#endif
}
SHAR_EOF
fi
if test -f 'UUE.C'
then
	echo shar: "will not over-write existing file 'UUE.C'"
else
cat << \SHAR_EOF > 'UUE.C'
/*
 *
 * Uue -- encode a file so that it's printable ascii, short lines
 *
 * Slightly modified from a version posted to net.sources a while back,
 * and suitable for compilation on the IBM PC
 *
 * modified for Lattice C on the ST - 11.05.85 by MSD
 * modified for ALCYON on the ST -    10-24-86 by RDR
 * modified a little more for MWC...  02/09/87 by JPHD
 * (An optional first argument of the form: -nnumber (e.g. -500), will
 * produce a serie of files that long, linked by the include statement,
 * such files are automatically uudecoded by the companion program.)
 * More mods, - ...		   05/06/87 by jphd
 * Mods for TOPS 20, and more.     08/06/87 by jphd
 *     (remove freopen and rindex...change filename generation...)
 * (A lot more to do about I/O speed, avoiding completely the stdio.h...)
 *
 */


#include <stdio.h>
#include <ctype.h>

#define USAGE 

/* ENC is the basic 1 character encoding function to make a char printing */
#define ENC(c) (((c) & 077) + ' ')

extern FILE  *fopen();
FILE *fp, *outp;
char ofname[80];
int lenofname;
int stdo = 0;

#ifdef ST
#define READ "rb"
#else
#define READ "r"
#endif

int part = 'a', chap = 'a';
#define SEQMAX 'z'
#define SEQMIN 'a'
char seqc = SEQMAX;

int split = 0; fileln = 32000;

main(argc, argv)
int argc; char *argv[];
{
	char *fname;

	if (argc < 2) {
		fprintf(stderr, "Almost foolproof uuencode v3.1 06 Aug 1987\n");
		fprintf(stderr, "Usage: uue [-n] inputfile [-]\n");
		exit(2);
		}
	if (argv[1][0] == '-') {
		fileln = -atoi(argv[1]);
		if (fileln <= 0) {
			fprintf(stderr, "Wrong file length arg.\n");
			exit();
		}
		split = 1;
		argv++;
		argc--;
	}
	if ((fp=fopen(argv[1], READ))==NULL) {  /* binary input !!! */
		fprintf(stderr,"Cannot open %s\n",argv[1]);
		exit(1);
	}
	strcpy(ofname, argv[1]);
	fname = ofname;
	do {
		if (*fname == '.')
			*fname = '\0';
	} while (*fname++);
		/* 8 char prefix + .uue -> 12 chars MAX */
	lenofname = strlen(ofname);
	if (lenofname > 8) ofname[8] = '\0';
	strcat(ofname,".uue");
	lenofname = strlen(ofname);
	if (!split && (argc > 2) && (argv[2][0] == '-')) {
		stdo = 1;
		outp = stdout;
	 } else {
		 makename();
		 if((outp = fopen(ofname, "w")) == NULL) {
			 fprintf(stderr,"Cannot open %s\n", ofname);
			 exit(1);
			 }
	}
	maketable();
	fprintf(outp,"begin %o %s\n", 0644, argv[1]);
	encode();
	fprintf(outp,"end\n");
	fclose(outp);
	exit(0);
}

/* create ASCII table so a mailer can screw it up and the decode
 * program can restore the error.
 */
maketable()
{
	register int i, j;

	fputs("table\n", outp);
	for(i = ' ', j = 0; i < '`' ; j++) {
		if (j == 32)
			putc('\n', outp);
		fputc(i++, outp);
	}
	putc('\n', outp);
}

/*
 * Generate the names needed for single and multiple part encoding.
 */
makename()
{
	if (split) {
		ofname[lenofname - 1] = part;
		ofname[lenofname - 2] = chap;
	}
}

/*
 * copy from in to out, encoding as you go along.
 */
encode()
{
	char buf[80];
	register int i, n;
	register int lines;
	lines = 6;

	for (;;) {
		n = fr(buf, 45);
		putc(ENC(n), outp);
		for (i = 0; i < n; i += 3)
		      outdec(&buf[i]);
		putc(seqc, outp);
		seqc--;
		if (seqc < SEQMIN) seqc = SEQMAX;
		putc('\n', outp);
		++lines;
		if (split && (lines > fileln)) {
			part++;
			if (part > 'z') {
				part = 'a';
				if (chap == 'z')
					chap = 'a'; /* loop ... */
				else
					chap++;
			}
			makename();
			fprintf(outp,"include %s\n",ofname);
			fclose(outp);
			if((outp = fopen(ofname, "w")) == NULL) {
				fprintf(stderr,"Cannot open %s\n",ofname);
				exit(1);
			}
			maketable();
			fprintf(outp,"begin part %c %s\n",part,ofname);
			lines = 6;
		}
		if (n <= 0)
			break;
	}
}

/*
 * output one group of 3 bytes, pointed at by p, on file f.
 */
outdec(p)
register char *p;
{
	register int c1, c2, c3, c4;

	c1 = *p >> 2;
	c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
	c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
	c4 = p[2] & 077;
	putc(ENC(c1), outp);
	putc(ENC(c2), outp);
	putc(ENC(c3), outp);
	putc(ENC(c4), outp);
}

/* fr: like read but stdio */
int fr(buf, cnt)
register char *buf;
register int cnt;
{
	register int c, i;
	for (i = 0; i < cnt; i++) {
		c = fgetc(fp);
		if (feof(fp))
			return(i);
		buf[i] = c;
	}
	return (cnt);
}
SHAR_EOF
fi
exit 0
#	End of shell archive