sl@0: /* sl@0: * tclMacLibrary.c -- sl@0: * sl@0: * This file should be included in Tcl extensions that want to sl@0: * automatically open their resource forks when the code is linked. sl@0: * These routines should not be exported but should be compiled sl@0: * locally by each fragment. Many thanks to Jay Lieske sl@0: * who provide an initial version of this sl@0: * file. sl@0: * sl@0: * Copyright (c) 1996 Sun Microsystems, Inc. sl@0: * sl@0: * See the file "license.terms" for information on usage and redistribution sl@0: * of this file, and for a DISCLAIMER OF ALL WARRANTIES. sl@0: * sl@0: * RCS: @(#) $Id: tclMacLibrary.c,v 1.5 2001/11/23 01:27:39 das Exp $ sl@0: */ sl@0: sl@0: /* sl@0: * Here is another place that we are using the old routine names... sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "tclMacInt.h" sl@0: sl@0: #if defined(TCL_REGISTER_LIBRARY) && defined(USE_TCL_STUBS) sl@0: #error "Can't use TCL_REGISTER_LIBRARY and USE_TCL_STUBS at the same time!" sl@0: /* sl@0: * Can't register a library with Tcl when using stubs in the current sl@0: * implementation, since Tcl_InitStubs hasn't been called yet sl@0: * when OpenLibraryResource is executing. sl@0: */ sl@0: #endif sl@0: sl@0: /* sl@0: * These function are not currently defined in any header file. The sl@0: * only place they should be used is in the Initialization and sl@0: * Termination entry points for a code fragment. The prototypes sl@0: * are included here to avoid compile errors. sl@0: */ sl@0: sl@0: OSErr TclMacInitializeFragment _ANSI_ARGS_(( sl@0: struct CFragInitBlock* initBlkPtr)); sl@0: void TclMacTerminateFragment _ANSI_ARGS_((void)); sl@0: sl@0: /* sl@0: * Static functions in this file. sl@0: */ sl@0: sl@0: static OSErr OpenLibraryResource _ANSI_ARGS_(( sl@0: struct CFragInitBlock* initBlkPtr)); sl@0: static void CloseLibraryResource _ANSI_ARGS_((void)); sl@0: sl@0: /* sl@0: * The refnum of the opened resource fork. sl@0: */ sl@0: static short ourResFile = kResFileNotOpened; sl@0: sl@0: /* sl@0: * This is the resource token for the our resource file. sl@0: * It stores the name we registered with the resource facility. sl@0: * We only need to use this if we are actually registering ourselves. sl@0: */ sl@0: sl@0: #ifdef TCL_REGISTER_LIBRARY sl@0: static Tcl_Obj *ourResToken; sl@0: #endif sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * TclMacInitializeFragment -- sl@0: * sl@0: * Called by MacOS CFM when the shared library is loaded. All this sl@0: * function really does is give Tcl a chance to open and register sl@0: * the resource fork of the library. sl@0: * sl@0: * Results: sl@0: * MacOS error code if loading should be canceled. sl@0: * sl@0: * Side effects: sl@0: * Opens the resource fork of the shared library file. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: OSErr sl@0: TclMacInitializeFragment( sl@0: struct CFragInitBlock* initBlkPtr) /* Pointer to our library. */ sl@0: { sl@0: OSErr err = noErr; sl@0: sl@0: #ifdef __MWERKS__ sl@0: { sl@0: extern OSErr __initialize( CFragInitBlock* initBlkPtr); sl@0: err = __initialize((CFragInitBlock *) initBlkPtr); sl@0: } sl@0: #endif sl@0: if (err == noErr) sl@0: err = OpenLibraryResource( initBlkPtr); sl@0: return err; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * TclMacTerminateFragment -- sl@0: * sl@0: * Called by MacOS CFM when the shared library is unloaded. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * The resource fork of the code fragment is closed. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: void sl@0: TclMacTerminateFragment() sl@0: { sl@0: CloseLibraryResource(); sl@0: sl@0: #ifdef __MWERKS__ sl@0: { sl@0: extern void __terminate(void); sl@0: __terminate(); sl@0: } sl@0: #endif sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * OpenLibraryResource -- sl@0: * sl@0: * This routine can be called by a MacOS fragment's initialiation sl@0: * function to open the resource fork of the file. sl@0: * Call it with the same data passed to the initialization function. sl@0: * If the fragment loading should fail if the resource fork can't sl@0: * be opened, then the initialization function can pass on this sl@0: * return value. sl@0: * sl@0: * If you #define TCL_REGISTER_RESOURCE before compiling this resource, sl@0: * then your library will register its open resource fork with the sl@0: * resource command. sl@0: * sl@0: * Results: sl@0: * It returns noErr on success and a MacOS error code on failure. sl@0: * sl@0: * Side effects: sl@0: * The resource fork of the code fragment is opened read-only and sl@0: * is installed at the head of the resource chain. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static OSErr sl@0: OpenLibraryResource( sl@0: struct CFragInitBlock* initBlkPtr) sl@0: { sl@0: /* sl@0: * The 3.0 version of the Universal headers changed CFragInitBlock sl@0: * to an opaque pointer type. CFragSystem7InitBlock is now the sl@0: * real pointer. sl@0: */ sl@0: sl@0: #if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300) sl@0: struct CFragInitBlock *realInitBlkPtr = initBlkPtr; sl@0: #else sl@0: CFragSystem7InitBlock *realInitBlkPtr = (CFragSystem7InitBlock *) initBlkPtr; sl@0: #endif sl@0: FSSpec* fileSpec = NULL; sl@0: OSErr err = noErr; sl@0: sl@0: sl@0: if (realInitBlkPtr->fragLocator.where == kDataForkCFragLocator) { sl@0: fileSpec = realInitBlkPtr->fragLocator.u.onDisk.fileSpec; sl@0: } else if (realInitBlkPtr->fragLocator.where == kResourceCFragLocator) { sl@0: fileSpec = realInitBlkPtr->fragLocator.u.inSegs.fileSpec; sl@0: } else { sl@0: err = resFNotFound; sl@0: } sl@0: sl@0: /* sl@0: * Open the resource fork for this library in read-only mode. sl@0: * This will make it the current res file, ahead of the sl@0: * application's own resources. sl@0: */ sl@0: sl@0: if (fileSpec != NULL) { sl@0: ourResFile = FSpOpenResFile(fileSpec, fsRdPerm); sl@0: if (ourResFile == kResFileNotOpened) { sl@0: err = ResError(); sl@0: } else { sl@0: #ifdef TCL_REGISTER_LIBRARY sl@0: ourResToken = Tcl_NewObj(); sl@0: Tcl_IncrRefCount(ourResToken); sl@0: p2cstr(realInitBlkPtr->libName); sl@0: Tcl_SetStringObj(ourResToken, (char *) realInitBlkPtr->libName, -1); sl@0: c2pstr((char *) realInitBlkPtr->libName); sl@0: TclMacRegisterResourceFork(ourResFile, ourResToken, sl@0: TCL_RESOURCE_DONT_CLOSE); sl@0: #endif sl@0: SetResFileAttrs(ourResFile, mapReadOnly); sl@0: } sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * CloseLibraryResource -- sl@0: * sl@0: * This routine should be called by a MacOS fragment's termination sl@0: * function to close the resource fork of the file sl@0: * that was opened with OpenLibraryResource. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * The resource fork of the code fragment is closed. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static void sl@0: CloseLibraryResource() sl@0: { sl@0: if (ourResFile != kResFileNotOpened) { sl@0: #ifdef TCL_REGISTER_LIBRARY sl@0: int length; sl@0: TclMacUnRegisterResourceFork( sl@0: Tcl_GetStringFromObj(ourResToken, &length), sl@0: NULL); sl@0: Tcl_DecrRefCount(ourResToken); sl@0: #endif sl@0: CloseResFile(ourResFile); sl@0: ourResFile = kResFileNotOpened; sl@0: } sl@0: }