[comp.binaries.ibm.pc.d] A unix unpacking script

norden@oucsace.cs.OHIOU.EDU (Jeffrey Norden) (12/02/88)

Below is a shell script which unix users may find helpful for unpacking the
offerings from comp.binaries.ibm.pc The script depends upon the uuencoded
info being bracketed between "BEGIN--cut here" and "END--cut here" lines.
The comments at the begining explain its use.
The grep at the end for finding the size and checksum in the comments of the
first file is kind of a kludge, but it seems to work.
Enjoy.
	-Jeff Norden, norden@ace.cs.ohiou.edu
	 Dept of Math, Ohio University, Athens, OH  45701

Cut here-------- snip ----------- snip --------- snip --------- Cut here
#! /bin/sh
# ibm-unpack: a shell script to create arc files from the messages
# distributed on the comp.binaries.ibm.pc newsgroup.
# -Jeff Norden, norden@ace.cs.ohiou.edu  Dec 1988
#   If foo1 foo2 and foo3 are files which contain the uuencoded version of
# foo.arc which you got off the net (including mail headers, etc), then
# invoking  "ibm-unpack foo?" will extract foo.arc for you.
#   Features/bugs: (1) zcat will be invoked on any file whose name ends
# in .Z, so you can keep your files compressed in order to save disk space.
# (2) if uudecode works ok, the size and checksum of the resulting file is
# printed, along with the info from the first distribution file, so you can
# compare them, (3) if there is more than one file, they must be specified
# in the correct order, (4) the size and checkusm stuff depends upon the
# format of the distribution files remaining the same as they are now.

