home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 52
/
Amiga_Dream_52.iso
/
Amiga
/
Workbench
/
Archivers
/
GGUUcode.lha
/
gguucode.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-03-14
|
9KB
|
441 lines
/*
* gguucode
*
* uuencoder/decoder for Amiga 68k and PowerUP (elf binary)
*
* To compile (with SAS/C PPC):
*
* scppc gguucode
* ppc-amigaos-ld -r -o gguucode lib:c_ppc.o gguucode.o lib:scppc.a lib:end.o
* protect gguucode +e
*
*/
/* Realized by Gabriele Greco
*
* Original authors:
*
* Written by Mark Horton
* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums
* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
* compatibility
* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
* error message on the Amiga port, to fix a bug that prevented decoding
* certain files, to work even if trailing spaces have been removed from a
* file, to check the filesize (if present), to add some error checking, to
* loop for multiple decodes from a single file, and to handle common
* BITNET mangling. Kludged around a missing string function in Aztec
* C. Changed "r" to "rb" and "w" to "wb" for Messy-dos machines
* (Thanks to Andrew Wylie).
*/
#define __USE_SYSBASE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <exec/types.h>
#include <dos/rdargs.h>
#include <proto/exec.h>
#include <proto/dos.h>
UBYTE __aligned version [] = "\0$VER: ggdecode 1.0 (13.3.98)";
void decode(FILE *in, FILE *out, UBYTE *dest);
LONG filemode(FILE *in);
void encode(FILE *in, FILE *out);
LONG outdec(UBYTE *p, FILE *f);
LONG fr(FILE *fd, UBYTE *buf, LONG cnt);
LONG totalsize = 0; /* Used to count the file size because ftell() does
not return sane results for pipes */
void start_encode(FILE *in,FILE *out,UBYTE *dest)
{
fprintf(out,"\nbegin %o %s\n", filemode(in), FilePart(dest));
encode(in, out);
fprintf(out,"end\n");
fprintf(out,"size %ld\n",totalsize);
}
long main(void)
{
FILE *in, *out;
LONG through_loop = 0; /* Dejavu indicator */
LONG mode; /* file's mode (from header) */
LONG filesize; /* theoretical file size (from header) */
UBYTE dest[200],source[200];
UBYTE buf[80];
STRPTR Arg[4]={NULL,NULL,NULL,NULL};
struct RDArgs *Args;
char action=2;
/* A filename can be specified to be uudecoded, or nothing can
be specified, and the input will come from STDIN */
if(Args=ReadArgs("FILE,A=ENCODE/S,X=DECODE/S,TO=DEST/K",(LONG *)Arg,NULL))
{
/*
int i;
for(i=0;i<4;i++)
{
printf("Arg %ld -> %ld - %s\n",i,Arg[i],Arg[i]);
}
*/
if(Arg[2]&&Arg[1])
{
printf("You cant encode and decode at the same time!\n");
action=0;
}
else if(Arg[1])
{
action=1;
}
else if(Arg[2])
{
action=2;
}
if(!Arg[0])
{
if(action==2)
in=stdin;
else if(action==1)
{
printf("You can't encode from stdin!\n");
action=0;
}
}
else
{
strcpy(source,Arg[0]);
if(!(in=fopen(Arg[0],"r")))
{
printf("Unable to open source file!\n");
action=0;
}
}
if(Arg[3])
{
DIR *d;
strcpy(dest,Arg[3]);
if(out=fopen(dest,"r"))
{
printf("The output file %s already exists!\n",dest);
fclose(out);
action=0;
}
else if(dest[strlen(dest)-1]!='/'&&dest[strlen(dest)-1]!=':')
{
if(d=opendir(dest))
{
strcat(dest,"/");
if(action==1)
{
printf("Destination must be a file if you are encoding!\n");
action=0;
}
closedir(d);
}
}
else
{
if(action==1 && (dest[strlen(dest)-1]=='/' || dest[strlen(dest)-1]==':') )
{
printf("Destination must be a file if you are encoding!\n");
action=0;
}
}
}
else
{
dest[0]=0;
if(action==1)
{
out=stdout;
}
}
FreeArgs(Args);
}
else
{
printf("Error in the command line!\n");
action=0;
}
if(!action)
{
exit(0);
}
else if (action==1)
{
if(dest[0]!=0)
if ((out = fopen(dest, "w")) == NULL)
{
fprintf(stderr, "ERROR: can't open output file %s\n", dest);
exit(20);
}
start_encode(in,out,source);
}
else for (;;)
{
/* search file for header line */
for (;;)
{
if (fgets(buf, sizeof buf, in) == NULL)
{
if (!through_loop)
{
fprintf(stderr, "ERROR: no `begin' line!\n");
exit(20);
}
else
{
exit(0);
}
}
if (strncmp(buf, "begin ", 6) == 0)
break;
}
if(!dest[0])
{
sscanf(buf, "begin %o %s", &mode, dest);
}
else if(dest[strlen(dest)-1]=='/'||dest[strlen(dest)-1]==':')
{
sscanf(buf, "begin %o %s", &mode, &dest[strlen(dest)]);
}
/* create output file */
if ((out = fopen(dest, "w")) == NULL)
{
fprintf(stderr, "ERROR: can't open output file %s\n", dest);
exit(20);
}
decode(in, out, dest);
if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
{ /* don't be overly picky about newline ^ */
fprintf(stderr, "ERROR: no `end' line\n");
exit(20);
}
if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
{
sscanf(buf, "size %ld", &filesize);
if (ftell(out) != filesize)
{
fprintf(stderr, "ERROR: file should have been %ld bytes long but was %ld.\n", filesize, ftell(out));
exit(20);
}
}
through_loop = 1;
} /* forever */
exit(0);
}
#define SUMSIZE 64
#define DEC(c) (((c) - ' ') & 077) /* single character decode */
/*
* Copy from in to out, decoding as you go.
* If a return or newline is encountered too early in a line, it is
* assumed that means that some editor has truncated trailing spaces.
*/
void decode(FILE *in, FILE *out, UBYTE *dest)
{
extern errno;
UBYTE *bp;
LONG nosum=0;
LONG j, n, checksum, line;
UBYTE buf[256];
for (line = 1; ; line++) /* for each input line */
{
if (fgets(buf, sizeof buf, in) == NULL)
{
fprintf(stderr, "ERROR: input ended unexpectedly!\n");
exit(20);
}
/* Pad end of lines in case some editor truncated trailing
spaces */
for (n=0;n<79;n++) /* search for first \r, \n or \000 */
{
if (buf[n]=='\176') /* If BITNET made a twiddle, */
buf[n]='\136'; /* we make a caret */
if (buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000')
break;
}
for (;n<79;n++) /* when found, fill rest of line with space */
{
buf[n]=' ';
}
buf[79]=0; /* terminate new string */
checksum = 0;
n = DEC(buf[0]);
if (n <= 0)
break; /* 0 bytes on a line?? Must be the last line */
bp = &buf[1];
/* FOUR input characters go into each THREE output charcters */
while (n >= 4)
{
j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; putc(j, out); checksum += j;
j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; putc(j, out); checksum += j;
j = DEC(bp[2]) << 6 | DEC(bp[3]); putc(j, out); checksum += j;
checksum = checksum % SUMSIZE;
bp += 4;
n -= 3;
}
j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
checksum += j;
if (n >= 1)
putc(j, out);
j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
checksum += j;
if (n >= 2)
putc(j, out);
j = DEC(bp[2]) << 6 | DEC(bp[3]);
checksum += j;
if (n >= 3)
putc(j, out);
checksum = checksum % SUMSIZE;
bp += 4;
n -= 3;
/* Error checking under UNIX??? You must be kidding... */
/* Check if an error occured while writing to that last line */
if (errno)
{
fprintf(stderr, "ERROR: error writing to %s\n",dest);
exit(20);
}
/* The line has been decoded; now check that sum */
nosum |= !isspace(*bp);
if (nosum) /* Is there a checksum at all?? */
{
if (checksum != DEC(*bp)) /* Does that checksum match? */
{
fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\n",dest, line);
}
} /* sum */
} /* line */
} /* function */
LONG filemode(FILE *in)
{
#ifdef unix_stat
struct stat sbuf;
fstat(fileno(in), &sbuf);
return( sbuf.st_mode & 0777); /* figure out the input file mode */
#else
return( 0644 ); /* Default permissions */
#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) + ' ': '`')
/*
* copy from in to out, encoding as you go along.
*/
void encode(FILE *in, FILE *out)
{
extern errno;
LONG i, n, checksum;
char buf[256];
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);
/* Error checking under UNIX?? You must be kidding! */
/*
if (errno) {
fprintf(stderr, "ERROR: error writing to output\n");
exit(20);
}
*/
if (n <= 0)
break;
}
}
/*
* output one group of 3 bytes, pointed at by p, on file f.
* return the checksum increment.
*/
LONG outdec(UBYTE *p, FILE *f)
{
LONG 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 */
LONG fr(FILE *fd, UBYTE *buf, LONG cnt)
{
LONG c, i;
for (i=0; i<cnt; i++) {
c = getc(fd);
if (c == EOF)
return(i);
totalsize++;
buf[i] = c;
}
return (cnt);
}