@zappdev/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/dist/zapp-cli.js +9471 -0
- package/native/src/app/app.zc +490 -0
- package/native/src/event/event.zc +24 -0
- package/native/src/event/events.zc +70 -0
- package/native/src/platform/darwin/backend.zc +923 -0
- package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
- package/native/src/platform/darwin/bootstrap.zc +9 -0
- package/native/src/platform/darwin/engine_jsc.zc +86 -0
- package/native/src/platform/darwin/engine_qjs.zc +92 -0
- package/native/src/platform/darwin/platform.zc +156 -0
- package/native/src/platform/darwin/webview.zc +550 -0
- package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
- package/native/src/platform/darwin/window.zc +1223 -0
- package/native/src/platform/darwin/worker/common.zc +223 -0
- package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
- package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
- package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
- package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
- package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
- package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
- package/native/src/platform/darwin/worker/dispatch.zc +55 -0
- package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
- package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
- package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
- package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
- package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
- package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
- package/native/src/platform/darwin/worker/jsc.zc +670 -0
- package/native/src/platform/darwin/worker/mod.zc +30 -0
- package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
- package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
- package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
- package/native/src/platform/darwin/worker/qjs.zc +1053 -0
- package/native/src/platform/darwin/worker/timers.zc +149 -0
- package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
- package/native/src/platform/platform.zc +64 -0
- package/native/src/platform/shared/log.zc +156 -0
- package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
- package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
- package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
- package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
- package/native/src/platform/shared/worker_registry.zc +206 -0
- package/native/src/platform/window.zc +446 -0
- package/native/src/platform/windows/backend.zc +452 -0
- package/native/src/platform/windows/backend_bootstrap.zc +9 -0
- package/native/src/platform/windows/bootstrap.zc +9 -0
- package/native/src/platform/windows/engine_qjs.zc +60 -0
- package/native/src/platform/windows/platform.zc +387 -0
- package/native/src/platform/windows/webview.zc +1175 -0
- package/native/src/platform/windows/webview_bootstrap.zc +9 -0
- package/native/src/platform/windows/window.zc +1271 -0
- package/native/src/platform/windows/worker/common.zc +409 -0
- package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
- package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
- package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
- package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
- package/native/src/platform/windows/worker/core/url_core.zc +216 -0
- package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
- package/native/src/platform/windows/worker/dispatch.zc +34 -0
- package/native/src/platform/windows/worker/mod.zc +46 -0
- package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
- package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
- package/native/src/platform/windows/worker/qjs.zc +1049 -0
- package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
- package/native/src/platform/worker.zc +8 -0
- package/native/src/service/service.zc +228 -0
- package/native/vendor/quickjs-ng/.gitattributes +4 -0
- package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
- package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
- package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
- package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
- package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
- package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
- package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
- package/native/vendor/quickjs-ng/.gitmodules +5 -0
- package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
- package/native/vendor/quickjs-ng/LICENSE +24 -0
- package/native/vendor/quickjs-ng/Makefile +149 -0
- package/native/vendor/quickjs-ng/amalgam.js +53 -0
- package/native/vendor/quickjs-ng/api-test.c +927 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
- package/native/vendor/quickjs-ng/ctest.c +17 -0
- package/native/vendor/quickjs-ng/cutils.h +2013 -0
- package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
- package/native/vendor/quickjs-ng/dtoa.c +1619 -0
- package/native/vendor/quickjs-ng/dtoa.h +87 -0
- package/native/vendor/quickjs-ng/examples/fib.c +67 -0
- package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
- package/native/vendor/quickjs-ng/examples/hello.js +1 -0
- package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
- package/native/vendor/quickjs-ng/examples/meson.build +17 -0
- package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
- package/native/vendor/quickjs-ng/examples/point.c +154 -0
- package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
- package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
- package/native/vendor/quickjs-ng/fuzz.c +51 -0
- package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/native/vendor/quickjs-ng/gen/hello.c +53 -0
- package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
- package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
- package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
- package/native/vendor/quickjs-ng/libregexp.c +2687 -0
- package/native/vendor/quickjs-ng/libregexp.h +98 -0
- package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
- package/native/vendor/quickjs-ng/libunicode.c +1746 -0
- package/native/vendor/quickjs-ng/libunicode.h +126 -0
- package/native/vendor/quickjs-ng/list.h +107 -0
- package/native/vendor/quickjs-ng/lre-test.c +73 -0
- package/native/vendor/quickjs-ng/meson.build +684 -0
- package/native/vendor/quickjs-ng/meson_options.txt +6 -0
- package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
- package/native/vendor/quickjs-ng/qjs.c +748 -0
- package/native/vendor/quickjs-ng/qjsc.c +673 -0
- package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
- package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
- package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
- package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
- package/native/vendor/quickjs-ng/quickjs.c +60259 -0
- package/native/vendor/quickjs-ng/quickjs.h +1419 -0
- package/native/vendor/quickjs-ng/repl.js +1927 -0
- package/native/vendor/quickjs-ng/run-test262.c +2417 -0
- package/native/vendor/quickjs-ng/standalone.js +129 -0
- package/native/vendor/quickjs-ng/tests/assert.js +49 -0
- package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
- package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
- package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
- package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
- package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
- package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
- package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
- package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
- package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
- package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
- package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
- package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
- package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
- package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
- package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
- package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
- package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
- package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
- package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
- package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
- package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
- package/native/vendor/quickjs-ng/tests/empty.js +0 -0
- package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
- package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
- package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
- package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
- package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
- package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
- package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
- package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
- package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
- package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
- package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
- package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
- package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
- package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
- package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
- package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
- package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
- package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
- package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
- package/native/vendor/quickjs-ng/tests.conf +14 -0
- package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
- package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
- package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/native/vendor/quickjs-ng/update-version.sh +32 -0
- package/native/vendor/webview2/include/WebView2.h +60636 -0
- package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
- package/package.json +33 -0
- package/src/backend.ts +139 -0
- package/src/build-config.ts +87 -0
- package/src/build.ts +276 -0
- package/src/common.ts +195 -0
- package/src/config.ts +89 -0
- package/src/dev.ts +164 -0
- package/src/generate.ts +200 -0
- package/src/icons.ts +116 -0
- package/src/init.ts +190 -0
- package/src/package.ts +150 -0
- package/src/zapp-cli.ts +263 -0
|
@@ -0,0 +1,4986 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* QuickJS C library
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2017-2021 Fabrice Bellard
|
|
5
|
+
* Copyright (c) 2017-2021 Charlie Gordon
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
#include "quickjs.h"
|
|
26
|
+
#include <stdlib.h>
|
|
27
|
+
#include <stdio.h>
|
|
28
|
+
#include <stdarg.h>
|
|
29
|
+
#include <inttypes.h>
|
|
30
|
+
#include <string.h>
|
|
31
|
+
#include <assert.h>
|
|
32
|
+
#include <errno.h>
|
|
33
|
+
#include <fcntl.h>
|
|
34
|
+
#if !defined(_MSC_VER)
|
|
35
|
+
#include <sys/time.h>
|
|
36
|
+
#include <unistd.h>
|
|
37
|
+
#endif
|
|
38
|
+
#include <time.h>
|
|
39
|
+
#include <signal.h>
|
|
40
|
+
#include <limits.h>
|
|
41
|
+
#include <sys/stat.h>
|
|
42
|
+
#if !defined(_MSC_VER)
|
|
43
|
+
#include <dirent.h>
|
|
44
|
+
#endif
|
|
45
|
+
#if defined(_WIN32)
|
|
46
|
+
#include <windows.h>
|
|
47
|
+
#include <direct.h>
|
|
48
|
+
#include <io.h>
|
|
49
|
+
#include <conio.h>
|
|
50
|
+
#include <sys/stat.h>
|
|
51
|
+
#include <sys/types.h>
|
|
52
|
+
#include <sys/utime.h>
|
|
53
|
+
#define popen _popen
|
|
54
|
+
#define pclose _pclose
|
|
55
|
+
#define rmdir _rmdir
|
|
56
|
+
#define getcwd _getcwd
|
|
57
|
+
#define chdir _chdir
|
|
58
|
+
#else
|
|
59
|
+
#include <sys/ioctl.h>
|
|
60
|
+
#include <poll.h>
|
|
61
|
+
#if !defined(__wasi__)
|
|
62
|
+
#include <dlfcn.h>
|
|
63
|
+
#include <termios.h>
|
|
64
|
+
#include <sys/resource.h>
|
|
65
|
+
#include <sys/wait.h>
|
|
66
|
+
#include <grp.h>
|
|
67
|
+
#endif
|
|
68
|
+
|
|
69
|
+
#if defined(__APPLE__)
|
|
70
|
+
typedef sig_t sighandler_t;
|
|
71
|
+
#include <crt_externs.h>
|
|
72
|
+
#include <TargetConditionals.h>
|
|
73
|
+
#define environ (*_NSGetEnviron())
|
|
74
|
+
#endif
|
|
75
|
+
|
|
76
|
+
#ifdef __sun
|
|
77
|
+
typedef void (*sighandler_t)(int);
|
|
78
|
+
extern char **environ;
|
|
79
|
+
#endif
|
|
80
|
+
|
|
81
|
+
#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
|
82
|
+
typedef sig_t sighandler_t;
|
|
83
|
+
extern char **environ;
|
|
84
|
+
#endif
|
|
85
|
+
|
|
86
|
+
#endif /* _WIN32 */
|
|
87
|
+
|
|
88
|
+
#include "cutils.h"
|
|
89
|
+
#include "list.h"
|
|
90
|
+
#include "quickjs-libc.h"
|
|
91
|
+
|
|
92
|
+
#if JS_HAVE_THREADS
|
|
93
|
+
#include "quickjs-c-atomics.h"
|
|
94
|
+
#define USE_WORKER // enable os.Worker
|
|
95
|
+
#endif
|
|
96
|
+
|
|
97
|
+
#ifndef S_IFBLK
|
|
98
|
+
#define S_IFBLK 0
|
|
99
|
+
#endif
|
|
100
|
+
|
|
101
|
+
#ifndef S_IFIFO
|
|
102
|
+
#define S_IFIFO 0
|
|
103
|
+
#endif
|
|
104
|
+
|
|
105
|
+
#ifndef MAX_SAFE_INTEGER // already defined in amalgamation builds
|
|
106
|
+
#define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1)
|
|
107
|
+
#endif
|
|
108
|
+
|
|
109
|
+
#ifndef QJS_NATIVE_MODULE_SUFFIX
|
|
110
|
+
#ifdef _WIN32
|
|
111
|
+
#define QJS_NATIVE_MODULE_SUFFIX ".dll"
|
|
112
|
+
#else
|
|
113
|
+
#define QJS_NATIVE_MODULE_SUFFIX ".so"
|
|
114
|
+
#endif
|
|
115
|
+
#endif
|
|
116
|
+
|
|
117
|
+
/* TODO:
|
|
118
|
+
- add socket calls
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
typedef struct {
|
|
122
|
+
struct list_head link;
|
|
123
|
+
int fd;
|
|
124
|
+
JSValue rw_func[2];
|
|
125
|
+
} JSOSRWHandler;
|
|
126
|
+
|
|
127
|
+
typedef struct {
|
|
128
|
+
struct list_head link;
|
|
129
|
+
int sig_num;
|
|
130
|
+
JSValue func;
|
|
131
|
+
} JSOSSignalHandler;
|
|
132
|
+
|
|
133
|
+
typedef struct {
|
|
134
|
+
struct list_head link;
|
|
135
|
+
int64_t timer_id;
|
|
136
|
+
uint8_t repeats:1;
|
|
137
|
+
int64_t timeout;
|
|
138
|
+
int64_t delay;
|
|
139
|
+
JSValue func;
|
|
140
|
+
} JSOSTimer;
|
|
141
|
+
|
|
142
|
+
typedef struct {
|
|
143
|
+
struct list_head link;
|
|
144
|
+
JSValue promise;
|
|
145
|
+
JSValue reason;
|
|
146
|
+
} JSRejectedPromiseEntry;
|
|
147
|
+
|
|
148
|
+
#ifdef USE_WORKER
|
|
149
|
+
|
|
150
|
+
typedef struct {
|
|
151
|
+
struct list_head link;
|
|
152
|
+
uint8_t *data;
|
|
153
|
+
size_t data_len;
|
|
154
|
+
/* list of SharedArrayBuffers, necessary to free the message */
|
|
155
|
+
uint8_t **sab_tab;
|
|
156
|
+
size_t sab_tab_len;
|
|
157
|
+
} JSWorkerMessage;
|
|
158
|
+
|
|
159
|
+
typedef struct JSWaker {
|
|
160
|
+
#ifdef _WIN32
|
|
161
|
+
HANDLE handle;
|
|
162
|
+
#else
|
|
163
|
+
int read_fd;
|
|
164
|
+
int write_fd;
|
|
165
|
+
#endif
|
|
166
|
+
} JSWaker;
|
|
167
|
+
|
|
168
|
+
typedef struct {
|
|
169
|
+
int ref_count;
|
|
170
|
+
js_mutex_t mutex;
|
|
171
|
+
struct list_head msg_queue; /* list of JSWorkerMessage.link */
|
|
172
|
+
JSWaker waker;
|
|
173
|
+
} JSWorkerMessagePipe;
|
|
174
|
+
|
|
175
|
+
typedef struct {
|
|
176
|
+
struct list_head link;
|
|
177
|
+
JSWorkerMessagePipe *recv_pipe;
|
|
178
|
+
JSValue on_message_func;
|
|
179
|
+
} JSWorkerMessageHandler;
|
|
180
|
+
|
|
181
|
+
#endif // USE_WORKER
|
|
182
|
+
|
|
183
|
+
typedef struct JSThreadState {
|
|
184
|
+
struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
|
|
185
|
+
struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
|
|
186
|
+
struct list_head os_timers; /* list of JSOSTimer.link */
|
|
187
|
+
struct list_head port_list; /* list of JSWorkerMessageHandler.link */
|
|
188
|
+
struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */
|
|
189
|
+
int eval_script_recurse; /* only used in the main thread */
|
|
190
|
+
int64_t next_timer_id; /* for setTimeout / setInterval */
|
|
191
|
+
bool can_js_os_poll;
|
|
192
|
+
/* not used in the main thread */
|
|
193
|
+
#ifdef USE_WORKER
|
|
194
|
+
JSWorkerMessagePipe *recv_pipe, *send_pipe;
|
|
195
|
+
#else
|
|
196
|
+
void *recv_pipe;
|
|
197
|
+
#endif // USE_WORKER
|
|
198
|
+
JSClassID std_file_class_id;
|
|
199
|
+
JSClassID worker_class_id;
|
|
200
|
+
} JSThreadState;
|
|
201
|
+
|
|
202
|
+
static uint64_t os_pending_signals;
|
|
203
|
+
|
|
204
|
+
static void *js_std_dbuf_realloc(void *opaque, void *ptr, size_t size)
|
|
205
|
+
{
|
|
206
|
+
JSRuntime *rt = opaque;
|
|
207
|
+
return js_realloc_rt(rt, ptr, size);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
static void js_std_dbuf_init(JSContext *ctx, DynBuf *s)
|
|
211
|
+
{
|
|
212
|
+
dbuf_init2(s, JS_GetRuntime(ctx), js_std_dbuf_realloc);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static bool my_isdigit(int c)
|
|
216
|
+
{
|
|
217
|
+
return (c >= '0' && c <= '9');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static JSThreadState *js_get_thread_state(JSRuntime *rt)
|
|
221
|
+
{
|
|
222
|
+
return (JSThreadState *)js_std_cmd(/*GetOpaque*/0, rt);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
static void js_set_thread_state(JSRuntime *rt, JSThreadState *ts)
|
|
226
|
+
{
|
|
227
|
+
js_std_cmd(/*SetOpaque*/1, rt, ts);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#ifdef __GNUC__
|
|
231
|
+
#pragma GCC diagnostic push
|
|
232
|
+
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
|
233
|
+
#endif // __GNUC__
|
|
234
|
+
static JSValue js_printf_internal(JSContext *ctx,
|
|
235
|
+
int argc, JSValueConst *argv, FILE *fp)
|
|
236
|
+
{
|
|
237
|
+
char fmtbuf[32];
|
|
238
|
+
uint8_t cbuf[UTF8_CHAR_LEN_MAX+1];
|
|
239
|
+
JSValue res;
|
|
240
|
+
DynBuf dbuf;
|
|
241
|
+
const char *fmt_str = NULL;
|
|
242
|
+
const uint8_t *fmt, *fmt_end;
|
|
243
|
+
const uint8_t *p;
|
|
244
|
+
char *q;
|
|
245
|
+
int i, c, len, mod;
|
|
246
|
+
size_t fmt_len;
|
|
247
|
+
int32_t int32_arg;
|
|
248
|
+
int64_t int64_arg;
|
|
249
|
+
double double_arg;
|
|
250
|
+
const char *string_arg;
|
|
251
|
+
|
|
252
|
+
js_std_dbuf_init(ctx, &dbuf);
|
|
253
|
+
|
|
254
|
+
if (argc > 0) {
|
|
255
|
+
fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]);
|
|
256
|
+
if (!fmt_str)
|
|
257
|
+
goto fail;
|
|
258
|
+
|
|
259
|
+
i = 1;
|
|
260
|
+
fmt = (const uint8_t *)fmt_str;
|
|
261
|
+
fmt_end = fmt + fmt_len;
|
|
262
|
+
while (fmt < fmt_end) {
|
|
263
|
+
for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++)
|
|
264
|
+
continue;
|
|
265
|
+
dbuf_put(&dbuf, p, fmt - p);
|
|
266
|
+
if (fmt >= fmt_end)
|
|
267
|
+
break;
|
|
268
|
+
q = fmtbuf;
|
|
269
|
+
*q++ = *fmt++; /* copy '%' */
|
|
270
|
+
|
|
271
|
+
/* flags */
|
|
272
|
+
for(;;) {
|
|
273
|
+
c = *fmt;
|
|
274
|
+
if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||
|
|
275
|
+
c == '\'') {
|
|
276
|
+
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
277
|
+
goto invalid;
|
|
278
|
+
*q++ = c;
|
|
279
|
+
fmt++;
|
|
280
|
+
} else {
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
/* width */
|
|
285
|
+
if (*fmt == '*') {
|
|
286
|
+
if (i >= argc)
|
|
287
|
+
goto missing;
|
|
288
|
+
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
|
289
|
+
goto fail;
|
|
290
|
+
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
|
|
291
|
+
fmt++;
|
|
292
|
+
} else {
|
|
293
|
+
while (my_isdigit(*fmt)) {
|
|
294
|
+
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
295
|
+
goto invalid;
|
|
296
|
+
*q++ = *fmt++;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (*fmt == '.') {
|
|
300
|
+
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
301
|
+
goto invalid;
|
|
302
|
+
*q++ = *fmt++;
|
|
303
|
+
if (*fmt == '*') {
|
|
304
|
+
if (i >= argc)
|
|
305
|
+
goto missing;
|
|
306
|
+
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
|
307
|
+
goto fail;
|
|
308
|
+
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
|
|
309
|
+
fmt++;
|
|
310
|
+
} else {
|
|
311
|
+
while (my_isdigit(*fmt)) {
|
|
312
|
+
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
313
|
+
goto invalid;
|
|
314
|
+
*q++ = *fmt++;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* we only support the "l" modifier for 64 bit numbers */
|
|
320
|
+
mod = ' ';
|
|
321
|
+
if (*fmt == 'l') {
|
|
322
|
+
mod = *fmt++;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* type */
|
|
326
|
+
c = *fmt++;
|
|
327
|
+
if (q >= fmtbuf + sizeof(fmtbuf) - 1)
|
|
328
|
+
goto invalid;
|
|
329
|
+
*q++ = c;
|
|
330
|
+
*q = '\0';
|
|
331
|
+
|
|
332
|
+
switch (c) {
|
|
333
|
+
case 'c':
|
|
334
|
+
if (i >= argc)
|
|
335
|
+
goto missing;
|
|
336
|
+
if (JS_IsString(argv[i])) {
|
|
337
|
+
// TODO(chqrlie) need an API to wrap charCodeAt and codePointAt */
|
|
338
|
+
string_arg = JS_ToCString(ctx, argv[i++]);
|
|
339
|
+
if (!string_arg)
|
|
340
|
+
goto fail;
|
|
341
|
+
int32_arg = utf8_decode((const uint8_t *)string_arg, &p);
|
|
342
|
+
JS_FreeCString(ctx, string_arg);
|
|
343
|
+
} else {
|
|
344
|
+
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
|
345
|
+
goto fail;
|
|
346
|
+
}
|
|
347
|
+
// XXX: throw an exception?
|
|
348
|
+
if ((unsigned)int32_arg > 0x10FFFF)
|
|
349
|
+
int32_arg = 0xFFFD;
|
|
350
|
+
/* ignore conversion flags, width and precision */
|
|
351
|
+
len = utf8_encode(cbuf, int32_arg);
|
|
352
|
+
dbuf_put(&dbuf, cbuf, len);
|
|
353
|
+
break;
|
|
354
|
+
|
|
355
|
+
case 'd':
|
|
356
|
+
case 'i':
|
|
357
|
+
case 'o':
|
|
358
|
+
case 'u':
|
|
359
|
+
case 'x':
|
|
360
|
+
case 'X':
|
|
361
|
+
if (i >= argc)
|
|
362
|
+
goto missing;
|
|
363
|
+
if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
|
|
364
|
+
goto fail;
|
|
365
|
+
if (mod == 'l') {
|
|
366
|
+
/* 64 bit number */
|
|
367
|
+
#if defined(_WIN32)
|
|
368
|
+
if (q >= fmtbuf + sizeof(fmtbuf) - 3)
|
|
369
|
+
goto invalid;
|
|
370
|
+
q[2] = q[-1];
|
|
371
|
+
q[-1] = 'I';
|
|
372
|
+
q[0] = '6';
|
|
373
|
+
q[1] = '4';
|
|
374
|
+
q[3] = '\0';
|
|
375
|
+
dbuf_printf(&dbuf, fmtbuf, (int64_t)int64_arg);
|
|
376
|
+
#else
|
|
377
|
+
if (q >= fmtbuf + sizeof(fmtbuf) - 2)
|
|
378
|
+
goto invalid;
|
|
379
|
+
q[1] = q[-1];
|
|
380
|
+
q[-1] = q[0] = 'l';
|
|
381
|
+
q[2] = '\0';
|
|
382
|
+
dbuf_printf(&dbuf, fmtbuf, (long long)int64_arg);
|
|
383
|
+
#endif
|
|
384
|
+
} else {
|
|
385
|
+
dbuf_printf(&dbuf, fmtbuf, (int)int64_arg);
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
|
|
389
|
+
case 's':
|
|
390
|
+
if (i >= argc)
|
|
391
|
+
goto missing;
|
|
392
|
+
/* XXX: handle strings containing null characters */
|
|
393
|
+
string_arg = JS_ToCString(ctx, argv[i++]);
|
|
394
|
+
if (!string_arg)
|
|
395
|
+
goto fail;
|
|
396
|
+
dbuf_printf(&dbuf, fmtbuf, string_arg);
|
|
397
|
+
JS_FreeCString(ctx, string_arg);
|
|
398
|
+
break;
|
|
399
|
+
|
|
400
|
+
case 'e':
|
|
401
|
+
case 'f':
|
|
402
|
+
case 'g':
|
|
403
|
+
case 'a':
|
|
404
|
+
case 'E':
|
|
405
|
+
case 'F':
|
|
406
|
+
case 'G':
|
|
407
|
+
case 'A':
|
|
408
|
+
if (i >= argc)
|
|
409
|
+
goto missing;
|
|
410
|
+
if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
|
|
411
|
+
goto fail;
|
|
412
|
+
dbuf_printf(&dbuf, fmtbuf, double_arg);
|
|
413
|
+
break;
|
|
414
|
+
|
|
415
|
+
case '%':
|
|
416
|
+
dbuf_putc(&dbuf, '%');
|
|
417
|
+
break;
|
|
418
|
+
|
|
419
|
+
default:
|
|
420
|
+
/* XXX: should support an extension mechanism */
|
|
421
|
+
invalid:
|
|
422
|
+
JS_ThrowTypeError(ctx, "invalid conversion specifier in format string");
|
|
423
|
+
goto fail;
|
|
424
|
+
missing:
|
|
425
|
+
JS_ThrowReferenceError(ctx, "missing argument for conversion specifier");
|
|
426
|
+
goto fail;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
JS_FreeCString(ctx, fmt_str);
|
|
430
|
+
}
|
|
431
|
+
if (dbuf.error) {
|
|
432
|
+
res = JS_ThrowOutOfMemory(ctx);
|
|
433
|
+
} else {
|
|
434
|
+
if (fp) {
|
|
435
|
+
len = fwrite(dbuf.buf, 1, dbuf.size, fp);
|
|
436
|
+
res = JS_NewInt32(ctx, len);
|
|
437
|
+
} else {
|
|
438
|
+
res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
dbuf_free(&dbuf);
|
|
442
|
+
return res;
|
|
443
|
+
|
|
444
|
+
fail:
|
|
445
|
+
JS_FreeCString(ctx, fmt_str);
|
|
446
|
+
dbuf_free(&dbuf);
|
|
447
|
+
return JS_EXCEPTION;
|
|
448
|
+
}
|
|
449
|
+
#ifdef __GNUC__
|
|
450
|
+
#pragma GCC diagnostic pop // ignored "-Wformat-nonliteral"
|
|
451
|
+
#endif // __GNUC__
|
|
452
|
+
|
|
453
|
+
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)
|
|
454
|
+
{
|
|
455
|
+
FILE *f;
|
|
456
|
+
size_t n, len;
|
|
457
|
+
uint8_t *p, *buf, tmp[8192];
|
|
458
|
+
|
|
459
|
+
f = fopen(filename, "rb");
|
|
460
|
+
if (!f)
|
|
461
|
+
return NULL;
|
|
462
|
+
buf = NULL;
|
|
463
|
+
len = 0;
|
|
464
|
+
do {
|
|
465
|
+
n = fread(tmp, 1, sizeof(tmp), f);
|
|
466
|
+
if (ctx) {
|
|
467
|
+
p = js_realloc(ctx, buf, len + n + 1);
|
|
468
|
+
} else {
|
|
469
|
+
p = realloc(buf, len + n + 1);
|
|
470
|
+
}
|
|
471
|
+
if (!p) {
|
|
472
|
+
if (ctx) {
|
|
473
|
+
js_free(ctx, buf);
|
|
474
|
+
} else {
|
|
475
|
+
free(buf);
|
|
476
|
+
}
|
|
477
|
+
fclose(f);
|
|
478
|
+
return NULL;
|
|
479
|
+
}
|
|
480
|
+
memcpy(&p[len], tmp, n);
|
|
481
|
+
buf = p;
|
|
482
|
+
len += n;
|
|
483
|
+
buf[len] = '\0';
|
|
484
|
+
} while (n == sizeof(tmp));
|
|
485
|
+
fclose(f);
|
|
486
|
+
*pbuf_len = len;
|
|
487
|
+
return buf;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* load and evaluate a file */
|
|
491
|
+
static JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,
|
|
492
|
+
int argc, JSValueConst *argv)
|
|
493
|
+
{
|
|
494
|
+
uint8_t *buf;
|
|
495
|
+
const char *filename;
|
|
496
|
+
JSValue ret;
|
|
497
|
+
size_t buf_len;
|
|
498
|
+
|
|
499
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
500
|
+
if (!filename)
|
|
501
|
+
return JS_EXCEPTION;
|
|
502
|
+
buf = js_load_file(ctx, &buf_len, filename);
|
|
503
|
+
if (!buf) {
|
|
504
|
+
JS_ThrowReferenceError(ctx, "could not load '%s'", filename);
|
|
505
|
+
JS_FreeCString(ctx, filename);
|
|
506
|
+
return JS_EXCEPTION;
|
|
507
|
+
}
|
|
508
|
+
ret = JS_Eval(ctx, (char *)buf, buf_len, filename,
|
|
509
|
+
JS_EVAL_TYPE_GLOBAL);
|
|
510
|
+
js_free(ctx, buf);
|
|
511
|
+
JS_FreeCString(ctx, filename);
|
|
512
|
+
return ret;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
static int get_bool_option(JSContext *ctx, bool *pbool,
|
|
516
|
+
JSValueConst obj,
|
|
517
|
+
const char *option)
|
|
518
|
+
{
|
|
519
|
+
JSValue val;
|
|
520
|
+
val = JS_GetPropertyStr(ctx, obj, option);
|
|
521
|
+
if (JS_IsException(val))
|
|
522
|
+
return -1;
|
|
523
|
+
if (!JS_IsUndefined(val)) {
|
|
524
|
+
*pbool = JS_ToBool(ctx, val);
|
|
525
|
+
}
|
|
526
|
+
JS_FreeValue(ctx, val);
|
|
527
|
+
return 0;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
static void free_buf(JSRuntime *rt, void *opaque, void *ptr) {
|
|
531
|
+
js_free_rt(rt, ptr);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/* load a file as a UTF-8 encoded string or Uint8Array */
|
|
535
|
+
static JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,
|
|
536
|
+
int argc, JSValueConst *argv)
|
|
537
|
+
{
|
|
538
|
+
uint8_t *buf;
|
|
539
|
+
const char *filename;
|
|
540
|
+
JSValueConst options_obj;
|
|
541
|
+
JSValue ret;
|
|
542
|
+
size_t buf_len;
|
|
543
|
+
bool binary = false;
|
|
544
|
+
|
|
545
|
+
if (argc >= 2) {
|
|
546
|
+
options_obj = argv[1];
|
|
547
|
+
if (get_bool_option(ctx, &binary, options_obj,
|
|
548
|
+
"binary"))
|
|
549
|
+
return JS_EXCEPTION;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
553
|
+
if (!filename)
|
|
554
|
+
return JS_EXCEPTION;
|
|
555
|
+
buf = js_load_file(ctx, &buf_len, filename);
|
|
556
|
+
JS_FreeCString(ctx, filename);
|
|
557
|
+
if (!buf)
|
|
558
|
+
return JS_NULL;
|
|
559
|
+
if (binary) {
|
|
560
|
+
ret = JS_NewUint8Array(ctx, buf, buf_len, free_buf, NULL, false);
|
|
561
|
+
} else {
|
|
562
|
+
ret = JS_NewStringLen(ctx, (char *)buf, buf_len);
|
|
563
|
+
js_free(ctx, buf);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return ret;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
static JSValue js_std_writeFile(JSContext *ctx, JSValueConst this_val,
|
|
570
|
+
int argc, JSValueConst *argv)
|
|
571
|
+
{
|
|
572
|
+
const char *filename;
|
|
573
|
+
const char *mode;
|
|
574
|
+
const void *buf;
|
|
575
|
+
size_t len, n;
|
|
576
|
+
JSValueConst data;
|
|
577
|
+
JSValue val, ret, unref;
|
|
578
|
+
bool release;
|
|
579
|
+
FILE *fp;
|
|
580
|
+
|
|
581
|
+
ret = JS_EXCEPTION;
|
|
582
|
+
len = 0;
|
|
583
|
+
buf = "";
|
|
584
|
+
mode = "w";
|
|
585
|
+
data = argv[1];
|
|
586
|
+
unref = JS_UNDEFINED;
|
|
587
|
+
release = false;
|
|
588
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
589
|
+
if (!filename)
|
|
590
|
+
return JS_EXCEPTION;
|
|
591
|
+
if (JS_IsObject(data)) {
|
|
592
|
+
val = JS_GetPropertyStr(ctx, data, "buffer");
|
|
593
|
+
if (JS_IsException(val))
|
|
594
|
+
goto exception;
|
|
595
|
+
if (JS_IsArrayBuffer(val)) {
|
|
596
|
+
data = unref = val;
|
|
597
|
+
} else {
|
|
598
|
+
JS_FreeValue(ctx, val);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (JS_IsArrayBuffer(data)) {
|
|
602
|
+
buf = JS_GetArrayBuffer(ctx, &len, data);
|
|
603
|
+
mode = "wb";
|
|
604
|
+
} else if (!JS_IsUndefined(data)) {
|
|
605
|
+
buf = JS_ToCStringLen(ctx, &len, data);
|
|
606
|
+
release = true;
|
|
607
|
+
}
|
|
608
|
+
if (!buf)
|
|
609
|
+
goto exception;
|
|
610
|
+
fp = fopen(filename, mode);
|
|
611
|
+
if (!fp) {
|
|
612
|
+
JS_ThrowPlainError(ctx, "error opening %s for writing", filename);
|
|
613
|
+
goto exception;
|
|
614
|
+
}
|
|
615
|
+
n = fwrite(buf, len, 1, fp);
|
|
616
|
+
fclose(fp);
|
|
617
|
+
if (n != 1) {
|
|
618
|
+
JS_ThrowPlainError(ctx, "error writing to %s", filename);
|
|
619
|
+
goto exception;
|
|
620
|
+
}
|
|
621
|
+
ret = JS_UNDEFINED;
|
|
622
|
+
exception:
|
|
623
|
+
JS_FreeCString(ctx, filename);
|
|
624
|
+
if (release)
|
|
625
|
+
JS_FreeCString(ctx, buf);
|
|
626
|
+
JS_FreeValue(ctx, unref);
|
|
627
|
+
return ret;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
|
|
631
|
+
const char *module_name);
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
#if defined(_WIN32)
|
|
635
|
+
static JSModuleDef *js_module_loader_so(JSContext *ctx,
|
|
636
|
+
const char *module_name)
|
|
637
|
+
{
|
|
638
|
+
JSModuleDef *m;
|
|
639
|
+
HINSTANCE hd;
|
|
640
|
+
JSInitModuleFunc *init;
|
|
641
|
+
char *filename = NULL;
|
|
642
|
+
size_t len = strlen(module_name);
|
|
643
|
+
bool is_absolute = len > 2 && ((module_name[0] >= 'A' && module_name[0] <= 'Z') ||
|
|
644
|
+
(module_name[0] >= 'a' && module_name[0] <= 'z')) && module_name[1] == ':';
|
|
645
|
+
bool is_relative = len > 2 && module_name[0] == '.' && (module_name[1] == '/' || module_name[1] == '\\');
|
|
646
|
+
if (is_absolute || is_relative) {
|
|
647
|
+
filename = (char *)module_name;
|
|
648
|
+
} else {
|
|
649
|
+
filename = js_malloc(ctx, len + 2 + 1);
|
|
650
|
+
if (!filename)
|
|
651
|
+
return NULL;
|
|
652
|
+
strcpy(filename, "./");
|
|
653
|
+
strcpy(filename + 2, module_name);
|
|
654
|
+
}
|
|
655
|
+
hd = LoadLibraryA(filename);
|
|
656
|
+
if (filename != module_name)
|
|
657
|
+
js_free(ctx, filename);
|
|
658
|
+
if (hd == NULL) {
|
|
659
|
+
JS_ThrowReferenceError(ctx, "js_load_module '%s' error: %lu",
|
|
660
|
+
module_name, GetLastError());
|
|
661
|
+
goto fail;
|
|
662
|
+
}
|
|
663
|
+
init = (JSInitModuleFunc *)(uintptr_t)GetProcAddress(hd, "js_init_module");
|
|
664
|
+
if (!init) {
|
|
665
|
+
JS_ThrowReferenceError(ctx, "js_init_module '%s' not found: %lu",
|
|
666
|
+
module_name, GetLastError());
|
|
667
|
+
goto fail;
|
|
668
|
+
}
|
|
669
|
+
m = init(ctx, module_name);
|
|
670
|
+
if (!m) {
|
|
671
|
+
JS_ThrowReferenceError(ctx, "js_call_module '%s' initialization error",
|
|
672
|
+
module_name);
|
|
673
|
+
fail:
|
|
674
|
+
if (hd != NULL)
|
|
675
|
+
FreeLibrary(hd);
|
|
676
|
+
return NULL;
|
|
677
|
+
}
|
|
678
|
+
return m;
|
|
679
|
+
}
|
|
680
|
+
#elif defined(__wasi__)
|
|
681
|
+
static JSModuleDef *js_module_loader_so(JSContext *ctx,
|
|
682
|
+
const char *module_name)
|
|
683
|
+
{
|
|
684
|
+
JS_ThrowReferenceError(ctx, "shared library modules are not supported yet");
|
|
685
|
+
return NULL;
|
|
686
|
+
}
|
|
687
|
+
#else
|
|
688
|
+
static JSModuleDef *js_module_loader_so(JSContext *ctx,
|
|
689
|
+
const char *module_name)
|
|
690
|
+
{
|
|
691
|
+
JSModuleDef *m;
|
|
692
|
+
void *hd;
|
|
693
|
+
JSInitModuleFunc *init;
|
|
694
|
+
char *filename;
|
|
695
|
+
|
|
696
|
+
if (!strchr(module_name, '/')) {
|
|
697
|
+
/* must add a '/' so that the DLL is not searched in the
|
|
698
|
+
system library paths */
|
|
699
|
+
filename = js_malloc(ctx, strlen(module_name) + 2 + 1);
|
|
700
|
+
if (!filename)
|
|
701
|
+
return NULL;
|
|
702
|
+
strcpy(filename, "./");
|
|
703
|
+
strcpy(filename + 2, module_name);
|
|
704
|
+
} else {
|
|
705
|
+
filename = (char *)module_name;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/* C module */
|
|
709
|
+
hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
|
|
710
|
+
if (filename != module_name)
|
|
711
|
+
js_free(ctx, filename);
|
|
712
|
+
if (!hd) {
|
|
713
|
+
JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library: %s",
|
|
714
|
+
module_name, dlerror());
|
|
715
|
+
goto fail;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
*(void **) (&init) = dlsym(hd, "js_init_module");
|
|
719
|
+
if (!init) {
|
|
720
|
+
JS_ThrowReferenceError(ctx, "could not load module filename '%s': js_init_module not found",
|
|
721
|
+
module_name);
|
|
722
|
+
goto fail;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
m = init(ctx, module_name);
|
|
726
|
+
if (!m) {
|
|
727
|
+
JS_ThrowReferenceError(ctx, "could not load module filename '%s': initialization error",
|
|
728
|
+
module_name);
|
|
729
|
+
fail:
|
|
730
|
+
if (hd)
|
|
731
|
+
dlclose(hd);
|
|
732
|
+
return NULL;
|
|
733
|
+
}
|
|
734
|
+
return m;
|
|
735
|
+
}
|
|
736
|
+
#endif /* !_WIN32 */
|
|
737
|
+
|
|
738
|
+
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
|
|
739
|
+
bool use_realpath, bool is_main)
|
|
740
|
+
{
|
|
741
|
+
JSModuleDef *m;
|
|
742
|
+
char buf[JS__PATH_MAX + 16];
|
|
743
|
+
JSValue meta_obj;
|
|
744
|
+
JSAtom module_name_atom;
|
|
745
|
+
const char *module_name;
|
|
746
|
+
|
|
747
|
+
assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);
|
|
748
|
+
m = JS_VALUE_GET_PTR(func_val);
|
|
749
|
+
|
|
750
|
+
module_name_atom = JS_GetModuleName(ctx, m);
|
|
751
|
+
module_name = JS_AtomToCString(ctx, module_name_atom);
|
|
752
|
+
JS_FreeAtom(ctx, module_name_atom);
|
|
753
|
+
if (!module_name)
|
|
754
|
+
return -1;
|
|
755
|
+
if (!strchr(module_name, ':')) {
|
|
756
|
+
strcpy(buf, "file://");
|
|
757
|
+
#if !defined(_WIN32) && !defined(__wasi__)
|
|
758
|
+
/* realpath() cannot be used with modules compiled with qjsc
|
|
759
|
+
because the corresponding module source code is not
|
|
760
|
+
necessarily present */
|
|
761
|
+
if (use_realpath) {
|
|
762
|
+
char *res = realpath(module_name, buf + strlen(buf));
|
|
763
|
+
if (!res) {
|
|
764
|
+
JS_ThrowTypeError(ctx, "realpath failure");
|
|
765
|
+
JS_FreeCString(ctx, module_name);
|
|
766
|
+
return -1;
|
|
767
|
+
}
|
|
768
|
+
} else
|
|
769
|
+
#endif
|
|
770
|
+
{
|
|
771
|
+
js__pstrcat(buf, sizeof(buf), module_name);
|
|
772
|
+
}
|
|
773
|
+
} else {
|
|
774
|
+
js__pstrcpy(buf, sizeof(buf), module_name);
|
|
775
|
+
}
|
|
776
|
+
JS_FreeCString(ctx, module_name);
|
|
777
|
+
|
|
778
|
+
meta_obj = JS_GetImportMeta(ctx, m);
|
|
779
|
+
if (JS_IsException(meta_obj))
|
|
780
|
+
return -1;
|
|
781
|
+
JS_DefinePropertyValueStr(ctx, meta_obj, "url",
|
|
782
|
+
JS_NewString(ctx, buf),
|
|
783
|
+
JS_PROP_C_W_E);
|
|
784
|
+
JS_DefinePropertyValueStr(ctx, meta_obj, "main",
|
|
785
|
+
JS_NewBool(ctx, is_main),
|
|
786
|
+
JS_PROP_C_W_E);
|
|
787
|
+
JS_FreeValue(ctx, meta_obj);
|
|
788
|
+
return 0;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
static int json_module_init(JSContext *ctx, JSModuleDef *m)
|
|
792
|
+
{
|
|
793
|
+
JSValue val;
|
|
794
|
+
val = JS_GetModulePrivateValue(ctx, m);
|
|
795
|
+
JS_SetModuleExport(ctx, m, "default", val);
|
|
796
|
+
return 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
static JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val)
|
|
800
|
+
{
|
|
801
|
+
JSModuleDef *m;
|
|
802
|
+
m = JS_NewCModule(ctx, module_name, json_module_init);
|
|
803
|
+
if (!m) {
|
|
804
|
+
JS_FreeValue(ctx, val);
|
|
805
|
+
return NULL;
|
|
806
|
+
}
|
|
807
|
+
/* only export the "default" symbol which will contain the JSON object */
|
|
808
|
+
JS_AddModuleExport(ctx, m, "default");
|
|
809
|
+
JS_SetModulePrivateValue(ctx, m, val);
|
|
810
|
+
return m;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/* in order to conform with the specification, only the keys should be
|
|
814
|
+
tested and not the associated values. */
|
|
815
|
+
int js_module_check_attributes(JSContext *ctx, void *opaque,
|
|
816
|
+
JSValueConst attributes)
|
|
817
|
+
{
|
|
818
|
+
JSPropertyEnum *tab;
|
|
819
|
+
uint32_t i, len;
|
|
820
|
+
int ret;
|
|
821
|
+
const char *cstr;
|
|
822
|
+
size_t cstr_len;
|
|
823
|
+
|
|
824
|
+
if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))
|
|
825
|
+
return -1;
|
|
826
|
+
ret = 0;
|
|
827
|
+
for(i = 0; i < len; i++) {
|
|
828
|
+
cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);
|
|
829
|
+
if (!cstr) {
|
|
830
|
+
ret = -1;
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) {
|
|
834
|
+
JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr);
|
|
835
|
+
ret = -1;
|
|
836
|
+
}
|
|
837
|
+
JS_FreeCString(ctx, cstr);
|
|
838
|
+
if (ret)
|
|
839
|
+
break;
|
|
840
|
+
}
|
|
841
|
+
JS_FreePropertyEnum(ctx, tab, len);
|
|
842
|
+
return ret;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/* return > 0 if the attributes indicate a JSON module, 0 otherwise, -1 on error */
|
|
846
|
+
int js_module_test_json(JSContext *ctx, JSValueConst attributes)
|
|
847
|
+
{
|
|
848
|
+
JSValue str;
|
|
849
|
+
const char *cstr;
|
|
850
|
+
size_t len;
|
|
851
|
+
int res;
|
|
852
|
+
|
|
853
|
+
if (JS_IsUndefined(attributes))
|
|
854
|
+
return 0;
|
|
855
|
+
str = JS_GetPropertyStr(ctx, attributes, "type");
|
|
856
|
+
if (JS_IsException(str))
|
|
857
|
+
return -1;
|
|
858
|
+
if (!JS_IsString(str)) {
|
|
859
|
+
JS_FreeValue(ctx, str);
|
|
860
|
+
return 0;
|
|
861
|
+
}
|
|
862
|
+
cstr = JS_ToCStringLen(ctx, &len, str);
|
|
863
|
+
JS_FreeValue(ctx, str);
|
|
864
|
+
if (!cstr)
|
|
865
|
+
return -1;
|
|
866
|
+
if (len == 4 && !memcmp(cstr, "json", len)) {
|
|
867
|
+
res = 1;
|
|
868
|
+
} else {
|
|
869
|
+
/* unknown type - throw error */
|
|
870
|
+
JS_ThrowTypeError(ctx, "unsupported module type: '%s'", cstr);
|
|
871
|
+
JS_FreeCString(ctx, cstr);
|
|
872
|
+
return -1;
|
|
873
|
+
}
|
|
874
|
+
JS_FreeCString(ctx, cstr);
|
|
875
|
+
return res;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
JSModuleDef *js_module_loader(JSContext *ctx,
|
|
879
|
+
const char *module_name, void *opaque,
|
|
880
|
+
JSValueConst attributes)
|
|
881
|
+
{
|
|
882
|
+
JSModuleDef *m;
|
|
883
|
+
|
|
884
|
+
if (js__has_suffix(module_name, QJS_NATIVE_MODULE_SUFFIX)) {
|
|
885
|
+
m = js_module_loader_so(ctx, module_name);
|
|
886
|
+
} else {
|
|
887
|
+
int res;
|
|
888
|
+
size_t buf_len;
|
|
889
|
+
uint8_t *buf;
|
|
890
|
+
|
|
891
|
+
res = js_module_test_json(ctx, attributes);
|
|
892
|
+
if (res < 0)
|
|
893
|
+
return NULL;
|
|
894
|
+
buf = js_load_file(ctx, &buf_len, module_name);
|
|
895
|
+
if (!buf) {
|
|
896
|
+
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
|
|
897
|
+
module_name);
|
|
898
|
+
return NULL;
|
|
899
|
+
}
|
|
900
|
+
if (js__has_suffix(module_name, ".json") || res > 0) {
|
|
901
|
+
/* compile as JSON */
|
|
902
|
+
JSValue val;
|
|
903
|
+
val = JS_ParseJSON(ctx, (char *)buf, buf_len, module_name);
|
|
904
|
+
js_free(ctx, buf);
|
|
905
|
+
if (JS_IsException(val))
|
|
906
|
+
return NULL;
|
|
907
|
+
m = create_json_module(ctx, module_name, val);
|
|
908
|
+
if (!m)
|
|
909
|
+
return NULL;
|
|
910
|
+
} else {
|
|
911
|
+
JSValue func_val;
|
|
912
|
+
/* compile the module */
|
|
913
|
+
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
|
|
914
|
+
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
|
915
|
+
js_free(ctx, buf);
|
|
916
|
+
if (JS_IsException(func_val))
|
|
917
|
+
return NULL;
|
|
918
|
+
if (js_module_set_import_meta(ctx, func_val, true, false) < 0) {
|
|
919
|
+
JS_FreeValue(ctx, func_val);
|
|
920
|
+
return NULL;
|
|
921
|
+
}
|
|
922
|
+
/* the module is already referenced, so we must free it */
|
|
923
|
+
m = JS_VALUE_GET_PTR(func_val);
|
|
924
|
+
JS_FreeValue(ctx, func_val);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
return m;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
static JSValue js_std_exit(JSContext *ctx, JSValueConst this_val,
|
|
931
|
+
int argc, JSValueConst *argv)
|
|
932
|
+
{
|
|
933
|
+
int status;
|
|
934
|
+
if (JS_ToInt32(ctx, &status, argv[0]))
|
|
935
|
+
status = -1;
|
|
936
|
+
exit(status);
|
|
937
|
+
return JS_UNDEFINED;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
static JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,
|
|
941
|
+
int argc, JSValueConst *argv)
|
|
942
|
+
{
|
|
943
|
+
const char *name, *str;
|
|
944
|
+
name = JS_ToCString(ctx, argv[0]);
|
|
945
|
+
if (!name)
|
|
946
|
+
return JS_EXCEPTION;
|
|
947
|
+
str = getenv(name);
|
|
948
|
+
JS_FreeCString(ctx, name);
|
|
949
|
+
if (!str)
|
|
950
|
+
return JS_UNDEFINED;
|
|
951
|
+
else
|
|
952
|
+
return JS_NewString(ctx, str);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
#if defined(_WIN32)
|
|
956
|
+
static void setenv(const char *name, const char *value, int overwrite)
|
|
957
|
+
{
|
|
958
|
+
char *str;
|
|
959
|
+
size_t name_len, value_len;
|
|
960
|
+
name_len = strlen(name);
|
|
961
|
+
value_len = strlen(value);
|
|
962
|
+
str = malloc(name_len + 1 + value_len + 1);
|
|
963
|
+
memcpy(str, name, name_len);
|
|
964
|
+
str[name_len] = '=';
|
|
965
|
+
memcpy(str + name_len + 1, value, value_len);
|
|
966
|
+
str[name_len + 1 + value_len] = '\0';
|
|
967
|
+
_putenv(str);
|
|
968
|
+
free(str);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
static void unsetenv(const char *name)
|
|
972
|
+
{
|
|
973
|
+
setenv(name, "", true);
|
|
974
|
+
}
|
|
975
|
+
#endif /* _WIN32 */
|
|
976
|
+
|
|
977
|
+
static JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,
|
|
978
|
+
int argc, JSValueConst *argv)
|
|
979
|
+
{
|
|
980
|
+
const char *name, *value;
|
|
981
|
+
name = JS_ToCString(ctx, argv[0]);
|
|
982
|
+
if (!name)
|
|
983
|
+
return JS_EXCEPTION;
|
|
984
|
+
value = JS_ToCString(ctx, argv[1]);
|
|
985
|
+
if (!value) {
|
|
986
|
+
JS_FreeCString(ctx, name);
|
|
987
|
+
return JS_EXCEPTION;
|
|
988
|
+
}
|
|
989
|
+
setenv(name, value, true);
|
|
990
|
+
JS_FreeCString(ctx, name);
|
|
991
|
+
JS_FreeCString(ctx, value);
|
|
992
|
+
return JS_UNDEFINED;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
|
|
996
|
+
int argc, JSValueConst *argv)
|
|
997
|
+
{
|
|
998
|
+
const char *name;
|
|
999
|
+
name = JS_ToCString(ctx, argv[0]);
|
|
1000
|
+
if (!name)
|
|
1001
|
+
return JS_EXCEPTION;
|
|
1002
|
+
unsetenv(name);
|
|
1003
|
+
JS_FreeCString(ctx, name);
|
|
1004
|
+
return JS_UNDEFINED;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/* return an object containing the list of the available environment
|
|
1008
|
+
variables. */
|
|
1009
|
+
static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
|
|
1010
|
+
int argc, JSValueConst *argv)
|
|
1011
|
+
{
|
|
1012
|
+
char **envp;
|
|
1013
|
+
const char *name, *p, *value;
|
|
1014
|
+
JSValue obj;
|
|
1015
|
+
uint32_t idx;
|
|
1016
|
+
size_t name_len;
|
|
1017
|
+
JSAtom atom;
|
|
1018
|
+
int ret;
|
|
1019
|
+
|
|
1020
|
+
obj = JS_NewObject(ctx);
|
|
1021
|
+
if (JS_IsException(obj))
|
|
1022
|
+
return JS_EXCEPTION;
|
|
1023
|
+
envp = environ;
|
|
1024
|
+
for(idx = 0; envp[idx] != NULL; idx++) {
|
|
1025
|
+
name = envp[idx];
|
|
1026
|
+
p = strchr(name, '=');
|
|
1027
|
+
name_len = p - name;
|
|
1028
|
+
if (!p)
|
|
1029
|
+
continue;
|
|
1030
|
+
value = p + 1;
|
|
1031
|
+
atom = JS_NewAtomLen(ctx, name, name_len);
|
|
1032
|
+
if (atom == JS_ATOM_NULL)
|
|
1033
|
+
goto fail;
|
|
1034
|
+
ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),
|
|
1035
|
+
JS_PROP_C_W_E);
|
|
1036
|
+
JS_FreeAtom(ctx, atom);
|
|
1037
|
+
if (ret < 0)
|
|
1038
|
+
goto fail;
|
|
1039
|
+
}
|
|
1040
|
+
return obj;
|
|
1041
|
+
fail:
|
|
1042
|
+
JS_FreeValue(ctx, obj);
|
|
1043
|
+
return JS_EXCEPTION;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
|
|
1047
|
+
int argc, JSValueConst *argv)
|
|
1048
|
+
{
|
|
1049
|
+
JS_RunGC(JS_GetRuntime(ctx));
|
|
1050
|
+
return JS_UNDEFINED;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
static int interrupt_handler(JSRuntime *rt, void *opaque)
|
|
1054
|
+
{
|
|
1055
|
+
return (os_pending_signals >> SIGINT) & 1;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
|
|
1059
|
+
int argc, JSValueConst *argv)
|
|
1060
|
+
{
|
|
1061
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
1062
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
1063
|
+
const char *str = NULL;
|
|
1064
|
+
size_t len;
|
|
1065
|
+
JSValue ret, obj;
|
|
1066
|
+
JSValueConst options_obj, arg;
|
|
1067
|
+
bool backtrace_barrier = false;
|
|
1068
|
+
bool eval_function = false;
|
|
1069
|
+
bool eval_module = false;
|
|
1070
|
+
bool compile_only = false;
|
|
1071
|
+
bool compile_module = false;
|
|
1072
|
+
bool is_async = false;
|
|
1073
|
+
int flags;
|
|
1074
|
+
|
|
1075
|
+
if (argc >= 2) {
|
|
1076
|
+
options_obj = argv[1];
|
|
1077
|
+
if (get_bool_option(ctx, &backtrace_barrier, options_obj,
|
|
1078
|
+
"backtrace_barrier"))
|
|
1079
|
+
return JS_EXCEPTION;
|
|
1080
|
+
if (get_bool_option(ctx, &eval_function, options_obj,
|
|
1081
|
+
"eval_function"))
|
|
1082
|
+
return JS_EXCEPTION;
|
|
1083
|
+
if (get_bool_option(ctx, &eval_module, options_obj,
|
|
1084
|
+
"eval_module"))
|
|
1085
|
+
return JS_EXCEPTION;
|
|
1086
|
+
if (get_bool_option(ctx, &compile_only, options_obj,
|
|
1087
|
+
"compile_only"))
|
|
1088
|
+
return JS_EXCEPTION;
|
|
1089
|
+
if (get_bool_option(ctx, &compile_module, options_obj,
|
|
1090
|
+
"compile_module"))
|
|
1091
|
+
return JS_EXCEPTION;
|
|
1092
|
+
if (get_bool_option(ctx, &is_async, options_obj,
|
|
1093
|
+
"async"))
|
|
1094
|
+
return JS_EXCEPTION;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
if (eval_module) {
|
|
1098
|
+
arg = argv[0];
|
|
1099
|
+
if (JS_VALUE_GET_TAG(arg) != JS_TAG_MODULE)
|
|
1100
|
+
return JS_ThrowTypeError(ctx, "not a module");
|
|
1101
|
+
|
|
1102
|
+
if (JS_ResolveModule(ctx, arg) < 0)
|
|
1103
|
+
return JS_EXCEPTION;
|
|
1104
|
+
|
|
1105
|
+
if (js_module_set_import_meta(ctx, arg, false, false) < 0)
|
|
1106
|
+
return JS_EXCEPTION;
|
|
1107
|
+
|
|
1108
|
+
return JS_EvalFunction(ctx, JS_DupValue(ctx, arg));
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
if (!eval_function) {
|
|
1112
|
+
str = JS_ToCStringLen(ctx, &len, argv[0]);
|
|
1113
|
+
if (!str)
|
|
1114
|
+
return JS_EXCEPTION;
|
|
1115
|
+
}
|
|
1116
|
+
if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) {
|
|
1117
|
+
/* install the interrupt handler */
|
|
1118
|
+
JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
|
|
1119
|
+
}
|
|
1120
|
+
flags = compile_module ? JS_EVAL_TYPE_MODULE : JS_EVAL_TYPE_GLOBAL;
|
|
1121
|
+
if (backtrace_barrier)
|
|
1122
|
+
flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
|
|
1123
|
+
if (compile_only)
|
|
1124
|
+
flags |= JS_EVAL_FLAG_COMPILE_ONLY;
|
|
1125
|
+
if (is_async)
|
|
1126
|
+
flags |= JS_EVAL_FLAG_ASYNC;
|
|
1127
|
+
if (eval_function) {
|
|
1128
|
+
obj = JS_DupValue(ctx, argv[0]);
|
|
1129
|
+
ret = JS_EvalFunction(ctx, obj); // takes ownership of |obj|
|
|
1130
|
+
} else {
|
|
1131
|
+
ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
|
|
1132
|
+
}
|
|
1133
|
+
JS_FreeCString(ctx, str);
|
|
1134
|
+
if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
|
|
1135
|
+
/* remove the interrupt handler */
|
|
1136
|
+
JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL);
|
|
1137
|
+
os_pending_signals &= ~((uint64_t)1 << SIGINT);
|
|
1138
|
+
/* convert the uncatchable "interrupted" error into a normal error
|
|
1139
|
+
so that it can be caught by the REPL */
|
|
1140
|
+
if (JS_IsException(ret))
|
|
1141
|
+
JS_ResetUncatchableError(ctx);
|
|
1142
|
+
}
|
|
1143
|
+
return ret;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
typedef struct {
|
|
1147
|
+
FILE *f;
|
|
1148
|
+
bool is_popen;
|
|
1149
|
+
} JSSTDFile;
|
|
1150
|
+
|
|
1151
|
+
static bool is_stdio(FILE *f)
|
|
1152
|
+
{
|
|
1153
|
+
return f == stdin || f == stdout || f == stderr;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
static void safe_close(FILE *f, bool is_popen)
|
|
1157
|
+
{
|
|
1158
|
+
if (!f)
|
|
1159
|
+
return;
|
|
1160
|
+
if (is_stdio(f))
|
|
1161
|
+
return;
|
|
1162
|
+
if (is_popen) {
|
|
1163
|
+
#if !defined(__wasi__)
|
|
1164
|
+
pclose(f);
|
|
1165
|
+
#endif
|
|
1166
|
+
} else {
|
|
1167
|
+
fclose(f);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
static void js_std_file_finalizer(JSRuntime *rt, JSValueConst val)
|
|
1172
|
+
{
|
|
1173
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
1174
|
+
JSSTDFile *s = JS_GetOpaque(val, ts->std_file_class_id);
|
|
1175
|
+
if (s) {
|
|
1176
|
+
safe_close(s->f, s->is_popen);
|
|
1177
|
+
js_free_rt(rt, s);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
static ssize_t js_get_errno(ssize_t ret)
|
|
1182
|
+
{
|
|
1183
|
+
if (ret == -1)
|
|
1184
|
+
ret = -errno;
|
|
1185
|
+
return ret;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
|
|
1189
|
+
int argc, JSValueConst *argv)
|
|
1190
|
+
{
|
|
1191
|
+
int err;
|
|
1192
|
+
if (JS_ToInt32(ctx, &err, argv[0]))
|
|
1193
|
+
return JS_EXCEPTION;
|
|
1194
|
+
return JS_NewString(ctx, strerror(err));
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
static JSValue js_new_std_file(JSContext *ctx, FILE *f, bool is_popen)
|
|
1198
|
+
{
|
|
1199
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
1200
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
1201
|
+
JSSTDFile *s;
|
|
1202
|
+
JSValue obj;
|
|
1203
|
+
obj = JS_NewObjectClass(ctx, ts->std_file_class_id);
|
|
1204
|
+
if (JS_IsException(obj))
|
|
1205
|
+
goto exception;
|
|
1206
|
+
s = js_mallocz(ctx, sizeof(*s));
|
|
1207
|
+
if (!s)
|
|
1208
|
+
goto exception;
|
|
1209
|
+
s->is_popen = is_popen;
|
|
1210
|
+
s->f = f;
|
|
1211
|
+
JS_SetOpaque(obj, s);
|
|
1212
|
+
return obj;
|
|
1213
|
+
exception:
|
|
1214
|
+
safe_close(f, is_popen);
|
|
1215
|
+
JS_FreeValue(ctx, obj);
|
|
1216
|
+
return JS_EXCEPTION;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
static void js_set_error_object(JSContext *ctx, JSValueConst obj, int err)
|
|
1220
|
+
{
|
|
1221
|
+
if (!JS_IsUndefined(obj)) {
|
|
1222
|
+
JS_SetPropertyStr(ctx, obj, "errno", JS_NewInt32(ctx, err));
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
|
|
1227
|
+
int argc, JSValueConst *argv)
|
|
1228
|
+
{
|
|
1229
|
+
const char *filename, *mode = NULL;
|
|
1230
|
+
FILE *f;
|
|
1231
|
+
int err;
|
|
1232
|
+
|
|
1233
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
1234
|
+
if (!filename)
|
|
1235
|
+
goto fail;
|
|
1236
|
+
mode = JS_ToCString(ctx, argv[1]);
|
|
1237
|
+
if (!mode)
|
|
1238
|
+
goto fail;
|
|
1239
|
+
if (mode[strspn(mode, "rwa+bx")] != '\0') {
|
|
1240
|
+
JS_ThrowTypeError(ctx, "invalid file mode");
|
|
1241
|
+
goto fail;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
f = fopen(filename, mode);
|
|
1245
|
+
if (!f)
|
|
1246
|
+
err = errno;
|
|
1247
|
+
else
|
|
1248
|
+
err = 0;
|
|
1249
|
+
if (argc >= 3)
|
|
1250
|
+
js_set_error_object(ctx, argv[2], err);
|
|
1251
|
+
JS_FreeCString(ctx, filename);
|
|
1252
|
+
JS_FreeCString(ctx, mode);
|
|
1253
|
+
if (!f)
|
|
1254
|
+
return JS_NULL;
|
|
1255
|
+
return js_new_std_file(ctx, f, false);
|
|
1256
|
+
fail:
|
|
1257
|
+
JS_FreeCString(ctx, filename);
|
|
1258
|
+
JS_FreeCString(ctx, mode);
|
|
1259
|
+
return JS_EXCEPTION;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
#if !defined(__wasi__)
|
|
1263
|
+
static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
|
|
1264
|
+
int argc, JSValueConst *argv)
|
|
1265
|
+
{
|
|
1266
|
+
const char *filename, *mode = NULL;
|
|
1267
|
+
FILE *f;
|
|
1268
|
+
int err;
|
|
1269
|
+
|
|
1270
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
1271
|
+
if (!filename)
|
|
1272
|
+
goto fail;
|
|
1273
|
+
mode = JS_ToCString(ctx, argv[1]);
|
|
1274
|
+
if (!mode)
|
|
1275
|
+
goto fail;
|
|
1276
|
+
if (strcmp(mode, "r") && strcmp(mode, "w")) {
|
|
1277
|
+
JS_ThrowTypeError(ctx, "invalid file mode");
|
|
1278
|
+
goto fail;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
f = popen(filename, mode);
|
|
1282
|
+
if (!f)
|
|
1283
|
+
err = errno;
|
|
1284
|
+
else
|
|
1285
|
+
err = 0;
|
|
1286
|
+
if (argc >= 3)
|
|
1287
|
+
js_set_error_object(ctx, argv[2], err);
|
|
1288
|
+
JS_FreeCString(ctx, filename);
|
|
1289
|
+
JS_FreeCString(ctx, mode);
|
|
1290
|
+
if (!f)
|
|
1291
|
+
return JS_NULL;
|
|
1292
|
+
return js_new_std_file(ctx, f, true);
|
|
1293
|
+
fail:
|
|
1294
|
+
JS_FreeCString(ctx, filename);
|
|
1295
|
+
JS_FreeCString(ctx, mode);
|
|
1296
|
+
return JS_EXCEPTION;
|
|
1297
|
+
}
|
|
1298
|
+
#endif // !defined(__wasi__)
|
|
1299
|
+
|
|
1300
|
+
static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
|
|
1301
|
+
int argc, JSValueConst *argv)
|
|
1302
|
+
{
|
|
1303
|
+
const char *mode;
|
|
1304
|
+
FILE *f;
|
|
1305
|
+
int fd, err;
|
|
1306
|
+
|
|
1307
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
1308
|
+
return JS_EXCEPTION;
|
|
1309
|
+
mode = JS_ToCString(ctx, argv[1]);
|
|
1310
|
+
if (!mode)
|
|
1311
|
+
goto fail;
|
|
1312
|
+
if (mode[strspn(mode, "rwa+")] != '\0') {
|
|
1313
|
+
JS_ThrowTypeError(ctx, "invalid file mode");
|
|
1314
|
+
goto fail;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
f = fdopen(fd, mode);
|
|
1318
|
+
if (!f)
|
|
1319
|
+
err = errno;
|
|
1320
|
+
else
|
|
1321
|
+
err = 0;
|
|
1322
|
+
if (argc >= 3)
|
|
1323
|
+
js_set_error_object(ctx, argv[2], err);
|
|
1324
|
+
JS_FreeCString(ctx, mode);
|
|
1325
|
+
if (!f)
|
|
1326
|
+
return JS_NULL;
|
|
1327
|
+
return js_new_std_file(ctx, f, false);
|
|
1328
|
+
fail:
|
|
1329
|
+
JS_FreeCString(ctx, mode);
|
|
1330
|
+
return JS_EXCEPTION;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
#if !defined(__wasi__)
|
|
1334
|
+
static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
|
|
1335
|
+
int argc, JSValueConst *argv)
|
|
1336
|
+
{
|
|
1337
|
+
FILE *f;
|
|
1338
|
+
f = tmpfile();
|
|
1339
|
+
if (argc >= 1)
|
|
1340
|
+
js_set_error_object(ctx, argv[0], f ? 0 : errno);
|
|
1341
|
+
if (!f)
|
|
1342
|
+
return JS_NULL;
|
|
1343
|
+
return js_new_std_file(ctx, f, false);
|
|
1344
|
+
}
|
|
1345
|
+
#endif
|
|
1346
|
+
|
|
1347
|
+
static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val,
|
|
1348
|
+
int argc, JSValueConst *argv)
|
|
1349
|
+
{
|
|
1350
|
+
return js_printf_internal(ctx, argc, argv, NULL);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
static JSValue js_std_printf(JSContext *ctx, JSValueConst this_val,
|
|
1354
|
+
int argc, JSValueConst *argv)
|
|
1355
|
+
{
|
|
1356
|
+
return js_printf_internal(ctx, argc, argv, stdout);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
static FILE *js_std_file_get(JSContext *ctx, JSValueConst obj)
|
|
1360
|
+
{
|
|
1361
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
1362
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
1363
|
+
JSSTDFile *s = JS_GetOpaque2(ctx, obj, ts->std_file_class_id);
|
|
1364
|
+
if (!s)
|
|
1365
|
+
return NULL;
|
|
1366
|
+
if (!s->f) {
|
|
1367
|
+
JS_ThrowTypeError(ctx, "invalid file handle");
|
|
1368
|
+
return NULL;
|
|
1369
|
+
}
|
|
1370
|
+
return s->f;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
static JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,
|
|
1374
|
+
int argc, JSValueConst *argv, int magic)
|
|
1375
|
+
{
|
|
1376
|
+
FILE *f;
|
|
1377
|
+
int i;
|
|
1378
|
+
const char *str;
|
|
1379
|
+
size_t len;
|
|
1380
|
+
|
|
1381
|
+
if (magic == 0) {
|
|
1382
|
+
f = stdout;
|
|
1383
|
+
} else {
|
|
1384
|
+
f = js_std_file_get(ctx, this_val);
|
|
1385
|
+
if (!f)
|
|
1386
|
+
return JS_EXCEPTION;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
for(i = 0; i < argc; i++) {
|
|
1390
|
+
str = JS_ToCStringLen(ctx, &len, argv[i]);
|
|
1391
|
+
if (!str)
|
|
1392
|
+
return JS_EXCEPTION;
|
|
1393
|
+
fwrite(str, 1, len, f);
|
|
1394
|
+
JS_FreeCString(ctx, str);
|
|
1395
|
+
}
|
|
1396
|
+
return JS_UNDEFINED;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,
|
|
1400
|
+
int argc, JSValueConst *argv)
|
|
1401
|
+
{
|
|
1402
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
1403
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
1404
|
+
JSSTDFile *s = JS_GetOpaque2(ctx, this_val, ts->std_file_class_id);
|
|
1405
|
+
int err;
|
|
1406
|
+
if (!s)
|
|
1407
|
+
return JS_EXCEPTION;
|
|
1408
|
+
if (!s->f)
|
|
1409
|
+
return JS_ThrowTypeError(ctx, "invalid file handle");
|
|
1410
|
+
if (is_stdio(s->f))
|
|
1411
|
+
return JS_ThrowTypeError(ctx, "cannot close stdio");
|
|
1412
|
+
#if !defined(__wasi__)
|
|
1413
|
+
if (s->is_popen)
|
|
1414
|
+
err = js_get_errno(pclose(s->f));
|
|
1415
|
+
else
|
|
1416
|
+
#endif
|
|
1417
|
+
err = js_get_errno(fclose(s->f));
|
|
1418
|
+
s->f = NULL;
|
|
1419
|
+
return JS_NewInt32(ctx, err);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
|
|
1423
|
+
int argc, JSValueConst *argv)
|
|
1424
|
+
{
|
|
1425
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1426
|
+
if (!f)
|
|
1427
|
+
return JS_EXCEPTION;
|
|
1428
|
+
return js_printf_internal(ctx, argc, argv, f);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
|
|
1432
|
+
int argc, JSValueConst *argv)
|
|
1433
|
+
{
|
|
1434
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1435
|
+
if (!f)
|
|
1436
|
+
return JS_EXCEPTION;
|
|
1437
|
+
fflush(f);
|
|
1438
|
+
return JS_UNDEFINED;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
static JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,
|
|
1442
|
+
int argc, JSValueConst *argv, int is_bigint)
|
|
1443
|
+
{
|
|
1444
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1445
|
+
int64_t pos;
|
|
1446
|
+
if (!f)
|
|
1447
|
+
return JS_EXCEPTION;
|
|
1448
|
+
#if defined(__linux__) || defined(__GLIBC__)
|
|
1449
|
+
pos = ftello(f);
|
|
1450
|
+
#else
|
|
1451
|
+
pos = ftell(f);
|
|
1452
|
+
#endif
|
|
1453
|
+
if (is_bigint)
|
|
1454
|
+
return JS_NewBigInt64(ctx, pos);
|
|
1455
|
+
else
|
|
1456
|
+
return JS_NewInt64(ctx, pos);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
static JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,
|
|
1460
|
+
int argc, JSValueConst *argv)
|
|
1461
|
+
{
|
|
1462
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1463
|
+
int64_t pos;
|
|
1464
|
+
int whence, ret;
|
|
1465
|
+
if (!f)
|
|
1466
|
+
return JS_EXCEPTION;
|
|
1467
|
+
if (JS_ToInt64Ext(ctx, &pos, argv[0]))
|
|
1468
|
+
return JS_EXCEPTION;
|
|
1469
|
+
if (JS_ToInt32(ctx, &whence, argv[1]))
|
|
1470
|
+
return JS_EXCEPTION;
|
|
1471
|
+
#if defined(__linux__) || defined(__GLIBC__)
|
|
1472
|
+
ret = fseeko(f, pos, whence);
|
|
1473
|
+
#else
|
|
1474
|
+
ret = fseek(f, pos, whence);
|
|
1475
|
+
#endif
|
|
1476
|
+
if (ret < 0)
|
|
1477
|
+
ret = -errno;
|
|
1478
|
+
return JS_NewInt32(ctx, ret);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
static JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val,
|
|
1482
|
+
int argc, JSValueConst *argv)
|
|
1483
|
+
{
|
|
1484
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1485
|
+
if (!f)
|
|
1486
|
+
return JS_EXCEPTION;
|
|
1487
|
+
return JS_NewBool(ctx, feof(f));
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
static JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val,
|
|
1491
|
+
int argc, JSValueConst *argv)
|
|
1492
|
+
{
|
|
1493
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1494
|
+
if (!f)
|
|
1495
|
+
return JS_EXCEPTION;
|
|
1496
|
+
return JS_NewBool(ctx, ferror(f));
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
static JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val,
|
|
1500
|
+
int argc, JSValueConst *argv)
|
|
1501
|
+
{
|
|
1502
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1503
|
+
if (!f)
|
|
1504
|
+
return JS_EXCEPTION;
|
|
1505
|
+
clearerr(f);
|
|
1506
|
+
return JS_UNDEFINED;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
static JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val,
|
|
1510
|
+
int argc, JSValueConst *argv)
|
|
1511
|
+
{
|
|
1512
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1513
|
+
if (!f)
|
|
1514
|
+
return JS_EXCEPTION;
|
|
1515
|
+
return JS_NewInt32(ctx, fileno(f));
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
static JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val,
|
|
1519
|
+
int argc, JSValueConst *argv, int magic)
|
|
1520
|
+
{
|
|
1521
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1522
|
+
bool is_write = (magic != 0);
|
|
1523
|
+
uint64_t pos, len;
|
|
1524
|
+
size_t size, ret;
|
|
1525
|
+
const char *str;
|
|
1526
|
+
uint8_t *buf;
|
|
1527
|
+
|
|
1528
|
+
if (!f)
|
|
1529
|
+
return JS_EXCEPTION;
|
|
1530
|
+
pos = 0;
|
|
1531
|
+
if (argc > 1 && JS_ToIndex(ctx, &pos, argv[1]))
|
|
1532
|
+
return JS_EXCEPTION;
|
|
1533
|
+
len = 0;
|
|
1534
|
+
if (argc > 2 && JS_ToIndex(ctx, &len, argv[2]))
|
|
1535
|
+
return JS_EXCEPTION;
|
|
1536
|
+
if (is_write && JS_IsString(argv[0])) {
|
|
1537
|
+
str = JS_ToCStringLen(ctx, &size, argv[0]);
|
|
1538
|
+
buf = (void *)str;
|
|
1539
|
+
} else {
|
|
1540
|
+
str = NULL;
|
|
1541
|
+
buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
|
|
1542
|
+
}
|
|
1543
|
+
if (!buf)
|
|
1544
|
+
return JS_EXCEPTION;
|
|
1545
|
+
if (pos > size)
|
|
1546
|
+
pos = size;
|
|
1547
|
+
if (argc < 3)
|
|
1548
|
+
len = size - pos;
|
|
1549
|
+
if (pos + len > size)
|
|
1550
|
+
len = size - pos;
|
|
1551
|
+
if (is_write) {
|
|
1552
|
+
ret = fwrite(buf + pos, 1, len, f);
|
|
1553
|
+
} else {
|
|
1554
|
+
ret = fread(buf + pos, 1, len, f);
|
|
1555
|
+
}
|
|
1556
|
+
JS_FreeCString(ctx, str);
|
|
1557
|
+
return JS_NewInt64(ctx, ret);
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/* XXX: could use less memory and go faster */
|
|
1561
|
+
static JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val,
|
|
1562
|
+
int argc, JSValueConst *argv)
|
|
1563
|
+
{
|
|
1564
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1565
|
+
int c;
|
|
1566
|
+
DynBuf dbuf;
|
|
1567
|
+
JSValue obj;
|
|
1568
|
+
|
|
1569
|
+
if (!f)
|
|
1570
|
+
return JS_EXCEPTION;
|
|
1571
|
+
|
|
1572
|
+
js_std_dbuf_init(ctx, &dbuf);
|
|
1573
|
+
for(;;) {
|
|
1574
|
+
c = fgetc(f);
|
|
1575
|
+
if (c == EOF) {
|
|
1576
|
+
if (dbuf.size == 0) {
|
|
1577
|
+
/* EOF */
|
|
1578
|
+
dbuf_free(&dbuf);
|
|
1579
|
+
return JS_NULL;
|
|
1580
|
+
} else {
|
|
1581
|
+
break;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
if (c == '\n')
|
|
1585
|
+
break;
|
|
1586
|
+
if (dbuf_putc(&dbuf, c)) {
|
|
1587
|
+
dbuf_free(&dbuf);
|
|
1588
|
+
return JS_ThrowOutOfMemory(ctx);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
|
|
1592
|
+
dbuf_free(&dbuf);
|
|
1593
|
+
return obj;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/* XXX: could use less memory and go faster */
|
|
1597
|
+
static JSValue js_std_file_readAs(JSContext *ctx, JSValueConst this_val,
|
|
1598
|
+
int argc, JSValueConst *argv, int magic)
|
|
1599
|
+
{
|
|
1600
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1601
|
+
int c;
|
|
1602
|
+
DynBuf dbuf;
|
|
1603
|
+
JSValue obj;
|
|
1604
|
+
uint64_t max_size64;
|
|
1605
|
+
size_t max_size;
|
|
1606
|
+
JSValueConst max_size_val;
|
|
1607
|
+
|
|
1608
|
+
if (!f)
|
|
1609
|
+
return JS_EXCEPTION;
|
|
1610
|
+
|
|
1611
|
+
if (argc >= 1)
|
|
1612
|
+
max_size_val = argv[0];
|
|
1613
|
+
else
|
|
1614
|
+
max_size_val = JS_UNDEFINED;
|
|
1615
|
+
max_size = (size_t)-1;
|
|
1616
|
+
if (!JS_IsUndefined(max_size_val)) {
|
|
1617
|
+
if (JS_ToIndex(ctx, &max_size64, max_size_val))
|
|
1618
|
+
return JS_EXCEPTION;
|
|
1619
|
+
if (max_size64 < max_size)
|
|
1620
|
+
max_size = max_size64;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
js_std_dbuf_init(ctx, &dbuf);
|
|
1624
|
+
while (max_size != 0) {
|
|
1625
|
+
c = fgetc(f);
|
|
1626
|
+
if (c == EOF)
|
|
1627
|
+
break;
|
|
1628
|
+
if (dbuf_putc(&dbuf, c)) {
|
|
1629
|
+
dbuf_free(&dbuf);
|
|
1630
|
+
return JS_EXCEPTION;
|
|
1631
|
+
}
|
|
1632
|
+
max_size--;
|
|
1633
|
+
}
|
|
1634
|
+
if (magic) {
|
|
1635
|
+
obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);
|
|
1636
|
+
} else {
|
|
1637
|
+
obj = JS_NewArrayBufferCopy(ctx, dbuf.buf, dbuf.size);
|
|
1638
|
+
}
|
|
1639
|
+
dbuf_free(&dbuf);
|
|
1640
|
+
return obj;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
static JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val,
|
|
1644
|
+
int argc, JSValueConst *argv)
|
|
1645
|
+
{
|
|
1646
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1647
|
+
if (!f)
|
|
1648
|
+
return JS_EXCEPTION;
|
|
1649
|
+
return JS_NewInt32(ctx, fgetc(f));
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val,
|
|
1653
|
+
int argc, JSValueConst *argv)
|
|
1654
|
+
{
|
|
1655
|
+
FILE *f = js_std_file_get(ctx, this_val);
|
|
1656
|
+
int c;
|
|
1657
|
+
if (!f)
|
|
1658
|
+
return JS_EXCEPTION;
|
|
1659
|
+
if (JS_ToInt32(ctx, &c, argv[0]))
|
|
1660
|
+
return JS_EXCEPTION;
|
|
1661
|
+
c = fputc(c, f);
|
|
1662
|
+
return JS_NewInt32(ctx, c);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
/* urlGet */
|
|
1666
|
+
#if !defined(__wasi__)
|
|
1667
|
+
|
|
1668
|
+
#define URL_GET_PROGRAM "curl -s -i --"
|
|
1669
|
+
#define URL_GET_BUF_SIZE 4096
|
|
1670
|
+
|
|
1671
|
+
static int http_get_header_line(FILE *f, char *buf, size_t buf_size,
|
|
1672
|
+
DynBuf *dbuf)
|
|
1673
|
+
{
|
|
1674
|
+
int c;
|
|
1675
|
+
char *p;
|
|
1676
|
+
|
|
1677
|
+
p = buf;
|
|
1678
|
+
for(;;) {
|
|
1679
|
+
c = fgetc(f);
|
|
1680
|
+
if (c < 0)
|
|
1681
|
+
return -1;
|
|
1682
|
+
if ((p - buf) < buf_size - 1)
|
|
1683
|
+
*p++ = c;
|
|
1684
|
+
if (dbuf)
|
|
1685
|
+
dbuf_putc(dbuf, c);
|
|
1686
|
+
if (c == '\n')
|
|
1687
|
+
break;
|
|
1688
|
+
}
|
|
1689
|
+
*p = '\0';
|
|
1690
|
+
return 0;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
static int http_get_status(const char *buf)
|
|
1694
|
+
{
|
|
1695
|
+
const char *p = buf;
|
|
1696
|
+
while (*p != ' ' && *p != '\0')
|
|
1697
|
+
p++;
|
|
1698
|
+
if (*p != ' ')
|
|
1699
|
+
return 0;
|
|
1700
|
+
while (*p == ' ')
|
|
1701
|
+
p++;
|
|
1702
|
+
return atoi(p);
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
|
|
1706
|
+
int argc, JSValueConst *argv)
|
|
1707
|
+
{
|
|
1708
|
+
const char *url;
|
|
1709
|
+
DynBuf cmd_buf;
|
|
1710
|
+
DynBuf data_buf_s, *data_buf = &data_buf_s;
|
|
1711
|
+
DynBuf header_buf_s, *header_buf = &header_buf_s;
|
|
1712
|
+
char *buf;
|
|
1713
|
+
size_t i, len;
|
|
1714
|
+
int status;
|
|
1715
|
+
JSValue response = JS_UNDEFINED, ret_obj;
|
|
1716
|
+
JSValueConst options_obj;
|
|
1717
|
+
FILE *f;
|
|
1718
|
+
bool binary_flag, full_flag;
|
|
1719
|
+
|
|
1720
|
+
url = JS_ToCString(ctx, argv[0]);
|
|
1721
|
+
if (!url)
|
|
1722
|
+
return JS_EXCEPTION;
|
|
1723
|
+
|
|
1724
|
+
binary_flag = false;
|
|
1725
|
+
full_flag = false;
|
|
1726
|
+
|
|
1727
|
+
if (argc >= 2) {
|
|
1728
|
+
options_obj = argv[1];
|
|
1729
|
+
|
|
1730
|
+
if (get_bool_option(ctx, &binary_flag, options_obj, "binary"))
|
|
1731
|
+
goto fail_obj;
|
|
1732
|
+
|
|
1733
|
+
if (get_bool_option(ctx, &full_flag, options_obj, "full")) {
|
|
1734
|
+
fail_obj:
|
|
1735
|
+
JS_FreeCString(ctx, url);
|
|
1736
|
+
return JS_EXCEPTION;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
js_std_dbuf_init(ctx, &cmd_buf);
|
|
1741
|
+
dbuf_printf(&cmd_buf, "%s '", URL_GET_PROGRAM);
|
|
1742
|
+
for(i = 0; url[i] != '\0'; i++) {
|
|
1743
|
+
unsigned char c = url[i];
|
|
1744
|
+
switch (c) {
|
|
1745
|
+
case '\'':
|
|
1746
|
+
/* shell single quoted string does not support \' */
|
|
1747
|
+
dbuf_putstr(&cmd_buf, "'\\''");
|
|
1748
|
+
break;
|
|
1749
|
+
case '[': case ']': case '{': case '}': case '\\':
|
|
1750
|
+
/* prevent interpretation by curl as range or set specification */
|
|
1751
|
+
dbuf_putc(&cmd_buf, '\\');
|
|
1752
|
+
/* FALLTHROUGH */
|
|
1753
|
+
default:
|
|
1754
|
+
dbuf_putc(&cmd_buf, c);
|
|
1755
|
+
break;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
JS_FreeCString(ctx, url);
|
|
1759
|
+
dbuf_putstr(&cmd_buf, "'");
|
|
1760
|
+
dbuf_putc(&cmd_buf, '\0');
|
|
1761
|
+
if (dbuf_error(&cmd_buf)) {
|
|
1762
|
+
dbuf_free(&cmd_buf);
|
|
1763
|
+
return JS_EXCEPTION;
|
|
1764
|
+
}
|
|
1765
|
+
// printf("%s\n", (char *)cmd_buf.buf);
|
|
1766
|
+
f = popen((char *)cmd_buf.buf, "r");
|
|
1767
|
+
dbuf_free(&cmd_buf);
|
|
1768
|
+
if (!f) {
|
|
1769
|
+
return JS_ThrowTypeError(ctx, "could not start curl");
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
js_std_dbuf_init(ctx, data_buf);
|
|
1773
|
+
js_std_dbuf_init(ctx, header_buf);
|
|
1774
|
+
|
|
1775
|
+
buf = js_malloc(ctx, URL_GET_BUF_SIZE);
|
|
1776
|
+
if (!buf)
|
|
1777
|
+
goto fail;
|
|
1778
|
+
|
|
1779
|
+
/* get the HTTP status */
|
|
1780
|
+
if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) {
|
|
1781
|
+
status = 0;
|
|
1782
|
+
goto bad_header;
|
|
1783
|
+
}
|
|
1784
|
+
status = http_get_status(buf);
|
|
1785
|
+
if (!full_flag && !(status >= 200 && status <= 299)) {
|
|
1786
|
+
goto bad_header;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
/* wait until there is an empty line */
|
|
1790
|
+
for(;;) {
|
|
1791
|
+
if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) {
|
|
1792
|
+
bad_header:
|
|
1793
|
+
response = JS_NULL;
|
|
1794
|
+
goto done;
|
|
1795
|
+
}
|
|
1796
|
+
if (!strcmp(buf, "\r\n"))
|
|
1797
|
+
break;
|
|
1798
|
+
}
|
|
1799
|
+
if (dbuf_error(header_buf))
|
|
1800
|
+
goto fail;
|
|
1801
|
+
header_buf->size -= 2; /* remove the trailing CRLF */
|
|
1802
|
+
|
|
1803
|
+
/* download the data */
|
|
1804
|
+
for(;;) {
|
|
1805
|
+
len = fread(buf, 1, URL_GET_BUF_SIZE, f);
|
|
1806
|
+
if (len == 0)
|
|
1807
|
+
break;
|
|
1808
|
+
dbuf_put(data_buf, (uint8_t *)buf, len);
|
|
1809
|
+
}
|
|
1810
|
+
if (dbuf_error(data_buf))
|
|
1811
|
+
goto fail;
|
|
1812
|
+
if (binary_flag) {
|
|
1813
|
+
response = JS_NewArrayBufferCopy(ctx,
|
|
1814
|
+
data_buf->buf, data_buf->size);
|
|
1815
|
+
} else {
|
|
1816
|
+
response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size);
|
|
1817
|
+
}
|
|
1818
|
+
if (JS_IsException(response))
|
|
1819
|
+
goto fail;
|
|
1820
|
+
done:
|
|
1821
|
+
js_free(ctx, buf);
|
|
1822
|
+
buf = NULL;
|
|
1823
|
+
pclose(f);
|
|
1824
|
+
f = NULL;
|
|
1825
|
+
dbuf_free(data_buf);
|
|
1826
|
+
data_buf = NULL;
|
|
1827
|
+
|
|
1828
|
+
if (full_flag) {
|
|
1829
|
+
ret_obj = JS_NewObject(ctx);
|
|
1830
|
+
if (JS_IsException(ret_obj))
|
|
1831
|
+
goto fail;
|
|
1832
|
+
JS_DefinePropertyValueStr(ctx, ret_obj, "response",
|
|
1833
|
+
response,
|
|
1834
|
+
JS_PROP_C_W_E);
|
|
1835
|
+
if (!JS_IsNull(response)) {
|
|
1836
|
+
JS_DefinePropertyValueStr(ctx, ret_obj, "responseHeaders",
|
|
1837
|
+
JS_NewStringLen(ctx, (char *)header_buf->buf,
|
|
1838
|
+
header_buf->size),
|
|
1839
|
+
JS_PROP_C_W_E);
|
|
1840
|
+
JS_DefinePropertyValueStr(ctx, ret_obj, "status",
|
|
1841
|
+
JS_NewInt32(ctx, status),
|
|
1842
|
+
JS_PROP_C_W_E);
|
|
1843
|
+
}
|
|
1844
|
+
} else {
|
|
1845
|
+
ret_obj = response;
|
|
1846
|
+
}
|
|
1847
|
+
dbuf_free(header_buf);
|
|
1848
|
+
return ret_obj;
|
|
1849
|
+
fail:
|
|
1850
|
+
if (f)
|
|
1851
|
+
pclose(f);
|
|
1852
|
+
js_free(ctx, buf);
|
|
1853
|
+
if (data_buf)
|
|
1854
|
+
dbuf_free(data_buf);
|
|
1855
|
+
if (header_buf)
|
|
1856
|
+
dbuf_free(header_buf);
|
|
1857
|
+
JS_FreeValue(ctx, response);
|
|
1858
|
+
return JS_EXCEPTION;
|
|
1859
|
+
}
|
|
1860
|
+
#endif // !defined(__wasi__)
|
|
1861
|
+
|
|
1862
|
+
static JSClassDef js_std_file_class = {
|
|
1863
|
+
"FILE",
|
|
1864
|
+
.finalizer = js_std_file_finalizer,
|
|
1865
|
+
};
|
|
1866
|
+
|
|
1867
|
+
static const JSCFunctionListEntry js_std_error_props[] = {
|
|
1868
|
+
/* various errno values */
|
|
1869
|
+
#define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
|
|
1870
|
+
DEF(EINVAL),
|
|
1871
|
+
DEF(EIO),
|
|
1872
|
+
DEF(EACCES),
|
|
1873
|
+
DEF(EEXIST),
|
|
1874
|
+
DEF(ENOSPC),
|
|
1875
|
+
DEF(ENOSYS),
|
|
1876
|
+
DEF(EBUSY),
|
|
1877
|
+
DEF(ENOENT),
|
|
1878
|
+
DEF(EPERM),
|
|
1879
|
+
DEF(EPIPE),
|
|
1880
|
+
DEF(EBADF),
|
|
1881
|
+
#undef DEF
|
|
1882
|
+
};
|
|
1883
|
+
|
|
1884
|
+
static const JSCFunctionListEntry js_std_funcs[] = {
|
|
1885
|
+
JS_CFUNC_DEF("exit", 1, js_std_exit ),
|
|
1886
|
+
JS_CFUNC_DEF("gc", 0, js_std_gc ),
|
|
1887
|
+
JS_CFUNC_DEF("evalScript", 1, js_evalScript ),
|
|
1888
|
+
JS_CFUNC_DEF("loadScript", 1, js_loadScript ),
|
|
1889
|
+
JS_CFUNC_DEF("getenv", 1, js_std_getenv ),
|
|
1890
|
+
JS_CFUNC_DEF("setenv", 1, js_std_setenv ),
|
|
1891
|
+
JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ),
|
|
1892
|
+
JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ),
|
|
1893
|
+
#if !defined(__wasi__)
|
|
1894
|
+
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
|
|
1895
|
+
#endif
|
|
1896
|
+
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
|
|
1897
|
+
JS_CFUNC_DEF("writeFile", 2, js_std_writeFile ),
|
|
1898
|
+
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
|
|
1899
|
+
|
|
1900
|
+
/* FILE I/O */
|
|
1901
|
+
JS_CFUNC_DEF("open", 2, js_std_open ),
|
|
1902
|
+
#if !defined(__wasi__)
|
|
1903
|
+
JS_CFUNC_DEF("popen", 2, js_std_popen ),
|
|
1904
|
+
JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ),
|
|
1905
|
+
#endif
|
|
1906
|
+
JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ),
|
|
1907
|
+
JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ),
|
|
1908
|
+
JS_CFUNC_DEF("printf", 1, js_std_printf ),
|
|
1909
|
+
JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ),
|
|
1910
|
+
JS_PROP_INT32_DEF("SEEK_SET", SEEK_SET, JS_PROP_CONFIGURABLE ),
|
|
1911
|
+
JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
|
|
1912
|
+
JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
|
|
1913
|
+
JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
|
|
1914
|
+
};
|
|
1915
|
+
|
|
1916
|
+
static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
|
|
1917
|
+
JS_CFUNC_DEF("close", 0, js_std_file_close ),
|
|
1918
|
+
JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 1 ),
|
|
1919
|
+
JS_CFUNC_DEF("printf", 1, js_std_file_printf ),
|
|
1920
|
+
JS_CFUNC_DEF("flush", 0, js_std_file_flush ),
|
|
1921
|
+
JS_CFUNC_MAGIC_DEF("tell", 0, js_std_file_tell, 0 ),
|
|
1922
|
+
JS_CFUNC_MAGIC_DEF("tello", 0, js_std_file_tell, 1 ),
|
|
1923
|
+
JS_CFUNC_DEF("seek", 2, js_std_file_seek ),
|
|
1924
|
+
JS_CFUNC_DEF("eof", 0, js_std_file_eof ),
|
|
1925
|
+
JS_CFUNC_DEF("fileno", 0, js_std_file_fileno ),
|
|
1926
|
+
JS_CFUNC_DEF("error", 0, js_std_file_error ),
|
|
1927
|
+
JS_CFUNC_DEF("clearerr", 0, js_std_file_clearerr ),
|
|
1928
|
+
JS_CFUNC_MAGIC_DEF("read", 1, js_std_file_read_write, 0 ),
|
|
1929
|
+
JS_CFUNC_MAGIC_DEF("write", 1, js_std_file_read_write, 1 ),
|
|
1930
|
+
JS_CFUNC_DEF("getline", 0, js_std_file_getline ),
|
|
1931
|
+
JS_CFUNC_MAGIC_DEF("readAsArrayBuffer", 0, js_std_file_readAs, 0 ),
|
|
1932
|
+
JS_CFUNC_MAGIC_DEF("readAsString", 0, js_std_file_readAs, 1 ),
|
|
1933
|
+
JS_CFUNC_DEF("getByte", 0, js_std_file_getByte ),
|
|
1934
|
+
JS_CFUNC_DEF("putByte", 1, js_std_file_putByte ),
|
|
1935
|
+
/* setvbuf, ... */
|
|
1936
|
+
};
|
|
1937
|
+
|
|
1938
|
+
static int js_std_init(JSContext *ctx, JSModuleDef *m)
|
|
1939
|
+
{
|
|
1940
|
+
JSValue proto;
|
|
1941
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
1942
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
1943
|
+
|
|
1944
|
+
/* FILE class */
|
|
1945
|
+
/* the class ID is created once */
|
|
1946
|
+
JS_NewClassID(rt, &ts->std_file_class_id);
|
|
1947
|
+
/* the class is created once per runtime */
|
|
1948
|
+
JS_NewClass(rt, ts->std_file_class_id, &js_std_file_class);
|
|
1949
|
+
proto = JS_NewObject(ctx);
|
|
1950
|
+
JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs,
|
|
1951
|
+
countof(js_std_file_proto_funcs));
|
|
1952
|
+
JS_SetClassProto(ctx, ts->std_file_class_id, proto);
|
|
1953
|
+
|
|
1954
|
+
JS_SetModuleExportList(ctx, m, js_std_funcs,
|
|
1955
|
+
countof(js_std_funcs));
|
|
1956
|
+
JS_SetModuleExport(ctx, m, "in", js_new_std_file(ctx, stdin, false));
|
|
1957
|
+
JS_SetModuleExport(ctx, m, "out", js_new_std_file(ctx, stdout, false));
|
|
1958
|
+
JS_SetModuleExport(ctx, m, "err", js_new_std_file(ctx, stderr, false));
|
|
1959
|
+
return 0;
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name)
|
|
1963
|
+
{
|
|
1964
|
+
JSModuleDef *m;
|
|
1965
|
+
m = JS_NewCModule(ctx, module_name, js_std_init);
|
|
1966
|
+
if (!m)
|
|
1967
|
+
return NULL;
|
|
1968
|
+
JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs));
|
|
1969
|
+
JS_AddModuleExport(ctx, m, "in");
|
|
1970
|
+
JS_AddModuleExport(ctx, m, "out");
|
|
1971
|
+
JS_AddModuleExport(ctx, m, "err");
|
|
1972
|
+
return m;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
/**********************************************************/
|
|
1976
|
+
/* 'os' object */
|
|
1977
|
+
|
|
1978
|
+
static JSValue js_os_open(JSContext *ctx, JSValueConst this_val,
|
|
1979
|
+
int argc, JSValueConst *argv)
|
|
1980
|
+
{
|
|
1981
|
+
const char *filename;
|
|
1982
|
+
int flags, mode, ret;
|
|
1983
|
+
|
|
1984
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
1985
|
+
if (!filename)
|
|
1986
|
+
return JS_EXCEPTION;
|
|
1987
|
+
if (JS_ToInt32(ctx, &flags, argv[1]))
|
|
1988
|
+
goto fail;
|
|
1989
|
+
if (argc >= 3 && !JS_IsUndefined(argv[2])) {
|
|
1990
|
+
if (JS_ToInt32(ctx, &mode, argv[2])) {
|
|
1991
|
+
fail:
|
|
1992
|
+
JS_FreeCString(ctx, filename);
|
|
1993
|
+
return JS_EXCEPTION;
|
|
1994
|
+
}
|
|
1995
|
+
} else {
|
|
1996
|
+
mode = 0666;
|
|
1997
|
+
}
|
|
1998
|
+
#if defined(_WIN32)
|
|
1999
|
+
/* force binary mode by default */
|
|
2000
|
+
if (!(flags & O_TEXT))
|
|
2001
|
+
flags |= O_BINARY;
|
|
2002
|
+
#endif
|
|
2003
|
+
ret = js_get_errno(open(filename, flags, mode));
|
|
2004
|
+
JS_FreeCString(ctx, filename);
|
|
2005
|
+
return JS_NewInt32(ctx, ret);
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
static JSValue js_os_close(JSContext *ctx, JSValueConst this_val,
|
|
2009
|
+
int argc, JSValueConst *argv)
|
|
2010
|
+
{
|
|
2011
|
+
int fd, ret;
|
|
2012
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2013
|
+
return JS_EXCEPTION;
|
|
2014
|
+
ret = js_get_errno(close(fd));
|
|
2015
|
+
return JS_NewInt32(ctx, ret);
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
static JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,
|
|
2019
|
+
int argc, JSValueConst *argv)
|
|
2020
|
+
{
|
|
2021
|
+
int fd, whence;
|
|
2022
|
+
int64_t pos, ret;
|
|
2023
|
+
bool is_bigint;
|
|
2024
|
+
|
|
2025
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2026
|
+
return JS_EXCEPTION;
|
|
2027
|
+
is_bigint = JS_IsBigInt(argv[1]);
|
|
2028
|
+
if (JS_ToInt64Ext(ctx, &pos, argv[1]))
|
|
2029
|
+
return JS_EXCEPTION;
|
|
2030
|
+
if (JS_ToInt32(ctx, &whence, argv[2]))
|
|
2031
|
+
return JS_EXCEPTION;
|
|
2032
|
+
ret = lseek(fd, pos, whence);
|
|
2033
|
+
if (ret == -1)
|
|
2034
|
+
ret = -errno;
|
|
2035
|
+
if (is_bigint)
|
|
2036
|
+
return JS_NewBigInt64(ctx, ret);
|
|
2037
|
+
else
|
|
2038
|
+
return JS_NewInt64(ctx, ret);
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
static JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,
|
|
2042
|
+
int argc, JSValueConst *argv, int magic)
|
|
2043
|
+
{
|
|
2044
|
+
int fd;
|
|
2045
|
+
uint64_t pos, len;
|
|
2046
|
+
size_t size;
|
|
2047
|
+
ssize_t ret;
|
|
2048
|
+
uint8_t *buf;
|
|
2049
|
+
|
|
2050
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2051
|
+
return JS_EXCEPTION;
|
|
2052
|
+
if (JS_ToIndex(ctx, &pos, argv[2]))
|
|
2053
|
+
return JS_EXCEPTION;
|
|
2054
|
+
if (JS_ToIndex(ctx, &len, argv[3]))
|
|
2055
|
+
return JS_EXCEPTION;
|
|
2056
|
+
buf = JS_GetArrayBuffer(ctx, &size, argv[1]);
|
|
2057
|
+
if (!buf)
|
|
2058
|
+
return JS_EXCEPTION;
|
|
2059
|
+
if (pos + len > size)
|
|
2060
|
+
return JS_ThrowRangeError(ctx, "read/write array buffer overflow");
|
|
2061
|
+
if (magic)
|
|
2062
|
+
ret = js_get_errno(write(fd, buf + pos, len));
|
|
2063
|
+
else
|
|
2064
|
+
ret = js_get_errno(read(fd, buf + pos, len));
|
|
2065
|
+
return JS_NewInt64(ctx, ret);
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
|
|
2069
|
+
int argc, JSValueConst *argv)
|
|
2070
|
+
{
|
|
2071
|
+
int fd;
|
|
2072
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2073
|
+
return JS_EXCEPTION;
|
|
2074
|
+
return JS_NewBool(ctx, (isatty(fd) != 0));
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
#if defined(_WIN32)
|
|
2078
|
+
static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
|
|
2079
|
+
int argc, JSValueConst *argv)
|
|
2080
|
+
{
|
|
2081
|
+
int fd;
|
|
2082
|
+
HANDLE handle;
|
|
2083
|
+
CONSOLE_SCREEN_BUFFER_INFO info;
|
|
2084
|
+
JSValue obj;
|
|
2085
|
+
|
|
2086
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2087
|
+
return JS_EXCEPTION;
|
|
2088
|
+
handle = (HANDLE)_get_osfhandle(fd);
|
|
2089
|
+
|
|
2090
|
+
if (!GetConsoleScreenBufferInfo(handle, &info))
|
|
2091
|
+
return JS_NULL;
|
|
2092
|
+
obj = JS_NewArray(ctx);
|
|
2093
|
+
if (JS_IsException(obj))
|
|
2094
|
+
return obj;
|
|
2095
|
+
JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E);
|
|
2096
|
+
JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E);
|
|
2097
|
+
return obj;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/* Windows 10 built-in VT100 emulation */
|
|
2101
|
+
#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
|
2102
|
+
#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
|
|
2103
|
+
|
|
2104
|
+
static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
|
|
2105
|
+
int argc, JSValueConst *argv)
|
|
2106
|
+
{
|
|
2107
|
+
int fd;
|
|
2108
|
+
HANDLE handle;
|
|
2109
|
+
|
|
2110
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2111
|
+
return JS_EXCEPTION;
|
|
2112
|
+
handle = (HANDLE)_get_osfhandle(fd);
|
|
2113
|
+
SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT);
|
|
2114
|
+
_setmode(fd, _O_BINARY);
|
|
2115
|
+
if (fd == 0) {
|
|
2116
|
+
handle = (HANDLE)_get_osfhandle(1); /* corresponding output */
|
|
2117
|
+
SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
|
2118
|
+
}
|
|
2119
|
+
return JS_UNDEFINED;
|
|
2120
|
+
}
|
|
2121
|
+
#elif !defined(__wasi__)
|
|
2122
|
+
static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
|
|
2123
|
+
int argc, JSValueConst *argv)
|
|
2124
|
+
{
|
|
2125
|
+
int fd;
|
|
2126
|
+
struct winsize ws;
|
|
2127
|
+
JSValue obj;
|
|
2128
|
+
|
|
2129
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2130
|
+
return JS_EXCEPTION;
|
|
2131
|
+
if (ioctl(fd, TIOCGWINSZ, &ws) == 0 &&
|
|
2132
|
+
ws.ws_col >= 4 && ws.ws_row >= 4) {
|
|
2133
|
+
obj = JS_NewArray(ctx);
|
|
2134
|
+
if (JS_IsException(obj))
|
|
2135
|
+
return obj;
|
|
2136
|
+
JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E);
|
|
2137
|
+
JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E);
|
|
2138
|
+
return obj;
|
|
2139
|
+
} else {
|
|
2140
|
+
return JS_NULL;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
static struct termios oldtty;
|
|
2145
|
+
|
|
2146
|
+
static void term_exit(void)
|
|
2147
|
+
{
|
|
2148
|
+
tcsetattr(0, TCSANOW, &oldtty);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
/* XXX: should add a way to go back to normal mode */
|
|
2152
|
+
static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
|
|
2153
|
+
int argc, JSValueConst *argv)
|
|
2154
|
+
{
|
|
2155
|
+
struct termios tty;
|
|
2156
|
+
int fd;
|
|
2157
|
+
|
|
2158
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2159
|
+
return JS_EXCEPTION;
|
|
2160
|
+
|
|
2161
|
+
memset(&tty, 0, sizeof(tty));
|
|
2162
|
+
tcgetattr(fd, &tty);
|
|
2163
|
+
oldtty = tty;
|
|
2164
|
+
|
|
2165
|
+
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|
|
2166
|
+
|INLCR|IGNCR|ICRNL|IXON);
|
|
2167
|
+
tty.c_oflag |= OPOST;
|
|
2168
|
+
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
|
|
2169
|
+
tty.c_cflag &= ~(CSIZE|PARENB);
|
|
2170
|
+
tty.c_cflag |= CS8;
|
|
2171
|
+
tty.c_cc[VMIN] = 1;
|
|
2172
|
+
tty.c_cc[VTIME] = 0;
|
|
2173
|
+
|
|
2174
|
+
tcsetattr(fd, TCSANOW, &tty);
|
|
2175
|
+
|
|
2176
|
+
atexit(term_exit);
|
|
2177
|
+
return JS_UNDEFINED;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
#endif /* !_WIN32 && !__wasi__ */
|
|
2181
|
+
|
|
2182
|
+
static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
|
|
2183
|
+
int argc, JSValueConst *argv)
|
|
2184
|
+
{
|
|
2185
|
+
const char *filename;
|
|
2186
|
+
int ret;
|
|
2187
|
+
|
|
2188
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
2189
|
+
if (!filename)
|
|
2190
|
+
return JS_EXCEPTION;
|
|
2191
|
+
#if defined(_WIN32)
|
|
2192
|
+
{
|
|
2193
|
+
struct stat st;
|
|
2194
|
+
if (stat(filename, &st) == 0 && (st.st_mode & _S_IFDIR)) {
|
|
2195
|
+
ret = rmdir(filename);
|
|
2196
|
+
} else {
|
|
2197
|
+
ret = unlink(filename);
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
#else
|
|
2201
|
+
ret = remove(filename);
|
|
2202
|
+
#endif
|
|
2203
|
+
ret = js_get_errno(ret);
|
|
2204
|
+
JS_FreeCString(ctx, filename);
|
|
2205
|
+
return JS_NewInt32(ctx, ret);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,
|
|
2209
|
+
int argc, JSValueConst *argv)
|
|
2210
|
+
{
|
|
2211
|
+
const char *oldpath, *newpath;
|
|
2212
|
+
int ret;
|
|
2213
|
+
|
|
2214
|
+
oldpath = JS_ToCString(ctx, argv[0]);
|
|
2215
|
+
if (!oldpath)
|
|
2216
|
+
return JS_EXCEPTION;
|
|
2217
|
+
newpath = JS_ToCString(ctx, argv[1]);
|
|
2218
|
+
if (!newpath) {
|
|
2219
|
+
JS_FreeCString(ctx, oldpath);
|
|
2220
|
+
return JS_EXCEPTION;
|
|
2221
|
+
}
|
|
2222
|
+
ret = js_get_errno(rename(oldpath, newpath));
|
|
2223
|
+
JS_FreeCString(ctx, oldpath);
|
|
2224
|
+
JS_FreeCString(ctx, newpath);
|
|
2225
|
+
return JS_NewInt32(ctx, ret);
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
static bool is_main_thread(JSRuntime *rt)
|
|
2229
|
+
{
|
|
2230
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2231
|
+
return !ts->recv_pipe;
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
static JSOSRWHandler *find_rh(JSThreadState *ts, int fd)
|
|
2235
|
+
{
|
|
2236
|
+
JSOSRWHandler *rh;
|
|
2237
|
+
struct list_head *el;
|
|
2238
|
+
|
|
2239
|
+
list_for_each(el, &ts->os_rw_handlers) {
|
|
2240
|
+
rh = list_entry(el, JSOSRWHandler, link);
|
|
2241
|
+
if (rh->fd == fd)
|
|
2242
|
+
return rh;
|
|
2243
|
+
}
|
|
2244
|
+
return NULL;
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh)
|
|
2248
|
+
{
|
|
2249
|
+
int i;
|
|
2250
|
+
list_del(&rh->link);
|
|
2251
|
+
for(i = 0; i < 2; i++) {
|
|
2252
|
+
JS_FreeValueRT(rt, rh->rw_func[i]);
|
|
2253
|
+
}
|
|
2254
|
+
js_free_rt(rt, rh);
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val,
|
|
2258
|
+
int argc, JSValueConst *argv, int magic)
|
|
2259
|
+
{
|
|
2260
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
2261
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2262
|
+
JSOSRWHandler *rh;
|
|
2263
|
+
int fd;
|
|
2264
|
+
JSValueConst func;
|
|
2265
|
+
|
|
2266
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
2267
|
+
return JS_EXCEPTION;
|
|
2268
|
+
func = argv[1];
|
|
2269
|
+
if (JS_IsNull(func)) {
|
|
2270
|
+
rh = find_rh(ts, fd);
|
|
2271
|
+
if (rh) {
|
|
2272
|
+
JS_FreeValue(ctx, rh->rw_func[magic]);
|
|
2273
|
+
rh->rw_func[magic] = JS_NULL;
|
|
2274
|
+
if (JS_IsNull(rh->rw_func[0]) &&
|
|
2275
|
+
JS_IsNull(rh->rw_func[1])) {
|
|
2276
|
+
/* remove the entry */
|
|
2277
|
+
free_rw_handler(JS_GetRuntime(ctx), rh);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
} else {
|
|
2281
|
+
if (!JS_IsFunction(ctx, func))
|
|
2282
|
+
return JS_ThrowTypeError(ctx, "not a function");
|
|
2283
|
+
rh = find_rh(ts, fd);
|
|
2284
|
+
if (!rh) {
|
|
2285
|
+
rh = js_mallocz(ctx, sizeof(*rh));
|
|
2286
|
+
if (!rh)
|
|
2287
|
+
return JS_EXCEPTION;
|
|
2288
|
+
rh->fd = fd;
|
|
2289
|
+
rh->rw_func[0] = JS_NULL;
|
|
2290
|
+
rh->rw_func[1] = JS_NULL;
|
|
2291
|
+
list_add_tail(&rh->link, &ts->os_rw_handlers);
|
|
2292
|
+
}
|
|
2293
|
+
JS_FreeValue(ctx, rh->rw_func[magic]);
|
|
2294
|
+
rh->rw_func[magic] = JS_DupValue(ctx, func);
|
|
2295
|
+
}
|
|
2296
|
+
return JS_UNDEFINED;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num)
|
|
2300
|
+
{
|
|
2301
|
+
JSOSSignalHandler *sh;
|
|
2302
|
+
struct list_head *el;
|
|
2303
|
+
list_for_each(el, &ts->os_signal_handlers) {
|
|
2304
|
+
sh = list_entry(el, JSOSSignalHandler, link);
|
|
2305
|
+
if (sh->sig_num == sig_num)
|
|
2306
|
+
return sh;
|
|
2307
|
+
}
|
|
2308
|
+
return NULL;
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
static void free_sh(JSRuntime *rt, JSOSSignalHandler *sh)
|
|
2312
|
+
{
|
|
2313
|
+
list_del(&sh->link);
|
|
2314
|
+
JS_FreeValueRT(rt, sh->func);
|
|
2315
|
+
js_free_rt(rt, sh);
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
static void os_signal_handler(int sig_num)
|
|
2319
|
+
{
|
|
2320
|
+
os_pending_signals |= ((uint64_t)1 << sig_num);
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
#if defined(_WIN32)
|
|
2324
|
+
typedef void (*sighandler_t)(int sig_num);
|
|
2325
|
+
#endif
|
|
2326
|
+
|
|
2327
|
+
static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
|
|
2328
|
+
int argc, JSValueConst *argv)
|
|
2329
|
+
{
|
|
2330
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
2331
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2332
|
+
JSOSSignalHandler *sh;
|
|
2333
|
+
uint32_t sig_num;
|
|
2334
|
+
JSValueConst func;
|
|
2335
|
+
sighandler_t handler;
|
|
2336
|
+
|
|
2337
|
+
if (!is_main_thread(rt))
|
|
2338
|
+
return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread");
|
|
2339
|
+
|
|
2340
|
+
if (JS_ToUint32(ctx, &sig_num, argv[0]))
|
|
2341
|
+
return JS_EXCEPTION;
|
|
2342
|
+
if (sig_num >= 64)
|
|
2343
|
+
return JS_ThrowRangeError(ctx, "invalid signal number");
|
|
2344
|
+
func = argv[1];
|
|
2345
|
+
/* func = null: SIG_DFL, func = undefined, SIG_IGN */
|
|
2346
|
+
if (JS_IsNull(func) || JS_IsUndefined(func)) {
|
|
2347
|
+
sh = find_sh(ts, sig_num);
|
|
2348
|
+
if (sh) {
|
|
2349
|
+
free_sh(JS_GetRuntime(ctx), sh);
|
|
2350
|
+
}
|
|
2351
|
+
if (JS_IsNull(func))
|
|
2352
|
+
handler = SIG_DFL;
|
|
2353
|
+
else
|
|
2354
|
+
handler = SIG_IGN;
|
|
2355
|
+
signal(sig_num, handler);
|
|
2356
|
+
} else {
|
|
2357
|
+
if (!JS_IsFunction(ctx, func))
|
|
2358
|
+
return JS_ThrowTypeError(ctx, "not a function");
|
|
2359
|
+
sh = find_sh(ts, sig_num);
|
|
2360
|
+
if (!sh) {
|
|
2361
|
+
sh = js_mallocz(ctx, sizeof(*sh));
|
|
2362
|
+
if (!sh)
|
|
2363
|
+
return JS_EXCEPTION;
|
|
2364
|
+
sh->sig_num = sig_num;
|
|
2365
|
+
list_add_tail(&sh->link, &ts->os_signal_handlers);
|
|
2366
|
+
}
|
|
2367
|
+
JS_FreeValue(ctx, sh->func);
|
|
2368
|
+
sh->func = JS_DupValue(ctx, func);
|
|
2369
|
+
signal(sig_num, os_signal_handler);
|
|
2370
|
+
}
|
|
2371
|
+
return JS_UNDEFINED;
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
#if !defined(_WIN32) && !defined(__wasi__)
|
|
2375
|
+
static JSValue js_os_cputime(JSContext *ctx, JSValueConst this_val,
|
|
2376
|
+
int argc, JSValueConst *argv)
|
|
2377
|
+
{
|
|
2378
|
+
struct rusage ru;
|
|
2379
|
+
int64_t cputime;
|
|
2380
|
+
|
|
2381
|
+
cputime = 0;
|
|
2382
|
+
if (!getrusage(RUSAGE_SELF, &ru))
|
|
2383
|
+
cputime = (int64_t)ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec;
|
|
2384
|
+
|
|
2385
|
+
return JS_NewInt64(ctx, cputime);
|
|
2386
|
+
}
|
|
2387
|
+
#endif
|
|
2388
|
+
|
|
2389
|
+
static JSValue js_os_exepath(JSContext *ctx, JSValueConst this_val,
|
|
2390
|
+
int argc, JSValueConst *argv)
|
|
2391
|
+
{
|
|
2392
|
+
char buf[JS__PATH_MAX];
|
|
2393
|
+
size_t len = sizeof(buf);
|
|
2394
|
+
if (js_exepath(buf, &len))
|
|
2395
|
+
return JS_UNDEFINED;
|
|
2396
|
+
return JS_NewStringLen(ctx, buf, len);
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
static JSValue js_os_now(JSContext *ctx, JSValueConst this_val,
|
|
2400
|
+
int argc, JSValueConst *argv)
|
|
2401
|
+
{
|
|
2402
|
+
return JS_NewInt64(ctx, js__hrtime_ns() / 1000);
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
static uint64_t js__hrtime_ms(void)
|
|
2406
|
+
{
|
|
2407
|
+
return js__hrtime_ns() / (1000 * 1000);
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
static void free_timer(JSRuntime *rt, JSOSTimer *th)
|
|
2411
|
+
{
|
|
2412
|
+
list_del(&th->link);
|
|
2413
|
+
JS_FreeValueRT(rt, th->func);
|
|
2414
|
+
js_free_rt(rt, th);
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
// TODO(bnoordhuis) accept string as first arg and eval at timer expiry
|
|
2418
|
+
// TODO(bnoordhuis) retain argv[2..] as args for callback if argc > 2
|
|
2419
|
+
static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
|
|
2420
|
+
int argc, JSValueConst *argv, int magic)
|
|
2421
|
+
{
|
|
2422
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
2423
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2424
|
+
int64_t delay;
|
|
2425
|
+
JSValueConst func;
|
|
2426
|
+
JSOSTimer *th;
|
|
2427
|
+
|
|
2428
|
+
func = argv[0];
|
|
2429
|
+
if (!JS_IsFunction(ctx, func))
|
|
2430
|
+
return JS_ThrowTypeError(ctx, "not a function");
|
|
2431
|
+
if (JS_ToInt64(ctx, &delay, argv[1]))
|
|
2432
|
+
return JS_EXCEPTION;
|
|
2433
|
+
if (delay < 1)
|
|
2434
|
+
delay = 1;
|
|
2435
|
+
th = js_mallocz(ctx, sizeof(*th));
|
|
2436
|
+
if (!th)
|
|
2437
|
+
return JS_EXCEPTION;
|
|
2438
|
+
th->timer_id = ts->next_timer_id++;
|
|
2439
|
+
if (ts->next_timer_id > MAX_SAFE_INTEGER)
|
|
2440
|
+
ts->next_timer_id = 1;
|
|
2441
|
+
th->repeats = (magic > 0);
|
|
2442
|
+
th->timeout = js__hrtime_ms() + delay;
|
|
2443
|
+
th->delay = delay;
|
|
2444
|
+
th->func = JS_DupValue(ctx, func);
|
|
2445
|
+
list_add_tail(&th->link, &ts->os_timers);
|
|
2446
|
+
return JS_NewInt64(ctx, th->timer_id);
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)
|
|
2450
|
+
{
|
|
2451
|
+
struct list_head *el;
|
|
2452
|
+
if (timer_id <= 0)
|
|
2453
|
+
return NULL;
|
|
2454
|
+
list_for_each(el, &ts->os_timers) {
|
|
2455
|
+
JSOSTimer *th = list_entry(el, JSOSTimer, link);
|
|
2456
|
+
if (th->timer_id == timer_id)
|
|
2457
|
+
return th;
|
|
2458
|
+
}
|
|
2459
|
+
return NULL;
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val,
|
|
2463
|
+
int argc, JSValueConst *argv)
|
|
2464
|
+
{
|
|
2465
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
2466
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2467
|
+
JSOSTimer *th;
|
|
2468
|
+
int64_t timer_id;
|
|
2469
|
+
|
|
2470
|
+
if (JS_ToInt64(ctx, &timer_id, argv[0]))
|
|
2471
|
+
return JS_EXCEPTION;
|
|
2472
|
+
th = find_timer_by_id(ts, timer_id);
|
|
2473
|
+
if (!th)
|
|
2474
|
+
return JS_UNDEFINED;
|
|
2475
|
+
free_timer(rt, th);
|
|
2476
|
+
return JS_UNDEFINED;
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
/* return a promise */
|
|
2480
|
+
static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
|
|
2481
|
+
int argc, JSValueConst *argv)
|
|
2482
|
+
{
|
|
2483
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
2484
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2485
|
+
int64_t delay;
|
|
2486
|
+
JSOSTimer *th;
|
|
2487
|
+
JSValue promise, resolving_funcs[2];
|
|
2488
|
+
|
|
2489
|
+
if (JS_ToInt64(ctx, &delay, argv[0]))
|
|
2490
|
+
return JS_EXCEPTION;
|
|
2491
|
+
promise = JS_NewPromiseCapability(ctx, resolving_funcs);
|
|
2492
|
+
if (JS_IsException(promise))
|
|
2493
|
+
return JS_EXCEPTION;
|
|
2494
|
+
|
|
2495
|
+
th = js_mallocz(ctx, sizeof(*th));
|
|
2496
|
+
if (!th) {
|
|
2497
|
+
JS_FreeValue(ctx, promise);
|
|
2498
|
+
JS_FreeValue(ctx, resolving_funcs[0]);
|
|
2499
|
+
JS_FreeValue(ctx, resolving_funcs[1]);
|
|
2500
|
+
return JS_EXCEPTION;
|
|
2501
|
+
}
|
|
2502
|
+
th->timer_id = -1;
|
|
2503
|
+
th->timeout = js__hrtime_ms() + delay;
|
|
2504
|
+
th->func = JS_DupValue(ctx, resolving_funcs[0]);
|
|
2505
|
+
list_add_tail(&th->link, &ts->os_timers);
|
|
2506
|
+
JS_FreeValue(ctx, resolving_funcs[0]);
|
|
2507
|
+
JS_FreeValue(ctx, resolving_funcs[1]);
|
|
2508
|
+
return promise;
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
static int call_handler(JSContext *ctx, JSValue func)
|
|
2512
|
+
{
|
|
2513
|
+
int r;
|
|
2514
|
+
JSValue ret, func1;
|
|
2515
|
+
/* 'func' might be destroyed when calling itself (if it frees the
|
|
2516
|
+
handler), so must take extra care */
|
|
2517
|
+
func1 = JS_DupValue(ctx, func);
|
|
2518
|
+
ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL);
|
|
2519
|
+
JS_FreeValue(ctx, func1);
|
|
2520
|
+
r = 0;
|
|
2521
|
+
if (JS_IsException(ret))
|
|
2522
|
+
r = -1;
|
|
2523
|
+
JS_FreeValue(ctx, ret);
|
|
2524
|
+
return r;
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
static int js_os_run_timers(JSRuntime *rt, JSContext *ctx, JSThreadState *ts, int *min_delay)
|
|
2528
|
+
{
|
|
2529
|
+
JSValue func;
|
|
2530
|
+
JSOSTimer *th;
|
|
2531
|
+
int64_t cur_time, delay;
|
|
2532
|
+
struct list_head *el;
|
|
2533
|
+
int r;
|
|
2534
|
+
|
|
2535
|
+
if (list_empty(&ts->os_timers)) {
|
|
2536
|
+
*min_delay = -1;
|
|
2537
|
+
return 0;
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
cur_time = js__hrtime_ms();
|
|
2541
|
+
*min_delay = INT32_MAX;
|
|
2542
|
+
|
|
2543
|
+
list_for_each(el, &ts->os_timers) {
|
|
2544
|
+
th = list_entry(el, JSOSTimer, link);
|
|
2545
|
+
delay = th->timeout - cur_time;
|
|
2546
|
+
if (delay > 0) {
|
|
2547
|
+
*min_delay = min_int(*min_delay, delay);
|
|
2548
|
+
} else {
|
|
2549
|
+
*min_delay = 0;
|
|
2550
|
+
func = JS_DupValueRT(rt, th->func);
|
|
2551
|
+
if (th->repeats)
|
|
2552
|
+
th->timeout = cur_time + th->delay;
|
|
2553
|
+
else
|
|
2554
|
+
free_timer(rt, th);
|
|
2555
|
+
r = call_handler(ctx, func);
|
|
2556
|
+
JS_FreeValueRT(rt, func);
|
|
2557
|
+
return r;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
return 0;
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
#ifdef USE_WORKER
|
|
2565
|
+
|
|
2566
|
+
#ifdef _WIN32
|
|
2567
|
+
|
|
2568
|
+
static int js_waker_init(JSWaker *w)
|
|
2569
|
+
{
|
|
2570
|
+
w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
2571
|
+
return w->handle ? 0 : -1;
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
static void js_waker_signal(JSWaker *w)
|
|
2575
|
+
{
|
|
2576
|
+
SetEvent(w->handle);
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
static void js_waker_clear(JSWaker *w)
|
|
2580
|
+
{
|
|
2581
|
+
ResetEvent(w->handle);
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2584
|
+
static void js_waker_close(JSWaker *w)
|
|
2585
|
+
{
|
|
2586
|
+
CloseHandle(w->handle);
|
|
2587
|
+
w->handle = INVALID_HANDLE_VALUE;
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
#else // !_WIN32
|
|
2591
|
+
|
|
2592
|
+
static int js_waker_init(JSWaker *w)
|
|
2593
|
+
{
|
|
2594
|
+
int fds[2];
|
|
2595
|
+
|
|
2596
|
+
if (pipe(fds) < 0)
|
|
2597
|
+
return -1;
|
|
2598
|
+
w->read_fd = fds[0];
|
|
2599
|
+
w->write_fd = fds[1];
|
|
2600
|
+
return 0;
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
static void js_waker_signal(JSWaker *w)
|
|
2604
|
+
{
|
|
2605
|
+
int ret;
|
|
2606
|
+
|
|
2607
|
+
for(;;) {
|
|
2608
|
+
ret = write(w->write_fd, "", 1);
|
|
2609
|
+
if (ret == 1)
|
|
2610
|
+
break;
|
|
2611
|
+
if (ret < 0 && (errno != EAGAIN || errno != EINTR))
|
|
2612
|
+
break;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
static void js_waker_clear(JSWaker *w)
|
|
2617
|
+
{
|
|
2618
|
+
uint8_t buf[16];
|
|
2619
|
+
int ret;
|
|
2620
|
+
|
|
2621
|
+
for(;;) {
|
|
2622
|
+
ret = read(w->read_fd, buf, sizeof(buf));
|
|
2623
|
+
if (ret >= 0)
|
|
2624
|
+
break;
|
|
2625
|
+
if (errno != EAGAIN && errno != EINTR)
|
|
2626
|
+
break;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2630
|
+
static void js_waker_close(JSWaker *w)
|
|
2631
|
+
{
|
|
2632
|
+
close(w->read_fd);
|
|
2633
|
+
close(w->write_fd);
|
|
2634
|
+
w->read_fd = -1;
|
|
2635
|
+
w->write_fd = -1;
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
#endif // _WIN32
|
|
2639
|
+
|
|
2640
|
+
static void js_free_message(JSWorkerMessage *msg);
|
|
2641
|
+
|
|
2642
|
+
/* return 1 if a message was handled, 0 if no message */
|
|
2643
|
+
static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
|
|
2644
|
+
JSWorkerMessageHandler *port)
|
|
2645
|
+
{
|
|
2646
|
+
JSWorkerMessagePipe *ps = port->recv_pipe;
|
|
2647
|
+
int ret;
|
|
2648
|
+
struct list_head *el;
|
|
2649
|
+
JSWorkerMessage *msg;
|
|
2650
|
+
JSValue obj, data_obj, func, retval;
|
|
2651
|
+
|
|
2652
|
+
js_mutex_lock(&ps->mutex);
|
|
2653
|
+
if (!list_empty(&ps->msg_queue)) {
|
|
2654
|
+
el = ps->msg_queue.next;
|
|
2655
|
+
msg = list_entry(el, JSWorkerMessage, link);
|
|
2656
|
+
|
|
2657
|
+
/* remove the message from the queue */
|
|
2658
|
+
list_del(&msg->link);
|
|
2659
|
+
|
|
2660
|
+
// drain read end of pipe
|
|
2661
|
+
if (list_empty(&ps->msg_queue))
|
|
2662
|
+
js_waker_clear(&ps->waker);
|
|
2663
|
+
|
|
2664
|
+
js_mutex_unlock(&ps->mutex);
|
|
2665
|
+
|
|
2666
|
+
data_obj = JS_ReadObject(ctx, msg->data, msg->data_len,
|
|
2667
|
+
JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE);
|
|
2668
|
+
|
|
2669
|
+
js_free_message(msg);
|
|
2670
|
+
|
|
2671
|
+
if (JS_IsException(data_obj))
|
|
2672
|
+
goto fail;
|
|
2673
|
+
obj = JS_NewObject(ctx);
|
|
2674
|
+
if (JS_IsException(obj)) {
|
|
2675
|
+
JS_FreeValue(ctx, data_obj);
|
|
2676
|
+
goto fail;
|
|
2677
|
+
}
|
|
2678
|
+
JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E);
|
|
2679
|
+
|
|
2680
|
+
/* 'func' might be destroyed when calling itself (if it frees the
|
|
2681
|
+
handler), so must take extra care */
|
|
2682
|
+
func = JS_DupValue(ctx, port->on_message_func);
|
|
2683
|
+
retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj);
|
|
2684
|
+
JS_FreeValue(ctx, obj);
|
|
2685
|
+
JS_FreeValue(ctx, func);
|
|
2686
|
+
if (JS_IsException(retval)) {
|
|
2687
|
+
fail:
|
|
2688
|
+
js_std_dump_error(ctx);
|
|
2689
|
+
} else {
|
|
2690
|
+
JS_FreeValue(ctx, retval);
|
|
2691
|
+
}
|
|
2692
|
+
ret = 1;
|
|
2693
|
+
} else {
|
|
2694
|
+
js_mutex_unlock(&ps->mutex);
|
|
2695
|
+
ret = 0;
|
|
2696
|
+
}
|
|
2697
|
+
return ret;
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
#endif // USE_WORKER
|
|
2701
|
+
|
|
2702
|
+
/* flags for js_os_poll_internal */
|
|
2703
|
+
#define JS_OS_POLL_RUN_TIMERS (1 << 0)
|
|
2704
|
+
#define JS_OS_POLL_WORKERS (1 << 1)
|
|
2705
|
+
#define JS_OS_POLL_SIGNALS (1 << 2)
|
|
2706
|
+
|
|
2707
|
+
#if defined(_WIN32)
|
|
2708
|
+
static int js_os_poll_internal(JSContext *ctx, int timeout_ms, int flags)
|
|
2709
|
+
{
|
|
2710
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
2711
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2712
|
+
int min_delay, count;
|
|
2713
|
+
JSOSRWHandler *rh;
|
|
2714
|
+
struct list_head *el;
|
|
2715
|
+
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
|
|
2716
|
+
|
|
2717
|
+
/* XXX: handle signals if useful */
|
|
2718
|
+
|
|
2719
|
+
min_delay = timeout_ms;
|
|
2720
|
+
|
|
2721
|
+
if (flags & JS_OS_POLL_RUN_TIMERS) {
|
|
2722
|
+
if (js_os_run_timers(rt, ctx, ts, &min_delay))
|
|
2723
|
+
return -1;
|
|
2724
|
+
if (min_delay == 0)
|
|
2725
|
+
return 0; // expired timer
|
|
2726
|
+
if (min_delay < 0)
|
|
2727
|
+
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->port_list))
|
|
2728
|
+
return -1; /* no more events */
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
count = 0;
|
|
2732
|
+
list_for_each(el, &ts->os_rw_handlers) {
|
|
2733
|
+
rh = list_entry(el, JSOSRWHandler, link);
|
|
2734
|
+
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0]))
|
|
2735
|
+
handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
|
|
2736
|
+
if (count == (int)countof(handles))
|
|
2737
|
+
break;
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2740
|
+
if (flags & JS_OS_POLL_WORKERS) {
|
|
2741
|
+
list_for_each(el, &ts->port_list) {
|
|
2742
|
+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
|
2743
|
+
if (JS_IsNull(port->on_message_func))
|
|
2744
|
+
continue;
|
|
2745
|
+
handles[count++] = port->recv_pipe->waker.handle;
|
|
2746
|
+
if (count == (int)countof(handles))
|
|
2747
|
+
break;
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
if (count > 0) {
|
|
2752
|
+
DWORD ret, timeout = INFINITE;
|
|
2753
|
+
if (min_delay != -1)
|
|
2754
|
+
timeout = min_delay;
|
|
2755
|
+
ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
|
|
2756
|
+
if (ret < (DWORD)count) {
|
|
2757
|
+
list_for_each(el, &ts->os_rw_handlers) {
|
|
2758
|
+
rh = list_entry(el, JSOSRWHandler, link);
|
|
2759
|
+
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
|
|
2760
|
+
return call_handler(ctx, rh->rw_func[0]);
|
|
2761
|
+
/* must stop because the list may have been modified */
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
if (flags & JS_OS_POLL_WORKERS) {
|
|
2766
|
+
list_for_each(el, &ts->port_list) {
|
|
2767
|
+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
|
2768
|
+
if (!JS_IsNull(port->on_message_func)) {
|
|
2769
|
+
JSWorkerMessagePipe *ps = port->recv_pipe;
|
|
2770
|
+
if (ps->waker.handle == handles[ret]) {
|
|
2771
|
+
if (handle_posted_message(rt, ctx, port))
|
|
2772
|
+
goto done;
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
} else if (min_delay > 0) {
|
|
2779
|
+
Sleep(min_delay);
|
|
2780
|
+
}
|
|
2781
|
+
done:
|
|
2782
|
+
return 0;
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
static int js_os_poll(JSContext *ctx)
|
|
2786
|
+
{
|
|
2787
|
+
return js_os_poll_internal(ctx, -1,
|
|
2788
|
+
JS_OS_POLL_RUN_TIMERS | JS_OS_POLL_WORKERS | JS_OS_POLL_SIGNALS);
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
int js_std_poll_io(JSContext *ctx, int timeout_ms)
|
|
2792
|
+
{
|
|
2793
|
+
int ret = js_os_poll_internal(ctx, timeout_ms, 0);
|
|
2794
|
+
/* map return codes: -1 on error stays -1, negative from handler becomes -2 */
|
|
2795
|
+
if (ret < -1)
|
|
2796
|
+
return -2;
|
|
2797
|
+
return ret;
|
|
2798
|
+
}
|
|
2799
|
+
#else // !defined(_WIN32)
|
|
2800
|
+
static int js_os_poll_internal(JSContext *ctx, int timeout_ms, int flags)
|
|
2801
|
+
{
|
|
2802
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
2803
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
2804
|
+
int r, w, ret, nfds, min_delay;
|
|
2805
|
+
JSOSRWHandler *rh;
|
|
2806
|
+
struct list_head *el;
|
|
2807
|
+
struct pollfd *pfd, *pfds, pfds_local[64];
|
|
2808
|
+
|
|
2809
|
+
min_delay = timeout_ms;
|
|
2810
|
+
|
|
2811
|
+
/* only check signals in the main thread */
|
|
2812
|
+
if ((flags & JS_OS_POLL_SIGNALS) &&
|
|
2813
|
+
!ts->recv_pipe &&
|
|
2814
|
+
unlikely(os_pending_signals != 0)) {
|
|
2815
|
+
JSOSSignalHandler *sh;
|
|
2816
|
+
uint64_t mask;
|
|
2817
|
+
|
|
2818
|
+
list_for_each(el, &ts->os_signal_handlers) {
|
|
2819
|
+
sh = list_entry(el, JSOSSignalHandler, link);
|
|
2820
|
+
mask = (uint64_t)1 << sh->sig_num;
|
|
2821
|
+
if (os_pending_signals & mask) {
|
|
2822
|
+
os_pending_signals &= ~mask;
|
|
2823
|
+
return call_handler(ctx, sh->func);
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
if (flags & JS_OS_POLL_RUN_TIMERS) {
|
|
2829
|
+
if (js_os_run_timers(rt, ctx, ts, &min_delay))
|
|
2830
|
+
return -1;
|
|
2831
|
+
if (min_delay == 0)
|
|
2832
|
+
return 0; // expired timer
|
|
2833
|
+
if (min_delay < 0)
|
|
2834
|
+
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->port_list))
|
|
2835
|
+
return -1; /* no more events */
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
nfds = 0;
|
|
2839
|
+
list_for_each(el, &ts->os_rw_handlers) {
|
|
2840
|
+
rh = list_entry(el, JSOSRWHandler, link);
|
|
2841
|
+
nfds += (!JS_IsNull(rh->rw_func[0]) || !JS_IsNull(rh->rw_func[1]));
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
#ifdef USE_WORKER
|
|
2845
|
+
if (flags & JS_OS_POLL_WORKERS) {
|
|
2846
|
+
list_for_each(el, &ts->port_list) {
|
|
2847
|
+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
|
2848
|
+
nfds += !JS_IsNull(port->on_message_func);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
#endif // USE_WORKER
|
|
2852
|
+
|
|
2853
|
+
if (nfds == 0) {
|
|
2854
|
+
if (min_delay > 0) {
|
|
2855
|
+
struct timespec ts_sleep = {
|
|
2856
|
+
.tv_sec = min_delay / 1000,
|
|
2857
|
+
.tv_nsec = (min_delay % 1000) * 1000000L
|
|
2858
|
+
};
|
|
2859
|
+
uint64_t mask = os_pending_signals;
|
|
2860
|
+
while (nanosleep(&ts_sleep, &ts_sleep)
|
|
2861
|
+
&& errno == EINTR
|
|
2862
|
+
&& mask == os_pending_signals);
|
|
2863
|
+
}
|
|
2864
|
+
return 0;
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
pfd = pfds = pfds_local;
|
|
2868
|
+
if (nfds > (int)countof(pfds_local)) {
|
|
2869
|
+
pfd = pfds = js_malloc(ctx, nfds * sizeof(*pfd));
|
|
2870
|
+
if (!pfd)
|
|
2871
|
+
return -1;
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
list_for_each(el, &ts->os_rw_handlers) {
|
|
2875
|
+
rh = list_entry(el, JSOSRWHandler, link);
|
|
2876
|
+
r = POLLIN * !JS_IsNull(rh->rw_func[0]);
|
|
2877
|
+
w = POLLOUT * !JS_IsNull(rh->rw_func[1]);
|
|
2878
|
+
if (r || w)
|
|
2879
|
+
*pfd++ = (struct pollfd){rh->fd, r|w, 0};
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
#ifdef USE_WORKER
|
|
2883
|
+
if (flags & JS_OS_POLL_WORKERS) {
|
|
2884
|
+
list_for_each(el, &ts->port_list) {
|
|
2885
|
+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
|
2886
|
+
if (!JS_IsNull(port->on_message_func)) {
|
|
2887
|
+
JSWorkerMessagePipe *ps = port->recv_pipe;
|
|
2888
|
+
*pfd++ = (struct pollfd){ps->waker.read_fd, POLLIN, 0};
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
#endif // USE_WORKER
|
|
2893
|
+
|
|
2894
|
+
// FIXME(bnoordhuis) the loop below is quadratic in theory but
|
|
2895
|
+
// linear-ish in practice because we bail out on the first hit,
|
|
2896
|
+
// i.e., it's probably good enough for now
|
|
2897
|
+
ret = 0;
|
|
2898
|
+
nfds = poll(pfds, nfds, min_delay);
|
|
2899
|
+
if (nfds < 0) {
|
|
2900
|
+
ret = -1;
|
|
2901
|
+
goto done;
|
|
2902
|
+
}
|
|
2903
|
+
for (pfd = pfds; nfds-- > 0; pfd++) {
|
|
2904
|
+
rh = find_rh(ts, pfd->fd);
|
|
2905
|
+
if (rh) {
|
|
2906
|
+
r = (POLLERR|POLLHUP|POLLNVAL|POLLIN) * !JS_IsNull(rh->rw_func[0]);
|
|
2907
|
+
w = (POLLERR|POLLHUP|POLLNVAL|POLLOUT) * !JS_IsNull(rh->rw_func[1]);
|
|
2908
|
+
if (r & pfd->revents) {
|
|
2909
|
+
ret = call_handler(ctx, rh->rw_func[0]);
|
|
2910
|
+
goto done;
|
|
2911
|
+
/* must stop because the list may have been modified */
|
|
2912
|
+
}
|
|
2913
|
+
if (w & pfd->revents) {
|
|
2914
|
+
ret = call_handler(ctx, rh->rw_func[1]);
|
|
2915
|
+
goto done;
|
|
2916
|
+
/* must stop because the list may have been modified */
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
#ifdef USE_WORKER
|
|
2920
|
+
else if (flags & JS_OS_POLL_WORKERS) {
|
|
2921
|
+
list_for_each(el, &ts->port_list) {
|
|
2922
|
+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
|
2923
|
+
if (!JS_IsNull(port->on_message_func)) {
|
|
2924
|
+
JSWorkerMessagePipe *ps = port->recv_pipe;
|
|
2925
|
+
if (pfd->fd == ps->waker.read_fd) {
|
|
2926
|
+
if (handle_posted_message(rt, ctx, port))
|
|
2927
|
+
goto done;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
#endif // USE_WORKER
|
|
2933
|
+
}
|
|
2934
|
+
done:
|
|
2935
|
+
if (pfds != pfds_local)
|
|
2936
|
+
js_free(ctx, pfds);
|
|
2937
|
+
return ret;
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
static int js_os_poll(JSContext *ctx)
|
|
2941
|
+
{
|
|
2942
|
+
return js_os_poll_internal(ctx, -1,
|
|
2943
|
+
JS_OS_POLL_RUN_TIMERS | JS_OS_POLL_WORKERS | JS_OS_POLL_SIGNALS);
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2946
|
+
int js_std_poll_io(JSContext *ctx, int timeout_ms)
|
|
2947
|
+
{
|
|
2948
|
+
int ret = js_os_poll_internal(ctx, timeout_ms, 0);
|
|
2949
|
+
/* map return codes: -1 on error stays -1, negative from handler becomes -2 */
|
|
2950
|
+
if (ret < -1)
|
|
2951
|
+
return -2;
|
|
2952
|
+
return ret;
|
|
2953
|
+
}
|
|
2954
|
+
#endif // defined(_WIN32)
|
|
2955
|
+
|
|
2956
|
+
static JSValue make_obj_error(JSContext *ctx,
|
|
2957
|
+
JSValue obj,
|
|
2958
|
+
int err)
|
|
2959
|
+
{
|
|
2960
|
+
JSValue vals[2];
|
|
2961
|
+
|
|
2962
|
+
if (JS_IsException(obj))
|
|
2963
|
+
return obj;
|
|
2964
|
+
vals[0] = obj;
|
|
2965
|
+
vals[1] = JS_NewInt32(ctx, err);
|
|
2966
|
+
return JS_NewArrayFrom(ctx, countof(vals), vals);
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
static JSValue make_string_error(JSContext *ctx,
|
|
2970
|
+
const char *buf,
|
|
2971
|
+
int err)
|
|
2972
|
+
{
|
|
2973
|
+
return make_obj_error(ctx, JS_NewString(ctx, buf), err);
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
/* return [cwd, errorcode] */
|
|
2977
|
+
static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,
|
|
2978
|
+
int argc, JSValueConst *argv)
|
|
2979
|
+
{
|
|
2980
|
+
char buf[JS__PATH_MAX];
|
|
2981
|
+
int err;
|
|
2982
|
+
|
|
2983
|
+
if (!getcwd(buf, sizeof(buf))) {
|
|
2984
|
+
buf[0] = '\0';
|
|
2985
|
+
err = errno;
|
|
2986
|
+
} else {
|
|
2987
|
+
err = 0;
|
|
2988
|
+
}
|
|
2989
|
+
return make_string_error(ctx, buf, err);
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
|
|
2993
|
+
int argc, JSValueConst *argv)
|
|
2994
|
+
{
|
|
2995
|
+
const char *target;
|
|
2996
|
+
int err;
|
|
2997
|
+
|
|
2998
|
+
target = JS_ToCString(ctx, argv[0]);
|
|
2999
|
+
if (!target)
|
|
3000
|
+
return JS_EXCEPTION;
|
|
3001
|
+
err = js_get_errno(chdir(target));
|
|
3002
|
+
JS_FreeCString(ctx, target);
|
|
3003
|
+
return JS_NewInt32(ctx, err);
|
|
3004
|
+
}
|
|
3005
|
+
|
|
3006
|
+
static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,
|
|
3007
|
+
int argc, JSValueConst *argv)
|
|
3008
|
+
{
|
|
3009
|
+
int mode, ret;
|
|
3010
|
+
const char *path;
|
|
3011
|
+
|
|
3012
|
+
if (argc >= 2) {
|
|
3013
|
+
if (JS_ToInt32(ctx, &mode, argv[1]))
|
|
3014
|
+
return JS_EXCEPTION;
|
|
3015
|
+
} else {
|
|
3016
|
+
mode = 0777;
|
|
3017
|
+
}
|
|
3018
|
+
path = JS_ToCString(ctx, argv[0]);
|
|
3019
|
+
if (!path)
|
|
3020
|
+
return JS_EXCEPTION;
|
|
3021
|
+
#if defined(_WIN32)
|
|
3022
|
+
(void)mode;
|
|
3023
|
+
ret = js_get_errno(mkdir(path));
|
|
3024
|
+
#else
|
|
3025
|
+
ret = js_get_errno(mkdir(path, mode));
|
|
3026
|
+
#endif
|
|
3027
|
+
JS_FreeCString(ctx, path);
|
|
3028
|
+
return JS_NewInt32(ctx, ret);
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
/* return [array, errorcode] */
|
|
3032
|
+
static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
|
|
3033
|
+
int argc, JSValueConst *argv)
|
|
3034
|
+
{
|
|
3035
|
+
#ifdef _WIN32
|
|
3036
|
+
const char *path;
|
|
3037
|
+
JSValue obj;
|
|
3038
|
+
int err;
|
|
3039
|
+
uint32_t len;
|
|
3040
|
+
HANDLE h;
|
|
3041
|
+
WIN32_FIND_DATAA d;
|
|
3042
|
+
char s[1024];
|
|
3043
|
+
|
|
3044
|
+
path = JS_ToCString(ctx, argv[0]);
|
|
3045
|
+
if (!path)
|
|
3046
|
+
return JS_EXCEPTION;
|
|
3047
|
+
obj = JS_NewArray(ctx);
|
|
3048
|
+
if (JS_IsException(obj)) {
|
|
3049
|
+
JS_FreeCString(ctx, path);
|
|
3050
|
+
return JS_EXCEPTION;
|
|
3051
|
+
}
|
|
3052
|
+
snprintf(s, sizeof(s), "%s/*", path);
|
|
3053
|
+
JS_FreeCString(ctx, path);
|
|
3054
|
+
err = 0;
|
|
3055
|
+
h = FindFirstFileA(s, &d);
|
|
3056
|
+
if (h == INVALID_HANDLE_VALUE)
|
|
3057
|
+
err = GetLastError();
|
|
3058
|
+
if (err)
|
|
3059
|
+
goto done;
|
|
3060
|
+
JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewString(ctx, "."),
|
|
3061
|
+
JS_PROP_C_W_E);
|
|
3062
|
+
for (len = 1; FindNextFileA(h, &d); len++) {
|
|
3063
|
+
JS_DefinePropertyValueUint32(ctx, obj, len,
|
|
3064
|
+
JS_NewString(ctx, d.cFileName),
|
|
3065
|
+
JS_PROP_C_W_E);
|
|
3066
|
+
}
|
|
3067
|
+
FindClose(h);
|
|
3068
|
+
done:
|
|
3069
|
+
return make_obj_error(ctx, obj, err);
|
|
3070
|
+
#else
|
|
3071
|
+
const char *path;
|
|
3072
|
+
DIR *f;
|
|
3073
|
+
struct dirent *d;
|
|
3074
|
+
JSValue obj;
|
|
3075
|
+
int err;
|
|
3076
|
+
uint32_t len;
|
|
3077
|
+
|
|
3078
|
+
path = JS_ToCString(ctx, argv[0]);
|
|
3079
|
+
if (!path)
|
|
3080
|
+
return JS_EXCEPTION;
|
|
3081
|
+
obj = JS_NewArray(ctx);
|
|
3082
|
+
if (JS_IsException(obj)) {
|
|
3083
|
+
JS_FreeCString(ctx, path);
|
|
3084
|
+
return JS_EXCEPTION;
|
|
3085
|
+
}
|
|
3086
|
+
f = opendir(path);
|
|
3087
|
+
if (!f)
|
|
3088
|
+
err = errno;
|
|
3089
|
+
else
|
|
3090
|
+
err = 0;
|
|
3091
|
+
JS_FreeCString(ctx, path);
|
|
3092
|
+
if (!f)
|
|
3093
|
+
goto done;
|
|
3094
|
+
len = 0;
|
|
3095
|
+
for(;;) {
|
|
3096
|
+
errno = 0;
|
|
3097
|
+
d = readdir(f);
|
|
3098
|
+
if (!d) {
|
|
3099
|
+
err = errno;
|
|
3100
|
+
break;
|
|
3101
|
+
}
|
|
3102
|
+
JS_DefinePropertyValueUint32(ctx, obj, len++,
|
|
3103
|
+
JS_NewString(ctx, d->d_name),
|
|
3104
|
+
JS_PROP_C_W_E);
|
|
3105
|
+
}
|
|
3106
|
+
closedir(f);
|
|
3107
|
+
done:
|
|
3108
|
+
return make_obj_error(ctx, obj, err);
|
|
3109
|
+
#endif
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
#if !defined(_WIN32) && !defined(__wasi__)
|
|
3113
|
+
#define PAT "XXXXXX"
|
|
3114
|
+
#define PSZ (sizeof(PAT)-1)
|
|
3115
|
+
static JSValue js_os_mkdstemp(JSContext *ctx, JSValueConst this_val,
|
|
3116
|
+
int argc, JSValueConst *argv, int magic)
|
|
3117
|
+
{
|
|
3118
|
+
char pat_s[32] = "tmp"PAT, *pat = pat_s;
|
|
3119
|
+
const char *s;
|
|
3120
|
+
size_t k, n;
|
|
3121
|
+
JSValue val;
|
|
3122
|
+
int err;
|
|
3123
|
+
|
|
3124
|
+
if (argc > 0) {
|
|
3125
|
+
s = JS_ToCStringLen(ctx, &n, argv[0]);
|
|
3126
|
+
if (!s)
|
|
3127
|
+
return JS_EXCEPTION;
|
|
3128
|
+
k = n;
|
|
3129
|
+
if (n < PSZ || memcmp(&s[n-PSZ], PAT, PSZ))
|
|
3130
|
+
k += PSZ;
|
|
3131
|
+
if (k >= sizeof(pat_s))
|
|
3132
|
+
pat = js_malloc(ctx, k+1);
|
|
3133
|
+
if (pat) {
|
|
3134
|
+
memcpy(pat, s, n);
|
|
3135
|
+
if (n < k)
|
|
3136
|
+
memcpy(&pat[n], PAT, PSZ);
|
|
3137
|
+
pat[k] = '\0';
|
|
3138
|
+
}
|
|
3139
|
+
JS_FreeCString(ctx, s);
|
|
3140
|
+
if (!pat)
|
|
3141
|
+
return JS_EXCEPTION;
|
|
3142
|
+
}
|
|
3143
|
+
if (magic == 'd') {
|
|
3144
|
+
err = 0;
|
|
3145
|
+
if (!mkdtemp(pat))
|
|
3146
|
+
err = -errno;
|
|
3147
|
+
} else {
|
|
3148
|
+
err = js_get_errno(mkstemp(pat));
|
|
3149
|
+
}
|
|
3150
|
+
val = JS_NewString(ctx, pat);
|
|
3151
|
+
if (pat != pat_s)
|
|
3152
|
+
js_free(ctx, pat);
|
|
3153
|
+
return make_obj_error(ctx, val, err);
|
|
3154
|
+
}
|
|
3155
|
+
#undef PSZ
|
|
3156
|
+
#undef PAT
|
|
3157
|
+
#endif // !defined(_WIN32) && !defined(__wasi__)
|
|
3158
|
+
|
|
3159
|
+
#if !defined(_WIN32)
|
|
3160
|
+
static int64_t timespec_to_ms(const struct timespec *tv)
|
|
3161
|
+
{
|
|
3162
|
+
return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000);
|
|
3163
|
+
}
|
|
3164
|
+
#endif
|
|
3165
|
+
|
|
3166
|
+
/* return [obj, errcode] */
|
|
3167
|
+
static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,
|
|
3168
|
+
int argc, JSValueConst *argv, int is_lstat)
|
|
3169
|
+
{
|
|
3170
|
+
const char *path;
|
|
3171
|
+
int err, res;
|
|
3172
|
+
struct stat st;
|
|
3173
|
+
JSValue obj;
|
|
3174
|
+
|
|
3175
|
+
path = JS_ToCString(ctx, argv[0]);
|
|
3176
|
+
if (!path)
|
|
3177
|
+
return JS_EXCEPTION;
|
|
3178
|
+
#if defined(_WIN32)
|
|
3179
|
+
res = stat(path, &st);
|
|
3180
|
+
#else
|
|
3181
|
+
if (is_lstat)
|
|
3182
|
+
res = lstat(path, &st);
|
|
3183
|
+
else
|
|
3184
|
+
res = stat(path, &st);
|
|
3185
|
+
#endif
|
|
3186
|
+
err = (res < 0) ? errno : 0;
|
|
3187
|
+
JS_FreeCString(ctx, path);
|
|
3188
|
+
if (res < 0) {
|
|
3189
|
+
obj = JS_NULL;
|
|
3190
|
+
} else {
|
|
3191
|
+
obj = JS_NewObject(ctx);
|
|
3192
|
+
if (JS_IsException(obj))
|
|
3193
|
+
return JS_EXCEPTION;
|
|
3194
|
+
JS_DefinePropertyValueStr(ctx, obj, "dev",
|
|
3195
|
+
JS_NewInt64(ctx, st.st_dev),
|
|
3196
|
+
JS_PROP_C_W_E);
|
|
3197
|
+
JS_DefinePropertyValueStr(ctx, obj, "ino",
|
|
3198
|
+
JS_NewInt64(ctx, st.st_ino),
|
|
3199
|
+
JS_PROP_C_W_E);
|
|
3200
|
+
JS_DefinePropertyValueStr(ctx, obj, "mode",
|
|
3201
|
+
JS_NewInt32(ctx, st.st_mode),
|
|
3202
|
+
JS_PROP_C_W_E);
|
|
3203
|
+
JS_DefinePropertyValueStr(ctx, obj, "nlink",
|
|
3204
|
+
JS_NewInt64(ctx, st.st_nlink),
|
|
3205
|
+
JS_PROP_C_W_E);
|
|
3206
|
+
JS_DefinePropertyValueStr(ctx, obj, "uid",
|
|
3207
|
+
JS_NewInt64(ctx, st.st_uid),
|
|
3208
|
+
JS_PROP_C_W_E);
|
|
3209
|
+
JS_DefinePropertyValueStr(ctx, obj, "gid",
|
|
3210
|
+
JS_NewInt64(ctx, st.st_gid),
|
|
3211
|
+
JS_PROP_C_W_E);
|
|
3212
|
+
JS_DefinePropertyValueStr(ctx, obj, "rdev",
|
|
3213
|
+
JS_NewInt64(ctx, st.st_rdev),
|
|
3214
|
+
JS_PROP_C_W_E);
|
|
3215
|
+
JS_DefinePropertyValueStr(ctx, obj, "size",
|
|
3216
|
+
JS_NewInt64(ctx, st.st_size),
|
|
3217
|
+
JS_PROP_C_W_E);
|
|
3218
|
+
#if !defined(_WIN32)
|
|
3219
|
+
JS_DefinePropertyValueStr(ctx, obj, "blocks",
|
|
3220
|
+
JS_NewInt64(ctx, st.st_blocks),
|
|
3221
|
+
JS_PROP_C_W_E);
|
|
3222
|
+
#endif
|
|
3223
|
+
#if defined(_WIN32)
|
|
3224
|
+
JS_DefinePropertyValueStr(ctx, obj, "atime",
|
|
3225
|
+
JS_NewInt64(ctx, (int64_t)st.st_atime * 1000),
|
|
3226
|
+
JS_PROP_C_W_E);
|
|
3227
|
+
JS_DefinePropertyValueStr(ctx, obj, "mtime",
|
|
3228
|
+
JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000),
|
|
3229
|
+
JS_PROP_C_W_E);
|
|
3230
|
+
JS_DefinePropertyValueStr(ctx, obj, "ctime",
|
|
3231
|
+
JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000),
|
|
3232
|
+
JS_PROP_C_W_E);
|
|
3233
|
+
#elif defined(__APPLE__)
|
|
3234
|
+
JS_DefinePropertyValueStr(ctx, obj, "atime",
|
|
3235
|
+
JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)),
|
|
3236
|
+
JS_PROP_C_W_E);
|
|
3237
|
+
JS_DefinePropertyValueStr(ctx, obj, "mtime",
|
|
3238
|
+
JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)),
|
|
3239
|
+
JS_PROP_C_W_E);
|
|
3240
|
+
JS_DefinePropertyValueStr(ctx, obj, "ctime",
|
|
3241
|
+
JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)),
|
|
3242
|
+
JS_PROP_C_W_E);
|
|
3243
|
+
#else
|
|
3244
|
+
JS_DefinePropertyValueStr(ctx, obj, "atime",
|
|
3245
|
+
JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)),
|
|
3246
|
+
JS_PROP_C_W_E);
|
|
3247
|
+
JS_DefinePropertyValueStr(ctx, obj, "mtime",
|
|
3248
|
+
JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)),
|
|
3249
|
+
JS_PROP_C_W_E);
|
|
3250
|
+
JS_DefinePropertyValueStr(ctx, obj, "ctime",
|
|
3251
|
+
JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)),
|
|
3252
|
+
JS_PROP_C_W_E);
|
|
3253
|
+
#endif
|
|
3254
|
+
}
|
|
3255
|
+
return make_obj_error(ctx, obj, err);
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
#if !defined(_WIN32)
|
|
3259
|
+
static void ms_to_timeval(struct timeval *tv, uint64_t v)
|
|
3260
|
+
{
|
|
3261
|
+
tv->tv_sec = v / 1000;
|
|
3262
|
+
tv->tv_usec = (v % 1000) * 1000;
|
|
3263
|
+
}
|
|
3264
|
+
#endif
|
|
3265
|
+
|
|
3266
|
+
static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
|
|
3267
|
+
int argc, JSValueConst *argv)
|
|
3268
|
+
{
|
|
3269
|
+
const char *path;
|
|
3270
|
+
int64_t atime, mtime;
|
|
3271
|
+
int ret;
|
|
3272
|
+
|
|
3273
|
+
if (JS_ToInt64(ctx, &atime, argv[1]))
|
|
3274
|
+
return JS_EXCEPTION;
|
|
3275
|
+
if (JS_ToInt64(ctx, &mtime, argv[2]))
|
|
3276
|
+
return JS_EXCEPTION;
|
|
3277
|
+
path = JS_ToCString(ctx, argv[0]);
|
|
3278
|
+
if (!path)
|
|
3279
|
+
return JS_EXCEPTION;
|
|
3280
|
+
#if defined(_WIN32)
|
|
3281
|
+
{
|
|
3282
|
+
struct _utimbuf times;
|
|
3283
|
+
times.actime = atime / 1000;
|
|
3284
|
+
times.modtime = mtime / 1000;
|
|
3285
|
+
ret = js_get_errno(_utime(path, ×));
|
|
3286
|
+
}
|
|
3287
|
+
#else
|
|
3288
|
+
{
|
|
3289
|
+
struct timeval times[2];
|
|
3290
|
+
ms_to_timeval(×[0], atime);
|
|
3291
|
+
ms_to_timeval(×[1], mtime);
|
|
3292
|
+
ret = js_get_errno(utimes(path, times));
|
|
3293
|
+
}
|
|
3294
|
+
#endif
|
|
3295
|
+
JS_FreeCString(ctx, path);
|
|
3296
|
+
return JS_NewInt32(ctx, ret);
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
/* sleep(delay_ms) */
|
|
3300
|
+
static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
|
|
3301
|
+
int argc, JSValueConst *argv)
|
|
3302
|
+
{
|
|
3303
|
+
int64_t delay;
|
|
3304
|
+
int ret;
|
|
3305
|
+
|
|
3306
|
+
if (JS_ToInt64(ctx, &delay, argv[0]))
|
|
3307
|
+
return JS_EXCEPTION;
|
|
3308
|
+
if (delay < 0)
|
|
3309
|
+
delay = 0;
|
|
3310
|
+
#if defined(_WIN32)
|
|
3311
|
+
{
|
|
3312
|
+
if (delay > INT32_MAX)
|
|
3313
|
+
delay = INT32_MAX;
|
|
3314
|
+
Sleep(delay);
|
|
3315
|
+
ret = 0;
|
|
3316
|
+
}
|
|
3317
|
+
#else
|
|
3318
|
+
{
|
|
3319
|
+
struct timespec ts;
|
|
3320
|
+
|
|
3321
|
+
ts.tv_sec = delay / 1000;
|
|
3322
|
+
ts.tv_nsec = (delay % 1000) * 1000000;
|
|
3323
|
+
ret = js_get_errno(nanosleep(&ts, NULL));
|
|
3324
|
+
}
|
|
3325
|
+
#endif
|
|
3326
|
+
return JS_NewInt32(ctx, ret);
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
#if defined(_WIN32)
|
|
3330
|
+
static char *realpath(const char *path, char *buf)
|
|
3331
|
+
{
|
|
3332
|
+
if (!_fullpath(buf, path, JS__PATH_MAX)) {
|
|
3333
|
+
errno = ENOENT;
|
|
3334
|
+
return NULL;
|
|
3335
|
+
} else {
|
|
3336
|
+
return buf;
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
#endif
|
|
3340
|
+
|
|
3341
|
+
#if !defined(__wasi__)
|
|
3342
|
+
/* return [path, errorcode] */
|
|
3343
|
+
static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
|
|
3344
|
+
int argc, JSValueConst *argv)
|
|
3345
|
+
{
|
|
3346
|
+
const char *path;
|
|
3347
|
+
char buf[JS__PATH_MAX], *res;
|
|
3348
|
+
int err;
|
|
3349
|
+
|
|
3350
|
+
path = JS_ToCString(ctx, argv[0]);
|
|
3351
|
+
if (!path)
|
|
3352
|
+
return JS_EXCEPTION;
|
|
3353
|
+
res = realpath(path, buf);
|
|
3354
|
+
JS_FreeCString(ctx, path);
|
|
3355
|
+
if (!res) {
|
|
3356
|
+
buf[0] = '\0';
|
|
3357
|
+
err = errno;
|
|
3358
|
+
} else {
|
|
3359
|
+
err = 0;
|
|
3360
|
+
}
|
|
3361
|
+
return make_string_error(ctx, buf, err);
|
|
3362
|
+
}
|
|
3363
|
+
#endif
|
|
3364
|
+
|
|
3365
|
+
#if !defined(_WIN32) && !defined(__wasi__) && !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
|
|
3366
|
+
static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
|
|
3367
|
+
int argc, JSValueConst *argv)
|
|
3368
|
+
{
|
|
3369
|
+
const char *target, *linkpath;
|
|
3370
|
+
int err;
|
|
3371
|
+
|
|
3372
|
+
target = JS_ToCString(ctx, argv[0]);
|
|
3373
|
+
if (!target)
|
|
3374
|
+
return JS_EXCEPTION;
|
|
3375
|
+
linkpath = JS_ToCString(ctx, argv[1]);
|
|
3376
|
+
if (!linkpath) {
|
|
3377
|
+
JS_FreeCString(ctx, target);
|
|
3378
|
+
return JS_EXCEPTION;
|
|
3379
|
+
}
|
|
3380
|
+
err = js_get_errno(symlink(target, linkpath));
|
|
3381
|
+
JS_FreeCString(ctx, target);
|
|
3382
|
+
JS_FreeCString(ctx, linkpath);
|
|
3383
|
+
return JS_NewInt32(ctx, err);
|
|
3384
|
+
}
|
|
3385
|
+
|
|
3386
|
+
/* return [path, errorcode] */
|
|
3387
|
+
static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
|
|
3388
|
+
int argc, JSValueConst *argv)
|
|
3389
|
+
{
|
|
3390
|
+
const char *path;
|
|
3391
|
+
char buf[JS__PATH_MAX];
|
|
3392
|
+
int err;
|
|
3393
|
+
ssize_t res;
|
|
3394
|
+
|
|
3395
|
+
path = JS_ToCString(ctx, argv[0]);
|
|
3396
|
+
if (!path)
|
|
3397
|
+
return JS_EXCEPTION;
|
|
3398
|
+
res = readlink(path, buf, sizeof(buf) - 1);
|
|
3399
|
+
if (res < 0) {
|
|
3400
|
+
buf[0] = '\0';
|
|
3401
|
+
err = errno;
|
|
3402
|
+
} else {
|
|
3403
|
+
buf[res] = '\0';
|
|
3404
|
+
err = 0;
|
|
3405
|
+
}
|
|
3406
|
+
JS_FreeCString(ctx, path);
|
|
3407
|
+
return make_string_error(ctx, buf, err);
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
static char **build_envp(JSContext *ctx, JSValue obj)
|
|
3411
|
+
{
|
|
3412
|
+
uint32_t len, i;
|
|
3413
|
+
JSPropertyEnum *tab;
|
|
3414
|
+
char **envp, *pair;
|
|
3415
|
+
const char *key, *str;
|
|
3416
|
+
JSValue val;
|
|
3417
|
+
size_t key_len, str_len;
|
|
3418
|
+
|
|
3419
|
+
if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,
|
|
3420
|
+
JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0)
|
|
3421
|
+
return NULL;
|
|
3422
|
+
envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1));
|
|
3423
|
+
if (!envp)
|
|
3424
|
+
goto fail;
|
|
3425
|
+
for(i = 0; i < len; i++) {
|
|
3426
|
+
val = JS_GetProperty(ctx, obj, tab[i].atom);
|
|
3427
|
+
if (JS_IsException(val))
|
|
3428
|
+
goto fail;
|
|
3429
|
+
str = JS_ToCString(ctx, val);
|
|
3430
|
+
JS_FreeValue(ctx, val);
|
|
3431
|
+
if (!str)
|
|
3432
|
+
goto fail;
|
|
3433
|
+
key = JS_AtomToCString(ctx, tab[i].atom);
|
|
3434
|
+
if (!key) {
|
|
3435
|
+
JS_FreeCString(ctx, str);
|
|
3436
|
+
goto fail;
|
|
3437
|
+
}
|
|
3438
|
+
key_len = strlen(key);
|
|
3439
|
+
str_len = strlen(str);
|
|
3440
|
+
pair = js_malloc(ctx, key_len + str_len + 2);
|
|
3441
|
+
if (!pair) {
|
|
3442
|
+
JS_FreeCString(ctx, key);
|
|
3443
|
+
JS_FreeCString(ctx, str);
|
|
3444
|
+
goto fail;
|
|
3445
|
+
}
|
|
3446
|
+
memcpy(pair, key, key_len);
|
|
3447
|
+
pair[key_len] = '=';
|
|
3448
|
+
memcpy(pair + key_len + 1, str, str_len);
|
|
3449
|
+
pair[key_len + 1 + str_len] = '\0';
|
|
3450
|
+
envp[i] = pair;
|
|
3451
|
+
JS_FreeCString(ctx, key);
|
|
3452
|
+
JS_FreeCString(ctx, str);
|
|
3453
|
+
}
|
|
3454
|
+
done:
|
|
3455
|
+
for(i = 0; i < len; i++)
|
|
3456
|
+
JS_FreeAtom(ctx, tab[i].atom);
|
|
3457
|
+
js_free(ctx, tab);
|
|
3458
|
+
return envp;
|
|
3459
|
+
fail:
|
|
3460
|
+
if (envp) {
|
|
3461
|
+
for(i = 0; i < len; i++)
|
|
3462
|
+
js_free(ctx, envp[i]);
|
|
3463
|
+
js_free(ctx, envp);
|
|
3464
|
+
envp = NULL;
|
|
3465
|
+
}
|
|
3466
|
+
goto done;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
/* execvpe is not available on non GNU systems */
|
|
3470
|
+
static int my_execvpe(const char *filename, char **argv, char **envp)
|
|
3471
|
+
{
|
|
3472
|
+
char *path, *p, *p_next, *p1;
|
|
3473
|
+
char buf[JS__PATH_MAX];
|
|
3474
|
+
size_t filename_len, path_len;
|
|
3475
|
+
bool eacces_error;
|
|
3476
|
+
|
|
3477
|
+
filename_len = strlen(filename);
|
|
3478
|
+
if (filename_len == 0) {
|
|
3479
|
+
errno = ENOENT;
|
|
3480
|
+
return -1;
|
|
3481
|
+
}
|
|
3482
|
+
if (strchr(filename, '/'))
|
|
3483
|
+
return execve(filename, argv, envp);
|
|
3484
|
+
|
|
3485
|
+
path = getenv("PATH");
|
|
3486
|
+
if (!path)
|
|
3487
|
+
path = (char *)"/bin:/usr/bin";
|
|
3488
|
+
eacces_error = false;
|
|
3489
|
+
p = path;
|
|
3490
|
+
for(p = path; p != NULL; p = p_next) {
|
|
3491
|
+
p1 = strchr(p, ':');
|
|
3492
|
+
if (!p1) {
|
|
3493
|
+
p_next = NULL;
|
|
3494
|
+
path_len = strlen(p);
|
|
3495
|
+
} else {
|
|
3496
|
+
p_next = p1 + 1;
|
|
3497
|
+
path_len = p1 - p;
|
|
3498
|
+
}
|
|
3499
|
+
/* path too long */
|
|
3500
|
+
if ((path_len + 1 + filename_len + 1) > JS__PATH_MAX)
|
|
3501
|
+
continue;
|
|
3502
|
+
memcpy(buf, p, path_len);
|
|
3503
|
+
buf[path_len] = '/';
|
|
3504
|
+
memcpy(buf + path_len + 1, filename, filename_len);
|
|
3505
|
+
buf[path_len + 1 + filename_len] = '\0';
|
|
3506
|
+
|
|
3507
|
+
execve(buf, argv, envp);
|
|
3508
|
+
|
|
3509
|
+
switch(errno) {
|
|
3510
|
+
case EACCES:
|
|
3511
|
+
eacces_error = true;
|
|
3512
|
+
break;
|
|
3513
|
+
case ENOENT:
|
|
3514
|
+
case ENOTDIR:
|
|
3515
|
+
break;
|
|
3516
|
+
default:
|
|
3517
|
+
return -1;
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
if (eacces_error)
|
|
3521
|
+
errno = EACCES;
|
|
3522
|
+
return -1;
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
static void (*js_os_exec_closefrom)(int);
|
|
3526
|
+
|
|
3527
|
+
#if !defined(EMSCRIPTEN) && !defined(__wasi__)
|
|
3528
|
+
|
|
3529
|
+
static js_once_t js_os_exec_once = JS_ONCE_INIT;
|
|
3530
|
+
|
|
3531
|
+
static void js_os_exec_once_init(void)
|
|
3532
|
+
{
|
|
3533
|
+
*(void **) (&js_os_exec_closefrom) = dlsym(RTLD_DEFAULT, "closefrom");
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
#endif
|
|
3537
|
+
|
|
3538
|
+
/* exec(args[, options]) -> exitcode */
|
|
3539
|
+
static JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,
|
|
3540
|
+
int argc, JSValueConst *argv)
|
|
3541
|
+
{
|
|
3542
|
+
JSValueConst options, args = argv[0];
|
|
3543
|
+
JSValue val, ret_val;
|
|
3544
|
+
const char **exec_argv, *file = NULL, *str, *cwd = NULL;
|
|
3545
|
+
char **envp = environ;
|
|
3546
|
+
uint32_t exec_argc, i;
|
|
3547
|
+
int ret, pid, status;
|
|
3548
|
+
bool block_flag = true, use_path = true;
|
|
3549
|
+
static const char *std_name[3] = { "stdin", "stdout", "stderr" };
|
|
3550
|
+
int std_fds[3];
|
|
3551
|
+
uint32_t uid = -1, gid = -1;
|
|
3552
|
+
int ngroups = -1;
|
|
3553
|
+
gid_t groups[64];
|
|
3554
|
+
|
|
3555
|
+
val = JS_GetPropertyStr(ctx, args, "length");
|
|
3556
|
+
if (JS_IsException(val))
|
|
3557
|
+
return JS_EXCEPTION;
|
|
3558
|
+
ret = JS_ToUint32(ctx, &exec_argc, val);
|
|
3559
|
+
JS_FreeValue(ctx, val);
|
|
3560
|
+
if (ret)
|
|
3561
|
+
return JS_EXCEPTION;
|
|
3562
|
+
/* arbitrary limit to avoid overflow */
|
|
3563
|
+
if (exec_argc < 1 || exec_argc > 65535) {
|
|
3564
|
+
return JS_ThrowTypeError(ctx, "invalid number of arguments");
|
|
3565
|
+
}
|
|
3566
|
+
exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1));
|
|
3567
|
+
if (!exec_argv)
|
|
3568
|
+
return JS_EXCEPTION;
|
|
3569
|
+
for(i = 0; i < exec_argc; i++) {
|
|
3570
|
+
val = JS_GetPropertyUint32(ctx, args, i);
|
|
3571
|
+
if (JS_IsException(val))
|
|
3572
|
+
goto exception;
|
|
3573
|
+
str = JS_ToCString(ctx, val);
|
|
3574
|
+
JS_FreeValue(ctx, val);
|
|
3575
|
+
if (!str)
|
|
3576
|
+
goto exception;
|
|
3577
|
+
exec_argv[i] = str;
|
|
3578
|
+
}
|
|
3579
|
+
exec_argv[exec_argc] = NULL;
|
|
3580
|
+
|
|
3581
|
+
for(i = 0; i < 3; i++)
|
|
3582
|
+
std_fds[i] = i;
|
|
3583
|
+
|
|
3584
|
+
/* get the options, if any */
|
|
3585
|
+
if (argc >= 2) {
|
|
3586
|
+
options = argv[1];
|
|
3587
|
+
|
|
3588
|
+
if (get_bool_option(ctx, &block_flag, options, "block"))
|
|
3589
|
+
goto exception;
|
|
3590
|
+
if (get_bool_option(ctx, &use_path, options, "usePath"))
|
|
3591
|
+
goto exception;
|
|
3592
|
+
|
|
3593
|
+
val = JS_GetPropertyStr(ctx, options, "file");
|
|
3594
|
+
if (JS_IsException(val))
|
|
3595
|
+
goto exception;
|
|
3596
|
+
if (!JS_IsUndefined(val)) {
|
|
3597
|
+
file = JS_ToCString(ctx, val);
|
|
3598
|
+
JS_FreeValue(ctx, val);
|
|
3599
|
+
if (!file)
|
|
3600
|
+
goto exception;
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
val = JS_GetPropertyStr(ctx, options, "cwd");
|
|
3604
|
+
if (JS_IsException(val))
|
|
3605
|
+
goto exception;
|
|
3606
|
+
if (!JS_IsUndefined(val)) {
|
|
3607
|
+
cwd = JS_ToCString(ctx, val);
|
|
3608
|
+
JS_FreeValue(ctx, val);
|
|
3609
|
+
if (!cwd)
|
|
3610
|
+
goto exception;
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3613
|
+
/* stdin/stdout/stderr handles */
|
|
3614
|
+
for(i = 0; i < 3; i++) {
|
|
3615
|
+
val = JS_GetPropertyStr(ctx, options, std_name[i]);
|
|
3616
|
+
if (JS_IsException(val))
|
|
3617
|
+
goto exception;
|
|
3618
|
+
if (!JS_IsUndefined(val)) {
|
|
3619
|
+
int fd;
|
|
3620
|
+
ret = JS_ToInt32(ctx, &fd, val);
|
|
3621
|
+
JS_FreeValue(ctx, val);
|
|
3622
|
+
if (ret)
|
|
3623
|
+
goto exception;
|
|
3624
|
+
std_fds[i] = fd;
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
val = JS_GetPropertyStr(ctx, options, "env");
|
|
3629
|
+
if (JS_IsException(val))
|
|
3630
|
+
goto exception;
|
|
3631
|
+
if (!JS_IsUndefined(val)) {
|
|
3632
|
+
envp = build_envp(ctx, val);
|
|
3633
|
+
JS_FreeValue(ctx, val);
|
|
3634
|
+
if (!envp)
|
|
3635
|
+
goto exception;
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3638
|
+
val = JS_GetPropertyStr(ctx, options, "uid");
|
|
3639
|
+
if (JS_IsException(val))
|
|
3640
|
+
goto exception;
|
|
3641
|
+
if (!JS_IsUndefined(val)) {
|
|
3642
|
+
ret = JS_ToUint32(ctx, &uid, val);
|
|
3643
|
+
JS_FreeValue(ctx, val);
|
|
3644
|
+
if (ret)
|
|
3645
|
+
goto exception;
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
val = JS_GetPropertyStr(ctx, options, "gid");
|
|
3649
|
+
if (JS_IsException(val))
|
|
3650
|
+
goto exception;
|
|
3651
|
+
if (!JS_IsUndefined(val)) {
|
|
3652
|
+
ret = JS_ToUint32(ctx, &gid, val);
|
|
3653
|
+
JS_FreeValue(ctx, val);
|
|
3654
|
+
if (ret)
|
|
3655
|
+
goto exception;
|
|
3656
|
+
}
|
|
3657
|
+
|
|
3658
|
+
val = JS_GetPropertyStr(ctx, options, "groups");
|
|
3659
|
+
if (JS_IsException(val))
|
|
3660
|
+
goto exception;
|
|
3661
|
+
if (!JS_IsUndefined(val)) {
|
|
3662
|
+
int64_t idx, len;
|
|
3663
|
+
JSValue prop;
|
|
3664
|
+
uint32_t id;
|
|
3665
|
+
ngroups = 0;
|
|
3666
|
+
if (JS_GetLength(ctx, val, &len)) {
|
|
3667
|
+
JS_FreeValue(ctx, val);
|
|
3668
|
+
goto exception;
|
|
3669
|
+
}
|
|
3670
|
+
for (idx = 0; idx < len; idx++) {
|
|
3671
|
+
prop = JS_GetPropertyInt64(ctx, val, idx);
|
|
3672
|
+
if (JS_IsException(prop))
|
|
3673
|
+
break;
|
|
3674
|
+
if (JS_IsUndefined(prop))
|
|
3675
|
+
continue;
|
|
3676
|
+
ret = JS_ToUint32(ctx, &id, prop);
|
|
3677
|
+
JS_FreeValue(ctx, prop);
|
|
3678
|
+
if (ret)
|
|
3679
|
+
break;
|
|
3680
|
+
if (ngroups == countof(groups)) {
|
|
3681
|
+
JS_ThrowRangeError(ctx, "too many groups");
|
|
3682
|
+
break;
|
|
3683
|
+
}
|
|
3684
|
+
groups[ngroups++] = id;
|
|
3685
|
+
}
|
|
3686
|
+
JS_FreeValue(ctx, val);
|
|
3687
|
+
if (idx < len)
|
|
3688
|
+
goto exception;
|
|
3689
|
+
}
|
|
3690
|
+
|
|
3691
|
+
}
|
|
3692
|
+
|
|
3693
|
+
#if !defined(EMSCRIPTEN) && !defined(__wasi__)
|
|
3694
|
+
// should happen pre-fork because it calls dlsym()
|
|
3695
|
+
// and that's not an async-signal-safe function
|
|
3696
|
+
js_once(&js_os_exec_once, js_os_exec_once_init);
|
|
3697
|
+
#endif
|
|
3698
|
+
|
|
3699
|
+
pid = fork();
|
|
3700
|
+
if (pid < 0) {
|
|
3701
|
+
JS_ThrowTypeError(ctx, "fork error");
|
|
3702
|
+
goto exception;
|
|
3703
|
+
}
|
|
3704
|
+
if (pid == 0) {
|
|
3705
|
+
/* child */
|
|
3706
|
+
/* remap the stdin/stdout/stderr handles if necessary */
|
|
3707
|
+
for(i = 0; i < 3; i++) {
|
|
3708
|
+
if (std_fds[i] != i) {
|
|
3709
|
+
if (dup2(std_fds[i], i) < 0)
|
|
3710
|
+
_exit(127);
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3714
|
+
if (js_os_exec_closefrom) {
|
|
3715
|
+
js_os_exec_closefrom(3);
|
|
3716
|
+
} else {
|
|
3717
|
+
int fd_max = sysconf(_SC_OPEN_MAX);
|
|
3718
|
+
for(i = 3; i < fd_max; i++)
|
|
3719
|
+
close(i);
|
|
3720
|
+
}
|
|
3721
|
+
|
|
3722
|
+
if (cwd) {
|
|
3723
|
+
if (chdir(cwd) < 0)
|
|
3724
|
+
_exit(127);
|
|
3725
|
+
}
|
|
3726
|
+
if (ngroups != -1) {
|
|
3727
|
+
if (setgroups(ngroups, groups) < 0)
|
|
3728
|
+
_exit(127);
|
|
3729
|
+
}
|
|
3730
|
+
if (uid != -1) {
|
|
3731
|
+
if (setuid(uid) < 0)
|
|
3732
|
+
_exit(127);
|
|
3733
|
+
}
|
|
3734
|
+
if (gid != -1) {
|
|
3735
|
+
if (setgid(gid) < 0)
|
|
3736
|
+
_exit(127);
|
|
3737
|
+
}
|
|
3738
|
+
|
|
3739
|
+
if (!file)
|
|
3740
|
+
file = exec_argv[0];
|
|
3741
|
+
if (use_path)
|
|
3742
|
+
ret = my_execvpe(file, (char **)exec_argv, envp);
|
|
3743
|
+
else
|
|
3744
|
+
ret = execve(file, (char **)exec_argv, envp);
|
|
3745
|
+
_exit(127);
|
|
3746
|
+
}
|
|
3747
|
+
/* parent */
|
|
3748
|
+
if (block_flag) {
|
|
3749
|
+
for(;;) {
|
|
3750
|
+
ret = waitpid(pid, &status, 0);
|
|
3751
|
+
if (ret == pid) {
|
|
3752
|
+
if (WIFEXITED(status)) {
|
|
3753
|
+
ret = WEXITSTATUS(status);
|
|
3754
|
+
break;
|
|
3755
|
+
} else if (WIFSIGNALED(status)) {
|
|
3756
|
+
ret = -WTERMSIG(status);
|
|
3757
|
+
break;
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3761
|
+
} else {
|
|
3762
|
+
ret = pid;
|
|
3763
|
+
}
|
|
3764
|
+
ret_val = JS_NewInt32(ctx, ret);
|
|
3765
|
+
done:
|
|
3766
|
+
JS_FreeCString(ctx, file);
|
|
3767
|
+
JS_FreeCString(ctx, cwd);
|
|
3768
|
+
for(i = 0; i < exec_argc; i++)
|
|
3769
|
+
JS_FreeCString(ctx, exec_argv[i]);
|
|
3770
|
+
js_free(ctx, exec_argv);
|
|
3771
|
+
if (envp != environ) {
|
|
3772
|
+
char **p;
|
|
3773
|
+
p = envp;
|
|
3774
|
+
while (*p != NULL) {
|
|
3775
|
+
js_free(ctx, *p);
|
|
3776
|
+
p++;
|
|
3777
|
+
}
|
|
3778
|
+
js_free(ctx, envp);
|
|
3779
|
+
}
|
|
3780
|
+
return ret_val;
|
|
3781
|
+
exception:
|
|
3782
|
+
ret_val = JS_EXCEPTION;
|
|
3783
|
+
goto done;
|
|
3784
|
+
}
|
|
3785
|
+
|
|
3786
|
+
/* getpid() -> pid */
|
|
3787
|
+
static JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val,
|
|
3788
|
+
int argc, JSValueConst *argv)
|
|
3789
|
+
{
|
|
3790
|
+
return JS_NewInt32(ctx, getpid());
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
/* waitpid(pid, block) -> [pid, status] */
|
|
3794
|
+
static JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,
|
|
3795
|
+
int argc, JSValueConst *argv)
|
|
3796
|
+
{
|
|
3797
|
+
int pid, status, options, ret;
|
|
3798
|
+
JSValue obj;
|
|
3799
|
+
|
|
3800
|
+
if (JS_ToInt32(ctx, &pid, argv[0]))
|
|
3801
|
+
return JS_EXCEPTION;
|
|
3802
|
+
if (JS_ToInt32(ctx, &options, argv[1]))
|
|
3803
|
+
return JS_EXCEPTION;
|
|
3804
|
+
|
|
3805
|
+
ret = waitpid(pid, &status, options);
|
|
3806
|
+
if (ret < 0) {
|
|
3807
|
+
ret = -errno;
|
|
3808
|
+
status = 0;
|
|
3809
|
+
}
|
|
3810
|
+
|
|
3811
|
+
obj = JS_NewArray(ctx);
|
|
3812
|
+
if (JS_IsException(obj))
|
|
3813
|
+
return obj;
|
|
3814
|
+
JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret),
|
|
3815
|
+
JS_PROP_C_W_E);
|
|
3816
|
+
JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status),
|
|
3817
|
+
JS_PROP_C_W_E);
|
|
3818
|
+
return obj;
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
/* pipe() -> [read_fd, write_fd] or null if error */
|
|
3822
|
+
static JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val,
|
|
3823
|
+
int argc, JSValueConst *argv)
|
|
3824
|
+
{
|
|
3825
|
+
int pipe_fds[2], ret;
|
|
3826
|
+
JSValue obj;
|
|
3827
|
+
|
|
3828
|
+
ret = pipe(pipe_fds);
|
|
3829
|
+
if (ret < 0)
|
|
3830
|
+
return JS_NULL;
|
|
3831
|
+
obj = JS_NewArray(ctx);
|
|
3832
|
+
if (JS_IsException(obj))
|
|
3833
|
+
return obj;
|
|
3834
|
+
JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]),
|
|
3835
|
+
JS_PROP_C_W_E);
|
|
3836
|
+
JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]),
|
|
3837
|
+
JS_PROP_C_W_E);
|
|
3838
|
+
return obj;
|
|
3839
|
+
}
|
|
3840
|
+
|
|
3841
|
+
/* kill(pid, sig) */
|
|
3842
|
+
static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val,
|
|
3843
|
+
int argc, JSValueConst *argv)
|
|
3844
|
+
{
|
|
3845
|
+
int pid, sig, ret;
|
|
3846
|
+
|
|
3847
|
+
if (JS_ToInt32(ctx, &pid, argv[0]))
|
|
3848
|
+
return JS_EXCEPTION;
|
|
3849
|
+
if (JS_ToInt32(ctx, &sig, argv[1]))
|
|
3850
|
+
return JS_EXCEPTION;
|
|
3851
|
+
ret = js_get_errno(kill(pid, sig));
|
|
3852
|
+
return JS_NewInt32(ctx, ret);
|
|
3853
|
+
}
|
|
3854
|
+
|
|
3855
|
+
/* dup(fd) */
|
|
3856
|
+
static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val,
|
|
3857
|
+
int argc, JSValueConst *argv)
|
|
3858
|
+
{
|
|
3859
|
+
int fd, ret;
|
|
3860
|
+
|
|
3861
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
3862
|
+
return JS_EXCEPTION;
|
|
3863
|
+
ret = js_get_errno(dup(fd));
|
|
3864
|
+
return JS_NewInt32(ctx, ret);
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3867
|
+
/* dup2(fd) */
|
|
3868
|
+
static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
|
|
3869
|
+
int argc, JSValueConst *argv)
|
|
3870
|
+
{
|
|
3871
|
+
int fd, fd2, ret;
|
|
3872
|
+
|
|
3873
|
+
if (JS_ToInt32(ctx, &fd, argv[0]))
|
|
3874
|
+
return JS_EXCEPTION;
|
|
3875
|
+
if (JS_ToInt32(ctx, &fd2, argv[1]))
|
|
3876
|
+
return JS_EXCEPTION;
|
|
3877
|
+
ret = js_get_errno(dup2(fd, fd2));
|
|
3878
|
+
return JS_NewInt32(ctx, ret);
|
|
3879
|
+
}
|
|
3880
|
+
|
|
3881
|
+
#endif /* !_WIN32 */
|
|
3882
|
+
|
|
3883
|
+
#ifdef USE_WORKER
|
|
3884
|
+
|
|
3885
|
+
/* Worker */
|
|
3886
|
+
|
|
3887
|
+
typedef struct {
|
|
3888
|
+
JSWorkerMessagePipe *recv_pipe;
|
|
3889
|
+
JSWorkerMessagePipe *send_pipe;
|
|
3890
|
+
JSWorkerMessageHandler *msg_handler;
|
|
3891
|
+
} JSWorkerData;
|
|
3892
|
+
|
|
3893
|
+
typedef struct {
|
|
3894
|
+
char *filename; /* module filename */
|
|
3895
|
+
char *basename; /* module base name */
|
|
3896
|
+
JSWorkerMessagePipe *recv_pipe, *send_pipe;
|
|
3897
|
+
} WorkerFuncArgs;
|
|
3898
|
+
|
|
3899
|
+
typedef struct {
|
|
3900
|
+
int ref_count;
|
|
3901
|
+
uint64_t buf[];
|
|
3902
|
+
} JSSABHeader;
|
|
3903
|
+
|
|
3904
|
+
static JSRuntime *(*js_worker_new_runtime_func)(void);
|
|
3905
|
+
static JSContext *(*js_worker_new_context_func)(JSRuntime *rt);
|
|
3906
|
+
|
|
3907
|
+
static int atomic_add_int(int *ptr, int v)
|
|
3908
|
+
{
|
|
3909
|
+
return atomic_fetch_add((_Atomic uint32_t*)ptr, v) + v;
|
|
3910
|
+
}
|
|
3911
|
+
|
|
3912
|
+
/* shared array buffer allocator */
|
|
3913
|
+
static void *js_sab_alloc(void *opaque, size_t size)
|
|
3914
|
+
{
|
|
3915
|
+
JSSABHeader *sab;
|
|
3916
|
+
sab = malloc(sizeof(JSSABHeader) + size);
|
|
3917
|
+
if (!sab)
|
|
3918
|
+
return NULL;
|
|
3919
|
+
sab->ref_count = 1;
|
|
3920
|
+
return sab->buf;
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3923
|
+
static void js_sab_free(void *opaque, void *ptr)
|
|
3924
|
+
{
|
|
3925
|
+
JSSABHeader *sab;
|
|
3926
|
+
int ref_count;
|
|
3927
|
+
sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
|
|
3928
|
+
ref_count = atomic_add_int(&sab->ref_count, -1);
|
|
3929
|
+
assert(ref_count >= 0);
|
|
3930
|
+
if (ref_count == 0) {
|
|
3931
|
+
free(sab);
|
|
3932
|
+
}
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3935
|
+
static void js_sab_dup(void *opaque, void *ptr)
|
|
3936
|
+
{
|
|
3937
|
+
JSSABHeader *sab;
|
|
3938
|
+
sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
|
|
3939
|
+
atomic_add_int(&sab->ref_count, 1);
|
|
3940
|
+
}
|
|
3941
|
+
|
|
3942
|
+
static JSWorkerMessagePipe *js_new_message_pipe(void)
|
|
3943
|
+
{
|
|
3944
|
+
JSWorkerMessagePipe *ps;
|
|
3945
|
+
|
|
3946
|
+
ps = malloc(sizeof(*ps));
|
|
3947
|
+
if (!ps)
|
|
3948
|
+
return NULL;
|
|
3949
|
+
if (js_waker_init(&ps->waker)) {
|
|
3950
|
+
free(ps);
|
|
3951
|
+
return NULL;
|
|
3952
|
+
}
|
|
3953
|
+
ps->ref_count = 1;
|
|
3954
|
+
init_list_head(&ps->msg_queue);
|
|
3955
|
+
js_mutex_init(&ps->mutex);
|
|
3956
|
+
return ps;
|
|
3957
|
+
}
|
|
3958
|
+
|
|
3959
|
+
static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps)
|
|
3960
|
+
{
|
|
3961
|
+
atomic_add_int(&ps->ref_count, 1);
|
|
3962
|
+
return ps;
|
|
3963
|
+
}
|
|
3964
|
+
|
|
3965
|
+
static void js_free_message(JSWorkerMessage *msg)
|
|
3966
|
+
{
|
|
3967
|
+
size_t i;
|
|
3968
|
+
/* free the SAB */
|
|
3969
|
+
for(i = 0; i < msg->sab_tab_len; i++) {
|
|
3970
|
+
js_sab_free(NULL, msg->sab_tab[i]);
|
|
3971
|
+
}
|
|
3972
|
+
free(msg->sab_tab);
|
|
3973
|
+
free(msg->data);
|
|
3974
|
+
free(msg);
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3977
|
+
static void js_free_message_pipe(JSWorkerMessagePipe *ps)
|
|
3978
|
+
{
|
|
3979
|
+
struct list_head *el, *el1;
|
|
3980
|
+
JSWorkerMessage *msg;
|
|
3981
|
+
int ref_count;
|
|
3982
|
+
|
|
3983
|
+
if (!ps)
|
|
3984
|
+
return;
|
|
3985
|
+
|
|
3986
|
+
ref_count = atomic_add_int(&ps->ref_count, -1);
|
|
3987
|
+
assert(ref_count >= 0);
|
|
3988
|
+
if (ref_count == 0) {
|
|
3989
|
+
list_for_each_safe(el, el1, &ps->msg_queue) {
|
|
3990
|
+
msg = list_entry(el, JSWorkerMessage, link);
|
|
3991
|
+
js_free_message(msg);
|
|
3992
|
+
}
|
|
3993
|
+
js_mutex_destroy(&ps->mutex);
|
|
3994
|
+
js_waker_close(&ps->waker);
|
|
3995
|
+
free(ps);
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
|
|
3999
|
+
static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port)
|
|
4000
|
+
{
|
|
4001
|
+
if (port) {
|
|
4002
|
+
js_free_message_pipe(port->recv_pipe);
|
|
4003
|
+
JS_FreeValueRT(rt, port->on_message_func);
|
|
4004
|
+
list_del(&port->link);
|
|
4005
|
+
js_free_rt(rt, port);
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
|
|
4009
|
+
static void js_worker_finalizer(JSRuntime *rt, JSValueConst val)
|
|
4010
|
+
{
|
|
4011
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4012
|
+
JSWorkerData *worker = JS_GetOpaque(val, ts->worker_class_id);
|
|
4013
|
+
if (worker) {
|
|
4014
|
+
js_free_message_pipe(worker->recv_pipe);
|
|
4015
|
+
js_free_message_pipe(worker->send_pipe);
|
|
4016
|
+
js_free_port(rt, worker->msg_handler);
|
|
4017
|
+
js_free_rt(rt, worker);
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
static JSClassDef js_worker_class = {
|
|
4022
|
+
"Worker",
|
|
4023
|
+
.finalizer = js_worker_finalizer,
|
|
4024
|
+
};
|
|
4025
|
+
|
|
4026
|
+
static void worker_func(void *opaque)
|
|
4027
|
+
{
|
|
4028
|
+
JSRuntime *(*new_runtime_func)(void);
|
|
4029
|
+
JSContext *(*new_context_func)(JSRuntime *);
|
|
4030
|
+
WorkerFuncArgs *args = opaque;
|
|
4031
|
+
JSRuntime *rt;
|
|
4032
|
+
JSThreadState *ts;
|
|
4033
|
+
JSContext *ctx;
|
|
4034
|
+
JSValue val;
|
|
4035
|
+
|
|
4036
|
+
new_runtime_func = js_worker_new_runtime_func;
|
|
4037
|
+
if (!new_runtime_func)
|
|
4038
|
+
new_runtime_func = JS_NewRuntime;
|
|
4039
|
+
rt = new_runtime_func();
|
|
4040
|
+
if (rt == NULL) {
|
|
4041
|
+
fprintf(stderr, "JS_NewRuntime failure");
|
|
4042
|
+
exit(1);
|
|
4043
|
+
}
|
|
4044
|
+
js_std_init_handlers(rt);
|
|
4045
|
+
|
|
4046
|
+
JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
|
|
4047
|
+
|
|
4048
|
+
/* set the pipe to communicate with the parent */
|
|
4049
|
+
ts = js_get_thread_state(rt);
|
|
4050
|
+
ts->recv_pipe = args->recv_pipe;
|
|
4051
|
+
ts->send_pipe = args->send_pipe;
|
|
4052
|
+
|
|
4053
|
+
/* function pointer to avoid linking the whole JS_NewContext() if
|
|
4054
|
+
not needed */
|
|
4055
|
+
new_context_func = js_worker_new_context_func;
|
|
4056
|
+
if (!new_context_func)
|
|
4057
|
+
new_context_func = JS_NewContext;
|
|
4058
|
+
ctx = new_context_func(rt);
|
|
4059
|
+
if (ctx == NULL) {
|
|
4060
|
+
fprintf(stderr, "JS_NewContext failure");
|
|
4061
|
+
exit(1);
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
JS_SetCanBlock(rt, true);
|
|
4065
|
+
|
|
4066
|
+
js_std_add_helpers(ctx, -1, NULL);
|
|
4067
|
+
|
|
4068
|
+
val = JS_LoadModule(ctx, args->basename, args->filename);
|
|
4069
|
+
free(args->filename);
|
|
4070
|
+
free(args->basename);
|
|
4071
|
+
free(args);
|
|
4072
|
+
val = js_std_await(ctx, val);
|
|
4073
|
+
if (JS_IsException(val))
|
|
4074
|
+
js_std_dump_error(ctx);
|
|
4075
|
+
JS_FreeValue(ctx, val);
|
|
4076
|
+
|
|
4077
|
+
js_std_loop(ctx);
|
|
4078
|
+
|
|
4079
|
+
js_std_free_handlers(rt);
|
|
4080
|
+
JS_FreeContext(ctx);
|
|
4081
|
+
JS_FreeRuntime(rt);
|
|
4082
|
+
}
|
|
4083
|
+
|
|
4084
|
+
static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target,
|
|
4085
|
+
JSWorkerMessagePipe *recv_pipe,
|
|
4086
|
+
JSWorkerMessagePipe *send_pipe)
|
|
4087
|
+
{
|
|
4088
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4089
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4090
|
+
JSValue obj = JS_UNDEFINED, proto;
|
|
4091
|
+
JSWorkerData *s;
|
|
4092
|
+
|
|
4093
|
+
/* create the object */
|
|
4094
|
+
if (JS_IsUndefined(new_target)) {
|
|
4095
|
+
proto = JS_GetClassProto(ctx, ts->worker_class_id);
|
|
4096
|
+
} else {
|
|
4097
|
+
proto = JS_GetPropertyStr(ctx, new_target, "prototype");
|
|
4098
|
+
if (JS_IsException(proto))
|
|
4099
|
+
goto fail;
|
|
4100
|
+
}
|
|
4101
|
+
obj = JS_NewObjectProtoClass(ctx, proto, ts->worker_class_id);
|
|
4102
|
+
JS_FreeValue(ctx, proto);
|
|
4103
|
+
if (JS_IsException(obj))
|
|
4104
|
+
goto fail;
|
|
4105
|
+
s = js_mallocz(ctx, sizeof(*s));
|
|
4106
|
+
if (!s)
|
|
4107
|
+
goto fail;
|
|
4108
|
+
s->recv_pipe = js_dup_message_pipe(recv_pipe);
|
|
4109
|
+
s->send_pipe = js_dup_message_pipe(send_pipe);
|
|
4110
|
+
|
|
4111
|
+
JS_SetOpaque(obj, s);
|
|
4112
|
+
return obj;
|
|
4113
|
+
fail:
|
|
4114
|
+
JS_FreeValue(ctx, obj);
|
|
4115
|
+
return JS_EXCEPTION;
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
|
|
4119
|
+
int argc, JSValueConst *argv)
|
|
4120
|
+
{
|
|
4121
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4122
|
+
WorkerFuncArgs *args = NULL;
|
|
4123
|
+
js_thread_t thr;
|
|
4124
|
+
JSValue obj = JS_UNDEFINED;
|
|
4125
|
+
int ret;
|
|
4126
|
+
const char *filename = NULL, *basename;
|
|
4127
|
+
JSAtom basename_atom;
|
|
4128
|
+
|
|
4129
|
+
/* XXX: in order to avoid problems with resource liberation, we
|
|
4130
|
+
don't support creating workers inside workers */
|
|
4131
|
+
if (!is_main_thread(rt))
|
|
4132
|
+
return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker");
|
|
4133
|
+
|
|
4134
|
+
/* base name, assuming the calling function is a normal JS
|
|
4135
|
+
function */
|
|
4136
|
+
basename_atom = JS_GetScriptOrModuleName(ctx, 1);
|
|
4137
|
+
if (basename_atom == JS_ATOM_NULL) {
|
|
4138
|
+
return JS_ThrowTypeError(ctx, "could not determine calling script or module name");
|
|
4139
|
+
}
|
|
4140
|
+
basename = JS_AtomToCString(ctx, basename_atom);
|
|
4141
|
+
JS_FreeAtom(ctx, basename_atom);
|
|
4142
|
+
if (!basename)
|
|
4143
|
+
goto fail;
|
|
4144
|
+
|
|
4145
|
+
/* module name */
|
|
4146
|
+
filename = JS_ToCString(ctx, argv[0]);
|
|
4147
|
+
if (!filename)
|
|
4148
|
+
goto fail;
|
|
4149
|
+
|
|
4150
|
+
args = malloc(sizeof(*args));
|
|
4151
|
+
if (!args)
|
|
4152
|
+
goto oom_fail;
|
|
4153
|
+
memset(args, 0, sizeof(*args));
|
|
4154
|
+
args->filename = strdup(filename);
|
|
4155
|
+
args->basename = strdup(basename);
|
|
4156
|
+
|
|
4157
|
+
/* ports */
|
|
4158
|
+
args->recv_pipe = js_new_message_pipe();
|
|
4159
|
+
if (!args->recv_pipe)
|
|
4160
|
+
goto oom_fail;
|
|
4161
|
+
args->send_pipe = js_new_message_pipe();
|
|
4162
|
+
if (!args->send_pipe)
|
|
4163
|
+
goto oom_fail;
|
|
4164
|
+
|
|
4165
|
+
obj = js_worker_ctor_internal(ctx, new_target,
|
|
4166
|
+
args->send_pipe, args->recv_pipe);
|
|
4167
|
+
if (JS_IsException(obj))
|
|
4168
|
+
goto fail;
|
|
4169
|
+
|
|
4170
|
+
ret = js_thread_create(&thr, worker_func, args, JS_THREAD_CREATE_DETACHED);
|
|
4171
|
+
if (ret != 0) {
|
|
4172
|
+
JS_ThrowTypeError(ctx, "could not create worker");
|
|
4173
|
+
goto fail;
|
|
4174
|
+
}
|
|
4175
|
+
JS_FreeCString(ctx, basename);
|
|
4176
|
+
JS_FreeCString(ctx, filename);
|
|
4177
|
+
return obj;
|
|
4178
|
+
oom_fail:
|
|
4179
|
+
JS_ThrowOutOfMemory(ctx);
|
|
4180
|
+
fail:
|
|
4181
|
+
JS_FreeCString(ctx, basename);
|
|
4182
|
+
JS_FreeCString(ctx, filename);
|
|
4183
|
+
if (args) {
|
|
4184
|
+
free(args->filename);
|
|
4185
|
+
free(args->basename);
|
|
4186
|
+
js_free_message_pipe(args->recv_pipe);
|
|
4187
|
+
js_free_message_pipe(args->send_pipe);
|
|
4188
|
+
free(args);
|
|
4189
|
+
}
|
|
4190
|
+
JS_FreeValue(ctx, obj);
|
|
4191
|
+
return JS_EXCEPTION;
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
|
|
4195
|
+
int argc, JSValueConst *argv)
|
|
4196
|
+
{
|
|
4197
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4198
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4199
|
+
JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id);
|
|
4200
|
+
JSWorkerMessagePipe *ps;
|
|
4201
|
+
size_t data_len, i;
|
|
4202
|
+
uint8_t *data;
|
|
4203
|
+
JSWorkerMessage *msg;
|
|
4204
|
+
JSSABTab sab_tab;
|
|
4205
|
+
|
|
4206
|
+
if (!worker)
|
|
4207
|
+
return JS_EXCEPTION;
|
|
4208
|
+
|
|
4209
|
+
data = JS_WriteObject2(ctx, &data_len, argv[0],
|
|
4210
|
+
JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE,
|
|
4211
|
+
&sab_tab);
|
|
4212
|
+
if (!data)
|
|
4213
|
+
return JS_EXCEPTION;
|
|
4214
|
+
|
|
4215
|
+
msg = malloc(sizeof(*msg));
|
|
4216
|
+
if (!msg)
|
|
4217
|
+
goto fail;
|
|
4218
|
+
msg->data = NULL;
|
|
4219
|
+
msg->sab_tab = NULL;
|
|
4220
|
+
|
|
4221
|
+
/* must reallocate because the allocator may be different */
|
|
4222
|
+
msg->data = malloc(data_len);
|
|
4223
|
+
if (!msg->data)
|
|
4224
|
+
goto fail;
|
|
4225
|
+
memcpy(msg->data, data, data_len);
|
|
4226
|
+
msg->data_len = data_len;
|
|
4227
|
+
|
|
4228
|
+
if (sab_tab.len > 0) {
|
|
4229
|
+
msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab.len);
|
|
4230
|
+
if (!msg->sab_tab)
|
|
4231
|
+
goto fail;
|
|
4232
|
+
memcpy(msg->sab_tab, sab_tab.tab, sizeof(msg->sab_tab[0]) * sab_tab.len);
|
|
4233
|
+
}
|
|
4234
|
+
msg->sab_tab_len = sab_tab.len;
|
|
4235
|
+
|
|
4236
|
+
js_free(ctx, data);
|
|
4237
|
+
js_free(ctx, sab_tab.tab);
|
|
4238
|
+
|
|
4239
|
+
/* increment the SAB reference counts */
|
|
4240
|
+
for(i = 0; i < msg->sab_tab_len; i++) {
|
|
4241
|
+
js_sab_dup(NULL, msg->sab_tab[i]);
|
|
4242
|
+
}
|
|
4243
|
+
|
|
4244
|
+
ps = worker->send_pipe;
|
|
4245
|
+
js_mutex_lock(&ps->mutex);
|
|
4246
|
+
/* indicate that data is present */
|
|
4247
|
+
if (list_empty(&ps->msg_queue))
|
|
4248
|
+
js_waker_signal(&ps->waker);
|
|
4249
|
+
list_add_tail(&msg->link, &ps->msg_queue);
|
|
4250
|
+
js_mutex_unlock(&ps->mutex);
|
|
4251
|
+
return JS_UNDEFINED;
|
|
4252
|
+
fail:
|
|
4253
|
+
if (msg) {
|
|
4254
|
+
free(msg->data);
|
|
4255
|
+
free(msg->sab_tab);
|
|
4256
|
+
free(msg);
|
|
4257
|
+
}
|
|
4258
|
+
js_free(ctx, data);
|
|
4259
|
+
js_free(ctx, sab_tab.tab);
|
|
4260
|
+
return JS_EXCEPTION;
|
|
4261
|
+
|
|
4262
|
+
}
|
|
4263
|
+
|
|
4264
|
+
static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,
|
|
4265
|
+
JSValueConst func)
|
|
4266
|
+
{
|
|
4267
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4268
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4269
|
+
JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id);
|
|
4270
|
+
JSWorkerMessageHandler *port;
|
|
4271
|
+
|
|
4272
|
+
if (!worker)
|
|
4273
|
+
return JS_EXCEPTION;
|
|
4274
|
+
|
|
4275
|
+
port = worker->msg_handler;
|
|
4276
|
+
if (JS_IsNull(func)) {
|
|
4277
|
+
if (port) {
|
|
4278
|
+
js_free_port(rt, port);
|
|
4279
|
+
worker->msg_handler = NULL;
|
|
4280
|
+
}
|
|
4281
|
+
} else {
|
|
4282
|
+
if (!JS_IsFunction(ctx, func))
|
|
4283
|
+
return JS_ThrowTypeError(ctx, "not a function");
|
|
4284
|
+
if (!port) {
|
|
4285
|
+
port = js_mallocz(ctx, sizeof(*port));
|
|
4286
|
+
if (!port)
|
|
4287
|
+
return JS_EXCEPTION;
|
|
4288
|
+
port->recv_pipe = js_dup_message_pipe(worker->recv_pipe);
|
|
4289
|
+
port->on_message_func = JS_NULL;
|
|
4290
|
+
list_add_tail(&port->link, &ts->port_list);
|
|
4291
|
+
worker->msg_handler = port;
|
|
4292
|
+
}
|
|
4293
|
+
JS_FreeValue(ctx, port->on_message_func);
|
|
4294
|
+
port->on_message_func = JS_DupValue(ctx, func);
|
|
4295
|
+
}
|
|
4296
|
+
return JS_UNDEFINED;
|
|
4297
|
+
}
|
|
4298
|
+
|
|
4299
|
+
static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val)
|
|
4300
|
+
{
|
|
4301
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4302
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4303
|
+
JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, ts->worker_class_id);
|
|
4304
|
+
JSWorkerMessageHandler *port;
|
|
4305
|
+
if (!worker)
|
|
4306
|
+
return JS_EXCEPTION;
|
|
4307
|
+
port = worker->msg_handler;
|
|
4308
|
+
if (port) {
|
|
4309
|
+
return JS_DupValue(ctx, port->on_message_func);
|
|
4310
|
+
} else {
|
|
4311
|
+
return JS_NULL;
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
|
|
4315
|
+
static const JSCFunctionListEntry js_worker_proto_funcs[] = {
|
|
4316
|
+
JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ),
|
|
4317
|
+
JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ),
|
|
4318
|
+
};
|
|
4319
|
+
|
|
4320
|
+
#endif /* USE_WORKER */
|
|
4321
|
+
|
|
4322
|
+
void js_std_set_worker_new_runtime_func(JSRuntime *(*func)(void))
|
|
4323
|
+
{
|
|
4324
|
+
#ifdef USE_WORKER
|
|
4325
|
+
js_worker_new_runtime_func = func;
|
|
4326
|
+
#endif
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt))
|
|
4330
|
+
{
|
|
4331
|
+
#ifdef USE_WORKER
|
|
4332
|
+
js_worker_new_context_func = func;
|
|
4333
|
+
#endif
|
|
4334
|
+
}
|
|
4335
|
+
|
|
4336
|
+
#if defined(_WIN32)
|
|
4337
|
+
#define OS_PLATFORM "win32"
|
|
4338
|
+
#elif defined(__APPLE__)
|
|
4339
|
+
#define OS_PLATFORM "darwin"
|
|
4340
|
+
#elif defined(EMSCRIPTEN)
|
|
4341
|
+
#define OS_PLATFORM "js"
|
|
4342
|
+
#elif defined(__CYGWIN__)
|
|
4343
|
+
#define OS_PLATFORM "cygwin"
|
|
4344
|
+
#elif defined(__linux__)
|
|
4345
|
+
#define OS_PLATFORM "linux"
|
|
4346
|
+
#elif defined(__OpenBSD__)
|
|
4347
|
+
#define OS_PLATFORM "openbsd"
|
|
4348
|
+
#elif defined(__NetBSD__)
|
|
4349
|
+
#define OS_PLATFORM "netbsd"
|
|
4350
|
+
#elif defined(__FreeBSD__)
|
|
4351
|
+
#define OS_PLATFORM "freebsd"
|
|
4352
|
+
#elif defined(__wasi__)
|
|
4353
|
+
#define OS_PLATFORM "wasi"
|
|
4354
|
+
#elif defined(__GNU__)
|
|
4355
|
+
#define OS_PLATFORM "hurd"
|
|
4356
|
+
#else
|
|
4357
|
+
#define OS_PLATFORM "unknown"
|
|
4358
|
+
#endif
|
|
4359
|
+
|
|
4360
|
+
#define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )
|
|
4361
|
+
|
|
4362
|
+
static const JSCFunctionListEntry js_os_funcs[] = {
|
|
4363
|
+
JS_CFUNC_DEF("open", 2, js_os_open ),
|
|
4364
|
+
OS_FLAG(O_RDONLY),
|
|
4365
|
+
OS_FLAG(O_WRONLY),
|
|
4366
|
+
OS_FLAG(O_RDWR),
|
|
4367
|
+
OS_FLAG(O_APPEND),
|
|
4368
|
+
OS_FLAG(O_CREAT),
|
|
4369
|
+
OS_FLAG(O_EXCL),
|
|
4370
|
+
OS_FLAG(O_TRUNC),
|
|
4371
|
+
#if defined(_WIN32)
|
|
4372
|
+
OS_FLAG(O_BINARY),
|
|
4373
|
+
OS_FLAG(O_TEXT),
|
|
4374
|
+
#endif
|
|
4375
|
+
JS_CFUNC_DEF("close", 1, js_os_close ),
|
|
4376
|
+
JS_CFUNC_DEF("seek", 3, js_os_seek ),
|
|
4377
|
+
JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ),
|
|
4378
|
+
JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ),
|
|
4379
|
+
JS_CFUNC_DEF("isatty", 1, js_os_isatty ),
|
|
4380
|
+
#if !defined(__wasi__)
|
|
4381
|
+
JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ),
|
|
4382
|
+
JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ),
|
|
4383
|
+
#endif
|
|
4384
|
+
JS_CFUNC_DEF("remove", 1, js_os_remove ),
|
|
4385
|
+
JS_CFUNC_DEF("rename", 2, js_os_rename ),
|
|
4386
|
+
JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ),
|
|
4387
|
+
JS_CFUNC_MAGIC_DEF("setWriteHandler", 2, js_os_setReadHandler, 1 ),
|
|
4388
|
+
JS_CFUNC_DEF("signal", 2, js_os_signal ),
|
|
4389
|
+
OS_FLAG(SIGINT),
|
|
4390
|
+
OS_FLAG(SIGABRT),
|
|
4391
|
+
OS_FLAG(SIGFPE),
|
|
4392
|
+
OS_FLAG(SIGILL),
|
|
4393
|
+
OS_FLAG(SIGSEGV),
|
|
4394
|
+
OS_FLAG(SIGTERM),
|
|
4395
|
+
#if !defined(_WIN32) && !defined(__wasi__)
|
|
4396
|
+
OS_FLAG(SIGQUIT),
|
|
4397
|
+
OS_FLAG(SIGPIPE),
|
|
4398
|
+
OS_FLAG(SIGALRM),
|
|
4399
|
+
OS_FLAG(SIGUSR1),
|
|
4400
|
+
OS_FLAG(SIGUSR2),
|
|
4401
|
+
OS_FLAG(SIGCHLD),
|
|
4402
|
+
OS_FLAG(SIGCONT),
|
|
4403
|
+
OS_FLAG(SIGSTOP),
|
|
4404
|
+
OS_FLAG(SIGTSTP),
|
|
4405
|
+
OS_FLAG(SIGTTIN),
|
|
4406
|
+
OS_FLAG(SIGTTOU),
|
|
4407
|
+
JS_CFUNC_DEF("cputime", 0, js_os_cputime ),
|
|
4408
|
+
#endif
|
|
4409
|
+
JS_CFUNC_DEF("exePath", 0, js_os_exepath ),
|
|
4410
|
+
JS_CFUNC_DEF("now", 0, js_os_now ),
|
|
4411
|
+
JS_CFUNC_MAGIC_DEF("setTimeout", 2, js_os_setTimeout, 0 ),
|
|
4412
|
+
JS_CFUNC_MAGIC_DEF("setInterval", 2, js_os_setTimeout, 1 ),
|
|
4413
|
+
// per spec: both functions can cancel timeouts and intervals
|
|
4414
|
+
JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
|
|
4415
|
+
JS_CFUNC_DEF("clearInterval", 1, js_os_clearTimeout ),
|
|
4416
|
+
JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
|
|
4417
|
+
JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
|
|
4418
|
+
JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
|
|
4419
|
+
JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
|
|
4420
|
+
JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
|
|
4421
|
+
JS_CFUNC_DEF("readdir", 1, js_os_readdir ),
|
|
4422
|
+
#if !defined(_WIN32) && !defined(__wasi__)
|
|
4423
|
+
JS_CFUNC_MAGIC_DEF("mkdtemp", 0, js_os_mkdstemp, 'd' ),
|
|
4424
|
+
JS_CFUNC_MAGIC_DEF("mkstemp", 0, js_os_mkdstemp, 's' ),
|
|
4425
|
+
#endif
|
|
4426
|
+
/* st_mode constants */
|
|
4427
|
+
OS_FLAG(S_IFMT),
|
|
4428
|
+
OS_FLAG(S_IFIFO),
|
|
4429
|
+
OS_FLAG(S_IFCHR),
|
|
4430
|
+
OS_FLAG(S_IFDIR),
|
|
4431
|
+
OS_FLAG(S_IFBLK),
|
|
4432
|
+
OS_FLAG(S_IFREG),
|
|
4433
|
+
#if !defined(_WIN32)
|
|
4434
|
+
OS_FLAG(S_IFSOCK),
|
|
4435
|
+
OS_FLAG(S_IFLNK),
|
|
4436
|
+
OS_FLAG(S_ISGID),
|
|
4437
|
+
OS_FLAG(S_ISUID),
|
|
4438
|
+
#endif
|
|
4439
|
+
JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
|
|
4440
|
+
JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
|
|
4441
|
+
JS_CFUNC_DEF("sleep", 1, js_os_sleep ),
|
|
4442
|
+
#if !defined(__wasi__)
|
|
4443
|
+
JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
|
|
4444
|
+
#endif
|
|
4445
|
+
#if !defined(_WIN32) && !defined(__wasi__) && !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
|
|
4446
|
+
JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
|
|
4447
|
+
JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
|
|
4448
|
+
JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
|
|
4449
|
+
JS_CFUNC_DEF("exec", 1, js_os_exec ),
|
|
4450
|
+
JS_CFUNC_DEF("getpid", 0, js_os_getpid ),
|
|
4451
|
+
JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
|
|
4452
|
+
OS_FLAG(WNOHANG),
|
|
4453
|
+
JS_CFUNC_DEF("pipe", 0, js_os_pipe ),
|
|
4454
|
+
JS_CFUNC_DEF("kill", 2, js_os_kill ),
|
|
4455
|
+
JS_CFUNC_DEF("dup", 1, js_os_dup ),
|
|
4456
|
+
JS_CFUNC_DEF("dup2", 2, js_os_dup2 ),
|
|
4457
|
+
#endif
|
|
4458
|
+
};
|
|
4459
|
+
|
|
4460
|
+
static int js_os_init(JSContext *ctx, JSModuleDef *m)
|
|
4461
|
+
{
|
|
4462
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4463
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4464
|
+
|
|
4465
|
+
ts->can_js_os_poll = true;
|
|
4466
|
+
|
|
4467
|
+
#ifdef USE_WORKER
|
|
4468
|
+
{
|
|
4469
|
+
JSValue proto, obj;
|
|
4470
|
+
/* Worker class */
|
|
4471
|
+
JS_NewClassID(rt, &ts->worker_class_id);
|
|
4472
|
+
JS_NewClass(rt, ts->worker_class_id, &js_worker_class);
|
|
4473
|
+
proto = JS_NewObject(ctx);
|
|
4474
|
+
JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs));
|
|
4475
|
+
|
|
4476
|
+
obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1,
|
|
4477
|
+
JS_CFUNC_constructor, 0);
|
|
4478
|
+
JS_SetConstructor(ctx, obj, proto);
|
|
4479
|
+
|
|
4480
|
+
JS_SetClassProto(ctx, ts->worker_class_id, proto);
|
|
4481
|
+
|
|
4482
|
+
/* set 'Worker.parent' if necessary */
|
|
4483
|
+
if (ts->recv_pipe && ts->send_pipe) {
|
|
4484
|
+
JS_DefinePropertyValueStr(ctx, obj, "parent",
|
|
4485
|
+
js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe),
|
|
4486
|
+
JS_PROP_C_W_E);
|
|
4487
|
+
}
|
|
4488
|
+
|
|
4489
|
+
JS_SetModuleExport(ctx, m, "Worker", obj);
|
|
4490
|
+
}
|
|
4491
|
+
#endif /* USE_WORKER */
|
|
4492
|
+
|
|
4493
|
+
return JS_SetModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
|
|
4494
|
+
}
|
|
4495
|
+
|
|
4496
|
+
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)
|
|
4497
|
+
{
|
|
4498
|
+
JSModuleDef *m;
|
|
4499
|
+
m = JS_NewCModule(ctx, module_name, js_os_init);
|
|
4500
|
+
if (!m)
|
|
4501
|
+
return NULL;
|
|
4502
|
+
JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
|
|
4503
|
+
#ifdef USE_WORKER
|
|
4504
|
+
JS_AddModuleExport(ctx, m, "Worker");
|
|
4505
|
+
#endif
|
|
4506
|
+
return m;
|
|
4507
|
+
}
|
|
4508
|
+
|
|
4509
|
+
/**********************************************************/
|
|
4510
|
+
|
|
4511
|
+
static JSValue js_print(JSContext *ctx, JSValueConst this_val,
|
|
4512
|
+
int argc, JSValueConst *argv)
|
|
4513
|
+
{
|
|
4514
|
+
#ifdef _WIN32
|
|
4515
|
+
HANDLE handle;
|
|
4516
|
+
DWORD mode;
|
|
4517
|
+
#endif
|
|
4518
|
+
const char *s;
|
|
4519
|
+
JSValueConst v;
|
|
4520
|
+
DynBuf b;
|
|
4521
|
+
int i;
|
|
4522
|
+
|
|
4523
|
+
dbuf_init(&b);
|
|
4524
|
+
for(i = 0; i < argc; i++) {
|
|
4525
|
+
v = argv[i];
|
|
4526
|
+
s = JS_ToCString(ctx, v);
|
|
4527
|
+
if (!s && JS_IsObject(v)) {
|
|
4528
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
4529
|
+
JSValue t = JS_ToObjectString(ctx, v);
|
|
4530
|
+
s = JS_ToCString(ctx, t);
|
|
4531
|
+
JS_FreeValue(ctx, t);
|
|
4532
|
+
}
|
|
4533
|
+
if (s) {
|
|
4534
|
+
dbuf_printf(&b, "%s%s", &" "[!i], s);
|
|
4535
|
+
JS_FreeCString(ctx, s);
|
|
4536
|
+
} else {
|
|
4537
|
+
dbuf_printf(&b, "%s<exception>", &" "[!i]);
|
|
4538
|
+
JS_FreeValue(ctx, JS_GetException(ctx));
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
dbuf_putc(&b, '\n');
|
|
4542
|
+
#ifdef _WIN32
|
|
4543
|
+
// use WriteConsoleA with CP_UTF8 for better Unicode handling vis-a-vis
|
|
4544
|
+
// the mangling that happens when going through msvcrt's stdio layer,
|
|
4545
|
+
// *except* when stdout is redirected to something that is not a console
|
|
4546
|
+
handle = (HANDLE)_get_osfhandle(/*STDOUT_FILENO*/1); // don't CloseHandle
|
|
4547
|
+
if (GetFileType(handle) != FILE_TYPE_CHAR)
|
|
4548
|
+
goto fallback;
|
|
4549
|
+
if (!GetConsoleMode(handle, &mode))
|
|
4550
|
+
goto fallback;
|
|
4551
|
+
handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
4552
|
+
if (handle == INVALID_HANDLE_VALUE)
|
|
4553
|
+
goto fallback;
|
|
4554
|
+
mode = GetConsoleOutputCP();
|
|
4555
|
+
SetConsoleOutputCP(CP_UTF8);
|
|
4556
|
+
WriteConsoleA(handle, b.buf, b.size, NULL, NULL);
|
|
4557
|
+
SetConsoleOutputCP(mode);
|
|
4558
|
+
FlushFileBuffers(handle);
|
|
4559
|
+
goto done;
|
|
4560
|
+
fallback:
|
|
4561
|
+
#endif
|
|
4562
|
+
fwrite(b.buf, 1, b.size, stdout);
|
|
4563
|
+
fflush(stdout);
|
|
4564
|
+
goto done; // avoid unused label warning
|
|
4565
|
+
done:
|
|
4566
|
+
dbuf_free(&b);
|
|
4567
|
+
return JS_UNDEFINED;
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
|
|
4571
|
+
{
|
|
4572
|
+
JSValue global_obj, console, args;
|
|
4573
|
+
int i;
|
|
4574
|
+
|
|
4575
|
+
/* XXX: should these global definitions be enumerable? */
|
|
4576
|
+
global_obj = JS_GetGlobalObject(ctx);
|
|
4577
|
+
|
|
4578
|
+
console = JS_NewObject(ctx);
|
|
4579
|
+
JS_SetPropertyStr(ctx, console, "log",
|
|
4580
|
+
JS_NewCFunction(ctx, js_print, "log", 1));
|
|
4581
|
+
JS_SetPropertyStr(ctx, global_obj, "console", console);
|
|
4582
|
+
|
|
4583
|
+
/* same methods as the mozilla JS shell */
|
|
4584
|
+
if (argc >= 0) {
|
|
4585
|
+
args = JS_NewArray(ctx);
|
|
4586
|
+
for(i = 0; i < argc; i++) {
|
|
4587
|
+
JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i]));
|
|
4588
|
+
}
|
|
4589
|
+
JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args);
|
|
4590
|
+
}
|
|
4591
|
+
|
|
4592
|
+
JS_SetPropertyStr(ctx, global_obj, "print",
|
|
4593
|
+
JS_NewCFunction(ctx, js_print, "print", 1));
|
|
4594
|
+
|
|
4595
|
+
JS_FreeValue(ctx, global_obj);
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4598
|
+
static void js_std_finalize(JSRuntime *rt, void *arg)
|
|
4599
|
+
{
|
|
4600
|
+
JSThreadState *ts = arg;
|
|
4601
|
+
js_set_thread_state(rt, NULL);
|
|
4602
|
+
js_free_rt(rt, ts);
|
|
4603
|
+
}
|
|
4604
|
+
|
|
4605
|
+
void js_std_init_handlers(JSRuntime *rt)
|
|
4606
|
+
{
|
|
4607
|
+
JSThreadState *ts;
|
|
4608
|
+
|
|
4609
|
+
ts = js_mallocz_rt(rt, sizeof(*ts));
|
|
4610
|
+
if (!ts) {
|
|
4611
|
+
fprintf(stderr, "Could not allocate memory for the worker");
|
|
4612
|
+
exit(1);
|
|
4613
|
+
}
|
|
4614
|
+
init_list_head(&ts->os_rw_handlers);
|
|
4615
|
+
init_list_head(&ts->os_signal_handlers);
|
|
4616
|
+
init_list_head(&ts->os_timers);
|
|
4617
|
+
init_list_head(&ts->port_list);
|
|
4618
|
+
init_list_head(&ts->rejected_promise_list);
|
|
4619
|
+
|
|
4620
|
+
ts->next_timer_id = 1;
|
|
4621
|
+
|
|
4622
|
+
js_set_thread_state(rt, ts);
|
|
4623
|
+
JS_AddRuntimeFinalizer(rt, js_std_finalize, ts);
|
|
4624
|
+
|
|
4625
|
+
#ifdef USE_WORKER
|
|
4626
|
+
/* set the SharedArrayBuffer memory handlers */
|
|
4627
|
+
{
|
|
4628
|
+
JSSharedArrayBufferFunctions sf;
|
|
4629
|
+
memset(&sf, 0, sizeof(sf));
|
|
4630
|
+
sf.sab_alloc = js_sab_alloc;
|
|
4631
|
+
sf.sab_free = js_sab_free;
|
|
4632
|
+
sf.sab_dup = js_sab_dup;
|
|
4633
|
+
JS_SetSharedArrayBufferFunctions(rt, &sf);
|
|
4634
|
+
}
|
|
4635
|
+
#endif
|
|
4636
|
+
}
|
|
4637
|
+
|
|
4638
|
+
static void free_rp(JSRuntime *rt, JSRejectedPromiseEntry *rp)
|
|
4639
|
+
{
|
|
4640
|
+
list_del(&rp->link);
|
|
4641
|
+
JS_FreeValueRT(rt, rp->promise);
|
|
4642
|
+
JS_FreeValueRT(rt, rp->reason);
|
|
4643
|
+
js_free_rt(rt, rp);
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4646
|
+
void js_std_free_handlers(JSRuntime *rt)
|
|
4647
|
+
{
|
|
4648
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4649
|
+
struct list_head *el, *el1;
|
|
4650
|
+
|
|
4651
|
+
list_for_each_safe(el, el1, &ts->os_rw_handlers) {
|
|
4652
|
+
JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link);
|
|
4653
|
+
free_rw_handler(rt, rh);
|
|
4654
|
+
}
|
|
4655
|
+
|
|
4656
|
+
list_for_each_safe(el, el1, &ts->os_signal_handlers) {
|
|
4657
|
+
JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link);
|
|
4658
|
+
free_sh(rt, sh);
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4661
|
+
list_for_each_safe(el, el1, &ts->os_timers) {
|
|
4662
|
+
JSOSTimer *th = list_entry(el, JSOSTimer, link);
|
|
4663
|
+
free_timer(rt, th);
|
|
4664
|
+
}
|
|
4665
|
+
|
|
4666
|
+
list_for_each_safe(el, el1, &ts->rejected_promise_list) {
|
|
4667
|
+
JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
|
|
4668
|
+
free_rp(rt, rp);
|
|
4669
|
+
}
|
|
4670
|
+
|
|
4671
|
+
#ifdef USE_WORKER
|
|
4672
|
+
/* XXX: free port_list ? */
|
|
4673
|
+
js_free_message_pipe(ts->recv_pipe);
|
|
4674
|
+
js_free_message_pipe(ts->send_pipe);
|
|
4675
|
+
#endif
|
|
4676
|
+
}
|
|
4677
|
+
|
|
4678
|
+
static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val)
|
|
4679
|
+
{
|
|
4680
|
+
const char *str;
|
|
4681
|
+
|
|
4682
|
+
str = JS_ToCString(ctx, val);
|
|
4683
|
+
if (str) {
|
|
4684
|
+
fprintf(f, "%s\n", str);
|
|
4685
|
+
JS_FreeCString(ctx, str);
|
|
4686
|
+
} else {
|
|
4687
|
+
fprintf(f, "[exception]\n");
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
|
|
4691
|
+
static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val)
|
|
4692
|
+
{
|
|
4693
|
+
JSValue val;
|
|
4694
|
+
bool is_error;
|
|
4695
|
+
|
|
4696
|
+
is_error = JS_IsError(exception_val);
|
|
4697
|
+
js_dump_obj(ctx, stderr, exception_val);
|
|
4698
|
+
if (is_error) {
|
|
4699
|
+
val = JS_GetPropertyStr(ctx, exception_val, "stack");
|
|
4700
|
+
} else {
|
|
4701
|
+
js_std_cmd(/*ErrorBackTrace*/2, ctx, &val);
|
|
4702
|
+
}
|
|
4703
|
+
if (!JS_IsUndefined(val)) {
|
|
4704
|
+
js_dump_obj(ctx, stderr, val);
|
|
4705
|
+
JS_FreeValue(ctx, val);
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4709
|
+
void js_std_dump_error(JSContext *ctx)
|
|
4710
|
+
{
|
|
4711
|
+
JSValue exception_val;
|
|
4712
|
+
|
|
4713
|
+
exception_val = JS_GetException(ctx);
|
|
4714
|
+
js_std_dump_error1(ctx, exception_val);
|
|
4715
|
+
JS_FreeValue(ctx, exception_val);
|
|
4716
|
+
}
|
|
4717
|
+
|
|
4718
|
+
static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts,
|
|
4719
|
+
JSValueConst promise)
|
|
4720
|
+
{
|
|
4721
|
+
struct list_head *el;
|
|
4722
|
+
|
|
4723
|
+
list_for_each(el, &ts->rejected_promise_list) {
|
|
4724
|
+
JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
|
|
4725
|
+
if (JS_IsSameValue(ctx, rp->promise, promise))
|
|
4726
|
+
return rp;
|
|
4727
|
+
}
|
|
4728
|
+
return NULL;
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4731
|
+
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
|
|
4732
|
+
JSValueConst reason,
|
|
4733
|
+
bool is_handled, void *opaque)
|
|
4734
|
+
{
|
|
4735
|
+
|
|
4736
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4737
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4738
|
+
JSRejectedPromiseEntry *rp = find_rejected_promise(ctx, ts, promise);
|
|
4739
|
+
|
|
4740
|
+
if (is_handled) {
|
|
4741
|
+
/* the rejection is handled, so the entry can be removed if present */
|
|
4742
|
+
if (rp)
|
|
4743
|
+
free_rp(rt, rp);
|
|
4744
|
+
} else {
|
|
4745
|
+
/* add a new entry if needed */
|
|
4746
|
+
if (!rp) {
|
|
4747
|
+
rp = js_malloc_rt(rt, sizeof(*rp));
|
|
4748
|
+
if (rp) {
|
|
4749
|
+
rp->promise = JS_DupValue(ctx, promise);
|
|
4750
|
+
rp->reason = JS_DupValue(ctx, reason);
|
|
4751
|
+
list_add_tail(&rp->link, &ts->rejected_promise_list);
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
}
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4757
|
+
/* check if there are pending promise rejections. It must be done
|
|
4758
|
+
asynchrously in case a rejected promise is handled later. Currently
|
|
4759
|
+
we do it once the application is about to sleep. It could be done
|
|
4760
|
+
more often if needed. */
|
|
4761
|
+
static void js_std_promise_rejection_check(JSContext *ctx)
|
|
4762
|
+
{
|
|
4763
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4764
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4765
|
+
struct list_head *el;
|
|
4766
|
+
|
|
4767
|
+
if (unlikely(!list_empty(&ts->rejected_promise_list))) {
|
|
4768
|
+
list_for_each(el, &ts->rejected_promise_list) {
|
|
4769
|
+
JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
|
|
4770
|
+
fprintf(stderr, "Possibly unhandled promise rejection: ");
|
|
4771
|
+
js_std_dump_error1(ctx, rp->reason);
|
|
4772
|
+
fflush(stderr);
|
|
4773
|
+
}
|
|
4774
|
+
exit(1);
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
|
|
4778
|
+
/* main loop which calls the user JS callbacks */
|
|
4779
|
+
int js_std_loop(JSContext *ctx)
|
|
4780
|
+
{
|
|
4781
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4782
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4783
|
+
JSContext *ctx1;
|
|
4784
|
+
int err;
|
|
4785
|
+
|
|
4786
|
+
for(;;) {
|
|
4787
|
+
/* execute the pending jobs */
|
|
4788
|
+
for(;;) {
|
|
4789
|
+
err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
|
4790
|
+
if (err <= 0) {
|
|
4791
|
+
if (err < 0)
|
|
4792
|
+
goto done;
|
|
4793
|
+
break;
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
js_std_promise_rejection_check(ctx);
|
|
4798
|
+
|
|
4799
|
+
if (!ts->can_js_os_poll || js_os_poll(ctx))
|
|
4800
|
+
break;
|
|
4801
|
+
}
|
|
4802
|
+
done:
|
|
4803
|
+
return JS_HasException(ctx);
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4806
|
+
int js_std_loop_once(JSContext *ctx)
|
|
4807
|
+
{
|
|
4808
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4809
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4810
|
+
JSContext *ctx1;
|
|
4811
|
+
int err, min_delay;
|
|
4812
|
+
|
|
4813
|
+
/* execute all pending jobs */
|
|
4814
|
+
for(;;) {
|
|
4815
|
+
err = JS_ExecutePendingJob(rt, &ctx1);
|
|
4816
|
+
if (err < 0)
|
|
4817
|
+
return -2; /* error */
|
|
4818
|
+
if (err == 0)
|
|
4819
|
+
break;
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
/* run at most one expired timer */
|
|
4823
|
+
if (js_os_run_timers(rt, ctx, ts, &min_delay) < 0)
|
|
4824
|
+
return -2; /* error in timer callback */
|
|
4825
|
+
|
|
4826
|
+
/* check if more work is pending */
|
|
4827
|
+
if (JS_IsJobPending(rt))
|
|
4828
|
+
return 0; /* more microtasks pending */
|
|
4829
|
+
|
|
4830
|
+
if (min_delay == 0)
|
|
4831
|
+
return 0; /* timer ready to fire immediately */
|
|
4832
|
+
|
|
4833
|
+
if (min_delay > 0)
|
|
4834
|
+
return min_delay; /* next timer delay in ms */
|
|
4835
|
+
|
|
4836
|
+
return -1; /* idle, no pending work */
|
|
4837
|
+
}
|
|
4838
|
+
|
|
4839
|
+
/* Wait for a promise and execute pending jobs while waiting for
|
|
4840
|
+
it. Return the promise result or JS_EXCEPTION in case of promise
|
|
4841
|
+
rejection. */
|
|
4842
|
+
JSValue js_std_await(JSContext *ctx, JSValue obj)
|
|
4843
|
+
{
|
|
4844
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
|
4845
|
+
JSThreadState *ts = js_get_thread_state(rt);
|
|
4846
|
+
JSValue ret;
|
|
4847
|
+
int state;
|
|
4848
|
+
|
|
4849
|
+
for(;;) {
|
|
4850
|
+
state = JS_PromiseState(ctx, obj);
|
|
4851
|
+
if (state == JS_PROMISE_FULFILLED) {
|
|
4852
|
+
ret = JS_PromiseResult(ctx, obj);
|
|
4853
|
+
JS_FreeValue(ctx, obj);
|
|
4854
|
+
break;
|
|
4855
|
+
} else if (state == JS_PROMISE_REJECTED) {
|
|
4856
|
+
ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
|
|
4857
|
+
JS_FreeValue(ctx, obj);
|
|
4858
|
+
break;
|
|
4859
|
+
} else if (state == JS_PROMISE_PENDING) {
|
|
4860
|
+
JSContext *ctx1;
|
|
4861
|
+
int err;
|
|
4862
|
+
err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
|
|
4863
|
+
if (err < 0) {
|
|
4864
|
+
js_std_dump_error(ctx1);
|
|
4865
|
+
}
|
|
4866
|
+
if (err == 0)
|
|
4867
|
+
js_std_promise_rejection_check(ctx);
|
|
4868
|
+
if (ts->can_js_os_poll)
|
|
4869
|
+
js_os_poll(ctx);
|
|
4870
|
+
} else {
|
|
4871
|
+
/* not a promise */
|
|
4872
|
+
ret = obj;
|
|
4873
|
+
break;
|
|
4874
|
+
}
|
|
4875
|
+
}
|
|
4876
|
+
return ret;
|
|
4877
|
+
}
|
|
4878
|
+
|
|
4879
|
+
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
|
4880
|
+
int load_only)
|
|
4881
|
+
{
|
|
4882
|
+
JSValue obj, val;
|
|
4883
|
+
obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE);
|
|
4884
|
+
if (JS_IsException(obj))
|
|
4885
|
+
goto exception;
|
|
4886
|
+
if (load_only) {
|
|
4887
|
+
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
|
|
4888
|
+
if (js_module_set_import_meta(ctx, obj, false, false) < 0)
|
|
4889
|
+
goto exception;
|
|
4890
|
+
}
|
|
4891
|
+
JS_FreeValue(ctx, obj);
|
|
4892
|
+
} else {
|
|
4893
|
+
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
|
|
4894
|
+
if (JS_ResolveModule(ctx, obj) < 0) {
|
|
4895
|
+
JS_FreeValue(ctx, obj);
|
|
4896
|
+
goto exception;
|
|
4897
|
+
}
|
|
4898
|
+
if (js_module_set_import_meta(ctx, obj, false, true) < 0)
|
|
4899
|
+
goto exception;
|
|
4900
|
+
val = JS_EvalFunction(ctx, obj);
|
|
4901
|
+
val = js_std_await(ctx, val);
|
|
4902
|
+
} else {
|
|
4903
|
+
val = JS_EvalFunction(ctx, obj);
|
|
4904
|
+
}
|
|
4905
|
+
if (JS_IsException(val)) {
|
|
4906
|
+
exception:
|
|
4907
|
+
js_std_dump_error(ctx);
|
|
4908
|
+
exit(1);
|
|
4909
|
+
}
|
|
4910
|
+
JS_FreeValue(ctx, val);
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
|
|
4915
|
+
int argc, JSValueConst *argv)
|
|
4916
|
+
{
|
|
4917
|
+
uint8_t *buf;
|
|
4918
|
+
uint64_t pos, len;
|
|
4919
|
+
JSValue obj;
|
|
4920
|
+
size_t size;
|
|
4921
|
+
int flags;
|
|
4922
|
+
|
|
4923
|
+
if (JS_ToIndex(ctx, &pos, argv[1]))
|
|
4924
|
+
return JS_EXCEPTION;
|
|
4925
|
+
if (JS_ToIndex(ctx, &len, argv[2]))
|
|
4926
|
+
return JS_EXCEPTION;
|
|
4927
|
+
if (JS_ToInt32(ctx, &flags, argv[3]))
|
|
4928
|
+
return JS_EXCEPTION;
|
|
4929
|
+
flags &= ~JS_READ_OBJ_SAB;
|
|
4930
|
+
buf = JS_GetArrayBuffer(ctx, &size, argv[0]);
|
|
4931
|
+
if (!buf)
|
|
4932
|
+
return JS_EXCEPTION;
|
|
4933
|
+
if (pos + len > size)
|
|
4934
|
+
return JS_ThrowRangeError(ctx, "array buffer overflow");
|
|
4935
|
+
obj = JS_ReadObject(ctx, buf + pos, len, flags);
|
|
4936
|
+
return obj;
|
|
4937
|
+
}
|
|
4938
|
+
|
|
4939
|
+
static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,
|
|
4940
|
+
int argc, JSValueConst *argv)
|
|
4941
|
+
{
|
|
4942
|
+
size_t len;
|
|
4943
|
+
uint8_t *buf;
|
|
4944
|
+
JSValue array;
|
|
4945
|
+
int flags;
|
|
4946
|
+
|
|
4947
|
+
if (JS_ToInt32(ctx, &flags, argv[1]))
|
|
4948
|
+
return JS_EXCEPTION;
|
|
4949
|
+
flags &= ~JS_WRITE_OBJ_SAB;
|
|
4950
|
+
buf = JS_WriteObject(ctx, &len, argv[0], flags);
|
|
4951
|
+
if (!buf)
|
|
4952
|
+
return JS_EXCEPTION;
|
|
4953
|
+
array = JS_NewArrayBufferCopy(ctx, buf, len);
|
|
4954
|
+
js_free(ctx, buf);
|
|
4955
|
+
return array;
|
|
4956
|
+
}
|
|
4957
|
+
|
|
4958
|
+
|
|
4959
|
+
static const JSCFunctionListEntry js_bjson_funcs[] = {
|
|
4960
|
+
JS_CFUNC_DEF("read", 4, js_bjson_read ),
|
|
4961
|
+
JS_CFUNC_DEF("write", 2, js_bjson_write ),
|
|
4962
|
+
#define DEF(x) JS_PROP_INT32_DEF(#x, JS_##x, JS_PROP_CONFIGURABLE)
|
|
4963
|
+
DEF(READ_OBJ_BYTECODE),
|
|
4964
|
+
DEF(READ_OBJ_REFERENCE),
|
|
4965
|
+
DEF(WRITE_OBJ_BYTECODE),
|
|
4966
|
+
DEF(WRITE_OBJ_REFERENCE),
|
|
4967
|
+
DEF(WRITE_OBJ_STRIP_DEBUG),
|
|
4968
|
+
DEF(WRITE_OBJ_STRIP_SOURCE),
|
|
4969
|
+
#undef DEF
|
|
4970
|
+
};
|
|
4971
|
+
|
|
4972
|
+
static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
|
|
4973
|
+
{
|
|
4974
|
+
return JS_SetModuleExportList(ctx, m, js_bjson_funcs,
|
|
4975
|
+
countof(js_bjson_funcs));
|
|
4976
|
+
}
|
|
4977
|
+
|
|
4978
|
+
JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name)
|
|
4979
|
+
{
|
|
4980
|
+
JSModuleDef *m;
|
|
4981
|
+
m = JS_NewCModule(ctx, module_name, js_bjson_init);
|
|
4982
|
+
if (!m)
|
|
4983
|
+
return NULL;
|
|
4984
|
+
JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));
|
|
4985
|
+
return m;
|
|
4986
|
+
}
|