[net.micro.atari16] UUDECODER for the ST

franco@iuvax.UUCP (03/09/86)

Here is a UUDECODER for the ST which I tested myself on the RTXDEMO binary
that was posted recently.  This works for me and it should work for you.
Please try it and report results to the net.  It is written in dev kit C.
Link with osbind, gemlib, libf.  Soon to come - the encoder. 

Hopefully there will be no more complaints about uudecode inability after
this.


/*
 * Uudecode -- decode a uuencoded file back to binary form.
 *
 * Useage: (CLI) uudec <uuencoded filename>
 *         (GEM) click on uudec.ttp
 *               enter <uuncoded filename> in dialog box
 *               hit CR
 *
 * Result: File specified in first line of uuencoded file is created,
 *         contents of uuencoded file are decoded and placed into
 *         the created file.
 *
 * How it works:
 *         The bits of every three consecutive bytes of the binary file are
 *         encoded into four consecutive printable ascii bytes according
 *         to the following diagram:
 *
 *               |         |         |         |         |
 *               |x1x2|3456|x7x8|1234|x5x6|7812|x3x4|5678|
 *               -----------------------------------------
 *
 *         where the long vertical bars separate bytes and the short
 *         vertical bars separate half bytes.  The x'ed bits are not
 *         important to us (they are given values which result in 
 *         printable ascii characters).  The first eight digits 
 *         increasing in order from 1 to 8 mark the positions of the 
 *         first byte of the group of three binary bytes.  The next 
 *         eight mark the second byte and so on.  Each line of the
 *         encoded file contains a count character followed a number
 *         (multiple of four) of encoded bytes.  To decode we merely
 *         need to go through the usual bit pushing.
 *
 * Problems: Contact J. Franco (franco@indiana.CSNET)
 *
 * Comment: This should work.  I successfully downloded the recently posted
 *          RTXDEMO with no trouble whatsoever (and that is a pretty big 
 *          file).
 *
 * Note:    This is the latest of a number of hacks of a uudecoder originally
 *          intended for the IBM PC. (3/6/86 - JVF)
 */

#include <stdio.h>
#include <osbind.h>

char *Progname = "UUDECODE";

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

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

FILE *in, *out, *efopen(), *efopenb(), *fopen(), *fopenb();

main(argc, argv)
        int argc; char *argv[];
        {
        
        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 = efopenb(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=((*p&64)<<1)   | ((*p&31)<<2)   | ((p[1]&64)>>5) | ((p[1]&16)>>4);
        c2=((p[1]&15)<<4) | ((p[2]&64)>>3) | ((p[2]&28)>>2);
        c3=((p[2]&3)<<6)  | ((p[3]&64)>>1) | ((p[3]&31));
        if (n >= 1)
           { if (c1 == 13)
                  fprintf(f,"%c",13);
             else
                  putc(c1, f);
           }
        if (n >= 2)
           { if (c2 == 13)
                  fprintf(f,"%c",13);
             else
                  putc(c2, f);
           }
        if (n >= 3)
           { if (c3 == 13)
                  fprintf(f,"%c",13);
              else
                  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);
        }



/* 
 * efopenb is a slightly modified efopen()
 * All it does is use the ST fopenb() call to open
 * a binary file.
 * Note that this is uuencode so only the input file
 * needs to be opened with this function.
 */

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