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