Skip to content

Commit 2d08b2e

Browse files
committed
Add getExecutablePath
1 parent 09248f6 commit 2d08b2e

6 files changed

Lines changed: 7099 additions & 7021 deletions

File tree

generated/mhs.c

Lines changed: 7020 additions & 7020 deletions
Large diffs are not rendered by default.

lib/System/Environment.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module System.Environment(
99
getEnvironment,
1010
setEnv,
1111
unsetEnv,
12+
getExecutablePath,
1213
) where
1314
import qualified Prelude(); import MiniPrelude
1415
import Primitives
@@ -17,6 +18,7 @@ import Data.Bifunctor(second)
1718
import Data.List(span)
1819
import Foreign.C.Error
1920
import Foreign.C.String
21+
import Foreign.Marshal.Alloc
2022
import Foreign.Marshal.Array
2123
import Foreign.Ptr
2224
import System.IO
@@ -95,3 +97,13 @@ unsetEnv key = do
9597
chkKey "unsetEnv" key
9698
withCAString key $ \ ckey ->
9799
throwErrnoIfMinus1_ "unsetEnv" $ c_unsetenv ckey
100+
101+
foreign import ccall get_executable_path :: IO CString
102+
103+
getExecutablePath :: IO String
104+
getExecutablePath = do
105+
p <- throwErrnoIfNull "get_executable_path" get_executable_path
106+
s <- peekCAString p
107+
free p
108+
return s
109+

src/MicroHs/FFI.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,5 +290,6 @@ runtimeFFI = [
290290
"ETOOMANYREFS", "ETXTBSY", "EUSERS", "EWOULDBLOCK", "EXDEV",
291291
"errno",
292292
"strerror_r",
293-
"environ"
293+
"environ",
294+
"get_executable_path"
294295
]

src/runtime/eval.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7381,6 +7381,7 @@ from_t mhs_mpz_log2(int s) {
73817381
#if WANT_TIME
73827382
from_t mhs_gettimeofday(int s) { return mhs_from_Int(s, 2, gettimeofday(mhs_to_Ptr(s, 0), mhs_to_Ptr(s, 1))); }
73837383
#endif
7384+
from_t mhs_get_executable_path(int s) { return mhs_from_Ptr(s, 0, get_executable_path()); }
73847385

73857386
const struct ffi_entry ffi_table[] = {
73867387
{ "GETRAW", 0, mhs_GETRAW},
@@ -7687,6 +7688,7 @@ const struct ffi_entry ffi_table[] = {
76877688
{ "&errno", 0, mhs_addr_errno},
76887689
{ "strerror_r", 3, mhs_strerror_r},
76897690
#endif
7691+
{ "get_executable_path", 0, mhs_get_executable_path},
76907692
{ 0,0 }
76917693
};
76927694

src/runtime/unix/extra.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,39 @@ uint64_t end_kperf(void) { return 0; }
182182
#endif /* apple-arm */
183183

184184
#endif /* WANT_KPERF */
185+
186+
#include <stdlib.h>
187+
188+
#if defined(__linux__)
189+
#include <unistd.h>
190+
#include <limits.h>
191+
#elif defined(__APPLE__) && defined(__MACH__)
192+
#include <mach-o/dyld.h>
193+
#include <limits.h>
194+
#endif
195+
196+
/* Return path to executable as a null-terminated UTF-8 string. */
197+
char*
198+
get_executable_path(void) {
199+
#if defined(__linux__)
200+
return realpath("/proc/self/exe", NULL);
201+
202+
#elif defined(__APPLE__) && defined(__MACH__)
203+
uint32_t size = 0;
204+
_NSGetExecutablePath(NULL, &size);
205+
char *buf = malloc(size);
206+
if (!buf)
207+
return NULL;
208+
209+
if (_NSGetExecutablePath(buf, &size) == 0) {
210+
char *canonical = realpath(buf, NULL);
211+
free(buf);
212+
return canonical;
213+
}
214+
free(buf);
215+
return NULL;
216+
217+
#else /* Unsupported */
218+
return NULL;
219+
#endif
220+
}

src/runtime/windows/extra.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
#include <conio.h>
55
#include <io.h>
6+
#include <stdlib.h>
7+
#include <windows.h>
68

79
/*
810
* Find First Set
@@ -154,3 +156,28 @@ tmpname(const char* prefix, const char* suffix)
154156
return filename;
155157
}
156158
#define TMPNAME tmpname
159+
160+
/* Return path to executable as a null-terminated UTF-8 string. */
161+
char*
162+
get_executable_path(void) {
163+
DWORD size = MAX_PATH;
164+
WCHAR *wbuf = malloc(size * sizeof(WCHAR));
165+
if (!wbuf) return NULL;
166+
167+
DWORD len = GetModuleFileNameW(NULL, wbuf, size);
168+
while (len == size && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
169+
size *= 2;
170+
WCHAR *new_buf = realloc(wbuf, size * sizeof(WCHAR));
171+
if (!new_buf) { free(wbuf); return NULL; }
172+
wbuf = new_buf;
173+
len = GetModuleFileNameW(NULL, wbuf, size);
174+
}
175+
176+
int utf8_len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL, NULL);
177+
char *utf8_buf = malloc(utf8_len);
178+
if (utf8_buf) {
179+
WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, utf8_buf, utf8_len, NULL, NULL);
180+
}
181+
free(wbuf);
182+
return utf8_buf;
183+
}

0 commit comments

Comments
 (0)