@scriptc/runtime 0.0.15 → 0.0.17
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/package.json +1 -1
- package/src/scr_bytes_io.c +2 -3
- package/src/scr_console.c +28 -7
- package/src/scr_exception.c +2 -2
- package/src/scr_island.c +1 -1
- package/src/scr_lib.c +172 -11
- package/src/scr_readline.c +4 -3
- package/src/scr_runtime.h +19 -13
- package/src/scr_web.c +1 -1
package/package.json
CHANGED
package/src/scr_bytes_io.c
CHANGED
|
@@ -154,13 +154,12 @@ ScrBytes *scr_crypto_random_bytes(double n) {
|
|
|
154
154
|
/* ── process.stdout/stderr.write(buf) ──────────────────────────────────── */
|
|
155
155
|
|
|
156
156
|
bool scr_process_stdout_write_bytes(const ScrBytes *b) {
|
|
157
|
-
|
|
157
|
+
scr_stdio_write(1, b->data, b->len * scr_bytes_elem_size(b->elem));
|
|
158
158
|
return true;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
bool scr_process_stderr_write_bytes(const ScrBytes *b) {
|
|
162
|
-
|
|
163
|
-
fwrite(b->data, 1, b->len * scr_bytes_elem_size(b->elem), stderr);
|
|
162
|
+
scr_stdio_write(2, b->data, b->len * scr_bytes_elem_size(b->elem));
|
|
164
163
|
return true;
|
|
165
164
|
}
|
|
166
165
|
|
package/src/scr_console.c
CHANGED
|
@@ -83,8 +83,11 @@ void scr_init(void) {
|
|
|
83
83
|
_setmode(_fileno(stderr), _O_BINARY);
|
|
84
84
|
_setmode(_fileno(stdin), _O_BINARY);
|
|
85
85
|
#endif
|
|
86
|
-
/*
|
|
87
|
-
*
|
|
86
|
+
/* A private formatting buffer coalesces the several stdio calls needed to
|
|
87
|
+
* render one console line. Every JavaScript-visible stdout write flushes
|
|
88
|
+
* before returning, so this buffer is never observable as delayed output:
|
|
89
|
+
* Node hands each console.log/process.stdout.write chunk to its backing
|
|
90
|
+
* stream immediately. */
|
|
88
91
|
static char outbuf[1 << 16];
|
|
89
92
|
setvbuf(stdout, outbuf, _IOFBF, sizeof outbuf);
|
|
90
93
|
/* atexit is LIFO; registration order makes exit run: library cleanup
|
|
@@ -131,18 +134,36 @@ static void scr_console_write(FILE *out, size_t n, const ScrLogArg *args) {
|
|
|
131
134
|
}
|
|
132
135
|
}
|
|
133
136
|
fputc('\n', out);
|
|
137
|
+
/* Console methods submit one formatted chunk to their backing stream.
|
|
138
|
+
* Keep the C buffer only as a formatter coalescing detail: a caller
|
|
139
|
+
* observing a live child must see this line before the next JS turn. */
|
|
140
|
+
fflush(out);
|
|
134
141
|
}
|
|
135
142
|
|
|
136
143
|
void scr_console_log(size_t n, const ScrLogArg *args) {
|
|
137
144
|
scr_console_write(stdout, n, args);
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
/* console.error and console.warn.
|
|
141
|
-
*
|
|
142
|
-
* redirection (2>&1)
|
|
143
|
-
*
|
|
144
|
-
* way. */
|
|
147
|
+
/* console.error and console.warn. Flush stdout first so runtime-internal
|
|
148
|
+
* output that is still being assembled cannot cross this stderr line under
|
|
149
|
+
* a merged redirection (2>&1); JavaScript-visible stdout writes have already
|
|
150
|
+
* flushed themselves. */
|
|
145
151
|
void scr_console_error(size_t n, const ScrLogArg *args) {
|
|
146
152
|
fflush(stdout);
|
|
147
153
|
scr_console_write(stderr, n, args);
|
|
148
154
|
}
|
|
155
|
+
|
|
156
|
+
/* One JavaScript-visible raw write. Node's global console and process stream
|
|
157
|
+
* methods hand each chunk to the backing stream when called; they do not
|
|
158
|
+
* retain stdout until a later stderr write, a 64 KiB threshold, or process
|
|
159
|
+
* exit. The runtime remains synchronous internally, so its backpressure
|
|
160
|
+
* surface is still constantly true, but the bytes are observable promptly.
|
|
161
|
+
*
|
|
162
|
+
* stderr flushes any runtime-internal stdout fragment first to preserve the
|
|
163
|
+
* existing merged-fd ordering convention. */
|
|
164
|
+
void scr_stdio_write(int fd, const void *data, size_t len) {
|
|
165
|
+
FILE *out = fd == 2 ? stderr : stdout;
|
|
166
|
+
if (fd == 2) fflush(stdout);
|
|
167
|
+
if (len > 0) fwrite(data, 1, len, out);
|
|
168
|
+
fflush(out);
|
|
169
|
+
}
|
package/src/scr_exception.c
CHANGED
|
@@ -307,8 +307,8 @@ int scr_exit_code_hint_get(void) { return scr_exit_code_hint; }
|
|
|
307
307
|
|
|
308
308
|
void scr_exc_print_uncaught(void) {
|
|
309
309
|
scr_exit_code_note(1);
|
|
310
|
-
/*
|
|
311
|
-
*
|
|
310
|
+
/* Settle any runtime-internal stdout fragment before the stderr line when
|
|
311
|
+
* both share an fd. JavaScript-visible writes already flush themselves. */
|
|
312
312
|
fflush(stdout);
|
|
313
313
|
fputs("Uncaught ", stderr);
|
|
314
314
|
switch (scr_exc_kind) {
|
package/src/scr_island.c
CHANGED
|
@@ -2682,7 +2682,7 @@ static JSValue isl_host_write(JSContext *ctx, JSValueConst this_val, int argc,
|
|
|
2682
2682
|
size_t len;
|
|
2683
2683
|
const char *s = JS_ToCStringLen(ctx, &len, argv[1]);
|
|
2684
2684
|
if (!s) return JS_EXCEPTION;
|
|
2685
|
-
|
|
2685
|
+
scr_stdio_write(fd, s, len);
|
|
2686
2686
|
JS_FreeCString(ctx, s);
|
|
2687
2687
|
return JS_TRUE;
|
|
2688
2688
|
}
|
package/src/scr_lib.c
CHANGED
|
@@ -584,21 +584,18 @@ ScrStr *scr_process_cwd(void) {
|
|
|
584
584
|
return scr_str_new(buf, strlen(buf));
|
|
585
585
|
}
|
|
586
586
|
|
|
587
|
-
/* The raw byte writes
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
* Node's backpressure signal — a synchronous fwrite has no backpressure,
|
|
593
|
-
* so it is constantly true. */
|
|
587
|
+
/* The raw byte writes use the SAME stdio stream as console, and each call
|
|
588
|
+
* flushes before returning so live consumers see Node's source order without
|
|
589
|
+
* an observable C buffering delay. The boolean is Node's backpressure signal
|
|
590
|
+
* — this synchronous runtime has no queued backpressure, so it is constantly
|
|
591
|
+
* true. */
|
|
594
592
|
bool scr_process_stdout_write(const ScrStr *data) {
|
|
595
|
-
|
|
593
|
+
scr_stdio_write(1, data->data, data->len);
|
|
596
594
|
return true;
|
|
597
595
|
}
|
|
598
596
|
|
|
599
597
|
bool scr_process_stderr_write(const ScrStr *data) {
|
|
600
|
-
|
|
601
|
-
fwrite(data->data, 1, data->len, stderr);
|
|
598
|
+
scr_stdio_write(2, data->data, data->len);
|
|
602
599
|
return true;
|
|
603
600
|
}
|
|
604
601
|
|
|
@@ -606,7 +603,7 @@ bool scr_process_stderr_write(const ScrStr *data) {
|
|
|
606
603
|
* WritableStream-typed value — the prefixStream idiom): the value is the
|
|
607
604
|
* stream's fd (1 or 2, minted by the process.stdout/stderr reads), and
|
|
608
605
|
* the write dispatches onto the exact stdout/stderr paths above so
|
|
609
|
-
*
|
|
606
|
+
* prompt submission and ordering stay identical. */
|
|
610
607
|
bool scr_proc_stream_write(double fd, const ScrStr *data) {
|
|
611
608
|
return (int)fd == 2 ? scr_process_stderr_write(data) : scr_process_stdout_write(data);
|
|
612
609
|
}
|
|
@@ -3506,6 +3503,170 @@ ScrStr *scr_num_to_fixed0(double x) {
|
|
|
3506
3503
|
return r;
|
|
3507
3504
|
}
|
|
3508
3505
|
|
|
3506
|
+
/* The explicit-fraction-digits toFixed needs the exact binary value, not
|
|
3507
|
+
* the shortest decimal that round-trips to it: (1.005).toFixed(2) is
|
|
3508
|
+
* "1.00", for example. Represent abs(x) * 10^f as
|
|
3509
|
+
*
|
|
3510
|
+
* mantissa * 5^f * 2^(binary_exponent + f)
|
|
3511
|
+
*
|
|
3512
|
+
* in a tiny base-2^32 integer, then shift right with the spec's
|
|
3513
|
+
* round-half-up rule. The largest value handled here is below 1e21 with
|
|
3514
|
+
* f=100, so the rounded integer is below 1e121 (402 bits); sixteen limbs
|
|
3515
|
+
* leave comfortable headroom without heap allocation. */
|
|
3516
|
+
#define SCR_FIXED_LIMBS 16
|
|
3517
|
+
typedef struct {
|
|
3518
|
+
uint32_t limb[SCR_FIXED_LIMBS]; /* little-endian */
|
|
3519
|
+
int len;
|
|
3520
|
+
} ScrFixedInt;
|
|
3521
|
+
|
|
3522
|
+
static void scr_fixed_normalize(ScrFixedInt *v) {
|
|
3523
|
+
while (v->len > 1 && v->limb[v->len - 1] == 0) v->len--;
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3526
|
+
static void scr_fixed_mul5(ScrFixedInt *v) {
|
|
3527
|
+
uint64_t carry = 0;
|
|
3528
|
+
for (int i = 0; i < v->len; i++) {
|
|
3529
|
+
uint64_t p = (uint64_t)v->limb[i] * 5 + carry;
|
|
3530
|
+
v->limb[i] = (uint32_t)p;
|
|
3531
|
+
carry = p >> 32;
|
|
3532
|
+
}
|
|
3533
|
+
if (carry != 0) v->limb[v->len++] = (uint32_t)carry;
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
static bool scr_fixed_bit(const ScrFixedInt *v, int bit) {
|
|
3537
|
+
int word = bit / 32;
|
|
3538
|
+
return word < v->len && ((v->limb[word] >> (bit % 32)) & 1u) != 0;
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3541
|
+
static void scr_fixed_shr(ScrFixedInt *v, int bits) {
|
|
3542
|
+
int words = bits / 32;
|
|
3543
|
+
int rem = bits % 32;
|
|
3544
|
+
if (words >= v->len) {
|
|
3545
|
+
v->limb[0] = 0;
|
|
3546
|
+
v->len = 1;
|
|
3547
|
+
return;
|
|
3548
|
+
}
|
|
3549
|
+
int n = v->len - words;
|
|
3550
|
+
for (int i = 0; i < n; i++) {
|
|
3551
|
+
uint32_t lo = v->limb[i + words] >> rem;
|
|
3552
|
+
uint32_t hi =
|
|
3553
|
+
rem != 0 && i + words + 1 < v->len
|
|
3554
|
+
? v->limb[i + words + 1] << (32 - rem)
|
|
3555
|
+
: 0;
|
|
3556
|
+
v->limb[i] = lo | hi;
|
|
3557
|
+
}
|
|
3558
|
+
v->len = n;
|
|
3559
|
+
scr_fixed_normalize(v);
|
|
3560
|
+
}
|
|
3561
|
+
|
|
3562
|
+
static void scr_fixed_shl(ScrFixedInt *v, int bits) {
|
|
3563
|
+
uint32_t out[SCR_FIXED_LIMBS] = {0};
|
|
3564
|
+
int words = bits / 32;
|
|
3565
|
+
int rem = bits % 32;
|
|
3566
|
+
for (int i = 0; i < v->len; i++) {
|
|
3567
|
+
int at = i + words;
|
|
3568
|
+
out[at] |= v->limb[i] << rem;
|
|
3569
|
+
if (rem != 0) out[at + 1] |= v->limb[i] >> (32 - rem);
|
|
3570
|
+
}
|
|
3571
|
+
int n = v->len + words + (rem != 0 ? 1 : 0);
|
|
3572
|
+
memcpy(v->limb, out, sizeof out);
|
|
3573
|
+
v->len = n;
|
|
3574
|
+
scr_fixed_normalize(v);
|
|
3575
|
+
}
|
|
3576
|
+
|
|
3577
|
+
static void scr_fixed_inc(ScrFixedInt *v) {
|
|
3578
|
+
uint64_t carry = 1;
|
|
3579
|
+
for (int i = 0; i < v->len && carry != 0; i++) {
|
|
3580
|
+
uint64_t s = (uint64_t)v->limb[i] + carry;
|
|
3581
|
+
v->limb[i] = (uint32_t)s;
|
|
3582
|
+
carry = s >> 32;
|
|
3583
|
+
}
|
|
3584
|
+
if (carry != 0) v->limb[v->len++] = (uint32_t)carry;
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
/* Divide in place by 1e9; each quotient limb still fits uint32_t because
|
|
3588
|
+
* the carried remainder is below the divisor. Returns the remainder. */
|
|
3589
|
+
static uint32_t scr_fixed_div1e9(ScrFixedInt *v) {
|
|
3590
|
+
uint64_t rem = 0;
|
|
3591
|
+
for (int i = v->len - 1; i >= 0; i--) {
|
|
3592
|
+
uint64_t cur = (rem << 32) | v->limb[i];
|
|
3593
|
+
v->limb[i] = (uint32_t)(cur / 1000000000u);
|
|
3594
|
+
rem = cur % 1000000000u;
|
|
3595
|
+
}
|
|
3596
|
+
scr_fixed_normalize(v);
|
|
3597
|
+
return (uint32_t)rem;
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3600
|
+
/* Number.prototype.toFixed(fractionDigits), with the argument already
|
|
3601
|
+
* number-typed by the frontend. ToIntegerOrInfinity validation precedes
|
|
3602
|
+
* the receiver's non-finite arm, as ECMA-262 requires. Invalid precision
|
|
3603
|
+
* raises V8's catchable RangeError text; otherwise the result is +1. */
|
|
3604
|
+
ScrStr *scr_num_to_fixed(double x, double fraction_digits) {
|
|
3605
|
+
double fd = isnan(fraction_digits) ? 0 : trunc(fraction_digits);
|
|
3606
|
+
if (!(fd >= 0 && fd <= 100)) {
|
|
3607
|
+
static const char msg[] =
|
|
3608
|
+
"toFixed() digits argument must be between 0 and 100";
|
|
3609
|
+
scr_throw_error_msg(SCR_ERR_RANGE, msg, sizeof msg - 1);
|
|
3610
|
+
return NULL;
|
|
3611
|
+
}
|
|
3612
|
+
int f = (int)fd;
|
|
3613
|
+
if (!isfinite(x) || fabs(x) >= 1e21) return scr_f64_to_scrstr(x);
|
|
3614
|
+
|
|
3615
|
+
bool neg = x < 0; /* false for -0, exactly like the spec's sign arm */
|
|
3616
|
+
double a = neg ? -x : x;
|
|
3617
|
+
uint64_t bits;
|
|
3618
|
+
memcpy(&bits, &a, sizeof bits);
|
|
3619
|
+
uint64_t mantissa = bits & ((1ull << 52) - 1);
|
|
3620
|
+
int ieee_exp = (int)((bits >> 52) & 0x7ffu);
|
|
3621
|
+
int binary_exp;
|
|
3622
|
+
if (ieee_exp == 0) {
|
|
3623
|
+
binary_exp = -1074;
|
|
3624
|
+
} else {
|
|
3625
|
+
mantissa |= 1ull << 52;
|
|
3626
|
+
binary_exp = ieee_exp - 1023 - 52;
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
ScrFixedInt n = {{(uint32_t)mantissa, (uint32_t)(mantissa >> 32)}, 2};
|
|
3630
|
+
scr_fixed_normalize(&n);
|
|
3631
|
+
for (int i = 0; i < f; i++) scr_fixed_mul5(&n);
|
|
3632
|
+
int shift = binary_exp + f;
|
|
3633
|
+
if (shift >= 0) {
|
|
3634
|
+
scr_fixed_shl(&n, shift);
|
|
3635
|
+
} else {
|
|
3636
|
+
int right = -shift;
|
|
3637
|
+
bool round_up = scr_fixed_bit(&n, right - 1);
|
|
3638
|
+
scr_fixed_shr(&n, right);
|
|
3639
|
+
if (round_up) scr_fixed_inc(&n);
|
|
3640
|
+
}
|
|
3641
|
+
|
|
3642
|
+
/* Render the exact rounded integer through base-1e9 chunks, then place
|
|
3643
|
+
* the decimal point f digits from the right (padding through zero). */
|
|
3644
|
+
uint32_t chunks[SCR_FIXED_LIMBS];
|
|
3645
|
+
int chunk_count = 0;
|
|
3646
|
+
do {
|
|
3647
|
+
chunks[chunk_count++] = scr_fixed_div1e9(&n);
|
|
3648
|
+
} while (!(n.len == 1 && n.limb[0] == 0));
|
|
3649
|
+
|
|
3650
|
+
char digits[128];
|
|
3651
|
+
int dlen = snprintf(digits, sizeof digits, "%u", chunks[chunk_count - 1]);
|
|
3652
|
+
for (int i = chunk_count - 2; i >= 0; i--) {
|
|
3653
|
+
dlen += snprintf(digits + dlen, sizeof digits - (size_t)dlen,
|
|
3654
|
+
"%09u", chunks[i]);
|
|
3655
|
+
}
|
|
3656
|
+
|
|
3657
|
+
char out[128];
|
|
3658
|
+
int o = 0;
|
|
3659
|
+
if (neg) out[o++] = '-';
|
|
3660
|
+
int padded = dlen > f + 1 ? dlen : f + 1;
|
|
3661
|
+
int integer_digits = padded - f;
|
|
3662
|
+
int leading_zeros = padded - dlen;
|
|
3663
|
+
for (int i = 0; i < padded; i++) {
|
|
3664
|
+
if (f != 0 && i == integer_digits) out[o++] = '.';
|
|
3665
|
+
out[o++] = i < leading_zeros ? '0' : digits[i - leading_zeros];
|
|
3666
|
+
}
|
|
3667
|
+
return scr_str_new(out, (size_t)o);
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3509
3670
|
/* Increment a decimal digit string in place. Returns true on overflow —
|
|
3510
3671
|
* the value becomes 1 followed by len zeros (the caller folds the zeros
|
|
3511
3672
|
* into its scale); an EMPTY string increments to "1" the same way (the
|
package/src/scr_readline.c
CHANGED
|
@@ -235,9 +235,10 @@ void scr_rl_question(double id, const ScrStr *query, ScrClosure *cb /*moves*/,
|
|
|
235
235
|
scr_throw_error_msg(SCR_ERR_ERROR, "readline was closed", 19);
|
|
236
236
|
return;
|
|
237
237
|
}
|
|
238
|
-
/* The prompt writes to stdout under pipes too (Node's question does)
|
|
239
|
-
*
|
|
240
|
-
|
|
238
|
+
/* The prompt writes to stdout under pipes too (Node's question does), and
|
|
239
|
+
* must be visible before input arrives even though it has no trailing
|
|
240
|
+
* newline. */
|
|
241
|
+
scr_stdio_write(1, query->data, query->len);
|
|
241
242
|
if (rl->dead) {
|
|
242
243
|
/* Created after stdin ended: pinned against Node — the prompt still
|
|
243
244
|
* writes, but the DESTROYED stream delivers nothing and 'close'
|
package/src/scr_runtime.h
CHANGED
|
@@ -35,8 +35,9 @@ char *strcasestr(const char *hay, const char *needle);
|
|
|
35
35
|
|
|
36
36
|
/* ── process ──────────────────────────────────────────────────────────── */
|
|
37
37
|
|
|
38
|
-
/* Called once at the top of main: stdout
|
|
39
|
-
* flush-at-exit, RC audit registration (when built with -DSCR_RC_AUDIT).
|
|
38
|
+
/* Called once at the top of main: private stdout formatter buffer,
|
|
39
|
+
* flush-at-exit, RC audit registration (when built with -DSCR_RC_AUDIT).
|
|
40
|
+
* JavaScript-visible writes flush before returning. */
|
|
40
41
|
void scr_init(void);
|
|
41
42
|
|
|
42
43
|
/* ── the trap funnel (scr_console.c; scr_library.c under -DSCR_LIB) ──────
|
|
@@ -1840,10 +1841,13 @@ int scr_lib_arg_count(void);
|
|
|
1840
1841
|
const char *scr_lib_arg(int i);
|
|
1841
1842
|
ScrStr *scr_process_platform(void); /* +1 interned ("darwin", "linux", ...) */
|
|
1842
1843
|
ScrStr *scr_process_cwd(void); /* +1 fresh (getcwd) */
|
|
1843
|
-
/*
|
|
1844
|
-
*
|
|
1845
|
-
*
|
|
1846
|
-
|
|
1844
|
+
/* Submit one raw chunk to fd 1/2 and flush it before returning. Used by all
|
|
1845
|
+
* JavaScript-visible console/process/readline/island output paths so the
|
|
1846
|
+
* internal stdio formatting buffer never delays live output. */
|
|
1847
|
+
void scr_stdio_write(int fd, const void *data, size_t len);
|
|
1848
|
+
/* process.stdout/.stderr .write — raw bytes (no newline or formatting; data
|
|
1849
|
+
* borrowed), promptly visible and ordered with console output. Constantly
|
|
1850
|
+
* true (the synchronous runtime never queues backpressure). */
|
|
1847
1851
|
bool scr_process_stdout_write(const ScrStr *data);
|
|
1848
1852
|
bool scr_process_stderr_write(const ScrStr *data);
|
|
1849
1853
|
/* The first-class WritableStream write: fd is the stream value itself
|
|
@@ -4239,12 +4243,14 @@ bool scr_num_is_finite(double x);
|
|
|
4239
4243
|
bool scr_num_is_nan(double x);
|
|
4240
4244
|
bool scr_num_is_integer(double x);
|
|
4241
4245
|
bool scr_num_is_safe_integer(double x);
|
|
4242
|
-
/*
|
|
4243
|
-
*
|
|
4244
|
-
*
|
|
4245
|
-
*
|
|
4246
|
+
/* Number.prototype formatters: toExponential() is the fraction-digits-free
|
|
4247
|
+
* shortest correctly-rounded mantissa; toFixed0 is the non-throwing omitted
|
|
4248
|
+
* argument form. toFixed implements an explicit 0..100 fractionDigits with
|
|
4249
|
+
* exact binary-value rounding and THROWS V8's catchable RangeError outside
|
|
4250
|
+
* that range. All successful results are +1. */
|
|
4246
4251
|
ScrStr *scr_num_to_exponential(double x);
|
|
4247
4252
|
ScrStr *scr_num_to_fixed0(double x);
|
|
4253
|
+
ScrStr *scr_num_to_fixed(double x, double fraction_digits);
|
|
4248
4254
|
|
|
4249
4255
|
/* Object.is over two numbers — the spec's SameValue on doubles: NaN
|
|
4250
4256
|
* equals NaN, +0 differs from -0, everything else is ==. Never throws. */
|
|
@@ -5835,11 +5841,11 @@ typedef struct {
|
|
|
5835
5841
|
} v;
|
|
5836
5842
|
} ScrLogArg;
|
|
5837
5843
|
|
|
5838
|
-
/* Space-joined args + '\n',
|
|
5844
|
+
/* Space-joined args + '\n', submitted before return. Borrows string args. */
|
|
5839
5845
|
void scr_console_log(size_t n, const ScrLogArg *args);
|
|
5840
5846
|
/* The stderr twin (console.error AND console.warn — one stream in Node):
|
|
5841
|
-
* identical formatting,
|
|
5842
|
-
*
|
|
5847
|
+
* identical formatting, with stdout settled first so merged (2>&1) output
|
|
5848
|
+
* keeps source order. */
|
|
5843
5849
|
void scr_console_error(size_t n, const ScrLogArg *args);
|
|
5844
5850
|
|
|
5845
5851
|
#endif /* SCR_RUNTIME_H */
|
package/src/scr_web.c
CHANGED
|
@@ -1739,7 +1739,7 @@ static JSValue web_host_write(JSContext *ctx, JSValueConst this_val, int argc,
|
|
|
1739
1739
|
size_t len;
|
|
1740
1740
|
const char *s = JS_ToCStringLen(ctx, &len, argv[1]);
|
|
1741
1741
|
if (!s) return JS_EXCEPTION;
|
|
1742
|
-
|
|
1742
|
+
scr_stdio_write(fd, s, len);
|
|
1743
1743
|
JS_FreeCString(ctx, s);
|
|
1744
1744
|
return JS_UNDEFINED;
|
|
1745
1745
|
}
|