🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.sources.mac
Article #47

Tar 1.1 Source (part 3 of 3)

#47
From: Craig Ruff
Date: Sat, 14 May 1988 06:57
1393 lines
31868 bytes
[Tar 1.1 Source - part 3 of 3]

---
#! /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:
#	extract.c
#	list.c
#	menu.c
#	window.c
# This archive created: Wed May 11 07:24:07 1988
# By:	Roger L. Long (bytebug@dhw68k.cts.com)
export PATH; PATH=/bin:$PATH
echo shar: extracting "'extract.c'" '(7771 characters)'
if test -f 'extract.c'
then
	echo shar: will not over-write existing file "'extract.c'"
else
sed 's/^X//' << \SHAR_EOF > 'extract.c'
X/*
X * Macintosh Tar
X *
X * Modified by Craig Ruff for use on the Macintosh.
X */
X/*
X * Extract files from a tar archive.
X *
X * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
X *
X * @(#) extract.c 1.17 86/10/29 Public Domain - gnu
X */
X#include "tar.h"
X
Xextern union record	*head;		/* Points to current tape header */
Xextern struct stat {
X	long	st_size;
X	long	st_mtime;
X} hstat;				/* Fake stat struct for compat. */
X
Xvoid ExtractArchive();
Xextern void PrintHeader();
Xextern void SkipFile();
X
Xint MakeDirs();			/* Makes required directories */
X
X/*
X * Extract - extract the entire archive
X */
XExtract() {
X	Point		where;
X	SFReply		reply;
X	WDPBRec		wdpb;
X
X	/*
X	 * Use the standard file dialog to select the archive.
X	 */
X	where.h = where.v = 75;
X	SFGetFile(pass(where), "\PSelect TAR file", NIL, 0, NIL, NIL, &reply);
X	if (!reply.good)
X		return;
X
X	/*
X	 * Remember the VRefNum and Name for OpenArchive.
X	 * Find out where to put the extracted files.
X	 */
X	arVRefNum = reply.vRefNum;
X	arName = reply.fName;
X	if (GetDir("\Pto put extracted files") == FALSE)
X		return;
X
X	/*
X	 * Open the target directory as a base to put everything.
X	 */
X	wdpb.ioCompletion = NIL;
X	wdpb.ioNamePtr = NIL;
X	wdpb.ioVRefNum = dirVRefNum;
X	wdpb.ioWDProcID = 'TAR ';
X	wdpb.ioWDDirID = dirDirID;
X	if (PBOpenWD(&wdpb, FALSE) != noErr) {
X		OSAlert("\PExtract", "\PPBOpenWD", NIL, wdpb.ioResult);
X		return;
X	}
X
X	/*
X	 * Extract and print the files as found in the archive.
X	 */
X	dirVRefNum = wdpb.ioVRefNum;
X	if (WindInit())
X		goto done;
X
X	TextFace(underlineStyle);
X	WPrintf(header);
X	TextFace(0);
X
X	if (setjmp(errJmp) == 0)
X		ReadAnd(ExtractArchive);
X	else
X		CloseArchive();
X
X	WindEnd(autoPage);
Xdone:
X	(void) PBCloseWD(&wdpb, FALSE);
X}
X
X/*
X * Extract a file from the archive.
X */
Xvoid
XExtractArchive()
X{
X	register char	*data;
X	register char	*p;
X	CInfoPBRec	pb;
X	HPrmBlkRec	dpb;
X	HPrmBlkRec	fpb;
X	int	fd, i, namelen;
X	long	check, written;
X	long	size;
X	OSErr	err;
X	char	macName[256];
X	char	*routine = "\PExtractArchive";
X
X	SaveRec(&head);			/* Make sure it sticks around */
X	UseRec(head);			/* And go past it in the archive */
X	DecodeHeader(head, &hstat, 1);	/* Snarf fields */
X
X	/* Print the record from 'head' and 'hstat' */
X	PrintHeader();
X
X	switch (head->header.linkflag) {
X	default:
X		WPrintf("Unknown file type %d for %s",
X			head->header.linkflag, head->header.name);
X		break;
X
X	case LF_OLDNORMAL:
X	case LF_NORMAL:
X		/*
X		 * Appears to be a file.
X		 * See if it's really a directory.
X		 */
X		namelen = strlen(head->header.name) - 1;
X		if (head->header.name[namelen] == '/')
X			goto really_dir;
X
X		FixName(head->header.name, macName);
X	again_file:
X		fpb.ioCompletion = NIL;
X		fpb.ioNamePtr = macName;
X		fpb.ioVRefNum = dirVRefNum;
X		fpb.u.hfp.ioDirID = 0;
X		err = PBHCreate(&fpb, FALSE);
X		if (err == noErr) {
X			fpb.ioCompletion = NIL;
X			fpb.ioNamePtr = macName;
X			fpb.ioVRefNum = dirVRefNum;
X			fpb.u.hfp.ioDirID = 0;
X			fpb.u.hfp.ioFDirIndex = 0;
X			if (PBHGetFInfo(&fpb, FALSE)) {
X				OSAlert(routine, "\PPBHGetFInfo", NIL, fpb.ioResult);
X				goto doNext;
X			}
X
X			strncpy(&fpb.u.hfp.ioFlFndrInfo.fdCreator, fdCreator, 4);
X			strncpy(&fpb.u.hfp.ioFlFndrInfo.fdType, fdType, 4);
X			fpb.ioCompletion = NIL;
X			fpb.ioNamePtr = macName;
X			fpb.ioVRefNum = dirVRefNum;
X			fpb.u.hfp.ioDirID = 0;
X			if (PBHSetFInfo(&fpb, FALSE)) {
X				OSAlert(routine, "\PPBHSetFInfo", NIL, fpb.ioResult);
X				goto doNext;
X			}
X
X			fpb.u.iop.ioPermssn = fsWrPerm;
X			fpb.u.iop.ioMisc = NIL;
X			err = PBHOpen(&fpb, FALSE);
X		}
X
X		if (err != noErr) {
X			if (MakeDirs(macName))
X				goto again_file;
X
X			PgmAlert(routine, "\PCould not make file", macName, NIL);
X			SkipFile((long)hstat.st_size);
X			break;
X		}
X
X		/*
X		 * Note that this only extracts data forks!
X		 */
X		for (size = hstat.st_size;
X		     size > 0;
X		     size -= written) {
X			/*
X			 * Locate data, determine max length
X			 * writeable, write it, record that
X			 * we have used the data, then check
X			 * if the write worked.
X			 */
X			data = FindRec()->charptr;
X			written = EndOfRecs()->charptr - data;
X			if (written > size)
X				written = size;
X
X			/*
X			 * Convert newlines to return for Mac compatability.
X			 */
X			if (cvtNl) {
X				for (i = written, p = data; --i >= 0; p++)
X					if (*p == '\n')
X						*p = '\r';
X			}
X
X			check = written;
X			fpb.u.iop.ioBuffer = data;
X			fpb.u.iop.ioReqCount = check;
X			fpb.u.iop.ioPosMode = fsAtMark;
X			fpb.u.iop.ioPosOffset = 0;
X			err = PBWrite(&fpb, FALSE);
X			if (err != noErr) {
X				OSAlert(routine, "\PPBWrite", NIL, err);
X				goto doNext;
X			}
X
X			check = fpb.u.iop.ioActCount;
X			/*
X			 * The following is in violation of strict
X			 * typing, since the arg to userec
X			 * should be a struct rec *.  FIXME.
X			 */
X			UseRec(data + written - 1);
X			if (check == written) continue;
X			/*
X			 * Error in writing to file.
X			 * Print it, skip to next file in archive.
X			 */
X			PgmAlert(routine, "\PWrite short", NIL, NIL);
X		doNext:
X			PBClose(&fpb, FALSE);
X			SkipFile((long)(size - written));
X			goto quit;
X		}
X
X		PBClose(&fpb, FALSE);
X	quit:
X		break;
X
X	case LF_DIR:
X		/* Check for trailing / */
X		namelen = strlen(head->header.name)-1;
X	really_dir:
X		while (namelen && head->header.name[namelen] == '/')
X			head->header.name[namelen--] = '\0';	/* Zap / */
X		
X		FixName(head->header.name, macName);
X		/* FALL THROUGH */
X	again_dir:
X		dpb.ioCompletion = NIL;
X		dpb.ioNamePtr = macName;
X		dpb.ioVRefNum = dirVRefNum;
X		dpb.u.hfp.ioDirID = 0;
X		err = PBDirCreate(&dpb, FALSE);
X		if ((err != noErr) && (err != dupFNErr)) {
X			if (MakeDirs(macName))
X				goto again_dir;
X
X			PgmAlert(routine, "\PCould not make directory",
X					macName, NIL);
X		}
X		break;
X
X	}
X
X	/* We don't need to save it any longer. */
X	SaveRec((union record **) 0);	/* Unsave it */
X}
X
X/*
X * After a file/link/symlink/dir creation has failed, see if
X * it's because some required directory was not present, and if
X * so, create all required dirs.
X */
Xint
XMakeDirs(pathname)
Xchar *pathname;
X{
X	int	madeone = 0;		/* Did we do anything yet? */
X	int	i, savedLen;
X	OSErr	err;
X	HPrmBlkRec	pb;
X
X	savedLen = pathname[0] & 0xff;
X	/*
X	 * skip initial ':'
X	 *
X	 * Note that the directory name has already been converted to Mac style.
X	 */
X	for (i = 2; i < savedLen; i++) {
X		while ((i < savedLen) && (pathname[i] != ':'))
X			i++;
X
X		if (i == savedLen)
X			break;
X
X		pathname[0] = i++ - 1;
X		pb.ioCompletion = NIL;
X		pb.ioNamePtr = pathname;
X		pb.ioVRefNum = dirVRefNum;
X		pb.u.hfp.ioDirID = 0;
X		err = PBDirCreate(&pb, FALSE);
X		if (err == dupFNErr) {
X			continue;
X
X		} else if (err != noErr) {
X			OSAlert("\PMakeDirs", "\PPBDirCreate", pathname,
X					pb.ioResult);
X			return(0);
X
X		} else {
X			madeone++;		/* Remember if we made one */
X			continue;
X		}
X	}
X
X	pathname[0] = savedLen;
X	return(madeone);		/* Tell them to retry if we made one */
X}
X
X/*
X * FixName - convert to a Mac style pathname
X *
X *	Conversions:
X *		.	->		(Stay at this directory level)
X *		..	-> ::		(Up a directory level)
X *		.xxxx	-> _xxxx	(Don't get in trouble with device names)
X *		xx:xx	-> xx/xx	(Don't get in trouble with directory delims)
X */
XFixName(tar, mac)
Xregister char	*tar;
Xchar	*mac;
X{
X	char		*end = tar + strlen(tar);
X	register char	*p = mac + 1;
X	register char	*next;
X
X	for (next = tar; tar < end; next++) {
X		/*
X		 * Swallow up all contiguous '/' characters.
X		 */
X		while (*next && (*next == '/'))
X			next++;
X
X		/*
X		 * Find the entire name up until the next '/'.
X		 */
X		tar = next;
X		while (*next && (*next != '/'))
X			next++;
X
X		*next = 0;
X		*p++ = ':';
X		if (*tar == '.')
X			switch (*(tar + 1)) {
X			case '\0':
X				p--;
X				continue;
X
X			case '.':
X				if (*(tar + 2) == 0)
X					continue;
X				/* else FALL THROUGH */
X
X			default:
X				*tar = '_';
X			}
X
X		while (tar < next) {
X			if (*tar == ':')
X				*tar = '/';
X			*p++ = *tar++;
X		}
X	}
X
X	*mac = p - mac - 1;
X}
SHAR_EOF
if test 7771 -ne "`wc -c < 'extract.c'`"
then
	echo shar: error transmitting "'extract.c'" '(should have been 7771 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'list.c'" '(7209 characters)'
