home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Utilities / Programming / EnterAct 3.7.3 / hAWK project / AWK Source / hAWK_Interface.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-22  |  64.6 KB  |  2,582 lines  |  [TEXT/KEEN]

  1. /* hAWK_Interface.c : hAWK dialog interface */
  2. /* Copyright © 1986, 1988, 1989 1991 the Free Software Foundation, Inc.
  3.  *         This file is part of GAWK, the GNU implementation of the
  4.  * AWK Progamming Language, modified for the Macintosh (also called hAWK).
  5.  *         GAWK is free software; you can redistribute or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 1, or any later version.
  8.  *         GAWK is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  * GNU General Public License for more details.
  12.  *         You should have received a copy of the GNU General Public License
  13.  * along with GAWK; see the file "COPYING hAWK". If not, write to
  14.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  * Written for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  16.  */
  17.  
  18. /* Code to synthesize a command line based on user's choices in the
  19. main hAWK dialog. Mouse-driven, except for variables that one wishes
  20. to be set on the command line - these must be typed in.
  21.  
  22. Program options: choose from a list of all hAWK programs in the
  23. folder "hAWK programs", or some other programs via a standard SFGetFile dialog.
  24. "Library" files may also be added - the parser treats them as being appended
  25. to the main program, but for the sake of sanity they should contain only
  26. function definitions.
  27.  
  28. Variables options: not very fancy, just type in "var=value" (not including the quotes)
  29. in the dialog for variables.
  30.  
  31. Input options: here's where the Mac really shines - hAWK has generalized options for
  32. input which allow a program to be run on different input without altering the
  33. dialog setup - that's why its possible and useful to save the setup associated
  34. with a particular hAWK program
  35. - Specific input file; the one "fixed" option, allows user to pick one particular
  36.     input file as input
  37. - Selected front text / All of front text; takes as input all or the selected part
  38.     of the text window that happens to be in front when hAWK is called
  39. - MFS selected files; takes as input all files selected for multi-file operation
  40.     in the calling application - usually multi-file searching.
  41.  
  42. Save settings: saves the dialog options with the hAWK program. Especially useful
  43. for restoring the input option.
  44.  
  45. An "About" button displays copysquawk about hAWK/gawk/awk/nawk.
  46.  
  47. Rev Dec 5/92: Run button always drawn bold in a more-general way,
  48. Set Variables button emboldened if variables are already present for a program.
  49.  
  50. Rev may 96: allow calling program to pass in a command line - if present, skip the
  51. hAWK dialog, make argv's and go straight to AWKmain().
  52. */
  53.  
  54. #include <stdlib.h>
  55. #include <stdio.h>
  56. //#include <fcntl.h>
  57. #include <string.h>
  58. #include <setjmp.h>
  59. #include "CodeResHelper.h" /* TMalloc etc */
  60. #include "CodeResource.h"
  61. #include "AppCodeComm.h"
  62.  
  63. // Some key constants
  64. #define        ETX                '\003'        /* enter                 */
  65. #define        BS                '\b'        /* backspace            */
  66. #define        HT                '\t'        /* tab                    */
  67. #define        CR                0x0D        /* return                */
  68. #define        ESC                '\033'        /* clear                */
  69. #define        FS                '\034'        /* left arrow            */
  70. #define        GS                '\035'        /* right arrow            */
  71. #define        RS                '\036'        /* up arrow                */
  72. #define        US                '\037'        /* down arrow            */
  73. #define        COMMA            ','         /* or 0x2C */
  74. #define        BLANK            ' '         /* a space */
  75. #define        OPTBL            ' '            /* option-space */
  76.  
  77. // And some macros for character handling
  78. #define alpha(c)    (('a'<=(c)&&(c)<='z')||('A'<=(c)&&(c)<='Z')||(c)=='_')
  79. #define num(c)        ('0'<=(c) && (c)<='9')
  80. #define alphanum(c)    (alpha(c)||num(c))
  81. #define white(c)    ((c) == BLANK || ((c) > 0 && (c) <= CR) || (c) == OPTBL)
  82.  
  83.  
  84. // Use better memory routines for allocating argv[]
  85. #define malloc(x) Fmalloc(x)
  86. #define realloc(x, y) Frealloc(x, y)
  87. #define free(x) Ffree(x)
  88.  
  89. extern void *alloca(unsigned short size);
  90. extern void DumpZoneList(void);
  91. extern void DisposeProgress(void); /* hAWK_prompt.c */
  92.  
  93. /* buffer holding position of long jump */
  94. jmp_buf        envBuf;
  95.  
  96. static short argc;
  97. static char **argv;
  98. static short NUMARGVS = 500; /* Was a #define, now variable */
  99.  
  100. short gInputError; /* Not used yet */
  101.  
  102. /* interface constants and struct recording user choices */
  103. #define NUMLIBS        10        /* max number of libraries */
  104. #define NUMVARSETS        10    /* max number of "command line" variables */
  105. typedef struct HawkSetup
  106.     {
  107.     short        inputType;        /* input file or "metafile" specification */
  108.     Boolean    showOut, selectOut; /* passed back to calling application */
  109.     char     *progname;            /* the hAWK program */
  110.     char     *libraryname[NUMLIBS];
  111.     char    *varsetting[NUMVARSETS];
  112.     char    *inputname; /* optional, if one specific file selected   */
  113.     short        progVRefNum; /* not saved to disk - for currently selected program*/
  114.     short        defaultVRefNum; /* not saved, for the folder "hAWK programs" */
  115.     short        otherVRefNum; /* for "unlisted" program */
  116.     } HawkSetup;
  117. /* global record of user choices */
  118. HawkSetup HS;
  119.  
  120. /* Current popup items. Note the current selection for the input popup is
  121. recorded in HS,inputType. */
  122. static short     mainProgMenuNum = 1,
  123.             libraryMenuNum = 1;
  124.  
  125. /* User choices can be saved with hAWK program for next run */
  126. #define        HAWKID            1011    /* resource id, type 'HAWK' */
  127.  
  128. /* Dialog to set up a hAWK run.
  129. */
  130. #define    HawkDlogID        405
  131. /* OK is 1, Cancel is 2 */
  132. #define SaveHawkSetup    3
  133. #define ProgramStat        5
  134. #define LibraryStat        6
  135. #define InputStat        7
  136. #define VariableButton    8
  137. #define ShowOut            9
  138. #define SelectOut        10
  139. #define ProgramPopup    11
  140. #define LibraryPopup    12
  141. #define InputPopup        13
  142. #define AboutHawk        14
  143. #define RunUserItem        15
  144. #define VarUserItem        16
  145.  
  146. /* popups */
  147. #define MainProgramID    187
  148. #define LibraryID        188
  149. #define InputID            189
  150.  
  151. /* The "Take input from:" popup varies accoring to which extensions
  152. are supplied by the application: GetFrontText_Ext is nonnull only if
  153. it is appropriate to take input from a front text window - note this
  154. will be null even if the application supports the extension, in the case
  155. where no text file is open at the time this code resource is called.
  156. GetNextFileToSearch_Ext is nonnull if the application supports selecting
  157. multiple files somehow, the most common use being for multi-file
  158. searching. Again this will be passed in as NULL if there are no files
  159. selected at the time of the call.
  160. */
  161. typedef struct InputPopupItems
  162.     {
  163.     short        frontSelected,    /* user's selected text in front text window */
  164.             frontAll,        /* all of text in front window */
  165.             multiSelected,    /* multiple files, as specified within application */
  166.             specificFile;    /* pick one with SFGetFIle */
  167.     } InputPopupItems, *InPopItemPtr;
  168. static InputPopupItems    inPop;
  169.  
  170. /* from AWK_MAIN.C */
  171. extern short AWKmain(short argc, char **argv);
  172.  
  173. /* Functions defined in this file: */
  174. short InvokeHAWK(void); /* the external call - see Code_Main.c */
  175. void PreloadAllSegments(void);
  176. /* Dialog management, "command line" creation: */
  177. Boolean DoHawkDialog(void);
  178. void CreateHawkProgramResourcePopups(void);
  179. void CreateInputPopup(void);
  180. long FindHawkProgramFolder(char *curvolName, char *hawkFolderName);
  181. void AddProgramsToMenu(char *curvolName, long theDirID, MenuHandle theMenu);
  182. void AlphaAppendMenu(MenuHandle theMenu, short lowPoint, char *name);
  183. short AlphaMenuPos(char *name, MenuHandle theMenu, short highPoint, short lowPoint);
  184. short MenuCompare(char *name, MenuHandle theMenu, short index);
  185. short PtrLenPascalCompare(Ptr spatPtr, short patLen, Ptr stargetPtr);
  186. void DestroyHawkPopups(void);
  187. pascal void HawkPopProc(WindowPtr wdPtr, short item);
  188. pascal void ButtonProc(WindowPtr wdPtr, short item);
  189. void SetPopupMark(short theMenuID, short newItem);
  190. void ResetHS(DialogPtr dPtr);
  191. void LoadHawkDlogFromHS(DialogPtr dPtr, Boolean progToo);
  192. void GetMenuEntryFromFullName(char *name, char *filename);
  193. void SaveInvocation(DialogPtr dPtr, char *name);
  194. Handle CreateHawkProgramResource(DialogPtr dPtr); /* from HS, mostly */
  195. Boolean ReadHAWKResource(char *name); /* to HS */
  196. Boolean FSpReadHAWKResource(char *name); /* to HS */
  197. void ConvertRsrcToHS(Handle h);
  198. void ClearHS(void);
  199. void RedrawItem(DialogPtr dPtr, short itemHit);
  200. void RedrawDialog(DialogPtr dPtr);
  201. Boolean DoVarDialog(DialogPtr hAWKDLOGdPtr);
  202. void LoadExistingVarsToDlog(DialogPtr dPtr);
  203. short BadVarFormat(DialogPtr dPtr);
  204. void GetHawkProgramName(DialogPtr dPtr, short item);
  205. void GetHawkLibraryName(short menuItem);
  206. void GetInputFileName(void);
  207. Boolean GetCommandLineFromDlogResult(void);
  208. char *CreateStdIn(Boolean wholeFile);
  209. Boolean GetInputsFromMFS(void);
  210. Boolean GetCommandLineArguments(void);
  211. void DoCmdLineDefaultLibsAndVars(void);
  212. Ptr FullPathNameForProgram
  213.     (Ptr        argPtr,
  214.     short        argLength,
  215.     short        *vRefNumP
  216.     );
  217. short GetWorkingDirectory
  218.     (char    *curvolName,
  219.     long    theDirID
  220.     );
  221. short GetNextCommandLineArg
  222.     (Ptr        *argPtrP,
  223.     short        *argLengthP
  224.     );
  225. /* Error handling, cleanup after run: */
  226. void JumpOnHAWKError(short inputErrorNumber);
  227. void CleanUpAfterHAWK(void);
  228. void HandleHAWKError(void);
  229. void DoExiting(void);
  230.  
  231. short InvokeHAWK(void)
  232.     {
  233.     
  234.     //_fmode = O_TEXT; /* default is binary */
  235.     InitTempCodeMemory(); /* see CodeResource_Helper.c */
  236.     
  237.     // Make sure we can load all our code into "real" memory
  238.     PreloadAllSegments();
  239.     
  240.     // Rev May 96, see if caller passed along a command line. If there is any failure
  241.     // or just no command line, do the dialog.
  242.     if (!GetCommandLineArguments())
  243.         {
  244.         //OKStopAlert("DBG could not get cmd line arguments");
  245.         if (argv != NULL)
  246.             {
  247.             while (--argc >= 0)
  248.                 {
  249.                 if (argv[argc] != NULL)
  250.                     free(argv[argc]);
  251.                 }
  252.             free(argv);
  253.             }
  254.         argv = NULL;
  255.         argc = 0;
  256.         if (!DoHawkDialog())
  257.             {
  258.             DoExiting();
  259.             return(-1); /* user cancelled, most likely, or out of memory */
  260.             }
  261.         }
  262.     SetWatchCursor();
  263.     
  264.     /* If hAWK fails, it long-jumps back to here
  265.     and setjmp returns non-zero. */
  266.     
  267.     if (!setjmp(envBuf))
  268.         {
  269.         //OKStopAlert("DBG about to call AWKMain");
  270.         AWKmain(argc, argv);
  271.         CleanUpAfterHAWK();
  272.         //_exiting(1);
  273.         /* show result if wanted */
  274.         DoExiting();
  275.         if (HS.showOut)
  276.             {
  277.             if (HS.selectOut)
  278.                 return(2);
  279.             return(1);
  280.             }
  281.         return(0);
  282.         }
  283.     else
  284.         {
  285.         CleanUpAfterHAWK();
  286.         //_exiting(1);
  287.         HandleHAWKError();
  288.         DoExiting();
  289.         return(-2);
  290.         }
  291.     }
  292.  
  293. /* Call functions in all other segments, just to load the code for those
  294. segments before we get going. This is segment 1 by the way.
  295. */
  296. void PreloadAllSegments(void)
  297.     {
  298.     extern void LoadSegment2(void);
  299.     extern void LoadSegment3(void);
  300.     extern void LoadSegment4(void);
  301.     extern void LoadSegment5(void);
  302.     extern void LoadSegment6(void);
  303.     extern void LoadSegment7(void);
  304.     
  305.     LoadSegment2();
  306.     LoadSegment3();
  307.     LoadSegment4();
  308.     LoadSegment5();
  309.     LoadSegment6();
  310.     LoadSegment7();
  311.     }
  312.  
  313. Boolean DoHawkDialog()
  314.     {
  315.     MenuHandle        theMenu;
  316.     DialogPtr        dPtr;
  317.     Handle            theHandle;
  318.     Rect            theBox;
  319.     Point            pt;
  320.     long            aLong;
  321.     short              theID, menuItem;
  322.     short                kind, itemHit, badChar, theType;
  323.     char            mText[64];
  324.     Boolean            checkValue;
  325.     UserItemUPP        HawkPopProcUPP;
  326.     UserItemUPP        ButtonProcUPP;
  327.     
  328.     if (!GetAndAlignDialog(HawkDlogID))
  329.         return(FALSE);
  330.     dPtr = GetNewDialog(HawkDlogID, NULL, (WindowPtr)-1L);
  331.     CreateHawkProgramResourcePopups();
  332.     /* attach procs for popups */
  333.     HawkPopProcUPP = NewUserItemProc(HawkPopProc);
  334.     GetDItem(dPtr, ProgramPopup, &kind, &theHandle, &theBox);
  335.     SetDItem(dPtr,ProgramPopup, kind, (Handle)HawkPopProcUPP, &theBox);
  336.     GetDItem(dPtr, LibraryPopup, &kind, &theHandle, &theBox);
  337.     SetDItem(dPtr,LibraryPopup, kind, (Handle)HawkPopProcUPP, &theBox);
  338.     GetDItem(dPtr, InputPopup, &kind, &theHandle, &theBox);
  339.     SetDItem(dPtr,InputPopup, kind, (Handle)HawkPopProcUPP, &theBox);
  340.     /*...and buttons */
  341.     ButtonProcUPP = NewUserItemProc(ButtonProc);
  342.     GetDItem(dPtr, RunUserItem, &kind, &theHandle, &theBox);
  343.     SetDItem(dPtr,RunUserItem, kind, (Handle)ButtonProcUPP, &theBox);
  344.     GetDItem(dPtr, VarUserItem, &kind, &theHandle, &theBox);
  345.     SetDItem(dPtr,VarUserItem, kind, (Handle)ButtonProcUPP, &theBox);
  346.     ((WindowPeek)(dPtr))->refCon = 0; /* used to record if variables exist */
  347.     /* init HawkSetup */
  348.     HS.progname = HS.inputname = NULL;
  349.     for (itemHit = 0; itemHit < NUMLIBS; ++itemHit)
  350.         HS.libraryname[itemHit] = NULL;
  351.     for (itemHit = 0; itemHit < NUMVARSETS; ++itemHit)
  352.         HS.varsetting[itemHit] = NULL;
  353.     ResetHS(dPtr); /* clears popup contents too */
  354.     SetPopupMark(InputID, HS.inputType);
  355.     ShowWindow(dPtr);
  356.     SetPort(dPtr);
  357.     /* Initially Run and Save Settings are disabled - no program yet */
  358.     HiliteDlgControl(dPtr, 1, 255);
  359.     HiliteDlgControl(dPtr, SaveHawkSetup, 255);
  360.     InitCursor();
  361.     itemHit = 99;
  362.     while (itemHit > 2) /* ie not Run/Cancel */
  363.         {
  364.         ModalDialog(NULL, &itemHit);
  365.         switch (itemHit)
  366.             {
  367.         case SaveHawkSetup: /* enabled only if program has been picked */
  368.             if (HS.progname)
  369.                 SaveInvocation(dPtr, HS.progname);
  370.             /* else very odd error - ignore */
  371.         break;
  372.         case ShowOut:
  373.         case SelectOut:
  374.             GetCheck (dPtr, itemHit, &checkValue);
  375.             SetCheck (dPtr, itemHit, !checkValue);
  376.         break;
  377.         case ProgramPopup:
  378.             /* Treat any pick from this menu as request
  379.             to change main program */
  380.             GetDItem(dPtr, ProgramStat, &kind, &theHandle, &theBox);
  381.             InvertRect(&theBox);
  382.             pt.v = theBox.top;
  383.             pt.h = theBox.right;
  384.             LocalToGlobal(&pt);
  385.             theMenu = GetMHandle(MainProgramID);
  386.             aLong = PopUpMenuSelect(theMenu, pt.v, pt.h, 1);
  387.             theID = HiWord(aLong);
  388.             menuItem = LoWord(aLong);
  389.             InvertRect(&theBox);
  390.             if (menuItem > 0) /* get program and any saved settings */
  391.                 {
  392.                 GetHawkProgramName(dPtr, menuItem);
  393.                 SetPopupMark(InputID, HS.inputType);
  394.                 RedrawDialog(dPtr);
  395.                 }
  396.         break;
  397.         case LibraryPopup:
  398.             /* Either "Select library" - add a library;
  399.             or the name of a library - delete it. */
  400.             GetDItem(dPtr, LibraryStat, &kind, &theHandle, &theBox);
  401.             InvertRect(&theBox);
  402.             pt.v = theBox.top;
  403.             pt.h = theBox.right;
  404.             LocalToGlobal(&pt);
  405.             theMenu = GetMHandle(LibraryID);
  406.             aLong = PopUpMenuSelect(theMenu, pt.v, pt.h, 1);
  407.             theID = HiWord(aLong);
  408.             menuItem = LoWord(aLong);
  409.             InvertRect(&theBox);
  410.             if (menuItem > 0) /* get or delete library */
  411.                 {
  412.                 GetHawkLibraryName(menuItem);
  413.                 RedrawItem(dPtr, itemHit);
  414.                 }
  415.         break;
  416.         case InputPopup:
  417.             GetDItem(dPtr, InputStat, &kind, &theHandle, &theBox);
  418.             InvertRect(&theBox);
  419.             pt.v = theBox.top;
  420.             pt.h = theBox.right;
  421.             LocalToGlobal(&pt);
  422.             theMenu = GetMHandle(InputID);
  423.             aLong = PopUpMenuSelect(theMenu, pt.v, pt.h, HS.inputType);
  424.             theID = HiWord(aLong);
  425.             menuItem = LoWord(aLong);
  426.             InvertRect(&theBox);
  427.             if (menuItem > 0)
  428.                 HS.inputType = menuItem;
  429.             if (menuItem == inPop.frontSelected)
  430.                 {
  431.                 ;
  432.                 }
  433.             else if (menuItem == inPop.frontAll)
  434.                 {
  435.                 ;
  436.                 }
  437.             else if (menuItem == inPop.multiSelected)
  438.                 {
  439.                 ;
  440.                 }
  441.             else if (menuItem == inPop.specificFile)
  442.                 {
  443.                 GetInputFileName();
  444.                 }
  445.             if (menuItem > 0 && menuItem != inPop.specificFile)
  446.                 {
  447.                 if (HS.inputname)
  448.                     {
  449.                     DisposPtr(HS.inputname);
  450.                     HS.inputname = NULL;
  451.                     SetItem(theMenu, inPop.specificFile, (StringPtr)"\pSelect input file...");
  452.                     }
  453.                 }
  454.             if (menuItem > 0)
  455.                 {
  456.                 SetPopupMark(InputID, HS.inputType);
  457.                 RedrawItem(dPtr, itemHit);
  458.                 }
  459.         break;
  460.         case VariableButton:
  461.             if (!DoVarDialog(dPtr)) /* serious error if FALSE */
  462.                 {
  463.                 itemHit = 2;
  464.                 SysBeep(2);
  465.                 goto NeverMind;
  466.                 }
  467.             RedrawDialog(dPtr);
  468.         break;
  469.         case AboutHawk:
  470.             OKStopAlert("Copyright © 1991, Free Software Foundation.\r\
  471. GNU Awk and hAWK come with ABSOLUTELY NO WARRANTY.  This is free software, and \
  472. you are welcome to distribute it under the terms of the GNU General \
  473. Public License, which covers both the warranty information and the \
  474. terms for redistribution.\r\
  475. You should have received a copy of the GNU General Public License along \
  476. with this program (see COPYING hAWK); if not, write to the Free Software Foundation, Inc., \
  477. 675 Mass Ave, Cambridge, MA 02139, USA.");
  478.         break;
  479.             }
  480.         }
  481. NeverMind:
  482.     // TEST ONLY DELETE
  483.     // DisposeRoutineDescriptor(HawkPopProcUPP);
  484.     // DisposeRoutineDescriptor(ButtonProcUPP);
  485.  
  486.     /* cancelled? */
  487.     if (itemHit == 2) /* cancel */
  488.         {
  489.         if (HS.inputname)
  490.             DisposPtr(HS.inputname);
  491.         if (HS.progname)
  492.             DisposPtr(HS.progname);
  493.         for (itemHit = 0; itemHit < NUMLIBS; ++itemHit)
  494.             {
  495.             if (HS.libraryname[itemHit])
  496.                 DisposPtr(HS.libraryname[itemHit]);
  497.             }
  498.         for (itemHit = 0; itemHit < NUMVARSETS; ++itemHit)
  499.             {
  500.             if (HS.varsetting[itemHit])
  501.                 DisposPtr(HS.varsetting[itemHit]);
  502.             }
  503.         DisposDialog(dPtr);
  504.         DestroyHawkPopups();
  505.         return(FALSE);
  506.         }
  507.     /* translate to "commmand" line */
  508.     if(!GetCommandLineFromDlogResult())
  509.         {
  510.         DisposDialog(dPtr);
  511.         DestroyHawkPopups();
  512.         return(FALSE);
  513.         }
  514.     GetCheck (dPtr, ShowOut, &checkValue);
  515.     HS.showOut = checkValue;
  516.     GetCheck (dPtr, SelectOut, &checkValue);
  517.     HS.selectOut = checkValue;
  518.     DisposDialog(dPtr);
  519.     DestroyHawkPopups();
  520.     return(TRUE);
  521.     }
  522.  
  523. /* Called for each run.
  524. The input selection popup depends on what extensions have
  525. been passed in for this run. A largely pointless exercise in
  526. dynamically maintaining a menu, yet Apple disapproves of
  527. disabling items in a popup menu, so this approach has the
  528. virtue of being not-officially-frowned-upon. */
  529. void CreateHawkProgramResourcePopups()
  530.     {
  531.     MenuHandle         theMenu;
  532.     
  533.     CreateInputPopup();
  534.     
  535.     theMenu = NewMenu(LibraryID, (StringPtr)"\pLibraries");
  536.     AppendMenu(theMenu, (StringPtr)"\pSelect library...");
  537.     InsertMenu(theMenu, -1);
  538.     
  539.     theMenu = NewMenu(InputID, (StringPtr)"\pInput");
  540.     if (HasGetFrontText())
  541.         {
  542.         inPop.frontSelected = 1;
  543.         inPop.frontAll = 2;
  544.         AppendMenu(theMenu, (StringPtr)"\pFront text selection");
  545.         AppendMenu(theMenu, (StringPtr)"\pAll of front text");
  546.         }
  547.     else
  548.         {
  549.         inPop.frontSelected = inPop.frontAll = 0;
  550.         }
  551.     if (HasGetNextMultiFile())
  552.         {
  553.         if (inPop.frontSelected)
  554.             inPop.multiSelected = 3;
  555.         else
  556.             inPop.multiSelected = 1;
  557.         AppendMenu(theMenu, (StringPtr)"\pMFS selected files");
  558.         }
  559.     else
  560.         inPop.multiSelected = 0;
  561.     if (inPop.frontSelected || inPop.multiSelected)
  562.         {
  563.         if (inPop.multiSelected == 3) /* all present */
  564.             inPop.specificFile = 5;
  565.         else if (inPop.multiSelected == 1) /* front options missing */
  566.             inPop.specificFile = 3;
  567.         else /* multi missing, therefore hasgetfront */
  568.             inPop.specificFile = 4;
  569.         AppendMenu(theMenu, (StringPtr)"\p-");
  570.         }
  571.     else
  572.         {
  573.         inPop.specificFile = 1;
  574.         }
  575.     /* This option is always available */
  576.     AppendMenu(theMenu, (StringPtr)"\pSelect input file...");
  577.     InsertMenu(theMenu, -1);
  578.     }
  579.  
  580. void CreateInputPopup()
  581.     {
  582.     MenuHandle         theMenu;
  583.     char            curvolName[32];
  584.     long            theDirID;
  585.     
  586.     theMenu = NewMenu(MainProgramID, (StringPtr)"\pMainProgram");
  587.     AppendMenu(theMenu, (StringPtr)"\pSelect unlisted program...");
  588.     
  589.     /* When hAWK is called, the current working folder is the one
  590.     containing hAWK - search it for the folder "hAWK programs.
  591.     If found, add all TEXT files whose names begin with $ to the
  592.     program popup, in alpha order. */
  593.     if (theDirID = FindHawkProgramFolder(curvolName, (char *)"\phAWK programs"))
  594.         AddProgramsToMenu(curvolName, theDirID, theMenu);
  595.     InsertMenu(theMenu, -1);
  596.     }
  597.  
  598. long FindHawkProgramFolder(char *curvolName, char *hawkFolderName)
  599.     {
  600.     HFileInfo    myCPB;
  601.     WDPBRec        theParms;
  602.     char        fName[32];
  603.     long        theDirID;
  604.     short            codeVRefNum, index = 1, len;
  605.     OSErr        err;
  606.     
  607.     
  608.     GetVol(NULL, &codeVRefNum);
  609.     /* Extract "\pVolName:" and dirID for code resource folder */
  610.     theParms.ioNamePtr = (StringPtr)(curvolName);
  611.     theParms.ioVRefNum = codeVRefNum;
  612.     theParms.ioWDIndex = 0;
  613.     theParms.ioWDProcID = 0;
  614.     if (PBGetWDInfo(&theParms,false))
  615.         {
  616.         OKStopAlert("Bad working directory");
  617.         return(0L);
  618.         }
  619.     len = curvolName[0];
  620.     curvolName[len + 1] = ':';
  621.     curvolName[0] = len + 1;
  622.     
  623.     theDirID = theParms.ioWDDirID;
  624.     
  625.     myCPB.ioNamePtr = (StringPtr)fName;
  626.     myCPB.ioVRefNum = theParms.ioWDVRefNum;
  627.     do
  628.         {
  629.         myCPB.ioFDirIndex = index;
  630.         myCPB.ioDirID = theDirID;
  631.         if ((err = PBGetCatInfo((CInfoPBPtr)&myCPB, FALSE)) == noErr)
  632.             {
  633.             if (((myCPB.ioFlAttrib>>4) & 0x01) == 1) /* a folder */
  634.                 {
  635.                 if (PEqualStrs((Byte *)fName, (Byte *)hawkFolderName))
  636.                     return(myCPB.ioDirID);
  637.                 }
  638.             }
  639.         ++index;
  640.         } while (err == noErr);
  641.     /* OKStopAlert("hawk program folder not found"); if you're testing */
  642.     return(0L);
  643.     }
  644.  
  645. void AddProgramsToMenu(char *curvolName, long theDirID, MenuHandle theMenu)
  646.     {
  647.     HFileInfo    myCPB;
  648.     WDPBRec        theParms;
  649.     HVolumeParam    vParms;
  650.     char        fName[32], volName[32];
  651.     short            index = 1, theVolRef, vRefNum;
  652.     OSErr        err;
  653.     Boolean        firstAdd = TRUE;
  654.     
  655.     /* Some shenanigans to open working directory for code resources */
  656.     BlockMove(curvolName, volName, 32);
  657.     vParms.ioCompletion = NULL;
  658.     vParms.ioNamePtr = (StringPtr)(volName);
  659.     vParms.ioVRefNum = -32768;
  660.     vParms.ioVolIndex = -1;
  661.     if (PBHGetVInfo((HParmBlkPtr)&vParms, FALSE))
  662.         theVolRef = 0;
  663.     else
  664.         theVolRef = vParms.ioVRefNum;
  665.     theParms.ioCompletion = NULL;
  666.     theParms.ioVRefNum = theVolRef;
  667.     theParms.ioNamePtr = NULL;
  668.     theParms.ioWDDirID = theDirID;
  669.     theParms.ioWDProcID = 'ERIK';
  670.     if (PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  671.         vRefNum = 0;
  672.     else
  673.         vRefNum = theParms.ioVRefNum;
  674.     
  675.     theParms.ioNamePtr = NULL;
  676.     theParms.ioVRefNum = vRefNum;
  677.     theParms.ioWDIndex = 0;
  678.     theParms.ioWDProcID = 0;
  679.     if (PBGetWDInfo(&theParms,false))
  680.         return;
  681.     HS.defaultVRefNum = vRefNum; /* saved away, folder is left open */
  682.     
  683.     myCPB.ioNamePtr = (StringPtr)fName;
  684.     myCPB.ioVRefNum = theParms.ioWDVRefNum;
  685.     do
  686.         {
  687.         myCPB.ioFDirIndex = index;
  688.         myCPB.ioDirID = theDirID;
  689.         if ((err = PBGetCatInfo((CInfoPBPtr)&myCPB, FALSE)) == noErr)
  690.             {
  691.             if (((myCPB.ioFlAttrib>>4) & 0x01) != 1) /* a file */
  692.                 {
  693.                 /* fName holds name of file */
  694.                 /* Is it the right kind of file? */
  695.                 if (myCPB.ioFlFndrInfo.fdType == 'TEXT'
  696.                     && fName[1] == '$')
  697.                     {
  698.                     if (firstAdd)
  699.                         {
  700.                         AppendMenu(theMenu, (StringPtr)"\p-");
  701.                         AppendMenu(theMenu, (StringPtr)"\p-");
  702.                         firstAdd = FALSE;
  703.                         }
  704.                     AlphaAppendMenu(theMenu, 4, fName);
  705.                     }
  706.                 }
  707.             }
  708.         ++index;
  709.         } while (err == noErr);
  710.     if (firstAdd) /* none added */
  711.         {
  712.         theParms.ioVRefNum = vRefNum;
  713.         PBCloseWD(&theParms, FALSE);
  714.         }
  715.     }
  716.  
  717. void AlphaAppendMenu(MenuHandle theMenu, short lowPoint, char *name)
  718.     {
  719.     short        newItemNum,
  720.             highPoint = CountMItems(theMenu);
  721.     
  722.     
  723.     newItemNum = AlphaMenuPos(name, theMenu, highPoint, lowPoint);
  724.     if (newItemNum > 0)
  725.         {
  726.         /*error duplicate - unlikely for file list. */
  727.         return;
  728.         }
  729.     else
  730.         newItemNum = -newItemNum;
  731.     InsMenuItem(theMenu, (StringPtr)"\pa", newItemNum - 1);
  732.     SetItem(theMenu, newItemNum, (StringPtr)name);
  733.     }
  734.  
  735. /* Binary search existing menu for match against nameptr; if
  736. match return lowPoint:highPoint. If no match let n = where name would
  737. be inserted, range lowPoint:highPoint+1, return -n. For insertion, do
  738. InsMenuItem(theMenu, (StringPtr)"\pa", n - 1); -see just above.
  739. */
  740. short AlphaMenuPos(char *name, MenuHandle theMenu, short highPoint, short lowPoint)
  741.     {
  742.     short        index;
  743.     
  744.     if (highPoint < lowPoint)
  745.         return(-lowPoint);
  746.     
  747.     do
  748.         {
  749.         index = (lowPoint + highPoint)/2;
  750.         if (MenuCompare(name, theMenu, index) < 0)
  751.             highPoint = index - 1;
  752.         else
  753.             lowPoint = index + 1;
  754.         } while (MenuCompare(name, theMenu, index) && lowPoint <= highPoint);
  755.     if (!MenuCompare(name, theMenu, index)) /* a hit */
  756.         return(index);
  757.     /* lowPoint went "one too far", ie it is number that name will be after insertion */
  758.     return(-lowPoint);
  759.     }
  760.  
  761. short MenuCompare(char *name, MenuHandle theMenu, short index)
  762.     {
  763.     char            itemStr[64];
  764.     
  765.     GetItem(theMenu, index, (StringPtr)itemStr);
  766.     /* Fudge, both mark and item strs are pascal, but warp to ptr/len vs pascal.
  767.     Sorry folks, doing it this way because I had the tested code already. */
  768.     return(PtrLenPascalCompare(name + 1L, name[0], itemStr));
  769.     }
  770.  
  771. /* Compare, for ptr, len vs pascal strings.
  772. Compare pattern with target, returning number
  773. reflecting alphabetical rather than ascii order.
  774. */
  775. typedef Byte *BPtr;
  776. short PtrLenPascalCompare(Ptr spatPtr, short patLen, Ptr stargetPtr)
  777.     {
  778.     BPtr    patPtr = (BPtr)spatPtr,
  779.             patEndPtr = patPtr + patLen,
  780.             curPtr = (BPtr)stargetPtr + 1,
  781.             curEndPtr = curPtr + (unsigned short)(stargetPtr[0]);
  782.     short        i, j;
  783.     
  784.     while (patPtr < patEndPtr && curPtr < curEndPtr && *patPtr == *curPtr)
  785.         {
  786.         ++patPtr;
  787.         ++curPtr;
  788.         }
  789.     
  790.     if (patPtr == patEndPtr && curPtr == curEndPtr) /* exact match */
  791.         return(0);
  792.     if (patPtr == patEndPtr && curPtr != curEndPtr) /* pattern too short */
  793.         return(-1);
  794.     if (patPtr != patEndPtr && curPtr == curEndPtr) /* starget too short */
  795.         return(1);
  796.     
  797.     /* true miscompare within string */
  798.     i = (short)*patPtr;
  799.     j = (short)*curPtr;
  800.     /* sequence: nonalpha, AaBbCc...Zz */
  801.     /* 'A' = 65, 'a' = 97; move 'U' to 'U'*2 + 256, 'u' to 'u'*2 + 193 */
  802.     /* 'A' -> 386, 'B' -> 388, 'a' -> 387, 'b' -> 389 etc */
  803.     if ('A' <= i && i <= 'Z')
  804.         i = i*2 + 256;
  805.     else if ('a' <= i && i <= 'z')
  806.         i = i*2 + 193;
  807.     if ('A' <= j && j <= 'Z')
  808.         j = j*2 + 256;
  809.     else if ('a' <= j && j <= 'z')
  810.         j = j*2 + 193;
  811.     return(i - j);
  812.     }
  813.  
  814. void DestroyHawkPopups()
  815.     {
  816.     MenuHandle    theMenu;
  817.     
  818.     theMenu = GetMHandle(MainProgramID);
  819.     if (!theMenu)
  820.         return;
  821.     DeleteMenu(MainProgramID);
  822.     DisposeMenu(theMenu);
  823.     
  824.     theMenu = GetMHandle(LibraryID);
  825.     if (!theMenu)
  826.         return;
  827.     DeleteMenu(LibraryID);
  828.     DisposeMenu(theMenu);
  829.     
  830.     theMenu = GetMHandle(InputID);
  831.     if (!theMenu)
  832.         return;
  833.     DeleteMenu(InputID);
  834.     DisposeMenu(theMenu);
  835.     }
  836.  
  837. /* Somebody's watching, so draw in the popup menus. */
  838. pascal void HawkPopProc(WindowPtr wdPtr, short item)
  839.     {
  840.     GrafPtr        savePort;
  841.     short            kind, menuNum, i, n, markChar;
  842.     Handle        theHandle;
  843.     MenuHandle    theMenu;
  844.     Rect        box;
  845.     Byte        mText[64];
  846.     
  847.     GetPort(&savePort);
  848.     SetPort (wdPtr);
  849.     if (item == LibraryPopup)
  850.         {
  851.         theMenu = GetMHandle(LibraryID);
  852.         menuNum = 1;
  853.         }
  854.     else if (item == ProgramPopup || item == InputPopup)
  855.         {
  856.         if (item == ProgramPopup)
  857.             theMenu = GetMHandle(MainProgramID);
  858.         else
  859.             theMenu = GetMHandle(InputID);
  860.         n = CountMItems(theMenu);
  861.         for (i = 1; i <= n; ++i)
  862.             {
  863.             GetItemMark(theMenu, i, &markChar);
  864.             if (markChar == ' ')
  865.                 break;
  866.             }
  867.         if (i <= n)
  868.             menuNum = i;
  869.         else
  870.             menuNum = 1;
  871.         }
  872.     else return;
  873.     
  874.     GetDItem(wdPtr, item, &kind, &theHandle, &box);
  875.     GetItem(theMenu, menuNum, mText);
  876.     EraseRect(&box);
  877.     TextBox(&(mText[1]),(unsigned char)(mText[0]),&box,teJustLeft);
  878.     box.left -= 1;
  879.     box.top -= 1;
  880.     box.right += 1;
  881.     box.bottom += 1;
  882.     FrameRect(&box);
  883.     MoveTo(box.left + 1, box.bottom);
  884.     LineTo(box.right, box.bottom);
  885.     MoveTo(box.right, box.top + 1);
  886.     LineTo(box.right, box.bottom);
  887.     SetPort(savePort);
  888.     }
  889.  
  890. pascal void ButtonProc(WindowPtr wdPtr, short item)
  891.     {
  892.     GrafPtr            savePort;
  893.     PenState        savePen;
  894.     Handle           h;
  895.     Rect            theBox;
  896.     short                theType, ovalSize, i;
  897.     Pattern            myWhite, myGray;
  898.     Boolean            needsFrame;
  899.     
  900.     GetDItem(wdPtr,item,&theType,&h,&theBox);
  901.     GetPort(&savePort);
  902.     SetPort(wdPtr);
  903.     GetPenState(&savePen);
  904.     PenNormal();
  905.     PenSize(2,2);
  906.     if (item == RunUserItem)
  907.         InsetRect(&theBox,-3,-3);
  908.     else if (item == VarUserItem)
  909.         {
  910.         needsFrame =(Boolean)(((WindowPeek)(wdPtr))->refCon);
  911.         if (needsFrame)
  912.             {
  913.             for (i = 0; i < 8; i += 2)
  914.                 myGray.pat[i] = 0xAA;
  915.             for (i = 1; i < 8; i += 2)
  916.                 myGray.pat[i] = 0x55;
  917.             PenPat(&myGray);
  918.             }
  919.         else
  920.             {
  921.             for (i = 0; i < 8; ++i)
  922.                 myWhite.pat[i] = 0;
  923.             PenPat(&myWhite);
  924.             }
  925.         InsetRect(&theBox,-2,-2);
  926.         
  927.         }
  928.     ovalSize = (theBox.bottom + 8 - theBox.top) / 2;    
  929.     FrameRoundRect(&theBox,ovalSize,ovalSize);
  930.     SetPenState(&savePen);
  931.     SetPort(savePort);
  932.     }
  933.  
  934. /* A space character is used to mark the currently-selected item,
  935. avoiding the horror of attempting to access global variables
  936. within the pascal callback above, within a CODE resource. */
  937. void SetPopupMark(short theMenuID, short newItem)
  938.     {
  939.     short            i, n, markChar;
  940.     MenuHandle    theMenu;
  941.     
  942.     theMenu = GetMHandle(theMenuID);
  943.     n = CountMItems(theMenu);
  944.     for (i = 1; i <= n; ++i)
  945.         {
  946.         GetItemMark(theMenu, i, &markChar);
  947.         if (markChar == ' ')
  948.             {
  949.             if (i == newItem)
  950.                 return;
  951.             else
  952.                 SetItemMark(theMenu, i, 0);
  953.             }
  954.         else if (i == newItem)
  955.             {
  956.             markChar = ' ';
  957.             SetItemMark(theMenu, i, markChar);
  958.             }
  959.         }
  960.     }
  961.  
  962. void ResetHS(DialogPtr dPtr)
  963.     {
  964.     MenuHandle    theMenu;
  965.     short        itemHit, numItems;
  966.     
  967.     SetCheck (dPtr, ShowOut, TRUE);
  968.     SetCheck (dPtr, SelectOut, TRUE);
  969.     mainProgMenuNum = libraryMenuNum = HS.inputType = 1;
  970.     HS.showOut = TRUE;
  971.     HS.selectOut = TRUE;
  972.     if (HS.progname)
  973.         {
  974.         DisposPtr(HS.progname);
  975.         HS.progname = NULL;
  976.         }
  977.     if (HS.inputname)
  978.         {
  979.         DisposPtr(HS.inputname);
  980.         HS.inputname = NULL;
  981.         }
  982.     for (itemHit = 0; itemHit < NUMLIBS; ++itemHit)
  983.         {
  984.         if (HS.libraryname[itemHit])
  985.             {
  986.             DisposPtr(HS.libraryname[itemHit]);
  987.             HS.libraryname[itemHit] = NULL;
  988.             }
  989.         }
  990.     for (itemHit = 0; itemHit < NUMVARSETS; ++itemHit)
  991.         {
  992.         if (HS.varsetting[itemHit])
  993.             {
  994.             DisposPtr(HS.varsetting[itemHit]);
  995.             HS.varsetting[itemHit] = NULL;
  996.             }
  997.         }
  998.     theMenu = GetMHandle(MainProgramID);
  999.     SetItem(theMenu, 1, (StringPtr)"\pSelect unlisted program...");
  1000.     theMenu = GetMHandle(LibraryID);
  1001.     itemHit = CountMItems(theMenu);
  1002.     while (--itemHit > 0)
  1003.         DelMenuItem(theMenu, 1);
  1004.     theMenu = GetMHandle(InputID);
  1005.     SetItem(theMenu, inPop.specificFile, (StringPtr)"\pSelect input file...");
  1006.     }
  1007.  
  1008. /* Set visual display and menus in Hawk dialog, and at end
  1009. convert all strings from pascal to c format. Note vars are not
  1010. shown here (but their strings are converted).
  1011. Assumes menus have been reset.
  1012. If progToo is FALSE, being called in response to HawkDlog main program popup
  1013. which retrieves and sets progname directly from open dialog, and also
  1014. sets menu entry. If progToo is TRUE, then have received progname from resource
  1015. and should then handle progname here - currently not needed.
  1016.  */
  1017. void LoadHawkDlogFromHS(DialogPtr dPtr, Boolean progToo)
  1018.     {
  1019.     MenuHandle    theMenu;
  1020.     short            i, numItems = 1;
  1021.     char        filename[32];
  1022.     
  1023.     /* Set the checks */
  1024.     SetCheck (dPtr, ShowOut, HS.showOut);
  1025.     SetCheck (dPtr, SelectOut, HS.selectOut);
  1026.     
  1027.     if (progToo)
  1028.         {
  1029.         PtoCstr((StringPtr)HS.progname);
  1030.         GetMenuEntryFromFullName(HS.progname, filename);
  1031.         theMenu = GetMHandle(MainProgramID);
  1032.         SetItem(theMenu, 1, (StringPtr)filename);
  1033.         }
  1034.     /* variables - nothing shown, just convert strings */
  1035.     for (i = 0; i < NUMVARSETS; ++i)
  1036.         {
  1037.         if (HS.varsetting[i])
  1038.             PtoCstr((StringPtr)HS.varsetting[i]);
  1039.         else
  1040.             break;
  1041.         }
  1042.     /* dialog's refCon used to tell ButtonProc if variables exist */
  1043.     if (i)
  1044.         ((WindowPeek)(dPtr))->refCon = 1;
  1045.     else
  1046.         ((WindowPeek)(dPtr))->refCon = 0;
  1047.     /* libraries - append to menu and convert strings */
  1048.     theMenu = GetMHandle(LibraryID);
  1049.     for (i = 0; i < NUMLIBS; ++i)
  1050.         {
  1051.         if (HS.libraryname[i])
  1052.             {
  1053.             PtoCstr((StringPtr)HS.libraryname[i]);
  1054.             GetMenuEntryFromFullName(HS.libraryname[i], filename);
  1055.             if (numItems == 1)
  1056.                 {
  1057.                 InsMenuItem(theMenu, (StringPtr)"\pa", 0);
  1058.                 SetItem(theMenu, 1, (StringPtr)filename);
  1059.                 InsMenuItem(theMenu, (StringPtr)"\p-", 1);
  1060.                 }
  1061.             else
  1062.                 {
  1063.                 InsMenuItem(theMenu, (StringPtr)"\pa", numItems-2);
  1064.                 SetItem(theMenu, numItems-1, (StringPtr)filename);
  1065.                 }
  1066.             ++numItems;
  1067.             
  1068.             }
  1069.         else
  1070.             break;
  1071.         }
  1072.     /* input - set input file name */
  1073.     if (HS.inputType == inPop.specificFile)
  1074.         {
  1075.         if (HS.inputname)
  1076.             {
  1077.             PtoCstr((StringPtr)HS.inputname);
  1078.             GetMenuEntryFromFullName(HS.inputname, filename);
  1079.             if (filename[0])
  1080.                 {
  1081.                 theMenu = GetMHandle(InputID);
  1082.                 SetItem(theMenu, inPop.specificFile, (StringPtr)filename);
  1083.                 }
  1084.             }
  1085.         }
  1086.     }
  1087.  
  1088. /* Extract pstr filename from end of cstr full path name */
  1089. void GetMenuEntryFromFullName(char *name, char *filename)
  1090.     {
  1091.     short len = strlen(name);
  1092.     Ptr    endPtr = name + len, startPtr = endPtr ;
  1093.     
  1094.     while (startPtr >= name)
  1095.         {
  1096.         if (*startPtr == ':')
  1097.             break;
  1098.         --startPtr;
  1099.         }
  1100.     ++startPtr;
  1101.     if (startPtr >= endPtr)
  1102.         {
  1103.         filename[0] = 0;
  1104.         return;
  1105.         }
  1106.     filename[0] = endPtr - startPtr;
  1107.     BlockMove(startPtr, filename+1, filename[0]);
  1108.     }
  1109.  
  1110. void SaveInvocation(DialogPtr dPtr, char *name)
  1111.     {
  1112.     short         saveVol, refNum, vRefNum;
  1113.     Handle        rHdle;
  1114.     char         filename[32];
  1115.     short         len = strlen(name);
  1116.     Ptr            endPtr = name + len, startPtr = endPtr ;
  1117.     
  1118.     while (startPtr >= name)
  1119.         {
  1120.         if (*startPtr == ':')
  1121.             break;
  1122.         --startPtr;
  1123.         }
  1124.     ++startPtr;
  1125.     if (startPtr >= endPtr) return;
  1126.     filename[0] = endPtr - startPtr;
  1127.     BlockMove(startPtr, filename+1, filename[0]);
  1128.     
  1129.     vRefNum = HS.progVRefNum;
  1130.     if (!vRefNum) return;
  1131.     
  1132.     if (GetVol(NULL, &saveVol))
  1133.         saveVol = 0;
  1134.  
  1135.     SetVol(NULL, vRefNum);
  1136.     if (refNum = OpenOrCreateResourceFork((StringPtr)filename))
  1137.         {
  1138.         if (rHdle = CreateHawkProgramResource(dPtr))
  1139.             {
  1140.             DeleteAllExistingRsrcs('HAWK', HAWKID);
  1141.             AddResource(rHdle, 'HAWK', HAWKID, (StringPtr)"");
  1142.             }
  1143.         CloseResFile (refNum);
  1144.         }
  1145.     /* Reset volume to original one */
  1146.     if (saveVol)
  1147.         SetVol(NULL, saveVol);
  1148.     /* Make sure changes are written out */
  1149.     FlushVol(NULL, vRefNum);
  1150.     }
  1151.  
  1152. /* Note all strings are c strings coming in (and going out).
  1153. Only HS.inputType requires special attention: it is the menu
  1154. item number corresponding to the currently-selected input
  1155. option, and varies according to which extensions from the
  1156. calling application have currently been made available. To avoid
  1157. confusion, the number saved is the one that would be used if all
  1158. extensions were present. */
  1159. Handle CreateHawkProgramResource(DialogPtr dPtr)
  1160.     {
  1161.     Handle    resH;
  1162.     Ptr        tPtr;
  1163.     long    size;
  1164.     short        numLibs = 0, numVars = 0, i, len;
  1165.     
  1166.     if (!(HS.progname)) return(NULL);
  1167.     /* precalc size of handle */
  1168.     size = 8;
  1169.     size += strlen(HS.progname) + 1;
  1170.     for (i = 0; i <= NUMLIBS; ++i)
  1171.         {
  1172.         if (!(HS.libraryname[i]))
  1173.             break;
  1174.         size += strlen(HS.libraryname[i]) + 1;
  1175.         ++numLibs;
  1176.         }
  1177.     for (i = 0; i < NUMVARSETS; ++i)
  1178.         {
  1179.         if (!(HS.varsetting[i]))
  1180.             break;
  1181.         size += strlen(HS.varsetting[i]) + 1;
  1182.         ++numVars;
  1183.         }
  1184.     if (HS.inputType == inPop.specificFile)
  1185.         size += strlen(HS.inputname) + 1;
  1186.     
  1187.     GetCheck(dPtr, ShowOut, &(HS.showOut));
  1188.     GetCheck(dPtr, SelectOut, &(HS.selectOut));
  1189.     
  1190.     resH = NewHandle(size);
  1191.     if (MemError() != noErr)
  1192.         return(NULL);
  1193.     tPtr = *resH;
  1194.     len = HS.inputType;
  1195.     if (inPop.specificFile < 5) /* adjust recorded input type */
  1196.         {
  1197.         /* Boost value of HS.inputType to what it would be if all
  1198.         input options were present - here we know that either the two
  1199.         front text options or the multifile option or both are missing. */
  1200.         if (HS.inputType == 1)
  1201.             {
  1202.             if (inPop.frontSelected == 0 && inPop.multiSelected == 0)
  1203.                 HS.inputType = 5;
  1204.             else if (inPop.frontSelected == 0)
  1205.                 HS.inputType = 3;
  1206.             else
  1207.                 HS.inputType = 1;
  1208.             }
  1209.         else if (HS.inputType == 3) /* implies inPop.frontSelected == 0 */
  1210.             HS.inputType = 5;
  1211.         else if (HS.inputType == 4) /* implies inPop.multiSelected == 0 */
  1212.             HS.inputType = 5;
  1213.         /* note HS.inputType == 2 needs no adjusting */
  1214.         }
  1215.     BlockMove((Ptr)(&HS.inputType), tPtr, 2);
  1216.     HS.inputType = len;
  1217.     tPtr += 2;
  1218.     BlockMove((Ptr)(&HS.showOut), tPtr, 1);
  1219.     ++tPtr;
  1220.     BlockMove((Ptr)(&HS.selectOut), tPtr, 1);
  1221.     ++tPtr;
  1222.     BlockMove((Ptr)(&numLibs), tPtr, 2);
  1223.     tPtr += 2;
  1224.     BlockMove((Ptr)(&numVars), tPtr, 2);
  1225.     tPtr += 2;
  1226.     /* Save text items in pascal format for easier read/write/setup */
  1227.     len = strlen(HS.progname);
  1228.     *tPtr++ = len;
  1229.     BlockMove(HS.progname, tPtr, len);
  1230.     tPtr += len;
  1231.     for (i = 0; i < NUMLIBS; ++i)
  1232.         {
  1233.         if (!(HS.libraryname[i]))
  1234.             break;
  1235.         len = strlen(HS.libraryname[i]);
  1236.         *tPtr++ = len;
  1237.         BlockMove(HS.libraryname[i], tPtr, len);
  1238.         tPtr += len;
  1239.         }
  1240.     for (i = 0; i < NUMVARSETS; ++i)
  1241.         {
  1242.         if (!(HS.varsetting[i]))
  1243.             break;
  1244.         len = strlen(HS.varsetting[i]);
  1245.         *tPtr++ = len;
  1246.         BlockMove(HS.varsetting[i], tPtr, len);
  1247.         tPtr += len;
  1248.         }
  1249.     if (HS.inputType == inPop.specificFile)
  1250.         {
  1251.         len = strlen(HS.inputname);
  1252.         *tPtr++ = len;
  1253.         BlockMove(HS.inputname, tPtr, len);
  1254.         }
  1255.     return(resH);
  1256.     }
  1257.  
  1258. /* Open res fork of Hawk pgm, copy setup info to HS. */
  1259. Boolean ReadHAWKResource(char *name) /* to HS */
  1260.     {
  1261.     short         saveVol, refNum, vRefNum;
  1262.     Handle        rHdle;
  1263.     char         filename[32];
  1264.     short         len = strlen(name);
  1265.     Ptr            endPtr = name + len, startPtr = endPtr ;
  1266.     
  1267.     while (startPtr >= name)
  1268.         {
  1269.         if (*startPtr == ':')
  1270.             break;
  1271.         --startPtr;
  1272.         }
  1273.     ++startPtr;
  1274.     if (startPtr >= endPtr) return(FALSE);
  1275.     filename[0] = endPtr - startPtr;
  1276.     BlockMove(startPtr, filename+1, filename[0]);
  1277.     
  1278.     vRefNum = HS.progVRefNum;
  1279.     if (!vRefNum) return(FALSE);
  1280.     
  1281.     if (GetVol(NULL, &saveVol))
  1282.         saveVol = 0;
  1283.     SetVol(NULL, vRefNum);
  1284.     
  1285.     if ((refNum = OpenResFile((StringPtr)filename)) != -1)
  1286.         {
  1287.         rHdle = Get1Resource ('HAWK', HAWKID);
  1288.         if (!rHdle)
  1289.             {
  1290.             CloseResFile(refNum);
  1291.             if (saveVol)
  1292.                 SetVol(NULL, saveVol);
  1293.             return(FALSE);
  1294.             }
  1295.         /* Convert raw rsrc to HS */
  1296.         ConvertRsrcToHS(rHdle);
  1297.         ReleaseResource(rHdle);
  1298.         CloseResFile(refNum);
  1299.         }
  1300.     /* Restore default volume if any */
  1301.     if (saveVol)
  1302.         SetVol(NULL, saveVol);
  1303.     if (refNum == -1)
  1304.         return(FALSE);
  1305.     return(TRUE);
  1306.     }
  1307.  
  1308. /* This should be passed -fProgramFullPathName.
  1309. */
  1310. Boolean FSpReadHAWKResource(char *name) /* to HS */
  1311.     {
  1312.     short         saveVol, refNum;
  1313.     Handle        rHdle;
  1314.     Str255         filename;
  1315.     short         len = strlen(name);
  1316.     Ptr            startPtr = name + len;
  1317.     
  1318.     while (startPtr >= name)
  1319.         {
  1320.         if (*startPtr == ':')
  1321.             break;
  1322.         --startPtr;
  1323.         }
  1324.     if (startPtr <= name)
  1325.         return FALSE;
  1326.     
  1327.     // Remember to strip -f
  1328.     if (len-2 > 0)
  1329.         {
  1330.         filename[0] = len-2;
  1331.         BlockMove(name+2, filename+1, filename[0]);
  1332.         }
  1333.     else
  1334.         return FALSE;
  1335.     
  1336.     if (GetVol(NULL, &saveVol))
  1337.         saveVol = 0;
  1338.  
  1339.     if ((refNum = OpenResFile((StringPtr)filename)) != -1)
  1340.         {
  1341.         rHdle = Get1Resource ('HAWK', HAWKID);
  1342.         if (!rHdle)
  1343.             {
  1344.             CloseResFile(refNum);
  1345.             if (saveVol)
  1346.                 SetVol(NULL, saveVol);
  1347.             return(FALSE);
  1348.             }
  1349.         /* Convert raw rsrc to HS */
  1350.         ConvertRsrcToHS(rHdle);
  1351.         ReleaseResource(rHdle);
  1352.         CloseResFile(refNum);
  1353.         }
  1354.     /* Restore default volume if any */
  1355.     if (saveVol)
  1356.         SetVol(NULL, saveVol);
  1357.     if (refNum == -1)
  1358.         return(FALSE);
  1359.     return(TRUE);
  1360.     }
  1361.  
  1362. /* Retrieve HawkSetup data, with strings in pascal format for the moment.
  1363. Set progname only if it has not already been set.
  1364. HS.inputType was saved as though all extensions present - if 
  1365. currently some extensions are missing then inputType needs adjusting.
  1366. The default for a missing choice is inPop.specificFile. */
  1367. void ConvertRsrcToHS(Handle h)
  1368.     {
  1369.     Ptr        tPtr, endPtr;
  1370.     long    size;
  1371.     short        numLibs, numVars, i, len, recordedInputType;
  1372.     
  1373.     //MoveHHi(h);
  1374.     HLock(h);
  1375.     tPtr = *h;
  1376.     size = GetHandleSize(h);
  1377.     endPtr = tPtr + size;
  1378.     BlockMove(tPtr, (Ptr)(&HS.inputType), 2);
  1379.     recordedInputType = HS.inputType;
  1380.     /* adjust inputType if extension(s) missing */
  1381.     if (inPop.specificFile < 5) /* adjust input type */
  1382.         {
  1383.         if (HS.inputType == 1 || HS.inputType == 2)
  1384.             {
  1385.             /* the frontSelected/frontAll options, not valid if 
  1386.             inPop.frontSelected == 0 */
  1387.             if (inPop.frontSelected == 0)
  1388.                 HS.inputType = inPop.specificFile;
  1389.             }
  1390.         else if (HS.inputType == 3)
  1391.             {
  1392.             /* multiSelected option - not valid if inPop.multiSelected == 0,
  1393.             and adjust if inPop.frontSelected == 0 */
  1394.             if (inPop.multiSelected == 0)
  1395.                 HS.inputType = inPop.specificFile;
  1396.             else if (inPop.frontSelected == 0)
  1397.                 HS.inputType = inPop.multiSelected;
  1398.             }
  1399.         else if (HS.inputType == 5) /* always valid */
  1400.             {
  1401.             if (inPop.frontSelected == 0 && inPop.multiSelected == 0)
  1402.                 HS.inputType = 1;
  1403.             else if (inPop.frontSelected == 0)
  1404.                 HS.inputType = 3;
  1405.             else
  1406.                 HS.inputType = 4;
  1407.             }
  1408.         /* note  4 not possible - in the full menu it's a dashed line */
  1409.         }
  1410.     tPtr += 2;
  1411.     BlockMove(tPtr, (Ptr)(&HS.showOut), 1);
  1412.     ++tPtr;
  1413.     BlockMove(tPtr, (Ptr)(&HS.selectOut), 1);
  1414.     ++tPtr;
  1415.     BlockMove(tPtr, (Ptr)(&numLibs), 2);
  1416.     tPtr += 2;
  1417.     BlockMove(tPtr, (Ptr)(&numVars), 2);
  1418.     tPtr += 2;
  1419.     len = *tPtr++;
  1420.     if (tPtr + len > endPtr)
  1421.         goto NoGo;
  1422.     if (!(HS.progname))
  1423.         {
  1424.         HS.progname = NewPtr(len+1);
  1425.         if (MemError() != noErr)
  1426.             goto NoGo;
  1427.         HS.progname[0] = len;
  1428.         BlockMove(tPtr, HS.progname+1, len);
  1429.         }
  1430.     tPtr += len;
  1431.     for (i = 0; i < numLibs; ++i)
  1432.         {
  1433.         len = *tPtr++;
  1434.         if (tPtr + len > endPtr)
  1435.             goto NoGo;
  1436.         HS.libraryname[i] = NewPtr(len+1);
  1437.         if (MemError() != noErr)
  1438.             goto NoGo;
  1439.         HS.libraryname[i][0] = len;
  1440.         BlockMove(tPtr, HS.libraryname[i]+1, len);
  1441.         tPtr += len;
  1442.         }
  1443.     for (i = 0; i < numVars; ++i)
  1444.         {
  1445.         len = *tPtr++;
  1446.         if (tPtr + len > endPtr)
  1447.             goto NoGo;
  1448.         HS.varsetting[i] = NewPtr(len+1);
  1449.         if (MemError() != noErr)
  1450.             goto NoGo;
  1451.         HS.varsetting[i][0] = len;
  1452.         BlockMove(tPtr, HS.varsetting[i]+1, len);
  1453.         tPtr += len;
  1454.         }
  1455.     if (recordedInputType == 5)
  1456.         {
  1457.         len = *tPtr++;
  1458.         if (tPtr + len > endPtr)
  1459.             goto NoGo;
  1460.         HS.inputname = NewPtr(len+1);
  1461.         if (MemError() != noErr)
  1462.             goto NoGo;
  1463.         HS.inputname[0] = len;
  1464.         BlockMove(tPtr, HS.inputname+1, len);
  1465.         }
  1466.     HUnlock(h);
  1467.     return;
  1468. NoGo:
  1469.     HUnlock(h);
  1470.     ClearHS();
  1471.     return;
  1472.     }
  1473.  
  1474. void ClearHS()
  1475.     {
  1476.     short        itemHit;
  1477.     
  1478.     HS.showOut = TRUE;
  1479.     HS.selectOut = TRUE;
  1480.     if (HS.inputname)
  1481.         {
  1482.         DisposPtr(HS.inputname);
  1483.         HS.inputname = NULL;
  1484.         }
  1485.     for (itemHit = 0; itemHit < NUMLIBS; ++itemHit)
  1486.         {
  1487.         if (HS.libraryname[itemHit])
  1488.             {
  1489.             DisposPtr(HS.libraryname[itemHit]);
  1490.             HS.libraryname[itemHit] = NULL;
  1491.             }
  1492.         }
  1493.     for (itemHit = 0; itemHit < NUMVARSETS; ++itemHit)
  1494.         {
  1495.         if (HS.varsetting[itemHit])
  1496.             {
  1497.             DisposPtr(HS.varsetting[itemHit]);
  1498.             HS.varsetting[itemHit] = NULL;
  1499.             }
  1500.         }
  1501.     }
  1502.  
  1503. void RedrawItem(DialogPtr dPtr, short itemHit)
  1504.     {
  1505.     GrafPtr        savePort;
  1506.     short            kind;
  1507.     Handle        theHandle;
  1508.     MenuHandle    theMenu;
  1509.     Rect        box;
  1510.     
  1511.     GetPort(&savePort);
  1512.     SetPort (dPtr);
  1513.     GetDItem(dPtr, itemHit, &kind, &theHandle, &box);
  1514.     InvalRect(&box);
  1515.     SetPort(savePort);
  1516.     }
  1517.  
  1518. void RedrawDialog(DialogPtr dPtr)
  1519.     {
  1520.     GrafPtr        savePort;
  1521.     
  1522.     GetPort(&savePort);
  1523.     SetPort (dPtr);
  1524.     InvalRect(&dPtr->portRect);
  1525.     SetPort(savePort);
  1526.     }
  1527.  
  1528. #define VARDlog        407
  1529. #define FirstVARID    4
  1530.  
  1531. /* The variables dialog. Needs a bit more error-checking. */
  1532. Boolean DoVarDialog(DialogPtr hAWKDLOGdPtr)
  1533.     {
  1534.     DialogPtr        dPtr;
  1535.     short                itemHit, theType, i, j;
  1536.     char            varStr[100];
  1537.     
  1538.     if (!GetAndAlignDialog(VARDlog))
  1539.         return(FALSE);
  1540.     dPtr = GetNewDialog(VARDlog, NULL, (WindowPtr)-1L);
  1541.     LoadExistingVarsToDlog(dPtr);
  1542.     ShowWindow(dPtr);
  1543.     FrameDialogItem(dPtr,1);
  1544.     InitCursor();
  1545.     itemHit = 99;
  1546.     while (itemHit > 2)
  1547.         {
  1548.         ModalDialog(NULL, &itemHit);
  1549.         /* Check length if you think someone might type > 99 characters */
  1550.         if (itemHit == 1) /* check format */
  1551.             {
  1552.             if ((itemHit = BadVarFormat(dPtr)) > 3)
  1553.                 {
  1554.                 SysBeep(2);
  1555.                 SelIText(dPtr, itemHit, 0, 32767);
  1556.                 }
  1557.             }
  1558.         }
  1559.     if (itemHit == 2) /* cancel */
  1560.         {
  1561.         DisposDialog(dPtr);
  1562.         return(TRUE);
  1563.         }
  1564.     /* Record new variable settings */
  1565.     j = 0;
  1566.     for (i = FirstVARID; i < FirstVARID + NUMVARSETS; ++i)
  1567.         {
  1568.         GetEText(dPtr, i, (StringPtr) varStr);
  1569.         if (varStr[0])
  1570.             {
  1571.             HS.varsetting[j] = NewPtr(varStr[0] + 3);
  1572.             if (MemError() != noErr)
  1573.                 return(FALSE);
  1574.             HS.varsetting[j][0] = varStr[0] + 2;
  1575.             BlockMove(varStr+1, HS.varsetting[j] + 3, varStr[0]);
  1576.             /* stick -v in front */
  1577.             HS.varsetting[j][1] = '-';
  1578.             HS.varsetting[j][2] = 'v';
  1579.             PtoCstr((StringPtr)HS.varsetting[j]);
  1580.             ++j;
  1581.             }
  1582.         }
  1583.     /* dialog's refCon used to tell ButtonProc if variables exist */
  1584.     if (j)
  1585.         ((WindowPeek)(hAWKDLOGdPtr))->refCon = 1;
  1586.     else
  1587.         ((WindowPeek)(hAWKDLOGdPtr))->refCon = 0;
  1588.     /* null out any left over */
  1589.     while (j < NUMVARSETS)
  1590.         {
  1591.         HS.varsetting[j++] = NULL;
  1592.         }
  1593.     DisposDialog(dPtr);
  1594.     return(TRUE);
  1595.     }
  1596.  
  1597. void LoadExistingVarsToDlog(DialogPtr dPtr)
  1598.     {
  1599.     short        itemHit;
  1600.     
  1601.     /* set the fields before showing */
  1602.     for (itemHit = 0; itemHit < NUMVARSETS; ++itemHit)
  1603.         {
  1604.         if (HS.varsetting[itemHit] && strlen(HS.varsetting[itemHit]))
  1605.             {
  1606.             /* Minor complication - have -v in front */
  1607.             CtoPstr(HS.varsetting[itemHit]+2);
  1608.             SetEText(dPtr, FirstVARID + itemHit, 
  1609.                 (StringPtr) (HS.varsetting[itemHit]+2));
  1610.             PtoCstr((StringPtr)HS.varsetting[itemHit]+2);
  1611.             }
  1612.         else
  1613.             SetEText(dPtr, FirstVARID + itemHit, 
  1614.                 (StringPtr) "\p");
  1615.         }
  1616.     }
  1617.  
  1618. /* Return 1 if all vars OK, var item number if one is bad (>= 4) */
  1619. short BadVarFormat(DialogPtr dPtr)
  1620.     {
  1621.     short                i, j, len;
  1622.     char            varStr[100];
  1623.     
  1624.     /* Variable format is varname=something. This is a quick check. */
  1625.     for (i = FirstVARID; i < FirstVARID + NUMVARSETS; ++i)
  1626.         {
  1627.         GetEText(dPtr, i, (StringPtr) varStr);
  1628.         if (varStr[0])
  1629.             {
  1630.             len = varStr[0];
  1631.             for (j = 1; j <= len; ++j)
  1632.                 {
  1633.                 if (varStr[j] == '=')
  1634.                     break;
  1635.                 }
  1636.             if (j >= len || j == 1)
  1637.                 return(i);
  1638.             }
  1639.         }
  1640.     return(1);
  1641.     }
  1642.  
  1643. void GetHawkProgramName(DialogPtr dPtr, short item)
  1644.     {
  1645.     MenuHandle    theMenu;
  1646.     Point         where;
  1647.     SFReply     reply;
  1648.     SFTypeList     types;
  1649.     long        len;
  1650.     short            numTypes;
  1651.     Boolean        userLocated;
  1652.     
  1653.     if (item == 1)
  1654.         {
  1655.         /* display dialog, get program name and input file name */
  1656.         types[0] = 'TEXT';
  1657.         types[1] = 'RRRS';
  1658.         numTypes = 2;
  1659.         GetDlogOrigin (getDlgID, &where);
  1660.         SFGetFile (where, (StringPtr)"\p", NULL, numTypes, types, NULL, &reply);
  1661.         if (!reply.good)
  1662.             return;
  1663.         userLocated = TRUE;
  1664.         }
  1665.     else /* either listed or unlisted program - the unlisted one is number 3 */
  1666.         {
  1667.         if (item == mainProgMenuNum) /* nothing new */
  1668.             return;
  1669.         theMenu = GetMHandle(MainProgramID);
  1670.         GetItem(theMenu, item, (StringPtr)(reply.fName));
  1671.         userLocated = FALSE;
  1672.         }
  1673.     /* reset HS and dialog */
  1674.     ResetHS(dPtr);
  1675.     
  1676.     HS.progname = NewPtr(256);
  1677.     if (MemError() != noErr)
  1678.         {
  1679.         HS.progVRefNum = 0;
  1680.         MemoryAlert();
  1681.         HiliteDlgControl(dPtr, 1, 255);
  1682.         HiliteDlgControl(dPtr, SaveHawkSetup, 255);
  1683.         return;
  1684.         }
  1685.     if (userLocated)
  1686.         HS.progVRefNum = reply.vRefNum;
  1687.     else if (item == 3)
  1688.         HS.progVRefNum = HS.otherVRefNum;
  1689.     else
  1690.         HS.progVRefNum = HS.defaultVRefNum;
  1691.     if (userLocated)
  1692.         mainProgMenuNum = 3;
  1693.     else
  1694.         mainProgMenuNum = item;
  1695.     AppendPStr((Byte *)(FullPathNameFromVRefNum(HS.progVRefNum,(Byte *)(HS.progname))),
  1696.         (Byte *)(reply.fName));
  1697.     /* stick -f in front */
  1698.     BlockMove(HS.progname+1, HS.progname + 3, 253);
  1699.     HS.progname[0] += 2;
  1700.     HS.progname[1] = '-';
  1701.     HS.progname[2] = 'f';
  1702.     SetPtrSize(HS.progname, HS.progname[0]+1);
  1703.     PtoCstr((StringPtr)HS.progname); /* also done by LoadHawkDlogFromHS */
  1704.     /* Restore saved invocation */
  1705.     if (ReadHAWKResource(HS.progname))
  1706.         LoadHawkDlogFromHS(dPtr, FALSE); /* Boolean progToo */
  1707.     theMenu = GetMHandle(MainProgramID);
  1708.     if (userLocated)
  1709.         SetItem(theMenu, 3, reply.fName);
  1710.     /* Enable Run and SaveSettings buttons */
  1711.     HiliteDlgControl(dPtr, 1, 0);
  1712.     HiliteDlgControl(dPtr, SaveHawkSetup, 0);
  1713.     if (item == 1)
  1714.         item = 3;
  1715.     SetPopupMark(MainProgramID, item);
  1716.  
  1717.     /* Redraw done by caller */
  1718.     }
  1719.  
  1720. /* Delete/add library. Add new item just before dash. */
  1721. void GetHawkLibraryName(short menuItem)
  1722.     {
  1723.     MenuHandle    theMenu;
  1724.     Point         where;
  1725.     SFReply     reply;
  1726.     SFTypeList     types;
  1727.     long        len;
  1728.     short            numTypes, numItems, which, i;
  1729.     Boolean        hasLib;
  1730.     
  1731.     theMenu = GetMHandle(LibraryID);
  1732.     numItems = CountMItems(theMenu);
  1733.     if (menuItem < numItems) /* delete */
  1734.         {
  1735.         DelMenuItem(theMenu, menuItem);
  1736.         if (numItems == 3)
  1737.             DelMenuItem(theMenu, 1); /* take out the dash */
  1738.         which = menuItem-1;
  1739.         if (HS.libraryname[which])
  1740.             {
  1741.             DisposPtr(HS.libraryname[which]);
  1742.             HS.libraryname[which] = NULL;
  1743.             /* consolidate pointers */
  1744.             if (which == NUMLIBS-1) return;
  1745.             BlockMove((Ptr)(&(HS.libraryname[which])), 
  1746.                 (Ptr)(&(HS.libraryname[which+1])), 
  1747.                 sizeof(char *) * (NUMLIBS-1 - which));
  1748.             }
  1749.         return;
  1750.         }
  1751.     /* add new library at end of list */
  1752.     which = 0;
  1753.     
  1754.     /* display dialog, get program name and input file name */
  1755.     types[0] = 'TEXT';
  1756.     types[1] = 'RRRS';
  1757.     numTypes = 2;
  1758.     GetDlogOrigin (getDlgID, &where);
  1759.     SFGetFile (where, (StringPtr)"\p", NULL, numTypes, types, NULL, &reply);
  1760.     if (!reply.good)
  1761.         return;
  1762.     HS.libraryname[which] = NewPtr(256);
  1763.     if (MemError() != noErr)
  1764.         {
  1765.         MemoryAlert();
  1766.         return;
  1767.         }
  1768.     AppendPStr((Byte *)(FullPathNameFromVRefNum(reply.vRefNum,(Byte *)(HS.libraryname[which]))),
  1769.         (Byte *)(reply.fName));
  1770.     /* stick -f in front */
  1771.     BlockMove(HS.libraryname[which]+1, HS.libraryname[which] + 3, 253);
  1772.     HS.libraryname[which][0] += 2;
  1773.     HS.libraryname[which][1] = '-';
  1774.     HS.libraryname[which][2] = 'f';
  1775.     PtoCstr((StringPtr)HS.libraryname[which]);
  1776.     /* Set menu */
  1777.     if (numItems == 1)
  1778.         {
  1779.         InsMenuItem(theMenu, (StringPtr)"\pa", 0);
  1780.         SetItem(theMenu, 1, reply.fName);
  1781.         InsMenuItem(theMenu, (StringPtr)"\p-", 1);
  1782.         }
  1783.     else
  1784.         {
  1785.         InsMenuItem(theMenu, (StringPtr)"\pa", numItems-2);
  1786.         SetItem(theMenu, numItems-1, reply.fName);
  1787.         }
  1788.     }
  1789.  
  1790. void GetInputFileName()
  1791.     {
  1792.     MenuHandle    theMenu;
  1793.     Point         where;
  1794.     SFReply     reply;
  1795.     SFTypeList     types;
  1796.     long        len;
  1797.     short            numTypes;
  1798.     
  1799.     /* display dialog, get program name and input file name */
  1800.     types[0] = 'TEXT';
  1801.     types[1] = 'RRRS';
  1802.     numTypes = 2;
  1803.     GetDlogOrigin (getDlgID, &where);
  1804.     SFGetFile (where, (StringPtr)"\p", NULL, numTypes, types, NULL, &reply);
  1805.     if (!reply.good)
  1806.         return;
  1807.     
  1808.     if (HS.inputname)
  1809.         {
  1810.         DisposPtr(HS.inputname);
  1811.         HS.inputname = NULL;
  1812.         }
  1813.     HS.inputname = NewPtr(256);
  1814.     if (MemError() != noErr)
  1815.         {
  1816.         MemoryAlert();
  1817.         return;
  1818.         }
  1819.     AppendPStr((Byte *)(FullPathNameFromVRefNum(reply.vRefNum,(Byte *)(HS.inputname))),
  1820.         (Byte *)(reply.fName));
  1821.     PtoCstr((StringPtr)HS.inputname);
  1822.     /* Set menu */
  1823.     theMenu = GetMHandle(InputID);
  1824.     SetItem(theMenu, inPop.specificFile, reply.fName);
  1825.     }
  1826.  
  1827. /* Command line for awk proper, generated from user
  1828. dialog choices and variable entries.
  1829. HAWK -fProgname -fLibraries -vVariables -- inputfiles
  1830. */
  1831. Boolean GetCommandLineFromDlogResult()
  1832.     {
  1833.     long    len;
  1834.     short        i;
  1835.     
  1836.     if (!(HS.progname))
  1837.         {
  1838.         SysBeep(2); /* - can't do much without a program. */
  1839.         return(FALSE);
  1840.         }
  1841.     if (HS.inputType == inPop.specificFile && !(HS.inputname))
  1842.         {
  1843.         /* A suspicious case, arrived at either thru:
  1844.         - pick "Specific file..." option for input, and then cancel
  1845.             to, in effect, select the empty file; or
  1846.         - saved input option does not exist for this run, have defaulted
  1847.             to this case.
  1848.         Since a hAWK program can still do things in its BEGIN block even with
  1849.         no input file, allow the "no input at all" option to proceed. */
  1850.         ;
  1851.         }
  1852.     argc = 0;
  1853.     argv = (char **)malloc( sizeof(char *) * NUMARGVS );
  1854.     if (argv == NULL)
  1855.         {
  1856.         CleanUpAfterHAWK();
  1857.         return(FALSE);
  1858.         }
  1859.     /* hawk name always as first arg */
  1860.     len = strlen(gacc.thisCodeName);
  1861.     argv[argc] = NewPtr(len+1);
  1862.     if (!argv[argc])
  1863.         return(FALSE);
  1864.     BlockMove(gacc.thisCodeName, argv[argc], len+1);
  1865.     ++argc;
  1866.     
  1867.     argv[argc] = HS.progname;
  1868.     ++argc;
  1869.     for (i = 0; i < NUMLIBS; ++i)
  1870.         {
  1871.         if (!(HS.libraryname[i]))
  1872.             break;
  1873.         argv[argc] = HS.libraryname[i];
  1874.         ++argc;
  1875.         }
  1876.     /* variables */
  1877.     for (i = 0; i < NUMVARSETS; ++i)
  1878.         {
  1879.         if (!(HS.varsetting[i]))
  1880.             break;
  1881.         argv[argc] = HS.varsetting[i];
  1882.         ++argc;
  1883.         }
  1884.     /* the -- */
  1885.     len = 2;
  1886.     argv[argc] = NewPtr(len+1);
  1887.     if (MemError() != noErr)
  1888.         {
  1889.         CleanUpAfterHAWK();
  1890.         return(FALSE);
  1891.         }
  1892.     BlockMove("--", argv[argc], len+1);
  1893.     ++argc;
  1894.     /* lastly, get input file if any - note hAWK can still do things even
  1895.     if no input file specified in command line. */
  1896.     if (HS.inputType == inPop.frontSelected || HS.inputType == inPop.frontAll)
  1897.         {
  1898.         argv[argc] = CreateStdIn(HS.inputType == inPop.frontAll);
  1899.         if (!argv[argc])
  1900.             {
  1901.             CleanUpAfterHAWK();
  1902.             return(FALSE);
  1903.             }
  1904.         ++argc;
  1905.         }
  1906.     else if (HS.inputType == inPop.multiSelected)
  1907.         {
  1908.         if (!GetInputsFromMFS())
  1909.             {
  1910.             CleanUpAfterHAWK();
  1911.             return(FALSE);
  1912.             }
  1913.         }
  1914.     else if (HS.inputType == inPop.specificFile && HS.inputname)
  1915.         {
  1916.         argv[argc] = HS.inputname;
  1917.         ++argc;
  1918.         }
  1919.     return(TRUE);
  1920.     }
  1921.  
  1922. /* If user wants the input to be whatever is in the front text file,
  1923. get a copy of the text and write it the the file used for standard input. */
  1924. char *CreateStdIn(Boolean wholeFile)
  1925.     {
  1926.     Ptr            copyOfName;
  1927.     Handle        hText;
  1928.     long        len;
  1929.     OSErr         IOResult;
  1930.     short             refNum;
  1931.     
  1932.     /* anything? */
  1933.     if (HasGetFrontText())
  1934.         {
  1935.         hText = GetFrontText(wholeFile);
  1936.         }
  1937.     else
  1938.         hText = NewHandle(0);
  1939.     if (!hText)
  1940.         return(NULL);
  1941.         
  1942.     /* save to standard input file */
  1943.     /* Delete the file.  We don't care if there's an error */
  1944.     FSDelete((StringPtr)gacc.stdInFileNameP, 0);
  1945.     
  1946.     /* Now try to create it. '????' is the creator. Report the file error, if any */
  1947.     if (IOResult = Create((StringPtr)gacc.stdInFileNameP, 0, '????', 'TEXT'))
  1948.         {
  1949.         DisposHandle(hText);
  1950.         OKStopAlert("Standard input file could not be created.");
  1951.         return(NULL);
  1952.         }
  1953.     
  1954.     if (IOResult = FSOpen ((StringPtr)gacc.stdInFileNameP, 0, &refNum))
  1955.         {
  1956.         DisposHandle(hText);
  1957.         OKStopAlert("Standard input file could not be opened.");
  1958.         return(NULL);
  1959.         }
  1960.     len = GetHandleSize(hText);
  1961.     if (IOResult = FSWrite (refNum, &len, *hText))
  1962.         {
  1963.         FSClose (refNum);
  1964.         DisposHandle(hText);
  1965.         OKStopAlert("Standard input file could not be written to.");
  1966.         return(NULL);
  1967.         }
  1968.     FSClose (refNum);
  1969.     DisposHandle(hText);
  1970.     /* return ptr to copy of gacc.stdInFileName if success, or NULL */
  1971.     len = strlen(gacc.stdInFileName);
  1972.     copyOfName = NewPtr(len+1);
  1973.     if (!copyOfName)
  1974.         return(NULL);
  1975.     BlockMove(gacc.stdInFileName, copyOfName, len+1);
  1976.     return(copyOfName);
  1977.     }
  1978.  
  1979. /* Build list of files from multi-file search or equivalent selection.
  1980. This version, concoct full path name for each file.
  1981. Next version, use dirID and save much space. */
  1982. Boolean GetInputsFromMFS()
  1983.     {
  1984.     char            **newArgv;
  1985.     Byte            *tempPtr, *endPtr;
  1986.     short            whichPane, index, vRefNum, lastvrefnum = 0;
  1987.     char            fileName[32];
  1988.     
  1989.     if (!HasGetNextMultiFile()) return(FALSE);
  1990.     /* determine which file to search next */
  1991.     whichPane = -1;
  1992.     GetNextMultiFile(&whichPane, &index, &vRefNum, fileName, FALSE);
  1993.     if (index < 0)
  1994.         return(FALSE);
  1995.     while (index >= 0)
  1996.         {
  1997.         tempPtr = (Byte *)malloc(256);
  1998.         if (tempPtr == NULL)
  1999.             return FALSE;
  2000.         /* This is a prime target for optimizing, since it does a lot of
  2001.         disk-pounding to retrieve the full path name. Detecting a run of
  2002.         the same vrefnum certainly helps.*/
  2003.         if (vRefNum != lastvrefnum) /* do it the hard way */
  2004.         AppendPStr((Byte *)(FullPathNameFromVRefNum(vRefNum, tempPtr)),
  2005.                 (Byte *)(fileName));
  2006.         else
  2007.             {
  2008.             BlockMove(argv[argc-1], (Ptr)tempPtr, 256);
  2009.             CtoPstr((Ptr)tempPtr);
  2010.             /* strip previous file name */
  2011.             endPtr = tempPtr + tempPtr[0];
  2012.             while (*endPtr != ':')
  2013.                 --endPtr;
  2014.             tempPtr[0] = (unsigned char)(endPtr - tempPtr);
  2015.             /* append new file name */
  2016.             AppendPStr(tempPtr, (Byte *)(fileName));
  2017.             }
  2018.         PtoCstr((StringPtr)tempPtr);
  2019.         argv[argc++] = (Ptr)tempPtr;
  2020.         lastvrefnum = vRefNum;
  2021.         GetNextMultiFile(&whichPane, &index, &vRefNum, fileName, FALSE);
  2022.         if (index >= 0 && argc > NUMARGVS - 1)
  2023.             { /* This is the only place where argv[] can overflow */
  2024.             NUMARGVS += 100; /* Apologies, NUMARGVS is actually a variable */
  2025.             newArgv = (char **)malloc(sizeof(char *) * NUMARGVS);
  2026.             if (newArgv == NULL)
  2027.                 return FALSE;
  2028.             BlockMove((Ptr)argv, (Ptr)newArgv, sizeof(char *) * (NUMARGVS - 100));
  2029.             free(argv);
  2030.             argv = newArgv;
  2031.             }
  2032.         }
  2033.     return(TRUE);
  2034.     }
  2035.  
  2036. typedef enum CommandLineTypesEnum
  2037.     {
  2038.     kErrorGetting_Arg = -1,
  2039.     kNoMore_Arg = 0,
  2040.     kHawkName_Arg = 1,
  2041.     kProgramName_Arg = 2,
  2042.     kVariable_Arg = 3,
  2043.     kOnlyFilesNow_Arg = 4,
  2044.     kInputFile_Arg = 5,
  2045.     kMFS_Arg = 6,
  2046.     kShowOut_Arg = 7,
  2047.     kShowSelect_Arg = 8,
  2048.     kNoShow_Arg = 9
  2049.     } CommandLineTypesEnum;
  2050.  
  2051. /* Rev May 96
  2052. Under version 4, caller may pass along a command line in text form. If so,
  2053. parse it into argv. Return TRUE if got a good command line, FALSE otherwise.
  2054. Memory allocation is done here, advancing through the text of the command line is
  2055. done by GetNextCommandLineArg().
  2056. For program names, use hAWK program folder if no path specified.
  2057. For input, "MFS" means multi-file selection (if allowed), case-sensitive there.
  2058. */
  2059. Boolean GetCommandLineArguments(void)
  2060.     {
  2061.     Ptr            argPtr = NULL;
  2062.     short        argLength = 0;
  2063.     Ptr            tempPtr;
  2064.     long        len;
  2065.     short        i;
  2066.     short        argumentType;
  2067.     short        vRefNum = 0;
  2068.     short        programArgument = 0;
  2069.     Boolean        gotCommandLine = FALSE;
  2070.     Boolean        onlyFiles = FALSE;
  2071.     Boolean        doneDefaultVariables = FALSE;
  2072.     
  2073.     // init HawkSetup.
  2074.     HS.showOut = FALSE;
  2075.     HS.selectOut = FALSE;
  2076.     HS.progname = HS.inputname = NULL;
  2077.     for (i = 0; i < NUMLIBS; ++i)
  2078.         HS.libraryname[i] = NULL;
  2079.     for (i = 0; i < NUMVARSETS; ++i)
  2080.         HS.varsetting[i] = NULL;
  2081.     
  2082.     argc = 0;
  2083.     if (    gacc.extend2ID == 'VER4'
  2084.         &&     gacc.commandLine != NULL )
  2085.         {
  2086.         gotCommandLine = TRUE;
  2087.         argv = (char **)malloc( sizeof(char *) * NUMARGVS );
  2088.         if (argv == NULL)
  2089.             {
  2090.             OKStopAlert("Could not allocate argv array, ouch!");
  2091.             return(FALSE);
  2092.             }
  2093.         while ( (argumentType = GetNextCommandLineArg(&argPtr, &argLength)) > 0)
  2094.             {
  2095.             switch (argumentType)
  2096.                 {
  2097.             case kHawkName_Arg:
  2098.                 //OKStopAlert("DBG about to allocate code name");
  2099.                 // hawk name always as first arg
  2100.                 len = strlen(gacc.thisCodeName);
  2101.                 argv[argc] = (Ptr)malloc(len+1);
  2102.                 if (!argv[argc])
  2103.                     {
  2104.                     OKStopAlert("Could not allocate hAWK name, ouch!");
  2105.                     return(FALSE);
  2106.                     }
  2107.                 BlockMove(gacc.thisCodeName, argv[argc], len+1);
  2108.                 ++argc;
  2109.             break;
  2110.             case kProgramName_Arg:
  2111.                 //OKStopAlert("DBG about to allocate program name");
  2112.                 tempPtr = FullPathNameForProgram(argPtr, argLength, &vRefNum);
  2113.                 if (tempPtr == NULL)
  2114.                     {
  2115.                     OKStopAlert("Could not allocate program name, ouch!");
  2116.                     return FALSE;
  2117.                     }
  2118.                 argv[argc] = tempPtr;
  2119.                 if (programArgument == 0)
  2120.                     programArgument = argc;
  2121.                 ++argc;
  2122.             break;
  2123.             case kVariable_Arg:
  2124.                 if (!doneDefaultVariables)
  2125.                     {
  2126.                     if (FSpReadHAWKResource(argv[programArgument]))
  2127.                         {
  2128.                         DoCmdLineDefaultLibsAndVars();
  2129.                         }
  2130.                     }
  2131.                 doneDefaultVariables = TRUE;
  2132.                 tempPtr = (Ptr)malloc(argLength + 3);
  2133.                 if (tempPtr == NULL)
  2134.                     {
  2135.                     OKStopAlert("Could not allocate variable, ouch!");
  2136.                     return FALSE;
  2137.                     }
  2138.                 tempPtr[0] = '-';
  2139.                 tempPtr[1] = 'v';
  2140.                 BlockMove(argPtr, tempPtr + 2, argLength);
  2141.                 tempPtr[argLength + 2] = '\0';
  2142.                 argv[argc] = tempPtr;
  2143.                 ++argc;
  2144.             break;
  2145.             case kOnlyFilesNow_Arg:
  2146.                 if (!doneDefaultVariables)
  2147.                     {
  2148.                     if (FSpReadHAWKResource(argv[programArgument]))
  2149.                         {
  2150.                         DoCmdLineDefaultLibsAndVars();
  2151.                         }
  2152.                     }
  2153.                 doneDefaultVariables = TRUE;
  2154.                 //OKStopAlert("DBG about to allocate dash dash");
  2155.                 tempPtr = (Ptr)malloc(3);
  2156.                 if (tempPtr == NULL)
  2157.                     {
  2158.                     OKStopAlert("Could not allocate -- separator, ouch!");
  2159.                     return FALSE;
  2160.                     }
  2161.                 BlockMove("--", tempPtr, 3);
  2162.                 argv[argc] = tempPtr;
  2163.                 ++argc;
  2164.                 onlyFiles = TRUE;
  2165.             break;
  2166.             case kInputFile_Arg:
  2167.                 //OKStopAlert("DBG about to allocate one input file");
  2168.                 tempPtr = (Ptr)malloc(argLength + 1);
  2169.                 if (tempPtr == NULL)
  2170.                     {
  2171.                     OKStopAlert("Could not allocate input file name, ouch!");
  2172.                     return FALSE;
  2173.                     }
  2174.                 BlockMove(argPtr, tempPtr, argLength);
  2175.                 tempPtr[argLength] = '\0';
  2176.                 argv[argc] = tempPtr;
  2177.                 ++argc;
  2178.             break;
  2179.             case kMFS_Arg:
  2180.                 //OKStopAlert("DBG about to allocate all MFS files");
  2181.                 if (!GetInputsFromMFS())
  2182.                     {
  2183.                     OKStopAlert("Could not get MFS file names, ouch!");
  2184.                     return FALSE;
  2185.                     }
  2186.             break;
  2187.             case kShowOut_Arg:        // -s
  2188.             case kShowSelect_Arg:    // -ss
  2189.             case kNoShow_Arg:        // -n
  2190.                 if (!doneDefaultVariables)
  2191.                     {
  2192.                     if (FSpReadHAWKResource(argv[programArgument]))
  2193.                         {
  2194.                         DoCmdLineDefaultLibsAndVars();
  2195.                         }
  2196.                     }
  2197.                 doneDefaultVariables = TRUE;
  2198.                 if (argumentType == kShowOut_Arg)
  2199.                     {
  2200.                     HS.showOut = TRUE;
  2201.                     HS.selectOut = FALSE;
  2202.                     }
  2203.                 else if (argumentType == kShowSelect_Arg)
  2204.                     {
  2205.                     HS.showOut = TRUE;
  2206.                     HS.selectOut = TRUE;
  2207.                     }
  2208.                 else
  2209.                     {
  2210.                     HS.showOut = FALSE;
  2211.                     }
  2212.             break;
  2213.             default:
  2214.                 // unknown argument type
  2215.             break;
  2216.                 } // switch
  2217.             } // while
  2218.         
  2219.         if (argc < 2)
  2220.             {
  2221.             OKStopAlert("\"hAWK\" was followed by insufficient information to run!");
  2222.             return FALSE;
  2223.             }
  2224.         else
  2225.             {
  2226.             if (!doneDefaultVariables)
  2227.                 {
  2228.                 if (FSpReadHAWKResource(argv[programArgument]))
  2229.                     {
  2230.                     DoCmdLineDefaultLibsAndVars();
  2231.                     }
  2232.                 }
  2233.             doneDefaultVariables = TRUE;
  2234.             }
  2235.         } // if v4 with cmd line
  2236.     
  2237.     return gotCommandLine;
  2238.     }
  2239.  
  2240. void DoCmdLineDefaultLibsAndVars(void)
  2241.     {
  2242.     short        i;
  2243.     
  2244.     for (i = 0; i < NUMLIBS; ++i)
  2245.         {
  2246.         if (!(HS.libraryname[i]))
  2247.             break;
  2248.         PtoCstr((StringPtr)HS.libraryname[i]);
  2249.         argv[argc] = HS.libraryname[i];
  2250.         ++argc;
  2251.         }
  2252.     
  2253.     for (i = 0; i < NUMVARSETS; ++i)
  2254.         {
  2255.         if (!(HS.varsetting[i]))
  2256.             break;
  2257.         PtoCstr((StringPtr)HS.varsetting[i]);
  2258.         argv[argc] = HS.varsetting[i];
  2259.         ++argc;
  2260.         }
  2261.     }
  2262.  
  2263. /* If we don't already have a full path, use the hawk program folder
  2264. to make one.
  2265. */
  2266. Ptr FullPathNameForProgram
  2267.     (Ptr        argPtr,
  2268.     short        argLength,
  2269.     short        *vRefNumP
  2270.     )
  2271.     {
  2272.     char        curvolName[32];
  2273.     char        pProgName[64];
  2274.     long        theDirID = 0;
  2275.     short        vRefNum = *vRefNumP;
  2276.     Ptr            tempPtr = NULL;
  2277.     long        len;
  2278.     Ptr            cPtr;
  2279.     Ptr            endPtr;
  2280.     
  2281.     // Does the program name contain a colon?
  2282.     cPtr = argPtr;
  2283.     endPtr = cPtr + argLength;
  2284.     for (; cPtr < endPtr; ++cPtr)
  2285.         {
  2286.         if (*cPtr == ':')
  2287.             break;
  2288.         }
  2289.     // No colon means we have to make the full path name
  2290.     if (cPtr >= endPtr)
  2291.         {
  2292.         if (argLength > 63)
  2293.             argLength = 63;
  2294.         BlockMove(argPtr, pProgName + 1, argLength);
  2295.         pProgName[0] = argLength;
  2296.         if ( vRefNum != 0
  2297.           || (theDirID = FindHawkProgramFolder(curvolName, (char *)"\phAWK programs")) != 0 )
  2298.             {
  2299.             if (theDirID != 0)
  2300.                 {
  2301.                 vRefNum = GetWorkingDirectory(curvolName, theDirID);
  2302.                 *vRefNumP = vRefNum;
  2303.                 }
  2304.             tempPtr = (Ptr)malloc(256);
  2305.             if (tempPtr != NULL)
  2306.                 {
  2307.                 AppendPStr((Byte *)(FullPathNameFromVRefNum(vRefNum,(Byte *)(tempPtr))),
  2308.                     (Byte *)(pProgName));
  2309.                 BlockMove(tempPtr+1, tempPtr + 3, 253);
  2310.                 tempPtr[0] += 2;
  2311.                 tempPtr[1] = '-';
  2312.                 tempPtr[2] = 'f';
  2313.                 PtoCstr((StringPtr)tempPtr);
  2314.                 }
  2315.             }
  2316.         }
  2317.     // If it has a colon, just tack '-f' in front of a copy.
  2318.     else
  2319.         {
  2320.         tempPtr = (Ptr)malloc(argLength + 3);
  2321.         if (tempPtr != NULL)
  2322.             {
  2323.             tempPtr[0] = '-';
  2324.             tempPtr[1] = 'f';
  2325.             BlockMove(argPtr, tempPtr + 2, argLength);
  2326.             tempPtr[argLength + 2] = '\0';
  2327.             }
  2328.         }
  2329.     return tempPtr;
  2330.     }
  2331.  
  2332. short GetWorkingDirectory
  2333.     (char    *curvolName,
  2334.     long    theDirID
  2335.     )
  2336.     {
  2337.     WDPBRec            theParms;
  2338.     HVolumeParam    vParms;
  2339.     char            volName[32];
  2340.     short            theVolRef, vRefNum;
  2341.     
  2342.     /* Some shenanigans to open working directory for code resources */
  2343.     BlockMove(curvolName, volName, 32);
  2344.     vParms.ioCompletion = NULL;
  2345.     vParms.ioNamePtr = (StringPtr)(volName);
  2346.     vParms.ioVRefNum = -32768;
  2347.     vParms.ioVolIndex = -1;
  2348.     if (PBHGetVInfo((HParmBlkPtr)&vParms, FALSE))
  2349.         theVolRef = 0;
  2350.     else
  2351.         theVolRef = vParms.ioVRefNum;
  2352.     theParms.ioCompletion = NULL;
  2353.     theParms.ioVRefNum = theVolRef;
  2354.     theParms.ioNamePtr = NULL;
  2355.     theParms.ioWDDirID = theDirID;
  2356.     theParms.ioWDProcID = 'ERIK';
  2357.     if (PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  2358.         vRefNum = 0;
  2359.     else
  2360.         vRefNum = theParms.ioVRefNum;
  2361.     
  2362.     theParms.ioNamePtr = NULL;
  2363.     theParms.ioVRefNum = vRefNum;
  2364.     theParms.ioWDIndex = 0;
  2365.     theParms.ioWDProcID = 0;
  2366.     if (PBGetWDInfo(&theParms,false))
  2367.         vRefNum = 0;
  2368.     return vRefNum;
  2369.     }
  2370.  
  2371. /* Grab the next command line argument, determine its type, or return 0.
  2372. Being nice, we strip out quotes here.
  2373. Pass *argPtrP = NULL the first time.
  2374. kNoMore_Arg = 0,
  2375. kHawkName_Arg = 1,
  2376. kProgramName_Arg = 2,
  2377. kVariable_Arg = 3,
  2378. kOnlyFilesNow_Arg = 4,
  2379. kInputFile_Arg = 5,
  2380. kMFS_Arg = 6,
  2381. kShowOut_Arg = 7,
  2382. kShowSelect_Arg = 8,
  2383. kNoShow_Arg = 9
  2384. */
  2385. short GetNextCommandLineArg
  2386.     (Ptr        *argPtrP,
  2387.     short        *argLengthP
  2388.     )
  2389.     {
  2390.     Ptr            argPtr = *argPtrP;
  2391.     Ptr            endPtr;
  2392.     short        argLength = *argLengthP;
  2393.     short        argumentType = kNoMore_Arg;
  2394.     long        commandLineLength;            // needed when stripping quotes
  2395.     long        amountToMove;                // ditto
  2396.     Boolean        stripQuotes = FALSE;
  2397.     
  2398.     if (argPtr == NULL)
  2399.         {
  2400.         argPtr = gacc.commandLine;
  2401.         argumentType = kHawkName_Arg;
  2402.         }
  2403.     else
  2404.         argPtr += argLength;
  2405.     argLength = 0;
  2406.     
  2407.     // skip past last arg's quote
  2408.     while (*argPtr == '"')
  2409.         ++argPtr;
  2410.     // skip white space
  2411.     while (white(*argPtr))
  2412.         ++argPtr;
  2413.     // First arg is "hAWK"
  2414.     if (argumentType == kHawkName_Arg)
  2415.         {
  2416.         endPtr = argPtr;
  2417.         while (*endPtr && !white(*endPtr))
  2418.             ++endPtr;
  2419.         }
  2420.     // Options indicate source program, variable, input follows
  2421.     else if (*argPtr == '-')
  2422.         {
  2423.         ++argPtr;
  2424.         if (*argPtr == 'f')
  2425.             {
  2426.             argumentType = kProgramName_Arg;
  2427.             ++argPtr;
  2428.             endPtr = argPtr;
  2429.             // program name, optionally in quotes
  2430.             if (*argPtr == '"')
  2431.                 {
  2432.                 ++argPtr;
  2433.                 ++endPtr;
  2434.                 while (*endPtr && *endPtr != '"')
  2435.                     ++endPtr;
  2436.                 }
  2437.             else
  2438.                 {
  2439.                 while (*endPtr && !white(*endPtr))
  2440.                     ++endPtr;
  2441.                 }
  2442.             }
  2443.         else if (*argPtr == 'v')
  2444.             {
  2445.             argumentType = kVariable_Arg;
  2446.             ++argPtr;
  2447.             endPtr = argPtr;
  2448.             // var name, opt space, '='
  2449.             while (*endPtr && *endPtr != '=')
  2450.                 ++endPtr;
  2451.             ++endPtr;
  2452.             // value, optionally in quotes
  2453.             if (*endPtr == '"')
  2454.                 {
  2455.                 // Remove first quote
  2456.                 commandLineLength = strlen(gacc.commandLine);
  2457.                 amountToMove = commandLineLength - (endPtr - gacc.commandLine);
  2458.                 if (amountToMove > 0)
  2459.                     BlockMove(endPtr+1, endPtr, amountToMove);
  2460.                 // Find second quote -- it can stay
  2461.                 while (*endPtr && *endPtr != '"')
  2462.                     ++endPtr;
  2463.                 }
  2464.             else
  2465.                 {
  2466.                 while (*endPtr && !white(*endPtr))
  2467.                     ++endPtr;
  2468.                 }
  2469.             }
  2470.         else if (*argPtr == '-')
  2471.             {
  2472.             argumentType = kOnlyFilesNow_Arg;
  2473.             ++argPtr;
  2474.             endPtr = argPtr;
  2475.             }
  2476.         else 
  2477.             {
  2478.             // -s, -ss, -n for show, show select, no show.
  2479.             endPtr = argPtr + 1;
  2480.             if (*argPtr == 's')
  2481.                 {
  2482.                 if (*endPtr == 's')
  2483.                     {
  2484.                     argumentType = kShowSelect_Arg;
  2485.                     ++endPtr;
  2486.                     }
  2487.                 else
  2488.                     {
  2489.                     argumentType = kShowOut_Arg;
  2490.                     }
  2491.                 }
  2492.             else if (*argPtr == 'n')
  2493.                 {
  2494.                 argumentType = kNoShow_Arg;
  2495.                 }
  2496.             // else unknown type
  2497.             }
  2498.         }
  2499.     // No option, must be input file
  2500.     else if (*argPtr)
  2501.         {
  2502.         argumentType = kInputFile_Arg;
  2503.         endPtr = argPtr;
  2504.         // file name, optionally in quotes
  2505.         if (*argPtr == '"')
  2506.             {
  2507.             ++argPtr;
  2508.             ++endPtr;
  2509.             while (*endPtr && *endPtr != '"')
  2510.                 ++endPtr;
  2511.             }
  2512.         else
  2513.             {
  2514.             while (*endPtr && !white(*endPtr))
  2515.                 ++endPtr;
  2516.             }
  2517.         // the special name "MFS" means all multi-file selected files
  2518.         if ( endPtr == argPtr + 3
  2519.           && *argPtr == 'M' && *(argPtr+1) == 'F' && *(argPtr+2) == 'S')
  2520.             argumentType = kMFS_Arg;
  2521.         }
  2522.     // All done when hit a null byte
  2523.     else
  2524.         {
  2525.         endPtr = argPtr;
  2526.         }
  2527.     *argPtrP = argPtr;
  2528.     argLength = endPtr - argPtr;
  2529.     *argLengthP = argLength;
  2530.     return argumentType;
  2531.     }
  2532.  
  2533. /* Bail out if error during hAWK run. */
  2534. void JumpOnHAWKError(short inputErrorNumber)
  2535.     {
  2536.     
  2537.     gInputError = inputErrorNumber;
  2538.     longjmp(envBuf, 1); /* return to save point */
  2539.     }
  2540.  
  2541. void CleanUpAfterHAWK(void)
  2542.     {
  2543.     /* Call TFreeAll if using TMalloc etc, call FFreeAll if using Fmalloc etc
  2544.     -at present, using Fmalloc which is better on all scores. */
  2545.     
  2546.     FFreeAll();
  2547.     alloca(0);
  2548.     DisposeProgress(); /* remove progress dialog from screen if present */
  2549.     }
  2550.  
  2551. void HandleHAWKError()
  2552.     {
  2553.     /* -future- use gInputError */
  2554.     SysBeep(2);
  2555.     }
  2556.  
  2557.  
  2558. static pascal void EmptyExitToShell(void);
  2559. enum
  2560.     {
  2561.     uppExitToShellProcInfo = kPascalStackBased
  2562.     };
  2563. // Patch ExitToShell out temporarily and call exit()
  2564. void DoExiting(void)
  2565.     {
  2566.     pascal void (*gOldExitToShell)(void);
  2567.     UniversalProcPtr EmptyExitToShellProcPtr;
  2568.     
  2569.     gOldExitToShell = (void *)GetToolTrapAddress(0xA9F4);
  2570.     EmptyExitToShellProcPtr = NewRoutineDescriptor((ProcPtr)&EmptyExitToShell,
  2571.                                     uppExitToShellProcInfo,
  2572.                                     GetCurrentISA());
  2573.     SetToolTrapAddress(EmptyExitToShellProcPtr, 0xA9F4);
  2574.     exit(0);
  2575.     SetToolTrapAddress((UniversalProcPtr)gOldExitToShell, 0xA9F4);
  2576.     }
  2577.  
  2578. static pascal void EmptyExitToShell(void)
  2579.     {
  2580.     ;
  2581.     }
  2582.