
: This is a shar archive.  Extract with sh, not csh.
echo x - Makefile
sed -e 's/^X//' > Makefile << '!Funky!Stuff!'
XFILES = xbin.c xbin.1 xbinary Makefile readme
XCFLAGS=-O
X
Xxbin:	xbin.o
X	cc -o xbin xbin.o
X
Xclean:
X	rm -f *.o xbin xbin.sh
X
Xshar:
X	shar $(FILES) > xbin.sh
!Funky!Stuff!
echo x - readme
sed -e 's/^X//' > readme << '!Funky!Stuff!'
X
XThis is a small rewrite of xbin to create either macget/macput format
Xfiles or MacBinary files from BinHex files.
X
Xxbin [other options] files:
X
X	.hqx	->	.rsrc .info .data
X
XFiles are suitable for downloading with MacTerminal 1.1 protocol.
X
Xxbin -b [other options] files
X
X	.hqx	->	.bin 
X
XFiles are suitable for downloading with MacBinary protocol, and there
Xare one-third as many output files!
X
XThere is a Makefile, and a new man page.  Enjoy!
X
XEarle Horton
!Funky!Stuff!
echo x - xbin.1
sed -e 's/^X//' > xbin.1 << '!Funky!Stuff!'
X.TH XBIN 1L "16 Jul 1988"
X.UC 4
X.SH NAME
Xxbin \- convert BinHex file to binary before downloading
Xto MacTerminal
X.SH SYNOPSIS
X.B xbin
X[
X.B \-o
X]
X[
X.B \-b
X]
X[
X.B \-v
X]
X[
X.B \-l
X]
X[[
X.B \-n
Xname
X] file] ...
X.SH DESCRIPTION
X.I Xbin
Xconverts a file created by BinHex (usually
Xnamed with one of the extensions ".hex", ".hcx", or ".hqx")
Xinto either three host-system files suitable for downloading to a
XMacintosh via macput, or a MacBinary format file.
XThis program is designed for use with the 1.1 Release
Xversion of MacTerminal, but includes a compatibility option for the
Xold -0.15X Almost-Alpha version.  MacBinary files are compatible
Xwith many Macintosh communication programs.
X.PP
XThe 
X.B -l 
X(list) option reads the header information and
Xprints out all the useful information there,
Xwithout creating any converted output files.
X.PP
XThe 
X.B -v 
X(verbose) option prints a line for each file to be converted, indicating
Xthe input and output file names.
X.PP
XThe 
X.B -n
Xname
Xoption allows the user to specify the name to use when creating
Xthe host files and the eventual name to use on the mac.
XThis option must precede the input file name it is to affect.
X.PP
XIf this option is not used, the names will be derived from
Xeither the input file name (.hex or .hcx files),
Xor the name encoded in the header information (.hqx files).
XSpaces and slashes will be converted to underscores, and
Xthe .h?x extension will be deleted, if one is included in the
Xinput file name.
X.PP
XA file name of "-" indicates that the input should be taken from stdin.
XIf no mac file name is specified, the default name (for .hex or .hcx files)
Xis "stdin".
X.PP
XMail or news headers and signatures need not be manually
Xstripped -- xbin will ignore pretty much anything
Xit doesn't need. 
X.PP
X.I xbin 
Xcreates three host-system files from each input file:
X.IB name .info ,
X.IB name .data ,
Xand
X.IB name .rsrc .
X.PP
XThe 
X.B \-o
Xflag specifies "old" (version -0.15X) MacTerminal compatibility mode.
X.PP
XThe
X.B \-b
Xflag specifies create a single MacBinary file:
X.IB name .bin ,
Xinstead of the three MacTerminal format files.
X.SH BUGS
XThe "LOCKED" bit in the flags cannot be set by xbin.
XThis is due to a bug in MacTerminal, which sets the flags
Xwhen the file is created, rather than after it has been
Xtransfered, resulting in it not being able to write the
Xfile.
X.PP
XInput files must contain a line starting with "(This file"
Xto detect the beginning of the BinHex information.
X.SH SEE ALSO
Xmacput(1), macget(1)
X.SH AUTHOR
XDave Johnson, Brown 12/16/84;
XCRC handling code by Darin Adler, TMQ Software 3/16/85
!Funky!Stuff!
echo x - xbin.c
sed -e 's/^X//' > xbin.c << '!Funky!Stuff!'
X
X
X#ifndef lint
Xstatic char     version[] = "xbin.c Version 2.2.2 07/16/88";
X#endif lint
Xstatic char     fname_trans_table[] =
X"@ABCDEFGHIJKLMNOPQRSTUVWXYZexxxxxxx#xxxxxxxxxxxx0123456789xxxxxxxABCDEFGHIJKLMNOPQRSTUVWXYZxxxx_xabcdefghijklmnopqrstuvwxyzxxxxxxABCDEFGHIJKLMNOPQRSTUVWXYZexxxxxxxxxxxxxxxxxxxx0123456789xxxxxxxABCDEFGHIJKLMNOPQRSTUVWXYZxxxx_xabcdefghijklmnopqrstuvwxyzxxxxxx";
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
X#ifdef MAXNAMLEN		/* 4.2 BSD */
X#define FNAMELEN MAXNAMLEN
X#else
X#define FNAMELEN DIRSIZ
X#endif
X
X#ifdef BSD
X#include <sys/time.h>
X#include <sys/timeb.h>
X#define search_last rindex
Xextern char    *rindex();
X#else
X#include <time.h>
Xextern long     timezone;
X#define search_last strrchr
Xextern char    *strrchr();
X#endif
X
X/* Mac time of 00:00:00 GMT, Jan 1, 1970 */
X#define TIMEDIFF 0x7c25b080
X
X#define DATABYTES 128
X
X#define BYTEMASK 0xff
X#define BYTEBIT 0x100
X#define WORDMASK 0xffff
X#define WORDBIT 0x10000
X
X#define NAMEBYTES 63
X#define H_NLENOFF 1
X#define H_NAMEOFF 2
X
X/* 65 <-> 80 is the FInfo structure */
X#define H_TYPEOFF 65
X#define H_AUTHOFF 69
X#define H_FLAGOFF 73
X
X#define H_LOCKOFF 81
X#define H_DLENOFF 83
X#define H_RLENOFF 87
X#define H_CTIMOFF 91
X#define H_MTIMOFF 95
X
X#define H_OLD_DLENOFF 81
X#define H_OLD_RLENOFF 85
X
X#define F_BUNDLE 0x2000
X#define F_LOCKED 0x8000
X
Xstruct macheader {
X	char            m_name[NAMEBYTES + 1];
X	char            m_type[4];
X	char            m_author[4];
X	short           m_flags;
X	long            m_datalen;
X	long            m_rsrclen;
X	long            m_createtime;
X	long            m_modifytime;
X}               mh;
X
Xstruct filenames {
X	char            f_info[256];
X	char            f_data[256];
X	char            f_rsrc[256];
X}               files;
X
Xint             pre_beta;	/* options */
Xint             listmode;
Xint             verbose;
Xint             macbinary = 0;
X
Xint             compressed;	/* state variables */
Xint             qformat;
XFILE           *ifp;
XFILE           *fp = NULL;
X
X
X/*
X * xbin -- unpack BinHex format file into suitable
X * format for downloading with macput
X * Dave Johnson, Brown University Computer Science
X *
X * checksum code by Darin Adler, TMQ Software
X *
X * modification to support MacBinary output file by Earle Horton
X *  uses code from Jim Budler's "macbin.c"
X *
X * (c) 1984 Brown University 
X * may be used but not sold without permission
X *
X * created ddj 12/16/84 
X * revised ddj 03/10/85 -- version 4.0 compatibility, other minor mods
X * revised ddj 03/11/85 -- strip LOCKED bit from m_flags
X * revised ahm 03/12/85 -- System V compatibility
X * revised dba 03/16/85 -- 4.0 EOF fixed, 4.0 checksum added
X * revised ddj 03/17/85 -- extend new features to older formats: -l, stdin
X * revised ddj 03/24/85 -- check for filename truncation, allow multiple files
X * revised ddj 03/26/85 -- fixed USG botches, many problems w/multiple files
X * revised jcb 03/30/85 -- revised for compatibility with 16-bit int
X * revised erh 07/16/88 -- revised to support MacBinary output with "-b"
X */
Xchar usage[] = "usage: \"xbin [-v] [-l] [-o] [-b] [-n name] [-] filename\"\n";
X
Xmain(ac, av)
X	char          **av;
X{
X	char           *filename, *macname;
X	int            i;
X
X	filename = "";
X	macname = "";
X	ac--;
X	av++;
X	while (ac) {
X		if (av[0][0] == '-') {
X			switch (av[0][1]) {
X			case '\0':
X				filename = "-";
X				break;
X			case 'v':
X				verbose++;
X				break;
X			case 'l':
X				listmode++;
X				break;
X			case 'o':
X				pre_beta++;
X				break;
X			case 'b':
X				macbinary = 1;
X				break;
X			case 'n':
X				if (ac > 1) {
X					ac--;
X					av++;
X					macname = av[0];
X					filename = "";
X					break;
X				} else
X					goto bad_usage;
X			default:
X				goto bad_usage;
X			}
X		} else
X			filename = av[0];
X		if (filename[0] != '\0') {
X			setup_files(filename, macname);
X			if (listmode) {
X				print_header();
X			} else 
X{
X if (macbinary == 1) {
X	fp = fopen(files.f_info, "w");
X	if (fp == NULL) {
X	       perror("output file");
X	       exit(-1);
X	}
X	for(i = 128 ; i-- > 0;) {
X	       putc(0,fp);/* Make space for info. */
X	}
X }
X process_forks();
X /* now that we know the size of the forks */
X if (macbinary == 1)
X rewind(fp);
X forge_info();
X}
X			if (ifp != stdin)
X				fclose(ifp);
X			macname = "";
X			ifp = NULL;	/* reset state */
X			qformat = 0;
X			compressed = 0;
X		}
X		ac--;
X		av++;
X	}
X	if (*filename == '\0') {
Xbad_usage:
X		fprintf(stderr, usage);
X		exit(1);
X	}
X}
X
Xstatic char    *extensions[] = {
X				".hqx",
X				".hcx",
X				".hex",
X				"",
X				NULL
X};
X
Xsetup_files(filename, macname)
X	char           *filename;	/* input file name -- extension
X					 * optional */
X	char           *macname;/* name to use on the mac side of things */
X{
X	char            namebuf[256], *np;
X	char          **ep;
X	int             n;
X	struct stat     stbuf;
X	long            curtime;
X
X	if (filename[0] == '-') {
X		ifp = stdin;
X		filename = "stdin";
X	} else {
X		/* find input file and open it */
X		for (ep = extensions; *ep != NULL; ep++) {
X			sprintf(namebuf, "%s%s", filename, *ep);
X			if (stat(namebuf, &stbuf) == 0)
X				break;
X		}
X		if (*ep == NULL) {
X			perror(namebuf);
X			exit(-1);
X		}
X		ifp = fopen(namebuf, "r");
X		if (ifp == NULL) {
X			perror(namebuf);
X			exit(-1);
X		}
X	}
X	if (ifp == stdin) {
X		curtime = time(0);
X		mh.m_createtime = curtime;
X		mh.m_modifytime = curtime;
X	} else {
X		mh.m_createtime = stbuf.st_mtime;
X		mh.m_modifytime = stbuf.st_mtime;
X	}
X	if (listmode || verbose) {
X		fprintf(stderr, "%s %s%s",
X			listmode ? "\nListing" : "Converting",
X			namebuf, listmode ? ":\n" : " ");
X	}
X	qformat = find_header();/* eat mailer header &cetera, intuit format */
X
X	if (qformat)
X		do_q_header(macname);
X	else
X		do_o_header(macname, filename);
X
X	/* make sure host file name doesn't get truncated beyond recognition */
X	n = strlen(mh.m_name);
X	if (n > FNAMELEN - 2)
X		n = FNAMELEN - 2;
X	strncpy(namebuf, mh.m_name, n);
X	namebuf[n] = '\0';
X
X	/* get rid of troublesome characters */
X	for (np = namebuf; *np; np++)
X		/* Negative chars on some systems make lousy subscripts. */
X		*np = fname_trans_table[(unsigned) *np];
X
X	if ((macbinary == 1)) {
X		sprintf(files.f_info, "%s.bin", namebuf);
X	} else {
X		sprintf(files.f_data, "%s.data", namebuf);
X		sprintf(files.f_rsrc, "%s.rsrc", namebuf);
X		sprintf(files.f_info, "%s.info", namebuf);
X	}
X	if (verbose) {
X		if ((macbinary == 1))
X			fprintf(stderr, "==> %s.bin\n", namebuf);
X		else
X			fprintf(stderr, "==> %s.{info,data,rsrc}\n", namebuf);
X	}
X}
X
X/* print out header information in human-readable format */
Xprint_header()
X{
X	char           *ctime();
X
X	printf("macname: %s\n", mh.m_name);
X	printf("filetype: %.4s, ", mh.m_type);
X	printf("author: %.4s, ", mh.m_author);
X	printf("flags: 0x%x\n", mh.m_flags);
X	if (qformat) {
X		printf("data length: %ld, ", mh.m_datalen);
X		printf("rsrc length: %ld\n", mh.m_rsrclen);
X	}
X	if (!pre_beta) {
X		printf("create time: %s", ctime(&mh.m_createtime));
X	}
X}
X
Xprocess_forks()
X{
X	if (qformat) {
X		/* read data and resource forks of .hqx file */
X		do_q_fork(files.f_data, mh.m_datalen);
X		do_q_fork(files.f_rsrc, mh.m_rsrclen);
X	} else
X		do_o_forks();
X}
X
X/* write out .info file from information in the mh structure */
Xforge_info()
X{
X	static char     buf[DATABYTES];
X	char           *np;
X	int             n;
X	long            tdiff;
X	struct tm      *tp;
X#ifdef BSD
X	struct timeb    tbuf;
X#else
X	long            bs;
X#endif
X
X	for (np = mh.m_name; *np; np++)
X		if (*np == '_')
X			*np = ' ';
X
X	buf[H_NLENOFF] = n = np - mh.m_name;
X	strncpy(buf + H_NAMEOFF, mh.m_name, n);
X	strncpy(buf + H_TYPEOFF, mh.m_type, 4);
X	strncpy(buf + H_AUTHOFF, mh.m_author, 4);
X	put2(buf + H_FLAGOFF, mh.m_flags & ~F_LOCKED);
X	if (pre_beta) {
X		put4(buf + H_OLD_DLENOFF, mh.m_datalen);
X		put4(buf + H_OLD_RLENOFF, mh.m_rsrclen);
X	} else {
X		put4(buf + H_DLENOFF, mh.m_datalen);
X		put4(buf + H_RLENOFF, mh.m_rsrclen);
X
X		/* convert unix file time to mac time format */
X#ifdef BSD
X		ftime(&tbuf);
X		tp = localtime(&tbuf.time);
X		tdiff = TIMEDIFF - tbuf.timezone * 60;
X		if (tp->tm_isdst)
X			tdiff += 60 * 60;
X#else
X		/* I hope this is right! -andy */
X		time(&bs);
X		tp = localtime(&bs);
X		tdiff = TIMEDIFF - timezone;
X		if (tp->tm_isdst)
X			tdiff += 60 * 60;
X#endif
X		put4(buf + H_CTIMOFF, mh.m_createtime + tdiff);
X		put4(buf + H_MTIMOFF, mh.m_modifytime + tdiff);
X	}
X	if (fp == NULL) {
X		fp = fopen(files.f_info, "w");
X		if (fp == NULL) {
X				perror("info file");
X			        exit(-1);
X		}
X	}
X	if (macbinary == 1) {
X		if (buf[74] & 0x40)
X			buf[81] = '\1';	/* protected */
X		buf[74] = '\0';         /* MacBinary identifiers */
X		buf[82] = '\0';
X	}
X	fwrite(buf, 1, DATABYTES, fp);
X	fclose(fp);
X	fp = NULL;
X}
X
X/* eat characters until header detected, return which format */
Xfind_header()
X{
X	int             c, at_bol;
X	char            ibuf[BUFSIZ];
X
X	/* look for "(This file ...)" line */
X	while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
X		if (strncmp(ibuf, "(This file", 10) == 0)
X			break;
X	}
X	at_bol = 1;
X	while ((c = getc(ifp)) != EOF) {
X		switch (c) {
X		case '\n':
X		case '\r':
X			at_bol = 1;
X			break;
X		case ':':
X			if (at_bol)	/* q format */
X				return 1;
X			break;
X		case '#':
X			if (at_bol) {	/* old format */
X				ungetc(c, ifp);
X				return 0;
X			}
X			break;
X		default:
X			at_bol = 0;
X			break;
X		}
X	}
X
X	fprintf(stderr, "unexpected EOF\n");
X	exit(2);
X	/* NOTREACHED */
X}
X
Xstatic unsigned int crc;
X
Xshort           get2q();
Xlong            get4q();
X
X/* read header of .hqx file */
Xdo_q_header(macname)
X	char           *macname;
X{
X	char            namebuf[256];	/* big enough for both att & bsd */
X	int             n;
X	int             calc_crc, file_crc;
X
X	crc = 0;		/* compute a crc for the header */
X	q_init();		/* reset static variables */
X
X	n = getq();		/* namelength */
X	n++;			/* must read trailing null also */
X	getqbuf(namebuf, n);	/* read name */
X	if (macname[0] == '\0')
X		macname = namebuf;
X
X	n = strlen(macname);
X	if (n > NAMEBYTES)
X		n = NAMEBYTES;
X	strncpy(mh.m_name, macname, n);
X	mh.m_name[n] = '\0';
X
X	getqbuf(mh.m_type, 4);
X	getqbuf(mh.m_author, 4);
X	mh.m_flags = get2q();
X	mh.m_datalen = get4q();
X	mh.m_rsrclen = get4q();
X
X	comp_q_crc(0);
X	comp_q_crc(0);
X	calc_crc = crc;
X	file_crc = get2q();
X	verify_crc(calc_crc, file_crc);
X}
X
Xdo_q_fork(fname, len)
X	char           *fname;
X	register long   len;
X{
X	register int    c, i;
X	int             calc_crc, file_crc;
X
X	if (macbinary != 1) {
X		if (fp != NULL) {
X			fclose(fp);
X		}
X		fp = fopen(fname, "w");
X		if (fp == NULL) {
X			perror(fname);
X			exit(-1);
X		}
X	}
X	crc = 0;		/* compute a crc for a fork */
X
X	if (len)
X		for (i = 0; i < len; i++) {
X			if ((c = getq()) == EOF) {
X				fprintf(stderr, "unexpected EOF\n");
X				exit(2);
X			}
X			putc(c, fp);
X		}
X
X	comp_q_crc(0);
X	comp_q_crc(0);
X	calc_crc = crc;
X	file_crc = get2q();
X	verify_crc(calc_crc, file_crc);
X	if (macbinary != 1) {
X		fclose(fp);
X		fp = NULL;
X	}
X}
X
X/* verify_crc(); -- check if crc's check out */
Xverify_crc(calc_crc, file_crc)
X	unsigned int    calc_crc, file_crc;
X{
X	calc_crc &= WORDMASK;
X	file_crc &= WORDMASK;
X
X	if (calc_crc != file_crc) {
X		fprintf(stderr, "CRC error\n---------\n");
X		fprintf(stderr, "CRC in file:\t0x%x\n", file_crc);
X		fprintf(stderr, "calculated CRC:\t0x%x\n", calc_crc);
X		exit(3);
X	}
X}
X
Xstatic int      eof;
Xstatic char     obuf[3];
Xstatic char    *op, *oend;
X
X/* initialize static variables for q format input */
Xq_init()
X{
X	eof = 0;
X	op = obuf;
X	oend = obuf + sizeof obuf;
X}
X
X/* get2q(); q format -- read 2 bytes from input, return short */
Xshort
Xget2q()
X{
X	register int    c;
X	short           value = 0;
X
X	c = getq();
X	value = (c & BYTEMASK) << 8;
X	c = getq();
X	value |= (c & BYTEMASK);
X
X	return value;
X}
X
X/* get4q(); q format -- read 4 bytes from input, return long */
Xlong
Xget4q()
X{
X	register int    c, i;
X	long            value = 0L;
X
X	for (i = 0; i < 4; i++) {
X		c = getq();
X		value <<= 8;
X		value |= (c & BYTEMASK);
X	}
X	return value;
X}
X
X/* getqbuf(); q format -- read n characters from input into buf */
X/*		All or nothing -- no partial buffer allowed */
Xgetqbuf(buf, n)
X	register char  *buf;
X	register int    n;
X{
X	register int    c, i;
X
X	for (i = 0; i < n; i++) {
X		if ((c = getq()) == EOF)
X			return EOF;
X		*buf++ = c;
X	}
X	return 0;
X}
X
X#define RUNCHAR 0x90
X
X/* q format -- return one byte per call, keeping track of run codes */
Xgetq()
X{
X	register int    c;
X
X	if ((c = getq_nocrc()) == EOF)
X		return EOF;
X	comp_q_crc(c);
X	return c;
X}
X
Xgetq_nocrc()
X{
X	static int      rep, lastc;
X	int             c;
X
X	if (rep) {
X		rep--;
X		return lastc;
X	}
X	if ((c = getq_raw()) == EOF) {
X		return EOF;
X	}
X	if (c == RUNCHAR) {
X		if ((rep = getq_raw()) == EOF)
X			return EOF;
X		if (rep == 0) {
X			return RUNCHAR;
X		} else {
X			/* already returned one, about to return another */
X			rep -= 2;
X			return lastc;
X		}
X	} else {
X		lastc = c;
X		return c;
X	}
X}
X
X/* q format -- return next 8 bits from file without interpreting run codes */
Xgetq_raw()
X{
X	char            ibuf[4];
X	register char  *ip = ibuf, *iend = ibuf + sizeof ibuf;
X	int             c;
X
X	if (op == obuf) {
X		for (ip = ibuf; ip < iend; ip++) {
X			if ((c = get6bits()) == EOF)
X				if (ip <= &ibuf[1])
X					return EOF;
X				else if (ip == &ibuf[2])
X					eof = 1;
X				else
X					eof = 2;
X			*ip = c;
X		}
X		obuf[0] = (ibuf[0] << 2 | ibuf[1] >> 4);
X		obuf[1] = (ibuf[1] << 4 | ibuf[2] >> 2);
X		obuf[2] = (ibuf[2] << 6 | ibuf[3]);
X	}
X	if ((eof) & (op >= &obuf[eof]))
X		return EOF;
X	c = *op++;
X	if (op >= oend)
X		op = obuf;
X	return (c & BYTEMASK);
X}
X
Xchar            tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
X
X/* q format -- decode one byte into 6 bit binary */
Xget6bits()
X{
X	register int    c;
X	register char  *where;
X
X	while (1) {
X		c = getc(ifp);
X		switch (c) {
X		case '\n':
X		case '\r':
X			continue;
X		case ':':
X		case EOF:
X			return EOF;
X		default:
X			where = tr;
X			while (*where != '\0' && *where != c)
X				where++;
X			if (*where == c)
X				return (where - tr);
X			else {
X				fprintf(stderr, "bad char\n");
X				return EOF;
X			}
X		}
X	}
X}
X
X#define CRCCONSTANT 0x1021
X
Xcomp_q_crc(c)
X	register unsigned int c;
X{
X	register int    i;
X	register unsigned long temp = crc;
X
X	for (i = 0; i < 8; i++) {
X		c <<= 1;
X		if ((temp <<= 1) & WORDBIT)
X			temp = (temp & WORDMASK) ^ CRCCONSTANT;
X		temp ^= (c >> 8);
X		c &= BYTEMASK;
X	}
X	crc = temp;
X}
X
X/* old format -- process .hex and .hcx files */
Xdo_o_header(macname, filename)
X	char           *macname, *filename;
X{
X	char            namebuf[256];	/* big enough for both att & bsd */
X	char            ibuf[BUFSIZ];
X	int             n;
X
X	/* set up name for output files */
X	if (macname[0] == '\0') {
X		strcpy(namebuf, filename);
X
X		/* strip directories */
X		macname = search_last(namebuf, '/');
X		if (macname == NULL)
X			macname = namebuf;
X		else
X			macname++;
X
X		/* strip extension */
X		n = strlen(macname);
X		if (n > 4) {
X			n -= 4;
X			if (macname[n] == '.' && macname[n + 1] == 'h'
X			    && macname[n + 3] == 'x')
X				macname[n] = '\0';
X		}
X	}
X	n = strlen(macname);
X	if (n > NAMEBYTES)
X		n = NAMEBYTES;
X	strncpy(mh.m_name, macname, n);
X	mh.m_name[n] = '\0';
X
X	/* read "#TYPEAUTH$flag"  line */
X	if (fgets(ibuf, BUFSIZ, ifp) == NULL) {
X		fprintf(stderr, "unexpected EOF\n");
X		exit(2);
X	}
X	n = strlen(ibuf);
X	if (n >= 7 && ibuf[0] == '#' && ibuf[n - 6] == '$') {
X		if (n >= 11)
X			strncpy(mh.m_type, &ibuf[1], 4);
X		if (n >= 15)
X			strncpy(mh.m_author, &ibuf[5], 4);
X		sscanf(&ibuf[n - 5], "%4hx", &mh.m_flags);
X	}
X}
X
Xdo_o_forks()
X{
X	char            ibuf[BUFSIZ];
X	int             forks = 0, found_crc = 0;
X	int             calc_crc, file_crc;
X	extern long     make_file();
X
X	crc = 0;		/* calculate a crc for both forks */
X
X	/* create empty files ahead of time */
X	if (macbinary != 1) {
X		close(creat(files.f_data, 0666));
X		close(creat(files.f_rsrc, 0666));
X	}
X	while (!found_crc && fgets(ibuf, BUFSIZ, ifp) != NULL) {
X		if (forks == 0 && strncmp(ibuf, "***COMPRESSED", 13) == 0) {
X			compressed++;
X			continue;
X		}
X		if (strncmp(ibuf, "***DATA", 7) == 0) {
X			mh.m_datalen = make_file(files.f_data, compressed);
X			forks++;
X			continue;
X		}
X		if (strncmp(ibuf, "***RESOURCE", 11) == 0) {
X			mh.m_rsrclen = make_file(files.f_rsrc, compressed);
X			forks++;
X			continue;
X		}
X		if (compressed && strncmp(ibuf, "***CRC:", 7) == 0) {
X			found_crc++;
X			calc_crc = crc;
X			sscanf(&ibuf[7], "%x", &file_crc);
X			break;
X		}
X		if (!compressed && strncmp(ibuf, "***CHECKSUM:", 12) == 0) {
X			found_crc++;
X			calc_crc = crc & BYTEMASK;
X			sscanf(&ibuf[12], "%x", &file_crc);
X			file_crc &= BYTEMASK;
X			break;
X		}
X	}
X
X	if (found_crc)
X		verify_crc(calc_crc, file_crc);
X	else {
X		fprintf(stderr, "missing CRC\n");
X		exit(3);
X	}
X}
X
Xlong
Xmake_file(fname, compressed)
X	char           *fname;
X	int             compressed;
X{
X	char            ibuf[BUFSIZ];
X	register long   nbytes = 0;
X
X	if (macbinary != 1) {
X		if (fp != NULL)
X			fclose(fp);
X		fp = fopen(fname, "w");
X		if (fp == NULL) {
X			perror(fname);
X			exit(-1);
X		}
X	}
X	while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
X		if (strncmp(ibuf, "***END", 6) == 0)
X			break;
X		if (compressed)
X			nbytes += comp_to_bin(ibuf, fp);
X		else
X			nbytes += hex_to_bin(ibuf, fp);
X	}
X	if (macbinary != 1) {
X		fclose(fp);
X		fp = NULL;
X	}
X	return nbytes;
X}
X
Xcomp_c_crc(c)
X	unsigned char   c;
X{
X	crc = (crc + c) & WORDMASK;
X	crc = ((crc << 3) & WORDMASK) | (crc >> 13);
X}
X
Xcomp_e_crc(c)
X	unsigned char   c;
X{
X	crc += c;
X}
X
X#define SIXB(c) (((c)-0x20) & 0x3f)
X
Xcomp_to_bin(ibuf, outf)
X	char            ibuf[];
XFILE           *outf;
X{
X	char            obuf[BUFSIZ];
X	register char  *ip = ibuf;
X	register char  *op = obuf;
X	register int    n, outcount;
X	int             numread, incount;
X
X	numread = strlen(ibuf);
X	ip[numread - 1] = ' ';	/* zap out the newline */
X	outcount = (SIXB(ip[0]) << 2) | (SIXB(ip[1]) >> 4);
X	incount = ((outcount / 3) + 1) * 4;
X	for (n = numread; n < incount; n++)	/* restore lost spaces */
X		ibuf[n] = ' ';
X
X	n = 0;
X	while (n <= outcount) {
X		*op++ = SIXB(ip[0]) << 2 | SIXB(ip[1]) >> 4;
X		*op++ = SIXB(ip[1]) << 4 | SIXB(ip[2]) >> 2;
X		*op++ = SIXB(ip[2]) << 6 | SIXB(ip[3]);
X		ip += 4;
X		n += 3;
X	}
X
X	for (n = 1; n <= outcount; n++)
X		comp_c_crc(obuf[n]);
X
X	fwrite(obuf + 1, 1, outcount, outf);
X	return outcount;
X}
X
Xhex_to_bin(ibuf, outf)
X	char            ibuf[];
XFILE           *outf;
X{
X	register char  *ip = ibuf;
X	register int    n, outcount;
X	int             c;
X
X	n = strlen(ibuf) - 1;
X	outcount = n / 2;
X	for (n = 0; n < outcount; n++) {
X		c = hexit(*ip++);
X		comp_e_crc(c = (c << 4) | hexit(*ip++));
X		fputc(c, outf);
X	}
X	return outcount;
X}
X
Xhexit(c)
X	int             c;
X{
X	if ('0' <= c && c <= '9')
X		return c - '0';
X	if ('A' <= c && c <= 'F')
X		return c - 'A' + 10;
X
X	fprintf(stderr, "illegal hex digit: %c", c);
X	exit(4);
X	/* NOTREACHED */
X}
X
Xput2(bp, value)
X	char           *bp;
X	short           value;
X{
X	*bp++ = (value >> 8) & BYTEMASK;
X	*bp++ = value & BYTEMASK;
X}
X
Xput4(bp, value)
X	char           *bp;
X	long            value;
X{
X	register int    i, c;
X
X	for (i = 0; i < 4; i++) {
X		c = (value >> 24) & BYTEMASK;
X		value <<= 8;
X		*bp++ = c;
X	}
X}
!Funky!Stuff!
echo x - xbinary
sed -e 's/^X//' > xbinary << '!Funky!Stuff!'
X#!/bin/csh
X# Shell script for always running xbin in MacBinary mode.  Make this
X# executable and put it in your search path.
Xxbin -b $*
!Funky!Stuff!
exit

