ecere: Initial Emscripten support
[sdk] / ecere / src / com / instance.c
index 37cf1eb..7ae555d 100644 (file)
@@ -1,3 +1,5 @@
+#define _Noreturn
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #define bool _bool
 #include <utime.h>
 #include <dlfcn.h>
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#endif
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
 #undef bool
 #endif
 
@@ -44,14 +52,62 @@ typedef unsigned long long uint64;
 #define MAX_FILENAME 274
 #define MAX_EXTENSION 17
 
+#if defined(__MINGW32__) && !defined(_W64) && __GNUC__ < 4
+__declspec(dllexport) int isblank(int c) { return c == '\t' || c == ' '; }
+#endif
+
+#if defined(__WIN32__)
+intptr_t stdinHandle, stdoutHandle;
+int osfStdin, osfStdout;
+FILE * fStdIn, * fStdOut;
+#endif
+
+FILE *eC_stdin(void)  {
+#if defined(__WIN32__)
+   if(!fStdIn)
+   {
+      stdinHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
+      osfStdin = _open_osfhandle(stdinHandle, _O_TEXT);
+      if(osfStdin != -1)
+         fStdIn = _fdopen( osfStdin, "rb");
+      else
+         fStdIn = stdin;
+      setvbuf( fStdIn, NULL, _IONBF, 0 );
+   }
+   return fStdIn;
+#else
+return stdin;
+#endif
+}
+
+FILE *eC_stdout(void)
+{
+#if 0 //defined(__WIN32__)
+   if(!fStdOut)
+   {
+      stdoutHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
+      osfStdout = _open_osfhandle(stdoutHandle, _O_TEXT);
+      if(osfStdout != -1)
+         fStdOut = _fdopen( osfStdout, "wb");
+      else
+         fStdOut = stdout;
+      setvbuf( fStdOut, NULL, _IONBF, 0 );
+   }
+   return fStdOut;
+#else
+   return stdout;
+#endif
+}
+FILE *eC_stderr(void) { return stderr; }
+
 void __ecereNameSpace__ecere__com__eSystem_Delete(void * memory);
 void * __ecereNameSpace__ecere__com__eSystem_New0(unsigned int size);
 void * __ecereNameSpace__ecere__com__eSystem_Renew(void * memory, unsigned int size);
 void * __ecereNameSpace__ecere__com__eSystem_Renew0(void * memory, unsigned int size);
-unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16(char * source, int * wordCount);
-unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer(char * source, uint16 * dest, int max);
+unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16(const char * source, int * wordCount);
+unsigned short * __ecereNameSpace__ecere__sys__UTF8toUTF16Buffer(const char * source, uint16 * dest, int max);
 char * __ecereNameSpace__ecere__sys__UTF16toUTF8(uint16 * source);
-char * __ecereNameSpace__ecere__sys__UTF16toUTF8Buffer(uint16 * source, byte * dest, int max);
+char * __ecereNameSpace__ecere__sys__UTF16toUTF8Buffer(uint16 * source, char * dest, int max);
 
 #define eSystem_Delete     __ecereNameSpace__ecere__com__eSystem_Delete
 #define eSystem_New0       __ecereNameSpace__ecere__com__eSystem_New0
