From 10458ef654d81983e17309dd151e55a6bde7b884 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Tue, 17 Mar 2015 16:00:51 +0000
Subject: [PATCH] first try at implementing GetExecutableName()

---
 Common/GmshMessage.cpp |   8 ++--
 Common/OS.cpp          | 101 +++++++++++++++++++++++++++++++++++++++++
 Common/OS.h            |   1 +
 Common/StringUtils.cpp |   3 +-
 4 files changed, 108 insertions(+), 5 deletions(-)

diff --git a/Common/GmshMessage.cpp b/Common/GmshMessage.cpp
index bb446163a9..93a99b7a01 100644
--- a/Common/GmshMessage.cpp
+++ b/Common/GmshMessage.cpp
@@ -99,19 +99,19 @@ static int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
 
 static void addGmshPathToEnvironmentVar(const std::string &name)
 {
-  std::vector<std::string> split = SplitFileName(CTX::instance()->argv0);
+  std::string gmshPath = SplitFileName(GetExecutableName(CTX::instance()->argv0))[0];
   std::string path;
   char *tmp = getenv(name.c_str());
   if(tmp){
     path = tmp;
 #if defined(WIN32)
-    path += ";" + split[0];
+    path += ";" + gmshPath;
 #else
-    path += ":" + split[0];
+    path += ":" + gmshPath;
 #endif
   }
   else
-    path = split[0];
+    path = gmshPath;
   SetEnvironmentVar(name.c_str(), path.c_str());
 }
 
diff --git a/Common/OS.cpp b/Common/OS.cpp
index e76f54e8ec..2dcda6c82a 100644
--- a/Common/OS.cpp
+++ b/Common/OS.cpp
@@ -20,6 +20,7 @@
 
 #if defined(__APPLE__)
 #include <sys/sysctl.h>
+#include <mach-o/dyld.h>
 #endif
 
 #if defined(__linux__) && !defined(BUILD_ANDROID)
@@ -143,6 +144,68 @@ static unsigned utf8toUtf16(const char* src, unsigned srclen,
   return count;
 }
 
+static unsigned utf8FromUtf16(char* dst, unsigned dstlen,
+                              const wchar_t* src, unsigned srclen)
+{
+  unsigned i = 0;
+  unsigned count = 0;
+  if (dstlen) {
+    for (;;) {
+      unsigned ucs;
+      if (i >= srclen) {dst[count] = 0; return count;}
+      ucs = src[i++];
+      if (ucs < 0x80U) {
+        dst[count++] = ucs;
+        if (count >= dstlen) {dst[count-1] = 0; break;}
+      }
+      else if (ucs < 0x800U) { /* 2 bytes */
+        if (count+2 >= dstlen) {dst[count] = 0; count += 2; break;}
+        dst[count++] = 0xc0 | (ucs >> 6);
+        dst[count++] = 0x80 | (ucs & 0x3F);
+      }
+      else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen &&
+	       src[i] >= 0xdc00 && src[i] <= 0xdfff) {
+        /* surrogate pair */
+        unsigned ucs2 = src[i++];
+        ucs = 0x10000U + ((ucs&0x3ff)<<10) + (ucs2&0x3ff);
+        /* all surrogate pairs turn into 4-byte utf8 */
+        if (count+4 >= dstlen) {dst[count] = 0; count += 4; break;}
+        dst[count++] = 0xf0 | (ucs >> 18);
+        dst[count++] = 0x80 | ((ucs >> 12) & 0x3F);
+        dst[count++] = 0x80 | ((ucs >> 6) & 0x3F);
+        dst[count++] = 0x80 | (ucs & 0x3F);
+      }
+      else {
+        /* all others are 3 bytes: */
+        if (count+3 >= dstlen) {dst[count] = 0; count += 3; break;}
+        dst[count++] = 0xe0 | (ucs >> 12);
+        dst[count++] = 0x80 | ((ucs >> 6) & 0x3F);
+        dst[count++] = 0x80 | (ucs & 0x3F);
+      }
+    }
+  }
+  /* we filled dst, measure the rest: */
+  while (i < srclen) {
+    unsigned ucs = src[i++];
+    if (ucs < 0x80U) {
+      count++;
+    }
+    else if (ucs < 0x800U) { /* 2 bytes */
+      count += 2;
+    }
+    else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen-1 &&
+             src[i+1] >= 0xdc00 && src[i+1] <= 0xdfff) {
+      /* surrogate pair */
+      ++i;
+      count += 4;
+    }
+    else {
+      count += 3;
+    }
+  }
+  return count;
+}
+
 static wchar_t *wbuf[3] = {NULL, NULL, NULL};
 
 static void setwbuf(int i, const char *f)
@@ -312,6 +375,44 @@ int GetProcessId()
 #endif
 }
 
+std::string GetExecutableName(const std::string &argv0)
+{
+  std::string name = "";
+#if defined(WIN32) && !defined(__CYGWIN__)
+  WCHAR src[MAX_PATH];
+  DWARD size = GetModuleFileNameW(NULL, src, MAX_PATH);
+  if(size){
+    char dst[MAX_PATH];
+    utf8FromUtf16(dst, MAX_PATH, src, size);
+    name = std::string(dst);
+  }
+#elif defined(__APPLE__)
+  char path[PATH_MAX];
+  uint32_t size = sizeof(path);
+  if (_NSGetExecutablePath(path, &size) == 0){
+    char real[PATH_MAX];
+    if(realpath(path, real)){
+      name = std::string(real);
+    }
+  }
+#elif defined(__linux__)
+  char path[PATH_MAX];
+  int s = readlink("/proc/self/exe", path, sizeof(path));
+  if(s > 0){
+    path[s - 1] = '\0';
+    name = std::string(path);
+  }
+#endif
+  if(name.empty()){
+    name = argv0;
+    printf("Found executable name through argv0 = '%s'\n", name.c_str());
+  }
+  else
+    printf("Found executable name = '%s'\n", name.c_str());
+
+  return name;
+}
+
 std::string GetHostName()
 {
   char host[256];
diff --git a/Common/OS.h b/Common/OS.h
index 72f5238372..6290b76522 100644
--- a/Common/OS.h
+++ b/Common/OS.h
@@ -18,6 +18,7 @@ double Cpu();
 double TotalRam();
 long GetMemoryUsage();
 int GetProcessId();
+std::string GetExecutableName(const std::string &argv0);
 std::string GetHostName();
 int UnlinkFile(const std::string &fileName);
 int StatFile(const std::string &fileName);
diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp
index 8378af230c..50c15ee46d 100644
--- a/Common/StringUtils.cpp
+++ b/Common/StringUtils.cpp
@@ -91,7 +91,8 @@ std::string FixRelativePath(const std::string &reference, const std::string &in)
 
 std::vector<std::string> SplitFileName(const std::string &fileName)
 {
-  // JFR DO NOT CHANGE TO std::vector<std::string> s(3), it segfaults while destructor si called 
+  // JFR DO NOT CHANGE TO std::vector<std::string> s(3), it segfaults while
+  // destructor si called
   std::vector<std::string> s; s.resize(3);
   if(fileName.size()){
     // returns [path, baseName, extension]
-- 
GitLab