tclMacLoad.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:10k
源码类别:

通讯编程

开发平台:

Visual C++

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