cruff@ncar.ucar.edu (Craig Ruff) (05/12/88)
[Tar 1.1 Source - part 1 of 3] [Moderator's Note: The Tar 1.1 binary will be posted in comp.binaries.mac.] --- #! /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 # tar.h # tar.c # tar.resource # buffer.c # This archive created: Wed May 11 07:24:03 1988 # By: Roger L. Long (bytebug@dhw68k.cts.com) export PATH; PATH=/bin:$PATH echo shar: extracting "'README'" '(355 characters)' if test -f 'README' then echo shar: will not over-write existing file "'README'" else sed 's/^X//' << \SHAR_EOF > 'README' X Tar for the Macintosh X XThese files make up the sources of tar for the Macintosh. I used Aztec C Xv3.4b to compile the program. I then used ResEdit to copy the (compiled) Xresources to the application. The file tar.resource contains the decompiled Xresources. This was done with ResTools 3.00. You can use that program Xor Rez to rebuild the resources. SHAR_EOF if test 355 -ne "`wc -c < 'README'`" then echo shar: error transmitting "'README'" '(should have been 355 characters)' fi fi # end of overwriting check echo shar: extracting "'Makefile'" '(244 characters)' if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else sed 's/^X//' << \SHAR_EOF > 'Makefile' XOBJECTS = buffer.o create.o dialog.o dir.o extract.o list.o menu.o tar.o window.o X Xtar: $(OBJECTS) hdrs.dmp X ln -W -o tar -M ../lib3/sacroot.o $(OBJECTS) -lc X X$(OBJECTS): hdrs.dmp X cc +Ihdrs.dmp -o $@ $*.c X Xhdrs.dmp: tar.h X cc +Hhdrs.dmp tar.h SHAR_EOF if test 244 -ne "`wc -c < 'Makefile'`" then echo shar: error transmitting "'Makefile'" '(should have been 244 characters)' fi fi # end of overwriting check echo shar: extracting "'tar.h'" '(3783 characters)' if test -f 'tar.h' then echo shar: will not over-write existing file "'tar.h'" else sed 's/^X//' << \SHAR_EOF > 'tar.h' X#include <types.h> X#include <quickdraw.h> X#include <font.h> X#include <event.h> X#include <control.h> X#include <window.h> X#include <menu.h> X#include <textedit.h> X#include <dialog.h> X#include <desk.h> X#include <toolutil.h> X#include <osutil.h> X#include <scrap.h> X#include <packages.h> X#include <list.h> X#include <pb.h> X#include <memory.h> X#include <print.h> X#include <syserr.h> X#include <setjmp.h> X X#ifndef NIL X#define NIL (0L) X#endif X X#ifndef EOF X#define EOF (-1L) X#endif X X#define DIRECTORY(pb) (((pb).ioFlAttrib & 0x10) == 0x10) X X/* X * Character definitions X */ X#define ENTER 0x03 X#define BS 0x08 X#define TAB 0x09 X#define RETURN 0x0d X X/* X * Difference between Mac and Unix times X */ X#define TIMEDIFF 0x7c25b080 X X/* X * Global Variables X */ Xextern Boolean autoPage; Xextern Boolean cvtNl; Xextern Boolean doneFlag; Xextern Boolean doPrint; Xextern Boolean ignorez; Xextern Boolean menusOK; Xextern Boolean pOpen; X Xextern char fdCreator[]; Xextern char fdType[]; Xextern char header[]; X Xextern jmp_buf errJmp; X Xextern THPrint prRecHdl; X X/* X * Standard File and GetDir saved outputs X */ Xextern char *arName; Xextern short arVRefNum; Xextern long dirDirID; Xextern short dirVRefNum; X X/* X * External routines X */ Xextern Boolean GetDir(); Xextern Boolean MenuInit(); Xextern Boolean PrSetup(); Xextern Boolean WindInit(); X X/* X * Remainder taken from: X * Header file for public domain tar (tape archive) program. X * X * @(#)tar.h 1.20 86/10/29 Public Domain. X * X * Created 25 August 1985 by John Gilmore, ihnp4!hoptoad!gnu. X */ X X/* X * Header block on tape. X * X * I'm going to use traditional DP naming conventions here. X * A "block" is a big chunk of stuff that we do I/O on. X * A "record" is a piece of info that we care about. X * Typically many "record"s fit into a "block". X */ X#define RECORDSIZE 512 X#define NAMSIZ 100 X#define TUNMLEN 32 X#define TGNMLEN 32 X Xunion record { X char charptr[RECORDSIZE]; X struct header { X char name[NAMSIZ]; X char mode[8]; X char uid[8]; X char gid[8]; X char size[12]; X char mtime[12]; X char chksum[8]; X char linkflag; X char linkname[NAMSIZ]; X char magic[8]; X char uname[TUNMLEN]; X char gname[TGNMLEN]; X char devmajor[8]; X char devminor[8]; X } header; X}; X X/* The checksum field is filled with this while the checksum is computed. */ X#define CHKBLANKS " " /* 8 blanks, no null */ X X/* The magic field is filled with this if uname and gname are valid. */ X#define TMAGIC "ustar " /* 7 chars and a null */ X X/* The linkflag defines the type of file */ X#define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */ X#define LF_NORMAL '0' /* Normal disk file */ X#define LF_LINK '1' /* Link to previously dumped file */ X#define LF_SYMLINK '2' /* Symbolic link */ X#define LF_CHR '3' /* Character special file */ X#define LF_BLK '4' /* Block special file */ X#define LF_DIR '5' /* Directory */ X#define LF_FIFO '6' /* FIFO special file */ X#define LF_CONTIG '7' /* Contiguous file */ X/* Further link types may be defined later. */ X X/* X * Global variables X */ Xextern int blocking; /* Size of each block, in records */ Xextern int blockSize; /* Size of each block, in bytes */ Xextern Boolean reblock; Xextern Boolean oldArch; X X/* X * We now default to Unix Standard format rather than 4.2BSD tar format. X * The code can actually produce all three: X * standard ANSI standard X * oldarch V7 X * neither 4.2BSD X * but we don't bother, since 4.2BSD can read ANSI standard format anyway. X * The only advantage to the "neither" option is that we can cmp(1) our X * output to the output of 4.2BSD tar, for debugging. X */ X#define standard (!oldArch) X Xextern short archive; /* File descriptor for archive file */ X X/* X * Declarations of functions available to the world. X */ Xunion record *FindRec(); Xvoid UseRec(); Xunion record *EndOfRecs(); XBoolean OpenArchive(); SHAR_EOF if test 3783 -ne "`wc -c < 'tar.h'`" then echo shar: error transmitting "'tar.h'" '(should have been 3783 characters)' fi fi # end of overwriting check echo shar: extracting "'tar.c'" '(2669 characters)' if test -f 'tar.c' then echo shar: will not over-write existing file "'tar.c'" else sed 's/^X//' << \SHAR_EOF > 'tar.c' X/* X * Macintosh TAR X * X * Written by Craig Ruff X * X * Main routine and global variables. X */ X X#include "tar.h" X#include <segment.h> X X#ifdef DEBUG X#include <resource.h> X#endif X X#define FSFCBLen (*(short *) 0x3f6) X X/* X * Global variable declarations X */ XBoolean autoPage = FALSE; /* List by screenfulls */ XBoolean cvtNl = FALSE; /* Convert newline to return and back */ XBoolean doneFlag = FALSE; /* Quit item selected? */ XBoolean doPrint = FALSE; /* List to printer */ XBoolean ignorez = FALSE; /* Ignore zero blocks */ XBoolean pOpen = FALSE; /* Printer open? */ XBoolean reblock = FALSE; /* Read enough for a full block size buffer */ XBoolean oldArch = FALSE; /* Old tar compatible */ X XTHPrint prRecHdl; /* Printer record (when printing) */ X Xchar *arName; /* Archive file name */ Xshort arVRefNum; /* Archive file VRefNum */ X Xshort archive; /* File descriptor for archive file */ Xint blocking; /* Size of each block, in records */ Xint blockSize; /* Size of each block, in bytes */ X Xchar fdCreator[4]; /* Finder Creator */ Xchar fdType[4]; /* Finder Type */ Xchar header[128]; /* Common header for listings */ Xjmp_buf errJmp; /* For error exits */ X Xmain() { X WindowPtr wind; X EventRecord e; X X /* X * Standard Mac Initializations X */ X InitGraf(&thePort); X InitFonts(); X FlushEvents(everyEvent, 0); X InitWindows(); X InitMenus(); X TEInit(); X InitDialogs(NIL); X InitCursor(); X X#ifdef DEBUG X /* X * So we don't keep copying resources into our application. X */ X if (OpenResFile("\Psys:C:tar:tar.rsrc") == -1) { X OSAlert("\Pmain", "\PDebug OpenResFile", NIL, 0); X ExitToShell(); X } X#endif X X /* Check for HFS running */ X if (FSFCBLen <= 0) { X HFSAlert(); X ExitToShell(); X } X X if (MenuInit()) X ExitToShell(); X X blocking = 20; X blockSize = blocking * RECORDSIZE; X strncpy(fdCreator, "????", 4); X strncpy(fdType, "TEXT", 4); X if ((prRecHdl = (THPrint) NewHandle((long) sizeof(TPrint))) == NIL) { X OSAlert("\Pmain", "\PNewHandle returned NIL", NIL, MemError()); X ExitToShell(); X } X X sprintf(header, "T Size Date Name%*s", 40, ""); X do { X SystemTask(); X /* Should never have a window open while a DA is running */ X if (!menusOK && (FrontWindow() == NIL)) X DDaMenus(); X X if (GetNextEvent(everyEvent, &e)) X switch (e.what) { X case mouseDown: X switch (FindWindow(pass(e.where), &wind)) { X case inSysWindow: X SystemClick(&e, wind); X break; X X case inMenuBar: X MenuCmd(MenuSelect(pass(e.where))); X break; X X } X break; X X case keyDown: X case autoKey: X if (e.modifiers & cmdKey) X MenuCmd(MenuKey(e.message & charCodeMask)); X break; X } X X } while (!doneFlag); X X if (pOpen) X PrClose(); X X ExitToShell(); X} SHAR_EOF if test 2669 -ne "`wc -c < 'tar.c'`" then echo shar: error transmitting "'tar.c'" '(should have been 2669 characters)' fi fi # end of overwriting check echo shar: extracting "'tar.resource'" '(10649 characters)' if test -f 'tar.resource' then echo shar: will not over-write existing file "'tar.resource'" else sed 's/^X//' << \SHAR_EOF > 'tar.resource' Xresource 'PICT' (128, purgeable) X{ X 474, X {7, 7, 114, 254}, X {17; 1; 160; 0; 130; 161; 0; 150; 0; 6; 5; 0; 0 X ; 0; 2; 152; 161; 0; 154; 0; 8; 255; 252; 0; 0 X ; 0; 69; 0; 0; 160; 0; 152; 1; 0; 10; 0; 7 X ; 0; 7; 0; 114; 0; 254; 3; 0; 2; 13; 0; 12 X ; 43; 11; 22; 21; 84; 97; 114; 32; 102; 111; 114; 32 X ; 116; 104; 101; 32; 77; 97; 99; 105; 110; 116; 111; 115 X ; 104; 160; 0; 153; 160; 0; 151; 161; 0; 150; 0; 6 X ; 5; 0; 0; 0; 2; 152; 161; 0; 154; 0; 8; 0 X ; 26; 0; 0; 0; 120; 0; 0; 160; 0; 152; 13; 0 X ; 10; 42; 27; 34; 87; 114; 105; 116; 116; 101; 110; 32 X ; 98; 121; 32; 67; 114; 97; 105; 103; 32; 82; 117; 102 X ; 102; 32; 119; 105; 116; 104; 32; 101; 120; 99; 101; 114 X ; 112; 116; 41; 191; 7; 115; 32; 102; 114; 111; 109; 13 X ; 160; 0; 153; 161; 0; 154; 0; 8; 0; 14; 0; 0 X ; 0; 120; 0; 0; 160; 0; 152; 40; 0; 61; 0; 11 X ; 34; 74; 111; 104; 110; 32; 71; 105; 108; 109; 111; 114 X ; 101; 39; 115; 32; 112; 117; 98; 108; 105; 99; 32; 100 X ; 111; 109; 97; 105; 110; 32; 116; 97; 114; 32; 112; 41 X ; 191; 8; 114; 111; 103; 114; 97; 109; 46; 13; 160; 0 X ; 153; 161; 0; 154; 0; 8; 0; 2; 0; 0; 0; 120 X ; 0; 0; 160; 0; 152; 40; 0; 73; 0; 11; 1; 13 X ; 160; 0; 153; 161; 0; 154; 0; 8; 255; 246; 0; 0 X ; 0; 120; 0; 0; 160; 0; 152; 42; 12; 34; 84; 104 X ; 105; 115; 32; 112; 114; 111; 103; 114; 97; 109; 32; 105 X ; 115; 32; 112; 117; 98; 108; 105; 99; 32; 100; 111; 109 X ; 97; 105; 110; 46; 32; 32; 78; 111; 41; 190; 9; 32 X ; 102; 101; 101; 32; 109; 97; 121; 13; 160; 0; 153; 161 X ; 0; 154; 0; 8; 255; 234; 0; 0; 0; 120; 0; 0 X ; 160; 0; 152; 40; 0; 97; 0; 11; 34; 98; 101; 32 X ; 99; 104; 97; 114; 103; 101; 100; 32; 102; 111; 114; 32 X ; 97; 32; 99; 111; 112; 121; 32; 111; 102; 32; 116; 104 X ; 105; 115; 32; 112; 114; 111; 103; 41; 186; 8; 114; 97 X ; 109; 32; 97; 110; 100; 13; 160; 0; 153; 161; 0; 154 X ; 0; 8; 255; 222; 0; 0; 0; 120; 0; 0; 160; 0 X ; 152; 40; 0; 109; 0; 11; 34; 100; 105; 115; 116; 114 X ; 105; 98; 117; 116; 105; 111; 110; 32; 109; 97; 121; 32 X ; 110; 111; 116; 32; 98; 101; 32; 114; 101; 115; 116; 114 X ; 105; 99; 116; 101; 100; 41; 184; 1; 46; 160; 0; 153 X ; 160; 0; 151; 160; 0; 131; 255} X}; X Xuserdefined resource 'TAR ' (0) X{ X long:0x8546172; X long:0x2076312e; X byte:49}; X Xresource 'BNDL' (128) X{ X 'TAR ', 0, X { X 'ICN#', {0, 128; 1, 129}; X 'FREF', {0, 128; 1, 129} X } X}; X Xresource 'FREF' (128) X{ X 'APPL', X 0, X "" X}; X Xresource 'FREF' (129) X{ X 'TARF', X 1, X "" X}; X Xresource 'ICN#' (128) X{ X 0xffff 0xffff 0x8000 0x0001 X 0x8780 0x01e1 0x8840 0x0211 X 0x97a0 0x0409 0xafd0 0x0805 X 0xafd0 0x08c5 0xafd0 0x08c5 X 0xafd0 0x0805 0x97a0 0x0409 X 0x8840 0x0211 0x8f80 0x01e1 X 0x8400 0x0041 0x8200 0x0081 X 0x810f 0xf101 0x8088 0x1201 X 0x8048 0x1401 0x8027 0xe801 X 0x801f 0xf001 0x8000 0x0001 X 0x8000 0x0001 0x8000 0x0001 X 0x80f9 0xcf01 0x8022 0x2881 X 0x8022 0x2881 0x8023 0xef01 X 0x8022 0x2901 0x8022 0x2881 X 0x8022 0x2881 0x8000 0x0001 X 0x8000 0x0001 0xffff 0xffff ; X X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X 0xffff 0xffff 0xffff 0xffff X}; X Xresource 'ICN#' (129) X{ X 0x0000 0x0000 0x0000 0x0000 X 0x000f 0xf000 0x0030 0x0c00 X 0x00c0 0x0300 0x0100 0x0080 X 0x0200 0x0040 0x0400 0x0020 X 0x0800 0x0010 0x0800 0x0010 X 0x1000 0x0008 0x1000 0x0008 X 0x21f3 0x9e04 0x2044 0x5104 X 0x2044 0x5104 0x2047 0xde04 X 0x2044 0x5204 0x2044 0x5104 X 0x2044 0x5104 0x2000 0x0004 X 0x1000 0x0008 0x1000 0x0008 X 0x0800 0x0010 0x0800 0x0010 X 0x0400 0x0020 0x0200 0x0040 X 0x0100 0x0080 0x00c0 0x0300 X 0x0030 0x0c00 0x000f 0xfffc X 0x0000 0x0000 0x0000 0x0000 ; X X 0x0000 0x0000 0x0000 0x0000 X 0x000f 0xf000 0x003f 0xfc00 X 0x00ff 0xff00 0x01ff 0xff80 X 0x03ff 0xffc0 0x07ff 0xffe0 X 0x0fff 0xfff0 0x0fff 0xfff0 X 0x1fff 0xfff8 0x1fff 0xfff8 X 0x3fff 0xfffc 0x3fff 0xfffc X 0x3fff 0xfffc 0x3fff 0xfffc X 0x3fff 0xfffc 0x3fff 0xfffc X 0x3fff 0xfffc 0x3fff 0xfffc X 0x1fff 0xfff8 0x1fff 0xfff8 X 0x0fff 0xfff0 0x0fff 0xfff0 X 0x07ff 0xffe0 0x03ff 0xffc0 X 0x01ff 0xff80 0x00ff 0xff00 X 0x003f 0xfc00 0x000f 0xfffc X 0x0000 0x0000 0x0000 0x0000 X}; X Xresource 'WIND' (129) X{ X {40, 20, 320, 480}, X 1, X visible, X noGoAway, X 0x0, X "" X}; X Xresource 'ALRT' (129, purgeable) X{ X {50, 65, 140, 385}, X 192, X OK,visible,0, X OK,visible,0, X OK,visible,0, X OK,visible,0 X}; X Xresource 'ALRT' (130, purgeable) X{ X {50, 65, 200, 385}, X 193, X OK,visible,0, X OK,visible,0, X OK,visible,0, X OK,visible,0 X}; X Xresource 'ALRT' (131, purgeable) X{ X {50, 65, 200, 385}, X 194, X OK,visible,0, X OK,visible,0, X OK,visible,0, X OK,visible,0 X}; X Xresource 'ALRT' (132, purgeable) X{ X {50, 65, 140, 385}, X 195, X OK,visible,0, X OK,visible,0, X OK,visible,0, X OK,visible,0 X}; X Xresource 'ALRT' (133, purgeable) X{ X {50, 65, 140, 385}, X 196, X OK,visible,0, X OK,visible,0, X OK,visible,0, X OK,visible,0 X}; X Xresource 'ALRT' (134, purgeable) X{ X {50, 65, 140, 385}, X 197, X OK,visible,0, X OK,visible,0, X OK,visible,0, X OK,visible,0 X}; X Xresource 'DITL' (129, purgeable) X{ X { X {15, 200, 37, 260}, X Button {enabled, "OK"}; X {50, 200, 74, 260}, X Button {enabled, "Cancel"}; X {40, 80, 55, 121}, X EditText {enabled, ""}; X {15, 40, 35, 159}, X StaticText {enabled, "Enter block size:"} X } X}; X Xresource 'DITL' (192, purgeable) X{ X { X {60, 124, 80, 184}, X Button {enabled, "OK"}; X {9, 67, 49, 256}, X StaticText {enabled, "Block size must be between 1 and 128 inclusive!"} X } X}; X Xresource 'DITL' (130, purgeable) X{ X { X {35, 15, 56, 160}, X Button {enabled, ""}; X {179, 256, 200, 336}, X Button {enabled, "Cancel"}; X {55, 247, 75, 341}, X StaticText {disabled, ""}; X {67, 456, 85, 536}, X Button {disabled, "Eject"}; X {93, 456, 111, 536}, X Button {disabled, "Drive"}; X {65, 15, 210, 230}, X Useritem {enabled, 7215}; X {141, 252, 142, 339}, X Useritem {disabled, 8274}; X {35, 168, 56, 228}, X Button {enabled, "UP"}; X {151, 256, 172, 336}, X Button {enabled, "Open"}; X {7, 15, 28, 339}, X StaticText {enabled, "Select directory ^0:"}; X {83, 256, 104, 336}, X Button {enabled, "Drive"}; X {111, 256, 132, 336}, X Button {enabled, "Eject"} X } X}; X Xresource 'DITL' (193, purgeable) X{ X { X {121, 126, 141, 186}, X Button {enabled, "OK"}; X {10, 68, 57, 311}, X StaticText {enabled, "^0: ^1"}; X {60, 69, 91, 313}, X StaticText {enabled, "^2"}; X {96, 80, 116, 200}, X StaticText {enabled, "OS Error: ^3"} X } X}; X Xresource 'DITL' (194, purgeable) X{ X { X {122, 123, 142, 183}, X Button {enabled, "OK"}; X {9, 99, 28, 289}, X StaticText {enabled, "^0: ^1"}; X {35, 100, 91, 289}, X StaticText {enabled, "^2"}; X {95, 101, 115, 289}, X StaticText {enabled, "^3"} X } X}; X Xresource 'DITL' (195, purgeable) X{ X { X {60, 124, 80, 184}, X Button {enabled, "OK"}; X {9, 92, 49, 221}, X StaticText {enabled, "Macintosh Tar only works with HFS."} X } X}; X Xresource 'DITL' (196) X{ X { X {63, 130, 83, 190}, X Button {enabled, "OK"}; X {9, 81, 56, 266}, X StaticText {enabled, "Skipping archive file (it is within the directory being archived)."} X } X}; X Xresource 'DITL' (197) X{ X { X {63, 130, 83, 190}, X Button {enabled, "OK"}; X {9, 81, 56, 266}, X StaticText {enabled, "Overrun of stack in window print (can't continue)!"} X } X}; X Xresource 'DITL' (131, purgeable) X{ X { X {78, 43, 98, 103}, X Button {enabled, "OK"}; X {79, 182, 99, 242}, X Button {enabled, "Cancel"}; X {13, 114, 33, 174}, X EditText {enabled, ""}; X {45, 114, 65, 174}, X EditText {enabled, ""}; X {13, 38, 33, 98}, X StaticText {enabled, "Creator:"}; X {44, 58, 65, 100}, X StaticText {enabled, "Type:"} X } X}; X Xresource 'DITL' (128, purgeable) X{ X { X {130, 74, 150, 134}, X Button {enabled, "OK"}; X {7, 7, 114, 254}, X Picture {enabled, 128} X } X}; X Xresource 'DLOG' (128, purgeable) X{ X {68, 112, 240, 380}, X 1, X visible, X noGoAway, X 0x0, X 128, X "About TAR" X}; X Xresource 'DLOG' (130, purgeable) X{ X {60, 75, 275, 423}, X 1, X invisible, X noGoAway, X 0x0, X 130, X "" X}; X Xresource 'DLOG' (129, purgeable) X{ X {44, 75, 144, 375}, X 1, X visible, X noGoAway, X 0x0, X 129, X "Block Size" X}; X Xresource 'DLOG' (131, purgeable) X{ X {44, 75, 144, 375}, X 1, X visible, X goAway, X 0x0, X 131, X "New Dialog" X}; X Xresource 'MENU' (128, preLoad) X{ X 128, X 0, X 0xfffffffb, X enabled, X "\024", X { X "About Tar...", noIcon, noKey, noMark, plain; X "-", noIcon, noKey, noMark, plain X } X}; X Xresource 'MENU' (129) X{ X 129, X 0, X 0xffffff6f, X enabled, X "File", X { X "Create...", noIcon, noKey, noMark, plain; X "Extract...", noIcon, noKey, noMark, plain; X "List...", noIcon, noKey, noMark, plain; X "-", noIcon, noKey, noMark, plain; X "Close", noIcon, noKey, noMark, plain; X "Page Setup...", noIcon, noKey, noMark, plain; X "-", noIcon, noKey, noMark, plain; X "Quit", noIcon, noKey, noMark, plain X } X}; X Xresource 'MENU' (130, preLoad) X{ X 130, X 0, X 0xfffffffb, X enabled, X "Edit", X { X "Undo", noIcon, 'Z', noMark, plain; X "-", noIcon, noKey, noMark, plain; X "Cut", noIcon, 'X', noMark, plain; X "Copy", noIcon, 'C', noMark, plain; X "Paste", noIcon, 'V', noMark, plain; X "Clear", noIcon, noKey, noMark, plain X } X}; X Xresource 'MENU' (131) X{ X 131, X 0, X 0xffffff6f, X enabled, X "Options", X { X "Convert Newlines", noIcon, noKey, noMark, plain; X "Old Tar Compatible", noIcon, noKey, noMark, plain; X "Block Size...", noIcon, noKey, noMark, plain; X "-", noIcon, noKey, noMark, plain; X "Page Screen Listings", noIcon, noKey, noMark, plain; X "List to Printer", noIcon, noKey, noMark, plain; X "-", noIcon, noKey, noMark, plain; X "Set Creator/Type...", noIcon, noKey, noMark, plain X } X}; X SHAR_EOF if test 10649 -ne "`wc -c < 'tar.resource'`" then echo shar: error transmitting "'tar.resource'" '(should have been 10649 characters)' fi fi # end of overwriting check echo shar: extracting "'buffer.c'" '(6263 characters)' if test -f 'buffer.c' then echo shar: will not over-write existing file "'buffer.c'" else sed 's/^X//' << \SHAR_EOF > 'buffer.c' X/* X * Macintosh Tar X * X * Modified by Craig Ruff for use on the Macintosh. X */ X/* X * Buffer management for public domain tar. X * X * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985. X * X * @(#) buffer.c 1.14 10/28/86 Public Domain - gnu X * X */ X X#include "tar.h" X Xunion record *arBlock; /* Start of block of archive */ Xunion record *arRecord; /* Current record of archive */ Xunion record *arLast; /* Last+1 record of archive block */ Xchar arReading; /* 0 writing, !0 reading archive */ X X/* X * The record pointed to by save_rec should not be overlaid X * when reading in a new tape block. Copy it to record_save_area first, and X * change the pointer in *save_rec to point to record_save_area. X * Saved_recno records the record number at the time of the save. X * This is used by annofile() to print the record number of a file's X * header record. X */ Xstatic union record **saveRec; Xstatic union record recordSaveArea; Xstatic int savedRecno; X X/* X * Record number of the start of this block of records X */ Xstatic int baseRec; X X/* X * Return the location of the next available input or output record. X */ Xunion record * XFindRec() X{ X if (arRecord == arLast) { X FlushArchive(); X if (arRecord == arLast) X return((union record *) NIL); /* EOF */ X } X X return(arRecord); X} X X/* X * Indicate that we have used all records up thru the argument. X * (should the arg have an off-by-1? XXX FIXME) X */ Xvoid XUseRec(rec) Xunion record *rec; X{ X while (rec >= arRecord) X arRecord++; X /* X * Do NOT flush the archive here. If we do, the same X * argument to userec() could mean the next record (if the X * input block is exactly one record long), which is not what X * is intended. X */ X if (arRecord > arLast) { X PgmAlert("\PUseRec", "\ParRecord > arLast", NIL, NIL); X longjmp(errJmp, 1); X } X} X X/* X * Return a pointer to the end of the current records buffer. X * All the space between findrec() and endofrecs() is available X * for filling with data, or taking data from. X */ Xunion record * XEndOfRecs() X{ X return(arLast); X} X X/* X * Open an archive file. The argument specifies whether we are X * reading or writing. X */ XBoolean XOpenArchive(read) Xint read; X{ X OSErr err; X char *routine = "\POpenArchive"; X X /* X * Get a block buffer for use later X */ X arBlock = (union record *) NewPtr((Size) blockSize); X if (arBlock == NIL) { X OSAlert(routine, "\RNewPtr", NIL, MemError()); X return(TRUE); X } X X arRecord = arBlock; X arLast = arBlock + blocking; X X /* X * Try and open the archive file. X */ X if (read) { X err = FSOpen(arName, arVRefNum, &archive); X X } else { X if ((err = Create(arName, arVRefNum, (OSType)'TAR ', (OSType)'TARF')) X == noErr) { X err = FSOpen(arName, arVRefNum, &archive); X } X } X X if (err != noErr) { X OSAlert(routine, "\PFSOpen or FSCreate", arName, err); X DisposPtr(arBlock); X archive = 0; X return(TRUE); X } X X arReading = read; X if (read) { X arLast = arBlock; /* Set up for 1st block = # 0 */ X FlushArchive(); X } X X return(FALSE); X} X X/* X * Remember a union record * as pointing to something that we X * need to keep when reading onward in the file. Only one such X * thing can be remembered at once, and it only works when reading X * an archive. X */ XSaveRec(pointer) Xunion record **pointer; X{ X saveRec = pointer; X savedRecno = baseRec + arRecord - arBlock; X} X X/* X * Perform a write to flush the buffer. X */ XFlWrite() X{ X OSErr err; X long count; X X count = blockSize; X err = FSWrite(archive, &count, arBlock->charptr); X if ((err == noErr) && (count == blockSize)) X return; X X /* FIXME, multi volume support on write goes here */ X OSAlert("\PFLWrite", "\PFSRead", NIL, err); X longjmp(errJmp, 1); X} X X/* X * Perform a read to flush the buffer. X */ XFlRead() X{ X OSErr err; /* Result from system call */ X long count; X int left; /* Bytes left */ X char *more; /* Pointer to next byte to read */ X char *routine = "\PFlRead"; X X /* X * If we are about to wipe out a record that X * somebody needs to keep, copy it out to a holding X * area and adjust somebody's pointer to it. X */ X if (saveRec && X *saveRec >= arRecord && X *saveRec < arLast) { X recordSaveArea = **saveRec; X *saveRec = &recordSaveArea; X } X X count = blockSize; X err = FSRead(archive, &count, arBlock->charptr); X if ((err == noErr) && (count == blockSize)) X return; X X else if ((err != noErr) && (err != eofErr)) { X OSAlert("\PReadError", "\PFSRead", NIL, err); X longjmp(errJmp, 1); X } X X more = arBlock->charptr + count; X left = blockSize - count; X Xagain: X if (0 == (((unsigned)left) % RECORDSIZE)) { X /* FIXME, for size=0, multi vol support */ X /* On the first block, warn about the problem */ X if (!reblock && baseRec == 0) { X char buf[80]; X X sprintf(&buf[1], "Blocksize = %ld records", X count / (long) RECORDSIZE); X buf[0] = strlen(&buf[1]); X PgmAlert(routine, buf, NIL, NIL); X } X X arLast = arBlock + ((unsigned)(blockSize - left))/RECORDSIZE; X return; X } X X if (reblock) { X /* X * User warned us about this. Fix up. X */ X if (left > 0) { X count = left; X err = FSRead(archive, &count, more); X if ((err != noErr) && (err != eofErr)) { X OSAlert("\PReadError", "\PFSRead", NIL, err); X longjmp(errJmp, 1); X } X if ((count == 0) || (err = eofErr)) { X PgmAlert(routine, "\PEof not on block boundary", X NIL, NIL); X longjmp(errJmp, 1); X } X left -= count; X more += count; X goto again; X } X } else { X PgmAlert(routine, "\PDid not read blocksize bytes", NIL, NIL); X longjmp(errJmp, 1); X } X} X X/* X * Flush the current buffer to/from the archive. X */ XFlushArchive() X{ X baseRec += arLast - arBlock;/* Keep track of block #s */ X arRecord = arBlock; /* Restore pointer to start */ X arLast = arBlock + blocking; /* Restore pointer to end */ X X if (!arReading) X FlWrite(); X else X FlRead(); X} X X/* X * Close the archive file. X */ XCloseArchive() X{ X if (!arReading) X FlushArchive(); X X DisposPtr(arBlock); X if (archive != 0) X (void) FSClose(archive); X X archive = 0; X} X X/* X * bcopy and bzero compatability routines. X * These could (should) potentially be done with the Mac traps. X */ Xchar * Xbcopy(s1, s2, n) Xchar *s1, *s2; Xregister int n; X{ X register char *s = s1; X register char *d = s2; X X while (--n >= 0) X *d++ = *s++; X X return(s1); X} X Xvoid Xbzero (s1, n) Xregister char *s1; Xregister int n; X{ X while (--n >= 0) X *s1++ = 0; X} SHAR_EOF if test 6263 -ne "`wc -c < 'buffer.c'`" then echo shar: error transmitting "'buffer.c'" '(should have been 6263 characters)' fi fi # end of overwriting check # End of shell archive exit 0 --- end of part 1 ---
cruff@ncar.ucar.edu (Craig Ruff) (05/13/88)
[Tar 1.1 Source - part 2 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: # create.c # dialog.c # dir.c # This archive created: Wed May 11 07:24:05 1988 # By: Roger L. Long (bytebug@dhw68k.cts.com) export PATH; PATH=/bin:$PATH echo shar: extracting "'create.c'" '(10693 characters)' if test -f 'create.c' then echo shar: will not over-write existing file "'create.c'" else sed 's/^X//' << \SHAR_EOF > 'create.c' X/* X * Macintosh Tar X * X * Modifed by Craig Ruff for use on the Macintosh. X */ X/* X * Create a tar archive. X * X * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu. X * X * @(#)create.c 1.19 9/9/86 Public Domain - gnu X */ X X#include "tar.h" X Xunion record *StartHeader(); Xextern union record *head; X X/* X * Fake stat struct for use with existing code X */ Xextern struct stat { X long st_size; X long st_mtime; X} hstat; X Xvoid FinishHeader(); Xvoid ToOct(); XBoolean FillName(); X X/* X * Used to save pathname info while descending the directory hierarchy. X */ Xstruct PathInfo { X struct PathInfo *next; X char name[32]; X}; Xtypedef struct PathInfo PathInfo; XPathInfo pathHead; X X/* X * ArCreate - manage the creation of an archive X * X * Asks for the archive name, creates the archive and then X * loops asking for directories to add to the archive. X */ XArCreate() { X Point where; X SFReply reply; X CInfoPBRec pb; X CursHandle cursor; X X /* X * Put up a standard file dialog asking for the archive file name. X */ X where.h = where.v = 75; X SFPutFile(pass(where), "\PName of TAR file", NIL, NIL, &reply); X if (!reply.good) X return; X X arVRefNum = reply.vRefNum; X arName = reply.fName; X if (OpenArchive(0)) /* Open for writing */ X return; X X if (setjmp(errJmp)) X goto done; X X /* X * Ask for directories to add to the archive. X * Note that this is WHOLE directories. X */ X while (GetDir("\Pto archive")) { X /* X * Get the catalog info for the selected directory. X */ X pathHead.next = NIL; X pb.ioCompletion = NIL; X pb.ioNamePtr = pathHead.name; X pb.ioVRefNum = dirVRefNum; X pb.u.hfi.ioDirID = dirDirID; X pb.ioFDirIndex = -1; X if (PBGetCatInfo(&pb, FALSE) != noErr) { X OSAlert("\PArCreate", "\PPBGetCatInfo", pathHead.name, X pb.ioResult); X break; X X } else { X /* X * Add the directory to the archive, X * while printing the files being added. X */ X if (WindInit()) X goto done; X X TextFace(underlineStyle); X WPrintf(header); X TextFace(0); X if ((cursor = GetCursor(watchCursor)) != NIL) X SetCursor(*cursor); X X DumpDir(&pb, &pathHead); X SetCursor(&arrow); X WindEnd(autoPage); X FlushEvents(everyEvent, 0); X } X X } X X WriteEot(); Xdone: X CloseArchive(); X} X X/* X * DumpDir - add a directory (possibly recursively) to the archive X * X * Exits via a longjmp on unrecoverable error X * Returns normally otherwise X */ XDumpDir(dir, path) XCInfoPBRec *dir; XPathInfo *path; X{ X union record *header; X int i; X CInfoPBRec pb; X WDPBRec wdpb; X PathInfo file; X char *routine = "\PDumpDir"; X EventRecord e; X X /* X * Output directory header record with permissions X * FIXME, do this AFTER files, to avoid R/O dir problems? X * If Unix Std format, don't put / on end of dir name X * If old archive format, don't write record at all. X */ X if (!oldArch) { X /* X * If people could really read standard archives, X * this should be: (FIXME) X * header = start_header(f_standard? p: namebuf, statbuf); X * but since they'd interpret LF_DIR records as X * regular files, we'd better put the / on the name. X */ X header = StartHeader(dir); X if (header == NIL) { X longjmp(errJmp, 1); X } X X if (standard) { X header->header.linkflag = LF_DIR; X } X X FinishHeader(header); /* Done with directory header */ X head = header; X PrintHeader(); X } X X /* X * Open this directory as a working directory so we can X * access files without the whole pathname (which might be too long). X */ X file.next = NIL; X path->next = &file; X wdpb.ioCompletion = NIL; X wdpb.ioNamePtr = NIL; X wdpb.ioVRefNum = dir->ioVRefNum; X wdpb.ioWDProcID = 'TAR '; X wdpb.ioWDDirID = dir->u.di.ioDrDirID; X if (PBOpenWD(&wdpb, FALSE) != noErr) { X OSAlert(routine, "\PPBOpenWD", NIL, wdpb.ioResult); X longjmp(errJmp, 1); X } X X /* X * Check all entries in the directory. X * Add regular files, recurse on subdirectories. X */ X pb.ioCompletion = NIL; X pb.ioNamePtr = file.name; X pb.ioVRefNum = wdpb.ioVRefNum; X for (i = 1; ; i++) { 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 pb.u.hfi.ioDirID = 0; X pb.ioFDirIndex = i; X if (PBGetCatInfo(&pb, FALSE) != noErr) { X if (pb.ioResult == fnfErr) X break; X X OSAlert(routine, "\PPBGetCatInfo", NIL, pb.ioResult); X longjmp(errJmp, 1); X } X X if ((unsigned char) file.name[0] > 32) { X /* X * Sanity check, we have overwritten our stack! X */ X PgmAlert(routine, "\PName too long", file.name, NIL); X longjmp(errJmp, 1); X } X X if (DIRECTORY(pb)) { X DumpDir(&pb, &file); X X } else { X if (pb.ioFRefNum == archive) { X /* X * DO NOT add the archive to itself! X */ X ArSkipAlert(); X continue; X } X X DumpFile(&pb, &file); X } X } X X /* X * Done with this directory, make sure we don't run out X * of working directories. X */ X PBCloseWD(&wdpb, FALSE); X path->next = NIL; X} X X/* X * DumpFile - Dump a single file. X * X * Exits via longjmp on unrecoverable error. X * Result is 1 for success, 0 for failure. X */ XDumpFile(file, path) XCInfoPBRec *file; XPathInfo *path; X{ X union record *header; X register char *p; X char *buf; X short f; /* File descriptor */ X HPrmBlkRec fpb; X long bufsize, count, i; X register long sizeleft; X register union record *start; X OSErr err; X char *routine = "\PDumpFile"; X X if ((header = StartHeader(file)) == NIL) X longjmp(errJmp, 1); X X FinishHeader(header); X /* X * Get the size of the file. X * Don't bother opening it if it is zero length. X */ X head = header; X hstat.st_size = file->u.hfi.ioFlLgLen; X PrintHeader(); X if ((sizeleft = file->u.hfi.ioFlLgLen) == 0) X return; X X fpb.ioCompletion = NIL; X fpb.ioNamePtr = file->ioNamePtr; X fpb.ioVRefNum = file->ioVRefNum; X fpb.u.hfp.ioDirID = 0; X fpb.u.iop.ioPermssn = fsRdPerm; X fpb.u.iop.ioMisc = NIL; X if (PBHOpen(&fpb, FALSE) != noErr) { X OSAlert(routine, "\PPBHOpen", file->ioNamePtr, fpb.ioResult); X longjmp(errJmp, 1); X } X X /* X * Dump the file to the archive. X * Note: this only dumps the data fork! X */ X while (sizeleft > 0) { X start = FindRec(); X bufsize = EndOfRecs()->charptr - start->charptr; X buf = start->charptr; X again: X count = (sizeleft < bufsize) ? sizeleft : bufsize; X fpb.u.iop.ioBuffer = buf; X fpb.u.iop.ioReqCount = count; X fpb.u.iop.ioPosMode = fsAtMark; X fpb.u.iop.ioPosOffset = 0; X if (PBRead(&fpb, FALSE) != noErr) { X OSAlert(routine, "\PPBRead", file->ioNamePtr, fpb.ioResult); X longjmp(errJmp, 1); X } X X count = fpb.u.iop.ioActCount; X if (cvtNl) { X /* X * Convert returns to newlines for Unix compat. X */ X for (i = count, p = buf; --i >= 0; p++) X if (*p == '\r') X *p = '\n'; X } X X sizeleft -= count; X UseRec(start + (count - 1) / RECORDSIZE); X } X PBClose(&fpb, FALSE); X X /* Clear last block garbage to zeros, FIXME */ X} X X X/* X * Make a header block for the file name whose stat info is st . X * Return header pointer for success, NULL if the name is too long. X */ Xunion record * XStartHeader(pb) XCInfoPBRec *pb; X{ X register union record *header; X Boolean directory = DIRECTORY(*pb); X X header = (union record *) FindRec(); X bzero(header->charptr, sizeof(union record)); /* XXX speed up */ X /* X * Generate the pathname, make sure we don't overflow X * the field in the tar header. X */ X if (FillName(header, directory)) { X char buf[NAMSIZ + 1]; X X buf[0] = NAMSIZ; X bcopy(header->header.name, &buf[1], NAMSIZ); X PgmAlert("\PStartHeader", "\PName too long", buf, NIL); X return(NIL); X } X X /* X * Fake the file mode, uid, gid. X * Convert from Mac based time to Unix based time. X */ X ToOct((directory) ? 0755L : 0644L, 8, header->header.mode); X ToOct(0L, 8, header->header.uid); X ToOct(0L, 8, header->header.gid); X ToOct((directory) ? 0L : pb->u.hfi.ioFlLgLen, 1+12, X header->header.size); X ToOct((directory) ? pb->u.di.ioDrMdDat - TIMEDIFF : X pb->u.hfi.ioFlMdDat - TIMEDIFF, X 1+12, header->header.mtime); X /* header->header.linkflag is left as null */ X return(header); X} X X/* X * Finish off a filled-in header block and write it out. X */ Xvoid XFinishHeader(header) Xregister union record *header; X{ X register int i; X register long sum; X register char *p; X X bcopy(CHKBLANKS, header->header.chksum, sizeof(header->header.chksum)); X X sum = 0; X p = header->charptr; X for (i = sizeof(union record); --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 /* X * Fill in the checksum field. It's formatted differently X * from the other fields: it has [6] digits, a null, then a X * space -- rather than digits, a space, then a null. X * We use to_oct then write the null in over to_oct's space. X * The final space is already there, from checksumming, and X * to_oct doesn't modify it. X * X * This is a fast way to do: X * (void) sprintf(header->header.chksum, "%6o", sum); X */ X ToOct((long) sum, 8, header->header.chksum); X header->header.chksum[6] = '\0'; /* Zap the space */ X UseRec(header); X return; X} X X X/* X * Quick and dirty octal conversion. X * Converts long "value" into a "digs"-digit field at "where", X * including a trailing space and room for a null. "digs"==3 means X * 1 digit, a space, and room for a null. X * X * We assume the trailing null is already there and don't fill it in. X * This fact is used by start_header and finish_header, so don't change it! X * X * This should be equivalent to: X * (void) sprintf(where, "%*lo ", digs-2, value); X * except that sprintf fills in the trailing null and we don't. X */ Xvoid XToOct(value, digs, where) Xregister long value; Xregister int digs; Xregister char *where; X{ X --digs; /* Trailing null slot is left alone */ X where[--digs] = ' '; /* Put in the space, though */ X X /* Produce the digits -- at least one */ X do { X where[--digs] = '0' + (value & 7); /* one octal digit */ X value >>= 3; X } while (digs > 0 && value != 0); X X /* Leading spaces, if necessary */ X while (digs > 0) X where[--digs] = ' '; X X} X X/* X * Write the EOT block(s). X */ XWriteEot() X{ X union record *p; X X p = FindRec(); X bzero(p->charptr, RECORDSIZE); X UseRec(p); X /* FIXME, only one EOT block should be needed. */ X p = FindRec(); X bzero(p->charptr, RECORDSIZE); X UseRec(p); X} X X/* X * FillName - generate the file or directory pathname X * X * Converts to Unix style pathnames. X * Appends a '/' for a directory. X */ XBoolean XFillName(header, directory) Xregister union record *header; XBoolean directory; X{ X register PathInfo *p; X char *q; X X q = header->header.name; X for (p = &pathHead; p != NIL; p = p->next) { X sprintf(q, "%.*s%c", p->name[0], &p->name[1], X (p->next == NIL) ? '\0' : '/'); X X q += p->name[0] + 1; X } X X if (directory) { X *(q - 1) = '/'; X *q = '\0'; X } X X return((q - header->header.name) > NAMSIZ); X} SHAR_EOF if test 10693 -ne "`wc -c < 'create.c'`" then echo shar: error transmitting "'create.c'" '(should have been 10693 characters)' fi fi # end of overwriting check echo shar: extracting "'dialog.c'" '(7050 characters)' if test -f 'dialog.c' then echo shar: will not over-write existing file "'dialog.c'" else sed 's/^X//' << \SHAR_EOF > 'dialog.c' X/* X * Macintosh Tar X * X * The routines in this file deal with the dialogs presented to the user. X * X * Written by Craig Ruff. X * X * Note that the dialog dealing with directory selection is in dir.c. X */ X X#include "tar.h" X#include <resource.h> X#include <segment.h> X X/* X * Dialog definitions X */ X#define aboutID 128 /* The "About ..." dialog */ X X#define blockID 129 /* The block size dialog */ X#define sizeItem 3 X X#define typeID 131 /* Creator/Type dialog */ X#define creatorItem 3 X#define typeItem 4 X X/* X * Alert Definitions X */ X#define badBlockID 129 /* Block size incorrect alert */ X#define osErrID 130 /* Generic OS Error alert */ X#define pgmErrID 131 /* Program logic error alert */ X#define hfsID 132 /* Must run under HFS alert */ X#define askipID 133 /* Skipping archive file note */ X#define stkErrID 134 /* Stack error alert */ X X/* X * AboutFilter - manage the "About ..." dialog X * X * Returns when the mouse or a key is pressed anywhere. X */ Xpascal Boolean XAboutFilter(theDialog, theEvent, itemHit) XDialogPtr theDialog; XEventRecord *theEvent; Xshort *itemHit; X{ X switch (theEvent->what) { X case keyDown: X case mouseDown: X *itemHit = 1; X return(TRUE); X break; X X default: X return(FALSE); X break; X } X} X X/* X * DoAboutBox - put the "About ..." dialog on the screen X */ XDoAboutBox() { X int itemHit; X WindowPtr myWindow; X X myWindow = GetNewDialog(aboutID, NIL, (WindowPtr) -1); X do { X ModalDialog(AboutFilter, &itemHit); X } while (itemHit != 1); X DisposDialog(myWindow); X} X X/* X * ValidBlockSize - checks the user entered blocksize for validity. X * X * Returns TRUE if ok, FALSE if bad. X */ XBoolean XValidBlockSize(theDialog) XDialogPtr theDialog; X{ X long n; X short type; X Handle hdl; X Rect box; X char text[256]; X X GetDItem(theDialog, sizeItem, &type, &hdl, &box); X GetIText(hdl, text); X StringToNum(text, &n); X X /* X * These limits are somewhat arbitrary. X */ X if ((n < 1) || (n > 128)) { X NoteAlert(badBlockID, NIL); X SelIText(theDialog, sizeItem, 0, 32767); X return(FALSE); X } X X blocking = (int) n; X blockSize = blocking * RECORDSIZE; X return(TRUE); X} X XRect okBox; /* ok Box location (gotten once for speed) */ XControlHandle okHdl; /* ok Box handle */ X X/* X * BlockFilter - manage user events during the block size dialog X * X * Allows numeric entry and editing, validates size. X * Returns TRUE if the dialog should exit, FALSE to continue. X */ Xpascal Boolean XBlockFilter(theDialog, theEvent, itemHit) XDialogPtr theDialog; XEventRecord *theEvent; Xshort *itemHit; X{ X long t; X Point lpt; X GrafPtr savedPort; X X switch (theEvent->what) { X case keyDown: X switch ((char) (theEvent->message & charCodeMask)) { X case RETURN: X case ENTER: X goto validate; X break; X X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X case TAB: case BS: X break; X X default: X SysBeep(5); X theEvent->what = nullEvent; X break; X } X break; X X case mouseDown: X pass(lpt) = pass(theEvent->where); X GetPort(&savedPort); X SetPort((GrafPtr) theDialog); X GlobalToLocal(&lpt); X SetPort(savedPort); X if (PtInRect(pass(lpt), &okBox)) { Xvalidate: if (ValidBlockSize(theDialog)) { X *itemHit = OK; X HiliteControl(okHdl, 1); X Delay(8L, &t); X HiliteControl(okHdl, 0); X return(TRUE); X } else X theEvent->what = nullEvent; X } X break; X } X X return(FALSE); X} X X/* X * CreatorTypeFilter - manage user events during the Creator/Type dialog X * X */ Xpascal Boolean XCreatorTypeFilter(theDialog, theEvent, itemHit) XDialogPtr theDialog; XEventRecord *theEvent; Xshort *itemHit; X{ X short type; X Handle hdl; X Rect box; X char text[256]; X int n; X long t; X Point lpt; X GrafPtr savedPort; X X switch (theEvent->what) { X case keyDown: X switch ((char) (theEvent->message & charCodeMask)) { X case RETURN: X case ENTER: X goto done; X break; X X default: X break; X } X break; X X case mouseDown: X pass(lpt) = pass(theEvent->where); X GetPort(&savedPort); X SetPort((GrafPtr) theDialog); X GlobalToLocal(&lpt); X SetPort(savedPort); X if (PtInRect(pass(lpt), &okBox)) { Xdone: X GetDItem(theDialog, creatorItem, &type, &hdl, &box); X GetIText(hdl, text); X n = (unsigned char) text[0]; X if (n > 4) X n = 4; X X strncpy(fdCreator, &text[1], n); X GetDItem(theDialog, typeItem, &type, &hdl, &box); X GetIText(hdl, text); X n = (unsigned char) text[0]; X if (n > 4) X n = 4; X X strncpy(fdType, &text[1], n); X *itemHit = OK; X HiliteControl(okHdl, 1); X Delay(8L, &t); X HiliteControl(okHdl, 0); X return(TRUE); X } X break; X } X X return(FALSE); X} X X/* X * DoBlockSize - put the block size dialog on the screen X * X * Puts the current block size into the edit field. X */ XDoBlockSize() { X int itemHit; X DialogPtr theDialog; X Handle hdl; X short type; X Rect box; X char text[256]; X X theDialog = GetNewDialog(blockID, NIL, (WindowPtr) -1); X GetDItem(theDialog, sizeItem, &type, &hdl, &box); X NumToString((long) blocking, text); X SetIText(hdl, text); X SelIText(theDialog, sizeItem, 0, 32767); X GetDItem(theDialog, OK, &type, &okHdl, &okBox); X do { X ModalDialog(BlockFilter, &itemHit); X } while ((itemHit != OK) && (itemHit != Cancel)); X DisposDialog(theDialog); X} X X/* X * DoCreatorType - put the set Creator/Type dialog on the screen X * X * Puts the current Creator and Type into the edit field. X */ XDoCreatorType() { X int itemHit; X DialogPtr theDialog; X Handle hdl; X short type; X Rect box; X char text[256]; X X theDialog = GetNewDialog(typeID, NIL, (WindowPtr) -1); X GetDItem(theDialog, creatorItem, &type, &hdl, &box); X text[0] = 4; X strncpy(&text[1], fdCreator, 4); X SetIText(hdl, text); X GetDItem(theDialog, typeItem, &type, &hdl, &box); X text[0] = 4; X strncpy(&text[1], fdType, 4); X SetIText(hdl, text); X SelIText(theDialog, creatorItem, 0, 32767); X GetDItem(theDialog, OK, &type, &okHdl, &okBox); X do { X ModalDialog(CreatorTypeFilter, &itemHit); X } while ((itemHit != OK) && (itemHit != Cancel)); X X DisposDialog(theDialog); X} X X/* X * OSAlert - put a generic OS Error Alert on the screen X * X * Used for errors not handled in another way (yet). X */ XOSAlert(p0, p1, p2, err) Xchar *p0, *p1, *p2; XOSErr err; X{ X char buf[256]; X X /* X * Manage the contingency of being called for resources missing! X */ X if (GetResource('ALRT', osErrID) == NIL) { X GrafPtr wmPort; X long t; X Rect r; X X GetWMgrPort(&wmPort); X SetPort(wmPort); X SetRect(&r, 140, 150, 360, 180); X EraseRect(&r); X MoveTo(150,170); X DrawString("\PPANIC! Resources Missing!"); X Delay(600L, &t); X ExitToShell(); X } X X NumToString((long) err, buf); X ParamText(p0, p1, p2, buf); X StopAlert(osErrID, NIL); X} X X/* X * PgmAlert - put a program logic alert on the screen X */ XPgmAlert(p0, p1, p2, p3) Xchar *p0, *p1, *p2, *p3; X{ X ParamText(p0, p1, p2, p3); X StopAlert(pgmErrID, NIL); X} X X/* X * HFSAlert - put a "HFS only" alert on the screen X */ XHFSAlert() { X StopAlert(hfsID, NIL); X} X X/* X * ArSkipAlert - put a "skipping archive file" note on the screen X */ XArSkipAlert() { X NoteAlert(askipID, NIL); X} X X/* X * StkErrAlert - put a stack corrupted alert on the screen X */ XStkErrAlert() { X StopAlert(stkErrID, NIL); X ExitToShell(); X} SHAR_EOF if test 7050 -ne "`wc -c < 'dialog.c'`" then echo shar: error transmitting "'dialog.c'" '(should have been 7050 characters)' fi fi # end of overwriting check echo shar: extracting "'dir.c'" '(11757 characters)' if test -f 'dir.c' then echo shar: will not over-write existing file "'dir.c'" else sed 's/^X//' << \SHAR_EOF > 'dir.c' X/* X * Macintosh Tar X * X * dir.c - routines dealing with directory selection X * X * Written by Craig Ruff X */ X X#include "tar.h" X X#define ROOTDIR 2 /* WATCH OUT! Subject to change? */ X X#define dirID 130 /* Directory selection dialog */ X#define selectItem 1 /* Use this directory */ X#define vnameItem 3 /* Volume name */ X#define boxItem 6 /* Directory list box */ X#define lineItem 7 /* User line item */ X#define upItem 8 /* Go to parent directory */ X#define openItem 9 /* Open a subdirectory */ X#define driveItem 11 /* Select drive item */ X#define ejectItem 12 /* Eject disk item */ X XListHandle dirList; /* Current directory list */ XRect dirListRect; /* Where is the list displayed? */ Xshort dirVRefNum; /* Selected directory VRefNum */ Xlong dirDirID; /* Selected directory DirID */ XRect selectRect; /* Rectangle of selectItem */ Xshort volIndex; /* Current volume index (for driveItem) */ XBoolean ejectable; /* Is the current volume ejectable? */ XPoint lineLeft; XPoint lineRight; X X/* X * DirFilter - handle events for the select directory dialog X * X * Returns TRUE if button pressed, FALSE if to continue X */ Xpascal Boolean XDirFilter(theDialog, theEvent, itemHit) XDialogPtr theDialog; XEventRecord *theEvent; Xshort *itemHit; X{ X long t; X Point lpt; X GrafPtr savedPort; X X switch (theEvent->what) { X case keyDown: X /* X * Default button for return or enter is Select X */ X if (((t = theEvent->message & charCodeMask) == RETURN) || X (t == ENTER)) { X *itemHit = selectItem; X return(TRUE); X } X break; X X case mouseDown: X /* X * If we get a click in the directory list, send X * it to the list manager, then pretend we got an X * open button press. X */ X GetPort(&savedPort); X SetPort(theDialog); X pass(lpt) = pass(theEvent->where); X GlobalToLocal(&lpt); X SetPort(savedPort); X if (PtInRect(pass(lpt), &dirListRect)) { X if (LClick(pass(lpt), theEvent->modifiers, dirList)) { X *itemHit = openItem; X return(TRUE); X } X theEvent->what = nullEvent; X } X break; X } X X return(FALSE); X} X X/* X * DirListProc - handle user defined redrawing of the dialog X */ Xpascal XDirListProc(theDialog, itemNo) XDialogPtr theDialog; Xshort itemNo; X{ X Rect r; X PenState pn; X X /* X * Highlight the default choice for return or enter, "Select". X */ X GetPenState(&pn); X PenSize(3, 3); X SetRect(&r, selectRect.left - 4, selectRect.top - 4, X selectRect.right + 4, selectRect.bottom + 4); X FrameRoundRect(&r, 16, 16); X X /* X * Draw the line separating Drive and Eject from Cancel and Open X */ X PenSize(1,1); X MoveTo(lineLeft.h, lineLeft.v); X LineTo(lineRight.h, lineRight.v); X SetPenState(&pn); X X /* X * Put a box around the directory list. X * Do not erase the scroll bar on the right. X * Then tell the list manager to update. X */ X SetRect(&r, dirListRect.left - 1, dirListRect.top - 1, X dirListRect.right + 1, dirListRect.bottom + 1); X FrameRect(&r); X SetRect(&r, dirListRect.left, dirListRect.top, X dirListRect.right - 15, dirListRect.bottom); X EraseRect(&r); X LUpdate(theDialog->visRgn, dirList); X} X X/* X * FillDirList - get all of the subdirectory names in this directory X * X * Returns TRUE if an error was found, FALSE otherwise. X */ XBoolean XFillDirList(dir, parent, dname) Xlong dir; Xlong *parent; Xchar *dname; X{ X short i, index; X CInfoPBRec pb; X WDPBRec wdpb; X char name[64]; X Point cell; X char *routine = "\PFillDirList"; X X /* X * Open this directory to get the catalog info. X */ X wdpb.ioCompletion = NIL; X wdpb.ioNamePtr = NIL; X wdpb.ioVRefNum = dirVRefNum; X wdpb.ioWDProcID = 'TAR '; X wdpb.ioWDDirID = dir; X if (PBOpenWD(&wdpb, FALSE) != noErr) { X OSAlert(routine, "\PPBOpenWD", NIL, wdpb.ioResult); X return(TRUE); X } X X /* X * We will get this directory's name for the select button. X */ X pb.ioCompletion = NIL; X pb.ioNamePtr = dname; X pb.ioVRefNum = dirVRefNum; X pb.u.hfi.ioDirID = dir; X pb.ioFDirIndex = -1; X if (PBGetCatInfo(&pb, FALSE) != noErr) { X OSAlert(routine, "\PPBGetCatInfo(1)", NIL, pb.ioResult); X return(TRUE); X } X X /* X * Save the parent's DirID. X * Loop until all directories have been found. X */ X *parent = pb.u.di.ioDrParID; X pb.ioNamePtr = name; X pb.ioVRefNum = wdpb.ioVRefNum; X for (i = 1, index = 0; ; i++) { X pb.u.hfi.ioDirID = 0; X pb.ioFDirIndex = i; X if (PBGetCatInfo(&pb, FALSE) != noErr) { X if (pb.ioResult == fnfErr) X break; X X OSAlert(routine, "\PPBGetCatInfo(2)", NIL, pb.ioResult); X return(TRUE); X } X X if (!DIRECTORY(pb)) X continue; X X /* X * Add another row to the list if we are beyond the end X * of the current list. X * Remember the DirID for possible later selection. X */ X if (index >= (**dirList).dataBounds.bottom) X (void) LAddRow(1, index, dirList); X X cell.h = 0; X cell.v = index++; X LSetCell(&name[1], (unsigned char) name[0], pass(cell), dirList); X cell.h = 1; X LSetCell(&pb.u.di.ioDrDirID, sizeof(long), pass(cell), dirList); X } X X /* X * Make sure we're not left in never-never land when X * the directory list is redisplayed. X * Free up any unused list rows. X */ X LScroll(-9999, -9999, dirList); X if (index < (**dirList).dataBounds.bottom) X LDelRow((**dirList).dataBounds.bottom - index, index, dirList); X X PBCloseWD(&wdpb, FALSE); X} X X/* X * IsEjectable - check if a volume is ejectable X * X * Returns TRUE or FALSE. X * X * I think there should be an easier way to do this! Like an additional X * flag in the GetVInfo call or something. X */ XBoolean XIsEjectable(volpb) XHPrmBlkPtr volpb; X{ X int drvnum = volpb->u.hvp.ioVDrvInfo; X QHdrPtr drvq; X struct DrvQEl *drv; X X /* X * This volume is not in a drive! Therefore is already ejected! X */ X if (drvnum == 0) X return(FALSE); X X /* X * Search the drive queue for our volume's drive. X * Check the hidden flags. Talk about hidden! X */ X drvq = GetDrvQHdr(); X for (drv = (struct DrvQEl *) drvq->qHead; X drv != (struct DrvQEl *) drvq->qTail; X drv = drv->qLink) X if (drv->dQDrive == drvnum) X break; X X if ((drv == (struct DrvQEl *) drvq->qTail) && (drv->dQDrive != drvnum)) X return(FALSE); X X return ((((long *) drv)[-1] & 0x80000) ? FALSE : TRUE); X} X X#define SysMap (*(short *) 0xa58) X X/* X * DirInit - set up some stuff for the dialog X * X * Returns TRUE if an error was found, FALSE otherwise. X */ XDirInit(vName) Xchar *vName; X{ X char *routine = "\PDirInit"; X WDPBRec pb; X HPrmBlkRec volpb; X OSErr err; X X /* X * Find out where we are currently. X */ X pb.ioCompletion = NIL; X pb.ioNamePtr = NIL; X if (PBHGetVol(&pb, FALSE) != noErr) { X OSAlert(routine, "\PPBHGetVol", NIL, pb.ioResult); X return(TRUE); X } X X /* X * Remember that, and figure out which volume index is ours. X */ X dirVRefNum = pb.ioWDVRefNum; X dirDirID = pb.ioWDDirID; X for (volIndex = 1; ; volIndex++) { X volpb.ioCompletion = NIL; X volpb.ioNamePtr = vName; X volpb.ioVRefNum = NIL; X volpb.u.hvp.ioVolIndex = volIndex; X if ((err = PBHGetVInfo(&volpb, FALSE)) != noErr) { X OSAlert(routine, "\PPBHGetVInfo", X (err == nsvErr) ? X "\PCould not find default volume" : X NIL, X volpb.ioResult); X return(TRUE); X } X X if (volpb.ioVRefNum == pb.ioWDVRefNum) { X ejectable = IsEjectable(&volpb); X break; X } X } X X return(FALSE); X} X X/* X * GetNextVol - get the next volume in the volume list (for the drive button) X * X * Returns the volume reference number. X */ Xshort XGetNextVol(vName) Xchar *vName; X{ X HPrmBlkRec volpb; X int found = FALSE; X X do { X volpb.ioCompletion = NIL; X volpb.ioNamePtr = vName; X volpb.ioVRefNum = NIL; X volpb.u.hvp.ioVolIndex = ++volIndex; X PBHGetVInfo(&volpb, FALSE); X if (volpb.ioResult == nsvErr) { X /* X * Reached the end of the list, start again. X */ X volIndex = 0; X continue; X X } X X if (volpb.ioResult != noErr) { X OSAlert("\PGetNextVol", "\PPBHGetVInfo", NIL, X volpb.ioResult); X return(-32768); X } X X if (volpb.u.hvp.ioVSigWord != 0x4244) X continue; /* Ignore non-HFS volumes */ X X found = TRUE; X ejectable = IsEjectable(&volpb); X } while (!found); X X return(volpb.ioVRefNum); X} X X/* X * GetDir - manage the directory selection dialog X */ XBoolean XGetDir(text) Xchar *text; X{ X short itemHit; X DialogPtr theDialog; X Handle dhdl, vhdl; X ControlHandle ehdl; X short len, type; X Rect dataBounds, r; X Point cell, size; X long parent; X GrafPtr savedPort; X char dirName[32], volName[32]; X Boolean selection; X char *routine = "\PGetDir"; X ParamBlkRec pb; X X /* X * Read in the selection dialog. X * Set the function specific message. X */ X theDialog = GetNewDialog(dirID, NIL, (WindowPtr) -1); X ParamText(text, NIL, NIL, NIL); X X /* X * Get the directory list information. X * We have all the user item drawing done when the list is updated too. X * The list boundaries are setup. Leave room for the scroll bar. X * Only one column of the list is displayed. The other is used X * to save the DirID. X */ X GetDItem(theDialog, boxItem, &type, &dhdl, &dirListRect); X SetDItem(theDialog, boxItem, type, (Handle) DirListProc, &dirListRect); X dataBounds.top = dataBounds.left = 0; X dataBounds.bottom = 0; X dataBounds.right = 2; X dirListRect.right -= 15; X size.h = dirListRect.right - dirListRect.left; X size.v = 0; X dirList = LNew(&dirListRect, &dataBounds, pass(size), 0, theDialog, X FALSE, FALSE, FALSE, TRUE); X if (dirList == NIL) { X PgmAlert(routine, "\PLNew NIL return", NIL, NIL); X itemHit = 0; X goto done; X } X X /* X * Ok, now include the scroll bar when the mouse is pressed (later). X * Only allow a single directory to be selected at a time. X */ X dirListRect.right += 15; X (**dirList).selFlags = lOnlyOne; X if (DirInit(volName)) { X itemHit = 0; X goto done; X } X X /* X * Save the control handles for "Eject" and the volume name X * for either enabling/disabling and name setting respectively. X * Save the control handle for the "Select" button so the X * current directory's name can be put into it. X */ X GetDItem(theDialog, lineItem, &type, &ehdl, &r); X lineLeft.h = r.left; X lineRight.v = lineLeft.v = r.top; X lineRight.h = r.right; X GetDItem(theDialog, ejectItem, &type, &ehdl, &r); X GetDItem(theDialog, vnameItem, &type, &vhdl, &r); X SetIText(vhdl, volName); X GetDItem(theDialog, selectItem, &type, &dhdl, &selectRect); X ShowWindow(theDialog); X cell.v = 0; X X /* X * Wait until either the user selects a directory or cancels. X */ X do { X /* X * Don't update the list on the screen while filling it. X * This looks sloppy. X */ X LDoDraw(FALSE, dirList); X if (FillDirList(dirDirID, &parent, dirName)) { X itemHit = 0; X goto done; X } X X LDoDraw(TRUE, dirList); X SetCTitle((ControlHandle) dhdl, dirName); X HiliteControl(ehdl, ejectable ? 0 : 255); X X /* X * Make sure the directory list IS redrawn. X */ X GetPort(&savedPort); X SetPort(theDialog); X InvalRect(&theDialog->portRect); X SetPort(savedPort); X X /* X * No directory is selected initially. X */ X cell.h = 0; X LSetSelect(FALSE, pass(cell), dirList); X ModalDialog(DirFilter, &itemHit); X cell.v = 0; X X /* X * See if anything was really selected. X */ X selection = LGetSelect(TRUE, &cell, dirList); X switch (itemHit) { X case openItem: X if (!selection) X break; X X /* X * Ok, use this directory now. X */ X cell.h = 1; X len = sizeof(dirDirID); X LGetCell(&dirDirID, &len, pass(cell), dirList); X break; X X case upItem: X if (dirDirID == ROOTDIR) X break; X X dirDirID = parent; X break; X X case driveItem: X case ejectItem: X dirDirID = ROOTDIR; X if ((dirVRefNum = GetNextVol(volName)) == 0) X return(FALSE); X X SetIText(vhdl, volName); X if (itemHit == driveItem) X break; X X pb.ioCompletion = NIL; X pb.ioNamePtr = NIL; X pb.ioVRefNum = dirVRefNum; X if (PBEject(&pb, FALSE) != noErr) X OSAlert(routine, "\PPBEject", NIL, pb.ioResult); X X break; X } X } while ((itemHit != selectItem) && (itemHit != Cancel)); X Xdone: X LDispose(dirList); X DisposDialog(theDialog); X return((itemHit == selectItem) ? TRUE : FALSE); X} SHAR_EOF if test 11757 -ne "`wc -c < 'dir.c'`" then echo shar: error transmitting "'dir.c'" '(should have been 11757 characters)' fi fi # end of overwriting check # End of shell archive exit 0 --- end of part 2 ---
cruff@ncar.ucar.edu (Craig Ruff) (05/14/88)
[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 ---