@@ -66,11 +122,12 @@ char * __ecereNameSpace__ecere__sys__UTF16toUTF8Buffer(uint16 * source, byte * d
 static char exeLocation[MAX_LOCATION];
 #endif
 
-int __ecereNameSpace__ecere__sys__Tokenize(char * string, int maxTokens, char* tokens[], bool escapeBackSlashes);
-char * __ecereNameSpace__ecere__sys__RSearchString(char * buffer, char * subStr, int maxLen, bool matchCase, bool matchWord);
-char * __ecereNameSpace__ecere__sys__GetLastDirectory(char * string, char * output);
-char * __ecereNameSpace__ecere__sys__PathCat(char * string, char * addedPath);
-char * __ecereNameSpace__ecere__sys__GetExtension(char * string, char * output);
+#define forArgsPassing 2
+int __ecereNameSpace__ecere__sys__Tokenize(char * string, int maxTokens, char* tokens[], int esc);
+char * __ecereNameSpace__ecere__sys__RSearchString(const char * buffer, const char * subStr, int maxLen, bool matchCase, bool matchWord);
+char * __ecereNameSpace__ecere__sys__GetLastDirectory(const char * string, char * output);
+char * __ecereNameSpace__ecere__sys__PathCat(char * string, const char * addedPath);
+char * __ecereNameSpace__ecere__sys__GetExtension(const char * string, char * output);
 
 #define Tokenize           __ecereNameSpace__ecere__sys__Tokenize
 #define RSearchString      __ecereNameSpace__ecere__sys__RSearchString
@@ -86,13 +143,54 @@ typedef enum { unknown, win32, tux, apple } Platform;
 Platform runtimePlatform = win32;
 #elif defined(__APPLE__)
 Platform runtimePlatform = apple;
-#elif defined(__linux__)
+#else //if defined(__linux__)
 Platform runtimePlatform = tux;
-#else
-Platform runtimePlatform = unknown;
+/*#else
+Platform runtimePlatform = unknown;    // 'linux' is used as a catch all UNIX platform for now
+*/
+#endif
+
+#if !defined(ECERE_NOFILE) && defined(__unix__) && !defined(__linux__)
+
+typedef struct _DualPipe _DualPipe;
+
+void DualPipe_Destructor(_DualPipe * dp);
+bool DualPipe_Getc(_DualPipe * dp, char * ch);
+bool DualPipe_Eof(_DualPipe * dp);
+void DualPipe_Wait(_DualPipe * dp);
+
+_DualPipe * _DualPipeOpen(int mode, char * commandLine, char * env, void ** inputPtr, void ** outputPtr);
+
+static bool DualPipe_GetLine(FILE * p, char *s, int max)
+{
+   int c = 0;
+   bool result = true;
+   s[c]=0;
+   if(feof(p))
+      result = false;
+   else
+   {
+      while(c<max-1)
+      {
+         int ch = 0;
+         if((ch = fgetc(p)) == EOF)
+         {
+            result = false;
+            break;
+         }
+         if(ch =='\n')
+            break;
+         if(ch !='\r')
+            s[c++]=(char)ch;
+      }
+   }
+   s[c]=0;
+   return result || c > 1;
+}
+
 #endif
 
-bool Instance_LocateModule(char * name, char * fileName)
+bool Instance_LocateModule(const char * name, char * fileName)
 {
 #if defined(__WIN32__)
    HMODULE hModule = null;
@@ -110,7 +208,7 @@ bool Instance_LocateModule(char * name, char * fileName)
       {
          uint16 _wfileName[MAX_LOCATION];
          GetModuleFileNameW(hModule, _wfileName, MAX_LOCATION);
-         UTF16toUTF8Buffer(_wfileName, (byte *)fileName, MAX_LOCATION);
+         UTF16toUTF8Buffer(_wfileName, fileName, MAX_LOCATION);
          return true;
       }
    }
@@ -118,7 +216,7 @@ bool Instance_LocateModule(char * name, char * fileName)
    {
       uint16 _wfileName[MAX_LOCATION];
       GetModuleFileNameW(null, _wfileName, MAX_LOCATION);
-      UTF16toUTF8Buffer(_wfileName, (byte *)fileName, MAX_LOCATION);
+      UTF16toUTF8Buffer(_wfileName, fileName, MAX_LOCATION);
       return true;
    }
 #elif defined(__APPLE__)
@@ -152,7 +250,7 @@ bool Instance_LocateModule(char * name, char * fileName)
    }
 #elif defined(__unix__)
    //File f = FileOpen("/proc/self/maps", read);
-   FILE * f;
+   FILE * f = null;
    char exeName[MAX_FILENAME];
    exeName[0] = 0;
 #if defined(__linux__)
@@ -229,8 +327,76 @@ bool Instance_LocateModule(char * name, char * fileName)
       }
       fclose(f);
    }
