home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / unix / unshar.sit / unshar.c < prev    next >
C/C++ Source or Header  |  1990-05-11  |  13KB  |  564 lines

  1. /* unshar for MPW that's good enough for comp.sources.unix archives */
  2.  
  3. #include <stdio.h>
  4. #include <string.h>
  5. /*#include <Files.h>
  6. #include <Errors.h>
  7. */
  8. #include <errno.h>
  9. #ifndef NIL
  10. #define NIL    (0L)
  11. #endif
  12.  
  13. #ifndef EOF
  14. #define EOF    (-1L)
  15. #endif
  16.  
  17. #define DIRECTORY(pb)    (((pb).dirInfo.ioFlAttrib & 0x10) == 0x10)
  18. #define    getDir    11    /* buttons in the dialogue box */
  19. #define    getCurDir    12
  20. #define    GD_PROMPT    13
  21.  
  22. typedef enum
  23. {
  24.     infoDlgRes = 1000,
  25.     aboutAlrtRes,    /* About... alert resource number */
  26.     abortRes,
  27.     gdDlgRes,
  28.     typeDlgRes,
  29.     errorAlertRes
  30. };
  31.  
  32.  
  33. typedef enum                /* File menu item numbers */
  34. {
  35.     extract = 1,
  36.     close,
  37.     quit
  38. };
  39.  
  40.  
  41. typedef enum                 /* Edit menu item numbers */
  42. {
  43.     undo = 1,
  44.     /* --- */
  45.     cut = 3,
  46.     copy,
  47.     paste,
  48.     clear
  49. };
  50.  
  51. typedef enum                /* Option menu item numbers */
  52. {
  53.     forceOpt = 1,
  54.     setCr
  55. };
  56.  
  57. typedef enum                /* dialog item numbers */
  58. {
  59.     okB = 1,
  60.     crText,
  61.     cancelB
  62. };
  63.  
  64. typedef enum
  65. {
  66.     continueB = 1,
  67.     quitB,
  68.     messageItem
  69. };
  70.  
  71. OSErr OurGetVol(char *volName,short *vRefNum,long *dirID); 
  72. OSErr OurDirCreate(short vRefNum,long parentDirID,char *directoryName,
  73.     long *createdDirID); 
  74. Boolean force = FALSE;  /* force overwriting existing files */
  75. MenuHandle    fileM, editM, optM;
  76. short dirVRefNum = 0;
  77. char *progname;
  78. OSType    fdCreator='PEDT';        /* Finder Creator */
  79. OSType    fdType='TEXT';        /* Finder Type */
  80. short    appFileCount,
  81.         whatToDo;
  82. DialogPtr    infoDlgPtr, typeDlgPtr;
  83.  
  84. SetDText (dlog, item, str)
  85. DialogPtr    dlog;
  86. int            item;
  87. Str255        str;
  88. {
  89. Handle    itemHandle;
  90. int        itemType;
  91. Rect    itemRect;
  92.  
  93.     GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
  94.     SetIText (itemHandle, str);
  95. }
  96.  
  97. /* Dialog handler */
  98.  
  99. GetDText (dlog, item, str)
  100. DialogPtr    dlog;
  101. int            item;
  102. StringPtr    str;
  103. {
  104. Handle    itemHandle;
  105. int        itemType;
  106. Rect    itemRect;
  107.  
  108.     GetDItem (dlog, item, &itemType, &itemHandle, &itemRect);
  109.     GetIText (itemHandle, str);
  110. }
  111.  
  112.  
  113. GetCreator()
  114. {
  115.     int        itemHit;
  116.     char    creator[5];
  117.  
  118.     typeDlgPtr = GetNewDialog (typeDlgRes, NIL, (WindowPtr) -1L);
  119.     BlockMove(&fdCreator, creator+1, 4);
  120.     creator[0] = '\004';
  121.     SetDText(typeDlgPtr, crText, creator);
  122.     SelectWindow(typeDlgPtr);
  123.     ShowWindow(typeDlgPtr);
  124.     DrawDialog(typeDlgPtr);
  125.     ModalDialog(NIL, &itemHit);
  126.     if (itemHit == okB) {
  127.         GetDText (typeDlgPtr, crText, &creator);
  128.         BlockMove(creator+1, &fdCreator, 4);
  129.     }
  130.     DisposDialog(typeDlgPtr);
  131. }
  132.  
  133.  
  134. /*
  135.     File menu handler
  136. */
  137.  
  138. DoFileMenu (item)
  139. int        item;
  140. {
  141. WindowPeek    wPeek;
  142.  
  143.     switch (item)
  144.     {
  145.         case extract:
  146.             Extract();
  147.             break;
  148.         case close:
  149.             if ((wPeek = (WindowPeek) FrontWindow ()) != NIL)
  150.             {
  151.                 if (wPeek->windowKind < 0)
  152.                     CloseDeskAcc (wPeek->windowKind);
  153.             }
  154.             break;
  155.         case quit:
  156.             SkelWhoa ();
  157.             break;
  158.     }
  159. }
  160.  
  161.  
  162. DoEditMenu (item)
  163. int        item;
  164. {
  165. DialogPtr    theDialog;
  166.  
  167.     theDialog = (DialogPtr) FrontWindow ();
  168.     if (((WindowPeek) theDialog)->windowKind != dialogKind)
  169.         return;
  170.  
  171.     switch (item)
  172.     {
  173.         case cut:
  174.         {
  175.             DlgCut (theDialog);
  176.             (void) ZeroScrap ();
  177.             (void) TEToScrap ();
  178.             break;
  179.         }
  180.  
  181.         case copy:
  182.         {
  183.             DlgCopy (theDialog);
  184.             (void) ZeroScrap ();
  185.             (void) TEToScrap ();
  186.             break;
  187.         }
  188.  
  189.         case paste:
  190.         {
  191.             (void) TEFromScrap ();
  192.             DlgPaste (theDialog);
  193.             break;
  194.         }
  195.  
  196.         case clear:
  197.         {
  198.             DlgDelete (theDialog);
  199.             break;
  200.         }
  201.     }
  202. }
  203.  
  204. DoOptMenu(item)
  205. int        item;
  206. {
  207.     switch (item)
  208.     {
  209.         case forceOpt:    force = !force;
  210.                                         CheckItem(optM, forceOpt, force);
  211.                                         break;
  212.          case setCr:        GetCreator();
  213.                                      break;
  214.      }
  215. }
  216.  
  217. /*
  218.     Handle selection of About╔ item from Apple menu
  219. */
  220.  
  221. DoAbout ()
  222. {
  223.     (void) Alert (aboutAlrtRes, NIL);
  224. }
  225.  
  226. Boolean        useCurDir;        /* Set if current dir to be used */
  227.  
  228. /* Filter procs & dialogue hooks to select directories only in SFGet file */
  229. pascal short
  230. DirSelHook(item, theDialog)
  231. short        item;
  232. DialogPtr    theDialog;
  233. {
  234.     if (item == getDir|| item == getCurDir) {
  235.         /* folder selected */
  236.         useCurDir = item == getCurDir;
  237.         item = getOpen;
  238.     }
  239.     return(item);
  240. }
  241.  
  242. pascal Boolean
  243. DirFilterProc(pb)
  244. CInfoPBPtr    pb;
  245. {
  246.     return(!DIRECTORY(*pb));    /* a directory if bit 4 is set */
  247. }
  248. /*
  249.  * GetDir - manage the directory selection dialog
  250.  */
  251. long
  252. GetDir(text)
  253. char    *text;
  254. {
  255.     char        *routine = "\pGetDir";
  256.     Point    where;
  257.     short    ht, wd;
  258.     SFReply    reply;
  259.     CInfoPBRec    pb;
  260.     DialogPtr    dlgP;
  261.     long        dirDirID=0;        /* Selected directory DirID */
  262.  
  263.     if ((dlgP = GetNewDialog(gdDlgRes, NIL,(WindowPtr) -1)) == NIL) {
  264.         return(TRUE);
  265.     }
  266.     wd = (dlgP->portRect.right)-(dlgP->portRect.left);
  267.     ht = (dlgP->portRect.bottom)-(dlgP->portRect.top);
  268.     /* centre the dialogue box on the screen
  269.        (but how do I know which screen?)
  270.     */
  271.     where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
  272.     where.v = (screenBits.bounds.bottom-screenBits.bounds.top-ht) / 2;
  273.     ParamText((StringPtr)text, (StringPtr)"\p", (StringPtr)"\p", (StringPtr)"\p");
  274.     SFPGetFile (where, (StringPtr)text, (FilterProc)DirFilterProc, -1, NIL, DirSelHook, &reply,
  275.                 gdDlgRes, NIL);
  276.     if (reply.good) {
  277.         dirVRefNum = reply.vRefNum;
  278.         if (useCurDir) {
  279.             dirDirID = CurDirStore;
  280.         }
  281.         else {
  282.             dirDirID = (long)(reply.fType);
  283.         }
  284.     }
  285.     return(dirDirID);
  286. }
  287.  
  288. void GetNextFile(fInfoPtr)
  289. SFReply    *fInfoPtr;
  290. {    AppFile    nextFile;
  291.     static    short    idx=1;
  292.  
  293.     GetAppFiles(idx++, &nextFile);
  294.     fInfoPtr->vRefNum = nextFile.vRefNum;
  295.     fInfoPtr->fType = nextFile.fType;
  296.     fInfoPtr->version = nextFile.versNum;
  297.     BlockMove(nextFile.fName, fInfoPtr->fName, (int)(nextFile.fName[0]+1));
  298.     appFileCount--;
  299. }
  300.  
  301.  
  302. Extract() {
  303.     Point        where;
  304.     SFReply        reply;
  305.  
  306.     while (1){
  307.         if (appFileCount > 0) GetNextFile(&reply);
  308.         else {
  309.             /*
  310.              * Use the standard file dialog to select the archive.
  311.              */
  312.             where.h = where.v = 75;
  313.             SFGetFile(where, (StringPtr)"\pSelect shar file", NIL, 0, NIL, NIL, &reply);
  314.             if (!reply.good)
  315.                 return;
  316.         }
  317.     
  318.         /*
  319.          * Remember the VRefNum and Name for OpenArchive.
  320.          * Find out where to put the extracted files.
  321.          */
  322.         (void) SetVol(NIL, reply.vRefNum);
  323.         PtoCstr((char *)reply.fName);
  324.         unshar(reply.fName);
  325.         (void) SetVol(NIL, reply.vRefNum);
  326.     }
  327. }
  328.  
  329.  
  330. main(argc, argv)
  331. int argc;
  332. char **argv;
  333. {
  334.     Handle        fTypeH;
  335.     DialogTHndl    dlgH;
  336.   Point    where;
  337.   short    ht, wd;
  338.         
  339.     SkelInit (3, NIL);
  340.     SkelApple ("\pAbout Unshar╔", DoAbout);
  341.  
  342.     fileM = NewMenu (1000, (StringPtr)"\pFile");
  343.     AppendMenu (fileM, (StringPtr)"\pExtract/O;Close/K;Quit/Q");
  344.     SkelMenu (fileM, DoFileMenu, NIL, FALSE);
  345.  
  346.     editM = NewMenu (1001, (StringPtr)"\pEdit");
  347.     AppendMenu (editM, (StringPtr)"\p(Undo/Z;(-;Cut/X;Copy/C;Paste/V;Clear");
  348.     SkelMenu (editM, DoEditMenu, NIL, FALSE);
  349.  
  350.     optM = NewMenu (1002, (StringPtr)"\pOptions");
  351.     AppendMenu (optM, (StringPtr)"\pOverwrite existing files;File type...");
  352.     SkelMenu (optM, DoOptMenu, NIL, TRUE);
  353.     
  354.     CountAppFiles (&whatToDo, &appFileCount);
  355.     if ((fTypeH = (char **)GetResource('ftyp', 0)) == NIL) {
  356.         ExitToShell();
  357.     }
  358.     BlockMove(*fTypeH, &fdCreator, 4);
  359.     BlockMove((*fTypeH)+4, &fdType, 4);
  360.     ReleaseResource(fTypeH);
  361.     
  362.     CouldDialog(typeDlgRes);
  363.     CouldDialog(infoDlgRes);
  364.     dlgH = (DialogTHndl)GetResource('DLOG', typeDlgRes);
  365.     wd = ((* dlgH)->boundsRect.right)-((* dlgH)->boundsRect.left);
  366.     /* centre the dialogue box on the screen
  367.        (but how do I know which screen?)
  368.     */
  369.     where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
  370.     (* dlgH)->boundsRect.right += where.h;
  371.     (* dlgH)->boundsRect.left = where.h;
  372.     
  373.     dlgH = (DialogTHndl)GetResource('DLOG', infoDlgRes);
  374.     wd = ((* dlgH)->boundsRect.right)-((* dlgH)->boundsRect.left);
  375.     /* centre the dialogue box on the screen
  376.        (but how do I know which screen?)
  377.     */
  378.     where.h = (screenBits.bounds.right-screenBits.bounds.left-wd) / 2;
  379.     (* dlgH)->boundsRect.right += where.h;
  380.     (* dlgH)->boundsRect.left = where.h;
  381.  
  382.     SkelMain ();
  383.     SkelClobber ();
  384.     FreeDialog(typeDlgRes);
  385.     FreeDialog(infoDlgRes);
  386. }
  387.  
  388. unshar(s)
  389. char    *s;
  390. {
  391.   char buffer[BUFSIZ];
  392.   char *cp;
  393.   FILE *infp, *outfp;
  394.   char unixfilename[64], mpwfilename[64];
  395.   int line;
  396.   short v;
  397.   long dirID, dID;
  398.   WDPBRec        wdpb;
  399.   char    lineNo[10];
  400.  
  401.   infp = fopen(s, "r");
  402.   CtoPstr(s);
  403.   if (!infp) {
  404.     ParamText((StringPtr)"\pCould not open file ", (StringPtr)s,
  405.               (StringPtr)"\p", (StringPtr)"\p");
  406.     (void)StopAlert(errorAlertRes, NIL);
  407.     return;
  408.   }
  409.  
  410.   /* skip over news header lines etc. */
  411.   for (line = 1; cp = fgets(buffer, sizeof(buffer), infp); line++)
  412.     if (buffer[0] == '#') break;
  413.   if (!cp) {
  414.     ParamText((StringPtr)"\pCould not locate start of archive in file",
  415.               (StringPtr)s, (StringPtr)"\p", (StringPtr)"\p");
  416.     (void)StopAlert(errorAlertRes, NIL);
  417.     return;
  418.   }
  419.     /*
  420.      * Open the target directory as a base to put everything.
  421.      */
  422.     if ((dirID = GetDir("\pin which to put extracted files")) == 0L)
  423.         return;
  424.     
  425.     wdpb.ioCompletion = NIL;
  426.     wdpb.ioNamePtr = NIL;
  427.     wdpb.ioVRefNum = dirVRefNum;
  428.     wdpb.ioWDProcID = 'Shar';
  429.     wdpb.ioWDDirID = dirID;
  430.     if (PBOpenWD(&wdpb, FALSE) != noErr) {
  431.         return;
  432.     }
  433.     
  434.     /*
  435.      * Extract and print the files as found in the archive.
  436.      */
  437.     dID = dirVRefNum = wdpb.ioVRefNum;
  438.     (void)SetVol(NIL, dID);
  439.  
  440.   /* now we should be at the start of the shar archive itself */
  441.   infoDlgPtr = NIL;
  442.   infoDlgPtr = GetNewDialog (infoDlgRes, NIL, (WindowPtr)-1L);
  443.   while (cp = fgets(buffer, sizeof(buffer), infp)) {
  444.     line++;
  445.     if (buffer[0] == '#') continue;    /* comment line */
  446.     if (buffer[0] == 'e') { /*fclose(infp); return;*/ break; }  /* exit */
  447.     if (buffer[0] == 'i') {
  448.         if (!strncmp(buffer, "if test -f", 10)) {
  449.         /* testing to see if a file is there */
  450.         if (sscanf(buffer, "if test -f '%s'", unixfilename) == 1) {
  451.           /* make Mac relative pathname */
  452.           sprintf(mpwfilename, "%s", unixfilename);
  453.           /* convert '/' to ':' & vice versa */
  454.           for (cp = mpwfilename+1; *cp; cp++)
  455.             if (*cp == '/')
  456.               *cp = ':';
  457.             else if (*cp == ':')
  458.               *cp = '/';
  459.           cp[-1] = 0;  /* drop trailing quote mark */
  460.           outfp = fopen(mpwfilename, "r");
  461.           if (outfp && !force) {
  462.             fclose(outfp);
  463.                  CtoPstr(mpwfilename);
  464.             ParamText((StringPtr)"\pWill not clobber existing file",
  465.                       (StringPtr)mpwfilename, (StringPtr)"\p", (StringPtr)"\p");
  466.             if (NoteAlert(errorAlertRes, NIL) == quitB) break;
  467.             while (buffer[0] != 'f') {  /* skip to size "fi" */
  468.               fgets(buffer, sizeof(buffer), infp);
  469.             }
  470.             fgets(buffer, sizeof(buffer), infp);  /* skip over ending comment */
  471.             fgets(buffer, sizeof(buffer), infp);  /* skip over test "fi" */
  472.           } else {
  473.             if (outfp) fclose(outfp);
  474.             CtoPstr(mpwfilename);
  475.             Create((StringPtr)mpwfilename, dID, fdCreator, fdType);
  476.             ParamText((StringPtr)mpwfilename,
  477.                       (StringPtr)"\p", (StringPtr)"\p", (StringPtr)"\p");
  478.             SelectWindow(infoDlgPtr);
  479.             ShowWindow(infoDlgPtr);
  480.             DrawDialog(infoDlgPtr);         
  481.             PtoCstr(mpwfilename);
  482.             outfp = fopen(mpwfilename, "a");
  483.             while (buffer[0] != 'X')
  484.               fgets(buffer, sizeof(buffer), infp);
  485.             do {
  486.               fputs(buffer+1, outfp);
  487.               fgets(buffer, sizeof(buffer), infp);
  488.             } while (buffer[0] == 'X');
  489.             fclose(outfp);
  490.             fgets(buffer, sizeof(buffer), infp);  /* skip to next if */
  491.             fgets(buffer, sizeof(buffer), infp);
  492.             fgets(buffer, sizeof(buffer), infp);
  493.             fgets(buffer, sizeof(buffer), infp);
  494.             fgets(buffer, sizeof(buffer), infp);
  495.           }
  496.         } else {
  497.           NumToString((long)line, (StringPtr)lineNo);
  498.           CtoPstr(buffer);
  499.           ParamText((StringPtr)"\pCannot understand 'if' statement, aborting",
  500.                       (StringPtr)s, (StringPtr)lineNo, (StringPtr)"\p");
  501.           (void) StopAlert(abortRes, NIL);
  502.           break;
  503.         }
  504.       } else if (!strncmp(buffer, "if test ! -d", 12)) {
  505.         /* testing to see if a directory is there */
  506.         if (sscanf(buffer, "if test ! -d '%s'", unixfilename) == 1) {
  507.           /* make Mac relative pathname */
  508.           sprintf(mpwfilename, ":%s", unixfilename);
  509.           /* convert '/' to ':' & vice versa */
  510.           for (cp = mpwfilename+1; *cp; cp++)
  511.             if (*cp == '/')
  512.               *cp = ':';
  513.             else if (*cp == ':')
  514.               *cp = '/';
  515.           cp[-1] = 0;  /* drop trailing quote mark */
  516.  
  517.           /* I wish MPW C had mkdir(), but at least we don't have to do parameter blocks */
  518.           OurGetVol(unixfilename, &v, &dirID);
  519.           CtoPstr(mpwfilename);
  520.           OurDirCreate(v, dirID, mpwfilename, &dID);
  521.           fgets(buffer, sizeof(buffer), infp);
  522.           fgets(buffer, sizeof(buffer), infp);
  523.           fgets(buffer, sizeof(buffer), infp);
  524.         }
  525.       }
  526.     }
  527.   }
  528.   if (infoDlgPtr != NIL) DisposDialog(infoDlgPtr);
  529.   infoDlgPtr = NIL;
  530.   (void) PBCloseWD(&wdpb, FALSE);
  531.   fclose(infp);
  532. }
  533.  
  534. OSErr OurGetVol(name, volP, dirIdP)
  535. char    *name;
  536. short    *volP;
  537. long    *dirIdP;
  538. {
  539.     WDPBRec    pb;
  540.     
  541.     pb.ioCompletion = NULL;
  542.     PBHGetVol (&pb, FALSE);
  543.     *volP = pb.ioVRefNum;
  544.     *dirIdP = pb.ioWDDirID;
  545.     BlockMove(pb.ioNamePtr, name, pb.ioNamePtr[0]+1);
  546. }
  547.  
  548. OSErr OurDirCreate(vRefNum,parentDirID, directoryName,
  549.     createdDirID)
  550. short    vRefNum;
  551. long    parentDirID;
  552. char    *directoryName;
  553. long    *createdDirID;
  554. {
  555.     HParamBlockRec    pb;
  556.     pb.fileParam.ioNamePtr = (StringPtr)directoryName;
  557.     pb.fileParam.ioVRefNum = vRefNum;
  558.     pb.fileParam.ioDirID = parentDirID;
  559.     pb.fileParam.ioCompletion = NULL;
  560.     PBDirCreate(&pb, FALSE);
  561.     *createdDirID = pb.fileParam.ioDirID;
  562. }
  563.  
  564.