@scriptc/runtime 0.0.4 → 0.0.6

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/src/scr_json.c CHANGED
@@ -36,8 +36,7 @@ long scr_dyn_live_count(void) { return scr_live_dyns; }
36
36
  #endif
37
37
 
38
38
  static void scr_json_oom(void) {
39
- fputs("scriptc: out of memory\n", stderr);
40
- abort();
39
+ scr_trap("scriptc: out of memory\n");
41
40
  }
42
41
 
43
42
  /* ── output buffer ─────────────────────────────────────────────────────
@@ -56,6 +55,9 @@ void scr_jb_init(ScrJsonBuf *b) {
56
55
  b->data = NULL;
57
56
  b->len = 0;
58
57
  b->cap = 0;
58
+ b->seen = NULL;
59
+ b->seen_len = 0;
60
+ b->seen_cap = 0;
59
61
  }
60
62
 
61
63
  static void scr_jb_grow(ScrJsonBuf *b, size_t need) {
@@ -77,6 +79,7 @@ static void scr_jb_grow(ScrJsonBuf *b, size_t need) {
77
79
  /* Abandon a buffer (parser error paths). */
78
80
  static void scr_jb_dispose(ScrJsonBuf *b) {
79
81
  if (b->data) scr_str_release(SCR_JB_STR(b));
82
+ free(b->seen);
80
83
  scr_jb_init(b);
81
84
  }
82
85
 
@@ -144,6 +147,10 @@ void scr_jb_put_json_str(ScrJsonBuf *b, const ScrStr *s) {
144
147
  }
145
148
 
