home *** CD-ROM | disk | FTP | other *** search
- /*
- File: unshar.c
-
- Contains: unshar for MPW that's good enough for
- comp.sources.unix archives
-
- Written by: sw
- Network Analysis Ltd
- 178 Wainbody Ave South
- Coventry CV3 6BX
- UK
- Phone: +44 203 419996
- E-mail: sw@network-analysis-ltd.co.uk
-
- Copyright: Public domain
-
- Change History (most recent first):
-
- <9> 18/11/91 sw Changes to compile with TC 5.0.
- <8> 18/11/91 sw Deal with embedded "cd"s
- <7> 19/5/91 sw Remove tests for "if"s and make less sensitive to
- variations in shar file formats. Also stop
- looking for #! /bin/sh; any comment line will do.
- Merge MPW and Think C vers into 1 src file.
- <6> 16/5/91 sw Handle shar files in sumex archives.
- <5> 3/5/91 sw Previous mod didn't get the last char of the
- filename.
- <4> 3/5/91 sw Cope with shar files that do not quote the
- filename in the "if test -f" line.
- <3> 3/2/91 sw Pick up terminating string from "sed" or "cat"
- command line.
- <2> 5/7/90 sw Reconvert to MPW tool
- <1> ?????? aw Original by Amanda Walker, Intercon
-
- To Do:
- */
- #ifdef MPW
- #include <Types.h>
- #include <StdDef.h>
- #include <Files.h>
- #include <CursorCtl.h>
- #include <StdLib.h>
- #endif MPW
- #include <errno.h>
- #include <stdio.h>
- #include <String.h>
- #ifndef NIL
- #define NIL (0L)
- #endif
-
- /* Strings used in error messages */
- #ifdef MPW
- #define CPSTR c2pstr
- #define PCSTR p2cstr
- #else
- #define CPSTR CtoPstr
- #define PCSTR PtoCstr
- #endif
-
- #ifndef EOF
- #define EOF (-1L)
- #endif
-
- #ifndef MPW
- /* for Think C
- */
-
- /* if using new Think C headers, uncomment the following line, otherwise
- use the line after that. Only one of the following pair of lines should be used
- */
- #define LOWMEM_LONG(lowMemVar) (*((long *)lowMemVar)) /* use this if new-style TC headers */
- /*
- #define LOWMEM_LONG(lowMemVar) (lowMemVar) /* use this if old-style TC headers */
-
- #define DIRECTORY(pb) (((pb).dirInfo.ioFlAttrib & 0x10) == 0x10)
- #define getDir 11 /* buttons in the dialogue box */
- #define getCurDir 12
- #define GD_PROMPT 13
-
- typedef enum
- {
- infoDlgRes = 1000,
- aboutAlrtRes, /* About... alert resource number */
- abortRes,
- gdDlgRes,
- typeDlgRes,
- errorAlertRes,
- dupFNAlertRes
- };
-
-
- typedef enum /* File menu item numbers */
- {
- extract = 1,
- close,
- quit
- };
-
-
- typedef enum /* Edit menu item numbers */
- {
- undo = 1,
- /* --- */
- cut = 3,
- copy,
- paste,
- clear
- };
-
- typedef enum /* Option menu item numbers */
- {
- forceOpt = 1,
- setCr
- };
-
- typedef enum /* dialog item numbers */
- {
- okB = 1,
- crText,
- cancelB
- };
-
- typedef enum
- {
- continueB = 1,
- quitB,
- messageItem
- };
-
- MenuHandle fileM, editM, optM;
- short dirVRefNum = 0;
- char *progname;
- short appFileCount,
- whatToDo;
- DialogPtr infoDlgPtr, typeDlgPtr;
-
- #endif /* Think C declarations */
-
- Boolean force = false; /* force overwriting existing files */
- OSType fdCreator = 'MPS '; /* Finder Creator */
- OSType fdType = 'TEXT'; /* Finder Type */
-
- void ErrMsg (char *p1, char *p2);
- /* for display errors */
- void ConvertFName (char *unixfilename, char *mpwfilename);
- /* for converting Unix->Mac filenames */
- void unshar(char *s); /* the guts of the program */
-
- #ifndef MPW
- /* Prototypes for Think C standalone version */
- void SetDText(DialogPtr dlog, int item, Str255 str);
- void GetDText(DialogPtr dlog, int item, StringPtr str);
- void GetCreator(void);
- void DoFileMenu(int item);
- void DoEditMenu(int item);
- void DoOptMenu(int item);
- void DoAbout(void);
- pascal short DirSelHook(int item, DialogPtr theDialog);
- pascal Boolean DirFilterProc(CInfoPBPtr pb);
- long GetDir(char *text);
- void GetNextFile(SFReply *fInfoPtr);
- void Extract(void);
-
-
- void SetDText(DialogPtr dlog, int item, Str255 str)
- {
- Handle itemHandle;
- short itemType;
- Rect itemRect;
-
- GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
- SetIText (itemHandle, str);
- }
-
- /* Dialog handler */
-
- void GetDText(DialogPtr dlog, int item, StringPtr str)
- {
- Handle itemHandle;
- short itemType;
- Rect itemRect;
-
- GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
- GetIText (itemHandle, str);
- }
-
-
- void GetCreator(void)
- {
- short itemHit;
- char creator[5];
-
- typeDlgPtr = GetNewDialog (typeDlgRes, NIL, (WindowPtr) -1L);
- BlockMove(&fdCreator, creator+1, 4);
- creator[0] = '\004';
- SetDText(typeDlgPtr, crText, (StringPtr)creator);
- SelectWindow(typeDlgPtr);
- ShowWindow(typeDlgPtr);
- DrawDialog(typeDlgPtr);
- ModalDialog(NIL, &itemHit);
- if (itemHit == okB) {
- GetDText (typeDlgPtr, crText,(StringPtr) &creator);
- BlockMove(creator+1, &fdCreator, 4);
- }
- DisposDialog(typeDlgPtr);
- }
-
-
- /*
- File menu handler
- */
-
- void DoFileMenu(int item)
- {
- WindowPeek wPeek;
-
- switch (item)
- {
- case extract:
- Extract();
- break;
- case close:
- if ((wPeek = (WindowPeek) FrontWindow ()) != NIL)
- {
- if (wPeek->windowKind < 0)
- CloseDeskAcc (wPeek->windowKind);
- }
- break;
- case quit:
- SkelWhoa ();
- break;
- }
- }
-
-
- void DoEditMenu(int item)
- {
- DialogPtr theDialog;
-
- theDialog = (DialogPtr) FrontWindow ();
- if (((WindowPeek) theDialog)->windowKind != dialogKind)
- return;
-
- switch (item)
- {
- case cut:
- {
- DlgCut (theDialog);
- (void) ZeroScrap ();
- (void) TEToScrap ();
- break;
- }
-
- case copy:
- {
- DlgCopy (theDialog);
- (void) ZeroScrap ();
- (void) TEToScrap ();
- break;
- }
-
- case paste:
- {
- (void) TEFromScrap ();
- DlgPaste (theDialog);
- break;
- }
-
- case clear:
- {
- DlgDelete (theDialog);
- break;
- }
- }
- }
-
- void DoOptMenu(item)
- int item;
- {
- switch (item)
- {
- case forceOpt: force = !force;
- CheckItem(optM, forceOpt, force);
- break;
- case setCr: GetCreator();
- break;
- }
- }
-
- /*
- Handle selection of About╔ item from Apple menu
- */
-
- void DoAbout(void)
- {
- (void) Alert (aboutAlrtRes, NIL);
- }
-
- Boolean useCurDir; /* Set if current dir to be used */
-
- /* Filter procs & dialogue hooks to select directories only in SFGet file */
- pascal short DirSelHook(int item, DialogPtr theDialog)
- {
- if (item == getDir|| item == getCurDir) {
- /* folder selected */
- useCurDir = item == getCurDir;
- item = getOpen;
- }
- return(item);
- }
-
- pascal Boolean DirFilterProc(CInfoPBPtr pb)
- {
- return(!DIRECTORY(*pb)); /* a directory if bit 4 is set */
- }
- /*
- * GetDir - manage the directory selection dialog
- */
- long GetDir(char *text)
- {
- Point where;
- short ht, wd;
- SFReply reply = {0};
- CInfoPBRec pb;
- DialogPtr dlgP;
- long dirDirID=0; /* Selected directory DirID */
-
- if ((dlgP = GetNewDialog(gdDlgRes, NIL,(WindowPtr) -1)) == NIL) {
- return(TRUE);
- }
- wd = (dlgP->portRect.right)-(dlgP->portRect.left);
- ht = (dlgP->portRect.bottom)-(dlgP->portRect.top);
- /* centre the dialogue box on the screen
- (but how do I know which screen?)
- */
- where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
- where.v = (screenBits.bounds.bottom-screenBits.bounds.top-ht) / 2;
- ParamText((StringPtr)text, (StringPtr)"\p", (StringPtr)"\p", (StringPtr)"\p");
- SFPGetFile (where,
- (StringPtr)text,
- (FileFilterProcPtr) DirFilterProc,
- -1, NIL,
- (DlgHookProcPtr) DirSelHook,
- &reply,
- gdDlgRes, NIL);
- if (reply.good) {
- dirVRefNum = reply.vRefNum;
- if (useCurDir) {
- dirDirID = *((long *)CurDirStore);
- }
- else {
- dirDirID = (long)(reply.fType);
- }
- }
- return(dirDirID);
- }
-
- void GetNextFile(SFReply *fInfoPtr)
- { AppFile nextFile;
- static short idx=1;
-
- GetAppFiles(idx++, &nextFile);
- fInfoPtr->vRefNum = nextFile.vRefNum;
- fInfoPtr->fType = nextFile.fType;
- fInfoPtr->version = nextFile.versNum;
- BlockMove(nextFile.fName, fInfoPtr->fName, (int)(nextFile.fName[0]+1));
- appFileCount--;
- }
-
- void Extract(void)
- {
- Point where;
- SFReply reply;
-
- while (1){
- if (appFileCount > 0) GetNextFile(&reply);
- else {
- /*
- * Use the standard file dialog to select the archive.
- */
- where.h = where.v = 75;
- SFGetFile(where, (StringPtr)"\pSelect shar file", NIL, -1, NIL, NIL, &reply);
- if (!reply.good)
- return;
- }
-
- /*
- * Remember the VRefNum and Name for OpenArchive.
- * Find out where to put the extracted files.
- */
- (void) SetVol(NIL, reply.vRefNum);
- PtoCstr(reply.fName);
- unshar((char *)reply.fName);
- (void) SetVol(NIL, reply.vRefNum);
- }
- }
-
- main(int argc, char *argv[])
- {
-
- Handle fTypeH;
- DialogTHndl dlgH;
- Point where;
- short ht, wd;
-
- SkelInit (3, NIL);
- SkelApple ("\pAbout Unshar╔", DoAbout);
-
- fileM = NewMenu (1000, (StringPtr)"\pFile");
- AppendMenu (fileM, (StringPtr)"\pExtract/O;Close/K;Quit/Q");
- SkelMenu (fileM, DoFileMenu, NIL, FALSE);
-
- editM = NewMenu (1001, (StringPtr)"\pEdit");
- AppendMenu (editM, (StringPtr)"\p(Undo/Z;(-;Cut/X;Copy/C;Paste/V;Clear");
- SkelMenu (editM, DoEditMenu, NIL, FALSE);
-
- optM = NewMenu (1002, (StringPtr)"\pOptions");
- AppendMenu (optM, (StringPtr)"\pOverwrite existing files;File type...");
- SkelMenu (optM, DoOptMenu, NIL, TRUE);
-
- CountAppFiles (&whatToDo, &appFileCount);
- if ((fTypeH = (char **)GetResource('ftyp', 0)) == NIL) {
- ExitToShell();
- }
- BlockMove(*fTypeH, &fdCreator, 4);
- BlockMove((*fTypeH)+4, &fdType, 4);
- ReleaseResource(fTypeH);
-
- CouldDialog(typeDlgRes);
- CouldDialog(infoDlgRes);
- dlgH = (DialogTHndl)GetResource('DLOG', typeDlgRes);
- wd = ((* dlgH)->boundsRect.right)-((* dlgH)->boundsRect.left);
- /* centre the dialogue box on the screen
- (but how do I know which screen?)
- */
- where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
- (* dlgH)->boundsRect.right += where.h;
- (* dlgH)->boundsRect.left = where.h;
-
- dlgH = (DialogTHndl)GetResource('DLOG', infoDlgRes);
- wd = ((* dlgH)->boundsRect.right)-((* dlgH)->boundsRect.left);
- /* centre the dialogue box on the screen
- (but how do I know which screen?)
- */
- where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
- (* dlgH)->boundsRect.right += where.h;
- (* dlgH)->boundsRect.left = where.h;
-
- /* if launched with a set of files, extract them first before asking
- the user for more
- */
- if (appFileCount > 0)
- Extract();
- SkelMain ();
- SkelClobber ();
- FreeDialog(typeDlgRes);
- FreeDialog(infoDlgRes);
- }
- #else /* MPW main support routines */
-
- main(int argc, char *argv[])
- {
- char **filelist; /* list of files to process */
- int fileCount = 0; /* no of files to process */
-
- #ifdef MPW
- InitCursorCtl(nil);
- #endif MPW
- argc--; argv++;
- if ((filelist = (char **)calloc((size_t)argc, sizeof(Ptr))) == NULL) {
- fprintf(stderr, "### Not enough memory\n");
- exit(-1);
- }
- while (argc) {
- if (argv[0][0] == '-') {
- switch (argv[0][1]) {
- case '\0':
- filelist[fileCount++] = "-";
- break;
- case 'c':
- /* creator is in next arg */
- argc--;
- argv++;
- strncpy((char *)&fdCreator, argv[0], (size_t)4);
- break;
- case 'f':
- force = true;
- break;
- case 't':
- /* type is in next arg */
- argc--;
- argv++;
- strncpy((char *)&fdType, argv[0], (size_t)4);
- break;
- default:
- fprintf(stderr, "### Usage: unshar -f -c creator -t type [files|-]\n");
- exit(-1);
- }
- }
- else
- filelist[fileCount++] = argv[0];
- argc--; argv++;
- }
- /* at this point all files to process are in filelist */
- for (argc = 0; argc < fileCount; argc++) {
- unshar(filelist[argc]);
- }
- }
- #endif
-
- /* This part (mostly) common to both MPW and Think C */
-
- void ErrMsg (char *p1, char *p2)
- {
- #ifdef MPW
- fprintf (stderr, "### %P %P\n", p1, p2);
- #else
- ParamText((StringPtr)p1, (StringPtr)p2, (StringPtr)"\p", (StringPtr)"\p");
- (void)StopAlert(errorAlertRes, NIL);
- #endif
- }
-
- void ConvertFName (char *unixfilename, char *macfilename)
- {
- char *cp, *tp;
- char buf[256];
- Boolean slashSeen = false;
-
- /* make a Mac relative pathname */
- /* rules of the game:
- 'foo' -> :foo
- "foo" -> :foo
- `foo` -> :foo
- ./foo -> :foo
- foo/baz -> :foo:baz
- .foo -> :_foo
- .. -> ::
- foo/./baz -> :foo:baz
- /foo/baz -> :foo:baz because we don't really want to create files at top vol level
- foo:baz -> :foo/baz
- rules apply recursively
- */
-
- (void) strcpy(macfilename, ":"); /* initialize with a leading colon */
- for (cp = buf, tp = unixfilename; *tp; tp++) {
- switch (*tp) {
- case '\'':
- case '"':
- case '`': break; /* delete these chars */
- case '.': if (*(tp+1) == '/') { /* delete any occurence of ./ */
- tp++;
- }
- else if (*(tp+1) == '.') {
- *cp++ = ':';
- *cp++ = ':'; /* convert .. to :: */
- tp++;
- }
- else if (cp == buf)
- *cp++ = '_'; /* replace leading dot with _ */
- else
- *cp++ = '.';
- break;
- case '/': if (cp != buf)
- *cp++ = ':'; /* replace / with : */
- slashSeen = true;
- break;
- case ':': *cp++ = '/'; /* replace : with / */
- break;
- default: *cp++ = *tp;
- break;
- }
- }
- *cp = '\0';
-
- if (slashSeen)
- (void) strcat(macfilename, buf);
- else
- (void) strcpy(macfilename, buf);
-
- }
-
- void unshar(char *s)
- {
- char buffer[BUFSIZ];
- char *cp;
- FILE *infp, *outfp;
- char unixfilename[256], mpwfilename[256];
- char *tp, *ts, delim;
- char terminator[30];
- int tlen;
- int line;
- long dirID, dID;
- short volRef;
- FInfo fileInfo;
- OSErr err;
- #ifndef MPW
- WDPBRec wdpb;
- char lineNo[10];
- #endif
-
- #ifdef MPW
- if (strcmp(s, "-") == 0) {
- infp = stdin;
- ErrMsg("\pProcessing std input:","");
- }
- else {
- infp = fopen(s, "r");
- CPSTR(s);
- if (!infp) {
- ErrMsg("\pCould not open file", s);
- exit(-1);
- }
- else ErrMsg("\pProcessing", s);
- }
- #else /* Think C */
- infp = fopen(s, "r");
- CPSTR(s);
- if (!infp) {
- ErrMsg((char*)"\pCould not open file", s);
- return;
- }
- #endif
-
- /* skip over news header lines etc. */
- for (line = 1; cp = fgets(buffer, sizeof(buffer), infp); line++)
- if (buffer[0] == '#' || buffer[0] == ':') break;
-
- if (!cp) {
- ErrMsg((char*)"\pCould not locate start of archive in file", s);
- exit(-1);
- }
-
- #ifndef MPW
- /* Think C version needs to ask user to locate target folder */
-
- /*
- * Open the target directory as a base to put everything.
- */
- if ((dirID = GetDir((char*)"\pin which to put extracted files")) == 0L)
- return;
-
- dID = dirID; /* dID may be changed if subfolders are created */
- (void)HSetVol(NIL, dirVRefNum, dirID);
-
- /* now we should be at the start of the shar archive itself */
- infoDlgPtr = NIL;
- infoDlgPtr = GetNewDialog (infoDlgRes, NIL, (WindowPtr)-1L);
- #endif
-
- HGetVol((StringPtr)buffer, &volRef, &dID); /* get current dir, vol */
- while (cp = fgets(buffer, sizeof(buffer), infp)) {
- line++;
- #ifdef MPW
- SpinCursor(-1);
- #endif MPW
-
- if (buffer[0] == '#' || buffer[0] == ':') continue; /* comment line */
- if (strncmp(buffer, "exit", 4) == 0) { break; } /* exit */
-
- /* there are 2 types of shar files:
- a) the ones that use "cat"
- b) the ones that use "sed"
- */
- if (strncmp(buffer, "sed", 3) == 0 ||
- strncmp(buffer, "cat", 3) == 0) {
- sscanf(buffer, "%*[^>]>%s", unixfilename);
- /* make Mac relative pathname */
- ConvertFName(unixfilename, mpwfilename);
-
- /* work out the terminating string */
- sscanf(buffer, "%*[^<]<<%s", terminator);
- tp = terminator;
- tlen = strlen(terminator);
-
- while (*tp == ' ') tp++; /* skip whitespace */
- switch (*tp) {
- case '\\': ts = tp + 1; /* start of term string */
- delim = ' ';
- break;
- case '"': ts = tp + 1;
- delim = *tp;
- break;
- case '\'': ts = tp + 1;
- delim = *tp;
- break;
- default: ts = tp;
- delim = ' ';
- break;
- }
- do {
- tp++;
- } while (*tp != '\0' && *tp != delim);
- *tp = '\0';
- tlen = tp - ts;
-
- outfp = fopen(mpwfilename, "r");
- CPSTR(mpwfilename);
- if (outfp && !force) {
- fclose(outfp);
- #ifdef MPW
- ErrMsg("\pWill not overwrite existing file", mpwfilename);
- #else
- ParamText((StringPtr)"\pWill not overwrite existing file",
- (StringPtr)mpwfilename, (StringPtr)"\p", (StringPtr)"\p");
- if (NoteAlert(dupFNAlertRes, NIL) == quitB) break;
- #endif
- while (strncmp(buffer, ts, tlen) != 0) { /* skip to terminating string */
- fgets(buffer, sizeof(buffer), infp);
- line++;
- }
- } else {
- if (outfp) fclose(outfp);
- if (HCreate(volRef, dID, (StringPtr)mpwfilename, fdCreator, fdType) != noErr) {
- ErrMsg((char*)"\pCouldn't create", mpwfilename);
- exit(-1);
- }
- #ifdef MPW
- fprintf(stderr, " Open \"%P\"\n", mpwfilename);
- #else
- ParamText((StringPtr)mpwfilename,
- (StringPtr)"\p", (StringPtr)"\p", (StringPtr)"\p");
- SelectWindow(infoDlgPtr);
- ShowWindow(infoDlgPtr);
- DrawDialog(infoDlgPtr);
- #endif
- PCSTR((StringPtr)mpwfilename);
- if ((outfp = fopen(mpwfilename, "w")) == NULL) {
- CPSTR(mpwfilename);
- ErrMsg((char*)"\pCouldn't open", mpwfilename);
- exit(-1);
- }
-
- if (strncmp(buffer, "sed", 3) == 0) {
- fgets(buffer, sizeof(buffer), infp);
- do {
- fputs(buffer+1, outfp);
- fgets(buffer, sizeof(buffer), infp);
- line++;
- #ifdef MPW
- SpinCursor(1);
- #endif MPW
- } while (strncmp(buffer, ts, tlen) != 0);
- }
- else {
- /* copy everything up to terminating string to output file */
- fgets(buffer, sizeof(buffer), infp);
- while (strncmp(buffer, ts, tlen) != 0) {
- fputs(buffer, outfp);
- fgets(buffer, sizeof(buffer), infp);
- line++;
- #ifdef MPW
- SpinCursor(1);
- #endif MPW
- }
- }
- fclose(outfp);
- #ifndef MPW
- HideWindow((WindowPtr)infoDlgPtr);
- #endif
- /* set file type and creator */
- CPSTR(mpwfilename);
- GetFInfo((StringPtr)mpwfilename,0,&fileInfo);
- fileInfo.fdType = fdType;
- fileInfo.fdCreator = fdCreator;
- SetFInfo((StringPtr)mpwfilename, 0, &fileInfo);
- PCSTR((StringPtr)mpwfilename);
- }
- } else if (strncmp(buffer, "if test ! -d", 12) == 0 ||
- strncmp(buffer, "if `test ! -d", 13) == 0) {
- /* testing to see if a directory is there */
- if (sscanf(buffer, "if test ! -d '%s'", unixfilename) == 1 ||
- sscanf(buffer, "if test ! -d %s", unixfilename) == 1 ||
- sscanf(buffer, "if `test ! -d %s`", unixfilename) == 1) {
- /* make Mac relative pathname */
- ConvertFName(unixfilename, mpwfilename);
-
- /* I wish MPW C had mkdir(), but at least we don't have to do parameter blocks */
- CPSTR(unixfilename);
- CPSTR(mpwfilename);
- HGetVol((StringPtr)unixfilename, &volRef, &dirID);
- err = DirCreate(volRef, dirID, (StringPtr)mpwfilename, &dID);
- }
- } else if (strncmp(buffer, "cd ", 3) == 0) {
- if (sscanf(buffer, "cd '%s'", unixfilename) == 1 ||
- sscanf(buffer, "cd %s", unixfilename) == 1) {
- /* change the default directory */
- ConvertFName(unixfilename, mpwfilename);
- CPSTR(mpwfilename);
- #ifdef MPW
- fprintf(stderr, "### Change directory to \"%P\"\n", mpwfilename);
- #endif
- HSetVol((StringPtr)mpwfilename, 0, 0L);
- HGetVol((StringPtr)unixfilename, &volRef, &dID);
- }
- }
- }
- fclose(infp);
- }
-