+#if !defined(ECERE_NOFILE) && !defined(__linux__) && !defined(__EMSCRIPTEN__)
+   if(name && name[0])
+   {
+      // Couldn't locate libraries with /proc/curmap/map, attempt with ldd
+      FILE * in = null, * out = null;
+      _DualPipe * p;
+      char command[MAX_LOCATION];
+      snprintf(command, sizeof(command), "ldd /proc/%d/file", (int)getpid());
+      p  = _DualPipeOpen(1, command, null, &in, &out);
+      if(p)
+      {
+         bool result = false;
+         char line[1025];
+         int nameLen = strlen(name);
+         while(DualPipe_GetLine(in, line, sizeof(line)))
+         {
+            char * path = strstr(line, "/");
+            if(path)
+            {
+               int pathLen = strlen(path);
+               char * subStr;
+               path[--pathLen] = 0;
+               subStr = RSearchString(path, name, pathLen, false, false);
+               if(subStr)
+               {
+                  if(( *(subStr-1) == '/' || !strncmp(subStr - 4, "/lib", 4)) &&
+                     (!subStr[nameLen] || !strncmp(subStr + nameLen, ".so", 3)))
+                  {
+                     char * space = strchr(path, ' ');
+                     if(space) *space = 0;
+                     strcpy(fileName, path);
+                     result = true;
+                  }
+               }
+            }
+         }
+         DualPipe_Wait(p);
+         fclose(in);
+         DualPipe_Destructor(p);
+         return result;
+      }
+   }
+#endif
    if(!name || !name[0])
    {
+#if defined(__FreeBSD__)
+      {
+         int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+         size_t cb = MAX_LOCATION;
+         fileName[0] = 0;
+         sysctl(mib, 4, fileName, &cb, null, 0);
+         if(fileName[0])
+            return true;
+      }
+#endif
+#if !defined(__linux__)
+      {
+         char * env;
+         if(!access("/proc/curproc/file", F_OK))
+         {
+            strcpy(fileName, "/proc/curproc/file");
+            return true;
+         }
+         if((env = getenv("_")))
+         {
+            strcpy(fileName, env);
+            return true;
+         }
+      }
+#endif
       strcpy(fileName, exeLocation);
       return true;
    }
@@ -238,7 +404,7 @@ bool Instance_LocateModule(char * name, char * fileName)
    return false;
 }
 