146
149
  ScrStr *scr_jb_finish(ScrJsonBuf *b) {
150
+ free(b->seen);
151
+ b->seen = NULL;
152
+ b->seen_len = 0;
153
+ b->seen_cap = 0;
147
154
  if (!b->data) return scr_str_new("", 0);
148
155
  ScrStr *s = SCR_JB_STR(b);
149
156
  s->len = b->len;
@@ -155,6 +162,144 @@ ScrStr *scr_jb_finish(ScrJsonBuf *b) {
155
162
  return s;
156
163
  }
157
164
 
165
+ /* ── circular-structure detection ──────────────────────────────────────
166
+ * RECURSIVE record types permit runtime reference cycles; JSON.stringify
167
+ * of a cyclic value throws V8's exact TypeError. The compiler-emitted
168
+ * walkers over cycle-CAPABLE containers (records whose shape carries a
169
+ * collector header, arrays of them, tuple shapes alike) bracket their
170
+ * bodies with enter/leave and stamp the current member edge before each
171
+ * cycle-capable member write; everything acyclic pays nothing. Detection
172
+ * is STACK membership (a DAG serializes the shared subtree twice, exactly
173
+ * like Node — only a path back to an ancestor is circular).
174
+ *
175
+ * The message mirrors V8's ConstructCircularStructureErrorMessage byte
176
+ * for byte: the starting object (where the repeat lands), one line per
177
+ * hop from it to the top of the stack ("property 'x' -> object with
178
+ * constructor 'Y'" / "index N -> ..."), the middle elided as "..." when
179
+ * there are more than three hops (first two + last one shown), and the
180
+ * closing edge. Constructor names are exactly 'Object'/'Array' — the only
181
+ * containers JSON-safe types admit. */
182
+ typedef struct ScrJsonSeenEnt {
183
+ const void *ptr;
184
+ bool is_array;
185
+ const char *prop; /* static property edge (emitted C literal) */
186
+ const ScrStr *prop_str; /* overflow-key edge (borrowed for the write) */
187
+ size_t index; /* array/tuple index edge */
188
+ } ScrJsonSeenEnt;
189
+
190
+ static void scr_jb_put_edge(ScrJsonBuf *m, const ScrJsonSeenEnt *e) {
191
+ if (e->prop || e->prop_str) {
192
+ scr_jb_puts(m, "property '");
193
+ if (e->prop) scr_jb_puts(m, e->prop);
194
+ else scr_jb_write(m, e->prop_str->data, e->prop_str->len);
195
+ scr_jb_putc(m, '\'');
196
+ return;
197
+ }
198
+ scr_jb_puts(m, "index ");
199
+ scr_jb_put_f64(m, (double)e->index);
200
+ }
201
+
202
+ static void scr_jb_put_ctor(ScrJsonBuf *m, bool is_array) {
203
+ scr_jb_puts(m, is_array ? "object with constructor 'Array'" : "object with constructor 'Object'");
204
+ }
205
+
206
+ bool scr_jb_enter(ScrJsonBuf *b, const void *v, bool is_array) {
207
+ for (size_t i = 0; i < b->seen_len; i++) {
208
+ if (b->seen[i].ptr != v) continue;
209
+ ScrJsonBuf m;
210
+ scr_jb_init(&m);
211
+ scr_jb_puts(&m, "Converting circular structure to JSON\n --> starting at ");
212
+ scr_jb_put_ctor(&m, b->seen[i].is_array);
213
+ const size_t n = b->seen_len;
214
+ const size_t hops = n - 1 - i; /* intermediate lines (j = i+1 .. n-1) */
215
+ for (size_t j = i + 1; j < n; j++) {
216
+ if (hops > 3 && j - (i + 1) == 2) {
217
+ scr_jb_puts(&m, "\n | ...");
218
+ j = n - 2; /* the loop increment lands on the LAST hop */
219
+ continue;
220
+ }
221
+ scr_jb_puts(&m, "\n | ");
222
+ scr_jb_put_edge(&m, &b->seen[j - 1]);
223
+ scr_jb_puts(&m, " -> ");
224
+ scr_jb_put_ctor(&m, b->seen[j].is_array);
225
+ }
226
+ scr_jb_puts(&m, "\n --- ");
227
+ scr_jb_put_edge(&m, &b->seen[n - 1]);
228
+ scr_jb_puts(&m, " closes the circle");
229
+ scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&m));
230
+ return false;
231
+ }
232
+ if (b->seen_len == b->seen_cap) {
233
+ size_t cap = b->seen_cap ? b->seen_cap * 2 : 8;
234
+ ScrJsonSeenEnt *grown = realloc(b->seen, cap * sizeof *grown);
235
+ if (!grown) scr_json_oom();
236
+ b->seen = grown;
237
+ b->seen_cap = cap;
238
+ }
239
+ ScrJsonSeenEnt *e = &b->seen[b->seen_len++];
240
+ e->ptr = v;
241
+ e->is_array = is_array;
242
+ e->prop = NULL;
243
+ e->prop_str = NULL;
244
+ e->index = 0;
245
+ return true;
246
+ }
247
+
248
+ void scr_jb_leave(ScrJsonBuf *b) {
249
+ if (b->seen_len > 0) b->seen_len--;
250
+ }
251
+
252
+ void scr_jb_edge_prop(ScrJsonBuf *b, const char *name) {
253
+ ScrJsonSeenEnt *e = &b->seen[b->seen_len - 1];
254
+ e->prop = name;
255
+ e->prop_str = NULL;
256
+ }
257
+
258
+ void scr_jb_edge_key(ScrJsonBuf *b, const ScrStr *key) {
259
+ ScrJsonSeenEnt *e = &b->seen[b->seen_len - 1];
260
+ e->prop = NULL;
261
+ e->prop_str = key;
262
+ }
263
+
264
+ void scr_jb_edge_idx(ScrJsonBuf *b, size_t i) {
265
+ ScrJsonSeenEnt *e = &b->seen[b->seen_len - 1];
266
+ e->prop = NULL;
267
+ e->prop_str = NULL;
268
+ e->index = i;
269
+ }
270
+
271
+ /* ── circular guard for the typed→dyn converters (sc_td_*) ────────────
272
+ * A recursive-typed value crossing into a checked-dynamic slot DEEP-
273
+ * COPIES into the DOM; a cyclic value has no finite copy. Node never
274
+ * copies (an unknown-typed binding shares the reference), so there is no
275
+ * Node-exact error to throw — the conversion TRAPS loudly instead
276
+ * (SEMANTICS.md documents the divergence). The emitted converters over
277
+ * cycle-capable containers bracket their walks with enter/leave; the
278
+ * stack is global (conversions never interleave). */
279
+ static const void **g_td_seen;
280
+ static size_t g_td_nseen;
281
+ static size_t g_td_cap;
282
+
283
+ void scr_dyn_from_enter(const void *v) {
284
+ for (size_t i = 0; i < g_td_nseen; i++) {
285
+ if (g_td_seen[i] == v) {
286
+ scr_trap("scriptc: cannot convert a circular structure into a checked-dynamic value "
287
+ "(unknown-typed slots deep-copy; break the cycle first)\n");
288
+ }
289
+ }
290
+ if (g_td_nseen == g_td_cap) {
291
+ g_td_cap = g_td_cap ? g_td_cap * 2 : 8;
292
+ const void **grown = realloc(g_td_seen, g_td_cap * sizeof *grown);
293
+ if (!grown) scr_json_oom();
294
+ g_td_seen = grown;
295
+ }
296
+ g_td_seen[g_td_nseen++] = v;
297
+ }
298
+
299
+ void scr_dyn_from_leave(void) {
300
+ if (g_td_nseen > 0) g_td_nseen--;
301
+ }
302
+
158
303
  /* ── DOM lifecycle ─────────────────────────────────────────────────────
159
304
  * Parse/release churn (a JSON round-trip loop allocates and frees every
160
305
  * node each iteration) runs on freelists instead of calloc/free: one list
@@ -421,8 +566,7 @@ void scr_dyn_handle_install(ScrDynHandleTag tag, const ScrDynHandleOps *ops) {
421
566
  static const ScrDynHandleOps *scr_dyn_handle_ops(ScrDynHandleTag tag) {
422
567
  const ScrDynHandleOps *ops = scr_dynh_ops[tag];
423
568
  if (!ops) {
424
- fputs("scriptc: internal error: dyn handle ops not installed\n", stderr);
425
- abort();
569
+ scr_trap("scriptc: internal error: dyn handle ops not installed\n");
426
570
  }
427
571
  return ops;
428
572
  }
@@ -501,8 +645,7 @@ static ScrDynThisEnt *scr_dyn_this_grow(void) {
501
645
  size_t cap = scr_dyn_this_cap ? scr_dyn_this_cap * 2 : 8;
502
646
  ScrDynThisEnt *s = realloc(scr_dyn_this_stack, cap * sizeof *s);
503
647
  if (!s) {
504
- fputs("scriptc: out of memory\n", stderr);
505
- abort();
648
+ scr_trap("scriptc: out of memory\n");
506
649
  }
507
650
  scr_dyn_this_stack = s;
508
651
  scr_dyn_this_cap = cap;
@@ -526,8 +669,7 @@ void scr_dyn_this_push_dyn(const ScrDyn *v) {
526
669
 
527
670
  void scr_dyn_this_pop(void) {
528
671
  if (scr_dyn_this_n == 0) {
529
- fputs("scriptc: internal error: receiver stack underflow\n", stderr);
530
- abort();
672
+ scr_trap("scriptc: internal error: receiver stack underflow\n");
531
673
  }
532
674
  ScrDynThisEnt *e = &scr_dyn_this_stack[--scr_dyn_this_n];
533
675
  if (e->dv) scr_dyn_release(e->dv);
@@ -763,13 +905,12 @@ ScrDyn *scr_dyn_from_error(const ScrError *e) {
763
905
  scr_errdyn_cap = scr_errdyn_cap ? scr_errdyn_cap * 2 : 8;
764
906
  scr_errdyn_cache = realloc(scr_errdyn_cache, scr_errdyn_cap * sizeof *scr_errdyn_cache);
765
907
  if (!scr_errdyn_cache) {
766
- fputs("scriptc: out of memory\n", stderr);
767
- abort();
908
+ scr_trap("scriptc: out of memory\n");
768
909
  }
769
910
  }
770
911
  if (!scr_errdyn_teardown_registered) {
771
912
  scr_errdyn_teardown_registered = true;
772
- atexit(scr_errdyn_teardown);
913
+ scr_atexit(scr_errdyn_teardown);
773
914
  }
774
915
  scr_errdyn_cache[scr_errdyn_n].err = scr_error_retain((ScrError *)e);
775
916
  scr_errdyn_cache[scr_errdyn_n].dyn = scr_dyn_retain(d);
@@ -824,13 +965,12 @@ void scr_errdyn_put(ScrError *e, ScrDyn *d) {
824
965
  scr_errdyn_cap = scr_errdyn_cap ? scr_errdyn_cap * 2 : 8;
825
966
  scr_errdyn_cache = realloc(scr_errdyn_cache, scr_errdyn_cap * sizeof *scr_errdyn_cache);
826
967
  if (!scr_errdyn_cache) {
827
- fputs("scriptc: out of memory\n", stderr);
828
- abort();
968
+ scr_trap("scriptc: out of memory\n");
829
969
  }
830
970
  }
831
971
  if (!scr_errdyn_teardown_registered) {
832
972
  scr_errdyn_teardown_registered = true;
833
- atexit(scr_errdyn_teardown);
973
+ scr_atexit(scr_errdyn_teardown);
834
974
  }
835
975
  scr_errdyn_cache[scr_errdyn_n].err = scr_error_retain(e);
836
976
  scr_errdyn_cache[scr_errdyn_n].dyn = scr_dyn_retain(d);
@@ -1035,8 +1175,7 @@ void scr_jb_put_dyn(ScrJsonBuf *b, const ScrDyn *d) {
1035
1175
  return;
1036
1176
  }
1037
1177
  }
1038
- fputs("scriptc: internal error: invalid dyn kind\n", stderr);
1039
- abort();
1178
+ scr_trap("scriptc: internal error: invalid dyn kind\n");
1040
1179
  }
1041
1180
 
1042
1181
  /* ── dynCheck failure path ─────────────────────────────────────────────── */
