Path: utzoo!utgpu!watmath!clyde!att!ucbvax!hplabs!felix!dhw68k!macintosh
From: twb@rolex.UUCP (Tom Bereiter)
Newsgroups: comp.sources.mac
Subject: StuffIt Utility for UN*X
Message-ID: <16553@dhw68k.cts.com>
Date: 6 Dec 88 16:30:45 GMT
Sender: macintosh@dhw68k.cts.com
Organization: Tandem Computers, Austin, TX
Lines: 837
Approved: bytebug@dhw68k.cts.com (Roger L. Long)
[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
X#include
X#include
X#include "sit.h"
X#ifdef BSD
X#include
X#include
X#else
X#include
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=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<>(W-B)) ^ *cp++];
X#else
X crc = (crc>>B) ^ crctab[(crc & ((1<
Xmain()
X{
X initcrctab();
X}
X
Xinitcrctab()
X{
X register int b, i;
X WTYPE v;
X
X
X for( b = 0; b <= (1<= 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<
X#include
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
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