diff options
Diffstat (limited to 'mac')
-rw-r--r-- | mac/tclMacLoad.c | 186 |
1 files changed, 116 insertions, 70 deletions
diff --git a/mac/tclMacLoad.c b/mac/tclMacLoad.c index e767651..a36e151 100644 --- a/mac/tclMacLoad.c +++ b/mac/tclMacLoad.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacLoad.c,v 1.12 2002/01/27 11:09:58 das Exp $ + * RCS: @(#) $Id: tclMacLoad.c,v 1.13 2002/07/17 20:00:46 vincentdarley Exp $ */ #include <CodeFragments.h> @@ -76,6 +76,16 @@ struct CfrgItem { Str255 name; /* This is actually variable sized. */ }; typedef struct CfrgItem CfrgItem; + +typedef struct TclMacLoadInfo { + int loaded; + CFragConnectionID connID; + FSSpec fileSpec; +} TclMacLoadInfo; + +static int TryToLoad(Tcl_Interp *interp, TclMacLoadInfo *loadInfo, + CONST char *sym /* native */) + /* *---------------------------------------------------------------------- @@ -97,18 +107,11 @@ typedef struct CfrgItem CfrgItem; */ int -TclpLoadFile( - Tcl_Interp *interp, /* Used for error reporting. */ - Tcl_Obj *pathPtr, /* Name of the file containing the desired - * code. */ - CONST char *sym1, - CONST char *sym2, /* Names of two procedures to look up in - * the file's symbol table. */ - Tcl_PackageInitProc **proc1Ptr, - Tcl_PackageInitProc **proc2Ptr, - /* Where to return the addresses corresponding - * to sym1 and sym2. */ - ClientData *clientDataPtr, /* Filled with token for dynamically loaded +TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr) + Tcl_Interp *interp; /* Used for error reporting. */ + Tcl_Obj *pathPtr; /* Name of the file containing the desired + * code (UTF-8). */ + TclLoadHandle *loadHandle; /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ Tcl_FSUnloadFileProc **unloadProcPtr) @@ -116,19 +119,11 @@ TclpLoadFile( * function which should be used for * this file. */ { - CFragConnectionID connID; - Ptr dummy; OSErr err; - CFragSymbolClass symClass; FSSpec fileSpec; - short fragFileRef, saveFileRef; - Handle fragResource; - UInt32 offset = 0; - UInt32 length = kCFragGoesToEOF; - StringPtr fragName=NULL; - Str255 errName, symbolName; Tcl_DString ds; CONST char *native; + TclMacLoadInfo *loadInfo; native = Tcl_FSGetNativePath(pathPtr); err = FSpLocationFromPath(strlen(native), native, &fileSpec); @@ -138,15 +133,37 @@ TclpLoadFile( return TCL_ERROR; } - /* - * First thing we must do is infer the package name from the sym1 - * variable (by removing the "_Init" suffix). This is kind of dumb - * since the caller actually knows this value, it just doesn't give - * it to us. - */ - native = Tcl_UtfToExternalDString(NULL, sym1, -1, &ds); - Tcl_DStringSetLength(&ds, Tcl_DStringLength(&ds) - 5); + loadInfo = (TclMacLoadInfo *) ckalloc(sizeof(TclMacLoadInfo)); + loadInfo->loaded = 0; + loadInfo->fileSpec = fileSpec; + loadInfo->connID = NULL; + if (TryToLoad(interp, loadInfo, NULL) != TCL_OK) { + ckfree(loadInfo); + return TCL_ERROR; + } + + *loadHandle = (TclLoadHandle)loadInfo; + *unloadProcPtr = &TclpUnloadFile; + return TCL_OK; +} +static int +TryToLoad(Tcl_Interp *interp, TclMacLoadInfo *loadInfo, + CONST char *sym /* native */) +{ + CFragConnectionID connID; + Ptr dummy; + short fragFileRef, saveFileRef; + Handle fragResource; + UInt32 offset = 0; + UInt32 length = kCFragGoesToEOF; + Str255 errName; + StringPtr fragName=NULL; + + if (loadInfo->loaded == 1) { + return TCL_OK; + } + /* * See if this fragment has a 'cfrg' resource. It will tell us where * to look for the fragment in the file. If it doesn't exist we will @@ -160,25 +177,27 @@ TclpLoadFile( fragFileRef = FSpOpenResFile(&fileSpec, fsRdPerm); SetResLoad(true); if (fragFileRef != -1) { - UseResFile(fragFileRef); - fragResource = Get1Resource(kCFragResourceType, kCFragResourceID); - HLock(fragResource); - if (ResError() == noErr) { - CfrgItem* srcItem; - long itemCount, index; - Ptr itemStart; + if (sym != NULL) { + UseResFile(fragFileRef); + fragResource = Get1Resource(kCFragResourceType, kCFragResourceID); + HLock(fragResource); + if (ResError() == noErr) { + CfrgItem* srcItem; + long itemCount, index; + Ptr itemStart; - itemCount = (*(CfrgHeaderPtrHand)fragResource)->itemCount; - itemStart = &(*(CfrgHeaderPtrHand)fragResource)->arrayStart; - for (index = 0; index < itemCount; - index++, itemStart += srcItem->itemSize) { - srcItem = (CfrgItem*)itemStart; - if (srcItem->archType != OUR_ARCH_TYPE) continue; - if (!strncasecmp(native, (char *) srcItem->name + 1, - strlen(native))) { - offset = srcItem->codeOffset; - length = srcItem->codeLength; - fragName=srcItem->name; + itemCount = (*(CfrgHeaderPtrHand)fragResource)->itemCount; + itemStart = &(*(CfrgHeaderPtrHand)fragResource)->arrayStart; + for (index = 0; index < itemCount; + index++, itemStart += srcItem->itemSize) { + srcItem = (CfrgItem*)itemStart; + if (srcItem->archType != OUR_ARCH_TYPE) continue; + if (!strncasecmp(sym, (char *) srcItem->name + 1, + strlen(sym))) { + offset = srcItem->codeOffset; + length = srcItem->codeLength; + fragName=srcItem->name; + } } } } @@ -191,20 +210,21 @@ TclpLoadFile( ReleaseResource(fragResource); CloseResFile(fragFileRef); UseResFile(saveFileRef); + if (sym == NULL) { + /* We just return */ + return TCL_OK; + } } - Tcl_DStringFree(&ds); /* - * Now we can attempt to load the fragement using the offset & length + * Now we can attempt to load the fragment using the offset & length * obtained from the resource. We don't worry about the main entry point * as we are going to search for specific entry points passed to us. */ err = GetDiskFragment(&fileSpec, offset, length, fragName, kLoadCFrag, &connID, &dummy, errName); - - *clientDataPtr = (ClientData) connID; - + if (err != fragNoErr) { p2cstr(errName); Tcl_AppendResult(interp, "couldn't load file \"", @@ -212,31 +232,53 @@ TclpLoadFile( "\": ", errName, (char *) NULL); return TCL_ERROR; } - - *unloadProcPtr = &TclpUnloadFile; + + loadInfo->connID = connID; + loadInfo->loaded = 1; + + return TCL_OK; +} + +Tcl_PackageInitProc* +TclpFindSymbol(interp, loadHandle, symbol) + Tcl_Interp *interp; + TclLoadHandle loadHandle; + CONST char *symbol; +{ + Tcl_DString ds; + Tcl_PackageInitProc *proc=NULL; + TclMacLoadInfo *loadInfo = (TclMacLoadInfo *)loadHandle; + Str255 symbolName; + CFragSymbolClass symClass; + OSErr err; - Tcl_UtfToExternalDString(NULL, sym1, -1, &ds); + if (loadInfo->loaded == 0) { + int res; + /* + * First thing we must do is infer the package name from the + * sym variable. We do this by removing the '_Init'. + */ + Tcl_UtfToExternalDString(NULL, symbol, -1, &ds); + Tcl_DStringSetLength(&ds, Tcl_DStringLength(&ds) - 5); + res = TryToLoad(interp, loadInfo, Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); + if (res != TCL_OK) { + return NULL; + } + } + + Tcl_UtfToExternalDString(NULL, symbol, -1, &ds); strcpy((char *) symbolName + 1, Tcl_DStringValue(&ds)); symbolName[0] = (unsigned) Tcl_DStringLength(&ds); - err = FindSymbol(connID, symbolName, (Ptr *) proc1Ptr, &symClass); + err = FindSymbol(loadInfo->connID, symbolName, (Ptr *) &proc, &symClass); Tcl_DStringFree(&ds); if (err != fragNoErr || symClass == kDataCFragSymbol) { Tcl_SetResult(interp, "could not find Initialization routine in library", TCL_STATIC); - return TCL_ERROR; + return NULL; } - - Tcl_UtfToExternalDString(NULL, sym2, -1, &ds); - strcpy((char *) symbolName + 1, Tcl_DStringValue(&ds)); - symbolName[0] = (unsigned) Tcl_DStringLength(&ds); - err = FindSymbol(connID, symbolName, (Ptr *) proc2Ptr, &symClass); - Tcl_DStringFree(&ds); - if (err != fragNoErr || symClass == kDataCFragSymbol) { - *proc2Ptr = NULL; - } - - return TCL_OK; + return proc; } /* @@ -264,7 +306,11 @@ TclpUnloadFile(clientData) * a token that represents the loaded * file. */ { - CloseConnection((CFragConnectionID*) &clientData); + TclMacLoadInfo *loadInfo = (TclMacLoadInfo *)clientData; + if (loadInfo->loaded) { + CloseConnection((CFragConnectionID*) &(loadInfo->connID)); + } + ckfree(loadInfo); } /* |