Skip to content

Commit 16785cd

Browse files
committed
Add os.exePath
It gets the current executable path. Implementation lifted from libuv. Currently implemented for the following platforms: - Linux - macOS - Windows
1 parent f4bfcb0 commit 16785cd

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed

cutils.c

+106
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#include <windows.h>
3636
#include <process.h> // _beginthread
3737
#endif
38+
#if defined(__APPLE__)
39+
#include <mach-o/dyld.h>
40+
#endif
3841

3942
#include "cutils.h"
4043

@@ -1201,6 +1204,109 @@ int64_t js__gettimeofday_us(void) {
12011204
return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
12021205
}
12031206

1207+
#if defined(_WIN32)
1208+
int js_exepath(char *buffer, size_t *size_ptr) {
1209+
int utf8_len, utf16_buffer_len, utf16_len;
1210+
WCHAR* utf16_buffer;
1211+
1212+
if (buffer == NULL || size_ptr == NULL || *size_ptr == 0)
1213+
return -1;
1214+
1215+
if (*size_ptr > 32768) {
1216+
/* Windows paths can never be longer than this. */
1217+
utf16_buffer_len = 32768;
1218+
} else {
1219+
utf16_buffer_len = (int)*size_ptr;
1220+
}
1221+
1222+
utf16_buffer = malloc(sizeof(WCHAR) * utf16_buffer_len);
1223+
if (!utf16_buffer)
1224+
return -1;
1225+
1226+
/* Get the path as UTF-16. */
1227+
utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
1228+
if (utf16_len <= 0)
1229+
goto error;
1230+
1231+
/* Convert to UTF-8 */
1232+
utf8_len = WideCharToMultiByte(CP_UTF8,
1233+
0,
1234+
utf16_buffer,
1235+
-1,
1236+
buffer,
1237+
(int)*size_ptr,
1238+
NULL,
1239+
NULL);
1240+
if (utf8_len == 0)
1241+
goto error;
1242+
1243+
free(utf16_buffer);
1244+
1245+
/* utf8_len *does* include the terminating null at this point, but the
1246+
* returned size shouldn't. */
1247+
*size_ptr = utf8_len - 1;
1248+
return 0;
1249+
1250+
error:
1251+
free(utf16_buffer);
1252+
return -1;
1253+
}
1254+
#elif defined(__APPLE__)
1255+
int js_exepath(char *buffer, size_t *size) {
1256+
/* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
1257+
char abspath[PATH_MAX * 2 + 1];
1258+
char exepath[PATH_MAX + 1];
1259+
uint32_t exepath_size;
1260+
size_t abspath_size;
1261+
1262+
if (buffer == NULL || size == NULL || *size == 0)
1263+
return -1;
1264+
1265+
exepath_size = sizeof(exepath);
1266+
if (_NSGetExecutablePath(exepath, &exepath_size))
1267+
return -1;
1268+
1269+
if (realpath(exepath, abspath) != abspath)
1270+
return -1;
1271+
1272+
abspath_size = strlen(abspath);
1273+
if (abspath_size == 0)
1274+
return -1;
1275+
1276+
*size -= 1;
1277+
if (*size > abspath_size)
1278+
*size = abspath_size;
1279+
1280+
memcpy(buffer, abspath, *size);
1281+
buffer[*size] = '\0';
1282+
1283+
return 0;
1284+
}
1285+
#elif defined(__linux__)
1286+
int js_exepath(char *buffer, size_t *size) {
1287+
ssize_t n;
1288+
1289+
if (buffer == NULL || size == NULL || *size == 0)
1290+
return -1;
1291+
1292+
n = *size - 1;
1293+
if (n > 0)
1294+
n = readlink("/proc/self/exe", buffer, n);
1295+
1296+
if (n == -1)
1297+
return n;
1298+
1299+
buffer[n] = '\0';
1300+
*size = n;
1301+
1302+
return 0;
1303+
}
1304+
#else
1305+
int js_exepath(char* buffer, size_t* size_ptr) {
1306+
return -1;
1307+
}
1308+
#endif
1309+
12041310
/*--- Cross-platform threading APIs. ----*/
12051311

12061312
#if JS_HAVE_THREADS

cutils.h

+14
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ extern "C" {
5454
#include <errno.h>
5555
#include <pthread.h>
5656
#endif
57+
#if !defined(_WIN32)
58+
#include <limits.h>
59+
#include <unistd.h>
60+
#endif
5761

5862
#if defined(_MSC_VER) && !defined(__clang__)
5963
# define likely(x) (x)
@@ -118,6 +122,14 @@ extern "C" {
118122
#endif
119123
#endif
120124

125+
#if defined(PATH_MAX)
126+
# define JS__PATH_MAX PATH_MAX
127+
#elif defined(_WIN32)
128+
# define JS__PATH_MAX 32767
129+
#else
130+
# define JS__PATH_MAX 8192
131+
#endif
132+
121133
void js__pstrcpy(char *buf, int buf_size, const char *str);
122134
char *js__pstrcat(char *buf, int buf_size, const char *s);
123135
int js__strstart(const char *str, const char *val, const char **ptr);
@@ -581,6 +593,8 @@ static inline size_t js__malloc_usable_size(const void *ptr)
581593
#endif
582594
}
583595

596+
int js_exepath(char* buffer, size_t* size);
597+
584598
/* Cross-platform threading APIs. */
585599

586600
#if defined(EMSCRIPTEN) || defined(__wasi__)

docs/docs/stdlib.md

+4
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ pathname of `path` and `err` the error code.
143143
Return `[str, err]` where `str` is the current working directory
144144
and `err` the error code.
145145

146+
### `exePath()`
147+
148+
Returns the full path of the current executable or `undefined` if not available / supported.
149+
146150
### `chdir(path)`
147151

148152
Change the current directory. Return 0 if OK or `-errno`.

quickjs-libc.c

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2323
* THE SOFTWARE.
2424
*/
25+
#include "quickjs.h"
2526
#include <stdlib.h>
2627
#include <stdio.h>
2728
#include <stdarg.h>
@@ -2237,6 +2238,16 @@ static JSValue js_os_cputime(JSContext *ctx, JSValueConst this_val,
22372238
}
22382239
#endif
22392240

2241+
static JSValue js_os_exepath(JSContext *ctx, JSValueConst this_val,
2242+
int argc, JSValueConst *argv)
2243+
{
2244+
char buf[JS__PATH_MAX];
2245+
size_t len = sizeof(buf);
2246+
if (js_exepath(buf, &len))
2247+
return JS_UNDEFINED;
2248+
return JS_NewStringLen(ctx, buf, len);
2249+
}
2250+
22402251
static JSValue js_os_now(JSContext *ctx, JSValueConst this_val,
22412252
int argc, JSValueConst *argv)
22422253
{
@@ -4023,6 +4034,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
40234034
OS_FLAG(SIGTTOU),
40244035
JS_CFUNC_DEF("cputime", 0, js_os_cputime ),
40254036
#endif
4037+
JS_CFUNC_DEF("exePath", 0, js_os_exepath ),
40264038
JS_CFUNC_DEF("now", 0, js_os_now ),
40274039
JS_CFUNC_MAGIC_DEF("setTimeout", 2, js_os_setTimeout, 0 ),
40284040
JS_CFUNC_MAGIC_DEF("setInterval", 2, js_os_setTimeout, 1 ),

0 commit comments

Comments
 (0)