-void Instance_COM_Initialize(int argc, char ** argv, char ** parsedCommand, int * argcPtr, char *** argvPtr)
+void Instance_COM_Initialize(int argc, char ** argv, char ** parsedCommand, int * argcPtr, const char *** argvPtr)
 {
 #if !defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
    // Disable stdout buffering on Unix
@@ -247,25 +413,45 @@ void Instance_COM_Initialize(int argc, char ** argv, char ** parsedCommand, int
 #if defined(__WIN32__)
    *parsedCommand = UTF16toUTF8(GetCommandLineW());
    *argvPtr = eSystem_New0(sizeof(char *) * 512);
-   *argcPtr = Tokenize(*parsedCommand, 512,(void*)(char **)(*argvPtr), false);
+   *argcPtr = Tokenize(*parsedCommand, 512,(void*)(char **)(*argvPtr), forArgsPassing);
 #else
    *argcPtr = argc;
-   *argvPtr = argv;
+   *argvPtr = (const char **)argv;
 #endif
 #if defined(__unix__)
    if(!__thisModule && argv)
    {
-      getcwd(exeLocation, MAX_LOCATION);
+      if(!getcwd(exeLocation, MAX_LOCATION))
+         exeLocation[0] = 0;
       PathCat(exeLocation, argv[0]);
    }
 #endif
 }
 
-void * Instance_Module_Load(char * name, void ** Load, void ** Unload)
+void System_SetArgs(int argc, char ** argv, int * argcPtr, const char *** argvPtr)
+{
+#if defined(__unix__)
+   *argcPtr = argc;
+   *argvPtr = (const char **)argv;
+
+   if(!__thisModule && argv)
+   {
+      if(!getcwd(exeLocation, MAX_LOCATION))
+         exeLocation[0] = 0;
+      PathCat(exeLocation, argv[0]);
+   }
+#endif
+}
+
+void * Instance_Module_Load(const char * libLocation, const char * name, void ** Load, void ** Unload)
 {
    char fileName[MAX_LOCATION];
    char extension[MAX_EXTENSION];
    void * library = null;
+#if defined(__unix__) || defined(__APPLE__)
+   int attempts = 0;
+   char * paths[] = { null, "/usr/lib/ec/lib", "/usr/lib32/ec/lib" };
+#endif
 
    *Load = null;
    *Unload = null;
@@ -294,11 +480,10 @@ void * Instance_Module_Load(char * name, void ** Load, void ** Unload)
          FreeLibrary(library);
    }
 #elif defined(__unix__) || defined(__APPLE__)
-#if defined(__ANDROID__)
-   sprintf(fileName, "/data/data/com.ecere.%s/lib/lib", name);
-#else
-   strcpy(fileName, "lib");
-#endif
+   if(libLocation || strchr(name, '/'))
+      strcpy(fileName, libLocation ? libLocation : "");
+   else
+      strcpy(fileName, "lib");
    strcat(fileName, name);
    GetExtension(fileName, extension);
    if(!extension[0])
@@ -308,15 +493,23 @@ void * Instance_Module_Load(char * name, void ** Load, void ** Unload)
       strcat(fileName, ".so");
 #endif
 
+#if !defined(__EMSCRIPTEN__)
    library = dlopen(fileName, RTLD_LAZY);
-   if(!library)
+#endif
+   while(!library && attempts < sizeof(paths)/sizeof(paths[0]))
    {
+      if(paths[attempts])
+         strcpy(fileName, paths[attempts++]);
+      else
+      {
+         attempts++;
 #ifdef DEB_HOST_MULTIARCH
-      strcpy(fileName, DEB_HOST_MULTIARCH);
-      strcat(fileName, "/ec/lib");
+         strcpy(fileName, DEB_HOST_MULTIARCH);
+         strcat(fileName, "/ec/lib");
 #else
-      strcpy(fileName, "/usr/lib/ec/lib");
+         continue;
 #endif
+      }
       strcat(fileName, name);
       GetExtension(fileName, extension);
       if(!extension[0])
@@ -325,18 +518,25 @@ void * Instance_Module_Load(char * name, void ** Load, void ** Unload)
 #else
          strcat(fileName, ".so");
 #endif
+#if !defined(__EMSCRIPTEN__)
       library = dlopen(fileName, RTLD_LAZY);
+#endif
    }
 
    if(library)
    {
       *Load = dlsym(library, "__ecereDll_Load");
       *Unload = dlsym(library, "__ecereDll_Unload");
+#if !defined(__EMSCRIPTEN__)
       if(!*Load)
          dlclose(library);
+#endif
    }
 #elif defined(__APPLE__)
-   strcpy(fileName, "lib");
+   if(libLocation || strchr(name, '/'))
+      strcpy(fileName, libLocation ? libLocation : "");
+   else
+      strcpy(fileName, "lib");
    strcat(fileName, name);
    GetExtension(fileName, extension);
    if(!extension[0])
@@ -348,13 +548,13 @@ void * Instance_Module_Load(char * name, void ** Load, void ** Unload)
       if(returnCode == NSObjectFileImageSuccess)
       {
          printf("NSObjectFileImageSuccess!\n");
-         library = NSLinkModule(fileImage,fileName, 
+         library = NSLinkModule(fileImage,fileName,
               NSLINKMODULE_OPTION_RETURN_ON_ERROR
             | NSLINKMODULE_OPTION_PRIVATE);
          // NSDestroyObjectFileImage(fileImage);
          if(library)
          {
-            *Load = NSAddressOfSymbol(NSLookupSymbolInModule(library, "__ecereDll_Load")); 
+            *Load = NSAddressOfSymbol(NSLookupSymbolInModule(library, "__ecereDll_Load"));
             *Unload = NSAddressOfSymbol(NSLookupSymbolInModule(library, "__ecereDll_Unload"));
             if(!*Load)
             {
@@ -376,8 +576,28 @@ void Instance_Module_Free(void * library)
 #if defined(__WIN32__)
    if(library)
       FreeLibrary(library);
-#elif defined(__unix__) || defined(__APPLE__)
+#elif (defined(__unix__) || defined(__APPLE__)) && !defined(__EMSCRIPTEN__)
    if(library)
       dlclose(library);
 #endif
 }
+
+#if defined(_DEBUG)
+   void InternalModuleLoadBreakpoint()
+   {
+   }
+#endif
+
+#include <math.h>
+
+bool Float_isNan(float n) { return isnan(n); }
+bool Float_isInf(float n) { return isinf(n); }
+int Float_signBit(float n) { return signbit(n); }
+float Float_nan(void) { return NAN; }
+float Float_inf(void) { return INFINITY; }
+
+bool Double_isNan(double n) { return isnan(n); }
+bool Double_isInf(double n) { return isinf(n); }
+int Double_signBit(double n) { return signbit(n); }
+double Double_nan(void) { return NAN; }
+double Double_inf(void) { return INFINITY; }