twb@rolex.UUCP (Tom Bereiter) (12/07/88)
[StuffIt Utility for UN*X]
After seeing several requests for a version of Stuffit for UN*X I thought
I'd post the following:
---
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# README
# Makefile
# sit.h
# sit.c
# updcrc.c
# macbinfilt.c
# This archive created: Tue Dec 6 07:45:06 1988
# By: Roger L. Long (bytebug@dhw68k.cts.com)
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(1209 characters)'
if test -f 'README'
then
echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThis shar file contains the source to "sit" a UNIX utility which produces
XStuffit archives for downloading to the mac. As a bonus I've also included
X"macbinfilt", a filter which takes articles from comp.binaries.mac, puts the
Xparts in the correct order, and throws out all the "noise" lines.
X
XTo use the sit code you need the getopt(3) library routine and the compress(1)
Xutility, both of which most everyone seems to have by now.
X
XThere is not much original code here: everything is reverse engineered from
Xthe unsit utility by Alan Weber. The updcrc.c file is exactly the same file
Xfrom the unsit package.
X
XI've tested the code on both BSD and SYSV machines. Both machines were big
Xendian so byte order problems may still be lurking.
X
XWhen you transfer archives to your mac be sure to use "binary" mode. In
Xorder for Suffit to recognize your downloaded file it must have a type of
X"SIT!". If your communication program doesn't allow you to specify the type
Xyou'll need to ResEdit it in. It should be quite simple to modify sit.c
Xto put a MacBinary header on the archive.
X
XAs with everything in the modern world: use at your own risk.
X
X--Tom Bereiter
X ..!{rutgers,ames}!cs.utexas.edu!halley!rolex!twb
SHAR_EOF
if test 1209 -ne "`wc -c < 'README'`"
then
echo shar: error transmitting "'README'" '(should have been 1209 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(67 characters)'
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
Xall: sit macbinfilt
X
Xsit: sit.o updcrc.o
X cc -o sit sit.o updcrc.o
SHAR_EOF
if test 67 -ne "`wc -c < 'Makefile'`"
then
echo shar: error transmitting "'Makefile'" '(should have been 67 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'sit.h'" '(1834 characters)'
if test -f 'sit.h'
then
echo shar: will not over-write existing file "'sit.h'"
else
sed 's/^X//' << \SHAR_EOF > 'sit.h'
X
X/* sit.h: contains declarations for SIT headers */
X
Xtypedef struct sitHdr { /* 22 bytes */
X u_char sig1[4]; /* = 'SIT!' -- for verification */
X u_char numFiles[2]; /* number of files in archive */
X u_char arcLen[4]; /* length of entire archive incl. */
X u_char sig2[4]; /* = 'rLau' -- for verification */
X u_char version; /* version number */
X char reserved[7];
X};
X
Xtypedef struct fileHdr { /* 112 bytes */
X u_char compRMethod; /* rsrc fork compression method */
X u_char compDMethod; /* data fork compression method */
X u_char fName[64]; /* a STR63 */
X char fType[4]; /* file type */
X char fCreator[4]; /* creator... */
X char FndrFlags[2]; /* copy of Finder flags */
X char cDate[4]; /* creation date */
X char mDate[4]; /* !restored-compat w/backup prgms */
X u_char rLen[4]; /* decom rsrc length */
X u_char dLen[4]; /* decomp data length */
X u_char cRLen[4]; /* compressed lengths */
X u_char cDLen[4];
X u_char rsrcCRC[2]; /* crc of rsrc fork */
X u_char dataCRC[2]; /* crc of data fork */
X char reserved[6];
X u_char hdrCRC[2]; /* crc of file header */
X};
X
X/* file format is:
X sitArchiveHdr
X file1Hdr
X file1RsrcFork
X file1DataFork
X file2Hdr
X file2RsrcFork
X file2DataFork
X .
X .
X .
X fileNHdr
X fileNRsrcFork
X fileNDataFork
X*/
X
X
X
X/* compression methods */
X#define noComp 0 /* just read each byte and write it to archive */
X#define repComp 1 /* RLE compression */
X#define lpzComp 2 /* LZW compression */
X#define hufComp 3 /* Huffman compression */
X
X/* all other numbers are reserved */
X
X/*
X * the format of a *.info file made by xbin
X */
Xstruct infohdr {
X char res0;
X char name[64]; /* 2 (a str 63) */
X char type[4]; /* 65 */
X char creator[4]; /* 69 */
X char flag[2]; /* 73 */
X char res1[8];
X char dlen[4]; /* 83 */
X char rlen[4]; /* 87 */
X char ctime[4]; /* 91 */
X char mtime[4]; /* 95 */
X};
SHAR_EOF
if test 1834 -ne "`wc -c < 'sit.h'`"
then
echo shar: error transmitting "'sit.h'" '(should have been 1834 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'sit.c'" '(6063 characters)'
if test -f 'sit.c'
then
echo shar: will not over-write existing file "'sit.c'"
else
sed 's/^X//' << \SHAR_EOF > 'sit.c'
X/*
X * sit - Stuffit for UNIX
X * Puts unix data files into stuffit archive suitable for downloading
X * to a Mac. Automatically processes files output from xbin.
X *
X * Reverse engineered from unsit by Allan G. Weber, which was based on
X * macput, which was based on ...
X * Just like unsit this uses the host's version of compress to do the work.
X *
X * Examples:
X * 1) take collection of UNIX text files and make them LSC text files
X * when uncompressed on the mac:
X * sit -u -T TEXT -C KAHL file ...
X * 2) Process output from xbin:
X * xbin file1 (produces FileOne.{info,rsrc,data})
X * sit file1
X *
X * Tom Bereiter
X * ..!{rutgers,ames}!cs.utexas.edu!halley!rolex!twb
X */
X#define BSD
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include "sit.h"
X#ifdef BSD
X#include <sys/time.h>
X#include <sys/timeb.h>
X#else
X#include <time.h>
Xextern long timezone;
X#endif
X
X#ifndef min
X#define min(a,b) ((a)<(b)?(a):(b))
X#endif
X
X/* Mac time of 00:00:00 GMT, Jan 1, 1970 */
X#define TIMEDIFF 0x7c25b080
X
Xstruct sitHdr sh;
Xstruct fileHdr fh;
X
Xchar buf[BUFSIZ];
Xchar *defoutfile = "archive.sit";
Xint ofd;
Xushort crc;
Xint clen;
Xint rmfiles;
Xint unixf;
Xchar *Creator, *Type;
X
Xusage() { fprintf(stderr,"Usage: sit file\n"); }
Xextern char *optarg;
Xextern int optind;
X
Xmain(argc,argv) char **argv; {
X int i,n;
X int total, nfiles;
X int c;
X
X while ((c=getopt(argc, argv, "ro:uC:T:")) != EOF)
X switch (c) {
X case 'r':
X rmfiles++; /* remove files when done */
X break;
X case 'o': /* specify output file */
X defoutfile = optarg;
X break;
X case 'u': /* unix file -- change '\n' to '\r' */
X unixf++;
X break;
X case 'C': /* set Mac creator */
X Creator = optarg;
X break;
X case 'T': /* set Mac file type */
X Type = optarg;
X break;
X case '?':
X usage();
X exit(1);
X }
X
X if ((ofd=creat(defoutfile,0644))<0) {
X perror(defoutfile);
X exit(1);
X }
X /* empty header, will seek back and fill in later */
X write(ofd,&sh,sizeof sh);
X
X for (i=optind; i<argc; i++) {
X n = put_file(argv[i]);
X if (n) {
X total += n;
X nfiles++;
X }
X }
X lseek(ofd,0,0);
X
X total += sizeof(sh);
X /* header header */
X strncpy(sh.sig1,"SIT!",4);
X cp2(nfiles,sh.numFiles);
X cp4(total,sh.arcLen);
X strncpy(sh.sig2,"rLau",4);
X sh.version = 1;
X
X write(ofd,&sh,sizeof sh);
X}
X
Xput_file(name)
Xchar name[];
X{
X struct stat st;
X struct infohdr ih;
X int i,n,fd;
X long fpos1, fpos2;
X char nbuf[256], *p;
X int fork=0;
X long tdiff;
X struct tm *tp;
X#ifdef BSD
X struct timeb tbuf;
X#else
X long bs;
X#endif
X
X fpos1 = lseek(ofd,0,1); /* remember where we are */
X /* write empty header, will seek back and fill in later */
X bzero(&fh,sizeof fh);
X write(ofd,&fh,sizeof fh);
X
X /* look for resource fork */
X strcpy(nbuf,name);
X strcat(nbuf,".rsrc");
X if (stat(nbuf,&st)>=0 && st.st_size) { /* resource fork exists */
X dofork(nbuf);
X cp4(st.st_size,fh.rLen);
X cp4(clen,fh.cRLen);
X cp2(crc,fh.rsrcCRC);
X fh.compRMethod = lpzComp;
X fork++;
X }
X if (rmfiles) unlink(nbuf); /* ignore errors */
X
X /* look for data fork */
X st.st_size = 0;
X strcpy(nbuf,name);
X if (stat(nbuf,&st)<0) { /* first try plain name */
X strcat(nbuf,".data");
X stat(nbuf,&st);
X }
X if (st.st_size) { /* data fork exists */
X dofork(nbuf);
X cp4(st.st_size,fh.dLen);
X cp4(clen,fh.cDLen);
X cp2(crc,fh.dataCRC);
X fh.compDMethod = lpzComp;
X fork++;
X }
X if (fork == 0) {
X fprintf(stderr,"%s: no data or resource files\n",name);
X return 0;
X }
X if (rmfiles) unlink(nbuf); /* ignore errors */
X
X /* look for .info file */
X strcpy(nbuf,name);
X strcat(nbuf,".info");
X if ((fd=open(nbuf,0))>=0 && read(fd,&ih,sizeof(ih))==sizeof(ih)) {
X strncpy(fh.fName, ih.name,64);
X strncpy(fh.fType, ih.type, 4);
X strncpy(fh.fCreator, ih.creator, 4);
X strncpy(fh.FndrFlags, ih.flag, 2);
X strncpy(fh.cDate, ih.ctime, 4);
X strncpy(fh.mDate, ih.mtime, 4);
X }
X else { /* no info file so fake it */
X strncpy(&fh.fName[1], name,63); fh.fName[0] = min(strlen(name),63);
X /* default to LSC text file */
X strncpy(fh.fType, Type ? Type : "TEXT", 4);
X strncpy(fh.fCreator, Creator ? Creator : "KAHL", 4);
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 cp4(st.st_ctime + tdiff, fh.cDate);
X cp4(st.st_mtime + tdiff, fh.mDate);
X }
X close(fd);
X if (rmfiles) unlink(nbuf); /* ignore errors */
X
X crc = updcrc(0,&fh,(sizeof fh)-2);
X cp2(crc, fh.hdrCRC);
X
X fpos2 = lseek(ofd,0,1); /* remember where we are */
X lseek(ofd,fpos1,0); /* seek back over file(s) and header */
X write(ofd,&fh,sizeof fh); /* write back header */
X fpos2=lseek(ofd,fpos2,0); /* seek forward file */
X
X return (fpos2 - fpos1);
X}
X
Xdofork(name)
Xchar name[];
X{
X FILE *fs;
X int n, fd, ufd;
X char *p;
X
X if ((fd=open(name,0))<0) {
X perror(name);
X return 0;
X }
X if (unixf) /* build conversion file */
X if ((ufd=creat("sit+temp",0644))<0) {
X perror("sit+temp");
X return 0;
X }
X /* do crc of file: */
X crc = 0;
X while ((n=read(fd,buf,BUFSIZ))>0) {
X if (unixf) { /* convert '\n' to '\r' */
X for (p=buf; p<&buf[n]; p++)
X if (*p == '\n') *p = '\r';
X write(ufd,buf,n);
X }
X crc = updcrc(crc,buf,n);
X }
X close(fd);
X /*
X * open pipe to compress file
X * If a unix file ('\n' -> '\r' conversion) 'sit+temp' will be a new copy
X * with the conversion done. Otherwise, 'sit+temp' is just a link to
X * the input file.
X */
X if (unixf)
X close(ufd);
X else link(name,"sit+temp");
X fs = popen("compress -c -n -b 14 sit+temp","r");
X if (fs == NULL) {
X perror(name);
X return 0;
X }
X /* write out compressed file */
X clen = 0;
X while ((n=fread(buf,1,BUFSIZ,fs))>0) {
X write(ofd,buf,n);
X clen += n;
X }
X pclose(fs);
X unlink("sit+temp");
X}
X
Xcp2(x,dest)
Xunsigned short x;
Xchar dest[];
X{
X dest[0] = x>>8;
X dest[1] = x;
X}
X
Xcp4(x,dest)
Xunsigned long x;
Xchar dest[];
X{
X dest[0] = x>>24;
X dest[1] = x>>16;
X dest[2] = x>>8;
X dest[3] = x;
X}
SHAR_EOF
if test 6063 -ne "`wc -c < 'sit.c'`"
then
echo shar: error transmitting "'sit.c'" '(should have been 6063 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'updcrc.c'" '(5848 characters)'
if test -f 'updcrc.c'
then
echo shar: will not over-write existing file "'updcrc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'updcrc.c'
X/* updcrc(3), crc(1) - calculate crc polynomials
X *
X * Calculate, intelligently, the CRC of a dataset incrementally given a
X * buffer full at a time.
X *
X * Usage:
X * newcrc = updcrc( oldcrc, bufadr, buflen )
X * unsigned int oldcrc, buflen;
X * char *bufadr;
X *
X * Compiling with -DTEST creates a program to print the CRC of stdin to stdout.
X * Compile with -DMAKETAB to print values for crctab to stdout. If you change
X * the CRC polynomial parameters, be sure to do this and change
X * crctab's initial value.
X *
X * Notes:
X * Regards the data stream as an integer whose MSB is the MSB of the first
X * byte recieved. This number is 'divided' (using xor instead of subtraction)
X * by the crc-polynomial P.
X * XMODEM does things a little differently, essentially treating the LSB of
X * the first data byte as the MSB of the integer. Define SWAPPED to make
X * things behave in this manner.
X *
X * Author: Mark G. Mendel, 7/86
X * UUCP: ihnp4!umn-cs!hyper!mark, GEnie: mgm
X */
X
X/* The CRC polynomial.
X * These 4 values define the crc-polynomial.
X * If you change them, you must change crctab[]'s initial value to what is
X * printed by initcrctab() [see 'compile with -DMAKETAB' above].
X */
X /* Value used by: CITT XMODEM ARC */
X#define P 0xA001 /* the poly: 0x1021 0x1021 A001 */
X#define INIT_CRC 0L /* init value: -1 0 0 */
X#define SWAPPED /* bit order: undef defined defined */
X#define W 16 /* bits in CRC:16 16 16 */
X
X /* data type that holds a W-bit unsigned integer */
X#if W <= 16
X# define WTYPE unsigned short
X#else
X# define WTYPE unsigned long
X#endif
X
X /* the number of bits per char: don't change it. */
X#define B 8
X
Xstatic WTYPE crctab[1<<B] = /* as calculated by initcrctab() */ {
X0x0, 0xc0c1, 0xc181, 0x140, 0xc301, 0x3c0, 0x280, 0xc241,
X0xc601, 0x6c0, 0x780, 0xc741, 0x500, 0xc5c1, 0xc481, 0x440,
X0xcc01, 0xcc0, 0xd80, 0xcd41, 0xf00, 0xcfc1, 0xce81, 0xe40,
X0xa00, 0xcac1, 0xcb81, 0xb40, 0xc901, 0x9c0, 0x880, 0xc841,
X0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
X0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
X0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
X0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
X0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
X0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
X0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
X0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
X0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
X0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
X0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
X0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
X0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
X0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
X0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
X0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
X0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
X0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
X0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
X0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
X0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
X0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
X0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
X0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
X0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
X0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
X0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
X0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
X} ;
X
XWTYPE
Xupdcrc( icrc, icp, icnt )
X WTYPE icrc;
X unsigned char *icp;
X int icnt;
X{
X register WTYPE crc = icrc;
X register unsigned char *cp = icp;
X register int cnt = icnt;
X
X while( cnt-- ) {
X#ifndef SWAPPED
X crc = (crc<<B) ^ crctab[(crc>>(W-B)) ^ *cp++];
X#else
X crc = (crc>>B) ^ crctab[(crc & ((1<<B)-1)) ^ *cp++];
X#endif SWAPPED
X }
X
X return( crc );
X}
X
X#ifdef MAKETAB
X
X#include <stdio.h>
Xmain()
X{
X initcrctab();
X}
X
Xinitcrctab()
X{
X register int b, i;
X WTYPE v;
X
X
X for( b = 0; b <= (1<<B)-1; ++b ) {
X#ifndef SWAPPED
X for( v = b<<(W-B), i = B; --i >= 0; )
X v = v & ((WTYPE)1<<(W-1)) ? (v<<1)^P : v<<1;
X#else
X for( v = b, i = B; --i >= 0; )
X v = v & 1 ? (v>>1)^P : v>>1;
X#endif
X crctab[b] = v;
X
X printf( "0x%lx,", v & ((1L<<W)-1L));
X if( (b&7) == 7 )
X printf("\n" );
X else
X printf(" ");
X }
X}
X#endif
X
X#ifdef TEST
X
X#include <stdio.h>
X#include <fcntl.h>
X
X#define MAXBUF 4096
X
X
X
Xmain( ac, av )
X int ac; char **av;
X{
X int fd;
X int nr;
X int i;
X char buf[MAXBUF];
X WTYPE crc, crc2;
X
X fd = 0;
X if( ac > 1 )
X if( (fd = open( av[1], O_RDONLY )) < 0 ) {
X perror( av[1] );
X exit( -1 );
X }
X crc = crc2 = INIT_CRC;
X
X while( (nr = read( fd, buf, MAXBUF )) > 0 ) {
X crc = updcrc( crc, buf, nr );
X }
X
X if( nr != 0 )
X perror( "reading" );
X else {
X printf( "%lx\n", crc );
X }
X
X#ifdef MAGICCHECK
X /* tack one's complement of crc onto data stream, and
X continue crc calculation. Should get a constant (magic number)
X dependent only on P, not the data.
X */
X crc2 = crc ^ -1L;
X for( nr = W-B; nr >= 0; nr -= B ) {
X buf[0] = (crc2 >> nr);
X crc = updcrc(crc, buf, 1);
X }
X
X /* crc should now equal magic */
X buf[0] = buf[1] = buf[2] = buf[3] = 0;
X printf( "magic test: %lx =?= %lx\n", crc, updcrc(-1, buf, W/B));
X#endif MAGICCHECK
X}
X
X#endif
SHAR_EOF
if test 5848 -ne "`wc -c < 'updcrc.c'`"
then
echo shar: error transmitting "'updcrc.c'" '(should have been 5848 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'macbinfilt.c'" '(3638 characters)'
if test -f 'macbinfilt.c'
then
echo shar: will not over-write existing file "'macbinfilt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'macbinfilt.c'
X/*
X * macbinfilt -- filters usenet articles from comp.binaries.mac into a form
X * suitable for xbin to decode. Will rearange parts of file if they are not
X * in order. Strips out all extraneous lines.
X * Does all of this by making many bold assumtions--but it's worked so far.
X *
X * Only works on one article at a time. All files on the input line are
X * considered parts of the same article.
X *
X * If you have the sysV regualar expression routines (regcmp, regex) then
X * define HAVE_REGCMP for a more robust pattern match.
X *
X * --Tom Bereiter
X * ..!{rutgers,ames}!cs.utexas.edu!halley!rolex!twb
X */
X#include <stdio.h>
X
Xint cur_part,part,divert_part;
Xint max_part;
X#define IBUFSZ 512
Xchar ibuf[IBUFSZ];
Xchar pname[80];
XFILE *ofs=stdout;
XFILE *saveofs;
XFILE *parts[100];
X
X#ifdef HAVE_REGCMP
X#define EXP ".*[Pp][Aa][Rr][Tt][ \t]*([0-9]+)$0[ \t]*[Oo][Ff][ \t]*([0-9]+)$1"
X#else
X#define EXP "part %d of %d"
X#endif
Xchar *exp;
X
Xmain(argc,argv) char **argv[]; {
X FILE *fs;
X int i,rc=0;
X
X#ifdef HAVE_REGCMP
X exp = (char *)regcmp(EXP,0);
X#else
X exp = EXP;
X#endif
X
X fputs("(This file must be converted with BinHex 4.0)\n\n",ofs);
X
X if (argc == 1)
X filter(stdin);
X else while (--argc) {
X if ((fs=fopen(*++argv,"r"))==NULL) {
X perror(*argv); exit(-1); }
X filter(fs);
X fclose(fs);
X }
X /* add any remaining parts */
X for (i=cur_part+1; i<=max_part; i++)
X if (parts[i])
X putpart(i);
X else {
X fprintf(stderr,"Missing part %d\n",i);
X rc = -1;
X }
X exit(rc);
X}
X
X/* valid xbin chars + '\n' and '\r' */
X#define Btst(i) (bmap[i>>3] & (1<<(i&07)))
Xchar bmap[]={0x00,0x24,0x00,0x00,0xfe,0x3f,0x7f,0x07,
X 0xff,0x7f,0x7f,0x0f,0x7f,0x3f,0x07,0x00};
X
X/* filter out extraneous lines and look for lines of the form:
X * part n of m
X * A line is considered valid if it has only valid xbin characters and is
X * either greater than 60 characters or ends in a ':'
X */
X
Xfilter(fs) FILE *fs; {
X register char *p,*inp;
X
Xreget:
X while ((inp=fgets(ibuf,IBUFSZ,fs))) {
X for (p=inp; *p; p++)
X if (Btst(*p) == 0) { /* invalid character */
X checkparts(inp);
X goto reget;
X }
X if (p-inp > 60 || inp[(p-inp)-2]==':') /* arbitrary max or end */
X fputs(ibuf,ofs);
X }
X if (divert_part) /* diversion in progress */
X end_oseq();
X}
X
Xcheckparts(str) char *str; {
X char *p;
X char num0[40], num1[40];
X
X#ifdef HAVE_REGEXP
X if (regex(exp, str, num0,num1)!=NULL) {
X part = atoi(num0);
X max_part = atoi(num1);
Xfprintf(stderr,"part %d of %d\n",part,max_part);
X dopart();
X }
X#else
X for (p=str; *p; p++) /* rescan for 'part' string */
X if (*p==exp[0])
X if (sscanf(p,exp,&part,&max_part) == 2) {
X dopart();
X break;
X }
X#endif
X}
X
Xdopart() {
X if (divert_part) { /* diversion in progress */
X if (part == divert_part) /* another mention of current part */
X return;
X end_oseq();
X }
X if (part == cur_part+1) /* OK: next in sequence */
X cur_part = part;
X else if (part > cur_part) /* out of sequence */
X oseq();
X else /* "can't" happen */
X fprintf(stderr,"Part %d unexpected\n",part);
X}
X
X/* part out of sequence */
Xoseq() {
X int i;
X
X /* try and fill in gap */
X for (i=cur_part+1; i<part; i++)
X if (parts[i]) {
X putpart(i);
X cur_part = i;
X }
X else goto isgap;
X /* all missing parts restored -- continue */
X return;
Xisgap:
X /* start diversion */
X divert_part = part;
X saveofs = ofs;
X sprintf(pname,"part%d",part);
X if ((ofs = fopen(pname,"w+")) == NULL) {
X perror(pname); exit(-1); }
X parts[part] = ofs;
X}
Xend_oseq() {
X divert_part = 0;
X ofs = saveofs;
X}
X
Xputpart(n) {
X FILE *fs;
X register int c;
X
X fs = parts[n];
X rewind(fs);
X while ((c=getc(fs))!=EOF)
X putc(c,ofs);
X fclose(fs);
X sprintf(pname,"part%d",n);
X unlink(pname);
X}
SHAR_EOF
if test 3638 -ne "`wc -c < 'macbinfilt.c'`"
then
echo shar: error transmitting "'macbinfilt.c'" '(should have been 3638 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
---