- no limits to external semaphore table
[cogvm:blessed.git] / platforms / iOS / vm / OSX / sqMacUnixExternalPrims.m
1
2 //  Created by John M McIntosh on 09-11-27.
3 //  This file orginally comes from the sqUnixExternalPrims.c written by Ian Piumarta
4 //  With additional work for the 3.x and 4.x series of macintosh carbon vms
5 //  To preserve the behavior, bugs, etc I decided to copy the code versus a new re-write
6
7 /* sqUnixExternalPrims.c -- Unix named primitives and loadable modules
8  * 
9  *   Copyright (C) 1996-2009 by Ian Piumarta
10  *   All rights reserved.
11  *   
12  *   This file is part of Unix Squeak.
13  * 
14  *   Permission is hereby granted, free of charge, to any person obtaining a copy
15  *   of this software and associated documentation files (the "Software"), to deal
16  *   in the Software without restriction, including without limitation the rights
17  *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18  *   copies of the Software, and to permit persons to whom the Software is
19  *   furnished to do so, subject to the following conditions:
20  * 
21  *   The above copyright notice and this permission notice shall be included in
22  *   all copies or substantial portions of the Software.
23  * 
24  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27  *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29  *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  *   SOFTWARE.
31  */
32
33  /* Author: Ian.Piumarta@INRIA.Fr
34  *
35  * Last edited: 2005-04-06 06:09:36 by piumarta on pauillac.hpl.hp.com
36         
37  * Altered by John M McIntosh johnmci@smalltalkconsulting.com Feb 24th, 2006 for os-x carbon support
38  3.8.11b2 load from resource location first, avoid plugins external directory because of intel migration effort issues.
39  3.8.17b1 April 25, 2007, JMM rework for 10.2.8 backwards support using Ian's dl* logic. 
40  5.0.0b6  Nov 27, 2009, JMM rework for the 32/64bit 5.0 VM
41   
42  */
43 #import "sqSqueakOSXInfoPlistInterface.h"
44 #import "SqueakOSXAppDelegate.h"
45 #import "sq.h"
46
47 extern SqueakOSXAppDelegate *gDelegateApp;
48
49 # define dprintf(ARGS) if (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakDebug) fprintf ARGS
50  
51 #if defined(HAVE_LIBDL) /* non-starter without this! */
52
53 #include <dlfcn.h> 
54 #include <sys/param.h>
55 #include <sys/stat.h>
56
57 /* get a value for RTLD_NOW, with increasing levels of desperation... */
58
59 #if !defined(RTLD_NOW)
60 # if defined(DL_NOW)
61 #   define RTLD_NOW DL_NOW
62 # elif defined(RTLD_LAZY)
63 #   define RTLD_NOW RTLD_LAZY
64 # elif defined(DL_LAZY)
65 #   define RTLD_NOW DL_LAZY
66 # else
67 #   warning: defining RTLD_NOW as 1
68 #   define RTLD_NOW 1
69 # endif
70 #endif
71
72 #if !defined(RTLD_GLOBAL)
73 # define RTLD_GLOBAL 0
74 #endif
75
76 #endif
77
78
79 /*** local functions ***/
80 void *ioLoadModuleRaw(char *pluginName);
81
82 /*  Attempt to load the shared library named by the concatenation of prefix,
83  *  moduleName and suffix.  Answer the new module entry, or 0 if the shared
84  *  library could not be loaded.
85  */
86 static void *tryLoadingInternals(NSString *libNameString) {     
87         struct stat buf;
88         int         err;
89         void        *handle = NULL;
90         const char* libName = [libNameString fileSystemRepresentation];
91         
92         if ((!(err= stat(libName, &buf))) && S_ISDIR(buf.st_mode)) {
93                 dprintf((stderr, "ignoring directory: %s\n", libName));
94         } else {
95             dprintf((stderr, "tryLoading %s\n", libName));
96                 handle= dlopen(libName, RTLD_NOW | RTLD_GLOBAL);
97             if (handle == NULL) {
98                         const char* why = dlerror();
99                         if ((!err) && (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakDebug))
100                                 fprintf(stderr, "ioLoadModule(%s):\n  %s\n", libName, why);
101                 } else {
102                     return handle;
103                 }
104         }
105         return NULL;
106 }
107
108 static void *tryLoading(NSString *dirNameString, char *moduleName)
109 {
110         void        *handle= NULL;
111         NSString    *libName;
112         
113         libName = [dirNameString stringByAppendingPathComponent: [NSString stringWithUTF8String: moduleName]];
114         libName = [libName stringByAppendingPathExtension: @"bundle/Contents/MacOS/"];
115         libName = [libName stringByAppendingPathComponent: [NSString stringWithUTF8String: moduleName]];
116         handle = tryLoadingInternals(libName);
117         if (handle) 
118                 return handle;
119         
120         libName = [dirNameString stringByAppendingPathComponent: [NSString stringWithUTF8String: moduleName]];
121         handle = tryLoadingInternals(libName);
122         if (handle) 
123                 return handle;
124         
125         if (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakPluginsBuiltInOrLocalOnly)
126                 return NULL;
127         
128         static char *prefixes[]= { "", "lib", 0 };
129         static char *suffixes[]= { "", "so", "dylib",0 };
130         char         **prefix= NULL, **suffix= NULL;
131
132         for (prefix= prefixes;  *prefix;  ++prefix)
133                 for (suffix= suffixes;  *suffix;  ++suffix)             {
134                         libName = [dirNameString stringByAppendingPathComponent: [NSString stringWithUTF8String: *prefix]];
135                         libName = [libName stringByAppendingString: [NSString stringWithUTF8String: moduleName]];
136                         libName = [libName stringByAppendingPathExtension: [NSString stringWithUTF8String: *suffix]];
137
138                         handle = tryLoadingInternals(libName);
139                         if (handle) 
140                                 return handle;
141                 }
142         return NULL;
143 }
144
145
146 /*  Find and load the named module.  Answer 0 if not found (do NOT fail
147  *  the primitive!).
148  */
149 void *ioLoadModule(char *pluginName) {
150         NSAutoreleasePool * pool = [NSAutoreleasePool new];
151         void* result = ioLoadModuleRaw(pluginName);
152         [pool drain];
153         return result;
154 }
155         
156 void *ioLoadModuleRaw(char *pluginName)
157 {
158         void *handle= null;
159
160         if ((pluginName == null) || (pluginName[0] == 0x00)) {
161                 handle = dlopen(0, RTLD_NOW | RTLD_GLOBAL);
162                 if (handle == null) {
163                         char * why = dlerror();
164                         dprintf((stderr, "ioLoadModule(<intrinsic>): %s\n", why));
165                 } else {
166                         dprintf((stderr, "loaded: <intrinsic>\n"));
167                         return handle;
168                 }
169     }
170         
171         /* first, look in the "<Squeak VM directory>Plugins" directory for the library */
172         NSString *pluginDirPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent: @"Contents/Plugins"];
173         // [[gDelegateApp.squeakApplication.vmPathStringURL path] stringByAppendingPathComponent: @"Plugins/"];
174         NSString *vmDirPath = [[NSBundle mainBundle] resourcePath];
175
176         if (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakPluginsBuiltInOrLocalOnly) {
177           if ( (handle= tryLoading( vmDirPath, pluginName)) || (handle= tryLoading( pluginDirPath,      pluginName)))
178                         return handle;
179     } else {
180                   if ((   handle= tryLoading( pluginDirPath,    pluginName))
181                           || (handle= tryLoading( @"./",                        pluginName))
182                           || (handle= tryLoading( vmDirPath,            pluginName))
183                           || (handle= tryLoading( @"",                          pluginName))
184                           )
185                         return handle;
186         }
187
188         // the following is needed so that, for example, the FFI can pick up
189         // things like <cdecl: 'xyz' module: 'CoreServices'>
190         {
191                 static char *frameworks[]=
192                 {
193                         "",
194                         "/CoreServices.framework/Frameworks",
195                         "/ApplicationServices.framework/Frameworks",
196                         "/Carbon.framework/Frameworks",
197                         0
198                 };
199                 
200                 static NSString *systemFolder = NULL;
201                 char **framework= NULL;
202                 char workingData[PATH_MAX+1];
203                 size_t pluginNameLength;
204                 NSString *path,*path2;
205                 
206                 if (!systemFolder) {
207                         struct FSRef frameworksFolderRef;
208                         OSErr err = FSFindFolder(kSystemDomain, kFrameworksFolderType, false, &frameworksFolderRef);
209 #pragma unused(err)
210                         NSURL *myURLRef = (NSURL *) CFURLCreateFromFSRef(kCFAllocatorDefault, &frameworksFolderRef);
211                         systemFolder = [[myURLRef path] retain];
212                         CFRelease(myURLRef);
213                 }
214                 
215                 pluginNameLength = strlen(pluginName);
216                 if (pluginNameLength > 10) {
217                         strncpy(workingData,pluginName+pluginNameLength-10,10);
218                         workingData[10] = 0x00;
219                         if (strcmp(workingData,".framework") == 0) {
220                                 strncpy(workingData,pluginName,pluginNameLength-10);
221                                 workingData[pluginNameLength-10] = 0x00;
222                                 path = [vmDirPath stringByAppendingPathComponent: [NSString stringWithUTF8String: pluginName]];
223                                 if (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakPluginsBuiltInOrLocalOnly) {
224                                         path2 = [path stringByAppendingPathComponent: [NSString stringWithUTF8String: workingData]];
225                                         if ((handle = tryLoadingInternals(path2)))
226                                                 return handle;
227                                 } else {
228                                         if ((handle= tryLoading(path, workingData)))
229                                                 return handle;
230                                 }
231                                 path = [pluginDirPath stringByAppendingPathComponent: [NSString stringWithUTF8String: pluginName]];
232
233                                 if (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakPluginsBuiltInOrLocalOnly) {
234                                         path2 = [path stringByAppendingPathComponent: [NSString stringWithUTF8String: workingData]];
235                                         if ((handle = tryLoadingInternals(path2)))
236                                                 return handle;
237                                 } else {
238                                         if ((handle= tryLoading(path, workingData)))
239                                                 return handle;
240                                 }
241
242                                 path = [systemFolder stringByAppendingPathComponent: [NSString stringWithUTF8String: pluginName]];
243                                 if (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakPluginsBuiltInOrLocalOnly) {
244                                         path2 = [path stringByAppendingPathComponent: [NSString stringWithUTF8String: workingData]];
245                                         if ((handle = tryLoadingInternals(path2)))
246                                                 return handle;
247                                 } else {
248                                         if ((handle= tryLoading(path, workingData)))
249                                                 return handle;
250                                 }
251                         }
252                 }
253                 
254                 if (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakPluginsBuiltInOrLocalOnly)
255                         return NULL;
256                 
257                 for (framework= frameworks;  *framework;  ++framework) {
258                         path = [[systemFolder stringByAppendingPathComponent: [NSString stringWithUTF8String: *framework]]
259                                         stringByAppendingPathComponent: [NSString stringWithUTF8String: pluginName]];
260                         if ((handle= tryLoading(path, pluginName)))
261                                 return handle;
262                         
263                         path = [systemFolder stringByAppendingPathComponent: [NSString stringWithUTF8String: *framework]];
264                         path = [path stringByAppendingPathComponent: [NSString stringWithUTF8String: pluginName]];
265                         path = [path stringByAppendingPathExtension: @"framework"];
266                         
267                         if ((handle= tryLoading(path, pluginName)))
268                                 return handle;
269                 }
270         }
271         
272         return NULL;
273 }
274
275
276 /*  Find a function in a loaded module.  Answer 0 if not found (do NOT
277  *  fail the primitive!).
278  */
279 void *ioFindExternalFunctionIn(char *lookupName, void *moduleHandle)
280 {
281   char buf[NAME_MAX+1];
282  
283   snprintf(buf, sizeof(buf), "%s", lookupName);
284   void *fn = dlsym(moduleHandle, buf);
285
286   dprintf((stderr, "ioFindExternalFunctionIn(%s, %ld)\n",lookupName, (long) moduleHandle));
287
288   if ((fn == NULL) && (((sqSqueakOSXInfoPlistInterface*) gDelegateApp.squeakApplication.infoPlistInterfaceLogic).SqueakDebug)
289       && strcmp(lookupName, "initialiseModule")
290       && strcmp(lookupName, "shutdownModule")
291       && strcmp(lookupName, "setInterpreter")
292       && strcmp(lookupName, "getModuleName")) {
293         char *why = dlerror();
294     fprintf(stderr, "ioFindExternalFunctionIn(%s, %p):\n  %s\n",lookupName, moduleHandle, why);
295         }
296
297   return fn;
298 }
299
300 /*  Free the module with the associated handle.  Answer 0 on error (do
301  *  NOT fail the primitive!).
302 */
303 sqInt ioFreeModule(void *moduleHandle)
304 {
305   int results = dlclose(moduleHandle);
306         
307   if (results) {
308           char* why = dlerror();
309       dprintf((stderr, "ioFreeModule(%ld): %s\n", (long) moduleHandle, why));
310       return 0;
311     }
312   return 1;
313 }