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