@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.
Files changed (209) hide show
  1. package/README.md +55 -0
  2. package/dist/zapp-cli.js +9471 -0
  3. package/native/src/app/app.zc +490 -0
  4. package/native/src/event/event.zc +24 -0
  5. package/native/src/event/events.zc +70 -0
  6. package/native/src/platform/darwin/backend.zc +923 -0
  7. package/native/src/platform/darwin/backend_bootstrap.zc +9 -0
  8. package/native/src/platform/darwin/bootstrap.zc +9 -0
  9. package/native/src/platform/darwin/engine_jsc.zc +86 -0
  10. package/native/src/platform/darwin/engine_qjs.zc +92 -0
  11. package/native/src/platform/darwin/platform.zc +156 -0
  12. package/native/src/platform/darwin/webview.zc +550 -0
  13. package/native/src/platform/darwin/webview_bootstrap.zc +9 -0
  14. package/native/src/platform/darwin/window.zc +1223 -0
  15. package/native/src/platform/darwin/worker/common.zc +223 -0
  16. package/native/src/platform/darwin/worker/core/base64_core.zc +29 -0
  17. package/native/src/platform/darwin/worker/core/crypto_core.zc +19 -0
  18. package/native/src/platform/darwin/worker/core/encoding_core.zc +32 -0
  19. package/native/src/platform/darwin/worker/core/fetch_core.zc +145 -0
  20. package/native/src/platform/darwin/worker/core/url_core.zc +69 -0
  21. package/native/src/platform/darwin/worker/core/websocket_core.zc +179 -0
  22. package/native/src/platform/darwin/worker/dispatch.zc +55 -0
  23. package/native/src/platform/darwin/worker/jsc/base64_jsc.zc +39 -0
  24. package/native/src/platform/darwin/worker/jsc/crypto_jsc.zc +49 -0
  25. package/native/src/platform/darwin/worker/jsc/encoding_jsc.zc +86 -0
  26. package/native/src/platform/darwin/worker/jsc/fetch_jsc.zc +149 -0
  27. package/native/src/platform/darwin/worker/jsc/url_jsc.zc +54 -0
  28. package/native/src/platform/darwin/worker/jsc/websocket_jsc.zc +127 -0
  29. package/native/src/platform/darwin/worker/jsc.zc +670 -0
  30. package/native/src/platform/darwin/worker/mod.zc +30 -0
  31. package/native/src/platform/darwin/worker/qjs/fetch_qjs.zc +233 -0
  32. package/native/src/platform/darwin/worker/qjs/qjs_macros.zc +23 -0
  33. package/native/src/platform/darwin/worker/qjs/websocket_qjs.zc +223 -0
  34. package/native/src/platform/darwin/worker/qjs.zc +1053 -0
  35. package/native/src/platform/darwin/worker/timers.zc +149 -0
  36. package/native/src/platform/darwin/worker/timers_qjs.zc +209 -0
  37. package/native/src/platform/platform.zc +64 -0
  38. package/native/src/platform/shared/log.zc +156 -0
  39. package/native/src/platform/shared/worker/qjs/base64_qjs.zc +38 -0
  40. package/native/src/platform/shared/worker/qjs/crypto_qjs.zc +44 -0
  41. package/native/src/platform/shared/worker/qjs/encoding_qjs.zc +95 -0
  42. package/native/src/platform/shared/worker/qjs/url_qjs.zc +65 -0
  43. package/native/src/platform/shared/worker_registry.zc +206 -0
  44. package/native/src/platform/window.zc +446 -0
  45. package/native/src/platform/windows/backend.zc +452 -0
  46. package/native/src/platform/windows/backend_bootstrap.zc +9 -0
  47. package/native/src/platform/windows/bootstrap.zc +9 -0
  48. package/native/src/platform/windows/engine_qjs.zc +60 -0
  49. package/native/src/platform/windows/platform.zc +387 -0
  50. package/native/src/platform/windows/webview.zc +1175 -0
  51. package/native/src/platform/windows/webview_bootstrap.zc +9 -0
  52. package/native/src/platform/windows/window.zc +1271 -0
  53. package/native/src/platform/windows/worker/common.zc +409 -0
  54. package/native/src/platform/windows/worker/core/base64_core.zc +52 -0
  55. package/native/src/platform/windows/worker/core/crypto_core.zc +34 -0
  56. package/native/src/platform/windows/worker/core/encoding_core.zc +60 -0
  57. package/native/src/platform/windows/worker/core/fetch_core.zc +274 -0
  58. package/native/src/platform/windows/worker/core/url_core.zc +216 -0
  59. package/native/src/platform/windows/worker/core/websocket_core.zc +343 -0
  60. package/native/src/platform/windows/worker/dispatch.zc +34 -0
  61. package/native/src/platform/windows/worker/mod.zc +46 -0
  62. package/native/src/platform/windows/worker/qjs/fetch_qjs.zc +255 -0
  63. package/native/src/platform/windows/worker/qjs/websocket_qjs.zc +263 -0
  64. package/native/src/platform/windows/worker/qjs.zc +1049 -0
  65. package/native/src/platform/windows/worker/timers_qjs.zc +288 -0
  66. package/native/src/platform/worker.zc +8 -0
  67. package/native/src/service/service.zc +228 -0
  68. package/native/vendor/quickjs-ng/.gitattributes +4 -0
  69. package/native/vendor/quickjs-ng/.github/dependabot.yml +7 -0
  70. package/native/vendor/quickjs-ng/.github/workflows/ci.yml +812 -0
  71. package/native/vendor/quickjs-ng/.github/workflows/docs.yml +49 -0
  72. package/native/vendor/quickjs-ng/.github/workflows/release.yml +162 -0
  73. package/native/vendor/quickjs-ng/.github/workflows/test-docs.yml +23 -0
  74. package/native/vendor/quickjs-ng/.github/workflows/tsan.yml +32 -0
  75. package/native/vendor/quickjs-ng/.github/workflows/valgrind.yml +33 -0
  76. package/native/vendor/quickjs-ng/.gitmodules +5 -0
  77. package/native/vendor/quickjs-ng/CMakeLists.txt +553 -0
  78. package/native/vendor/quickjs-ng/LICENSE +24 -0
  79. package/native/vendor/quickjs-ng/Makefile +149 -0
  80. package/native/vendor/quickjs-ng/amalgam.js +53 -0
  81. package/native/vendor/quickjs-ng/api-test.c +927 -0
  82. package/native/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
  83. package/native/vendor/quickjs-ng/builtin-array-fromasync.js +36 -0
  84. package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
  85. package/native/vendor/quickjs-ng/builtin-iterator-zip-keyed.js +194 -0
  86. package/native/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
  87. package/native/vendor/quickjs-ng/builtin-iterator-zip.js +210 -0
  88. package/native/vendor/quickjs-ng/ctest.c +17 -0
  89. package/native/vendor/quickjs-ng/cutils.h +2013 -0
  90. package/native/vendor/quickjs-ng/cxxtest.cc +2 -0
  91. package/native/vendor/quickjs-ng/dtoa.c +1619 -0
  92. package/native/vendor/quickjs-ng/dtoa.h +87 -0
  93. package/native/vendor/quickjs-ng/examples/fib.c +67 -0
  94. package/native/vendor/quickjs-ng/examples/fib_module.js +10 -0
  95. package/native/vendor/quickjs-ng/examples/hello.js +1 -0
  96. package/native/vendor/quickjs-ng/examples/hello_module.js +6 -0
  97. package/native/vendor/quickjs-ng/examples/meson.build +17 -0
  98. package/native/vendor/quickjs-ng/examples/pi_bigint.js +118 -0
  99. package/native/vendor/quickjs-ng/examples/point.c +154 -0
  100. package/native/vendor/quickjs-ng/examples/test_fib.js +8 -0
  101. package/native/vendor/quickjs-ng/examples/test_point.js +43 -0
  102. package/native/vendor/quickjs-ng/fuzz.c +51 -0
  103. package/native/vendor/quickjs-ng/gen/function_source.c +81 -0
  104. package/native/vendor/quickjs-ng/gen/hello.c +53 -0
  105. package/native/vendor/quickjs-ng/gen/hello_module.c +106 -0
  106. package/native/vendor/quickjs-ng/gen/repl.c +3053 -0
  107. package/native/vendor/quickjs-ng/gen/standalone.c +324 -0
  108. package/native/vendor/quickjs-ng/gen/test_fib.c +81 -0
  109. package/native/vendor/quickjs-ng/libregexp-opcode.h +58 -0
  110. package/native/vendor/quickjs-ng/libregexp.c +2687 -0
  111. package/native/vendor/quickjs-ng/libregexp.h +98 -0
  112. package/native/vendor/quickjs-ng/libunicode-table.h +4707 -0
  113. package/native/vendor/quickjs-ng/libunicode.c +1746 -0
  114. package/native/vendor/quickjs-ng/libunicode.h +126 -0
  115. package/native/vendor/quickjs-ng/list.h +107 -0
  116. package/native/vendor/quickjs-ng/lre-test.c +73 -0
  117. package/native/vendor/quickjs-ng/meson.build +684 -0
  118. package/native/vendor/quickjs-ng/meson_options.txt +6 -0
  119. package/native/vendor/quickjs-ng/qjs-wasi-reactor.c +208 -0
  120. package/native/vendor/quickjs-ng/qjs.c +748 -0
  121. package/native/vendor/quickjs-ng/qjsc.c +673 -0
  122. package/native/vendor/quickjs-ng/quickjs-atom.h +267 -0
  123. package/native/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
  124. package/native/vendor/quickjs-ng/quickjs-libc.c +4986 -0
  125. package/native/vendor/quickjs-ng/quickjs-libc.h +79 -0
  126. package/native/vendor/quickjs-ng/quickjs-opcode.h +369 -0
  127. package/native/vendor/quickjs-ng/quickjs.c +60259 -0
  128. package/native/vendor/quickjs-ng/quickjs.h +1419 -0
  129. package/native/vendor/quickjs-ng/repl.js +1927 -0
  130. package/native/vendor/quickjs-ng/run-test262.c +2417 -0
  131. package/native/vendor/quickjs-ng/standalone.js +129 -0
  132. package/native/vendor/quickjs-ng/tests/assert.js +49 -0
  133. package/native/vendor/quickjs-ng/tests/bug1221.js +16 -0
  134. package/native/vendor/quickjs-ng/tests/bug1296.js +12 -0
  135. package/native/vendor/quickjs-ng/tests/bug1297.js +22 -0
  136. package/native/vendor/quickjs-ng/tests/bug1301.js +21 -0
  137. package/native/vendor/quickjs-ng/tests/bug1302.js +24 -0
  138. package/native/vendor/quickjs-ng/tests/bug1305.js +26 -0
  139. package/native/vendor/quickjs-ng/tests/bug1318.js +54 -0
  140. package/native/vendor/quickjs-ng/tests/bug1352.js +8 -0
  141. package/native/vendor/quickjs-ng/tests/bug1354.js +6 -0
  142. package/native/vendor/quickjs-ng/tests/bug1355.js +58 -0
  143. package/native/vendor/quickjs-ng/tests/bug1368.js +9 -0
  144. package/native/vendor/quickjs-ng/tests/bug39/1.js +6 -0
  145. package/native/vendor/quickjs-ng/tests/bug39/2.js +6 -0
  146. package/native/vendor/quickjs-ng/tests/bug39/3.js +7 -0
  147. package/native/vendor/quickjs-ng/tests/bug488-upstream.js +7 -0
  148. package/native/vendor/quickjs-ng/tests/bug633/0.js +7 -0
  149. package/native/vendor/quickjs-ng/tests/bug633/1.js +4 -0
  150. package/native/vendor/quickjs-ng/tests/bug633/2.js +4 -0
  151. package/native/vendor/quickjs-ng/tests/bug633/3.js +4 -0
  152. package/native/vendor/quickjs-ng/tests/bug645/0.js +4 -0
  153. package/native/vendor/quickjs-ng/tests/bug645/1.js +9 -0
  154. package/native/vendor/quickjs-ng/tests/bug645/2.js +7 -0
  155. package/native/vendor/quickjs-ng/tests/bug648.js +13 -0
  156. package/native/vendor/quickjs-ng/tests/bug652.js +4 -0
  157. package/native/vendor/quickjs-ng/tests/bug741.js +19 -0
  158. package/native/vendor/quickjs-ng/tests/bug775.js +7 -0
  159. package/native/vendor/quickjs-ng/tests/bug776.js +7 -0
  160. package/native/vendor/quickjs-ng/tests/bug832.js +2 -0
  161. package/native/vendor/quickjs-ng/tests/bug858.js +26 -0
  162. package/native/vendor/quickjs-ng/tests/bug904.js +6 -0
  163. package/native/vendor/quickjs-ng/tests/bug988.js +7 -0
  164. package/native/vendor/quickjs-ng/tests/bug999.js +3 -0
  165. package/native/vendor/quickjs-ng/tests/destructured-export.js +8 -0
  166. package/native/vendor/quickjs-ng/tests/detect_module/0.js +1 -0
  167. package/native/vendor/quickjs-ng/tests/detect_module/1.js +2 -0
  168. package/native/vendor/quickjs-ng/tests/detect_module/2.js +1 -0
  169. package/native/vendor/quickjs-ng/tests/detect_module/3.js +8 -0
  170. package/native/vendor/quickjs-ng/tests/detect_module/4.js +3 -0
  171. package/native/vendor/quickjs-ng/tests/empty.js +0 -0
  172. package/native/vendor/quickjs-ng/tests/fixture_cyclic_import.js +2 -0
  173. package/native/vendor/quickjs-ng/tests/fixture_string_exports.js +12 -0
  174. package/native/vendor/quickjs-ng/tests/function_source.js +14 -0
  175. package/native/vendor/quickjs-ng/tests/microbench.js +1267 -0
  176. package/native/vendor/quickjs-ng/tests/null_or_undefined.js +38 -0
  177. package/native/vendor/quickjs-ng/tests/str-pad-leak.js +5 -0
  178. package/native/vendor/quickjs-ng/tests/test_bigint.js +107 -0
  179. package/native/vendor/quickjs-ng/tests/test_bjson.js +366 -0
  180. package/native/vendor/quickjs-ng/tests/test_builtin.js +1314 -0
  181. package/native/vendor/quickjs-ng/tests/test_closure.js +220 -0
  182. package/native/vendor/quickjs-ng/tests/test_cyclic_import.js +12 -0
  183. package/native/vendor/quickjs-ng/tests/test_domexception.js +35 -0
  184. package/native/vendor/quickjs-ng/tests/test_language.js +755 -0
  185. package/native/vendor/quickjs-ng/tests/test_loop.js +367 -0
  186. package/native/vendor/quickjs-ng/tests/test_queue_microtask.js +39 -0
  187. package/native/vendor/quickjs-ng/tests/test_std.js +340 -0
  188. package/native/vendor/quickjs-ng/tests/test_string_exports.js +25 -0
  189. package/native/vendor/quickjs-ng/tests/test_worker.js +43 -0
  190. package/native/vendor/quickjs-ng/tests/test_worker_module.js +30 -0
  191. package/native/vendor/quickjs-ng/tests.conf +14 -0
  192. package/native/vendor/quickjs-ng/unicode_download.sh +19 -0
  193. package/native/vendor/quickjs-ng/unicode_gen.c +3108 -0
  194. package/native/vendor/quickjs-ng/unicode_gen_def.h +310 -0
  195. package/native/vendor/quickjs-ng/update-version.sh +32 -0
  196. package/native/vendor/webview2/include/WebView2.h +60636 -0
  197. package/native/vendor/webview2/include/WebView2EnvironmentOptions.h +406 -0
  198. package/package.json +33 -0
  199. package/src/backend.ts +139 -0
  200. package/src/build-config.ts +87 -0
  201. package/src/build.ts +276 -0
  202. package/src/common.ts +195 -0
  203. package/src/config.ts +89 -0
  204. package/src/dev.ts +164 -0
  205. package/src/generate.ts +200 -0
  206. package/src/icons.ts +116 -0
  207. package/src/init.ts +190 -0
  208. package/src/package.ts +150 -0
  209. 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, &times));
3286
+ }
3287
+ #else
3288
+ {
3289
+ struct timeval times[2];
3290
+ ms_to_timeval(&times[0], atime);
3291
+ ms_to_timeval(&times[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
+ }