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