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