os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacLoad.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacLoad.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,380 @@
     1.4 +/*
     1.5 + * tclMacLoad.c --
     1.6 + *
     1.7 + *	This procedure provides a version of the TclLoadFile for use
     1.8 + *	on the Macintosh.  This procedure will only work with systems 
     1.9 + *	that use the Code Fragment Manager.
    1.10 + *
    1.11 + * Copyright (c) 1995-1997 Sun Microsystems, Inc.
    1.12 + *
    1.13 + * See the file "license.terms" for information on usage and redistribution
    1.14 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    1.15 + *
    1.16 + * RCS: @(#) $Id: tclMacLoad.c,v 1.16 2002/10/09 11:54:26 das Exp $
    1.17 + */
    1.18 +
    1.19 +#include <CodeFragments.h>
    1.20 +#include <Errors.h>
    1.21 +#include <Resources.h>
    1.22 +#include <Strings.h>
    1.23 +#include <FSpCompat.h>
    1.24 +
    1.25 +/*
    1.26 + * Seems that the 3.0.1 Universal headers leave this define out.  So we
    1.27 + * define it here...
    1.28 + */
    1.29 + 
    1.30 +#ifndef fragNoErr
    1.31 +    #define fragNoErr noErr
    1.32 +#endif
    1.33 +
    1.34 +#include "tclPort.h"
    1.35 +#include "tclInt.h"
    1.36 +#include "tclMacInt.h"
    1.37 +
    1.38 +#if GENERATINGPOWERPC
    1.39 +    #define OUR_ARCH_TYPE kPowerPCCFragArch
    1.40 +#else
    1.41 +    #define OUR_ARCH_TYPE kMotorola68KCFragArch
    1.42 +#endif
    1.43 +
    1.44 +/*
    1.45 + * The following data structure defines the structure of a code fragment
    1.46 + * resource.  We can cast the resource to be of this type to access
    1.47 + * any fields we need to see.
    1.48 + */
    1.49 +struct CfrgHeader {
    1.50 +    long 	res1;
    1.51 +    long 	res2;
    1.52 +    long 	version;
    1.53 +    long 	res3;
    1.54 +    long 	res4;
    1.55 +    long 	filler1;
    1.56 +    long 	filler2;
    1.57 +    long 	itemCount;
    1.58 +    char	arrayStart;	/* Array of externalItems begins here. */
    1.59 +};
    1.60 +typedef struct CfrgHeader CfrgHeader, *CfrgHeaderPtr, **CfrgHeaderPtrHand;
    1.61 +
    1.62 +/*
    1.63 + * The below structure defines a cfrag item within the cfrag resource.
    1.64 + */
    1.65 +struct CfrgItem {
    1.66 +    OSType 	archType;
    1.67 +    long 	updateLevel;
    1.68 +    long	currVersion;
    1.69 +    long	oldDefVersion;
    1.70 +    long	appStackSize;
    1.71 +    short	appSubFolder;
    1.72 +    char	usage;
    1.73 +    char	location;
    1.74 +    long	codeOffset;
    1.75 +    long	codeLength;
    1.76 +    long	res1;
    1.77 +    long	res2;
    1.78 +    short	itemSize;
    1.79 +    Str255	name;		/* This is actually variable sized. */
    1.80 +};
    1.81 +typedef struct CfrgItem CfrgItem;
    1.82 +
    1.83 +/*
    1.84 + * On MacOS, old shared libraries which contain many code fragments
    1.85 + * cannot, it seems, be loaded in one go.  We need to look provide
    1.86 + * the name of a code fragment while we load.  Since with the
    1.87 + * separation of the 'load' and 'findsymbol' be do not necessarily
    1.88 + * know a symbol name at load time, we have to store some further
    1.89 + * information in a structure like this so we can ensure we load
    1.90 + * properly in 'findsymbol' if the first attempts didn't work.
    1.91 + */
    1.92 +typedef struct TclMacLoadInfo {
    1.93 +    int loaded;
    1.94 +    CFragConnectionID connID;
    1.95 +    FSSpec fileSpec;
    1.96 +} TclMacLoadInfo;
    1.97 +
    1.98 +static int TryToLoad(Tcl_Interp *interp, TclMacLoadInfo *loadInfo, Tcl_Obj *pathPtr, 
    1.99 +		     CONST char *sym /* native */);
   1.100 +
   1.101 +
   1.102 +/*
   1.103 + *----------------------------------------------------------------------
   1.104 + *
   1.105 + * TclpDlopen --
   1.106 + *
   1.107 + *	This procedure is called to carry out dynamic loading of binary
   1.108 + *	code for the Macintosh.  This implementation is based on the
   1.109 + *	Code Fragment Manager & will not work on other systems.
   1.110 + *
   1.111 + * Results:
   1.112 + *	The result is TCL_ERROR, and an error message is left in
   1.113 + *	the interp's result.
   1.114 + *
   1.115 + * Side effects:
   1.116 + *	New binary code is loaded.
   1.117 + *
   1.118 + *----------------------------------------------------------------------
   1.119 + */
   1.120 +
   1.121 +int
   1.122 +TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
   1.123 +    Tcl_Interp *interp;		/* Used for error reporting. */
   1.124 +    Tcl_Obj *pathPtr;		/* Name of the file containing the desired
   1.125 +				 * code (UTF-8). */
   1.126 +    Tcl_LoadHandle *loadHandle;	/* Filled with token for dynamically loaded
   1.127 +				 * file which will be passed back to 
   1.128 +				 * (*unloadProcPtr)() to unload the file. */
   1.129 +    Tcl_FSUnloadFileProc **unloadProcPtr;
   1.130 +				/* Filled with address of Tcl_FSUnloadFileProc
   1.131 +				 * function which should be used for
   1.132 +				 * this file. */
   1.133 +{
   1.134 +    OSErr err;
   1.135 +    FSSpec fileSpec;
   1.136 +    CONST char *native;
   1.137 +    TclMacLoadInfo *loadInfo;
   1.138 +    
   1.139 +    native = Tcl_FSGetNativePath(pathPtr);
   1.140 +    err = FSpLocationFromPath(strlen(native), native, &fileSpec);
   1.141 +    
   1.142 +    if (err != noErr) {
   1.143 +	Tcl_SetResult(interp, "could not locate shared library", TCL_STATIC);
   1.144 +	return TCL_ERROR;
   1.145 +    }
   1.146 +    
   1.147 +    loadInfo = (TclMacLoadInfo *) ckalloc(sizeof(TclMacLoadInfo));
   1.148 +    loadInfo->loaded = 0;
   1.149 +    loadInfo->fileSpec = fileSpec;
   1.150 +    loadInfo->connID = NULL;
   1.151 +    
   1.152 +    if (TryToLoad(interp, loadInfo, pathPtr, NULL) != TCL_OK) {
   1.153 +	ckfree((char*) loadInfo);
   1.154 +	return TCL_ERROR;
   1.155 +    }
   1.156 +
   1.157 +    *loadHandle = (Tcl_LoadHandle)loadInfo;
   1.158 +    *unloadProcPtr = &TclpUnloadFile;
   1.159 +    return TCL_OK;
   1.160 +}
   1.161 +
   1.162 +/* 
   1.163 + * See the comments about 'struct TclMacLoadInfo' above. This
   1.164 + * function ensures the appropriate library or symbol is
   1.165 + * loaded.
   1.166 + */
   1.167 +static int
   1.168 +TryToLoad(Tcl_Interp *interp, TclMacLoadInfo *loadInfo, Tcl_Obj *pathPtr,
   1.169 +	  CONST char *sym /* native */) 
   1.170 +{
   1.171 +    OSErr err;
   1.172 +    CFragConnectionID connID;
   1.173 +    Ptr dummy;
   1.174 +    short fragFileRef, saveFileRef;
   1.175 +    Handle fragResource;
   1.176 +    UInt32 offset = 0;
   1.177 +    UInt32 length = kCFragGoesToEOF;
   1.178 +    Str255 errName;
   1.179 +    StringPtr fragName=NULL;
   1.180 +
   1.181 +    if (loadInfo->loaded == 1) {
   1.182 +        return TCL_OK;
   1.183 +    }
   1.184 +
   1.185 +    /*
   1.186 +     * See if this fragment has a 'cfrg' resource.  It will tell us where
   1.187 +     * to look for the fragment in the file.  If it doesn't exist we will
   1.188 +     * assume we have a ppc frag using the whole data fork.  If it does
   1.189 +     * exist we find the frag that matches the one we are looking for and
   1.190 +     * get the offset and size from the resource.
   1.191 +     */
   1.192 +     
   1.193 +    saveFileRef = CurResFile();
   1.194 +    SetResLoad(false);
   1.195 +    fragFileRef = FSpOpenResFile(&loadInfo->fileSpec, fsRdPerm);
   1.196 +    SetResLoad(true);
   1.197 +    if (fragFileRef != -1) {
   1.198 +	if (sym != NULL) {
   1.199 +	    UseResFile(fragFileRef);
   1.200 +	    fragResource = Get1Resource(kCFragResourceType, kCFragResourceID);
   1.201 +	    HLock(fragResource);
   1.202 +	    if (ResError() == noErr) {
   1.203 +		CfrgItem* srcItem;
   1.204 +		long itemCount, index;
   1.205 +		Ptr itemStart;
   1.206 +
   1.207 +		itemCount = (*(CfrgHeaderPtrHand)fragResource)->itemCount;
   1.208 +		itemStart = &(*(CfrgHeaderPtrHand)fragResource)->arrayStart;
   1.209 +		for (index = 0; index < itemCount;
   1.210 +		     index++, itemStart += srcItem->itemSize) {
   1.211 +		    srcItem = (CfrgItem*)itemStart;
   1.212 +		    if (srcItem->archType != OUR_ARCH_TYPE) continue;
   1.213 +		    if (!strncasecmp(sym, (char *) srcItem->name + 1,
   1.214 +			    strlen(sym))) {
   1.215 +			offset = srcItem->codeOffset;
   1.216 +			length = srcItem->codeLength;
   1.217 +			fragName=srcItem->name;
   1.218 +		    }
   1.219 +		}
   1.220 +	    }
   1.221 +	}
   1.222 +	/*
   1.223 +	 * Close the resource file.  If the extension wants to reopen the
   1.224 +	 * resource fork it should use the tclMacLibrary.c file during it's
   1.225 +	 * construction.
   1.226 +	 */
   1.227 +	HUnlock(fragResource);
   1.228 +	ReleaseResource(fragResource);
   1.229 +	CloseResFile(fragFileRef);
   1.230 +	UseResFile(saveFileRef);
   1.231 +	if (sym == NULL) {
   1.232 +	    /* We just return */
   1.233 +	    return TCL_OK;
   1.234 +	}
   1.235 +    }
   1.236 +
   1.237 +    /*
   1.238 +     * Now we can attempt to load the fragment using the offset & length
   1.239 +     * obtained from the resource.  We don't worry about the main entry point
   1.240 +     * as we are going to search for specific entry points passed to us.
   1.241 +     */
   1.242 +    
   1.243 +    err = GetDiskFragment(&loadInfo->fileSpec, offset, length, fragName,
   1.244 +	    kLoadCFrag, &connID, &dummy, errName);
   1.245 +    
   1.246 +    if (err != fragNoErr) {
   1.247 +	p2cstr(errName);
   1.248 +	if(pathPtr) {
   1.249 +	Tcl_AppendResult(interp, "couldn't load file \"", 
   1.250 +			 Tcl_GetString(pathPtr),
   1.251 +			 "\": ", errName, (char *) NULL);
   1.252 +	} else if(sym) {
   1.253 +	Tcl_AppendResult(interp, "couldn't load library \"", 
   1.254 +			 sym,
   1.255 +			 "\": ", errName, (char *) NULL);
   1.256 +	}
   1.257 +	return TCL_ERROR;
   1.258 +    }
   1.259 +
   1.260 +    loadInfo->connID = connID;
   1.261 +    loadInfo->loaded = 1;
   1.262 +
   1.263 +    return TCL_OK;
   1.264 +}
   1.265 +
   1.266 +/*
   1.267 + *----------------------------------------------------------------------
   1.268 + *
   1.269 + * TclpFindSymbol --
   1.270 + *
   1.271 + *	Looks up a symbol, by name, through a handle associated with
   1.272 + *	a previously loaded piece of code (shared library).
   1.273 + *
   1.274 + * Results:
   1.275 + *	Returns a pointer to the function associated with 'symbol' if
   1.276 + *	it is found.  Otherwise returns NULL and may leave an error
   1.277 + *	message in the interp's result.
   1.278 + *
   1.279 + *----------------------------------------------------------------------
   1.280 + */
   1.281 +Tcl_PackageInitProc*
   1.282 +TclpFindSymbol(interp, loadHandle, symbol) 
   1.283 +    Tcl_Interp *interp;
   1.284 +    Tcl_LoadHandle loadHandle;
   1.285 +    CONST char *symbol;
   1.286 +{
   1.287 +    Tcl_DString ds;
   1.288 +    Tcl_PackageInitProc *proc=NULL;
   1.289 +    TclMacLoadInfo *loadInfo = (TclMacLoadInfo *)loadHandle;
   1.290 +    Str255 symbolName;
   1.291 +    CFragSymbolClass symClass;
   1.292 +    OSErr err;
   1.293 +   
   1.294 +    if (loadInfo->loaded == 0) {
   1.295 +	int res;
   1.296 +	/*
   1.297 +	 * First thing we must do is infer the package name from the
   1.298 +	 * sym variable.  We do this by removing the '_Init'.
   1.299 +	 */
   1.300 +	Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
   1.301 +	Tcl_DStringSetLength(&ds, Tcl_DStringLength(&ds) - 5);
   1.302 +	res = TryToLoad(interp, loadInfo, NULL, Tcl_DStringValue(&ds));
   1.303 +	Tcl_DStringFree(&ds);
   1.304 +	if (res != TCL_OK) {
   1.305 +	    return NULL;
   1.306 +	}
   1.307 +    }
   1.308 +    
   1.309 +    Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
   1.310 +    strcpy((char *) symbolName + 1, Tcl_DStringValue(&ds));
   1.311 +    symbolName[0] = (unsigned) Tcl_DStringLength(&ds);
   1.312 +    err = FindSymbol(loadInfo->connID, symbolName, (Ptr *) &proc, &symClass);
   1.313 +    Tcl_DStringFree(&ds);
   1.314 +    if (err != fragNoErr || symClass == kDataCFragSymbol) {
   1.315 +	Tcl_SetResult(interp,
   1.316 +		"could not find Initialization routine in library",
   1.317 +		TCL_STATIC);
   1.318 +	return NULL;
   1.319 +    }
   1.320 +    return proc;
   1.321 +}
   1.322 +
   1.323 +/*
   1.324 + *----------------------------------------------------------------------
   1.325 + *
   1.326 + * TclpUnloadFile --
   1.327 + *
   1.328 + *	Unloads a dynamically loaded binary code file from memory.
   1.329 + *	Code pointers in the formerly loaded file are no longer valid
   1.330 + *	after calling this function.
   1.331 + *
   1.332 + * Results:
   1.333 + *	None.
   1.334 + *
   1.335 + * Side effects:
   1.336 + *	Does nothing.  Can anything be done?
   1.337 + *
   1.338 + *----------------------------------------------------------------------
   1.339 + */
   1.340 +
   1.341 +void
   1.342 +TclpUnloadFile(loadHandle)
   1.343 +    Tcl_LoadHandle loadHandle;	/* loadHandle returned by a previous call
   1.344 +				 * to TclpDlopen().  The loadHandle is 
   1.345 +				 * a token that represents the loaded 
   1.346 +				 * file. */
   1.347 +{
   1.348 +    TclMacLoadInfo *loadInfo = (TclMacLoadInfo *)loadHandle;
   1.349 +    if (loadInfo->loaded) {
   1.350 +	CloseConnection((CFragConnectionID*) &(loadInfo->connID));
   1.351 +    }
   1.352 +    ckfree((char*)loadInfo);
   1.353 +}
   1.354 +
   1.355 +/*
   1.356 + *----------------------------------------------------------------------
   1.357 + *
   1.358 + * TclGuessPackageName --
   1.359 + *
   1.360 + *	If the "load" command is invoked without providing a package
   1.361 + *	name, this procedure is invoked to try to figure it out.
   1.362 + *
   1.363 + * Results:
   1.364 + *	Always returns 0 to indicate that we couldn't figure out a
   1.365 + *	package name;  generic code will then try to guess the package
   1.366 + *	from the file name.  A return value of 1 would have meant that
   1.367 + *	we figured out the package name and put it in bufPtr.
   1.368 + *
   1.369 + * Side effects:
   1.370 + *	None.
   1.371 + *
   1.372 + *----------------------------------------------------------------------
   1.373 + */
   1.374 +
   1.375 +int
   1.376 +TclGuessPackageName(
   1.377 +    CONST char *fileName,	/* Name of file containing package (already
   1.378 +				 * translated to local form if needed). */
   1.379 +    Tcl_DString *bufPtr)	/* Initialized empty dstring.  Append
   1.380 +				 * package name to this if possible. */
   1.381 +{
   1.382 +    return 0;
   1.383 +}