home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
packer
/
uugrab
/
uudecode.c
next >
Wrap
C/C++ Source or Header
|
1990-08-22
|
11KB
|
444 lines
/* #ifndef lint
static char sccsid[] = "@(#)uudecode.c 5.3-1 (Berkeley) 9/1/87";
#endif */
/* 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. Also kludged around a missing string function in Aztec
C */
/* Modified by drw (Dale Worley, drw@math.mit.edu) to add the -f switch, which
forces the output to be on stdout. This makes uudecode into a filter, and
frees the user from perversions in the file name and mode given in the
input file. These changes Copyright (C) 1987 Dale R. Worley, and are hereby
put in the public domain. */
/* Modified by art (Art Dederick, {trwrb,oliveb,hplabs}!felix!art) to scan
for sectionized encoded files created by Richard Marks' v2.13 UUDECODE
program. Cat all sections in the proper order then pass to uudecode.
Added a more manageable method for assigning exit error codes. */
/*
* uudecode [-f] [input]
*
* Decode a file encoded with uuencode. WIll extract multiple encoded
* modules from a single file. Can deal with most mangled files, including
* BITNET. Will handle sectioned encoded files also.
*/
#include <stdio.h>
#include <ctype.h>
#ifdef AMIGA
#define AMIGA_LATTICE /* Set for Amiga Lattice C */
#define MCH_AMIGA
#define MPU68000
#endif
#ifdef unix
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
/* Exit error codes */
#define err_ok 0
#define err_dest_open 1
#define err_dest_write 2
#define err_eof 3
#define err_in_open 4
#define err_no_begin 5
#define err_no_end 6
#define err_no_user 7
#define err_out_close 8
#define err_sect_seq 9
#define err_sect_size 10
#define err_size 11
#define err_tilda_user 12
#define err_usage 13
char section_str[] = "======= [ remove this line";
#define section_str_sz (sizeof(section_str) - 1)
int section = 0; /* section flag and next section to get */
long written_size; /* number of bytes written to output, used instead of
ftell, because ftell doesn't work with -f */
#define SUMSIZE 64
#define DEC(c) (((c) - ' ') & 077) /* single character decode */
main(argc, argv)
char **argv;
{
FILE *in, *out;
int through_loop=0; /* Dejavu indicator */
int mode; /* file's mode (from header) */
long filesize; /* theoretical file size (from header) */
char dest[128];
char buf[80];
int f_option = 0; /* set to 1 if -f option is present */
#ifdef AMIGA_LATTICE
extern int Enable_Abort;
Enable_Abort=1;
#endif
/* First, check for the -f option */
if (argc >= 2 && strcmp(argv[1], "-f") == 0)
{
f_option = 1;
argc--; argv++;
}
/* A filename can be specified to be uudecoded, or nothing can
be specified, and the input will come from STDIN */
switch (argc)
{
case 1:
if ( isatty(fileno(stdin)) )
{
fprintf(stderr, "\n\Usage: %s [-f] [infile]\n", argv[0]);
exit(err_usage);
}
in=stdin;
break;
case 2:
if ( stricmp(argv[1],"-h")==0 )
{
fprintf(stderr, "\n\Usage: %s [-f] [infile]\n", argv[0]);
exit(err_usage);
}
if ((in = fopen(argv[1], "rb")) == NULL)
{
fprintf(stderr, "\nError: can't find %s\n", argv[1]);
fprintf(stderr, "Usage: %s [-f] [infile]\n", argv[0]);
exit(err_in_open);
}
break;
default:
fprintf(stderr, "\nUsage: %s [-f] [infile]\n", argv[0]);
exit(err_usage);
break;
}
/* Loop through file, searching for headers. Decode anything with a
header, complain if there where no headers. */
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(err_no_begin);
}
else
{
exit(err_ok);
}
}
if (strncmp(buf, "section 1 of uuencode", 21) == 0)
section = 1;
else if (strncmp(buf, "begin ", 6) == 0)
break;
}
sscanf(buf, "begin %o %s", &mode, dest);
/* set up the output file */
if (f_option)
{
/* the -f option is used, so use stdout */
out = stdout;
}
else
{
/* the -f option is not used, so use the filename (and mode) in the
* begin line */
#ifdef unix
/* handle ~user/file format */
if (dest[0] == '~')
{
char *sl;
struct passwd *getpwnam();
char *index();
struct passwd *user;
char dnbuf[100];
sl = index(dest, '/');
if (sl == NULL)
{
fprintf(stderr, "Illegal ~user\n");
exit(err_tilda_user);
}
*sl++ = 0;
user = getpwnam(dest+1);
if (user == NULL)
{
fprintf(stderr, "No such user as %s\n", dest);
exit(err_no_user);
}
strcpy(dnbuf, user->pw_dir);
strcat(dnbuf, "/");
strcat(dnbuf, sl);
strcpy(dest, dnbuf);
}
#endif
/* create output file */
if ((out = fopen(dest, "wb")) == NULL)
{
fprintf(stderr, "ERROR: can't open output file %s\n", dest);
exit(err_dest_open);
}
#ifdef unix
chmod(dest, mode);
#endif
}
/* actually decode the data */
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(err_no_end);
}
if (section) {
/* suck up the section trailer before the size line */
if (fgets(buf,sizeof buf,in) == NULL) {
fprintf(stderr, "ERROR: input ended unexpectedly!\n");
exit(err_eof);
}
}
if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
{
sscanf(buf, "size %ld", &filesize);
if (written_size != filesize)
{
fprintf(stderr,
"ERROR: file should have been %ld bytes long but was %ld.\n",
filesize, written_size);
exit(err_size);
}
}
/* close the output file */
if (!f_option)
if (fclose(out) != 0)
{
fprintf(stderr, "ERROR: error closing file %s.\n", dest);
exit(err_out_close);
}
through_loop = 1;
} /* forever */
} /* main */
/*
* 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.
*/
decode(in, out, dest)
FILE *in;
FILE *out;
char *dest;
{
char buf[81];
char *bp;
int nosum=0;
#ifndef unix
extern errno;
#endif
int j;
register int n;
int checksum, line, section_size;
/* zero the byte count and initial section size*/
section_size = written_size = 0;
for (line = 1; ; line++) /* for each input line */
{
if (fgets(buf, sizeof buf, in) == NULL)
{
fprintf(stderr, "ERROR: input ended unexpectedly!\n");
exit(err_eof);
}
/* Is this section finished? */
if (section &&
((strncmp(buf, section_str, section_str_sz) == 0)
|| buf[0] == '\n' || buf[0] == '\r')) {
long size;
/* Scan for section size */
do {
line++;
if (fgets(buf, sizeof buf, in) == NULL) {
fprintf(stderr, "ERROR: input ended unexpectedly!\n");
exit(err_eof);
}
n = sscanf(buf, "section size %ld", &size);
} while (n != 1);
line++;
if (section_size != size) {
fprintf(stderr, "ERROR: section size wrong!\n");
exit(err_sect_size);
}
section_size = 0;
section++;
/* Scan for start of next section */
for (n = 0; n != 1;) {
line++;
if (fgets(buf, sizeof buf, in) == NULL) {
fprintf(stderr, "ERROR: input ended unexpectedly!\n");
exit(err_eof);
}
n = sscanf(buf, "section %d of uuencode", &j);
}
if (section != j) {
fprintf(stderr, "ERROR: section %d out of sequence!\n", j);
exit(err_sect_seq);
}
while (buf[0] != 'M') {
line++;
if (fgets(buf, sizeof buf, in) == NULL) {
fprintf(stderr, "ERROR: input ended unexpectedly!\n");
exit(err_eof);
}
}
}
/* 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 characters */
while (n >= 4)
{
j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
putc(j, out);
checksum += j;
written_size++;
section_size++;
j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
putc(j, out);
checksum += j;
written_size++;
section_size++;
j = DEC(bp[2]) << 6 | DEC(bp[3]);
putc(j, out);
checksum += j;
written_size++;
section_size++;
checksum = checksum % SUMSIZE;
bp += 4;
n -= 3;
}
j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
checksum += j;
if (n >= 1)
{
putc(j, out);
written_size++;
section_size++;
}
j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
checksum += j;
if (n >= 2)
{
putc(j, out);
written_size++;
section_size++;
}
j = DEC(bp[2]) << 6 | DEC(bp[3]);
checksum += j;
if (n >= 3)
{
putc(j, out);
written_size++;
section_size++;
}
checksum = checksum % SUMSIZE;
bp += 4;
n -= 3;
#ifndef unix
/* 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(err_dest_write);
}
#endif
/* The line has been decoded; now check that sum */
nosum |= !isspace(*bp);
if (nosum && !section) /* 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 */
#ifdef unix
/*
* Return the ptr in sp at which the character c appears;
* 0 if not found
*/
char *
index(sp, c)
register char *sp, c;
{
do
{
if (*sp == c)
return(sp);
}
while (*sp++);
return(0);
}
#endif