if test -f 'list.c'
then
	echo shar: will not over-write existing file "'list.c'"
else
sed 's/^X//' << \SHAR_EOF > 'list.c'
X/*
X * Macintosh Tar
X *
X * Modified by Craig Ruff for use on the Macintosh.
X */
X/*
X * List a tar archive.
X *
X * Also includes support routines for reading a tar archive.
X *
X * Pubic Domain version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu).
X *
X * @(#)list.c 1.18 9/23/86 Public Domain - gnu
X */
X#include "tar.h"
X
Xchar *ctime();				/* From libc.a */
X
X#define	isodigit(c)	( ((c) >= '0') && ((c) <= '7') )
X#define isspace(c)	((c) == ' ')
X
Xlong FromOct();			/* Decode octal number */
X
Xunion record *head;		/* Points to current archive header */
Xstruct stat {
X	long	st_size;
X	long	st_mtime;
X} hstat;			/* Fake stat struct for compat. */
X
Xvoid ListArchive();
Xvoid PrintHeader();
Xvoid ReadAnd();
Xvoid SkipFile();
X
X/*
X * List - list an archive file
X */
XList() {
X	Point		where;
X	SFReply		reply;
X	Boolean		oldAutoPage = autoPage;
X
X	/*
X	 * Use standard file to get the archive file.
X	 * Always do a screen at a time if to the screen.
X	 */
X	where.h = where.v = 75;
X	SFGetFile(pass(where), "\PName of TAR file:", NIL, -1, NIL, NIL, &reply);
X	if (!reply.good)
X		return;
X
X	arVRefNum = reply.vRefNum;
X	arName = reply.fName;
X	if (WindInit())
X		return;
X
X	autoPage = TRUE;
X	TextFace(underlineStyle);
X	WPrintf(header);
X	TextFace(0);
X
X	if (setjmp(errJmp) == 0)
X		ReadAnd(ListArchive);
X	else
X		CloseArchive();
X
X	WindEnd(TRUE);
X	autoPage = oldAutoPage;
X}
X
X/*
X * Main loop for reading an archive.
X */
Xvoid
XReadAnd(doSomething)
Xvoid (*doSomething)();
X{
X	int 		status = 1;
X	int 		prevStatus;
X	EventRecord	e;
X	CursHandle	cursor;
X
X	if ((cursor = GetCursor(watchCursor)) != NIL)
X		SetCursor(*cursor);
X
X	OpenArchive(1);		/* Open for reading */
X
X	for(;;) {
X		SystemTask();
X		if (EventAvail(keyDownMask, &e) && (e.what != nullEvent)) {
X			if (
X				(e.modifiers & cmdKey) &&
X				((e.message & charCodeMask) == '.')
X			) {
X				GetNextEvent(keyDownMask, &e);
X				break;
X			}
X		}
X
X		prevStatus = status;
X		status = ReadHeader();
X		switch (status) {
X		case 1:			/* Valid header */
X			/* We should decode next field (mode) first... */
X			/* Ensure incoming names are null terminated. */
X			head->header.name[NAMSIZ-1] = '\0';
X			(*doSomething)();
X			continue;
X
X			/*
X			 * If the previous header was good, tell them
X			 * that we are skipping bad ones.
X			 */
X		case 0:			/* Invalid header */
X		case0:
X			UseRec(head);
X			if (prevStatus == 1) {
X				PgmAlert("\PReadAnd",
X						"\PSkipping to next file header...",
X						NIL, NIL);
X			}
X			continue;
X
X		case 2:			/* Block of zeroes */
X			if (ignorez)	
X				goto case0;	/* Just skip if asked */
X			/* FALL THRU */
X		case (int) EOF:		/* End of archive */
X			break;
X		}
X		break;
X	}
X
X	CloseArchive();
X	SetCursor(&arrow);
X}		
X
X
X/*
X * Print a header record, based on tar options.
X */
Xvoid
XListArchive()
X{
X	long t;
X
X	/* Save the record */
X	SaveRec(&head);
X
X	/*
X	 * Print the header record.
X	 * Don't sling the names too fast!
X	 */
X	PrintHeader();
X	if (!autoPage)
X		Delay(60L, &t);
X
X	/* Skip past it in the archive */
X	SaveRec((union record **) 0);	/* Unsave it */
X	UseRec(head);
X
X	/* Skip to the next header on the archive */
X	SkipFile((long)hstat.st_size);
X}
X
X
X/*
X * Read a record that's supposed to be a header record.
X * Return its address in "head", and if it is good, the file's
X * size in hstat.st_size.
X *
X * Return 1 for success, 0 if the checksum is bad, EOF on eof,
X * 2 for a block full of zeros (EOF marker).
X *
X * You must always userec(head) to skip past the header which this
X * routine reads.
X */
Xint
XReadHeader()
X{
X	register int	i;
X	register long	sum, recsum;
X	register char	*p;
X	register union record *header;
X
X	header = FindRec();
X	head = header;		/* This is our current header */
X	if (NIL == header)
X		return(EOF);
X
X	recsum = FromOct(8,  header->header.chksum);
X	sum = 0;
X	p = header->charptr;
X	for (i = sizeof(*header); --i >= 0;) {
X		/*
X		 * We can't use unsigned char here because of old compilers,
X		 * e.g. V7.
X		 */
X		sum += 0xFF & *p++;
X	}
X
X	/* Adjust checksum to count the "chksum" field as blanks. */
X	for (i = sizeof(header->header.chksum); --i >= 0;)
X		sum -= 0xFF & header->header.chksum[i];
X	sum += ' ' * sizeof(header->header.chksum);
X
X	if (sum == recsum) {
X		/*
X		 * Good record.  Decode file size and return.
X		 */
X		hstat.st_size = FromOct(1+12, header->header.size);
X		return(1);
X	}
X
X	if (sum == 8 * ' ') {
X		/*
X		 * This is a zeroed block...whole block is 0's except
X		 * for the 8 blanks we faked for the checksum field.
X		 */
X		return(2);
X	}
X
X	return(0);
X}
X
X/* 
X * Decode things from a file header record into a "struct stat".
X *
X * read_header() has already decoded the checksum and length, so we don't.
X *
X * If wantug != 0, we want the uid/group info decoded from Unix Standard
X * tapes (for extraction).  If == 0, we are just printing anyway, so save time.
X */
XDecodeHeader(header, st, wantug)
Xregister union record	*header;
Xregister struct stat	*st;
Xint	wantug;
X{
X	st->st_mtime = FromOct(1+12, header->header.mtime);
X}
X
X/*
X * Quick and dirty octal conversion.
X *
X * Result is -1 if the field is invalid (all blank, or nonoctal).
X */
Xlong
XFromOct(digs, where)
Xregister int	digs;
Xregister char	*where;
X{
X	register long	value;
X
X	while (isspace(*where)) {		/* Skip spaces */
X		where++;
X		if (--digs <= 0)
X			return(-1);		/* All blank field */
X	}
X
X	value = 0;
X	while (digs > 0 && isodigit(*where)) {	/* Scan til nonoctal */
X		value = (value << 3) | (*where++ - '0');
X		--digs;
X	}
X
X	if (digs > 0 && *where && !isspace(*where))
X		return(-1);			/* Ended on non-space/nul */
X
X	return(value);
X}
X
X/*
X * Actually print it.
X */
X#define	UGSWIDTH	9	/* min width of User, group, size */
X#define	DATEWIDTH	19	/* Last mod date */
Xstatic int ugswidth = UGSWIDTH;	/* Max width encountered so far */
X
Xvoid
XPrintHeader()
X{
X	char mode;
X	char *timestamp;
X	char *user, *group;
X	char size[12];		/* Holds a formatted long */
X	long longie;		/* To make ctime() call portable */
X	int	pad;
X
X	DecodeHeader(head, &hstat, 0);
X	/* File type and mode */
X	mode = '?';
X	switch (head->header.linkflag) {
X	case LF_NORMAL:
X	case LF_OLDNORMAL:
X		mode = 'F'; 
X		if ('/' == head->header.name[strlen(head->header.name)-1])
X			mode = 'D';
X		break;
X
X	case LF_DIR:
X		mode = 'D';
X		break;
X	}
X
X	/* 
X	 * Convert to Mac based time from Unix based time.
X	 */
X	longie = hstat.st_mtime + TIMEDIFF;
X
X	timestamp = ctime(&longie);
X	timestamp[16] = '\0';
X	timestamp[24] = '\0';
X
X	/* Format the file size or major/minor device numbers */
X	switch (head->header.linkflag) {
X	default:
X		(void) sprintf(size, "?????");
X		break;
X
X	case LF_DIR:
X		(void) sprintf(size, "%.*s", UGSWIDTH, "");
X		break;
X
X	case LF_OLDNORMAL:
X	case LF_NORMAL:
X		(void) sprintf(size, "%ld", hstat.st_size);
X		break;
X	}
X
X
X	/* Figure out padding and print the whole line. */
X	pad = strlen(size) + 1;
X	if (pad > ugswidth)
X		ugswidth = pad;
X
X	WPrintf("%c %*s%s %s %s %.*s", mode, ugswidth - pad, "", size,
X		timestamp+4, timestamp+20, sizeof(head->header.name),
X			      head->header.name);
X}
X
X/*
X * Skip over <size> bytes of data in records in the archive.
X */
Xvoid
XSkipFile(size)
Xregister long size;
X{
X	union record *x;
X
X	while (size > 0) {
X		x = FindRec();
X		if (x == NIL) {	/* Check it... */
X			PgmAlert("\PSkipFile", "\PUnexpected EOF on archive file",
X					NIL, NIL);
X			longjmp(errJmp, 1);
X		}
X		UseRec(x);
X		size -= RECORDSIZE;
X	}
X}
SHAR_EOF
if test 7209 -ne "`wc -c < 'list.c'`"
then
	echo shar: error transmitting "'list.c'" '(should have been 7209 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'menu.c'" '(4610 characters)'
