tclMacExit.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:9k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclMacExit.c --
  3.  *
  4.  * This file contains routines that deal with cleaning up various state
  5.  * when Tcl/Tk applications quit.  Unfortunantly, not all state is cleaned
  6.  * up by the process when an application quites or crashes.  Also you
  7.  * need to do different things depending on wether you are running as
  8.  * 68k code, PowerPC, or a code resource.  The Exit handler code was 
  9.  * adapted from code posted on alt.sources.mac by Dave Nebinger.
  10.  *
  11.  * Copyright (c) 1995 Dave Nebinger.
  12.  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
  13.  *
  14.  * See the file "license.terms" for information on usage and redistribution
  15.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  16.  *
  17.  * RCS: @(#) $Id: tclMacExit.c,v 1.4 1999/04/16 00:47:19 stanton Exp $
  18.  */
  19. #include "tclInt.h"
  20. #include "tclMacInt.h"
  21. #include <SegLoad.h>
  22. #include <Traps.h>
  23. #include <Processes.h>
  24. /*
  25.  * Various typedefs and defines needed to patch ExitToShell.
  26.  */
  27.  
  28. enum {
  29.         uppExitToShellProcInfo = kPascalStackBased
  30. };
  31. #if GENERATINGCFM
  32. typedef UniversalProcPtr ExitToShellUPP;
  33. #define CallExitToShellProc(userRoutine)        
  34.         CallUniversalProc((UniversalProcPtr)(userRoutine),uppExitToShellProcInfo)
  35. #define NewExitToShellProc(userRoutine) 
  36.         (ExitToShellUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), 
  37. uppExitToShellProcInfo, GetCurrentArchitecture())
  38. #else
  39. typedef ExitToShellProcPtr ExitToShellUPP;
  40. #define CallExitToShellProc(userRoutine)        
  41.         (*(userRoutine))()
  42. #define NewExitToShellProc(userRoutine) 
  43.         (ExitToShellUPP)(userRoutine)
  44. #endif
  45. #define DisposeExitToShellProc(userRoutine) 
  46.         DisposeRoutineDescriptor(userRoutine)
  47. #if defined(powerc)||defined(__powerc)
  48. #pragma options align=mac68k
  49. #endif
  50. struct ExitToShellUPPList{
  51.         struct ExitToShellUPPList* nextProc;
  52.         ExitToShellUPP userProc;
  53. };
  54. #if defined(powerc)||defined(__powerc)
  55. #pragma options align=reset
  56. #endif
  57. typedef struct ExitToShellDataStruct ExitToShellDataRec,* ExitToShellDataPtr,** ExitToShellDataHdl;
  58. typedef struct ExitToShellUPPList ExitToShellUPPList,* ExitToShellUPPListPtr,** ExitToShellUPPHdl;
  59. #if defined(powerc)||defined(__powerc)
  60. #pragma options align=mac68k
  61. #endif
  62. struct ExitToShellDataStruct{
  63.     unsigned long a5;
  64.     ExitToShellUPPList* userProcs;
  65.     ExitToShellUPP oldProc;
  66. };
  67. #if defined(powerc)||defined(__powerc)
  68. #pragma options align=reset
  69. #endif
  70. /*
  71.  * Static globals used within this file.
  72.  */
  73. static ExitToShellDataPtr gExitToShellData = (ExitToShellDataPtr) NULL;
  74. /*
  75.  *----------------------------------------------------------------------
  76.  *
  77.  * TclPlatformExit --
  78.  *
  79.  * This procedure implements the Macintosh specific exit routine.
  80.  * We explicitly callthe ExitHandler function to do various clean
  81.  * up.  
  82.  *
  83.  * Results:
  84.  * None.
  85.  *
  86.  * Side effects:
  87.  * We exit the process.
  88.  *
  89.  *----------------------------------------------------------------------
  90.  */
  91. void
  92. TclpExit(
  93.     int status) /* Ignored. */
  94. {
  95.     TclMacExitHandler();
  96. /* 
  97.  * If we are using the Metrowerks Standard Library, then we will call its exit so that it
  98.  * will get a chance to clean up temp files, and so forth.  It always calls the standard 
  99.  * ExitToShell, so the Tcl handlers will also get called.
  100.  *   
  101.  * If you have another exit, make sure that it does not patch ExitToShell, and does
  102.  * call it.  If so, it will probably work as well.
  103.  *
  104.  */
  105.  
  106. #ifdef __MSL__    
  107.     exit(status);
  108. #else
  109.     ExitToShell();
  110. #endif
  111. }
  112. /*
  113.  *----------------------------------------------------------------------
  114.  *
  115.  * TclMacExitHandler --
  116.  *
  117.  * This procedure is invoked after Tcl at the last possible moment
  118.  * to clean up any state Tcl has left around that may cause other
  119.  * applications to crash.  For example, this function can be used
  120.  * as the termination routine for CFM applications.
  121.  *
  122.  * Results:
  123.  * None.
  124.  *
  125.  * Side effects:
  126.  * Various cleanup occurs.
  127.  *
  128.  *----------------------------------------------------------------------
  129.  */
  130. void
  131. TclMacExitHandler()
  132. {
  133.     ExitToShellUPPListPtr curProc;
  134.     /*
  135.      * Loop through all installed Exit handlers
  136.      * and call them.  Always make sure we are in
  137.      * a clean state in case we are recursivly called.
  138.      */
  139.     if ((gExitToShellData) != NULL && (gExitToShellData->userProcs != NULL)){
  140.     
  141. /*
  142.  * Call the installed exit to shell routines.
  143.  */
  144. curProc = gExitToShellData->userProcs;
  145. do {
  146.     gExitToShellData->userProcs = curProc->nextProc;
  147.     CallExitToShellProc(curProc->userProc);
  148.     DisposeExitToShellProc(curProc->userProc);
  149.     DisposePtr((Ptr) curProc);
  150.     curProc = gExitToShellData->userProcs;
  151. } while (curProc != (ExitToShellUPPListPtr) NULL);
  152.     }
  153.     return;
  154. }
  155. /*
  156.  *----------------------------------------------------------------------
  157.  *
  158.  * TclMacInstallExitToShellPatch --
  159.  *
  160.  * This procedure installs a way to clean up state at the latest
  161.  * possible moment before we exit.  These are things that must
  162.  * be cleaned up or the system will crash.  The exact way in which
  163.  * this is implemented depends on the architecture in which we are
  164.  * running.  For 68k applications we patch the ExitToShell call.
  165.  * For PowerPC applications we just create a list of procs to call.
  166.  * The function ExitHandler should be installed in the Code 
  167.  * Fragments terminiation routine.
  168.  *
  169.  * Results:
  170.  * None.
  171.  *
  172.  * Side effects:
  173.  * Installs the new routine.
  174.  *
  175.  *----------------------------------------------------------------------
  176.  */
  177. OSErr 
  178. TclMacInstallExitToShellPatch(
  179.     ExitToShellProcPtr newProc) /* Function pointer. */
  180. {
  181.     ExitToShellUPP exitHandler;
  182.     ExitToShellUPPListPtr listPtr;
  183.     if (gExitToShellData == (ExitToShellDataPtr) NULL){
  184. TclMacInitExitToShell(true);
  185.     }
  186.     /*
  187.      * Add the passed in function pointer to the list of functions
  188.      * to be called when ExitToShell is called.
  189.      */
  190.     exitHandler = NewExitToShellProc(newProc);
  191.     listPtr = (ExitToShellUPPListPtr) NewPtrClear(sizeof(ExitToShellUPPList));
  192.     listPtr->userProc = exitHandler;
  193.     listPtr->nextProc = gExitToShellData->userProcs;
  194.     gExitToShellData->userProcs = listPtr;
  195.     return noErr;
  196. }
  197. /*
  198.  *----------------------------------------------------------------------
  199.  *
  200.  * ExitToShellPatchRoutine --
  201.  *
  202.  * This procedure is invoked when someone calls ExitToShell for
  203.  * this application.  This function performs some last miniute
  204.  * clean up and then calls the real ExitToShell routine.
  205.  *
  206.  * Results:
  207.  * None.
  208.  *
  209.  * Side effects:
  210.  * Various cleanup occurs.
  211.  *
  212.  *----------------------------------------------------------------------
  213.  */
  214. static pascal void
  215. ExitToShellPatchRoutine()
  216. {
  217.     ExitToShellUPP oldETS;
  218.     long oldA5;
  219.     /*
  220.      * Set up our A5 world.  This allows us to have
  221.      * access to our global variables in the 68k world.
  222.      */
  223.     oldA5 = SetCurrentA5();
  224.     SetA5(gExitToShellData->a5);
  225.     /*
  226.      * Call the function that invokes all
  227.      * of the handlers.
  228.      */
  229.     TclMacExitHandler();
  230.     /*
  231.      * Call the origional ExitToShell routine.
  232.      */
  233.     oldETS = gExitToShellData->oldProc;
  234.     DisposePtr((Ptr) gExitToShellData);
  235.     SetA5(oldA5);
  236.     CallExitToShellProc(oldETS);
  237.     return;
  238. }
  239. /*
  240.  *----------------------------------------------------------------------
  241.  *
  242.  * TclMacInitExitToShell --
  243.  *
  244.  * This procedure initializes the ExitToShell clean up machanism.
  245.  * Generally, this is handled automatically when users make a call
  246.  * to InstallExitToShellPatch.  However, it can be called 
  247.  * explicitly at startup time to turn off the patching mechanism.
  248.  * This can be used by code resources which could be removed from
  249.  * the application before ExitToShell is called.
  250.  *
  251.  * Note, if we are running from CFM code we never install the
  252.  * patch.  Instead, the function ExitHandler should be installed
  253.  * as the terminiation routine for the code fragment.
  254.  *
  255.  * Results:
  256.  * None.
  257.  *
  258.  * Side effects:
  259.  * Creates global state.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263. void 
  264. TclMacInitExitToShell(
  265.     int usePatch) /* True if on 68k. */
  266. {
  267.     if (gExitToShellData == (ExitToShellDataPtr) NULL){
  268. #if GENERATINGCFM
  269. gExitToShellData = (ExitToShellDataPtr)
  270.   NewPtr(sizeof(ExitToShellDataRec));
  271. gExitToShellData->a5 = SetCurrentA5();
  272. gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
  273. #else
  274. ExitToShellUPP oldExitToShell, newExitToShellPatch;
  275. short exitToShellTrap;
  276. /*
  277.  * Initialize patch mechanism.
  278.  */
  279.  
  280. gExitToShellData = (ExitToShellDataPtr) NewPtr(sizeof(ExitToShellDataRec));
  281. gExitToShellData->a5 = SetCurrentA5();
  282. gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
  283. /*
  284.  * Save state needed to call origional ExitToShell routine.  Install
  285.  * the new ExitToShell code in it's place.
  286.  */
  287. if (usePatch) {
  288.     exitToShellTrap = _ExitToShell & 0x3ff;
  289.     newExitToShellPatch = NewExitToShellProc(ExitToShellPatchRoutine);
  290.     oldExitToShell = (ExitToShellUPP)
  291.       NGetTrapAddress(exitToShellTrap, ToolTrap);
  292.     NSetTrapAddress((UniversalProcPtr) newExitToShellPatch,
  293.     exitToShellTrap, ToolTrap);
  294.     gExitToShellData->oldProc = oldExitToShell;
  295. }
  296. #endif
  297.     }
  298. }