1/* 2 * tclLoadMac.c -- 3 * 4 * This procedure provides a version of the dlopen() function for use 5 * on the Macintosh. This procedure will only work with systems 6 * that use the Code Fragment Manager. 7 * 8 * Adapted from tclMacLoad.c in the Tcl 8.0p2 distribution. 9 */ 10 11#include <CodeFragments.h> 12#include <Errors.h> 13#include <Resources.h> 14#include <Strings.h> 15#include <FSpCompat.h> 16 17/* 18 * Seems that the 3.0.1 Universal headers leave this define out. So we 19 * define it here... 20 */ 21 22#ifndef fragNoErr 23# define fragNoErr noErr 24#endif 25 26#include "tcl.h" 27#include "compat:dlfcn.h" 28 29#if GENERATINGPOWERPC 30# define OUR_ARCH_TYPE kPowerPCCFragArch 31#else 32# define OUR_ARCH_TYPE kMotorola68KCFragArch 33#endif 34 35/* 36 * The following data structure defines the structure of a code fragment 37 * resource. We can cast the resource to be of this type to access 38 * any fields we need to see. 39 */ 40struct CfrgHeader { 41 long res1; 42 long res2; 43 long version; 44 long res3; 45 long res4; 46 long filler1; 47 long filler2; 48 long itemCount; 49 char arrayStart; /* Array of externalItems begins here. */ 50}; 51typedef struct CfrgHeader CfrgHeader, *CfrgHeaderPtr, **CfrgHeaderPtrHand; 52 53/* 54 * The below structure defines a cfrag item within the cfrag resource. 55 */ 56struct 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}; 72typedef struct CfrgItem CfrgItem; 73 74/* 75 *---------------------------------------------------------------------- 76 * 77 * dlopen -- 78 * 79 * This function is an implementation of dlopen() for the Mac. 80 * 81 * Results: 82 * Returns the handle of the newly loaded library, or NULL on 83 * failure. 84 * 85 * Side effects: 86 * Loads the specified library into the process. 87 * 88 *---------------------------------------------------------------------- 89 */ 90 91static Str255 errName; 92 93void * 94dlopen(path, mode) 95 const char *path; 96 int mode; 97{ 98 CFragConnectionID connID; 99 Ptr dummy; 100 OSErr err; 101 FSSpec fileSpec; 102 short fragFileRef, saveFileRef; 103 Handle fragResource; 104 UInt32 offset = 0; 105 UInt32 length = kCFragGoesToEOF; 106 char packageName[255]; 107 const char* pkgGuess; 108 char* p; 109 110 /* 111 * First thing we must do is infer the package name from the file 112 * name. This is kind of dumb since the caller actually knows 113 * this value, it just doesn't give it to us. 114 */ 115 116 if ((pkgGuess = strrchr(path,':')) != NULL) { 117 pkgGuess++; 118 } else { 119 pkgGuess = path; 120 } 121 if (!strncmp(pkgGuess,"lib",3)) { 122 pkgGuess+=3; 123 } 124 strcpy(packageName,pkgGuess); 125 p = packageName; 126 if ((*p) && islower(UCHAR(*p++))) { 127 packageName[0] = (char) toupper(UCHAR(packageName[0])); 128 } 129 while (isalpha(UCHAR(*p)) || (*p == '_')) { 130 if (isupper(UCHAR(*p))) { 131 *p = (char) tolower(UCHAR(*p)); 132 } 133 p++; 134 } 135 *p = 0; 136 137 err = FSpLocationFromPath(strlen(path), (char *) path, &fileSpec); 138 if (err != noErr) { 139 strcpy((char *) errName, "file not found"); 140 return (void *) NULL; 141 } 142 143 /* 144 * See if this fragment has a 'cfrg' resource. It will tell us were 145 * to look for the fragment in the file. If it doesn't exist we will 146 * assume we have a ppc frag using the whole data fork. If it does 147 * exist we find the frag that matches the one we are looking for and 148 * get the offset and size from the resource. 149 */ 150 saveFileRef = CurResFile(); 151 SetResLoad(false); 152 fragFileRef = FSpOpenResFile(&fileSpec, fsRdPerm); 153 SetResLoad(true); 154 if (fragFileRef != -1) { 155 UseResFile(fragFileRef); 156 fragResource = Get1Resource(kCFragResourceType, kCFragResourceID); 157 HLock(fragResource); 158 if (ResError() == noErr) { 159 CfrgItem* srcItem; 160 long itemCount, index; 161 Ptr itemStart; 162 163 itemCount = (*(CfrgHeaderPtrHand)fragResource)->itemCount; 164 itemStart = &(*(CfrgHeaderPtrHand)fragResource)->arrayStart; 165 for (index = 0; index < itemCount; 166 index++, itemStart += srcItem->itemSize) { 167 srcItem = (CfrgItem*)itemStart; 168 if (srcItem->archType != OUR_ARCH_TYPE) continue; 169 if (!strncasecmp(packageName, (char *) srcItem->name + 1, 170 srcItem->name[0])) { 171 offset = srcItem->codeOffset; 172 length = srcItem->codeLength; 173 } 174 } 175 } 176 /* 177 * Close the resource file. If the extension wants to reopen the 178 * resource fork it should use the tclMacLibrary.c file during it's 179 * construction. 180 */ 181 HUnlock(fragResource); 182 ReleaseResource(fragResource); 183 CloseResFile(fragFileRef); 184 UseResFile(saveFileRef); 185 } 186 187 /* 188 * Now we can attempt to load the fragement using the offset & length 189 * obtained from the resource. We don't worry about the main entry point 190 * as we are going to search for specific entry points passed to us. 191 */ 192 193 c2pstr(packageName); 194 err = GetDiskFragment(&fileSpec, offset, length, (StringPtr) packageName, 195 kLoadCFrag, &connID, &dummy, errName); 196 if (err != fragNoErr) { 197 p2cstr(errName); 198 return (void *) NULL; 199 } 200 return (void *) connID; 201} 202 203/* 204 *---------------------------------------------------------------------- 205 * 206 * dlsym -- 207 * 208 * This function is an alternative for the system function 209 * GetProcAddress. It returns the address of a 210 * symbol, give the handle returned by dlopen(). 211 * 212 * Results: 213 * Returns the address of the symbol in the dll. 214 * 215 * Side effects: 216 * None. 217 * 218 *---------------------------------------------------------------------- 219 */ 220 221void * 222dlsym(handle, symbol) 223 void *handle; 224 const char *symbol; 225{ 226 void *procPtr; 227 char sym1[255]; 228 OSErr err; 229 SymClass symClass; 230 231 strcpy(sym1, symbol); 232 c2pstr(sym1); 233 234 err = FindSymbol((ConnectionID) handle, (StringPtr) sym1, 235 (Ptr *) &procPtr, &symClass); 236 if (err != fragNoErr || symClass == kDataCFragSymbol) { 237 procPtr = (void *) NULL; 238 } 239 return procPtr; 240} 241 242/* 243 *---------------------------------------------------------------------- 244 * 245 * dlerror -- 246 * 247 * This function returns a string describing the error which 248 * occurred in dlopen(). 249 * 250 * Results: 251 * Returns an error message. 252 * 253 * Side effects: 254 * None. 255 * 256 *---------------------------------------------------------------------- 257 */ 258 259char * 260dlerror() 261{ 262 return (char *) errName; 263} 264 265 266/* 267 *---------------------------------------------------------------------- 268 * 269 * dlclose -- 270 * 271 * Not implemented yet. 272 * 273 * Results: 274 * Always returns 0 (= O.K.) 275 * 276 * Side effects: 277 * None 278 * 279 *---------------------------------------------------------------------- 280 */ 281 282int 283dlclose(handle) 284 void *handle; 285{ 286 return 0; 287} 288 289