instance.c: Proper fix for localizing shared libraries on FreeBSD 9
[sdk] / ecere / src / com / instance.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <ctype.h>
5 #include <string.h>
6
7 #if defined(__GNUC__) || defined(__WATCOMC__) || defined(__WIN32__)
8 #include <time.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #endif
13
14 #if defined(__unix__) || defined(__APPLE__)
15 #define bool _bool
16 #include <utime.h>
17 #include <dlfcn.h>
18 #undef bool
19 #endif
20
21 #if defined(__WIN32__)
22 #define WIN32_LEAN_AND_MEAN
23 #define UNICODE
24 #include <windows.h>
25 #include <io.h>
26
27 #else
28 #include <unistd.h>
29 #endif
30
31 typedef int bool;
32 typedef unsigned char byte;
33 typedef unsigned short uint16;
34 typedef unsigned int uint;
35 typedef unsigned int FileSize;
36 typedef unsigned long long uint64;
37
38 #define false 0
39 #define true 1
40
41 #define null ((void *)0)
42
43 #define MAX_LOCATION 797
44 #define MAX_FILENAME 274
45 #define MAX_EXTENSION 17
46
47 FILE *eC_stdin(void)  { return stdin; }
48 FILE *eC_stdout(void) { return stdout; }
49 FILE *eC_stderr(void) { return stderr; }
50
51 void __ecereNameSpace__ecere__com__eSystem_Delete(void * memory);
52 void * __ecereNameSpace__ecere__com__eSystem_New0(unsigned int size);
53 void * __ecereNameSpace__ecere__com__eSystem_Renew(void * memory, unsigned int size);
54 void * __ecereNameSpace__ecere__com__eSystem_Renew0(void * memory, unsigned int size);
55 unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16(char * source, int * wordCount);
56 unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer(char * source, uint16 * dest, int max);
57 char * __ecereNameSpace__ecere__sys__UTF16toUTF8(uint16 * source);
58 char * __ecereNameSpace__ecere__sys__UTF16toUTF8Buffer(uint16 * source, byte * dest, int max);
59
60 #define eSystem_Delete     __ecereNameSpace__ecere__com__eSystem_Delete
61 #define eSystem_New0       __ecereNameSpace__ecere__com__eSystem_New0
62 #define eSystem_Renew      __ecereNameSpace__ecere__com__eSystem_Renew
63 #define eSystem_Renew0     __ecereNameSpace__ecere__com__eSystem_Renew0
64 #define UTF8toUTF16        __ecereNameSpace__ecere__sys__UTF8toUTF16
65 #define UTF8toUTF16Buffer  __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer
66 #define UTF16toUTF8        __ecereNameSpace__ecere__sys__UTF16toUTF8
67 #define UTF16toUTF8Buffer  __ecereNameSpace__ecere__sys__UTF16toUTF8Buffer
68
69 #if defined(__unix__)
70 static char exeLocation[MAX_LOCATION];
71 #endif
72
73 int __ecereNameSpace__ecere__sys__Tokenize(char * string, int maxTokens, char* tokens[], bool escapeBackSlashes);
74 char * __ecereNameSpace__ecere__sys__RSearchString(char * buffer, char * subStr, int maxLen, bool matchCase, bool matchWord);
75 char * __ecereNameSpace__ecere__sys__GetLastDirectory(char * string, char * output);
76 char * __ecereNameSpace__ecere__sys__PathCat(char * string, char * addedPath);
77 char * __ecereNameSpace__ecere__sys__GetExtension(char * string, char * output);
78
79 #define Tokenize           __ecereNameSpace__ecere__sys__Tokenize
80 #define RSearchString      __ecereNameSpace__ecere__sys__RSearchString
81 #define GetLastDirectory   __ecereNameSpace__ecere__sys__GetLastDirectory
82 #define PathCat            __ecereNameSpace__ecere__sys__PathCat
83 #define GetExtension       __ecereNameSpace__ecere__sys__GetExtension
84
85 extern struct __ecereNameSpace__ecere__com__Instance * __thisModule;
86
87 typedef enum { unknown, win32, tux, apple } Platform;
88
89 #if defined(__WIN32__)
90 Platform runtimePlatform = win32;
91 #elif defined(__APPLE__)
92 Platform runtimePlatform = apple;
93 #elif defined(__linux__)
94 Platform runtimePlatform = tux;
95 #else
96 Platform runtimePlatform = unknown;
97 #endif
98
99 #if !defined(ECERE_NOFILE) && defined(__unix__)
100
101 typedef struct _DualPipe _DualPipe;
102
103 void DualPipe_Destructor(_DualPipe * dp);
104 bool DualPipe_Getc(_DualPipe * dp, char * ch);
105 bool DualPipe_Eof(_DualPipe * dp);
106 void DualPipe_Wait(_DualPipe * dp);
107
108 _DualPipe * _DualPipeOpen(int mode, char * commandLine, char * env, void ** inputPtr, void ** outputPtr);
109
110 static bool DualPipe_GetLine(FILE * p, char *s, int max)
111 {
112    int c = 0;
113    bool result = true;
114    s[c]=0;
115    if(feof(p))
116       result = false;
117    else
118    {
119       while(c<max-1)
120       {
121          int ch = 0;
122          if((ch = fgetc(p)) == EOF)
123          {
124             result = false;
125             break;
126          }
127          if(ch =='\n') 
128             break;
129          if(ch !='\r')
130             s[c++]=(char)ch;
131       }
132    }
133    s[c]=0;
134    return result || c > 1;
135 }
136
137 #endif
138
139 bool Instance_LocateModule(char * name, char * fileName)
140 {
141 #if defined(__WIN32__)
142    HMODULE hModule = null;
143    if(name && name[0])
144    {
145       uint16 _wmoduleName[MAX_LOCATION];
146       UTF8toUTF16Buffer(name, _wmoduleName, MAX_LOCATION);
147       hModule = GetModuleHandle(_wmoduleName);
148       if(!hModule)
149       {
150          wcscat(_wmoduleName, L".exe");
151          hModule = GetModuleHandle(_wmoduleName);
152       }
153       if(hModule)
154       {
155          uint16 _wfileName[MAX_LOCATION];
156          GetModuleFileNameW(hModule, _wfileName, MAX_LOCATION);
157          UTF16toUTF8Buffer(_wfileName, (byte *)fileName, MAX_LOCATION);
158          return true;
159       }
160    }
161    else
162    {
163       uint16 _wfileName[MAX_LOCATION];
164       GetModuleFileNameW(null, _wfileName, MAX_LOCATION);
165       UTF16toUTF8Buffer(_wfileName, (byte *)fileName, MAX_LOCATION);
166       return true;
167    }
168 #elif defined(__APPLE__)
169    if(name && name[0])
170    {
171       int imageCount = _dyld_image_count();
172       int c;
173       int nameLen = strlen(name);
174       for(c = 0; c<imageCount; c++)
175       {
176          struct mach_header * header = _dyld_get_image_header(c);
177          char * path = _dyld_get_image_name(c);
178          int pathLen = strlen(path);
179          char * subStr = RSearchString(path, name, pathLen, false, false);
180          if(subStr)
181          {
182             if(( *(subStr-1) == '/' || !strncmp(subStr - 4, "/lib", 4)) &&
183                (!subStr[nameLen] || !strncmp(subStr + nameLen, ".dylib", 6)))
184             {
185                strcpy(fileName, path);
186                return true;
187             }
188          }
189       }
190    }
191    else
192    {
193       int size = MAX_LOCATION;
194       _NSGetExecutablePath(fileName, &size);
195       return true;
196    }
197 #elif defined(__unix__)
198    //File f = FileOpen("/proc/self/maps", read);
199    FILE * f;
200    char exeName[MAX_FILENAME];
201    exeName[0] = 0;
202 #if defined(__linux__)
203    f = fopen("/proc/self/status", "r");
204 #else
205    f = fopen("/proc/curproc/status", "r");
206 #endif
207    if(f)
208    {
209       char line[1025];
210       while(fgets(line, sizeof(line), f))
211       {
212          char * name = strstr(line, "Name:\t");
213          if(name)
214          {
215             int nameLen;
216             name += 6;
217             nameLen = strlen(name);
218             name[--nameLen] = 0;
219             strcpy(exeName, name);
220             break;
221          }
222       }
223       fclose(f);
224   }
225 #if defined(__linux__)
226    f = fopen("/proc/self/maps", "r");
227 #else
228    f = fopen("/proc/curproc/map", "r");
229 #endif
230    if(f)
231    {
232       char line[1025];
233       //while(f.GetLine(line, sizeof(line)))
234       while(fgets(line, sizeof(line), f))
235       {
236          char * path = strstr(line, "/");
237          if(path)
238          {
239             int pathLen = strlen(path);
240             path[--pathLen] = 0;
241             if(name && name[0])
242             {
243                int nameLen = strlen(name);
244                char * subStr;
245                subStr = RSearchString(path, name, pathLen, false, false);
246                if(subStr)
247                {
248                   if(( *(subStr-1) == '/' || !strncmp(subStr - 4, "/lib", 4)) &&
249                      (!subStr[nameLen] || !strncmp(subStr + nameLen, ".so", 3)))
250                   {
251                      char * space = strchr(path, ' ');
252                      if(space) *space = 0;
253                      strcpy(fileName, path);
254                      fclose(f);
255                      return true;
256                   }
257                }
258             }
259             else
260             {
261                char name[MAX_FILENAME];
262                GetLastDirectory(path, name);
263                if(!exeName[0] || !strcmp(name, exeName))
264                {
265                   char * space = strchr(path, ' ');
266                   if(space) *space = 0;
267                   strcpy(fileName, path);
268                   fclose(f);
269                   return true;
270                }
271             }
272          }
273       }
274       fclose(f);
275    }
276 #if !defined(ECERE_NOFILE) && !defined(__linux__)
277    if(name && name[0])
278    {
279       // Couldn't locate libraries with /proc/curmap/map, attempt with ldd
280       FILE * in = null, * out = null;
281       _DualPipe * p;
282       char command[MAX_LOCATION];
283       snprintf(command, sizeof(command), "ldd /proc/%d/file", (int)getpid());
284       p  = _DualPipeOpen(1, command, null, &in, &out);
285       if(p)
286       {
287          bool result = false;
288          char line[1025];
289          int nameLen = strlen(name);
290          while(DualPipe_GetLine(in, line, sizeof(line)))
291          {
292             char * path = strstr(line, "/");
293             if(path)
294             {
295                int pathLen = strlen(path);
296                char * subStr;
297                path[--pathLen] = 0;
298                subStr = RSearchString(path, name, pathLen, false, false);
299                if(subStr)
300                {
301                   if(( *(subStr-1) == '/' || !strncmp(subStr - 4, "/lib", 4)) &&
302                      (!subStr[nameLen] || !strncmp(subStr + nameLen, ".so", 3)))
303                   {
304                      char * space = strchr(path, ' ');
305                      if(space) *space = 0;
306                      strcpy(fileName, path);
307                      result = true;
308                   }
309                }
310             }
311          }
312          DualPipe_Wait(p);
313          fclose(in);
314          DualPipe_Destructor(p);
315          return result;
316       }
317    }
318 #endif
319    if(!name || !name[0])
320    {
321 #if !defined(__linux__)
322       if(!access("/proc/curproc/file", F_OK))
323          strcpy(fileName, "/proc/curproc/file");
324       else
325 #endif
326          strcpy(fileName, exeLocation);
327       return true;
328    }
329 #endif
330    return false;
331 }
332
333 void Instance_COM_Initialize(int argc, char ** argv, char ** parsedCommand, int * argcPtr, char *** argvPtr)
334 {
335 #if !defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
336    // Disable stdout buffering on Unix
337    setvbuf(stdout, null, _IONBF, 0);
338 #endif
339 #if defined(__WIN32__)
340    *parsedCommand = UTF16toUTF8(GetCommandLineW());
341    *argvPtr = eSystem_New0(sizeof(char *) * 512);
342    *argcPtr = Tokenize(*parsedCommand, 512,(void*)(char **)(*argvPtr), false);
343 #else
344    *argcPtr = argc;
345    *argvPtr = argv;
346 #endif
347 #if defined(__unix__)
348    if(!__thisModule && argv)
349    {
350       getcwd(exeLocation, MAX_LOCATION);
351       PathCat(exeLocation, argv[0]);
352    }
353 #endif
354 }
355
356 void * Instance_Module_Load(const char * libLocation, const char * name, void ** Load, void ** Unload)
357 {
358    char fileName[MAX_LOCATION];
359    char extension[MAX_EXTENSION];
360    void * library = null;
361 #if defined(__unix__) || defined(__APPLE__)
362    int attempts = 0;
363    char * paths[] = { null, "/usr/lib/ec/lib", "/usr/lib32/ec/lib" };
364 #endif
365
366    *Load = null;
367    *Unload = null;
368
369 #if defined(__WIN32__)
370    strcpy(fileName, name);
371    GetExtension(fileName, extension);
372    if(!extension[0])
373       strcat(fileName, ".dll");
374
375    {
376       uint16 _wfileName[MAX_LOCATION];
377       UTF8toUTF16Buffer(fileName, _wfileName, MAX_LOCATION);
378       library = LoadLibraryW(_wfileName);
379    }
380    if(library)
381    {
382 #ifdef _WIN64
383       *Load = (void *)GetProcAddress(library, "__ecereDll_Load");
384       *Unload = (void *)GetProcAddress(library, "__ecereDll_Unload");
385 #else
386       *Load = (void *)GetProcAddress(library, "__ecereDll_Load@4");
387       *Unload = (void *)GetProcAddress(library, "__ecereDll_Unload@4");
388 #endif
389       if(!*Load)
390          FreeLibrary(library);
391    }
392 #elif defined(__unix__) || defined(__APPLE__)
393    if(libLocation)
394       strcpy(fileName, libLocation);
395    else
396       strcpy(fileName, "lib");
397    strcat(fileName, name);
398    GetExtension(fileName, extension);
399    if(!extension[0])
400 #if defined(__APPLE__)
401       strcat(fileName, ".dylib");
402 #else
403       strcat(fileName, ".so");
404 #endif
405
406    library = dlopen(fileName, RTLD_LAZY);
407    while(!library && attempts < sizeof(paths)/sizeof(paths[0]))
408    {
409       if(paths[attempts])
410          strcpy(fileName, paths[attempts++]);
411       else
412       {
413          attempts++;
414 #ifdef DEB_HOST_MULTIARCH
415          strcpy(fileName, DEB_HOST_MULTIARCH);
416          strcat(fileName, "/ec/lib");
417 #else
418          continue;
419 #endif
420       }
421       strcat(fileName, name);
422       GetExtension(fileName, extension);
423       if(!extension[0])
424 #if defined(__APPLE__)
425          strcat(fileName, ".dylib");
426 #else
427          strcat(fileName, ".so");
428 #endif
429       library = dlopen(fileName, RTLD_LAZY);
430    }
431
432    if(library)
433    {
434       *Load = dlsym(library, "__ecereDll_Load");
435       *Unload = dlsym(library, "__ecereDll_Unload");
436       if(!*Load)
437          dlclose(library);
438    }
439 #elif defined(__APPLE__)
440    strcpy(fileName, "lib");
441    strcat(fileName, name);
442    GetExtension(fileName, extension);
443    if(!extension[0])
444       strcat(fileName, ".dylib");
445    {
446       NSObjectFileImage *fileImage;
447       NSObjectFileImageReturnCode returnCode = NSCreateObjectFileImageFromFile(fileName, &fileImage);
448
449       if(returnCode == NSObjectFileImageSuccess)
450       {
451          printf("NSObjectFileImageSuccess!\n");
452          library = NSLinkModule(fileImage,fileName, 
453               NSLINKMODULE_OPTION_RETURN_ON_ERROR
454             | NSLINKMODULE_OPTION_PRIVATE);
455          // NSDestroyObjectFileImage(fileImage);
456          if(library)
457          {
458             *Load = NSAddressOfSymbol(NSLookupSymbolInModule(library, "__ecereDll_Load")); 
459             *Unload = NSAddressOfSymbol(NSLookupSymbolInModule(library, "__ecereDll_Unload"));
460             if(!*Load)
461             {
462                NSUnLinkModule(library, 0);
463             }
464             else
465                printf("Found Load!\n");
466          }
467       }
468       else
469          printf("No Success :(\n");
470    }
471 #endif
472    return library;
473 }
474
475 void Instance_Module_Free(void * library)
476 {
477 #if defined(__WIN32__)
478    if(library)
479       FreeLibrary(library);
480 #elif defined(__unix__) || defined(__APPLE__)
481    if(library)
482       dlclose(library);
483 #endif
484 }
485
486 #if defined(_DEBUG)
487    void InternalModuleLoadBreakpoint()
488    {
489    }
490 #endif