if test -f 'menu.c'
then
	echo shar: will not over-write existing file "'menu.c'"
else
sed 's/^X//' << \SHAR_EOF > 'menu.c'
X/*
X * Macintosh Tar
X *
X * Written by Craig Ruff.
X *
X * Menu handling routines.
X */
X
X#include "tar.h"
X#include <resource.h>
X
X/*
X * Resource IDs for menus
X */
X#define appleID		128
X#define fileID		129
X#define editID		130
X#define optionID	131
X
X/*
X * Index for each menu
X */
X#define appleMenu	0
X#define fileMenu	1
X#define editMenu	2
X#define optionMenu	3
X#define menuCount	4
X
X/*
X * Item in Apple Menu
X */
X#define aboutItem	1
X
X/*
X * Items in File Menu
X */
X#define createItem	1		/* Create archive */
X#define extractItem	2		/* Extract archive */
X#define listItem	3		/* List archive */
X#define closeItem	5		/* Close (only for Desk Acc) */
X#define pgsetItem	6		/* Page setup */
X#define quitItem	8
X
X/*
X * Items in Edit Menu
X *
X * For use by Desk Accessories.
X */
X#define undoItem	1
X#define cutItem		3
X#define copyItem	4
X#define pasteItem	5
X#define clearItem	6
X
X/*
X * Items in Options Menu
X */
X#define convertItem	1		/* Convert newlines */
X#define	oldArchItem	2		/* Old tar compatible archive creation */
X#define blockItem	3		/* Set block size */
X#define pageItem	5		/* Control paging of screen listing */
X#define printItem	6		/* Use printer instead of screen */
X#define typeItem	8		/* Creator/Type dialog */
X
X
X/*
X * Menu related variables
X */
X
XMenuHandle	menus[menuCount];
XBoolean		menusOK;
X
X/*
X * MenuInit - set up menu bar
X *
X *	Reads non-apple menus from resource file.
X */
XBoolean
XMenuInit() {
X	int	i;
X	char	*routine = "\PMenuInit";
X
X	if ((menus[appleMenu] = GetMenu(appleID)) == NIL) {
X		OSAlert(routine, "\PGetMenu Apple Menu", NIL, ResError());
X		return(TRUE);
X	}
X
X	AddResMenu(menus[appleMenu], 'DRVR');
X	if ((menus[fileMenu] = GetMenu(fileID)) == NIL) {
X		OSAlert(routine, "\PGetMenu File Menu", NIL, ResError());
X		return(TRUE);
X	}
X
X	if ((menus[editMenu] = GetMenu(editID)) == NIL) {
X		OSAlert(routine, "\PGetMenu Edit Menu", NIL, ResError());
X		return(TRUE);
X	}
X
X	if ((menus[optionMenu] = GetMenu(optionID)) == NIL) {
X		OSAlert(routine, "\PGetMenu Option Menu", NIL, ResError());
X		return(TRUE);
X	}
X
X
X	CheckItem(menus[optionMenu], pageItem, autoPage);
X	for (i = appleMenu; i < menuCount; i++)
X		InsertMenu(menus[i], 0);
X
X	DDaMenus();
X	DrawMenuBar();
X	return(FALSE);
X}
X
X/*
X * MenuCmd - handle a menu pick or keyboard equivalent
X */
XMenuCmd(result)
Xlong	result;
X{
X	WindowPeek	wp;
X	short		theItem = result & 0xffff;
X	short		theMenu = (result >> 16) & 0xffff;
X	char		name[256];
X	OSErr		err;
X	char		*routine = "\PMenuCmd";
X	GrafPtr		savedPort;
X
X	switch (theMenu) {
X	case appleID:
X		if (theItem == aboutItem)
X			DoAboutBox();
X		else {
X			/*
X			 * Oh boy, set up for a desk accessory.
X			 */
X			GetItem(menus[appleMenu], theItem, name);
X			GetPort(&savedPort);
X			if ((err = ZeroScrap()) != noErr) {
X				OSAlert(routine, "\PZeroScrap", NIL, err);
X				break;
X			}
X
X			if ((err = TEToScrap()) != noErr) {
X				OSAlert(routine, "\PTEToScrap", NIL, err);
X				break;
X			}
X
X			(void) OpenDeskAcc(name);
X			SetPort(savedPort);
X			if (FrontWindow() != NIL) {
X				EDaMenus();
X			}
X		}
X		break;
X
X	case fileID:
X		switch (theItem) {
X		case createItem:
X			ArCreate();
X			break;
X
X		case extractItem:
X			Extract();
X			break;
X
X		case listItem:
X			List();
X			break;
X
X		case closeItem:
X			/*
X			 * If the front window belongs to a Desk Acc, close it!
X			 */
X			if ((wp = (WindowPeek) FrontWindow()) == NIL)
X				break;
X
X			if (wp->windowKind < 0) {
X				CloseDeskAcc(wp->windowKind);
X				DDaMenus();
X			}
X			break;
X
X		case pgsetItem:
X			if (!PrSetup())
X				(void) PrStlDialog(prRecHdl);
X			break;
X
X		case quitItem:
X			doneFlag = TRUE;
X			break;
X		}
X		break;
X
X	case editID:
X		/*
X		 * Send to a Desk Acc.
X		 */
X		(void) SystemEdit(theItem - 1);
X		break;
X
X	case optionID:
X		switch (theItem) {
X		case convertItem:
X			cvtNl ^= TRUE;
X			CheckItem(menus[optionMenu], convertItem, cvtNl);
X			break;
X
X		case oldArchItem:
X			oldArch ^= TRUE;
X			CheckItem(menus[optionMenu], oldArchItem, oldArch);
X			break;
X
X		case blockItem:
X			DoBlockSize();
X			break;
X
X		case pageItem:
X			autoPage ^= TRUE;
X			CheckItem(menus[optionMenu], pageItem, autoPage);
X			break;
X
X		case printItem:
X			doPrint ^= TRUE;
X			CheckItem(menus[optionMenu], printItem, doPrint);
X			break;
X
X		case typeItem:
X			DoCreatorType();
X			break;
X		}
X		break;
X	}
X
X	HiliteMenu(0);
X	FlushEvents(everyEvent, 0);
X}
X
X/*
X * DDaMenus - disable Desk Acc specific menu and menu item
X */
XDDaMenus() {
X	DisableItem(menus[editMenu], 0);
X	DisableItem(menus[fileMenu], closeItem);
X	DrawMenuBar();
X	menusOK = TRUE;
X}
X
X/*
X * EDaMenus - enable Desk Acc specific menu and menu item
X */
XEDaMenus() {
X	EnableItem(menus[editMenu], 0);
X	EnableItem(menus[fileMenu], closeItem);
X	DrawMenuBar();
X	menusOK = FALSE;
X}
SHAR_EOF
if test 4610 -ne "`wc -c < 'menu.c'`"
then
	echo shar: error transmitting "'menu.c'" '(should have been 4610 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'window.c'" '(7222 characters)'
