7432ffce877bf27a90e7458aab55a575eba1cf09
[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 } Platform;
141
142 #if defined(__WIN32__) && !defined(__EMSCRIPTEN__)
143 Platform runtimePlatform = win32;
144 #elif defined(__APPLE__)
145 Platform runtimePlatform = apple;
146 #else //if defined(__linux__)
147 Platform runtimePlatform = tux;
148 /*#else
149 Platform runtimePlatform = unknown;    // 'linux' is used as a catch all UNIX platform for now
150 */
151 #endif
152
153 #if !defined(ECERE_NOFILE) && defined(__unix__) && !defined(__linux__)
154
155 typedef struct _DualPipe _DualPipe;
156
157 void DualPipe_Destructor(_DualPipe * dp);
158 bool DualPipe_Getc(_DualPipe * dp, char * ch);
159 bool DualPipe_Eof(_DualPipe * dp);
160 void DualPipe_Wait(_DualPipe * dp);
161
162 _DualPipe * _DualPipeOpen(int mode, char * commandLine, char * env, void ** inputPtr, void ** outputPtr);
163
164 static bool DualPipe_GetLine(FILE * p, char *s, int max)
165 {
166    int c = 0;
167    bool result = true;
168    s[c]=0;
169    if(feof(p))
170       result = false;
171    else
172    {
173       while(c<max-1)
174       {
175          int ch = 0;
176          if((ch = fgetc(p)) == EOF)
177          {
178             result = false;
179             break;
180          }
181          if(ch =='\n')
182             break;
183          if(ch !='\r')
184             s[c++]=(char)ch;
185       }
186    }
187    s[c]=0;
188    return result || c > 1;
189 }
190
191 #endif
192
193 bool Instance_LocateModule(const char * name, char * fileName)
194 {
195 #if defined(__WIN32__) && !defined(__EMSCRIPTEN__)
196    HMODULE hModule = null;
197    if(name && name[0])
198    {
199       uint16 _wmoduleName[MAX_LOCATION];
200       UTF8toUTF16Buffer(name, _wmoduleName, MAX_LOCATION);
201       hModule = GetModuleHandle(_wmoduleName);
202       if(!hModule)
203       {
204          wcscat(_wmoduleName, L".exe");
205          hModule = GetModuleHandle(_wmoduleName);
206       }
207       if(hModule)
208       {
209          uint16 _wfileName[MAX_LOCATION];
210          GetModuleFileNameW(hModule, _wfileName, MAX_LOCATION);
211          UTF16toUTF8Buffer(_wfileName, fileName, MAX_LOCATION);
212          return true;
213       }
214    }
215    else
216    {
217       uint16 _wfileName[MAX_LOCATION];
218       GetModuleFileNameW(null, _wfileName, MAX_LOCATION);
219       UTF16toUTF8Buffer(_wfileName, fileName, MAX_LOCATION);
220       return true;
221    }
222 #elif defined(__APPLE__)
223    if(name && name[0])
224    {
225       int imageCount = _dyld_image_count();
226       int c;
227       int nameLen = strlen(name);
228       for(c = 0; c<imageCount; c++)
229       {
230          struct mach_header * header = _dyld_get_image_header(c);
231          char * path = _dyld_get_image_name(c);
232          int pathLen = strlen(path);
233          char * subStr = RSearchString(path, name, pathLen, false, false);
234          if(subStr)
235          {
236             if(( *(subStr-1) == '/' || !strncmp(subStr - 4, "/lib", 4)) &&
237                (!subStr[nameLen] || !strncmp(subStr + nameLen, ".dylib", 6)))
238             {
239                strcpy(fileName, path);
240                return true;
241             }
242          }
243       }
244    }
245    else
246    {
247       int size = MAX_LOCATION;
248       _NSGetExecutablePath(fileName, &size);
249       return true;
250    }
251 #elif defined(__unix__)
252    //File f = FileOpen("/proc/self/maps", read);
253    FILE * f = null;
254    char exeName[MAX_FILENAME];
255    exeName[0] = 0;
256 #if defined(__linux__)
257    f = fopen("/proc/self/status", "r");
258 #else
259    f = fopen("/proc/curproc/status", "r");
260 #endif
261    if(f)
262    {
263       char line[1025];
264       while(fgets(line, sizeof(line), f))
265       {
266          char * name = strstr(line, "Name:\t");
267          if(name)
268          {
269             int nameLen;
270             name += 6;
271             nameLen = strlen(name);
272             name[--nameLen] = 0;
273             strcpy(exeName, name);
274             break;
275          }
276       }
277       fclose(f);
278   }
279 #if defined(__linux__)
280    f = fopen("/proc/self/maps", "r");
281 #else
282    f = fopen("/proc/curproc/map", "r");
283 #endif
284    if(f)
285    {
286       char line[1025];
287       //while(f.GetLine(line, sizeof(line)))
288       while(fgets(line, sizeof(line), f))
289       {
290          char * path = strstr(line, "/");
291          if(path)
292          {
293             int pathLen = strlen(path);
294             path[--pathLen] = 0;
295             if(name && name[0])
296             {
297                int nameLen = strlen(name);
298                char * subStr;
299                subStr = RSearchString(path, name, pathLen, false, false);
300                if(subStr)
301                {
302                   if(( *(subStr-1) == '/' || !strncmp(subStr - 4, "/lib", 4)) &&
303                      (!subStr[nameLen] || !strncmp(subStr + nameLen, ".so", 3)))
304                   {
305                      char * space = strchr(path, ' ');
306                      if(space) *space = 0;
307                      strcpy(fileName, path);
308                      fclose(f);
309                      return true;
310                   }
311                }
312             }
313             else
314             {
315                char name[MAX_FILENAME];
316                GetLastDirectory(path, name);
317                if(!exeName[0] || !strcmp(name, exeName))
318                {
319                   char * space = strchr(path, ' ');
320                   if(space) *space = 0;
321                   strcpy(fileName, path);
322                   fclose(f);
323                   return true;
324                }
325             }
326          }
327       }
328       fclose(f);
329    }
330 #if !defined(ECERE_NOFILE) && !defined(__linux__) && !defined(__EMSCRIPTEN__) && !defined(__pnacl__)
331    if(name && name[0])
332    {
333       // Couldn't locate libraries with /proc/curmap/map, attempt with ldd
334       FILE * in = null, * out = null;
335       _DualPipe * p;
336       char command[MAX_LOCATION];
337       snprintf(command, sizeof(command), "ldd /proc/%d/file", (int)getpid());
338       p  = _DualPipeOpen(1, command, null, &in, &out);
339       if(p)
340       {
341          bool result = false;
342          char line[1025];
343          int nameLen = strlen(name);
344          while(DualPipe_GetLine(in, line, sizeof(line)))
345          {
346             char * path = strstr(line, "/");
347             if(path)
348             {
349                int pathLen = strlen(path);
350                char * subStr;
351                path[--pathLen] = 0;
352                subStr = RSearchString(path, name, pathLen, false, false);
353                if(subStr)
354                {
355                   if(( *(subStr-1) == '/' || !strncmp(subStr - 4, "/lib", 4)) &&
356                      (!subStr[nameLen] || !strncmp(subStr + nameLen, ".so", 3)))
357                   {
358                      char * space = strchr(path, ' ');
359                      if(space) *space = 0;
360                      strcpy(fileName, path);
361                      result = true;
362                   }
363                }
364             }
365          }
366          DualPipe_Wait(p);
367          fclose(in);
368          DualPipe_Destructor(p);
369          return result;
370       }
371    }
372 #endif
373    if(!name || !name[0])
374    {
375 #if defined(__FreeBSD__)
376       {
377          int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
378          size_t cb = MAX_LOCATION;
379          fileName[0] = 0;
380          sysctl(mib, 4, fileName, &cb, null, 0);
381          if(fileName[0])
382             return true;
383       }
384 #endif
385 #if !defined(__linux__)
386       {
387          char * env;
388          if(!access("/proc/curproc/file", F_OK))
389          {
390             strcpy(fileName, "/proc/curproc/file");
391             return true;
392          }
393          if((env = getenv("_")))
394          {
395             strcpy(fileName, env);
396             return true;
397          }
398       }
399 #endif
400       strcpy(fileName, exeLocation);
401       return true;
402    }
403 #endif
404    return false;
405 }
406
407 void Instance_COM_Initialize(int argc, char ** argv, char ** parsedCommand, int * argcPtr, const char *** argvPtr)
408 {
409 #if !defined(__WIN32__) && !defined(__EMSCRIPTEN__) && !defined(ECERE_BOOTSTRAP) && !defined(__pnacl__)
410    // Disable stdout buffering on Unix
411    setvbuf(stdout, null, _IONBF, 0);
412 #endif
413 #if defined(__WIN32__) && !defined(__EMSCRIPTEN__)
414    *parsedCommand = UTF16toUTF8(GetCommandLineW());
415    *argvPtr = eSystem_New0(sizeof(char *) * 512);
416    *argcPtr = Tokenize(*parsedCommand, 512,(void*)(char **)(*argvPtr), forArgsPassing);
417 #else
418    *argcPtr = argc;
419    *argvPtr = (const char **)argv;
420 #endif
421 #if defined(__unix__)
422    if(!__thisModule && argv)
423    {
424       if(!getcwd(exeLocation, MAX_LOCATION))
425          exeLocation[0] = 0;
426       PathCat(exeLocation, argv[0]);
427    }
428 #endif
429 }
430
431 void * Instance_Module_Load(const char * libLocation, const char * name, void ** Load, void ** Unload)
432 {
433    char fileName[MAX_LOCATION];
434    char extension[MAX_EXTENSION];
435    void * library = null;
436 #if defined(__unix__) || defined(__APPLE__)
437    int attempts = 0;
438    char * paths[] = { null, "/usr/lib/ec/lib", "/usr/lib32/ec/lib" };
439 #endif
440
441    *Load = null;
442    *Unload = null;
443
444 #if defined(__WIN32__) && !defined(__EMSCRIPTEN__)
445    strcpy(fileName, name);
446    GetExtension(fileName, extension);
447    if(!extension[0])
448       strcat(fileName, ".dll");
449
450    {
451       uint16 _wfileName[MAX_LOCATION];
452       UTF8toUTF16Buffer(fileName, _wfileName, MAX_LOCATION);
453       library = LoadLibraryW(_wfileName);
454    }
455    if(library)
456    {
457 #ifdef _WIN64
458       *Load = (void *)GetProcAddress(library, "__ecereDll_Load");
459       *Unload = (void *)GetProcAddress(library, "__ecereDll_Unload");
460 #else
461       *Load = (void *)GetProcAddress(library, "__ecereDll_Load@4");
462       *Unload = (void *)GetProcAddress(library, "__ecereDll_Unload@4");
463 #endif
464       if(!*Load)
465          FreeLibrary(library);
466    }
467 #elif defined(__unix__) || defined(__APPLE__)
468    if(libLocation || strchr(name, '/'))
469       strcpy(fileName, libLocation ? libLocation : "");
470    else
471       strcpy(fileName, "lib");
472    strcat(fileName, name);
473    GetExtension(fileName, extension);
474    if(!extension[0])
475 #if defined(__APPLE__)
476       strcat(fileName, ".dylib");
477 #else
478       strcat(fileName, ".so");
479 #endif
480
481 #if !defined(__EMSCRIPTEN__) && !defined(__pnacl__)
482    library = dlopen(fileName, RTLD_LAZY);
483 #endif
484    while(!library && attempts < sizeof(paths)/sizeof(paths[0]))
485    {
486       if(paths[attempts])
487          strcpy(fileName, paths[attempts++]);
488       else
489       {
490          attempts++;
491 #ifdef DEB_HOST_MULTIARCH
492          strcpy(fileName, DEB_HOST_MULTIARCH);
493          strcat(fileName, "/ec/lib");
494 #else
495          continue;
496 #endif
497       }
498       strcat(fileName, name);
499       GetExtension(fileName, extension);
500       if(!extension[0])
501 #if defined(__APPLE__)
502          strcat(fileName, ".dylib");
503 #else
504          strcat(fileName, ".so");
505 #endif
506 #if !defined(__EMSCRIPTEN__) && !defined(__pnacl__)
507       library = dlopen(fileName, RTLD_LAZY);
508 #endif
509    }
510
511    if(library)
512    {
513       *Load = dlsym(library, "__ecereDll_Load");
514       *Unload = dlsym(library, "__ecereDll_Unload");
515 #if !defined(__EMSCRIPTEN__) && !defined(__pnacl__)
516       if(!*Load)
517          dlclose(library);
518 #endif
519    }
520 #elif defined(__APPLE__)
521    if(libLocation || strchr(name, '/'))
522       strcpy(fileName, libLocation ? libLocation : "");
523    else
524       strcpy(fileName, "lib");
525    strcat(fileName, name);
526    GetExtension(fileName, extension);
527    if(!extension[0])
528       strcat(fileName, ".dylib");
529    {
530       NSObjectFileImage *fileImage;
531       NSObjectFileImageReturnCode returnCode = NSCreateObjectFileImageFromFile(fileName, &fileImage);
532
533       if(returnCode == NSObjectFileImageSuccess)
534       {
535          printf("NSObjectFileImageSuccess!\n");
536          library = NSLinkModule(fileImage,fileName,
537               NSLINKMODULE_OPTION_RETURN_ON_ERROR
538             | NSLINKMODULE_OPTION_PRIVATE);
539          // NSDestroyObjectFileImage(fileImage);
540          if(library)
541          {
542             *Load = NSAddressOfSymbol(NSLookupSymbolInModule(library, "__ecereDll_Load"));
543             *Unload = NSAddressOfSymbol(NSLookupSymbolInModule(library, "__ecereDll_Unload"));
544             if(!*Load)
545             {
546                NSUnLinkModule(library, 0);
547             }
548             else
549                printf("Found Load!\n");
550          }
551       }
552       else
553          printf("No Success :(\n");
554    }
555 #endif
556    return library;
557 }
558
559 void Instance_Module_Free(void * library)
560 {
561 #if defined(__WIN32__) && !defined(__EMSCRIPTEN__)
562    if(library)
563       FreeLibrary(library);
564 #elif (defined(__unix__) || defined(__APPLE__)) && !defined(__EMSCRIPTEN__) && !defined(__pnacl__)
565    if(library)
566       dlclose(library);
567 #endif
568 }
569
570 #if defined(_DEBUG)
571    void InternalModuleLoadBreakpoint()
572    {
573    }
574 #endif
575
576 #include <math.h>
577
578 bool Float_isNan(float n) { return isnan(n); }
579 bool Float_isInf(float n) { return isinf(n); }
580 int Float_signBit(float n) { return signbit(n); }
581 float Float_nan(void) { return NAN; }
582 float Float_inf(void) { return INFINITY; }
583
584 bool Double_isNan(double n) { return isnan(n); }
585 bool Double_isInf(double n) { return isinf(n); }
586 int Double_signBit(double n) { return signbit(n); }
587 double Double_nan(void) { return NAN; }
588 double Double_inf(void) { return INFINITY; }