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