Skip to content

Commit ced05c4

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 ced05c4

File tree

4 files changed

+134
-0
lines changed

4 files changed

+134
-0
lines changed

cutils.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,111 @@ int64_t js__gettimeofday_us(void) {
12011201
return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
12021202
}
12031203

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

12061311
#if JS_HAVE_THREADS

cutils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ extern "C" {
5454
#include <errno.h>
5555
#include <pthread.h>
5656
#endif
57+
#if !defined(_WIN32)
58+
#include <limits.h>
59+
#endif
5760

5861
#if defined(_MSC_VER) && !defined(__clang__)
5962
# define likely(x) (x)
@@ -118,6 +121,14 @@ extern "C" {
118121
#endif
119122
#endif
120123

124+
#if defined(PATH_MAX)
125+
# define JS__PATH_MAX PATH_MAX
126+
#elif defined(_WIN32)
127+
# define JS__PATH_MAX 32767
128+
#else
129+
# define JS__PATH_MAX 8192
130+
#endif
131+
121132
void js__pstrcpy(char *buf, int buf_size, const char *str);
122133
char *js__pstrcat(char *buf, int buf_size, const char *s);
123134
int js__strstart(const char *str, const char *val, const char **ptr);
@@ -581,6 +592,8 @@ static inline size_t js__malloc_usable_size(const void *ptr)
581592
#endif
582593
}
583594

595+
int js_exepath(char* buffer, size_t* size);
596+
584597
/* Cross-platform threading APIs. */
585598

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

docs/docs/stdlib.md

Lines changed: 4 additions & 0 deletions
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

Lines changed: 12 additions & 0 deletions
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)