Date: Mon, 21 Jan 91 15:07:27 -0600 From: Rob Elliott #! /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