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