[net.micro.pc] uuencode and uudecode - PD source

rb@ccivax.UUCP (rex ballard) (02/13/86)

/*
	The following program was posted to net.micro.atari
	and is being posted here because it seems to be of
	general interest to many people.
	This is how I got it, I don't know what machines it
	will work on, but it seems to be working on Atari and IBM
	PC's, and should also work on Amiga and maybe Macs.
	Sorry about posting to the general list,
	but I cannot access/post to net.sources
	The original poster was anonymous, and claims this is
	public domain.  Enjoy
*/

/*
 * Uudecode -- decode a uuencoded file back to binary form.
 *
 * Slightly modified from a version posted to net.sources once;
 * suitable for compilation on an IBM PC.
 *
 */

#include <stdio.h>

char *progname = "UUDECODE";

#define USAGE "Usage: UUDECODE [file]\n"

/* single character decode */
#define DEC(c)	(((c) - ' ') & 077)

main(argc, argv)
	int argc; char *argv[];
	{
	FILE *in, *out, *efopen();
	
	int mode;
	char dest[128];
	char buf[80];
	/* optional input arg */
	if (argc > 1) {
		in = efopen(argv[1], "r");
		argv++; argc--;
		}
	else
		in = stdin;
	if (argc != 1) {
		fprintf(stderr, USAGE);
		exit(2);
		}
	/* search for header line */
	for (;;) {
		if (fgets(buf, sizeof buf, in) == NULL) {
			fprintf(stderr, "No begin line\n");
			exit(3);
			}
		if (strncmp(buf, "begin ", 6) == 0)
			break;
		}
	sscanf(buf, "begin %o %s", &mode, dest);
	out = efopen(dest, "w");  /* create output file */
	decode(in, out);
	fclose(out);
	if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) {
		fprintf(stderr, "No end line\n");
		exit(5);
		}
	}

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

decode(in, out)
	FILE *in, *out;
	{
	char buf[80];
	char *bp;
	int n;
	for (;;) {
		if (fgets(buf, sizeof buf, in) == NULL) {
			fprintf(stderr, "Short file\n");
			break;
			}
		n = DEC(buf[0]);
		if (n <= 0)
			break;
		bp = &buf[1];
		while (n > 0) {
			outdec(bp, out, n);
			bp += 4;
			n -= 3;
			}
		}
	}

/*
 * 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.
 */

outdec(p, f, n)
	char *p; FILE *f; int n;
	{
	int c1, c2, c3;
	c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
	c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
	c3 = DEC(p[2]) << 6 | DEC(p[3]);
	if (n >= 1)
		putc(c1, f);
	if (n >= 2)
		putc(c2, f);
	if (n >= 3)
		putc(c3, f);
	}


/* fr: like read but stdio */

int fr(fd, buf, cnt)
	FILE *fd; char *buf; int cnt;
	{
	int c, i;
	for (i = 0; i < cnt; i++) {
		c = getc(fd);
		if (c == EOF)
			return(i);
		buf[i] = c;
		}
	return (cnt);
	}

/* If your library already has this function, use it and nuke the code below */

#ifdef noindex
/*
 * Return the ptr in sp at which the character c appears;
 * NULL if not found
 */

char *index(sp, c)
	register char *sp, c;
	{
	do {
		if (*sp == c)
			return(sp);
		} while (*sp++);
	return(NULL);
	}
#endif


/* Open a file, aborting on failure */

/* Written by Bernie Roehl, June 1985 */

FILE *
efopen(fn, mode)
	char *fn, *mode;
	{
	FILE *unit;
	if ((unit = fopen(fn, mode)) == NULL)
		error("Cannot open file %s", fn);
	else
		return unit;
	}

extern char *progname;

error(s1, s2)
	char *s1, *s2;
	{
	fprintf(stderr, "%s: ", progname);
	fprintf(stderr, s1, s2);
	exit(1);
	}