/* #ifndef lint
static char sccsid[] = "@(#)uuencode.c  5.3-1 (Berkeley) 1/22/85";
#endif */

/* Modification history:
 *   Date	Author		Modification
 * ========	===============	========================================================
 * 88-01-25	R.W.Bowers (RWB@Trng-E.Prime.COM) PLink: (MA*Rick) GEnie: (RWB)
 *				Cleaned-up AMIGA port and prettied-up the
 *				source.
 *				Added reporting of files as they are decoded.
 * yy-mm-dd	bcn (Bryce Nesbitt,ucbvax!cogsci!bryce)
 *				Modified to fix a very misleading error message
 *				on the Amiga port, enable CTRL-C for LATTICE,
 *				and add a transparant file size trailer for
 *				later check.
 * yy-mm-dd	fnf (Fred Fish,well!fnf)
 *				Modified to use Keith Pyle's suggestion for
 *				compatibility.
 * yy-mm-dd	ajr (Alan J Rosenthatl,flaps@utcsri.UUCP)
 *				Modified to use checksums.
 *		Mark Horton	Original coding.
 */

/*
 * uuencode >outfile infile_name
 *
 * Encode a file so it can be mailed to a remote system.  This version
 * transparantly adds line checksums and a file size for sanity checks.
 *
 */

#include <stdio.h>

#ifdef AMIGA
#define AMIGA_LATTICE		/* Set for Amiga Lattice C */
#define MCH_AMIGA
#define MPU68000
#endif

#ifdef unix
#include <sys/types.h>
#include <sys/stat.h>
#endif

#define SUMSIZE 64  		/* 6 bits */
/* ENC is the basic 1 character encode function to make a char printing */
/* Each output character represents 6 bits of input */
#define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
long totalsize=0; 	/* Used to count the file size because ftell() does
                           not return sane results for pipes */

main(argc, argv)
char **argv;
{
   FILE *in;
   int mode;
   char ifname[80];
#ifdef unix
   struct stat sbuf;
#endif
#ifdef AMIGA_LATTICE
   extern int Enable_Abort;		/* Enable CTRL-C for Lattice */
   Enable_Abort=1;
#endif

/* A filename can be specified to be UUEncoded, or nothing can
    be specified and the input will come from STDIN */

   switch (argc)
      {
      case 1:
         strcpy(ifname, "stdin\0");
         in=stdin;
         break;

      case 2:
         strcpy(ifname, argv[1]);
         if ((in = fopen(ifname, "r")) == NULL)
            {
            fprintf(stderr, "ERROR: can't find %s (%s)\n", ifname, argv[0]);
            exit(10);
            }
         break;

      default:
         fprintf(stderr, "USAGE: uuencode >outfile infile_name (%s)\n", argv[0]);
         exit(11);
         break;
      } /* switch (argc) */

#ifdef unix
   /* figure out the input file mode */
   fstat(fileno(in), &sbuf);
   mode = sbuf.st_mode & 0777;
#else
   mode = 0644;    			/* Default permissions */
#endif

   fprintf(stderr, "Begin File: %s, Mode: %o ... ", ifname, mode);
   printf("\nbegin %o %s\n", mode, ifname);

   encode(in, stdout);

   printf("end\n");
   printf("size %ld\n",totalsize);
   fprintf(stderr, "Size: %ld bytes.\n", totalsize);
   exit(0);
}

/*
 * copy from in to out, encoding as you go along.
 */
encode(in, out)
FILE *in;
FILE *out;
{
#ifndef unix
extern errno;
#endif
char buf[80];
int i, n, checksum;

   for (;;)
      {
      /* 1 (up to) 45 character line */
      n = fr(in, buf, 45);
      putc(ENC(n), out);

      checksum = 0;
      for (i=0; i<n; i += 3)
         checksum = (checksum+outdec(&buf[i], out)) % SUMSIZE;

      putc(ENC(checksum), out);
      putc('\n', out);

#ifndef unix
      /* Error checking under UNIX?? You must be kidding! */
      if (errno)
         {
         fprintf(stderr, "ERROR: error writing to output\n");
         exit(12);
         }
#endif
      if (n <= 0)
         break;
      } /* for (;;) */
} /* main */

/*
 * output one group of 3 bytes, pointed at by p, on file f.
 * return the checksum increment.
 */
int outdec(p, f)
char *p;
FILE *f;
{
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), f);
   putc(ENC(c2), f);
   putc(ENC(c3), f);
   putc(ENC(c4), f);

   return((p[0]+p[1]+p[2]) % SUMSIZE);
}

/* 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);
      totalsize++;
      buf[i] = c;
      }
   return (cnt);
}

