xbintsc 0.3.13 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -22
- package/README.zh-CN.md +20 -19
- package/bin/xbintsc.js +1 -2
- package/dist/src/cli/main.js +4 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +13 -0
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/calls/invocation.js +8 -2
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +6 -0
- package/dist/src/codegen/generator/context.js +24 -2
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/primary.js +5 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +5 -6
- package/dist/src/codegen/generator/tables.js +5 -6
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/compiler.js +15 -3
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/index.d.ts +1 -2
- package/dist/src/driver/index.js +1 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/modules.d.ts +1 -1
- package/dist/src/driver/modules.js +235 -25
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/driver/paths.d.ts +0 -9
- package/dist/src/driver/paths.js +0 -31
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/toolchain-provider.d.ts +10 -10
- package/dist/src/driver/toolchain-provider.js +9 -38
- package/dist/src/driver/toolchain-provider.js.map +1 -1
- package/dist/src/driver/toolchain.js +8 -2
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/native.d.ts +2 -3
- package/dist/src/extensions/native.js +2 -3
- package/dist/src/extensions/native.js.map +1 -1
- package/dist/src/extensions/node/fs/fs-ops.d.ts +5 -2
- package/dist/src/extensions/node/fs/fs-ops.js +45 -6
- package/dist/src/extensions/node/fs/fs-ops.js.map +1 -1
- package/dist/src/extensions/node/fs/index.d.ts +6 -2
- package/dist/src/extensions/node/fs/index.js +22 -3
- package/dist/src/extensions/node/fs/index.js.map +1 -1
- package/dist/src/extensions/node/fs-promises/index.d.ts +4 -3
- package/dist/src/extensions/node/fs-promises/index.js +31 -3
- package/dist/src/extensions/node/fs-promises/index.js.map +1 -1
- package/dist/tests/cli/main.test.js +8 -0
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +28 -1
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/modules.test.js +91 -4
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/driver/paths.test.js +1 -9
- package/dist/tests/driver/paths.test.js.map +1 -1
- package/dist/tests/driver/toolchain-provider.test.js +12 -79
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -1
- package/dist/tests/e2e/compile-node.test.js +240 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +12 -0
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/harness.js +11 -8
- package/dist/tests/e2e/harness.js.map +1 -1
- package/dist/tests/e2e/native-extensions.test.d.ts +4 -5
- package/dist/tests/e2e/native-extensions.test.js +6 -7
- package/dist/tests/e2e/native-extensions.test.js.map +1 -1
- package/dist/tests/e2e/node-modules.test.js +1 -1
- package/dist/tests/e2e/node-modules.test.js.map +1 -1
- package/dist/tests/e2e/npm-modules.test.d.ts +9 -0
- package/dist/tests/e2e/npm-modules.test.js +55 -0
- package/dist/tests/e2e/npm-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage.test.d.ts +11 -0
- package/dist/tests/e2e/runtime-coverage.test.js +646 -0
- package/dist/tests/e2e/runtime-coverage.test.js.map +1 -0
- package/package.json +1 -2
- package/runtime/ext_node/buffer/parts/prototype.inc +7 -0
- package/runtime/ext_node/buffer/parts/search.inc +8 -4
- package/runtime/ext_node/child_process/child_process.c +5 -0
- package/runtime/ext_node/fs/constants.c +113 -0
- package/runtime/ext_node/fs/copy_ops.c +145 -0
- package/runtime/ext_node/fs/dir.c +101 -0
- package/runtime/ext_node/fs/fd_ops.c +405 -0
- package/runtime/ext_node/fs/fs_common.h +388 -5
- package/runtime/ext_node/fs/fs_ops.c +100 -139
- package/runtime/ext_node/fs/glob.c +232 -0
- package/runtime/ext_node/fs/link_ops.c +91 -0
- package/runtime/ext_node/fs/meta_ops.c +403 -0
- package/runtime/ext_node/fs/promises.c +275 -60
- package/runtime/ext_node/fs/read_file.c +8 -4
- package/runtime/ext_node/fs/watch.c +52 -0
- package/runtime/ext_node/fs/write_file.c +20 -11
- package/runtime/ext_node/stream/stream.c +19 -2
- package/runtime/rt.h +8 -0
- package/runtime/rt_internal.h +10 -23
- package/runtime/xt_ext.h +0 -1
- package/runtime/xt_io.c +24 -3
- package/runtime/xt_stdlib2/helpers.inc +2 -4
- package/scripts/build-runtime.ts +7 -8
- package/scripts/coverage-runtime.ts +4 -4
- package/scripts/package-release.ts +12 -84
- package/src/cli/main.ts +4 -1
- package/src/codegen/generator/calls/access.ts +15 -0
- package/src/codegen/generator/calls/invocation.ts +8 -2
- package/src/codegen/generator/context.ts +30 -2
- package/src/codegen/generator/expressions/primary.ts +5 -0
- package/src/codegen/generator/tables.ts +5 -6
- package/src/driver/compiler.ts +16 -3
- package/src/driver/index.ts +1 -9
- package/src/driver/modules.ts +251 -26
- package/src/driver/paths.ts +0 -31
- package/src/driver/toolchain-provider.ts +12 -45
- package/src/driver/toolchain.ts +7 -2
- package/src/extensions/native.ts +2 -3
- package/src/extensions/node/fs/fs-ops.ts +48 -6
- package/src/extensions/node/fs/index.ts +25 -3
- package/src/extensions/node/fs-promises/index.ts +33 -4
- package/dist/src/driver/toolchain-download.d.ts +0 -50
- package/dist/src/driver/toolchain-download.js +0 -102
- package/dist/src/driver/toolchain-download.js.map +0 -1
- package/dist/tests/driver/toolchain-download.test.d.ts +0 -1
- package/dist/tests/driver/toolchain-download.test.js +0 -53
- package/dist/tests/driver/toolchain-download.test.js.map +0 -1
- package/scripts/fetch-toolchain.ts +0 -101
- package/src/driver/toolchain-download.ts +0 -135
|
@@ -2,68 +2,283 @@
|
|
|
2
2
|
* Node.js `fs/promises` for xbintsc.
|
|
3
3
|
*
|
|
4
4
|
* xbintsc has no asynchronous I/O scheduler, so these builtins reuse the
|
|
5
|
-
* synchronous `fs` implementations and wrap the result in
|
|
6
|
-
* settled
|
|
7
|
-
*
|
|
5
|
+
* synchronous `fs` implementations and wrap the result in a promise that is
|
|
6
|
+
* already settled. `await`/`.then` therefore work as expected while the actual
|
|
7
|
+
* work happens synchronously. A synchronous failure is turned into a rejected
|
|
8
|
+
* promise instead of a thrown exception (matching Node's contract).
|
|
9
|
+
*
|
|
10
|
+
* `open()` resolves to a `FileHandle`-shaped object (a plain object with an
|
|
11
|
+
* `fd` property and the usual methods); there is no shared prototype yet, so
|
|
12
|
+
* `handle instanceof FileHandle` is not supported.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
#include "../node_common.h"
|
|
16
|
+
#include "fs_common.h"
|
|
17
|
+
|
|
18
|
+
/* ------------------------------------------------------------------------- */
|
|
19
|
+
/* FileHandle */
|
|
20
|
+
/* ------------------------------------------------------------------------- */
|
|
21
|
+
|
|
22
|
+
static xt_value xt_fh_method(xt_value thisValue, xt_value (*fn)(int32_t, xt_value *), int32_t argc, xt_value *argv,
|
|
23
|
+
int prefix) {
|
|
24
|
+
xt_value args[10];
|
|
25
|
+
int32_t count = 0;
|
|
26
|
+
if (prefix >= 1) args[count++] = xt_object_get_cstr(thisValue, "fd");
|
|
27
|
+
if (prefix >= 2) args[count++] = xt_object_get_cstr(thisValue, "fd2");
|
|
28
|
+
for (int32_t i = 0; i < argc && count < 10; i++) args[count++] = argv[i];
|
|
29
|
+
return xt_fs_promisify(fn, count, args);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static xt_value xt_fh_read(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
33
|
+
(void)env;
|
|
34
|
+
return xt_fh_method(thisValue, xt_node_read, argc, argv, 1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static xt_value xt_fh_write(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
38
|
+
(void)env;
|
|
39
|
+
return xt_fh_method(thisValue, xt_node_write, argc, argv, 1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static xt_value xt_fh_close(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
43
|
+
(void)env;
|
|
44
|
+
return xt_fh_method(thisValue, xt_node_close, argc, argv, 1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static xt_value xt_fh_stat(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
48
|
+
(void)env;
|
|
49
|
+
return xt_fh_method(thisValue, xt_node_fstat, argc, argv, 1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static xt_value xt_fh_truncate(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
53
|
+
(void)env;
|
|
54
|
+
return xt_fh_method(thisValue, xt_node_ftruncate, argc, argv, 1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static xt_value xt_fh_chmod(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
58
|
+
(void)env;
|
|
59
|
+
return xt_fh_method(thisValue, xt_node_fchmod, argc, argv, 1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static xt_value xt_fh_chown(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
63
|
+
(void)env;
|
|
64
|
+
return xt_fh_method(thisValue, xt_node_fchown, argc, argv, 1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static xt_value xt_fh_utimes(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
68
|
+
(void)env;
|
|
69
|
+
return xt_fh_method(thisValue, xt_node_futimes, argc, argv, 1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static xt_value xt_fh_sync(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
73
|
+
(void)env;
|
|
74
|
+
return xt_fh_method(thisValue, xt_node_fsync, argc, argv, 1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static xt_value xt_fh_datasync(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
78
|
+
(void)env;
|
|
79
|
+
return xt_fh_method(thisValue, xt_node_fdatasync, argc, argv, 1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Read from the handle's current position to EOF; caller frees. */
|
|
83
|
+
static unsigned char *xt_fh_slurp(int fd, size_t *outLength) {
|
|
84
|
+
size_t capacity = 8192;
|
|
85
|
+
size_t length = 0;
|
|
86
|
+
unsigned char *bytes = (unsigned char *)malloc(capacity);
|
|
87
|
+
if (!bytes) return NULL;
|
|
88
|
+
for (;;) {
|
|
89
|
+
if (length == capacity) {
|
|
90
|
+
capacity *= 2;
|
|
91
|
+
unsigned char *grown = (unsigned char *)realloc(bytes, capacity);
|
|
92
|
+
if (!grown) {
|
|
93
|
+
free(bytes);
|
|
94
|
+
return NULL;
|
|
95
|
+
}
|
|
96
|
+
bytes = grown;
|
|
97
|
+
}
|
|
98
|
+
ssize_t bytesRead = XT_FS_READ(fd, bytes + length, capacity - length);
|
|
99
|
+
if (bytesRead < 0) {
|
|
100
|
+
free(bytes);
|
|
101
|
+
return NULL;
|
|
102
|
+
}
|
|
103
|
+
if (bytesRead == 0) break;
|
|
104
|
+
length += (size_t)bytesRead;
|
|
105
|
+
}
|
|
106
|
+
*outLength = length;
|
|
107
|
+
return bytes;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static xt_value xt_fh_read_all(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
111
|
+
(void)env;
|
|
112
|
+
int fd = (int)xt_to_number(xt_object_get_cstr(thisValue, "fd"));
|
|
113
|
+
const char *encoding = argc > 0 ? xt_fs_encoding(argv[0]) : NULL;
|
|
114
|
+
size_t length = 0;
|
|
115
|
+
unsigned char *bytes = xt_fh_slurp(fd, &length);
|
|
116
|
+
if (!bytes) return xt_promise_reject(xt_fs_error_object(errno, "read", NULL));
|
|
117
|
+
xt_value result = xt_fs_encode_bytes(bytes, length, encoding);
|
|
118
|
+
free(bytes);
|
|
119
|
+
return xt_promise_resolve(result);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static xt_value xt_fh_write_all(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
123
|
+
(void)env;
|
|
124
|
+
xt_value args[2];
|
|
125
|
+
args[0] = xt_object_get_cstr(thisValue, "fd");
|
|
126
|
+
args[1] = argc > 0 ? argv[0] : XT_UNDEFINED;
|
|
127
|
+
return xt_fs_promisify(xt_node_write, 2, args);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static xt_value xt_fh_new(xt_value fdValue) {
|
|
131
|
+
xt_value handle = xt_object_new();
|
|
132
|
+
xt_node_set(handle, "fd", fdValue);
|
|
133
|
+
xt_node_define_method(handle, "read", (void *)xt_fh_read);
|
|
134
|
+
xt_node_define_method(handle, "write", (void *)xt_fh_write);
|
|
135
|
+
xt_node_define_method(handle, "readFile", (void *)xt_fh_read_all);
|
|
136
|
+
xt_node_define_method(handle, "writeFile", (void *)xt_fh_write_all);
|
|
137
|
+
xt_node_define_method(handle, "appendFile", (void *)xt_fh_write_all);
|
|
138
|
+
xt_node_define_method(handle, "close", (void *)xt_fh_close);
|
|
139
|
+
xt_node_define_method(handle, "stat", (void *)xt_fh_stat);
|
|
140
|
+
xt_node_define_method(handle, "truncate", (void *)xt_fh_truncate);
|
|
141
|
+
xt_node_define_method(handle, "chmod", (void *)xt_fh_chmod);
|
|
142
|
+
xt_node_define_method(handle, "chown", (void *)xt_fh_chown);
|
|
143
|
+
xt_node_define_method(handle, "utimes", (void *)xt_fh_utimes);
|
|
144
|
+
xt_node_define_method(handle, "sync", (void *)xt_fh_sync);
|
|
145
|
+
xt_node_define_method(handle, "datasync", (void *)xt_fh_datasync);
|
|
146
|
+
return handle;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* ------------------------------------------------------------------------- */
|
|
150
|
+
/* Promise wrappers */
|
|
151
|
+
/* ------------------------------------------------------------------------- */
|
|
152
|
+
|
|
153
|
+
#define XT_FS_PROMISE(name, fn) \
|
|
154
|
+
xt_value name(int32_t argc, xt_value *argv) { return xt_fs_promisify((fn), argc, argv); }
|
|
155
|
+
|
|
156
|
+
XT_FS_PROMISE(xt_node_p_read_file, xt_node_read_text_file)
|
|
157
|
+
XT_FS_PROMISE(xt_node_p_write_file, xt_node_write_file)
|
|
158
|
+
XT_FS_PROMISE(xt_node_p_append_file, xt_node_append_file)
|
|
159
|
+
XT_FS_PROMISE(xt_node_p_mkdir, xt_node_mkdir)
|
|
160
|
+
XT_FS_PROMISE(xt_node_p_readdir, xt_node_read_dir)
|
|
161
|
+
XT_FS_PROMISE(xt_node_p_rm, xt_node_rm)
|
|
162
|
+
XT_FS_PROMISE(xt_node_p_unlink, xt_node_unlink)
|
|
163
|
+
XT_FS_PROMISE(xt_node_p_rmdir, xt_node_rmdir)
|
|
164
|
+
XT_FS_PROMISE(xt_node_p_rename, xt_node_rename)
|
|
165
|
+
XT_FS_PROMISE(xt_node_p_copy_file, xt_node_copy_file)
|
|
166
|
+
XT_FS_PROMISE(xt_node_p_realpath, xt_node_realpath)
|
|
167
|
+
XT_FS_PROMISE(xt_node_p_stat, xt_node_stat)
|
|
168
|
+
XT_FS_PROMISE(xt_node_p_lstat, xt_node_lstat)
|
|
169
|
+
XT_FS_PROMISE(xt_node_p_access, xt_node_access)
|
|
170
|
+
XT_FS_PROMISE(xt_node_p_cp, xt_node_cp)
|
|
171
|
+
XT_FS_PROMISE(xt_node_p_chmod, xt_node_chmod)
|
|
172
|
+
XT_FS_PROMISE(xt_node_p_chown, xt_node_chown)
|
|
173
|
+
XT_FS_PROMISE(xt_node_p_lchmod, xt_node_lchmod)
|
|
174
|
+
XT_FS_PROMISE(xt_node_p_lchown, xt_node_lchown)
|
|
175
|
+
XT_FS_PROMISE(xt_node_p_truncate, xt_node_truncate)
|
|
176
|
+
XT_FS_PROMISE(xt_node_p_utimes, xt_node_utimes)
|
|
177
|
+
XT_FS_PROMISE(xt_node_p_lutimes, xt_node_lutimes)
|
|
178
|
+
XT_FS_PROMISE(xt_node_p_link, xt_node_link)
|
|
179
|
+
XT_FS_PROMISE(xt_node_p_symlink, xt_node_symlink)
|
|
180
|
+
XT_FS_PROMISE(xt_node_p_readlink, xt_node_readlink)
|
|
181
|
+
XT_FS_PROMISE(xt_node_p_mkdtemp, xt_node_mkdtemp)
|
|
182
|
+
XT_FS_PROMISE(xt_node_p_statfs, xt_node_statfs)
|
|
183
|
+
XT_FS_PROMISE(xt_node_p_opendir, xt_node_opendir)
|
|
184
|
+
XT_FS_PROMISE(xt_node_p_glob, xt_node_glob)
|
|
185
|
+
XT_FS_PROMISE(xt_node_p_watch, xt_node_watch)
|
|
186
|
+
|
|
187
|
+
xt_value xt_node_p_open(int32_t argc, xt_value *argv) {
|
|
188
|
+
void *frame = xt_try_enter();
|
|
189
|
+
if (xt_try_setjmp(frame) == 0) {
|
|
190
|
+
xt_value fdValue = xt_node_open(argc, argv);
|
|
191
|
+
xt_try_leave(frame);
|
|
192
|
+
return xt_promise_resolve(xt_fh_new(fdValue));
|
|
193
|
+
}
|
|
194
|
+
xt_value exception = xt_try_exception(frame);
|
|
195
|
+
xt_try_leave(frame);
|
|
196
|
+
return xt_promise_reject(exception);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* ------------------------------------------------------------------------- */
|
|
200
|
+
/* `fs.promises` facade */
|
|
201
|
+
/* ------------------------------------------------------------------------- */
|
|
202
|
+
|
|
203
|
+
#define XT_FS_PROMISES_FACADE(name, object) \
|
|
204
|
+
static xt_value xt_fs_promises_facade_##name(xt_value thisValue, xt_value env, int32_t argc, \
|
|
205
|
+
xt_value *argv) { \
|
|
206
|
+
(void)thisValue; \
|
|
207
|
+
(void)env; \
|
|
208
|
+
return name(argc, argv); \
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
XT_FS_PROMISES_FACADE(xt_node_p_read_file, _)
|
|
212
|
+
XT_FS_PROMISES_FACADE(xt_node_p_write_file, _)
|
|
213
|
+
XT_FS_PROMISES_FACADE(xt_node_p_append_file, _)
|
|
214
|
+
XT_FS_PROMISES_FACADE(xt_node_p_mkdir, _)
|
|
215
|
+
XT_FS_PROMISES_FACADE(xt_node_p_readdir, _)
|
|
216
|
+
XT_FS_PROMISES_FACADE(xt_node_p_rm, _)
|
|
217
|
+
XT_FS_PROMISES_FACADE(xt_node_p_unlink, _)
|
|
218
|
+
XT_FS_PROMISES_FACADE(xt_node_p_rmdir, _)
|
|
219
|
+
XT_FS_PROMISES_FACADE(xt_node_p_rename, _)
|
|
220
|
+
XT_FS_PROMISES_FACADE(xt_node_p_copy_file, _)
|
|
221
|
+
XT_FS_PROMISES_FACADE(xt_node_p_realpath, _)
|
|
222
|
+
XT_FS_PROMISES_FACADE(xt_node_p_stat, _)
|
|
223
|
+
XT_FS_PROMISES_FACADE(xt_node_p_lstat, _)
|
|
224
|
+
XT_FS_PROMISES_FACADE(xt_node_p_access, _)
|
|
225
|
+
XT_FS_PROMISES_FACADE(xt_node_p_cp, _)
|
|
226
|
+
XT_FS_PROMISES_FACADE(xt_node_p_chmod, _)
|
|
227
|
+
XT_FS_PROMISES_FACADE(xt_node_p_chown, _)
|
|
228
|
+
XT_FS_PROMISES_FACADE(xt_node_p_lchmod, _)
|
|
229
|
+
XT_FS_PROMISES_FACADE(xt_node_p_lchown, _)
|
|
230
|
+
XT_FS_PROMISES_FACADE(xt_node_p_truncate, _)
|
|
231
|
+
XT_FS_PROMISES_FACADE(xt_node_p_utimes, _)
|
|
232
|
+
XT_FS_PROMISES_FACADE(xt_node_p_lutimes, _)
|
|
233
|
+
XT_FS_PROMISES_FACADE(xt_node_p_link, _)
|
|
234
|
+
XT_FS_PROMISES_FACADE(xt_node_p_symlink, _)
|
|
235
|
+
XT_FS_PROMISES_FACADE(xt_node_p_readlink, _)
|
|
236
|
+
XT_FS_PROMISES_FACADE(xt_node_p_mkdtemp, _)
|
|
237
|
+
XT_FS_PROMISES_FACADE(xt_node_p_statfs, _)
|
|
238
|
+
XT_FS_PROMISES_FACADE(xt_node_p_opendir, _)
|
|
239
|
+
XT_FS_PROMISES_FACADE(xt_node_p_glob, _)
|
|
240
|
+
XT_FS_PROMISES_FACADE(xt_node_p_watch, _)
|
|
241
|
+
XT_FS_PROMISES_FACADE(xt_node_p_open, _)
|
|
11
242
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
xt_value xt_node_p_copy_file(int32_t argc, xt_value *argv) { return xt_node_promises_wrap(argc, argv, xt_node_copy_file); }
|
|
54
|
-
xt_value xt_node_p_realpath(int32_t argc, xt_value *argv) { return xt_node_promises_wrap(argc, argv, xt_node_realpath); }
|
|
55
|
-
xt_value xt_node_p_stat(int32_t argc, xt_value *argv) { return xt_node_promises_wrap(argc, argv, xt_node_stat); }
|
|
56
|
-
xt_value xt_node_p_lstat(int32_t argc, xt_value *argv) { return xt_node_promises_wrap(argc, argv, xt_node_lstat); }
|
|
57
|
-
|
|
58
|
-
xt_value xt_node_p_access(int32_t argc, xt_value *argv) {
|
|
59
|
-
if (argc < 1) return xt_promise_resolve(xt_undefined());
|
|
60
|
-
const char *path = xt_string_data(xt_to_string(argv[0]));
|
|
61
|
-
if (!path) return xt_promise_resolve(xt_undefined());
|
|
62
|
-
if (xt_node_access(path, F_OK) == 0) return xt_promise_resolve(xt_undefined());
|
|
63
|
-
xt_value error = xt_object_new();
|
|
64
|
-
xt_node_set(error, "code", xt_string_from_cstr("ENOENT"));
|
|
65
|
-
xt_node_set(error, "errno", xt_number(-2));
|
|
66
|
-
xt_node_set(error, "path", xt_string_from_cstr(path));
|
|
67
|
-
xt_node_set(error, "message", xt_string_from_cstr("ENOENT: no such file or directory"));
|
|
68
|
-
return xt_promise_reject(error);
|
|
243
|
+
xt_value xt_fs_promises(void) {
|
|
244
|
+
static xt_value cached = 0;
|
|
245
|
+
if (XT_IS_OBJECT(cached)) return cached;
|
|
246
|
+
xt_value object = xt_object_new();
|
|
247
|
+
#define XT_FS_PROMISE_METHOD(jsName, name) \
|
|
248
|
+
xt_node_define_method(object, jsName, (void *)xt_fs_promises_facade_##name)
|
|
249
|
+
XT_FS_PROMISE_METHOD("readFile", xt_node_p_read_file);
|
|
250
|
+
XT_FS_PROMISE_METHOD("writeFile", xt_node_p_write_file);
|
|
251
|
+
XT_FS_PROMISE_METHOD("appendFile", xt_node_p_append_file);
|
|
252
|
+
XT_FS_PROMISE_METHOD("mkdir", xt_node_p_mkdir);
|
|
253
|
+
XT_FS_PROMISE_METHOD("readdir", xt_node_p_readdir);
|
|
254
|
+
XT_FS_PROMISE_METHOD("rm", xt_node_p_rm);
|
|
255
|
+
XT_FS_PROMISE_METHOD("unlink", xt_node_p_unlink);
|
|
256
|
+
XT_FS_PROMISE_METHOD("rmdir", xt_node_p_rmdir);
|
|
257
|
+
XT_FS_PROMISE_METHOD("rename", xt_node_p_rename);
|
|
258
|
+
XT_FS_PROMISE_METHOD("copyFile", xt_node_p_copy_file);
|
|
259
|
+
XT_FS_PROMISE_METHOD("realpath", xt_node_p_realpath);
|
|
260
|
+
XT_FS_PROMISE_METHOD("stat", xt_node_p_stat);
|
|
261
|
+
XT_FS_PROMISE_METHOD("lstat", xt_node_p_lstat);
|
|
262
|
+
XT_FS_PROMISE_METHOD("access", xt_node_p_access);
|
|
263
|
+
XT_FS_PROMISE_METHOD("cp", xt_node_p_cp);
|
|
264
|
+
XT_FS_PROMISE_METHOD("chmod", xt_node_p_chmod);
|
|
265
|
+
XT_FS_PROMISE_METHOD("chown", xt_node_p_chown);
|
|
266
|
+
XT_FS_PROMISE_METHOD("lchmod", xt_node_p_lchmod);
|
|
267
|
+
XT_FS_PROMISE_METHOD("lchown", xt_node_p_lchown);
|
|
268
|
+
XT_FS_PROMISE_METHOD("truncate", xt_node_p_truncate);
|
|
269
|
+
XT_FS_PROMISE_METHOD("utimes", xt_node_p_utimes);
|
|
270
|
+
XT_FS_PROMISE_METHOD("lutimes", xt_node_p_lutimes);
|
|
271
|
+
XT_FS_PROMISE_METHOD("link", xt_node_p_link);
|
|
272
|
+
XT_FS_PROMISE_METHOD("symlink", xt_node_p_symlink);
|
|
273
|
+
XT_FS_PROMISE_METHOD("readlink", xt_node_p_readlink);
|
|
274
|
+
XT_FS_PROMISE_METHOD("mkdtemp", xt_node_p_mkdtemp);
|
|
275
|
+
XT_FS_PROMISE_METHOD("statfs", xt_node_p_statfs);
|
|
276
|
+
XT_FS_PROMISE_METHOD("opendir", xt_node_p_opendir);
|
|
277
|
+
XT_FS_PROMISE_METHOD("glob", xt_node_p_glob);
|
|
278
|
+
XT_FS_PROMISE_METHOD("watch", xt_node_p_watch);
|
|
279
|
+
XT_FS_PROMISE_METHOD("open", xt_node_p_open);
|
|
280
|
+
#undef XT_FS_PROMISE_METHOD
|
|
281
|
+
xt_object_set(object, xt_string_from_cstr("constants"), xt_fs_constants());
|
|
282
|
+
cached = object;
|
|
283
|
+
return cached;
|
|
69
284
|
}
|
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
*
|
|
8
8
|
* `readFileSync(path[, options])` reads a file and returns its contents as a
|
|
9
9
|
* string. `options` may be an encoding string or an object with an `encoding`
|
|
10
|
-
* property; `"utf8"` (the default), `"ascii"`, `"latin1"` and `"binary"`
|
|
11
|
-
* the raw bytes, while `"hex"` and `"
|
|
12
|
-
*
|
|
10
|
+
* property; `"utf8"` (the default), `"ascii"`, `"latin1"` and `"binary"`
|
|
11
|
+
* return the raw bytes, while `"hex"`, `"base64"` and `"base64url"` return
|
|
12
|
+
* encoded strings.
|
|
13
|
+
*
|
|
14
|
+
* Deviation: Node returns a `Buffer` when no encoding is given. xbintsc has no
|
|
15
|
+
* dedicated binary value type, so the default result is a UTF-8 string (raw
|
|
16
|
+
* byte values are preserved for ASCII/latin1 content).
|
|
13
17
|
*/
|
|
14
18
|
|
|
15
19
|
#include "rt.h"
|
|
@@ -23,7 +27,7 @@ xt_value xt_node_read_text_file(int32_t argc, xt_value *argv) {
|
|
|
23
27
|
|
|
24
28
|
FILE *file = fopen(path, "rb");
|
|
25
29
|
if (!file) {
|
|
26
|
-
|
|
30
|
+
xt_fs_error("open", path);
|
|
27
31
|
return xt_undefined();
|
|
28
32
|
}
|
|
29
33
|
fseek(file, 0, SEEK_END);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `fs.watch` / `fs.watchFile` / `fs.unwatchFile` for xbintsc.
|
|
3
|
+
*
|
|
4
|
+
* The runtime has no event loop or timers, so file-change notifications can
|
|
5
|
+
* never fire. These builtins still return Node-shaped watcher objects (an
|
|
6
|
+
* emitter with a `close()` method) so that feature-detection and cleanup code
|
|
7
|
+
* keeps working; no `change`/`rename` events are delivered. This is a
|
|
8
|
+
* documented deviation.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#include "../node_common.h"
|
|
12
|
+
#include "fs_common.h"
|
|
13
|
+
|
|
14
|
+
static xt_value xt_fs_watch_close(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
15
|
+
(void)thisValue;
|
|
16
|
+
(void)env;
|
|
17
|
+
(void)argc;
|
|
18
|
+
(void)argv;
|
|
19
|
+
return xt_undefined();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static xt_value xt_fs_watch_make(xt_value filename, const char *listenerName) {
|
|
23
|
+
xt_value watcher = xt_object_new();
|
|
24
|
+
xt_node_install_emitter(watcher);
|
|
25
|
+
xt_node_define_method(watcher, "close", (void *)xt_fs_watch_close);
|
|
26
|
+
if (XT_IS_STRING(filename)) xt_node_set(watcher, "path", filename);
|
|
27
|
+
if (listenerName) xt_node_set(watcher, "kind", xt_string_from_cstr(listenerName));
|
|
28
|
+
return watcher;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
xt_value xt_node_watch(int32_t argc, xt_value *argv) {
|
|
32
|
+
xt_value filename = argc > 0 ? argv[0] : XT_UNDEFINED;
|
|
33
|
+
for (int32_t i = 1; i < argc; i++) {
|
|
34
|
+
if (XT_IS_FUNCTION(argv[i])) {
|
|
35
|
+
xt_value watcher = xt_fs_watch_make(filename, NULL);
|
|
36
|
+
xt_node_listeners(watcher, "change", 1);
|
|
37
|
+
return watcher;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return xt_fs_watch_make(filename, NULL);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
xt_value xt_node_watch_file(int32_t argc, xt_value *argv) {
|
|
44
|
+
xt_value filename = argc > 0 ? argv[0] : XT_UNDEFINED;
|
|
45
|
+
return xt_fs_watch_make(filename, "file");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
xt_value xt_node_unwatch_file(int32_t argc, xt_value *argv) {
|
|
49
|
+
(void)argc;
|
|
50
|
+
(void)argv;
|
|
51
|
+
return xt_undefined();
|
|
52
|
+
}
|
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
* Node.js `fs.writeFileSync` / `fs.appendFileSync` for xbintsc.
|
|
3
3
|
*
|
|
4
4
|
* `writeFileSync(path, data[, options])` truncates the file before writing;
|
|
5
|
-
* `appendFileSync(path, data[, options])` appends. `data`
|
|
6
|
-
*
|
|
7
|
-
* `"
|
|
5
|
+
* `appendFileSync(path, data[, options])` appends. `data` may be a string or a
|
|
6
|
+
* `Buffer`; strings are converted with `options.encoding` (`"hex"`/`"base64"`/
|
|
7
|
+
* `"base64url"` decode, everything else writes its UTF-8 bytes).
|
|
8
|
+
*
|
|
9
|
+
* Deviation: `options.mode` and `options.flag` are accepted but not applied
|
|
10
|
+
* (the file is always created with the process default mode and opened in the
|
|
11
|
+
* `"w"`/`"a"` binary mode). `TypedArray`/`DataView` inputs are not supported.
|
|
12
|
+
* Failures throw a Node-shaped `Error`.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
#include "rt.h"
|
|
@@ -16,19 +21,23 @@ static xt_value xt_node_write_common(int32_t argc, xt_value *argv, const char *m
|
|
|
16
21
|
const char *path = xt_string_data(pathValue);
|
|
17
22
|
if (!path) return xt_undefined();
|
|
18
23
|
|
|
19
|
-
xt_value dataValue = xt_to_string(argv[1]);
|
|
20
|
-
const char *text = xt_string_data(dataValue);
|
|
21
|
-
int32_t length = xt_string_length_value(dataValue);
|
|
22
|
-
if (!text || length < 0) return xt_undefined();
|
|
23
|
-
|
|
24
|
-
const char *encoding = argc > 2 ? xt_fs_encoding(argv[2]) : NULL;
|
|
25
24
|
size_t byteLength = 0;
|
|
26
|
-
unsigned char *bytes
|
|
25
|
+
unsigned char *bytes;
|
|
26
|
+
if (xt_node_is_buffer(argv[1])) {
|
|
27
|
+
bytes = xt_node_buffer_bytes(argv[1], &byteLength);
|
|
28
|
+
} else {
|
|
29
|
+
xt_value dataValue = xt_to_string(argv[1]);
|
|
30
|
+
const char *text = xt_string_data(dataValue);
|
|
31
|
+
int32_t length = xt_string_length_value(dataValue);
|
|
32
|
+
if (!text || length < 0) return xt_undefined();
|
|
33
|
+
const char *encoding = argc > 2 ? xt_fs_encoding(argv[2]) : NULL;
|
|
34
|
+
bytes = xt_fs_decode_text(text, (size_t)length, encoding, &byteLength);
|
|
35
|
+
}
|
|
27
36
|
if (!bytes) return xt_undefined();
|
|
28
37
|
|
|
29
38
|
FILE *file = fopen(path, mode);
|
|
30
39
|
if (!file) {
|
|
31
|
-
|
|
40
|
+
xt_fs_error("open", path);
|
|
32
41
|
free(bytes);
|
|
33
42
|
return xt_undefined();
|
|
34
43
|
}
|
|
@@ -145,6 +145,17 @@ static xt_value xt_stream_method_is_paused(xt_value thisValue, xt_value env, int
|
|
|
145
145
|
|
|
146
146
|
static xt_value xt_stream_transform_flush(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv);
|
|
147
147
|
|
|
148
|
+
/* No-op write callback used when `end(chunk)` forwards the chunk to `write`:
|
|
149
|
+
* the caller's `write` hook may invoke its completion callback, which must not
|
|
150
|
+
* be the user's `end` callback and must not be missing. */
|
|
151
|
+
static xt_value xt_stream_noop(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
152
|
+
(void)thisValue;
|
|
153
|
+
(void)env;
|
|
154
|
+
(void)argc;
|
|
155
|
+
(void)argv;
|
|
156
|
+
return xt_undefined();
|
|
157
|
+
}
|
|
158
|
+
|
|
148
159
|
static xt_value xt_stream_method_write(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
149
160
|
(void)env;
|
|
150
161
|
xt_value chunk = xt_arg(argc, argv, 0);
|
|
@@ -168,10 +179,12 @@ static xt_value xt_stream_method_write(xt_value thisValue, xt_value env, int32_t
|
|
|
168
179
|
|
|
169
180
|
xt_value writeFn = xt_object_get_cstr(thisValue, "__write");
|
|
170
181
|
if (XT_IS_FUNCTION(writeFn)) {
|
|
182
|
+
xt_value writeCallback =
|
|
183
|
+
XT_IS_FUNCTION(callback) ? callback : xt_closure_new((void *)xt_stream_noop, 0, NULL);
|
|
171
184
|
xt_value args[3];
|
|
172
185
|
args[0] = chunk;
|
|
173
186
|
args[1] = encoding;
|
|
174
|
-
args[2] =
|
|
187
|
+
args[2] = writeCallback;
|
|
175
188
|
xt_call_with_this(writeFn, thisValue, 3, args);
|
|
176
189
|
}
|
|
177
190
|
|
|
@@ -190,7 +203,11 @@ static xt_value xt_stream_method_end(xt_value thisValue, xt_value env, int32_t a
|
|
|
190
203
|
xt_value callback = XT_UNDEFINED;
|
|
191
204
|
if (argc >= 1 && !xt_truthy(xt_is_nullish(chunk))) {
|
|
192
205
|
xt_value writeFn = xt_object_get_cstr(thisValue, "write");
|
|
193
|
-
if (XT_IS_FUNCTION(writeFn))
|
|
206
|
+
if (XT_IS_FUNCTION(writeFn)) {
|
|
207
|
+
xt_value noop = xt_closure_new((void *)xt_stream_noop, 0, NULL);
|
|
208
|
+
xt_value writeArgs[3] = {chunk, xt_undefined(), noop};
|
|
209
|
+
xt_call_with_this(writeFn, thisValue, 3, writeArgs);
|
|
210
|
+
}
|
|
194
211
|
}
|
|
195
212
|
for (int32_t i = 0; i < argc; i++) {
|
|
196
213
|
if (XT_IS_FUNCTION(argv[i])) callback = argv[i];
|
package/runtime/rt.h
CHANGED
|
@@ -17,6 +17,14 @@
|
|
|
17
17
|
#include <stddef.h>
|
|
18
18
|
#include <stdint.h>
|
|
19
19
|
|
|
20
|
+
/* POSIX `ssize_t` is not exposed by the MSVC/UCRT headers clang uses on
|
|
21
|
+
* Windows (every Unix libc defines it). Alias the Windows pointer-sized signed
|
|
22
|
+
* integer so the runtime's POSIX shims compile unchanged. */
|
|
23
|
+
#if defined(_WIN32) && !defined(_SSIZE_T_DEFINED)
|
|
24
|
+
typedef intptr_t ssize_t;
|
|
25
|
+
#define _SSIZE_T_DEFINED
|
|
26
|
+
#endif
|
|
27
|
+
|
|
20
28
|
#ifdef __cplusplus
|
|
21
29
|
extern "C" {
|
|
22
30
|
#endif
|
package/runtime/rt_internal.h
CHANGED
|
@@ -224,31 +224,18 @@ typedef struct xt_try_frame {
|
|
|
224
224
|
struct xt_try_frame *prev;
|
|
225
225
|
xt_value exception;
|
|
226
226
|
} xt_try_frame;
|
|
227
|
-
/*
|
|
228
|
-
* C runtimes differ:
|
|
227
|
+
/* Save a try frame with clang's `_setjmp` built-in.
|
|
229
228
|
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* clang will not rewrite it. On Windows ARM64 it names `_setjmpex` (and the
|
|
240
|
-
* entry stack pointer from `llvm.sponentry`) instead, matching clang's own
|
|
241
|
-
* lowering there. `_setjmp`/`_setjmpex` (rather than the `setjmp` macro) is
|
|
242
|
-
* used so it pairs with the plain `longjmp` in `xt_throw`. */
|
|
243
|
-
#if defined(_WIN32) && !defined(__MINGW32__)
|
|
244
|
-
#define xt_try_setjmp(framePtr) _setjmp(((xt_try_frame *)(framePtr))->buf)
|
|
245
|
-
#elif defined(_WIN32) && defined(__aarch64__)
|
|
246
|
-
#define xt_try_setjmp(framePtr) _setjmpex(((xt_try_frame *)(framePtr))->buf, __builtin_sponentry())
|
|
247
|
-
#elif defined(_WIN32)
|
|
248
|
-
#define xt_try_setjmp(framePtr) _setjmp(((xt_try_frame *)(framePtr))->buf, __builtin_frame_address(0))
|
|
249
|
-
#else
|
|
229
|
+
* The generated IR passes the frame explicitly because it is already IR and
|
|
230
|
+
* clang will not rewrite it. This C helper instead calls `_setjmp(buf)` and lets
|
|
231
|
+
* clang supply the frame: on Windows x64 it injects the caller's frame address
|
|
232
|
+
* (`@llvm.frameaddress(0)`) into `_JUMP_BUFFER.Frame` so `longjmp` can feed it
|
|
233
|
+
* to `RtlUnwind`; on Windows ARM64, where the UCRT has no `_setjmp`, it lowers
|
|
234
|
+
* the call to `_setjmpex` with the entry stack pointer (`@llvm.sponentry`). On
|
|
235
|
+
* Linux/macOS `_setjmp` takes only the buffer and pairs with `longjmp`.
|
|
236
|
+
* `_setjmp` is used rather than the exported `setjmp` symbol, whose Windows ABI
|
|
237
|
+
* is an incompatible two-argument routine. */
|
|
250
238
|
#define xt_try_setjmp(framePtr) _setjmp(((xt_try_frame *)(framePtr))->buf)
|
|
251
|
-
#endif
|
|
252
239
|
void *xt_try_mark(void);
|
|
253
240
|
void xt_try_restore(void *mark);
|
|
254
241
|
|
package/runtime/xt_ext.h
CHANGED
package/runtime/xt_io.c
CHANGED
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
* bogus target (`STATUS_BAD_FUNCTION_TABLE`, 0xC00000FF). Windows ARM64 has
|
|
15
15
|
* no `_setjmp` at all: the generated IR uses `_setjmpex(buf, entry-sp)` with
|
|
16
16
|
* the stack pointer on entry (`@llvm.sponentry`), exactly as clang lowers a C
|
|
17
|
-
* `setjmp` there. The C runtime (see `xt_try_setjmp`) calls
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* `setjmp` there. The C runtime (see `xt_try_setjmp`) calls clang's
|
|
18
|
+
* `_setjmp` built-in so it gets the same frame injection (lowered to
|
|
19
|
+
* `_setjmpex` on ARM64). `_setjmp`/`_setjmpex` are used rather than the
|
|
20
20
|
* exported `setjmp` symbol, whose Windows ABI is an incompatible two-argument
|
|
21
21
|
* routine; on Linux/macOS `_setjmp` takes only the buffer and pairs with
|
|
22
22
|
* `longjmp` (the XSI `_longjmp` does not exist on Windows).
|
|
@@ -52,6 +52,26 @@ static xt_try_frame *g_try_top = NULL;
|
|
|
52
52
|
int32_t xt_program_argc = 0;
|
|
53
53
|
char **xt_program_argv = NULL;
|
|
54
54
|
|
|
55
|
+
#if defined(_WIN32)
|
|
56
|
+
/*
|
|
57
|
+
* The UCRT validates its low-level I/O arguments and, when one is out of
|
|
58
|
+
* range, calls the invalid-parameter handler. The default handler terminates
|
|
59
|
+
* the process through `_invoke_watson`, which fast-fails with exit status
|
|
60
|
+
* 0xC0000409. That makes POSIX-style calls such as `close(9999)` abort instead
|
|
61
|
+
* of reporting `EBADF`. Install a no-op handler so the CRT returns its normal
|
|
62
|
+
* error code (and sets `errno`) instead of crashing.
|
|
63
|
+
*/
|
|
64
|
+
static void __cdecl xt_noop_invalid_parameter_handler(const wchar_t *expression, const wchar_t *function_name,
|
|
65
|
+
const wchar_t *file_name, unsigned int line_number,
|
|
66
|
+
uintptr_t reserved) {
|
|
67
|
+
(void)expression;
|
|
68
|
+
(void)function_name;
|
|
69
|
+
(void)file_name;
|
|
70
|
+
(void)line_number;
|
|
71
|
+
(void)reserved;
|
|
72
|
+
}
|
|
73
|
+
#endif
|
|
74
|
+
|
|
55
75
|
void xt_set_program_args(int32_t argc, char **argv) {
|
|
56
76
|
#if defined(_WIN32)
|
|
57
77
|
/* Keep stdout/stderr in binary mode so `\n` is not translated to `\r\n`,
|
|
@@ -59,6 +79,7 @@ void xt_set_program_args(int32_t argc, char **argv) {
|
|
|
59
79
|
sockets (the generated `main` calls this before running the program). */
|
|
60
80
|
_setmode(_fileno(stdout), _O_BINARY);
|
|
61
81
|
_setmode(_fileno(stderr), _O_BINARY);
|
|
82
|
+
_set_invalid_parameter_handler(xt_noop_invalid_parameter_handler);
|
|
62
83
|
WSADATA wsaData;
|
|
63
84
|
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
64
85
|
#endif
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* `timegm` and `gmtime_r` are POSIX extensions that
|
|
3
|
-
* provide
|
|
4
|
-
* <time.h> only exposes `gmtime_r` when `_POSIX_C_SOURCE` is set and has no
|
|
5
|
-
* `timegm` at all, so wrap the MSVC-style equivalents for every `_WIN32` build.
|
|
2
|
+
* `timegm` and `gmtime_r` are POSIX extensions that the MSVC/UCRT headers do
|
|
3
|
+
* not provide, so wrap the MSVC-style equivalents for every `_WIN32` build.
|
|
6
4
|
*/
|
|
7
5
|
#if defined(_WIN32)
|
|
8
6
|
static time_t xt_timegm(struct tm *tm) { return (time_t)_mkgmtime64(tm); }
|