os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacLoad.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2  * tclMacLoad.c --
     3  *
     4  *	This procedure provides a version of the TclLoadFile for use
     5  *	on the Macintosh.  This procedure will only work with systems 
     6  *	that use the Code Fragment Manager.
     7  *
     8  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
     9  *
    10  * See the file "license.terms" for information on usage and redistribution
    11  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    12  *
    13  * RCS: @(#) $Id: tclMacLoad.c,v 1.16 2002/10/09 11:54:26 das Exp $
    14  */
    15 
    16 #include <CodeFragments.h>
    17 #include <Errors.h>
    18 #include <Resources.h>
    19 #include <Strings.h>
    20 #include <FSpCompat.h>
    21 
    22 /*
    23  * Seems that the 3.0.1 Universal headers leave this define out.  So we
    24  * define it here...
    25  */
    26  
    27 #ifndef fragNoErr
    28     #define fragNoErr noErr
    29 #endif
    30 
    31 #include "tclPort.h"
    32 #include "tclInt.h"
    33 #include "tclMacInt.h"
    34 
    35 #if GENERATINGPOWERPC
    36     #define OUR_ARCH_TYPE kPowerPCCFragArch
    37 #else
    38     #define OUR_ARCH_TYPE kMotorola68KCFragArch
    39 #endif
    40 
    41 /*
    42  * The following data structure defines the structure of a code fragment
    43  * resource.  We can cast the resource to be of this type to access
    44  * any fields we need to see.
    45  */
    46 struct CfrgHeader {
    47     long 	res1;
    48     long 	res2;
    49     long 	version;
    50     long 	res3;
    51     long 	res4;
    52     long 	filler1;
    53     long 	filler2;
    54     long 	itemCount;
    55     char	arrayStart;	/* Array of externalItems begins here. */
    56 };
    57 typedef struct CfrgHeader CfrgHeader, *CfrgHeaderPtr, **CfrgHeaderPtrHand;
    58 
    59 /*
    60  * The below structure defines a cfrag item within the cfrag resource.
    61  */
    62 struct CfrgItem {
    63     OSType 	archType;
    64     long 	updateLevel;
    65     long	currVersion;
    66     long	oldDefVersion;
    67     long	appStackSize;
    68     short	appSubFolder;
    69     char	usage;
    70     char	location;
    71     long	codeOffset;
    72     long	codeLength;
    73     long	res1;
    74     long	res2;
    75     short	itemSize;
    76     Str255	name;		/* This is actually variable sized. */
    77 };
    78 typedef struct CfrgItem CfrgItem;
    79 
    80 /*
    81  * On MacOS, old shared libraries which contain many code fragments
    82  * cannot, it seems, be loaded in one go.  We need to look provide
    83  * the name of a code fragment while we load.  Since with the
    84  * separation of the 'load' and 'findsymbol' be do not necessarily
    85  * know a symbol name at load time, we have to store some further
    86  * information in a structure like this so we can ensure we load
    87  * properly in 'findsymbol' if the first attempts didn't work.
    88  */
    89 typedef struct TclMacLoadInfo {
    90     int loaded;
    91     CFragConnectionID connID;
    92     FSSpec fileSpec;
    93 } TclMacLoadInfo;
    94 
    95 static int TryToLoad(Tcl_Interp *interp, TclMacLoadInfo *loadInfo, Tcl_Obj *pathPtr, 
    96 		     CONST char *sym /* native */);
    97 
    98 
    99 /*
   100  *----------------------------------------------------------------------
   101  *
   102  * TclpDlopen --
   103  *
   104  *	This procedure is called to carry out dynamic loading of binary
   105  *	code for the Macintosh.  This implementation is based on the
   106  *	Code Fragment Manager & will not work on other systems.
   107  *
   108  * Results:
   109  *	The result is TCL_ERROR, and an error message is left in
   110  *	the interp's result.
   111  *
   112  * Side effects:
   113  *	New binary code is loaded.
   114  *
   115  *----------------------------------------------------------------------
   116  */
   117 
   118 int
   119 TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
   120     Tcl_Interp *interp;		/* Used for error reporting. */
   121     Tcl_Obj *pathPtr;		/* Name of the file containing the desired
   122 				 * code (UTF-8). */
   123     Tcl_LoadHandle *loadHandle;	/* Filled with token for dynamically loaded
   124 				 * file which will be passed back to 
   125 				 * (*unloadProcPtr)() to unload the file. */
   126     Tcl_FSUnloadFileProc **unloadProcPtr;
   127 				/* Filled with address of Tcl_FSUnloadFileProc
   128 				 * function which should be used for
   129 				 * this file. */
   130 {
   131     OSErr err;
   132     FSSpec fileSpec;
   133     CONST char *native;
   134     TclMacLoadInfo *loadInfo;
   135     
   136     native = Tcl_FSGetNativePath(pathPtr);
   137     err = FSpLocationFromPath(strlen(native), native, &fileSpec);
   138     
   139     if (err != noErr) {
   140 	Tcl_SetResult(interp, "could not locate shared library", TCL_STATIC);
   141 	return TCL_ERROR;
   142     }
   143     
   144     loadInfo = (TclMacLoadInfo *) ckalloc(sizeof(TclMacLoadInfo));
   145     loadInfo->loaded = 0;
   146     loadInfo->fileSpec = fileSpec;
   147     loadInfo->connID = NULL;
   148     
   149     if (TryToLoad(interp, loadInfo, pathPtr, NULL) != TCL_OK) {
   150 	ckfree((char*) loadInfo);
   151 	return TCL_ERROR;
   152     }
   153 
   154     *loadHandle = (Tcl_LoadHandle)loadInfo;
   155     *unloadProcPtr = &TclpUnloadFile;
   156     return TCL_OK;
   157 }
   158 
   159 /* 
   160  * See the comments about 'struct TclMacLoadInfo' above. This
   161  * function ensures the appropriate library or symbol is
   162  * loaded.
   163  */
   164 static int
   165 TryToLoad(Tcl_Interp *interp, TclMacLoadInfo *loadInfo, Tcl_Obj *pathPtr,
   166 	  CONST char *sym /* native */) 
   167 {
   168     OSErr err;
   169     CFragConnectionID connID;
   170     Ptr dummy;
   171     short fragFileRef, saveFileRef;
   172     Handle fragResource;
   173     UInt32 offset = 0;
   174     UInt32 length = kCFragGoesToEOF;
   175     Str255 errName;
   176     StringPtr fragName=NULL;
   177 
   178     if (loadInfo->loaded == 1) {
   179         return TCL_OK;
   180     }
   181 
   182     /*
   183      * See if this fragment has a 'cfrg' resource.  It will tell us where
   184      * to look for the fragment in the file.  If it doesn't exist we will
   185      * assume we have a ppc frag using the whole data fork.  If it does
   186      * exist we find the frag that matches the one we are looking for and
   187      * get the offset and size from the resource.
   188      */
   189      
   190     saveFileRef = CurResFile();
   191     SetResLoad(false);
   192     fragFileRef = FSpOpenResFile(&loadInfo->fileSpec, fsRdPerm);
   193     SetResLoad(true);
   194     if (fragFileRef != -1) {
   195 	if (sym != NULL) {
   196 	    UseResFile(fragFileRef);
   197 	    fragResource = Get1Resource(kCFragResourceType, kCFragResourceID);
   198 	    HLock(fragResource);
   199 	    if (ResError() == noErr) {
   200 		CfrgItem* srcItem;
   201 		long itemCount, index;
   202 		Ptr itemStart;
   203 
   204 		itemCount = (*(CfrgHeaderPtrHand)fragResource)->itemCount;
   205 		itemStart = &(*(CfrgHeaderPtrHand)fragResource)->arrayStart;
   206 		for (index = 0; index < itemCount;
   207 		     index++, itemStart += srcItem->itemSize) {
   208 		    srcItem = (CfrgItem*)itemStart;
   209 		    if (srcItem->archType != OUR_ARCH_TYPE) continue;
   210 		    if (!strncasecmp(sym, (char *) srcItem->name + 1,
   211 			    strlen(sym))) {
   212 			offset = srcItem->codeOffset;
   213 			length = srcItem->codeLength;
   214 			fragName=srcItem->name;
   215 		    }
   216 		}
   217 	    }
   218 	}
   219 	/*
   220 	 * Close the resource file.  If the extension wants to reopen the
   221 	 * resource fork it should use the tclMacLibrary.c file during it's
   222 	 * construction.
   223 	 */
   224 	HUnlock(fragResource);
   225 	ReleaseResource(fragResource);
   226 	CloseResFile(fragFileRef);
   227 	UseResFile(saveFileRef);
   228 	if (sym == NULL) {
   229 	    /* We just return */
   230 	    return TCL_OK;
   231 	}
   232     }
   233 
   234     /*
   235      * Now we can attempt to load the fragment using the offset & length
   236      * obtained from the resource.  We don't worry about the main entry point
   237      * as we are going to search for specific entry points passed to us.
   238      */
   239     
   240     err = GetDiskFragment(&loadInfo->fileSpec, offset, length, fragName,
   241 	    kLoadCFrag, &connID, &dummy, errName);
   242     
   243     if (err != fragNoErr) {
   244 	p2cstr(errName);
   245 	if(pathPtr) {
   246 	Tcl_AppendResult(interp, "couldn't load file \"", 
   247 			 Tcl_GetString(pathPtr),
   248 			 "\": ", errName, (char *) NULL);
   249 	} else if(sym) {
   250 	Tcl_AppendResult(interp, "couldn't load library \"", 
   251 			 sym,
   252 			 "\": ", errName, (char *) NULL);
   253 	}
   254 	return TCL_ERROR;
   255     }
   256 
   257     loadInfo->connID = connID;
   258     loadInfo->loaded = 1;
   259 
   260     return TCL_OK;
   261 }
   262 
   263 /*
   264  *----------------------------------------------------------------------
   265  *
   266  * TclpFindSymbol --
   267  *
   268  *	Looks up a symbol, by name, through a handle associated with
   269  *	a previously loaded piece of code (shared library).
   270  *
   271  * Results:
   272  *	Returns a pointer to the function associated with 'symbol' if
   273  *	it is found.  Otherwise returns NULL and may leave an error
   274  *	message in the interp's result.
   275  *
   276  *----------------------------------------------------------------------
   277  */
   278 Tcl_PackageInitProc*
   279 TclpFindSymbol(interp, loadHandle, symbol) 
   280     Tcl_Interp *interp;
   281     Tcl_LoadHandle loadHandle;
   282     CONST char *symbol;
   283 {
   284     Tcl_DString ds;
   285     Tcl_PackageInitProc *proc=NULL;
   286     TclMacLoadInfo *loadInfo = (TclMacLoadInfo *)loadHandle;
   287     Str255 symbolName;
   288     CFragSymbolClass symClass;
   289     OSErr err;
   290    
   291     if (loadInfo->loaded == 0) {
   292 	int res;
   293 	/*
   294 	 * First thing we must do is infer the package name from the
   295 	 * sym variable.  We do this by removing the '_Init'.
   296 	 */
   297 	Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
   298 	Tcl_DStringSetLength(&ds, Tcl_DStringLength(&ds) - 5);
   299 	res = TryToLoad(interp, loadInfo, NULL, Tcl_DStringValue(&ds));
   300 	Tcl_DStringFree(&ds);
   301 	if (res != TCL_OK) {
   302 	    return NULL;
   303 	}
   304     }
   305     
   306     Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
   307     strcpy((char *) symbolName + 1, Tcl_DStringValue(&ds));
   308     symbolName[0] = (unsigned) Tcl_DStringLength(&ds);
   309     err = FindSymbol(loadInfo->connID, symbolName, (Ptr *) &proc, &symClass);
   310     Tcl_DStringFree(&ds);
   311     if (err != fragNoErr || symClass == kDataCFragSymbol) {
   312 	Tcl_SetResult(interp,
   313 		"could not find Initialization routine in library",
   314 		TCL_STATIC);
   315 	return NULL;
   316     }
   317     return proc;
   318 }
   319 
   320 /*
   321  *----------------------------------------------------------------------
   322  *
   323  * TclpUnloadFile --
   324  *
   325  *	Unloads a dynamically loaded binary code file from memory.
   326  *	Code pointers in the formerly loaded file are no longer valid
   327  *	after calling this function.
   328  *
   329  * Results:
   330  *	None.
   331  *
   332  * Side effects:
   333  *	Does nothing.  Can anything be done?
   334  *
   335  *----------------------------------------------------------------------
   336  */
   337 
   338 void
   339 TclpUnloadFile(loadHandle)
   340     Tcl_LoadHandle loadHandle;	/* loadHandle returned by a previous call
   341 				 * to TclpDlopen().  The loadHandle is 
   342 				 * a token that represents the loaded 
   343 				 * file. */
   344 {
   345     TclMacLoadInfo *loadInfo = (TclMacLoadInfo *)loadHandle;
   346     if (loadInfo->loaded) {
   347 	CloseConnection((CFragConnectionID*) &(loadInfo->connID));
   348     }
   349     ckfree((char*)loadInfo);
   350 }
   351 
   352 /*
   353  *----------------------------------------------------------------------
   354  *
   355  * TclGuessPackageName --
   356  *
   357  *	If the "load" command is invoked without providing a package
   358  *	name, this procedure is invoked to try to figure it out.
   359  *
   360  * Results:
   361  *	Always returns 0 to indicate that we couldn't figure out a
   362  *	package name;  generic code will then try to guess the package
   363  *	from the file name.  A return value of 1 would have meant that
   364  *	we figured out the package name and put it in bufPtr.
   365  *
   366  * Side effects:
   367  *	None.
   368  *
   369  *----------------------------------------------------------------------
   370  */
   371 
   372 int
   373 TclGuessPackageName(
   374     CONST char *fileName,	/* Name of file containing package (already
   375 				 * translated to local form if needed). */
   376     Tcl_DString *bufPtr)	/* Initialized empty dstring.  Append
   377 				 * package name to this if possible. */
   378 {
   379     return 0;
   380 }