usage="Usage: ibm-unpack file1 file2 ..."
if [ $# -eq 0 ]
then
  echo $usage; exit;
fi

SUM="sum -r"
TEMP=tmp$$.uue

rm -f $TEMP

echo Creating temp file...
for filename in $*
do
  if [ -z  "`echo $filename | grep \\.Z\$`" ]
  then
	CAT=cat
	echo " extracting data from $filename"
  else
	CAT=zcat
	echo " extracting data from $filename (using zcat to uncompress)"
  fi

${CAT} $filename | awk "
/^END--cut here/ {exit}
{if (printing) print}
/^BEGIN--cut here/ {printing=1}" >> $TEMP

done

echo; echo uudecoding...
uudecode < $TEMP || exit
rm -f $TEMP

echo;
echo info from the distribution:
echo "checksum     size (bytes)  file"
if [ -z  "`echo $1 | grep \\.Z\$`" ]
then
 grep "^ .*arc\$" $1
else
 zcat $1 | grep "^ .*arc\$"
fi
echo here is what we got:
 ls -l *.arc; echo "checksum: " `sum -r *.arc`

Cut here-------- snip ----------- snip --------- snip --------- Cut here

twb@hoqax.UUCP (T.W. Beattie) (12/04/88)

In article <371@oucsace.cs.OHIOU.EDU> 
norden@oucsace.UUCP (Jeffrey Norden) writes:
>Below is a shell script which unix users may find helpful for unpacking the
>offerings from comp.binaries.ibm.pc The script depends upon the uuencoded
>info being bracketed between "BEGIN
>	-Jeff Norden, norden@ace.cs.ohiou.edu

This script depends on a working UN*X uudecode.
I have the uuencode/uudecode:
	@(#)uuencode.1c	6.2 (Berkeley) 4/24/86
which doesn't (usually) work.
Anyone have a WORKING uudecode/uuencode for UNIX System V?

Tom.
hoqaa!twb

w8sdz@smoke.BRL.MIL (Keith B. Petersen ) (12/05/88)

If your uudecode doesn't seem to work, try this one.  This is for Unix,
not MSDOS.  It's from the current Berkeley distribution and is PD.
---cut-here---
#ifndef lint
static char sccsid[] = "@(#)uudecode.c	5.3 (Berkeley) 4/10/85";
#endif

/*
 * uudecode [input]
 *
 * create the specified file, decoding as you go.
 * used with uuencode.
 */
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>

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

main(argc, argv)
char **argv;
{
	FILE *in, *out;
	int mode;
	char dest[128];
	char buf[80];

	/* optional input arg */
	if (argc > 1) {
		if ((in = fopen(argv[1], "r")) == NULL) {
			perror(argv[1]);
			exit(1);
		}
		argv++; argc--;
	} else
		in = stdin;

	if (argc != 1) {
		printf("Usage: uudecode [infile]\n");
		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);

	/* 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(3);
		}
		*sl++ = 0;
		user = getpwnam(dest+1);
		if (user == NULL) {
			fprintf(stderr, "No such user as %s\n", dest);
			exit(4);
		}
		strcpy(dnbuf, user->pw_dir);
		strcat(dnbuf, "/");
		strcat(dnbuf, sl);
		strcpy(dest, dnbuf);
	}

	/* create output file */
	out = fopen(dest, "w");
	if (out == NULL) {
		perror(dest);
		exit(4);
	}
	chmod(dest, mode);

	decode(in, out);

	if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) {
		fprintf(stderr, "No end line\n");
		exit(5);
	}
	exit(0);
}

/*
 * copy from in to out, decoding as you go along.
 */
decode(in, out)
FILE *in;
FILE *out;
{
	char buf[80];
	char *bp;
	int n;

	for (;;) {
		/* for each input line */
		if (fgets(buf, sizeof buf, in) == NULL) {
			printf("Short file\n");
			exit(10);
		}
		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 c1, c2, c3;

	c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
	c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
	c3 = DEC(p[2]) << 6 | DEC(p[3]);
	if (n >= 1)
		putc(c1, f);
	if (n >= 2)
		putc(c2, f);
	if (n >= 3)
		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);
}

/*
 * Return the ptr in sp at which the character c appears;
 * NULL if not found
 */

#define	NULL	0

char *
index(sp, c)
register char *sp, c;
{
	do {
		if (*sp == c)
			return(sp);
	} while (*sp++);
	return(NULL);
}
-- 
Keith Petersen
Maintainer of the CP/M & MSDOS archives at WSMR-SIMTEL20.ARMY.MIL [26.0.0.74]
Arpa: W8SDZ@WSMR-SIMTEL20.ARMY.MIL
Uucp: {ames,decwrl,harvard,rutgers,ucbvax,uunet}!wsmr-simtel20.army.mil!w8sdz

w8sdz@smoke.BRL.MIL (Keith B. Petersen ) (12/05/88)

Here is the latest PD uuencode for Unix, from the current Berkeley
distribution.  It substitutes the accent grave (`) for the space
character to get around problems of some mailers stripping trailing
blanks.  Note that this uuencode's output defaults to stdout.  You
must redirect it to make a file.  I use the following shell script
which I named "uue":

	uuencode $1 $1 > $1.uue

It is envoked like this:   uue my.arc
and produces my.arc.uue as its output.

--cut-here--
#ifndef lint
static char sccsid[] = "@(#)uuencode.c	5.5 (Berkeley) 2/24/88";
#endif

/*
 * uuencode [input] output
 *
 * Encode a file so it can be mailed to a remote system.
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

/* ENC is the basic 1 character encoding function to make a char printing */
#define ENC(c) ((c) ? ((c) & 077) + ' ': '`')

main(argc, argv)
char **argv;
{
	FILE *in;
	struct stat sbuf;
	int mode;

	/* optional 1st argument */
	if (argc > 2) {
		if ((in = fopen(argv[1], "r")) == NULL) {
			perror(argv[1]);
			exit(1);
		}
		argv++; argc--;
	} else
		in = stdin;

	if (argc != 2) {
		fprintf(stderr,"Usage: uuencode [infile] remotefile\n");
		exit(2);
	}

	/* figure out the input file mode */
	if (fstat(fileno(in), &sbuf) < 0 || !isatty(fileno(in)))
		mode = 0666 & ~umask(0666);
	else
		mode = sbuf.st_mode & 0777;
	printf("begin %o %s\n", mode, argv[1]);

	encode(in, stdout);

	printf("end\n");
	exit(0);
}

/*
 * copy from in to out, encoding as you go along.
 */
encode(in, out)
register FILE *in;
register FILE *out;
{
	char buf[80];
	register int i, n;

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

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

		putc('\n', out);
		if (n <= 0)
			break;
	}
}

/*
 * output one group of 3 bytes, pointed at by p, on file f.
 */
outdec(p, f)
register char *p;
register FILE *f;
{
	register 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);
}
-- 
Keith Petersen
Maintainer of the CP/M & MSDOS archives at WSMR-SIMTEL20.ARMY.MIL [26.0.0.74]
Arpa: W8SDZ@WSMR-SIMTEL20.ARMY.MIL
Uucp: {ames,decwrl,harvard,rutgers,ucbvax,uunet}!wsmr-simtel20.army.mil!w8sdz

dhesi@bsu-cs.UUCP (Rahul Dhesi) (12/05/88)

In article <9066@smoke.BRL.MIL> w8sdz@brl.arpa (Keith Petersen) writes:
>#define DEC(c)	(((c) - ' ') & 077)

Shouldn't that be IBM?
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee}!bsu-cs!dhesi