/*
 * $Id: uuencode.c,v 36.9 1994/09/28 15:03:59 zodiac Rel zodiac $
 *
 * uuencode 36.9 -- Copyright (c) 1994 Ralph Seichter.
 *
 * Encodes binary files so that they can be posted to the Internet. This
 * tool is pure.
 *
 * This tool is FREELY DISTRIBUTABLE. Copying and spreading is encouraged,
 * as long as you don't charge anyone for giving him/her this tool. Please
 * note that the Copyright is mine, this is *NOT* public domain software!
 * Permission is hereby granted to include the complete (!) archive in all
 * non-profit public domain software series like Fred Fish, SaarAG, etc.
 *
 * $Log: uuencode.c,v $
 * Revision 36.9  1994/09/28  15:03:59  zodiac
 * No changes. Revision number was bumped to match uudecode.
 *
 * Revision 36.8  1994/09/28  14:18:47  zodiac
 * First release with 'pure' executables.
 *
 */

#define	VERSION		"\0$VER: uuencode 36.9 (28.9.94)"
#define	TEMPLATE		"FROM/A/M,TO=AS/A/K,NC=NOCHECKSUM/S,XC=XCHECKSUM/S,QUIET/S"

#define	MODE_NOCHKSUM	0x01
#define	MODE_XCHKSUM	0x02
#define	SIXBIT		0x40		/* 6 bit = 0x40 */

enum { ARG_FROM, ARG_TO, ARG_NOCHKSUM, ARG_XCHKSUM, ARG_QUIET, ARG_TOTAL };

/*
	Encoding (c == 0) returns (0x60).
	Encoding (c  > 0) returns ((c & 0x3F) + 0x20).

	There is always (0x20 <= c <= 0x60), which means
	that c is guaranteed to be a printable character!
*/

#define ENCODE(c) (c ? (c & 0x3F) + 0x20 : 0x60)



/* function prototypes and globals ******************************************/

LONG entryPoint (VOID);
BOOL encodeFile (struct DosLibrary *, BPTR, BPTR, STRPTR, BYTE);



/* the main program *********************************************************/

LONG __saveds entryPoint (VOID)
{
	LONG rc = RETURN_FAIL;
	struct DosLibrary *DOSBase;

	/* uuencode will *NOT* run without dos.library V36 or better! */
	if (DOSBase = (struct DosLibrary *)OpenLibrary (DOSNAME, 36))
	{
		LONG err;
		STRPTR arg[ARG_TOTAL];
		struct RDArgs *rda;

		rc = RETURN_ERROR;
		memset (arg, 0, sizeof (arg));
		if (rda = ReadArgs (TEMPLATE, (LONG *)arg, NULL))
		{
			BPTR out;
			STRPTR *name = (STRPTR *)arg[ARG_FROM];
			static UBYTE ver[] = VERSION;

			if (!arg[ARG_QUIET])
				Printf ("%s Copyright \xA9 Ralph Seichter\n", &ver[7]);
			if (out = Open (arg[ARG_TO], MODE_NEWFILE))
			{
				WORD i;
				BPTR in;
				BYTE mode;
				BOOL ok = TRUE;

				if (arg[ARG_NOCHKSUM])
					mode = MODE_NOCHKSUM;
				else if (arg[ARG_XCHKSUM])
					mode = MODE_XCHKSUM;
				else
					mode = 0;
				for (i = 0; ok && (name[i]); ++i)
					if (in = Open (name[i], MODE_OLDFILE))
					{
						if (!arg[ARG_QUIET])
							Printf ("Encoding file %s\n", name[i]);
						ok = encodeFile (DOSBase, in, out, FilePart (name[i]), mode);
						Close (in);
					}
				Close (out);
				if ((err = IoErr ()) > 0)
					PrintFault (err, NULL);
				else
					rc = RETURN_OK;
			}
			FreeArgs (rda);
		}
		CloseLibrary ((struct Library *)DOSBase);
	}
	return (rc);
}



/* encode a complete file ***************************************************/

BOOL encodeFile (struct DosLibrary *DOSBase, BPTR in, BPTR out, STRPTR name, BYTE mode)
{
	BOOL ok = FALSE;

	if (0 < FPrintf (out, "begin 644 %s\n", name))
	{
		LONG n, i, triple, checksum, size = 0;
		UBYTE c, buf[45], outbuf[80];
		STRPTR s, t;

		do
		{
			/* read a maximum of 45 bytes at a time */
			n = FRead (in, buf, 1, 45);
			size += n;

			/* the first byte in each output line is the */
			/* encoded number of encoded bytes in the line */
			s = outbuf;
			*s++ = ENCODE(n);

			/* now encode data in buffer. three input bytes
					will always result in four output bytes */
			for (checksum = 0, i = 0; i < n; i += 3)
			{
				t = &buf[i];

				/* first six bits (7-2) of byte 0 */
				c = t[0] >> 2;
				*s++ = ENCODE(c);

				/* last two bits (1-0) of byte 0 OR'ed with first
						four bits (7-4) of byte 1 */
				c = (t[0] << 4) & 0x30 | (t[1] >> 4) & 0x0F;
				*s++ = ENCODE(c);

				/* last four bits (3-0) of byte 1 OR'ed with first
						two bits (7-6) of byte 2 */
				c = (t[1] << 2) & 0x3C | (t[2] >> 6) & 0x03;
				*s++ = ENCODE(c);

				/* last six bits (5-0) of byte 2 */
				c = t[2] & 0x3F;
				*s++ = ENCODE(c);

				/* calculate checksum of current triplet */
				triple = (t[0] + t[1] + t[2]) % SIXBIT;

				/* and add this to total line checksum */
				checksum = (checksum + triple) % SIXBIT;
			}

			if (mode & MODE_XCHKSUM)
				*s++ = 'X';
			else if (!(mode & MODE_NOCHKSUM))
				/* the last byte in each line is the line checksum */
				*s++ = ENCODE(checksum);

			/* add a newline character and write line string to file */
			*s++ = '\n';
			*s = 0;
			if (0 != FPuts (out, outbuf))
				n = -1;
		}
		while (n > 0);
		if (n != -1)
			ok = (0 < FPrintf (out, "end\nsize %ld\n\n", size));
	}
	return (ok);
}

/* EOF */
