home *** CD-ROM | disk | FTP | other *** search
- /* Call_Resource.c: file to be added to any applications wishing to
- call the code resources that come with EnterAct.
- THIS IS A COPY of the other Call_Resource.c file on your source disk. */
-
- /* Copyright © 1991 the Free Software Foundation, Inc.
- * This file is free software; you can redistribute or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or any later version.
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with GAWK; see the file "COPYING hAWK". If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * Written for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
- */
-
- /*
- To call EnterAct-style code resources from your application:
- 1 Add a copy of this file to your app.
- 2 Call "InitCallResources()" in your startup code, just before
- entering your event loop. The arguments are:
- vRefNumForApp : preferably your application working directory, or 0
- codeFolderName : preferably (Ptr)"\pDrag_on Modules"
- menuID : the integer menu id of the menu you wish code resources
- to be appended to. Preferably not File or Edit.
- 3 Call "CallResource()" to handle the code resources picked from
- the menu you have added them to. Typically looks something like
- #define MenuInQuestion 261
- void DoMenuInQuestionCommand(short item)
- {
- switch (item)
- {
- case 1:
- DoItemOne();
- break;
- case 2:
- DoItemTwo();
- break;
- ...etc...
- default:
- if (item > 0)
- CallResource(MenuInQuestion, item);
- --or if you set VERSION2 == TRUE,
- CallResource(MenuInQuestion, item, true/false)--
- break;
- }
- }
- 4 Go through the extension ("callback") functions defined at the
- bottom of this file, and decide which ones you wish to support.
- You will probably not be able to support "InDictionary()", and
- "GetNextMultiFile()" requires that your application keep a list
- of files for some purpose or other (typically searching), but if
- your application supports text files you should be able to provide
- support for the others. Note "GetScreenHeight" and "GetScreenWidth"
- are done here, no modification needed. The code resources supplied
- with EnterAct can still do useful things even if no extensions are
- supplied.
-
- If you decide not to support a particular extension, you need only
- set the corresponding pointer to NULL in the function SetUpCodeCommunication().
- For example, if you don't support InDictionary_Ext, then put
- gacc.InDictionary_Ext = NULL;
- in SetUpCodeCommunication().
-
- For more about the "DoEventLoopOnce()" callback, see 6 below.
-
- 5 "ShowResult" and "SelectResult" defined below are called by
- "CallResource" in response to a request by a code resource to display
- the text results of the code resource run. If your application supports
- TEXT documents, you should modify these functions to provide your
- equivalents for these abilities. Otherwise, leave them as-is.
-
- 6 Version 2 of hAWK (the one you received with this file) supports
- concurrent execution. This means you fire up a hAWK program, go back
- to working in your application (or even switch to some other app)
- and hAWK notifies you when the program is done. There is a
- penalty in speed of the hAWK program, usually far outweighed by
- the benefit of being able to go back to work instantly rather than
- having to sit there watching the watch cursor. Your calling application
- should not be noticeably affected, except when the hAWK program
- is doing something massive such as a huge "sort" or a large "copy".
-
- The "VERSION2" defined constant just below should be set to TRUE if
- you wish to support concurrent execution of hAWK programs, FALSE
- if you do not. That's all that VERSION2 affects. Read Resource cannot
- run concurrently, and is not affected by the value of VERSION2.
-
- To support concurrent exec of hAWK programs, follow these steps:
- 1 define VERSION2 just below to be TRUE
- 2 In the menu where you call Drag_on Modules, use
- ...CallResource(MenuInQuestion, item, bool);
- rather than just CallResource(MenuInQuestion, item);
- -the "bool" variable is a Boolean, to be set to TRUE if
- you want concurrent execution. Recommended interface is
- to set this variable FALSE if the user has held down
- either the <Shift> or <Option> key or both, and set it
- TRUE otherwise.
- 3 One additional callback function needs to be provided,
- in "DoEventLoopOnce()" below. Your callback should
- have the form
- extern void HandleOneEvent(void);
- and can be a copy of your main event loop function,
- except that it should handle just one event and then
- return, and startup initializations if any can
- be skipped (creating a region to track the mouse,
- for example). If you use a global event record, you
- can use the same global in your "HandleOneEvent"
- function, but keep in mind that when "CallResource()"
- returns, your global event record will reflect the
- last event processed during your Drag_on Module run,
- rather than the original menu call -- check what your
- main event loop does with the event after the orginal
- call, and verify that nothing important will be confused
- by having the nature of the event changed during the
- Drag_on Modules run.
- (Note your event handler does not need to do any special
- checking for the <Command><period> that stops hAWK.)
- 4 If your calling app is in the background when hAWK
- finishes a run, a notice will be installed by the
- DoNotify() routine below, flashing an icon in the
- menu bar etc until you return to the calling app.
- In your MAIN event handler (not the handle-one-event)
- you should place the following bit of code to properly
- handle the notify when your app resumes:
- --declaration at the top of its file;
- -- to handle concurrent Drag_on Modules --
- Boolean gNotifying;
- Boolean gHawkIsRunning;
- NMRec gNotifyRec;
-
- -- and in your main event handler, for the case of
- "kSuspendResumeMessage";
- if (gNotifying)
- {
- NMRemove(&gNotifyRec);
- if (gNotifyRec.nmIcon)
- ReleaseResource(gNotifyRec.nmIcon);
- gNotifying = FALSE;
- ShowResultsAfterNotify();
- }
- You will also need the standard global that records
- whether or not your application is in the background,
- Boolean gInBackground;
- This variable should be set in your handle-one-event
- function, and if your spelling of this variable name
- differs from "gInBackground", change it here as well.
- This file requires access to "gInBackground" in order
- to determine if a notice should be posted at the end
- of a hAWK program run.
- 5 In both your main event handler and the one-event
- handler, calculate the "sleep" parameter for your
- WaitNextEvent() call roughly as
- gHawkIsRunning ? 2UL : GetCaretTime()
- --adjust to suit your taste.
- 6 If you want the small icon "hAWK!" to flash for
- notifications, move it to your application from "hAWK"
- itself (it's just stored there).
- 7 One little wrinkle: what happens if you Quit your
- application while hAWK is running? The recommended
- solution here is to ask your user to issue a
- <Command><period> to halt hAWK before proceeding
- with the Quit. If you just pull the rug out from
- under hAWK, files will probably be left open.
- Sketchily:
- Boolean DoQuit (...
- extern Boolean gHawkIsRunning;...
- if (gHawkIsRunning)
- {
- FlexAlert(justOK, stopIcon, "Please terminate your hAWK program \
- with <Command><period> before quitting.");
- return(FALSE);
- }...
-
- */
-
- #include <string.h>
-
- #ifndef NULL
- #define NULL ((void *) 0)
- #endif
-
- /* Change this to TRUE if you support concurrent hAWK - see above, point 6. */
- #define VERSION2 FALSE
-
- #if VERSION2 == TRUE
- extern Boolean gInBackground;
- extern Boolean gNotifying;
- extern Boolean gHawkIsRunning;
- extern NMRec gNotifyRec;
- #endif
-
- /* Canned options, if you want to get going in a hurry:
- SUPPORT_LEVEL should be set to one of the following four options:
- MINIMAL - no extensions, no showing of results after a code resource run.
- Note this doesn't mean the code resource won't be creating a text file,
- it just means your application won't be showing it.
- RESULTSONLY - no extensions, but ability to show results supplied by you.
- This means you should provide the hooks in ShowResult() and
- SelectResult() - nothing else to do.
- BASICTEXT - in addition to providing the hooks in ShowResult() and
- SelectResult(), fill in the blanks in GetFrontText() to allow the
- code resource access to your front text window during a run.
- CUSTOMSUPPORT - ie avoid the above canned options.
-
- There is one special case: if you support the "GetAppClip" extension,
- you’ll need to set SUPPORT_LEVEL to CUSTOMSUPPORT, and also
- define VERSION2 TRUE (getclip was not supported by version 1).
- */
-
-
- #define MINIMAL 1
- #define RESULTSONLY 2
- #define BASICTEXT 3
- #define CUSTOMSUPPORT 4
-
- /* Pick yer pleasure - from the above 4 options only, please. */
- #define SUPPORT_LEVEL MINIMAL
-
- /* Struct passed to all code resources. Everything should be optional.
- "stdInFileName" is primarily for code resources that insist on having input
- from an existing file - hAWK, for example. "stdOutFileName", however, is
- handy for use by any code resource that creates text, as this file can be
- shown by the calling application */
- typedef struct AppCodeComm
- {
- /* c strings except as noted */
- char *stdInFileName, /* text from application to code resource */
- *stdInFileNameP, /* pascal version of above */
- *stdOutFileName, /* text from code resource to application */
- *stdErrFileName, /* error messages from code resource */
- *callerName, /* the name of your application */
- *thisCodeName; /* name of code resource being called */
- short result;
- short version; /* currently 1 */
- /* Extension ("callback") functions - ALL OPTIONAL. These pointers-to-functions
- are all set in SetUpCodeCommunication() just before calling a code resource.*/
- short (*InDictionary_Ext)(char *tokenName);
- Handle (*GetFrontText_Ext)(Boolean getItAll);
- void (*GetNextMultiFile_Ext)(short *panePtr, short *indexPtr,
- short *vRefNumPtr, char *fileName, Boolean clearFlag);
- short (*OKStopAlert_Ext)(Ptr cstringPtr);
- void (*MemoryAlert_Ext)(void);
- short (*GetScreenHeight_Ext)(void);
- short (*GetScreenWidth_Ext)(void);
- void (*ShowWatchCursor_Ext)(void);
- /* Concurrent exec, added for version 2 */
- void (*DoEventLoopOnce_Ext)(void);
- /* Access to scrap/clip of calling app */
- Handle (*GetAppClip_Ext)(void);
- /* Added for version 3 */
- long extendID; // Caller should set to 'VER3'
- short (*PutAppClip_Ext)(char *newClipStr);
- } AppCodeComm, *ACCPtr;
-
- static AppCodeComm gacc;
-
- /* Your application name goes here. */
- static char callerName[] = "MyApp";
-
- typedef void (*CallCode)(ACCPtr ac);
-
- static char *stdPathP;
-
- typedef struct SpecificFolder
- {
- char volName[32];
- long theDirID;
- short vRefNum;
- } SpecificFolder;
- static SpecificFolder codeFolder;
-
- /* Functions defined in this file: */
- /* Call this one towards the end of your startup, just before event loop */
- void InitCallResources(short vRefNumForApp, char *codeFolderName, short menuID);
- /* Called by InitCallResource: */
- void SetUpStandardFileNames(short vRefNum);
- void ShowResourcesInMenu(short vRefNumForApp,
- char *codeFolderName, short menuID);
- /* Two support routines for above */
- long FindCodeResFolder(short vRefNumForApp, char *codeFolderName);
- void AddCodesToMenu(long theDirID, short menuID);
- void OpenWDForCODE(void);
- /* Call this one in the "default" part of the switch for the
- menu containing the code resource names */
- void CallResource(short menuID, short item
- #if VERSION2 == TRUE
- , Boolean concurrent
- #endif
- );
-
- #if VERSION2 == TRUE
- /* Enable/disable Drag_ons if running concurrently */
- void XableDrag_ons(short menuID, Boolean enable);
- /* Post a notify - NOTE this must be cleared by calling app */
- void DoNotify(void);
- /* For delayed showing of results */
- void ShowResultsAfterNotify(void);
- /* Beep and flush events */
- void AnnounceCompletion(void);
- #endif
-
- /* Called by CallResource(), decide which extension functions to pass along */
- Boolean SetUpCodeCommunication(char *progName);
- /* Called by CallResource() to display results of resource run */
- Boolean ShowResult(char *name); /* either stdout or stderr */
- void SelectResult(void);
- /* A few support functions: */
- /* Pascal strings */
- void CopyPStr(Byte *srcStr, Byte *dstStr);
- void AppendPStr(Byte *s1, Byte *s2);
- Boolean PasEqualStrs(char *aStr, char *bStr);
- /* Files, names and locations */
- Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s);
- Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s);
- short OpenWorkingDirectoryFromFullName(char *name, short len);
-
- /* The extension functions - wrappers for your own calls */
- short InDictionary(char *tokenName);
- Handle GetFrontText(Boolean getItAll);
- void GetNextMultiFile(short *panePtr, short *indexPtr,
- short *vRefNumPtr, char *fileName, Boolean clearFlag);
- short OKStopAlert(Ptr cstringPtr);
- void MemoryAlert(void);
- short GetScreenHeight(void);
- short GetScreenWidth(void);
- void ShowWatchCursor(void);
- void DoEventLoopOnce(void);
- Handle GetAppClip(void);
- short PutAppClip(char *newClipStr);
-
-
-
-
- /* Call just before entering your event loop.
- Sets up full path names for standard in/out/err files,
- adds any code resources present to the menu of your choice.
- */
- void InitCallResources(short vRefNumForApp, char *codeFolderName, short menuID)
- {
- SetUpStandardFileNames(vRefNumForApp);
- ShowResourcesInMenu(vRefNumForApp, codeFolderName, menuID);
- }
-
- /* Called once at beginning of application. Sets up full path names
- for std in/out/err files, and as a bonus sets gacc.callerName.
- The vRefNum passed in should be the application's vRefNum, but
- can be any old thing you want.
- -you can determine your application vrefnum at startup with
- short appVRefNum;
- if (GetVol(NULL, &appVRefNum))
- appVRefNum = 0;
- */
- void SetUpStandardFileNames(short vRefNum)
- {
- if (!vRefNum)
- GetVol(NULL, &vRefNum);
- stdPathP = NewPtr(256);
- if (MemError() != noErr)
- goto PathTrouble;
- gacc.stdInFileName = NewPtr(256);
- if (MemError() != noErr)
- goto PathTrouble;
- gacc.stdInFileNameP = NewPtr(256);
- if (MemError() != noErr)
- goto PathTrouble;
- gacc.stdOutFileName = NewPtr(256);
- if (MemError() != noErr)
- goto PathTrouble;
- gacc.stdErrFileName = NewPtr(256);
- if (MemError() != noErr)
- goto PathTrouble;
- if (vRefNum)
- (void)(FullPathNameFromVRefNum(vRefNum, (Byte *)stdPathP));
- else
- stdPathP[0] = 0;
- PtoCstr(stdPathP);
- strcpy((Ptr)(gacc.stdInFileName), (Ptr)stdPathP);
- strcpy((Ptr)(gacc.stdInFileNameP), (Ptr)stdPathP);
- strcpy((Ptr)(gacc.stdOutFileName), (Ptr)stdPathP);
- strcpy((Ptr)(gacc.stdErrFileName), (Ptr)stdPathP);
- strcat((Ptr)(gacc.stdInFileName), "$tempStdIn");
- strcat((Ptr)(gacc.stdInFileNameP), "$tempStdIn");
- strcat((Ptr)(gacc.stdOutFileName), "$tempStdOut");
- strcat((Ptr)gacc.stdErrFileName, "$tempStdErr");
- CtoPstr((Ptr)(gacc.stdInFileNameP));
- gacc.callerName = NewPtr(strlen(callerName)+1);
- if (MemError() != noErr)
- goto PathTrouble;
- strcpy(gacc.callerName, callerName);
-
- return;
- PathTrouble:
- OKStopAlert("Out of memory right at the start! \
- Blew the tubes trying to allocate standard file names.");
- ExitToShell();
- }
-
- /* Index through folders in application's folder, looking for
- "\pDrag_on Modules". If found, index through files in folder and add
- any resource files found. */
- void ShowResourcesInMenu(short vRefNumForApp,
- char *codeFolderName, short menuID)
- {
- long theDirID;
-
- if (theDirID = FindCodeResFolder(vRefNumForApp, codeFolderName))
- AddCodesToMenu(theDirID, menuID);
- }
-
- long FindCodeResFolder(short vRefNumForApp, char *codeFolderName)
- {
- HFileInfo myCPB;
- WDPBRec theParms;
- char fName[32];
- long theDirID;
- short index = 1, len;
- OSErr err;
-
- /* First extract "\pVolName:", volRef, and dirID for application folder */
- theParms.ioNamePtr = (StringPtr)(codeFolder.volName);
- theParms.ioVRefNum = vRefNumForApp;
- theParms.ioWDIndex = 0;
- theParms.ioWDProcID = 0;
- theParms.ioWDVRefNum = 0;
- if (PBGetWDInfo(&theParms,false))
- return(0L);
- len = codeFolder.volName[0];
- codeFolder.volName[len + 1] = ':';
- codeFolder.volName[0] = len + 1;
- codeFolder.vRefNum = theParms.ioWDVRefNum;
- theDirID = theParms.ioWDDirID;
-
- myCPB.ioNamePtr = (StringPtr)fName;
- myCPB.ioVRefNum = vRefNumForApp;
- do
- {
- myCPB.ioFDirIndex = index;
- myCPB.ioDirID = theDirID;
- if ((err = PBGetCatInfo(&myCPB, FALSE)) == noErr)
- {
- if (((myCPB.ioFlAttrib>>4) & 0x01) == 1) /* a folder */
- {
- if (PasEqualStrs(fName, codeFolderName))
- return(myCPB.ioDirID);
- }
- }
- ++index;
- } while (err == noErr);
- return(0L);
- }
-
- /* Search thru folder for code resources and add all codes to the menu. */
- void AddCodesToMenu(long theDirID, short menuID)
- {
- HFileParam fp;
- MenuHandle theMenu;
- char fName[32];
- short index = 1;
- OSErr err;
- Boolean firstAdd = TRUE;
-
- theMenu = GetMHandle(menuID);
- codeFolder.theDirID = theDirID;
- fp.ioNamePtr = (StringPtr)fName;;
- fp.ioVRefNum = codeFolder.vRefNum;
- fp.ioFVersNum = 0;
- do
- {
- fp.ioFDirIndex = index;
- fp.ioDirID = codeFolder.theDirID;
- if ((err = PBHGetFInfoSync((HParmBlkPtr)&fp)) == noErr)
- {
- if (fp.ioFlFndrInfo.fdType == 'rsrc'
- && fp.ioFlFndrInfo.fdCreator == 'RSED')
- {
- if (firstAdd)
- {
- AppendMenu(theMenu, "\P-");
- firstAdd = FALSE;
- }
- AppendMenu(theMenu, (StringPtr)fName);
- }
- }
- ++index;
- } while (err == noErr);
- /****** Open a working directory for the CODE folder: this is currently required
- for hAWK, but will be eliminated for hAWK's next version. */
- if (!firstAdd)
- OpenWDForCODE();
- }
-
- /****** Open a working directory for the CODE folder: this is currently required
- for hAWK, but will be eliminated for hAWK's next version. */
- void OpenWDForCODE()
- {
- WDPBRec theParms;
-
- theParms.ioCompletion = NULL;
- theParms.ioVRefNum = codeFolder.vRefNum;
- theParms.ioNamePtr = NULL;
- theParms.ioWDDirID = codeFolder.theDirID;
- theParms.ioWDProcID = 'ERIK';
- if (!PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
- codeFolder.vRefNum = theParms.ioVRefNum;
- }
-
- /* The main event. Given a pick from your menu, load and call
- the resource. Display results if asked to by the resource.
- */
- void CallResource(short menuID, short item
- #if VERSION2 == TRUE
- , Boolean concurrent
- #endif
- )
- {
- MenuHandle theMenu;
- Handle rHdle;
- CallCode codeCaller;
- char codeNameString[64];
- long eof;
- short saveVol, refNum;
-
- theMenu = GetMHandle(menuID);
- GetItem(theMenu, item, (StringPtr)codeNameString);
- if (31 < (unsigned char)(codeNameString[0]))
- {
- /* An odd error: if the code resource was added to the menu during
- startup, how can it have a name that is longer than a file name?
- The assumption here is that we are calling something that is not a
- code resource - either the wrong menu or an inappropriate item.
- Uncomment the following alert if you want to double-check this.
-
- OKStopAlert("Code resource name is too long.");
- */
- return;
- }
- gacc.thisCodeName = NULL;
- if (GetVol(NULL, &saveVol))
- saveVol = 0;
- SetVol(NULL, codeFolder.vRefNum);
- /* See if there's enough memory to load the code resource
- - the brute force approach, if anything more strict than necessary. */
- if (HOpenRF(codeFolder.vRefNum, codeFolder.theDirID,
- (StringPtr)codeNameString, fsRdPerm, &refNum))
- {
- if (saveVol)
- SetVol(NULL, saveVol);
- OKStopAlert("Couldn't open the code resource.");
- return;
- }
- if (GetEOF(refNum, &eof))
- {
- FSClose(refNum);
- if (saveVol)
- SetVol(NULL, saveVol);
- OKStopAlert("Code resource seems damaged or empty - giving up.");
- return;
- }
- FSClose(refNum);
- rHdle = NewHandle(eof + eof/10); /* a guess */
- if (MemError() != noErr)
- {
- if (saveVol)
- SetVol(NULL, saveVol);
- OKStopAlert("Not enough memory to proceed, sorry.");
- return;
- }
- DisposHandle(rHdle);
- rHdle = NULL;
- if ((refNum = HOpenResFile(codeFolder.vRefNum, codeFolder.theDirID,
- (StringPtr)codeNameString, fsRdPerm)) != -1 && refNum
- && ResError() == noErr)
- {
- /* load CODE 0, set up extensions etc, lock down and call
- -after, show results */
- rHdle = Get1Resource ('CODE', 0);
- if (!rHdle)
- {
- /* In error thinking it was a code resource - this really isn't fair */
- CloseResFile(refNum);
- if (saveVol)
- SetVol(NULL, saveVol);
- OKStopAlert("CODE 0 from that resource file seems to be missing.");
- return;
- }
- #if VERSION2 == TRUE
- gHawkIsRunning = TRUE;
- XableDrag_ons(menuID, FALSE);
- HiliteMenu(0);
- #endif
- HLock(rHdle);
- codeCaller = (CallCode)*rHdle;
- SetUpCodeCommunication(codeNameString);
- #if VERSION2 == TRUE
- if (!concurrent)
- gacc.DoEventLoopOnce_Ext = NULL;
- #endif
- codeCaller(&gacc);
-
- HUnlock(rHdle);
- ReleaseResource(rHdle);
- CloseResFile (refNum);
- #if VERSION2 == TRUE
- XableDrag_ons(menuID, TRUE);
- #endif
- }
- else
- OKStopAlert("Could not open the resource fork for that code resource.");
- if (saveVol)
- SetVol(NULL, saveVol);
- /* Show any file requested */
- /* results:
- <= -3 : no action at present
- -2 : show stderr
- -1 : user cancelled or error during dialog - no run
- 0 : run OK, do nothing special after
- 1 : show stdout
- 2 : show and select stdout
- > 2 : no action at present (counts as equivalent to 0)
- */
-
- #if VERSION2 == TRUE
- if (!(gHawkIsRunning && gInBackground))
- {
- AnnounceCompletion();
- }
- if (gHawkIsRunning && gInBackground)
- DoNotify();
- else
- #endif
-
- if (gacc.result == -2)
- ShowResult(gacc.stdErrFileName);
- else if (gacc.result == 1 || gacc.result == 2)
- {
- if (ShowResult(gacc.stdOutFileName) && gacc.result == 2)
- SelectResult();
- }
-
- #if VERSION2 == TRUE
- gHawkIsRunning = FALSE;
- #endif
-
- /* A small cleanup after */
- if (gacc.thisCodeName)
- DisposPtr(gacc.thisCodeName);
- }
-
- #if VERSION2 == TRUE
- void XableDrag_ons(short menuID, Boolean enable)
- {
- MenuHandle menu = GetMHandle(menuID);
- char mText[64];
- short i;
-
- if (!menu) return;
- i = CountMItems(menu);
- GetItem(menu, i, mText);
- while (i >= 1 && mText[1] != '-')
- {
- if (enable)
- EnableItem(menu, i);
- else
- DisableItem(menu, i);
- --i;
- GetItem(menu, i, mText);
- }
- }
-
- /* Post a notify. Beep, small icon, diamond beside calling app's name.
- NOTE when the calling app resumes, it should remove this notify and
- show results, with
- if (gNotifying)
- {
- NMRemove(&gNotifyRec);
- if (gNotifyRec.nmIcon)
- ReleaseResource(gNotifyRec.nmIcon);
- gNotifying = FALSE;
- ShowResultsAfterNotify();
- }
- */
- void DoNotify()
- {
- OSErr nmError;
-
- if (!gInBackground) return;
- gNotifyRec.qType = nmType;
- gNotifyRec.nmMark = 1;
- gNotifyRec.nmIcon = GetResource('SICN', 128); /* or NULL */
- HNoPurge(gNotifyRec.nmIcon);
- gNotifyRec.nmSound = (Handle)-1L;
- gNotifyRec.nmStr = 0L;
- gNotifyRec.nmResp = (NMProcPtr)0L;
- gNotifyRec.nmRefCon = 0L;
-
- nmError = NMInstall(&gNotifyRec);
- gNotifying = TRUE;
- }
-
- void ShowResultsAfterNotify()
- {
- if (gacc.result == -2)
- ShowResult(gacc.stdErrFileName);
- else if (gacc.result == 1 || gacc.result == 2)
- {
- if (ShowResult(gacc.stdOutFileName) && gacc.result == 2)
- SelectResult();
- }
- FlushEvents(activMask+mDownMask+mUpMask, 0);
- }
-
- void AnnounceCompletion()
- {
- long startTime, endTime;
-
-
- SysBeep(2);
- Delay(0L, &startTime);
- endTime = startTime;
- while (endTime - startTime < 50L)
- Delay(0L, &endTime);
- FlushEvents(62, 0);
- }
-
- #endif
-
-
- /* If you don't support some extensions, set the pointer for it to NULL here. */
- Boolean SetUpCodeCommunication(char *progName)
- {
- short len;
- #if SUPPORT_LEVEL >= BASICTEXT
- /* MyTextInFront(), which should return TRUE if one of your text
- windows is in front or second from front (normally at the time of the call
- the hAWK setup dialog will be the front window).
- */
- extern Boolean MyTextInFront(void);
- #if SUPPORT_LEVEL == CUSTOMSUPPORT
- /* CanDoMultiFiles() should return TRUE if the user has selected
- any files for multi-file operations, however you define that.
- */
- extern Boolean CanDoMultiFiles(void);
- #endif
- #endif
- gacc.result = 0; /* clear before run - 0 means don't do anything after */
-
- #if VERSION2 == TRUE
- gacc.version = 2;
- #else
- gacc.version = 1;
- #endif
-
- /* Extensions, set up every run */
- gacc.GetScreenHeight_Ext = GetScreenHeight;
- gacc.GetScreenWidth_Ext = GetScreenWidth;
- #if SUPPORT_LEVEL >= MINIMAL && SUPPORT_LEVEL <= BASICTEXT
- #if SUPPORT_LEVEL == BASICTEXT
- if (MyTextInFront())
- gacc.GetFrontText_Ext = GetFrontText; /* MODIFY GetFrontText()! */
- else
- gacc.GetFrontText_Ext = NULL;
- #else
- gacc.GetFrontText_Ext = NULL;
- #endif
- gacc.InDictionary_Ext = NULL;
- gacc.GetNextMultiFile_Ext = NULL;
- gacc.OKStopAlert_Ext = NULL;
- gacc.MemoryAlert_Ext = NULL;
- gacc.ShowWatchCursor_Ext = NULL;
- #if VERSION2 == TRUE
- gacc.DoEventLoopOnce_Ext = DoEventLoopOnce;
- gacc.GetAppClip_Ext = NULL;
- #else
- gacc.DoEventLoopOnce_Ext = NULL;
- gacc.GetAppClip_Ext = NULL;
- #endif
- #else /* CUSTOMSUPPORT - check all extension functions below. */
- gacc.InDictionary_Ext = InDictionary;
- if (MyTextInFront())
- gacc.GetFrontText_Ext = GetFrontText;
- else
- gacc.GetFrontText_Ext = NULL;
- if (CanDoMultiFiles())
- gacc.GetNextMultiFile_Ext = GetNextMultiFile;
- else
- gacc.GetNextMultiFile_Ext = NULL;
- gacc.OKStopAlert_Ext = OKStopAlert;
- gacc.MemoryAlert_Ext = MemoryAlert;
-
- gacc.ShowWatchCursor_Ext = ShowWatchCursor;
- #if VERSION2 == TRUE
- gacc.DoEventLoopOnce_Ext = DoEventLoopOnce;
- gacc.GetAppClip_Ext = GetAppClip;
- #else
- gacc.DoEventLoopOnce_Ext = NULL;
- gacc.GetAppClip_Ext = NULL;
- #endif
- #endif
-
- if (gacc.extendID == 'VER3')
- gacc.PutAppClip_Ext = PutAppClip;
- else
- gacc.PutAppClip_Ext = NULL;
-
-
- /* Set up code resource name for each call. */
- len = progName[0];
- gacc.thisCodeName = NewPtr(len+1);
- if (MemError() != noErr)
- return(FALSE); /* No big deal - but suggests code resource will
- run into trouble real quick if can't get 32 bytes
- now...*/
- BlockMove(progName, gacc.thisCodeName, len);
- gacc.thisCodeName[len] = '\0';
- return(TRUE);
- }
-
- /* This function is called by CallResource() to display the TEXT result
- of a code resource run. If your application supports TEXT files, you will
- have a function that takes a file name and vRefNum as arguments, and displays
- the TEXT file in a window - that's the one to use.
-
- A small but important complication: if the file is already being displayed
- in a window, your application should close it without asking to save
- changes, and then reread it from disk. Changes not saved, because these
- are temporary files needed for communication between the application and
- the code resource. */
- Boolean ShowResult(char *name)
- {
- #if SUPPORT_LEVEL >= RESULTSONLY
- short vrefnum;
- char filename[32];
- short len = strlen(name);
- Ptr endPtr = name + len, startPtr = endPtr;
-
- extern Boolean MyAppShowResult(short vRefNum, char *fileName);
-
-
- while (startPtr >= name)
- {
- if (*startPtr == ':')
- break;
- --startPtr;
- }
- ++startPtr;
- if (startPtr >= endPtr) return(FALSE);
- filename[0] = endPtr - startPtr;
- BlockMove(startPtr, filename+1, filename[0]);
-
- vrefnum = OpenWorkingDirectoryFromFullName(name, (short)(startPtr - name));
- if (!vrefnum) return(FALSE);
- return(MyAppShowResult(vrefnum, filename));
- #else
- return(FALSE);
- #endif
-
- /* For reference, the entire "MyAppShowResult" function for EnterAct is
- if (wdPtr = IsFileOpen(fileName, vRefNum))
- DoForcedCloseWindow(wdPtr);
- return(DoOpenFile(text, FALSE, vRefNum, fileName));
- */
-
- }
-
- /* This function should select all of the text in the front window, after
- checking that the front window is indeed a text window. */
- void SelectResult()
- {
- #if SUPPORT_LEVEL >= RESULTSONLY
- extern void MyAppSelectResult(void);
-
- MyAppSelectResult();
- #endif
- }
-
- /* Pascal strings */
-
- /* Copy one pascal string to another */
- void CopyPStr(Byte *srcStr, Byte *dstStr)
- {
- long srcLen = srcStr[0];
-
- BlockMove(srcStr, dstStr, srcLen + 1);
- }
-
- /* Append pascal s2 to pascal s1, avoiding overflow. */
- void AppendPStr(Byte *s1, Byte *s2)
- {
- short s1Len = s1[0];
- short s2Len = s2[0];
-
- if (s1Len + s2Len > 255)
- s2Len = 255 - s1Len;
-
- if (s2Len)
- {
- BlockMove (s2 + 1, s1 + s1Len + 1, s2Len);
- s1Len += s2Len;
- s1[0] = s1Len;
- }
- }
-
- Boolean PasEqualStrs(char *aStr, char *bStr)
- {
- short i, lena = aStr[0], lenb = bStr[0];
-
- if (!lena || !lenb || lena != lenb)return(FALSE);
- for (i = 1; i <= lena; ++i)
- {
- if (aStr[i] != bStr[i])
- return(FALSE);
- }
- return(TRUE);
- }
-
- /* Files, names and locations */
-
- /* NOTE the following two functions are based on examples supplied
- by Apple on one of their DTS disks - error checking has been added,
- and these versions are independent of the signed vs unsigned char
- controversy surrounding str255. Byte is defined in MacTypes.h
- for THINK C v4. */
-
- /* Warning, these calls can fail! And why not? Everything else can... */
- /* Bug, these two are not for use by unix imitations such as A/UX. */
-
- /* Construct "\PDisk:folder1:folder2:...folderN:" where folderN
- contains the file of interest. */
- Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s)
- {
- CInfoPBRec pb;
- Byte directoryName[256];
-
- s[0] = 0;
- pb.dirInfo.ioNamePtr = (StringPtr)directoryName;
- pb.dirInfo.ioDrParID = DirID;
-
- do
- {
- pb.dirInfo.ioVRefNum = vRefNum;
- pb.dirInfo.ioFDirIndex = -1;
- pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
- if (PBGetCatInfo(&pb, FALSE))
- {
- break;
- }
- /* Append a colon */
- AppendPStr(directoryName, (Byte *)"\p:");
- AppendPStr(directoryName, s);
- CopyPStr(directoryName, s);
- } while (pb.dirInfo.ioDrDirID != 2);
- return(s);
- }
-
-
- Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s)
- {
-
- WDPBRec pb;
-
- pb.ioNamePtr = NULL;
- pb.ioVRefNum = vRefNum;
- pb.ioWDIndex = 0;
- pb.ioWDProcID = 0;
-
- if (PBGetWDInfo(&pb,false))
- {
- s[0] = 0;
- return(s);
- }
- return(FullPathNameFromDirectory(pb.ioWDDirID,pb.ioWDVRefNum,s));
- }
-
- /* Determine working directory for file based on full path name. */
- short OpenWorkingDirectoryFromFullName(char *name, short len)
- {
- WDPBRec theParms;
- OSErr IOResult;
- char volname[256];
-
- volname[0] = len;
- BlockMove(name, volname+1, len);
-
- theParms.ioCompletion = NULL;
- theParms.ioVRefNum = 0;
- theParms.ioNamePtr = (StringPtr)volname;
- theParms.ioWDDirID = 0;
- theParms.ioWDProcID = 'ERIK';
- if (IOResult = PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
- {
- OKStopAlert("Disk may not be on-line, \
- or file may have been moved, deleted, or renamed.");
- theParms.ioVRefNum = 0;
- }
- return(theParms.ioVRefNum);
- }
-
-
- /* The extension functions.*/
-
- /* InDictionary() returns the general C type
- of a word, according to the following table:
- value C type
- 0 none - keyword, comment word, local variable, operator etc
- 1 #define or macro name eg #define TAB '\t'
- 2 variable name with more than function scope
- 4 function or method name
- 8 enum constant
- 16 typedef name
- 32 struct tag
- 64 union tag
- 128 enum tag
-
- See hAWK cross-referencing programs for an example of usage. It's unlikely
- that you will be able to provide an equivalent for this function, and
- there’s no great loss if you don’t.
- */
- short InDictionary(char *tokenName)
- {
- #if SUPPORT_LEVEL == CUSTOMSUPPORT
- extern short InMyAppDictionary(char *s);
-
- return(InMyAppDictionary(tokenName));
- #else
- return(0);
- #endif
- }
-
- /* This extension function should copy all or the selected part of the
- text in the frontmost window to a Handle. If the front window is not a
- text window, you should try the second-front window - if it isn't text
- either, return NULL. Front OR second front, because a dialog window may be
- the front window at the time - this is the case with hAWK, for example.
- */
- Handle GetFrontText(Boolean getItAll)
- {
- #if SUPPORT_LEVEL >= BASICTEXT
- extern Handle MyAppGetFrontText(Boolean getItAll);
-
- return(MyAppGetFrontText(getItAll));
- #else
- return(NULL);
- #endif
- }
-
- /* This function should retrieve file names and vRefNums from a one
- or two-dimensional list of files. If *panePtr == -1, you are being asked
- for the first file, otherwise the next file. When there are no more files,
- set *indexPtr = -1. If you have a two-dimensional list, think of panePtr as
- the column index and indexPtr as the row index. For a one-dimensional list,
- use indexPtr to keep track of where you are - just remember to set panePtr to
- something != -1 during the first call. Other than setting panePtr to something
- besides -1 during the first call, and setting indexPtr to -1 when there are
- no more files, you can use them for tracking which file comes next in any way
- you want.
- If you perhaps use full path names, see OpenWorkingDirectoryFromFullName()
- above for hints on how to convert to filename/vRefNum.
- clearFlag TRUE means clear the file from your list; FALSE means leave it in the
- list. Normally FALSE is best - someone might want to reuse the list quite soon,
- as in running two hAWK programs on the same list of files.
- */
- void GetNextMultiFile(short *panePtr, short *indexPtr,
- short *vRefNumPtr, char *fileName, Boolean clearFlag)
- {
- #if SUPPORT_LEVEL == CUSTOMSUPPORT
- extern void GetNextFileToSearch(short *panePtr, short *indexPtr,
- short *vRefNumPtr, char *fileName, Boolean clearFlag);
-
- GetNextFileToSearch(panePtr, indexPtr,
- vRefNumPtr, fileName, clearFlag);
- #else
- *indexPtr = -1;
- #endif
- }
-
- /* If you have an alert mechanism with just an OK button that accepts C
- strings, insert it here. Return of 1 means alert was shown and user
- clicked OK, return of 0 means the alert was not shown. If this happens,
- it would be quite OK for your alert function to try to get more memory or
- show an out-of memory alert before returning the 0 or 1. */
- short OKStopAlert(Ptr cstringPtr)
- {
- #if SUPPORT_LEVEL == CUSTOMSUPPORT
- /* Left in from EnterAct as an example - EnterAct uses FlexAlert(),
- essentially as published in MacTutor Jan '91. As a small refinement, it
- will display an out-of-memory alert if it runs into trouble. FlexAlert
- sizes the alert box to fit the text, and also formats the text nicely. */
- extern short FlexAlert(short buttonMode, short whichIcon, Ptr csPtr);
- #define JUSTOK 0
- #define STOPICON 0
- return(FlexAlert(JUSTOK, STOPICON, cstringPtr));
- #else
- return(0);
- #endif
- }
-
- /* Advise the user that memory has run out during code resource execution.
- You must have something for this kicking around in your application - a
- text message is much more likeable than a beep if things fo worng. */
- void MemoryAlert()
- {
- #if SUPPORT_LEVEL == CUSTOMSUPPORT
- extern void DoMemoryAlert(short msgNum, long memLimit);
-
- #define NONELEFT 4
-
- DoMemoryAlert(NONELEFT, 0L);
- #else
- SysBeep(2);
- #endif
- }
-
- short GetScreenHeight(void)
- {
- return(screenBits.bounds.bottom - screenBits.bounds.top);
- }
-
- short GetScreenWidth()
- {
- return(screenBits.bounds.right - screenBits.bounds.left);
- }
-
- void ShowWatchCursor()
- {
- #if SUPPORT_LEVEL == CUSTOMSUPPORT
- extern void MySetWatchCursor(void);
-
- MySetWatchCursor();
- #endif
-
- /* this goes something like:
- CursHandle Watch; -- ToolboxUtil.h enum constant --
- Watch = GetCursor(watchCursor);
- if (Watch)
- SetCursor (*Watch);
- else
- InitCursor();
- */
- }
-
- void DoEventLoopOnce()
- {
- #if VERSION2 == TRUE
- extern void HandleOneEvent(void);
-
- HandleOneEvent();
- #endif
- }
-
- Handle GetAppClip()
- {
- #if SUPPORT_LEVEL == CUSTOMSUPPORT
- #if VERSION2 == TRUE
- extern pascal Handle PEGetScrap(void);
- return(PEGetScrap());
- #endif
- #endif
- return(NULL);
- }
-
- short PutAppClip(char *newClipStr)
- {
- // Put the C string newClipStr on your application's private clip,
- // as for example make a handle here, put the string in it, and
- // set TextEdit's scrap to the new handle.
- // return 0 if failure, 1 if success.
- return 0;
- }
-