@@ -1750,8 +1889,7 @@ static ScrDyn *scr_sc_clone(const ScrDyn *v, const ScrScParent *up) {
1750
1889
  size_t len = what->len + sizeof suffix - 1;
1751
1890
  char *msg = malloc(len + 1);
1752
1891
  if (!msg) {
1753
- fputs("scriptc: out of memory\n", stderr);
1754
- abort();
1892
+ scr_trap("scriptc: out of memory\n");
1755
1893
  }
1756
1894
  memcpy(msg, what->data, what->len);
1757
1895
  memcpy(msg + what->len, suffix, sizeof suffix);
@@ -1860,8 +1998,7 @@ static ScrDyn *scr_dyn_objwalk(const ScrDyn *v, ScrObjWalk mode) {
1860
1998
  bool *is_index = malloc(n ? n * sizeof *is_index : 1);
1861
1999
  double *idx = malloc(n ? n * sizeof *idx : 1);
1862
2000
  if (!is_index || !idx) {
1863
- fputs("scriptc: out of memory\n", stderr);
1864
- abort();
2001
+ scr_trap("scriptc: out of memory\n");
1865
2002
  }
1866
2003
  size_t index_count = 0;
1867
2004
  for (size_t i = 0; i < n; i++) {
package/src/scr_lib.c CHANGED
@@ -126,11 +126,25 @@ static void scr_lib_cleanup(void) {
126
126
  scr_versions_openssl_str = NULL;
127
127
  }
128
128
 
129
+ #ifndef SCR_LIB
130
+ /* Executable lane only: a library artifact has no argv and registers no
131
+ * atexit handlers (the emitted library init never calls this; keeping it out
132
+ * the archive's objects free of any atexit reference — the K8 ambient
133
+ * audit's bar). */
129
134
  void scr_lib_init(int argc, char **argv) {
130
135
  scr_lib_argc = argc;
131
136
  scr_lib_argv = argv;
132
137
  atexit(scr_lib_cleanup);
133
138
  }
139
+ #endif /* !SCR_LIB */
140
+
141
+ #ifdef SCR_LIB
142
+ /* Library builds never call scr_lib_init (a library artifact has no argv and registers no
143
+ * atexit handlers); the interned process values above still intern lazily
144
+ * on first read, so the library reset seam releases them here instead —
145
+ * scr_library_reset (scr_library.c) calls this every session reset. */
146
+ void scr_lib_session_cleanup(void) { scr_lib_cleanup(); }
147
+ #endif
134
148
 
135
149
  /* Raw argv accessors for the island's process shim (scr_island.c): the
136
150
  * island's process.argv must match the static world's ["scriptc",
@@ -261,8 +275,7 @@ ScrStr *scr_env_get(const ScrStr *name) {
261
275
  if (need == 0) return NULL; /* absent (an empty value still needs its NUL) */
262
276
  char *buf = malloc(need);
263
277
  if (!buf) {
264
- fputs("scriptc: out of memory\n", stderr);
265
- abort();
278
+ scr_trap("scriptc: out of memory\n");
266
279
  }
267
280
  DWORD got = GetEnvironmentVariableA(name->data, buf, need);
268
281
  ScrStr *s = scr_str_new(buf, got);
@@ -553,8 +566,7 @@ bool scr_process_kill_named(double pid, const ScrStr *signal) {
553
566
  size_t cap = 16 + signal->len + 1;
554
567
  char *msg = malloc(cap);
555
568
  if (!msg) {
556
- fputs("scriptc: out of memory\n", stderr);
557
- abort();
569
+ scr_trap("scriptc: out of memory\n");
558
570
  }
559
571
  int len = snprintf(msg, cap, "Unknown signal: %s", signal->data);
560
572
  scr_throw_error_msg(SCR_ERR_TYPE, msg, (size_t)len);
@@ -567,8 +579,7 @@ bool scr_process_kill_named(double pid, const ScrStr *signal) {
567
579
  ScrStr *scr_process_cwd(void) {
568
580
  char buf[4096];
569
581
  if (!getcwd(buf, sizeof buf)) {
570
- fputs("scriptc: process.cwd() failed\n", stderr);
571
- abort();
582
+ scr_trap("scriptc: process.cwd() failed\n");
572
583
  }
573
584
  return scr_str_new(buf, strlen(buf));
574
585
  }
@@ -612,16 +623,14 @@ bool scr_proc_stream_write(double fd, const ScrStr *data) {
612
623
  ScrStr *scr_os_homedir(void) {
613
624
  const char *home = getenv("USERPROFILE");
614
625
  if (home && home[0] != '\0') return scr_str_new(home, strlen(home));
615
- fputs("scriptc: os.homedir() failed\n", stderr);
616
- abort();
626
+ scr_trap("scriptc: os.homedir() failed\n");
617
627
  }
618
628
 
619
629
  ScrStr *scr_os_user_name(void) {
620
630
  char buf[UNLEN + 1];
621
631
  DWORD n = sizeof buf;
622
632
  if (!GetUserNameA(buf, &n) || n == 0) {
623
- fputs("scriptc: os.userInfo() failed\n", stderr);
624
- abort();
633
+ scr_trap("scriptc: os.userInfo() failed\n");
625
634
  }
626
635
  return scr_str_new(buf, n - 1); /* n counts the NUL */
627
636
  }
@@ -648,8 +657,7 @@ ScrStr *scr_os_release(void) {
648
657
  RtlGetVersionFn fn =
649
658
  ntdll ? (RtlGetVersionFn)(void *)GetProcAddress(ntdll, "RtlGetVersion") : NULL;
650
659
  if (fn == NULL || fn(&info) != 0) {
651
- fputs("scriptc: os.release() failed\n", stderr);
652
- abort();
660
+ scr_trap("scriptc: os.release() failed\n");
653
661
  }
654
662
  char buf[64];
655
663
  int len = snprintf(buf, sizeof buf, "%lu.%lu.%lu", (unsigned long)info.dwMajorVersion,
@@ -676,8 +684,7 @@ ScrStr *scr_os_tmpdir(void) {
676
684
  char buf[MAX_PATH + 2];
677
685
  DWORD n = GetTempPathA(sizeof buf, buf);
678
686
  if (n == 0 || n >= sizeof buf) {
679
- fputs("scriptc: os.tmpdir() failed\n", stderr);
680
- abort();
687
+ scr_trap("scriptc: os.tmpdir() failed\n");
681
688
  }
682
689
  size_t len = n;
683
690
  if (len > 1 && (buf[len - 1] == '\\' || buf[len - 1] == '/')) len--;
@@ -693,8 +700,7 @@ ScrStr *scr_os_homedir(void) {
693
700
  struct passwd *result = NULL;
694
701
  char buf[8192];
695
702
  if (getpwuid_r(getuid(), &pw, buf, sizeof buf, &result) != 0 || !result || !result->pw_dir) {
696
- fputs("scriptc: os.homedir() failed\n", stderr);
697
- abort();
703
+ scr_trap("scriptc: os.homedir() failed\n");
698
704
  }
699
705
  return scr_str_new(result->pw_dir, strlen(result->pw_dir));
700
706
  }
@@ -706,8 +712,7 @@ ScrStr *scr_os_homedir(void) {
706
712
  static const struct passwd *scr_os_passwd(char *buf, size_t cap, struct passwd *pw) {
707
713
  struct passwd *result = NULL;
708
714
  if (getpwuid_r(getuid(), pw, buf, cap, &result) != 0 || !result) {
709
- fputs("scriptc: os.userInfo() failed\n", stderr);
710
- abort();
715
+ scr_trap("scriptc: os.userInfo() failed\n");
711
716
  }
712
717
  return result;
713
718
  }
@@ -740,8 +745,7 @@ ScrStr *scr_os_release(void) {
740
745
  /* uname(2)'s release field — Node's uv_os_uname()-backed answer. */
741
746
  struct utsname u;
742
747
  if (uname(&u) != 0) {
743
- fputs("scriptc: os.release() failed\n", stderr);
744
- abort();
748
+ scr_trap("scriptc: os.release() failed\n");
745
749
  }
746
750
  return scr_str_new(u.release, strlen(u.release));
747
751
  }
@@ -750,8 +754,7 @@ ScrStr *scr_os_type(void) {
750
754
  /* uname(2)'s sysname field ("Darwin", "Linux") — Node's os.type(). */
751
755
  struct utsname u;
752
756
  if (uname(&u) != 0) {
753
- fputs("scriptc: os.type() failed\n", stderr);
754
- abort();
757
+ scr_trap("scriptc: os.type() failed\n");
755
758
  }
756
759
  return scr_str_new(u.sysname, strlen(u.sysname));
757
760
  }
@@ -824,20 +827,20 @@ struct ScrIfaddrs {
824
827
  * stance. */
825
828
  ScrIfaddrs *scr_os_ifaddrs(void) {
826
829
  ScrIfaddrs *s = calloc(1, sizeof *s);
827
- if (!s) abort();
830
+ if (!s) scr_trap("scriptc: out of memory\n");
828
831
  ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
829
832
  GAA_FLAG_SKIP_DNS_SERVER;
830
833
  ULONG size = 16 * 1024;
831
834
  IP_ADAPTER_ADDRESSES *adapters = NULL;
832
835
  for (int tries = 0; tries < 4; tries++) {
833
836
  adapters = realloc(adapters, size);
834
- if (!adapters) abort();
837
+ if (!adapters) scr_trap("scriptc: out of memory\n");
835
838
  ULONG rc = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &size);
836
839
  if (rc == ERROR_SUCCESS) break;
837
840
  if (rc != ERROR_BUFFER_OVERFLOW) {
838
841
  free(adapters);
839
842
  s->rows = calloc(1, sizeof *s->rows);
840
- if (!s->rows) abort();
843
+ if (!s->rows) scr_trap("scriptc: out of memory\n");
841
844
  return s; /* empty snapshot */
842
845
  }
843
846
  }
@@ -850,7 +853,7 @@ ScrIfaddrs *scr_os_ifaddrs(void) {
850
853
  }
851
854
  }
852
855
  s->rows = calloc(count ? count : 1, sizeof *s->rows);
853
- if (!s->rows) abort();
856
+ if (!s->rows) scr_trap("scriptc: out of memory\n");
854
857
  for (IP_ADAPTER_ADDRESSES *a = adapters; a != NULL; a = a->Next) {
855
858
  if (a->OperStatus != IfOperStatusUp || a->FirstUnicastAddress == NULL) continue;
856
859
  char name[64] = "";
@@ -934,7 +937,7 @@ static int scr_netmask_prefix(const unsigned char *bytes, size_t len) {
934
937
 
935
938
  ScrIfaddrs *scr_os_ifaddrs(void) {
936
939
  ScrIfaddrs *s = calloc(1, sizeof *s);
937
- if (!s) abort();
940
+ if (!s) scr_trap("scriptc: out of memory\n");
938
941
  struct ifaddrs *addrs = NULL;
939
942
  if (getifaddrs(&addrs) != 0) return s;
940
943
  size_t count = 0;
@@ -942,7 +945,7 @@ ScrIfaddrs *scr_os_ifaddrs(void) {
942
945
  if (scr_ifaddr_row_ok(ent)) count++;
943
946
  }
944
947
  s->rows = calloc(count ? count : 1, sizeof *s->rows);
945
- if (!s->rows) abort();
948
+ if (!s->rows) scr_trap("scriptc: out of memory\n");
946
949
  for (struct ifaddrs *ent = addrs; ent != NULL; ent = ent->ifa_next) {
947
950
  if (!scr_ifaddr_row_ok(ent)) continue;
948
951
  ScrIfaddrRow *row = &s->rows[s->n++];
@@ -1419,8 +1422,7 @@ void scr_fs_throw(int e, const char *op, const ScrStr *path) {
1419
1422
  size_t cap = strlen(name) + strlen(text) + strlen(op) + strlen(shown) + 8;
1420
1423
  char *msg = malloc(cap);
1421
1424
  if (!msg) {
1422
- fputs("scriptc: out of memory\n", stderr);
1423
- abort();
1425
+ scr_trap("scriptc: out of memory\n");
1424
1426
  }
1425
1427
  int len = snprintf(msg, cap, "%s: %s, %s '%s'", name, text, op, shown);
1426
1428
  /* A real Error instance (name "Error", message = Node's text) — what a
@@ -1443,16 +1445,14 @@ ScrStr *scr_fs_read_file(ScrStr *path) {
1443
1445
  size_t cap = 4096, len = 0;
1444
1446
  char *buf = malloc(cap);
1445
1447
  if (!buf) {
1446
- fputs("scriptc: out of memory\n", stderr);
1447
- abort();
1448
+ scr_trap("scriptc: out of memory\n");
1448
1449
  }
1449
1450
  for (;;) {
1450
1451
  if (cap - len < 2048) {
1451
1452
  cap *= 2;
1452
1453
  char *grown = realloc(buf, cap);
1453
1454
  if (!grown) {
1454
- fputs("scriptc: out of memory\n", stderr);
1455
- abort();
1455
+ scr_trap("scriptc: out of memory\n");
1456
1456
  }
1457
1457
  buf = grown;
1458
1458
  }
@@ -1698,8 +1698,7 @@ static void scr_fs_throw2(int e, const char *op, const ScrStr *src, const ScrStr
1698
1698
  size_t cap = strlen(name) + strlen(text) + strlen(op) + strlen(shown_src) + strlen(shown_dest) + 16;
1699
1699
  char *msg = malloc(cap);
1700
1700
  if (!msg) {
1701
- fputs("scriptc: out of memory\n", stderr);
1702
- abort();
1701
+ scr_trap("scriptc: out of memory\n");
1703
1702
  }
1704
1703
  int len = snprintf(msg, cap, "%s: %s, %s '%s' -> '%s'", name, text, op, shown_src, shown_dest);
1705
1704
  scr_throw_error_msg_code(SCR_ERR_ERROR, msg, (size_t)len, name);
@@ -1856,8 +1855,7 @@ static void scr_mkdir_rec(char *path, size_t len, mode_t mode) {
1856
1855
  void scr_fs_mkdir_recursive(ScrStr *path) {
1857
1856
  char *buf = malloc(path->len + 1);
1858
1857
  if (!buf) {
1859
- fputs("scriptc: out of memory\n", stderr);
1860
- abort();
1858
+ scr_trap("scriptc: out of memory\n");
1861
1859
  }
1862
1860
  memcpy(buf, path->data, path->len + 1); /* ScrStr data is NUL-terminated */
1863
1861
  scr_mkdir_rec(buf, path->len, 0777);
@@ -1869,8 +1867,7 @@ void scr_fs_mkdir_recursive(ScrStr *path) {
1869
1867
  void scr_fs_mkdir_recursive_mode(ScrStr *path, double mode) {
1870
1868
  char *buf = malloc(path->len + 1);
1871
1869
  if (!buf) {
1872
- fputs("scriptc: out of memory\n", stderr);
1873
- abort();
1870
+ scr_trap("scriptc: out of memory\n");
1874
1871
  }
1875
1872
  memcpy(buf, path->data, path->len + 1);
1876
1873
  scr_mkdir_rec(buf, path->len, (mode_t)mode);
@@ -1917,8 +1914,7 @@ static void scr_rm_tree_e(const char *path, size_t len, ScrRmFail *f) {
1917
1914
  size_t namelen = strlen(ent->d_name);
1918
1915
  char *child = malloc(len + 1 + namelen + 1);
1919
1916
  if (!child) {
1920
- fputs("scriptc: out of memory\n", stderr);
1921
- abort();
1917
+ scr_trap("scriptc: out of memory\n");
1922
1918
  }
1923
1919
  memcpy(child, path, len);
1924
1920
  child[len] = '/';
@@ -2021,8 +2017,7 @@ static char *scr_win_mkdtemp(char *tmpl) {
2021
2017
  ScrStr *scr_fs_mkdtemp(ScrStr *prefix) {
2022
2018
  char *tmpl = malloc(prefix->len + 7);
2023
2019
  if (!tmpl) {
2024
- fputs("scriptc: out of memory\n", stderr);
2025
- abort();
2020
+ scr_trap("scriptc: out of memory\n");
2026
2021
  }
2027
2022
  memcpy(tmpl, prefix->data, prefix->len);
2028
2023
  memcpy(tmpl + prefix->len, "XXXXXX", 7);
@@ -2069,16 +2064,14 @@ static char *scr_read_fd_all(double fd, size_t *out_len) {
2069
2064
  size_t cap = 4096, len = 0;
2070
2065
  char *buf = malloc(cap);
2071
2066
  if (!buf) {
2072
- fputs("scriptc: out of memory\n", stderr);
2073
- abort();
2067
+ scr_trap("scriptc: out of memory\n");
2074
2068
  }
2075
2069
  for (;;) {
2076
2070
  if (cap - len < 2048) {
2077
2071
  cap *= 2;
2078
2072
  char *grown = realloc(buf, cap);
2079
2073
  if (!grown) {
2080
- fputs("scriptc: out of memory\n", stderr);
2081
- abort();
2074
+ scr_trap("scriptc: out of memory\n");
2082
2075
  }
2083
2076
  buf = grown;
2084
2077
  }
@@ -2286,8 +2279,7 @@ double scr_stats_mtime_ms(ScrStats *s) { return s->mtime_ms; }
2286
2279
  static ScrStats *scr_stats_of(const struct stat *st) {
2287
2280
  ScrStats *s = malloc(sizeof(ScrStats));
2288
2281
  if (!s) {
2289
- fputs("scriptc: out of memory\n", stderr);
2290
- abort();
2282
+ scr_trap("scriptc: out of memory\n");
2291
2283
  }
2292
2284
  s->rc = 1;
2293
2285
  s->is_file = S_ISREG(st->st_mode);
@@ -2384,16 +2376,14 @@ ScrScandir *scr_fs_scandir(ScrStr *path) {
2384
2376
  }
2385
2377
  ScrScandir *s = malloc(sizeof *s);
2386
2378
  if (!s) {
2387
- fputs("scriptc: out of memory\n", stderr);
2388
- abort();
2379
+ scr_trap("scriptc: out of memory\n");
2389
2380
  }
2390
2381
  s->len = 0;
2391
2382
  s->cap = 8;
2392
2383
  s->names = malloc(s->cap * sizeof *s->names);
2393
2384
  s->kinds = malloc(s->cap);
2394
2385
  if (!s->names || !s->kinds) {
2395
- fputs("scriptc: out of memory\n", stderr);
2396
- abort();
2386
+ scr_trap("scriptc: out of memory\n");
2397
2387
  }
2398
2388
  const struct dirent *ent;
2399
2389
  while ((ent = readdir(d)) != NULL) {
@@ -2434,8 +2424,7 @@ ScrScandir *scr_fs_scandir(ScrStr *path) {
2434
2424
  s->names = realloc(s->names, s->cap * sizeof *s->names);
2435
2425
  s->kinds = realloc(s->kinds, s->cap);
2436
2426
  if (!s->names || !s->kinds) {
2437
- fputs("scriptc: out of memory\n", stderr);
2438
- abort();
2427
+ scr_trap("scriptc: out of memory\n");
2439
2428
  }
2440
2429
  }
2441
2430
  s->names[s->len] = scr_str_new(ent->d_name, strlen(ent->d_name));
@@ -2545,8 +2534,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
2545
2534
  size_t size = (size_t)n;
2546
2535
  unsigned char *bytes = malloc(size ? size : 1);
2547
2536
  if (!bytes) {
2548
- fputs("scriptc: out of memory\n", stderr);
2549
- abort();
2537
+ scr_trap("scriptc: out of memory\n");
2550
2538
  }
2551
2539
  arc4random_buf(bytes, size);
2552
2540
  ScrStr *out;
@@ -2554,8 +2542,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
2554
2542
  static const char hex[] = "0123456789abcdef";
2555
2543
  char *buf = malloc(size * 2 + 1);
2556
2544
  if (!buf) {
2557
- fputs("scriptc: out of memory\n", stderr);
2558
- abort();
2545
+ scr_trap("scriptc: out of memory\n");
2559
2546
  }
2560
2547
  for (size_t i = 0; i < size; i++) {
2561
2548
  buf[i * 2] = hex[bytes[i] >> 4];
@@ -2569,8 +2556,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
2569
2556
  size_t outlen = (size + 2) / 3 * 4;
2570
2557
  char *buf = malloc(outlen + 1);
2571
2558
  if (!buf) {
2572
- fputs("scriptc: out of memory\n", stderr);
2573
- abort();
2559
+ scr_trap("scriptc: out of memory\n");
2574
2560
  }
2575
2561
  size_t o = 0;
2576
2562
  for (size_t i = 0; i < size; i += 3) {
@@ -2909,8 +2895,7 @@ static bool scr_x509_der(const uint8_t *in, size_t n, const uint8_t **der, size_
2909
2895
  }
2910
2896
  uint8_t *out = malloc(((size_t)(stop - b) / 4 + 1) * 3 + 3);
2911
2897
  if (!out) {
2912
- fputs("scriptc: out of memory\n", stderr);
2913
- abort();
2898
+ scr_trap("scriptc: out of memory\n");
2914
2899
  }
2915
2900
  size_t o = 0;
2916
2901
  unsigned acc = 0;
@@ -3126,8 +3111,7 @@ static uint32_t scr_to_uint32(double d);
3126
3111
  static ScrStr *scr_str_from_units(size_t n, uint32_t (*unit)(void *, size_t), void *src) {
3127
3112
  char *out = malloc(n * 3 + 1); /* worst case: 3 bytes per UTF-16 unit */
3128
3113
  if (!out) {
3129
- fputs("scriptc: out of memory\n", stderr);
3130
- abort();
3114
+ scr_trap("scriptc: out of memory\n");
3131
3115
  }
3132
3116
  size_t o = 0;
3133
3117
  for (size_t i = 0; i < n; i++) {