os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacExit.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacExit.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,333 @@
1.4 +/*
1.5 + * tclMacExit.c --
1.6 + *
1.7 + * This file contains routines that deal with cleaning up various state
1.8 + * when Tcl/Tk applications quit. Unfortunantly, not all state is cleaned
1.9 + * up by the process when an application quites or crashes. Also you
1.10 + * need to do different things depending on wether you are running as
1.11 + * 68k code, PowerPC, or a code resource. The Exit handler code was
1.12 + * adapted from code posted on alt.sources.mac by Dave Nebinger.
1.13 + *
1.14 + * Copyright (c) 1995 Dave Nebinger.
1.15 + * Copyright (c) 1995-1996 Sun Microsystems, Inc.
1.16 + *
1.17 + * See the file "license.terms" for information on usage and redistribution
1.18 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
1.19 + *
1.20 + * RCS: @(#) $Id: tclMacExit.c,v 1.4 1999/04/16 00:47:19 stanton Exp $
1.21 + */
1.22 +
1.23 +#include "tclInt.h"
1.24 +#include "tclMacInt.h"
1.25 +#include <SegLoad.h>
1.26 +#include <Traps.h>
1.27 +#include <Processes.h>
1.28 +
1.29 +/*
1.30 + * Various typedefs and defines needed to patch ExitToShell.
1.31 + */
1.32 +
1.33 +enum {
1.34 + uppExitToShellProcInfo = kPascalStackBased
1.35 +};
1.36 +
1.37 +#if GENERATINGCFM
1.38 +typedef UniversalProcPtr ExitToShellUPP;
1.39 +
1.40 +#define CallExitToShellProc(userRoutine) \
1.41 + CallUniversalProc((UniversalProcPtr)(userRoutine),uppExitToShellProcInfo)
1.42 +#define NewExitToShellProc(userRoutine) \
1.43 + (ExitToShellUPP)NewRoutineDescriptor((ProcPtr)(userRoutine), \
1.44 + uppExitToShellProcInfo, GetCurrentArchitecture())
1.45 +
1.46 +#else
1.47 +typedef ExitToShellProcPtr ExitToShellUPP;
1.48 +
1.49 +#define CallExitToShellProc(userRoutine) \
1.50 + (*(userRoutine))()
1.51 +#define NewExitToShellProc(userRoutine) \
1.52 + (ExitToShellUPP)(userRoutine)
1.53 +#endif
1.54 +
1.55 +#define DisposeExitToShellProc(userRoutine) \
1.56 + DisposeRoutineDescriptor(userRoutine)
1.57 +
1.58 +#if defined(powerc)||defined(__powerc)
1.59 +#pragma options align=mac68k
1.60 +#endif
1.61 +struct ExitToShellUPPList{
1.62 + struct ExitToShellUPPList* nextProc;
1.63 + ExitToShellUPP userProc;
1.64 +};
1.65 +#if defined(powerc)||defined(__powerc)
1.66 +#pragma options align=reset
1.67 +#endif
1.68 +
1.69 +typedef struct ExitToShellDataStruct ExitToShellDataRec,* ExitToShellDataPtr,** ExitToShellDataHdl;
1.70 +
1.71 +typedef struct ExitToShellUPPList ExitToShellUPPList,* ExitToShellUPPListPtr,** ExitToShellUPPHdl;
1.72 +
1.73 +#if defined(powerc)||defined(__powerc)
1.74 +#pragma options align=mac68k
1.75 +#endif
1.76 +struct ExitToShellDataStruct{
1.77 + unsigned long a5;
1.78 + ExitToShellUPPList* userProcs;
1.79 + ExitToShellUPP oldProc;
1.80 +};
1.81 +#if defined(powerc)||defined(__powerc)
1.82 +#pragma options align=reset
1.83 +#endif
1.84 +
1.85 +/*
1.86 + * Static globals used within this file.
1.87 + */
1.88 +static ExitToShellDataPtr gExitToShellData = (ExitToShellDataPtr) NULL;
1.89 +
1.90 +
1.91 +/*
1.92 + *----------------------------------------------------------------------
1.93 + *
1.94 + * TclPlatformExit --
1.95 + *
1.96 + * This procedure implements the Macintosh specific exit routine.
1.97 + * We explicitly callthe ExitHandler function to do various clean
1.98 + * up.
1.99 + *
1.100 + * Results:
1.101 + * None.
1.102 + *
1.103 + * Side effects:
1.104 + * We exit the process.
1.105 + *
1.106 + *----------------------------------------------------------------------
1.107 + */
1.108 +
1.109 +void
1.110 +TclpExit(
1.111 + int status) /* Ignored. */
1.112 +{
1.113 + TclMacExitHandler();
1.114 +
1.115 +/*
1.116 + * If we are using the Metrowerks Standard Library, then we will call its exit so that it
1.117 + * will get a chance to clean up temp files, and so forth. It always calls the standard
1.118 + * ExitToShell, so the Tcl handlers will also get called.
1.119 + *
1.120 + * If you have another exit, make sure that it does not patch ExitToShell, and does
1.121 + * call it. If so, it will probably work as well.
1.122 + *
1.123 + */
1.124 +
1.125 +#ifdef __MSL__
1.126 + exit(status);
1.127 +#else
1.128 + ExitToShell();
1.129 +#endif
1.130 +
1.131 +}
1.132 +
1.133 +/*
1.134 + *----------------------------------------------------------------------
1.135 + *
1.136 + * TclMacExitHandler --
1.137 + *
1.138 + * This procedure is invoked after Tcl at the last possible moment
1.139 + * to clean up any state Tcl has left around that may cause other
1.140 + * applications to crash. For example, this function can be used
1.141 + * as the termination routine for CFM applications.
1.142 + *
1.143 + * Results:
1.144 + * None.
1.145 + *
1.146 + * Side effects:
1.147 + * Various cleanup occurs.
1.148 + *
1.149 + *----------------------------------------------------------------------
1.150 + */
1.151 +
1.152 +void
1.153 +TclMacExitHandler()
1.154 +{
1.155 + ExitToShellUPPListPtr curProc;
1.156 +
1.157 + /*
1.158 + * Loop through all installed Exit handlers
1.159 + * and call them. Always make sure we are in
1.160 + * a clean state in case we are recursivly called.
1.161 + */
1.162 + if ((gExitToShellData) != NULL && (gExitToShellData->userProcs != NULL)){
1.163 +
1.164 + /*
1.165 + * Call the installed exit to shell routines.
1.166 + */
1.167 + curProc = gExitToShellData->userProcs;
1.168 + do {
1.169 + gExitToShellData->userProcs = curProc->nextProc;
1.170 + CallExitToShellProc(curProc->userProc);
1.171 + DisposeExitToShellProc(curProc->userProc);
1.172 + DisposePtr((Ptr) curProc);
1.173 + curProc = gExitToShellData->userProcs;
1.174 + } while (curProc != (ExitToShellUPPListPtr) NULL);
1.175 + }
1.176 +
1.177 + return;
1.178 +}
1.179 +
1.180 +/*
1.181 + *----------------------------------------------------------------------
1.182 + *
1.183 + * TclMacInstallExitToShellPatch --
1.184 + *
1.185 + * This procedure installs a way to clean up state at the latest
1.186 + * possible moment before we exit. These are things that must
1.187 + * be cleaned up or the system will crash. The exact way in which
1.188 + * this is implemented depends on the architecture in which we are
1.189 + * running. For 68k applications we patch the ExitToShell call.
1.190 + * For PowerPC applications we just create a list of procs to call.
1.191 + * The function ExitHandler should be installed in the Code
1.192 + * Fragments terminiation routine.
1.193 + *
1.194 + * Results:
1.195 + * None.
1.196 + *
1.197 + * Side effects:
1.198 + * Installs the new routine.
1.199 + *
1.200 + *----------------------------------------------------------------------
1.201 + */
1.202 +
1.203 +OSErr
1.204 +TclMacInstallExitToShellPatch(
1.205 + ExitToShellProcPtr newProc) /* Function pointer. */
1.206 +{
1.207 + ExitToShellUPP exitHandler;
1.208 + ExitToShellUPPListPtr listPtr;
1.209 +
1.210 + if (gExitToShellData == (ExitToShellDataPtr) NULL){
1.211 + TclMacInitExitToShell(true);
1.212 + }
1.213 +
1.214 + /*
1.215 + * Add the passed in function pointer to the list of functions
1.216 + * to be called when ExitToShell is called.
1.217 + */
1.218 + exitHandler = NewExitToShellProc(newProc);
1.219 + listPtr = (ExitToShellUPPListPtr) NewPtrClear(sizeof(ExitToShellUPPList));
1.220 + listPtr->userProc = exitHandler;
1.221 + listPtr->nextProc = gExitToShellData->userProcs;
1.222 + gExitToShellData->userProcs = listPtr;
1.223 +
1.224 + return noErr;
1.225 +}
1.226 +
1.227 +/*
1.228 + *----------------------------------------------------------------------
1.229 + *
1.230 + * ExitToShellPatchRoutine --
1.231 + *
1.232 + * This procedure is invoked when someone calls ExitToShell for
1.233 + * this application. This function performs some last miniute
1.234 + * clean up and then calls the real ExitToShell routine.
1.235 + *
1.236 + * Results:
1.237 + * None.
1.238 + *
1.239 + * Side effects:
1.240 + * Various cleanup occurs.
1.241 + *
1.242 + *----------------------------------------------------------------------
1.243 + */
1.244 +
1.245 +static pascal void
1.246 +ExitToShellPatchRoutine()
1.247 +{
1.248 + ExitToShellUPP oldETS;
1.249 + long oldA5;
1.250 +
1.251 + /*
1.252 + * Set up our A5 world. This allows us to have
1.253 + * access to our global variables in the 68k world.
1.254 + */
1.255 + oldA5 = SetCurrentA5();
1.256 + SetA5(gExitToShellData->a5);
1.257 +
1.258 + /*
1.259 + * Call the function that invokes all
1.260 + * of the handlers.
1.261 + */
1.262 + TclMacExitHandler();
1.263 +
1.264 + /*
1.265 + * Call the origional ExitToShell routine.
1.266 + */
1.267 + oldETS = gExitToShellData->oldProc;
1.268 + DisposePtr((Ptr) gExitToShellData);
1.269 + SetA5(oldA5);
1.270 + CallExitToShellProc(oldETS);
1.271 + return;
1.272 +}
1.273 +
1.274 +/*
1.275 + *----------------------------------------------------------------------
1.276 + *
1.277 + * TclMacInitExitToShell --
1.278 + *
1.279 + * This procedure initializes the ExitToShell clean up machanism.
1.280 + * Generally, this is handled automatically when users make a call
1.281 + * to InstallExitToShellPatch. However, it can be called
1.282 + * explicitly at startup time to turn off the patching mechanism.
1.283 + * This can be used by code resources which could be removed from
1.284 + * the application before ExitToShell is called.
1.285 + *
1.286 + * Note, if we are running from CFM code we never install the
1.287 + * patch. Instead, the function ExitHandler should be installed
1.288 + * as the terminiation routine for the code fragment.
1.289 + *
1.290 + * Results:
1.291 + * None.
1.292 + *
1.293 + * Side effects:
1.294 + * Creates global state.
1.295 + *
1.296 + *----------------------------------------------------------------------
1.297 + */
1.298 +
1.299 +void
1.300 +TclMacInitExitToShell(
1.301 + int usePatch) /* True if on 68k. */
1.302 +{
1.303 + if (gExitToShellData == (ExitToShellDataPtr) NULL){
1.304 +#if GENERATINGCFM
1.305 + gExitToShellData = (ExitToShellDataPtr)
1.306 + NewPtr(sizeof(ExitToShellDataRec));
1.307 + gExitToShellData->a5 = SetCurrentA5();
1.308 + gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
1.309 +#else
1.310 + ExitToShellUPP oldExitToShell, newExitToShellPatch;
1.311 + short exitToShellTrap;
1.312 +
1.313 + /*
1.314 + * Initialize patch mechanism.
1.315 + */
1.316 +
1.317 + gExitToShellData = (ExitToShellDataPtr) NewPtr(sizeof(ExitToShellDataRec));
1.318 + gExitToShellData->a5 = SetCurrentA5();
1.319 + gExitToShellData->userProcs = (ExitToShellUPPList*) NULL;
1.320 +
1.321 + /*
1.322 + * Save state needed to call origional ExitToShell routine. Install
1.323 + * the new ExitToShell code in it's place.
1.324 + */
1.325 + if (usePatch) {
1.326 + exitToShellTrap = _ExitToShell & 0x3ff;
1.327 + newExitToShellPatch = NewExitToShellProc(ExitToShellPatchRoutine);
1.328 + oldExitToShell = (ExitToShellUPP)
1.329 + NGetTrapAddress(exitToShellTrap, ToolTrap);
1.330 + NSetTrapAddress((UniversalProcPtr) newExitToShellPatch,
1.331 + exitToShellTrap, ToolTrap);
1.332 + gExitToShellData->oldProc = oldExitToShell;
1.333 + }
1.334 +#endif
1.335 + }
1.336 +}