if test -f 'window.c'
then
	echo shar: will not over-write existing file "'window.c'"
else
sed 's/^X//' << \SHAR_EOF > 'window.c'
X/*
X * Macintosh Tar
X *
X * Written by Craig Ruff
X *
X * Window manipulation routines for display (and printer) listings of archives.
X */
X
X#include "tar.h"
X#include <resource.h>
X
X#define dispID	129		/* Display window ID (in resource file) */
X#define LEFTMAR	5
X#define TOPMAR	5
X
XWindowPtr	dispWind;
XBoolean		windOpen = FALSE;
Xshort		fontHeight;
Xshort		bottomMargin;
Xshort		bottomLine;
Xshort		topLine;
Xshort		curLine;
Xshort		wLines;
Xshort		wCurLine = 0;
XRgnHandle 	update;
XTPPrPort	prPort;
XGrafPtr		savedPort;
X
X/*
X * WindInit - either open the window or printer port
X *
X *	Returns TRUE if an error is found, FALSE otherwise.
X *
X *	Separate routines for screen and printer are not really needed.
X */
XBoolean
XWindInit() {
X	FontInfo	fInfo;
X	char		*routine = "\PWindInit";
X
X	if (doPrint) {
X		/*
X		 * We are listing to the printer.
X		 * Make sure we have opened the printer driver.
X		 */
X		if (!pOpen && PrSetup())
X			return(TRUE);
X
X		/*
X		 * Ask about this listings specifics.
X		 */
X		if (PrJobDialog(prRecHdl) == FALSE)
X			return(TRUE);
X
X		if (PrError() != noErr) {
X			OSAlert(routine, "\PPrJobDialog", NIL, PrError());
X			return(TRUE);
X		}
X
X		/*
X		 * Open the printer document (once per listing).
X		 */
X		prPort = PrOpenDoc(prRecHdl, NIL, NIL);
X		if (PrError() != noErr) {
X			OSAlert(routine, "\PPrOpenDoc", NIL, PrError());
X			return(TRUE);
X		}
X
X		/*
X		 * Open the page (once per physical page).
X		 */
X		PrOpenPage(prPort, NIL);
X		if (PrError() != noErr) {
X			OSAlert(routine, "\PPrOpenPage", NIL, PrError());
X			return(TRUE);
X		}
X
X		/*
X		 * Use monaco 9 so our listing lines up properly.
X		 * (Lazy)
X		 */
X		GetPort(&savedPort);
X		SetPort(prPort);
X		TextFont(monaco);
X		TextSize(9);
X
X		/*
X		 * Figure out how many lines fit on a page.
X		 */
X		GetFontInfo(&fInfo);
X		fontHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
X		MoveTo(LEFTMAR, curLine = fontHeight);
X		bottomLine = (((**prRecHdl).prInfo.rPage.bottom / fontHeight) - 1)
X				* fontHeight;
X
X		return(FALSE);
X	}
X
X	/*
X	 * Listing to screen.
X	 * Get a temporary region for scrolling bits.
X	 * Get the window template from the resource file.
X	 */
X	if ((update = NewRgn()) == NIL) {
X		OSAlert(routine, "\PNewRgn", NIL, MemError());
X		return(TRUE);
X	}
X
X	if ((dispWind = GetNewWindow(dispID, NIL, (WindowPtr) -1)) == NIL) {
X		OSAlert(routine, "\PGetNewWindow", NIL, ResError());
X		return(TRUE);
X	}
X
X	/*
X	 * Use monaco 9 so our listing lines up.
X	 */
X	SetPort(dispWind);
X	TextFont(monaco);
X	TextSize(9);
X
X	/*
X	 * Figure out how many lines fit on a page, save this as margin info.
X	 */
X	GetFontInfo(&fInfo);
X	fontHeight = fInfo.ascent + fInfo.descent + fInfo.leading;
X
X	MoveTo(LEFTMAR, curLine = fontHeight);
X	topLine = curLine + fInfo.descent + fInfo.leading;
X	bottomLine = (wLines = dispWind->portRect.bottom / fontHeight) * fontHeight;
X	bottomMargin = bottomLine + fInfo.descent + fInfo.leading;
X
X	wCurLine = 0;
X	windOpen = TRUE;
X	return(FALSE);
X}
X
X/*
X * WindEnd - clean up after a listing to screen or printer
X */
XWindEnd(keyWait)
XBoolean	keyWait;
X{
X	if (doPrint) {
X		TPrStatus	prSt;
X		char		*routine = "\PWindEnd";
X		short		err;
X
X		/*
X		 * Printing, close page and document.
X		 */
X		PrClosePage(prPort);
X		if ((err = PrError()) != noErr) {
X			if (err != iPrAbort)
X				OSAlert(routine, "\PPrClosePage", NIL, PrError());
X			goto done;
X		}
X
X		PrCloseDoc(prPort);
X		if ((err = PrError()) != noErr) {
X			if (err != iPrAbort)
X				OSAlert(routine, "\PPrCloseDoc", NIL, PrError());
X			goto done;
X		}
X
X		/*
X		 * If the printing involved spooling, spool it now.
X		 */
X		if ((**prRecHdl).prJob.bJDocLoop == bSpoolLoop) 
X			PrPicFile(prRecHdl, NIL, NIL, NIL, &prSt);
X
X	done:	SetPort(savedPort);
X		return;
X	}
X
X	/*
X	 * Listing to screen.  See if we should wait for a key press to continue.
X	 */
X	if (keyWait) {
X		EventRecord	e;
X		Boolean		oldAutoPage = autoPage;
X
X		autoPage = FALSE;	/* So we don't get two messages */
X		if (!doPrint)
X			WPrintf("Press any key to continue");
X
X		do {
X			SystemTask();
X			if (GetNextEvent(keyDownMask, &e) == FALSE)
X				e.what = nullEvent;
X		} while (e.what != keyDown);
X
X		autoPage = oldAutoPage;
X	}
X
X	DisposeWindow(dispWind);
X	DisposeRgn(update);
X	windOpen = FALSE;
X}
X
X/*
X * WPrintf - printf to the screen or printer
X *
X * 	Used like you'd expect, but does NOT handle paper motion
X *	characters like newline, etc.
X */
XWPrintf(fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
Xchar	*fmt;
Xlong	a0, a1, a2, a3, a4, a5, a6, a7, a8, a9;
X{
X	Rect		r;
X	char		buf[256];
X	EventRecord	e;
X	char		*routine = "\PWPrintf";
X	short		err;
X
X	if (!windOpen && !doPrint)
X		return;
X
X	sprintf(buf, fmt, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X	if (strlen(buf) >= sizeof(buf))
X		StkErrAlert();		/* Sanity check, stack overrun */
X
X	if (doPrint) {
X		/*
X		 * Printing.
X		 */
X		if (curLine > bottomLine) {
X			/*
X			 * At end of page, start a new one.
X			 */
X			PrClosePage(prPort);
X			if ((err = PrError()) != noErr) {
X				if (err != iPrAbort)
X					OSAlert(routine, "\PPrClosePage", NIL,
X							PrError());
X				longjmp(errJmp, 1);
X			}
X
X			PrOpenPage(prPort, NIL);
X			if (PrError() != noErr) {
X				if (err != iPrAbort)
X					OSAlert(routine, "\PPrClosePage", NIL,
X							PrError());
X				longjmp(errJmp, 1);
X			}
X
X			/*
X			 * Yes, we really must reset the font.
X			 */
X			MoveTo(LEFTMAR, curLine = fontHeight);
X			TextFace(underlineStyle);
X			DrawText(header, 0, strlen(header));
X			TextFace(0);
X			MoveTo(LEFTMAR, curLine += fontHeight);
X		}
X
X		DrawText(buf, 0, strlen(buf));
X		MoveTo(LEFTMAR, curLine += fontHeight);
X		return;
X	}
X
X	/*
X	 * On screen.
X	 */
X	SetPort(dispWind);
X	if (autoPage && (++wCurLine == wLines)) {
X		/*
X		 * At end of screen, wait for key press.
X		 */
X		wCurLine = 0;
X		DrawText("Press any key to continue", 0, 25);
X		do {
X			SystemTask();
X			if (GetNextEvent(keyDownMask, &e) == FALSE)
X				e.what = nullEvent;
X		} while (e.what != keyDown);
X
X		SetRect(&r, dispWind->portRect.left, bottomMargin - fontHeight,
X				dispWind->portRect.right, bottomMargin);
X		EraseRect(&r);
X		MoveTo(LEFTMAR, curLine);
X
X	} else {
X		/*
X		 * No auto page, only stop if command S is pressed.
X		 */
X		if (GetNextEvent(keyDownMask, &e)) {
X			if (((e.message & charCodeMask & ~0x20) == 'S')
X						&& (e.modifiers & cmdKey)) {
X				do {
X					/*
X					 * Start again after command Q.
X					 */
X					SystemTask();
X					if (GetNextEvent(keyDownMask, &e) == FALSE)
X						e.message = 0;
X
X					e.message &= charCodeMask & ~0x20;
X				} while (e.message != 'Q');
X			}
X		}
X	}
X
X	if (curLine > bottomLine) {
X		/*
X		 * At end of screen, scroll up.
X		 */
X		SetRect(&r, dispWind->portRect.left, topLine,
X				dispWind->portRect.right, bottomMargin);
X		ScrollRect(&r, 0, -fontHeight, update);
X		SetEmptyRgn(update);
X		MoveTo(LEFTMAR, curLine = bottomLine);
X	}
X
X	DrawText(buf, 0, strlen(buf));
X	MoveTo(LEFTMAR, curLine += fontHeight);
X}
X
X/*
X * PrSetup - make sure the printer driver has been opened.
X *
X *	Returns TRUE if an error is found, FALSE otherwise.
X */
XBoolean
XPrSetup() {
X	char	*routine = "\PPrSetup";
X
X	if (!pOpen) {
X		PrOpen();
X		if (PrError() != noErr) {
X			OSAlert(routine, "\PPrOpen", NIL, PrError());
X			return(TRUE);
X		}
X
X		pOpen = TRUE;
X		PrintDefault(prRecHdl);
X		if (PrError() != noErr) {
X			OSAlert(routine, "\PPrintDefault", NIL, PrError());
X			return(TRUE);
X		}
X	}
X
X	return(FALSE);
X}
SHAR_EOF
if test 7222 -ne "`wc -c < 'window.c'`"
then
	echo shar: error transmitting "'window.c'" '(should have been 7222 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
--- end of part 3 ---
Technical Details
Message-ID: <7964@dhw68k.cts.com>
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!lll-tis!ames!oliveb!pyramid!hplabs!felix!dhw68k!macintosh
References: <7889@dhw68k.cts.com> <7925@dhw68k.cts.com>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!lll-tis!ames!oliveb!pyramid!hplabs!felix!dhw68k!macintosh
From: cruff@ncar.ucar.edu (Craig Ruff)
Newsgroups: comp.sources.mac
Subject: Tar 1.1 Source (part 3 of 3)
Message-ID: <7964@dhw68k.cts.com>
Date: 14 May 88 06:57:18 GMT
References: <7889@dhw68k.cts.com> <7925@dhw68k.cts.com>
Sender: macintosh@dhw68k.cts.com
Organization: Scientific Computing Division/NCAR, Boulder CO
Lines: 1392
Approved: bytebug@dhw68k.cts.com (Roger L. Long)