Path: 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) [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 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 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 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 ---