MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 2032 lines 63 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <stdlib.h> 4#include <stdio.h> 5#include <string.h> 6#include <signal.h> 7#include <time.h> 8#include <uthash.h> 9#include <uv.h> 10 11#ifdef _WIN32 12#define WIN32_LEAN_AND_MEAN 13#include <windows.h> 14#include <io.h> 15#include <psapi.h> 16#define STDIN_FILENO 0 17#define STDOUT_FILENO 1 18#define STDERR_FILENO 2 19#else 20#include <termios.h> 21#include <unistd.h> 22#include <sys/ioctl.h> 23#include <sys/time.h> 24#include <sys/resource.h> 25#include <sys/stat.h> 26#include <grp.h> 27#include <pwd.h> 28#endif 29 30#include "ant.h" 31#include "errors.h" 32#include "output.h" 33#include "utils.h" 34#include "tty_ctrl.h" 35#include "internal.h" 36#include "descriptors.h" 37#include "runtime.h" 38#include "silver/engine.h" 39#include "gc/modules.h" 40 41#include "modules/process.h" 42#include "modules/tty.h" 43#include "modules/symbol.h" 44#include "modules/buffer.h" 45#include "modules/napi.h" 46#include "modules/timer.h" 47#include "modules/string_decoder.h" 48 49#ifndef _WIN32 50extern char **environ; 51#else 52#define environ _environ 53#endif 54 55#define DEFAULT_MAX_LISTENERS 10 56#define INITIAL_LISTENER_CAPACITY 4 57 58typedef struct { 59 ant_value_t listener; 60 bool once; 61} ProcessEventListener; 62 63typedef struct { 64 char *event_type; 65 ProcessEventListener *listeners; 66 int listener_count; 67 int listener_capacity; 68 int emitting; 69 bool free_deferred; 70 UT_hash_handle hh; 71} ProcessEventType; 72 73static int max_listeners = DEFAULT_MAX_LISTENERS; 74static ProcessEventType *process_events = NULL; 75 76typedef struct { 77 uv_signal_t handle; 78 int signum; 79 UT_hash_handle hh; 80} SignalHandle; 81 82static SignalHandle *signal_handles = NULL; 83static ProcessEventType *stdin_events = NULL; 84static ProcessEventType *stdout_events = NULL; 85static ProcessEventType *stderr_events = NULL; 86 87typedef struct { 88 uv_tty_t tty; 89 bool tty_initialized; 90 bool reading; 91 bool keypress_enabled; 92 ant_value_t decoder; 93 int escape_state; 94 int escape_len; 95 char escape_buf[16]; 96} stdin_state_t; 97 98static stdin_state_t stdin_state = {0}; 99static uint64_t process_start_time = 0; 100 101#ifndef _WIN32 102static uv_signal_t sigwinch_handle; 103static bool sigwinch_initialized = false; 104#endif 105 106typedef struct { 107 const char *name; 108 int signum; 109 UT_hash_handle hh_name; 110 UT_hash_handle hh_num; 111} SignalEntry; 112 113static SignalEntry *signals_by_name = NULL; 114static SignalEntry *signals_by_num = NULL; 115 116static void init_signal_map(void) { 117 static bool initialized = false; 118 if (initialized) return; 119 120 #define S(sig) { #sig, sig, {0}, {0} } 121 static SignalEntry entries[] = { 122 S(SIGINT), S(SIGILL), S(SIGABRT), S(SIGFPE), 123 S(SIGSEGV), S(SIGTERM), 124 #ifdef SIGHUP 125 S(SIGHUP), 126 #endif 127 #ifdef SIGQUIT 128 S(SIGQUIT), 129 #endif 130 #ifdef SIGTRAP 131 S(SIGTRAP), 132 #endif 133 #ifdef SIGKILL 134 S(SIGKILL), 135 #endif 136 #ifdef SIGBUS 137 S(SIGBUS), 138 #endif 139 #ifdef SIGSYS 140 S(SIGSYS), 141 #endif 142 #ifdef SIGPIPE 143 S(SIGPIPE), 144 #endif 145 #ifdef SIGALRM 146 S(SIGALRM), 147 #endif 148 #ifdef SIGURG 149 S(SIGURG), 150 #endif 151 #ifdef SIGSTOP 152 S(SIGSTOP), 153 #endif 154 #ifdef SIGTSTP 155 S(SIGTSTP), 156 #endif 157 #ifdef SIGCONT 158 S(SIGCONT), 159 #endif 160 #ifdef SIGCHLD 161 S(SIGCHLD), 162 #endif 163 #ifdef SIGTTIN 164 S(SIGTTIN), 165 #endif 166 #ifdef SIGTTOU 167 S(SIGTTOU), 168 #endif 169 #ifdef SIGXCPU 170 S(SIGXCPU), 171 #endif 172 #ifdef SIGXFSZ 173 S(SIGXFSZ), 174 #endif 175 #ifdef SIGVTALRM 176 S(SIGVTALRM), 177 #endif 178 #ifdef SIGPROF 179 S(SIGPROF), 180 #endif 181 #ifdef SIGUSR1 182 S(SIGUSR1), 183 #endif 184 #ifdef SIGUSR2 185 S(SIGUSR2), 186 #endif 187 #ifdef SIGEMT 188 S(SIGEMT), 189 #endif 190 #ifdef SIGIO 191 S(SIGIO), 192 #endif 193 #ifdef SIGWINCH 194 S(SIGWINCH), 195 #endif 196 #ifdef SIGINFO 197 S(SIGINFO), 198 #endif 199 #ifdef SIGPWR 200 S(SIGPWR), 201 #endif 202 #ifdef SIGSTKFLT 203 S(SIGSTKFLT), 204 #endif 205 #ifdef SIGPOLL 206 S(SIGPOLL), 207 #endif 208 }; 209 #undef S 210 211 size_t count = sizeof(entries) / sizeof(entries[0]); 212 for (size_t i = 0; i < count; i++) { 213 HASH_ADD_KEYPTR(hh_name, signals_by_name, entries[i].name, strlen(entries[i].name), &entries[i]); 214 HASH_ADD(hh_num, signals_by_num, signum, sizeof(int), &entries[i]); 215 } 216 217 initialized = true; 218} 219 220static int get_signal_number(const char *name) { 221 init_signal_map(); 222 SignalEntry *entry = NULL; 223 HASH_FIND(hh_name, signals_by_name, name, strlen(name), entry); 224 return entry ? entry->signum : -1; 225} 226 227static const char *get_signal_name(int signum) { 228 init_signal_map(); 229 SignalEntry *entry = NULL; 230 HASH_FIND(hh_num, signals_by_num, &signum, sizeof(int), entry); 231 return entry ? entry->name : NULL; 232} 233 234static ProcessEventType *find_or_create_event(ProcessEventType **table, const char *event_type) { 235 ProcessEventType *evt = NULL; 236 HASH_FIND_STR(*table, event_type, evt); 237 238 if (evt == NULL) { 239 evt = malloc(sizeof(ProcessEventType)); 240 *evt = (ProcessEventType){ 241 .event_type = strdup(event_type), 242 .emitting = 0, 243 .listener_count = 0, 244 .free_deferred = false, 245 .listener_capacity = INITIAL_LISTENER_CAPACITY, 246 .listeners = malloc(sizeof(ProcessEventListener) * INITIAL_LISTENER_CAPACITY), 247 }; 248 HASH_ADD_KEYPTR(hh, *table, evt->event_type, strlen(evt->event_type), evt); 249 } 250 251 return evt; 252} 253 254static bool ensure_listener_capacity(ProcessEventType *evt) { 255 if (evt->listener_count >= evt->listener_capacity) { 256 int new_capacity = evt->listener_capacity * 2; 257 ProcessEventListener *new_listeners = realloc(evt->listeners, sizeof(ProcessEventListener) * new_capacity); 258 if (!new_listeners) return false; 259 evt->listeners = new_listeners; 260 evt->listener_capacity = new_capacity; 261 } 262 return true; 263} 264 265static void free_event_type(ProcessEventType **events, ProcessEventType *evt) { 266 if (!evt) return; 267 if (evt->emitting > 0) { evt->free_deferred = true; return; } 268 HASH_DEL(*events, evt); 269 270 free(evt->listeners); 271 free(evt->event_type); free(evt); 272} 273 274static void check_listener_warning(const char *event) { 275 ProcessEventType *evt = NULL; 276 HASH_FIND_STR(process_events, event, evt); 277 if (evt && evt->listener_count == max_listeners) fprintf(stderr, 278 "Warning: Possible EventEmitter memory leak detected. " 279 "%d '%s' listeners added. Use process.setMaxListeners() to increase limit.\n", 280 evt->listener_count, event 281 ); 282} 283 284static void uv_signal_handler(uv_signal_t *handle, int signum) { 285 const char *name = get_signal_name(signum); 286 if (name) { 287 ant_value_t sig_arg = js_mkstr(rt->js, name, strlen(name)); 288 emit_process_event(name, &sig_arg, 1); 289 } 290} 291 292static void start_signal_watch(int signum) { 293 SignalHandle *sh = NULL; 294 HASH_FIND_INT(signal_handles, &signum, sh); 295 if (sh) return; 296 297 sh = malloc(sizeof(SignalHandle)); 298 sh->signum = signum; 299 uv_signal_init(uv_default_loop(), &sh->handle); 300 uv_signal_start(&sh->handle, uv_signal_handler, signum); 301 uv_unref((uv_handle_t *)&sh->handle); 302 HASH_ADD_INT(signal_handles, signum, sh); 303} 304 305static void on_signal_handle_close(uv_handle_t *handle) { 306 SignalHandle *sh = (SignalHandle *)handle; 307 free(sh); 308} 309 310static void stop_signal_watch(int signum) { 311 SignalHandle *sh = NULL; 312 HASH_FIND_INT(signal_handles, &signum, sh); 313 if (!sh) return; 314 315 HASH_DEL(signal_handles, sh); 316 uv_signal_stop(&sh->handle); 317 uv_close((uv_handle_t *)&sh->handle, on_signal_handle_close); 318} 319 320 321void emit_process_event(const char *event_type, ant_value_t *args, int nargs) { 322 if (!rt->js) return; 323 324 ProcessEventType *evt = NULL; 325 HASH_FIND_STR(process_events, event_type, evt); 326 327 if (evt == NULL || evt->listener_count == 0) return; 328 evt->emitting++; int i = 0; 329 330 while (i < evt->listener_count) { 331 ProcessEventListener *listener = &evt->listeners[i]; 332 sv_vm_call(rt->js->vm, rt->js, listener->listener, js_mkundef(), args, nargs, NULL, false); 333 334 if (listener->once) { 335 for (int j = i; j < evt->listener_count - 1; j++) { 336 evt->listeners[j] = evt->listeners[j + 1]; 337 } evt->listener_count--; 338 } else i++; 339 } evt->emitting--; 340 341 if (evt->listener_count == 0 || evt->free_deferred) { 342 int signum = get_signal_number(event_type); 343 if (signum > 0) stop_signal_watch(signum); 344 if (evt->emitting == 0) free_event_type(&process_events, evt); 345 } 346} 347 348bool process_has_event_listeners(const char *event_type) { 349 ProcessEventType *evt = NULL; 350 if (!event_type) return false; 351 HASH_FIND_STR(process_events, event_type, evt); 352 return evt && evt->listener_count > 0; 353} 354 355static void emit_stdio_event(ProcessEventType **events, const char *event_type, ant_value_t *args, int nargs) { 356 if (!rt->js) return; 357 ProcessEventType *evt = NULL; 358 359 HASH_FIND_STR(*events, event_type, evt); 360 if (evt == NULL || evt->listener_count == 0) return; 361 362 evt->emitting++; 363 int i = 0; 364 while (i < evt->listener_count) { 365 ProcessEventListener *listener = &evt->listeners[i]; 366 sv_vm_call(rt->js->vm, rt->js, listener->listener, js_mkundef(), args, nargs, NULL, false); 367 if (listener->once) { 368 for (int j = i; j < evt->listener_count - 1; j++) 369 evt->listeners[j] = evt->listeners[j + 1]; 370 evt->listener_count--; 371 } else i++; 372 } evt->emitting--; 373 374 if ((evt->listener_count == 0 || evt->free_deferred) && evt->emitting == 0) 375 free_event_type(events, evt); 376} 377 378static const char *stdin_escape_name(const char *seq, int len) { 379 if (len < 2) return NULL; 380 381 if (seq[0] == '[') { 382 if (seq[1] >= '0' && seq[1] <= '9') { 383 int num = 0; 384 int idx = 1; 385 386 while (idx < len && seq[idx] >= '0' && seq[idx] <= '9') { 387 num = num * 10 + (seq[idx] - '0'); 388 idx++; 389 } 390 391 if (idx < len && seq[idx] == '~') { 392 typedef struct { 393 int code; 394 const char *name; 395 } esc_num_map_t; 396 397 static const esc_num_map_t esc_num_map[] = { 398 { 1, "home" }, 399 { 2, "insert" }, 400 { 3, "delete" }, 401 { 4, "end" }, 402 { 5, "pageup" }, 403 { 6, "pagedown" }, 404 { 7, "home" }, 405 { 8, "end" }, 406 { 15, "f5" }, 407 { 17, "f6" }, 408 { 18, "f7" }, 409 { 19, "f8" }, 410 { 20, "f9" }, 411 { 21, "f10" }, 412 { 23, "f11" }, 413 { 24, "f12" }, 414 }; 415 416 for (size_t i = 0; i < sizeof(esc_num_map) / sizeof(esc_num_map[0]); i++) { 417 if (esc_num_map[i].code == num) return esc_num_map[i].name; 418 } 419 } 420 return NULL; 421 } 422 423 typedef struct { 424 char code; 425 bool needs_tilde; 426 const char *name; 427 } esc_map_t; 428 429 static const esc_map_t esc_map[] = { 430 { 'A', false, "up" }, 431 { 'B', false, "down" }, 432 { 'C', false, "right" }, 433 { 'D', false, "left" }, 434 { 'H', false, "home" }, 435 { 'F', false, "end" }, 436 { 'Z', false, "tab" }, 437 { '2', true, "insert" }, 438 { '3', true, "delete" }, 439 { '5', true, "pageup" }, 440 { '6', true, "pagedown" }, 441 }; 442 443 for (size_t i = 0; i < sizeof(esc_map) / sizeof(esc_map[0]); i++) { 444 if (seq[1] != esc_map[i].code) continue; 445 if (esc_map[i].needs_tilde) { 446 return (len >= 3 && seq[2] == '~') ? esc_map[i].name : NULL; 447 } 448 return esc_map[i].name; 449 } 450 return NULL; 451 } 452 453 if (seq[0] == 'O') { 454 switch (seq[1]) { 455 case 'P': return "f1"; 456 case 'Q': return "f2"; 457 case 'R': return "f3"; 458 case 'S': return "f4"; 459 default: return NULL; 460 } 461 } 462 463 return NULL; 464} 465 466static void emit_keypress_event( 467 ant_t *js, 468 const char *str, 469 size_t str_len, 470 const char *name, 471 bool ctrl, 472 bool meta, 473 bool shift, 474 const char *sequence, 475 size_t sequence_len 476) { 477 ant_value_t str_val = js_mkstr(js, str ? str : "", str ? str_len : 0); 478 ant_value_t key_obj = js_mkobj(js); 479 480 if (name) { 481 js_set(js, key_obj, "name", js_mkstr(js, name, strlen(name))); 482 } else { 483 js_set(js, key_obj, "name", js_mkundef()); 484 } 485 486 js_set(js, key_obj, "ctrl", js_bool(ctrl)); 487 js_set(js, key_obj, "meta", js_bool(meta)); 488 js_set(js, key_obj, "shift", js_bool(shift)); 489 490 if (sequence) { 491 js_set(js, key_obj, "sequence", js_mkstr(js, sequence, sequence_len)); 492 } 493 494 ant_value_t args[2] = { str_val, key_obj }; 495 emit_stdio_event(&stdin_events, "keypress", args, 2); 496} 497 498static void process_keypress_data(ant_t *js, const char *data, size_t len) { 499 for (size_t i = 0; i < len; i++) { 500 unsigned char c = (unsigned char)data[i]; 501 502 if (stdin_state.escape_state == 1) { 503 stdin_state.escape_buf[stdin_state.escape_len++] = (char)c; 504 if (c == '[' || c == 'O') { 505 stdin_state.escape_state = 2; 506 continue; 507 } 508 509 emit_keypress_event(js, "\x1b", 1, "escape", false, false, false, "\x1b", 1); 510 stdin_state.escape_state = 0; 511 stdin_state.escape_len = 0; 512 } 513 514 if (stdin_state.escape_state == 2) { 515 stdin_state.escape_buf[stdin_state.escape_len++] = (char)c; 516 if ((c >= 'A' && c <= 'Z') || c == '~' || stdin_state.escape_len >= 15) { 517 char sequence[18]; 518 size_t seq_len = 0; 519 sequence[seq_len++] = '\x1b'; 520 memcpy(sequence + seq_len, stdin_state.escape_buf, (size_t)stdin_state.escape_len); 521 seq_len += (size_t)stdin_state.escape_len; 522 523 const char *name = stdin_escape_name(stdin_state.escape_buf, stdin_state.escape_len); 524 if (!name) name = "escape"; 525 526 emit_keypress_event(js, "", 0, name, false, false, false, sequence, seq_len); 527 stdin_state.escape_state = 0; 528 stdin_state.escape_len = 0; 529 } 530 continue; 531 } 532 533 if (c == 27) { 534 stdin_state.escape_state = 1; 535 stdin_state.escape_len = 0; 536 continue; 537 } 538 539 if (c == '\r' || c == '\n') { 540 emit_keypress_event(js, "\r", 1, "return", false, false, false, "\r", 1); 541 continue; 542 } 543 544 if (c == 127 || c == 8) { 545 emit_keypress_event(js, "", 0, "backspace", false, false, false, NULL, 0); 546 continue; 547 } 548 549 if (c == '\t') { 550 emit_keypress_event(js, "\t", 1, "tab", false, false, false, "\t", 1); 551 continue; 552 } 553 554 if (c < 32) { 555 char name_buf[2] = { (char)('a' + c - 1), '\0' }; 556 char seq = (char)c; 557 emit_keypress_event(js, &seq, 1, name_buf, true, false, false, &seq, 1); 558 continue; 559 } 560 561 char ch = (char)c; 562 char name_buf[2] = { ch, '\0' }; 563 emit_keypress_event(js, &ch, 1, name_buf, false, false, false, &ch, 1); 564 } 565 566 if (stdin_state.escape_state == 1) { 567 emit_keypress_event(js, "\x1b", 1, "escape", false, false, false, "\x1b", 1); 568 stdin_state.escape_state = 0; 569 stdin_state.escape_len = 0; 570 } 571} 572 573static bool remove_listener_from_events(ProcessEventType **events, const char *event, ant_value_t listener) { 574 ProcessEventType *evt = NULL; 575 HASH_FIND_STR(*events, event, evt); 576 if (!evt) return false; 577 578 for (int i = 0; i < evt->listener_count; i++) { 579 if (evt->listeners[i].listener != listener) continue; 580 memmove( 581 &evt->listeners[i], &evt->listeners[i + 1], 582 (size_t)(evt->listener_count - i - 1) * sizeof(ProcessEventListener) 583 ); 584 585 if (--evt->listener_count == 0) { 586 free_event_type(events, evt); 587 return true; 588 } 589 590 return false; 591 } 592 593 return false; 594} 595 596static bool stdin_is_tty(void) { 597 return uv_guess_handle(STDIN_FILENO) == UV_TTY; 598} 599 600static bool stdout_is_tty(void) { 601 return uv_guess_handle(STDOUT_FILENO) == UV_TTY; 602} 603 604static bool stderr_is_tty(void) { 605 return uv_guess_handle(STDERR_FILENO) == UV_TTY; 606} 607 608static void get_tty_size(int fd, int *rows, int *cols) { 609 int out_rows = 24, out_cols = 80; 610#ifndef _WIN32 611 struct winsize ws; 612 if (ioctl(fd, TIOCGWINSZ, &ws) == 0) { 613 if (ws.ws_row > 0) out_rows = ws.ws_row; 614 if (ws.ws_col > 0) out_cols = ws.ws_col; 615 } 616#else 617 CONSOLE_SCREEN_BUFFER_INFO csbi; 618 if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { 619 int width = csbi.srWindow.Right - csbi.srWindow.Left + 1; 620 int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; 621 if (height > 0) out_rows = height; 622 if (width > 0) out_cols = width; 623 } 624#endif 625 if (rows) *rows = out_rows; 626 if (cols) *cols = out_cols; 627} 628 629static bool stdin_set_raw_mode(bool enable) { 630 if (!stdin_is_tty()) return false; 631 return tty_set_raw_mode(STDIN_FILENO, enable); 632} 633 634static void stdin_alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { 635 (void)handle; 636 buf->base = malloc(suggested_size); 637#ifdef _WIN32 638 buf->len = (ULONG)suggested_size; 639#else 640 buf->len = suggested_size; 641#endif 642} 643 644static void on_stdin_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { 645 (void)stream; 646 if (nread > 0 && rt->js) { 647 ArrayBufferData *ab = create_array_buffer_data((size_t)nread); 648 if (ab) memcpy(ab->data, buf->base, (size_t)nread); 649 ant_value_t raw_val = ab 650 ? create_typed_array(rt->js, TYPED_ARRAY_UINT8, ab, 0, (size_t)nread, "Buffer") 651 : js_mkstr(rt->js, buf->base, (size_t)nread); 652 ant_value_t data_val = is_object_type(stdin_state.decoder) 653 ? string_decoder_decode_value(rt->js, stdin_state.decoder, raw_val, false) 654 : raw_val; 655 if (is_err(data_val)) data_val = raw_val; 656 emit_stdio_event(&stdin_events, "data", &data_val, 1); 657 if (stdin_state.keypress_enabled) process_keypress_data(rt->js, buf->base, (size_t)nread); 658 } 659 if (buf->base) free(buf->base); 660} 661 662static void stdin_start_reading(void) { 663 if (stdin_state.reading) return; 664 if (!stdin_state.tty_initialized) { 665 uv_loop_t *loop = uv_default_loop(); 666 if (uv_tty_init(loop, &stdin_state.tty, STDIN_FILENO, 1) != 0) return; 667 stdin_state.tty.data = NULL; 668 stdin_state.tty_initialized = true; 669 uv_unref((uv_handle_t *)&stdin_state.tty); 670 } 671 uv_ref((uv_handle_t *)&stdin_state.tty); 672 stdin_state.reading = true; 673 uv_read_start((uv_stream_t *)&stdin_state.tty, stdin_alloc_buffer, on_stdin_read); 674} 675 676static void stdin_stop_reading(void) { 677 if (!stdin_state.reading) return; 678 uv_read_stop((uv_stream_t *)&stdin_state.tty); 679 stdin_state.reading = false; 680 uv_unref((uv_handle_t *)&stdin_state.tty); 681} 682 683#ifndef _WIN32 684static void on_sigwinch(uv_signal_t *handle, int signum) { 685 if (!rt->js) return; 686 687 ant_value_t process_obj = js_get(rt->js, js_glob(rt->js), "process"); 688 if (!is_special_object(process_obj)) return; 689 690 ant_value_t stdout_obj = js_get(rt->js, process_obj, "stdout"); 691 if (!is_special_object(stdout_obj)) return; 692 693 emit_stdio_event(&stdout_events, "resize", NULL, 0); 694} 695#endif 696 697static void start_sigwinch_handler(void) { 698#ifndef _WIN32 699 if (sigwinch_initialized) return; 700 uv_loop_t *loop = uv_default_loop(); 701 if (uv_signal_init(loop, &sigwinch_handle) != 0) return; 702 if (uv_signal_start(&sigwinch_handle, on_sigwinch, SIGWINCH) != 0) { 703 uv_close((uv_handle_t *)&sigwinch_handle, NULL); 704 return; 705 } 706 uv_unref((uv_handle_t *)&sigwinch_handle); 707 sigwinch_initialized = true; 708#endif 709} 710 711static ant_value_t js_stdin_set_raw_mode(ant_t *js, ant_value_t *args, int nargs) { 712 bool enable = nargs > 0 ? js_truthy(js, args[0]) : true; 713 return js_bool(stdin_set_raw_mode(enable)); 714} 715 716static ant_value_t js_stdin_set_encoding(ant_t *js, ant_value_t *args, int nargs) { 717 ant_value_t this_obj = js_getthis(js); 718 719 ant_value_t encoding = nargs > 0 && !is_undefined(args[0]) ? args[0] : js_mkstr(js, "utf8", 4); 720 ant_value_t decoder = string_decoder_create(js, encoding); 721 ant_value_t encoding_str = 0; 722 723 if (is_err(decoder)) return decoder; 724 encoding_str = js_tostring_val(js, encoding); 725 if (is_err(encoding_str)) return encoding_str; 726 727 stdin_state.decoder = decoder; 728 js_set(js, this_obj, "encoding", encoding_str); 729 730 return this_obj; 731} 732 733static ant_value_t js_stdin_resume(ant_t *js, ant_value_t *args, int nargs) { 734 (void)args; (void)nargs; 735 stdin_start_reading(); 736 return js_getthis(js); 737} 738 739static ant_value_t js_stdin_pause(ant_t *js, ant_value_t *args, int nargs) { 740 (void)args; (void)nargs; 741 stdin_stop_reading(); 742 return js_getthis(js); 743} 744 745static ant_value_t js_stdin_on(ant_t *js, ant_value_t *args, int nargs) { 746 ant_value_t this_obj = js_getthis(js); 747 if (nargs < 2) return this_obj; 748 749 char *event = js_getstr(js, args[0], NULL); 750 if (!event || vtype(args[1]) != T_FUNC) return this_obj; 751 752 ProcessEventType *evt = find_or_create_event(&stdin_events, event); 753 if (!ensure_listener_capacity(evt)) return this_obj; 754 755 evt->listeners[evt->listener_count].listener = args[1]; 756 evt->listeners[evt->listener_count].once = false; 757 evt->listener_count++; 758 759 if (strcmp(event, "data") == 0) stdin_start_reading(); 760 761 return this_obj; 762} 763 764static ant_value_t js_stdin_remove_all_listeners(ant_t *js, ant_value_t *args, int nargs) { 765 ant_value_t this_obj = js_getthis(js); 766 767 if (nargs < 1) { 768 ProcessEventType *evt, *tmp; 769 HASH_ITER(hh, stdin_events, evt, tmp) { 770 free_event_type(&stdin_events, evt); 771 } 772 stdin_stop_reading(); 773 return this_obj; 774 } 775 776 char *event = js_getstr(js, args[0], NULL); 777 if (!event) return this_obj; 778 779 ProcessEventType *evt = NULL; 780 HASH_FIND_STR(stdin_events, event, evt); 781 if (evt) free_event_type(&stdin_events, evt); 782 if (strcmp(event, "data") == 0) stdin_stop_reading(); 783 784 return this_obj; 785} 786 787static ant_value_t js_stdin_remove_listener(ant_t *js, ant_value_t *args, int nargs) { 788 ant_value_t this_obj = js_getthis(js); 789 if (nargs < 2) return this_obj; 790 791 char *event = js_getstr(js, args[0], NULL); 792 if (!event) return this_obj; 793 794 bool now_empty = remove_listener_from_events(&stdin_events, event, args[1]); 795 if (now_empty && strcmp(event, "data") == 0) stdin_stop_reading(); 796 797 return this_obj; 798} 799 800static ant_value_t process_write_stream(ant_t *js, ant_value_t *args, int nargs, FILE *stream, int fd) { 801 if (nargs < 1) return js_false; 802 803 size_t len = 0; 804 char *data = js_getstr(js, args[0], &len); 805 ant_output_stream_t *out = NULL; 806 807 if (!data) return js_false; 808 if (uv_guess_handle(fd) == UV_TTY) { 809 return js_bool(tty_ctrl_write_fd(fd, data, len)); 810 } 811 812 out = ant_output_stream(stream); 813 ant_output_stream_begin(out); 814 815 if (!ant_output_stream_append(out, data, len)) return js_false; 816 return ant_output_stream_flush(out) ? js_true : js_false; 817} 818 819static ant_value_t js_stdout_write(ant_t *js, ant_value_t *args, int nargs) { 820 return process_write_stream(js, args, nargs, stdout, STDOUT_FILENO); 821} 822 823static ant_value_t js_stdout_on(ant_t *js, ant_value_t *args, int nargs) { 824 ant_value_t this_obj = js_getthis(js); 825 if (nargs < 2) return this_obj; 826 827 char *event = js_getstr(js, args[0], NULL); 828 if (!event || vtype(args[1]) != T_FUNC) return this_obj; 829 830 ProcessEventType *evt = find_or_create_event(&stdout_events, event); 831 if (!ensure_listener_capacity(evt)) return this_obj; 832 833 evt->listeners[evt->listener_count].listener = args[1]; 834 evt->listeners[evt->listener_count].once = false; 835 evt->listener_count++; 836 837 if (strcmp(event, "resize") == 0) start_sigwinch_handler(); 838 839 return this_obj; 840} 841 842static ant_value_t js_stdout_once(ant_t *js, ant_value_t *args, int nargs) { 843 ant_value_t this_obj = js_getthis(js); 844 if (nargs < 2) return this_obj; 845 846 char *event = js_getstr(js, args[0], NULL); 847 if (!event || vtype(args[1]) != T_FUNC) return this_obj; 848 849 ProcessEventType *evt = find_or_create_event(&stdout_events, event); 850 if (!ensure_listener_capacity(evt)) return this_obj; 851 852 evt->listeners[evt->listener_count].listener = args[1]; 853 evt->listeners[evt->listener_count].once = true; 854 evt->listener_count++; 855 856 if (strcmp(event, "resize") == 0) start_sigwinch_handler(); 857 858 return this_obj; 859} 860 861static ant_value_t js_stdout_remove_all_listeners(ant_t *js, ant_value_t *args, int nargs) { 862 ant_value_t this_obj = js_getthis(js); 863 864 if (nargs < 1) { 865 ProcessEventType *evt, *tmp; 866 HASH_ITER(hh, stdout_events, evt, tmp) { 867 free_event_type(&stdout_events, evt); 868 } 869 return this_obj; 870 } 871 872 char *event = js_getstr(js, args[0], NULL); 873 if (!event) return this_obj; 874 875 ProcessEventType *evt = NULL; 876 HASH_FIND_STR(stdout_events, event, evt); 877 if (evt) free_event_type(&stdout_events, evt); 878 879 return this_obj; 880} 881 882static ant_value_t js_stdout_remove_listener(ant_t *js, ant_value_t *args, int nargs) { 883 ant_value_t this_obj = js_getthis(js); 884 if (nargs < 2) return this_obj; 885 886 char *event = js_getstr(js, args[0], NULL); 887 if (!event) return this_obj; 888 889 remove_listener_from_events(&stdout_events, event, args[1]); 890 return this_obj; 891} 892 893static ant_value_t js_stdout_get_window_size(ant_t *js, ant_value_t *args, int nargs) { 894 (void)args; (void)nargs; 895 int rows = 0, cols = 0; 896 get_tty_size(STDOUT_FILENO, &rows, &cols); 897 ant_value_t arr = js_mkarr(js); 898 js_arr_push(js, arr, js_mknum(cols)); 899 js_arr_push(js, arr, js_mknum(rows)); 900 return arr; 901} 902 903static ant_value_t js_stdout_rows_getter(ant_t *js, ant_value_t *args, int nargs) { 904 (void)args; (void)nargs; 905 int rows = 0, cols = 0; 906 get_tty_size(STDOUT_FILENO, &rows, &cols); 907 return js_mknum(rows); 908} 909 910static ant_value_t js_stdout_columns_getter(ant_t *js, ant_value_t *args, int nargs) { 911 int rows = 0, cols = 0; 912 get_tty_size(STDOUT_FILENO, &rows, &cols); 913 return js_mknum(cols); 914} 915 916static ant_value_t js_stderr_write(ant_t *js, ant_value_t *args, int nargs) { 917 return process_write_stream(js, args, nargs, stderr, STDERR_FILENO); 918} 919 920static ant_value_t js_stderr_on(ant_t *js, ant_value_t *args, int nargs) { 921 ant_value_t this_obj = js_getthis(js); 922 if (nargs < 2) return this_obj; 923 924 char *event = js_getstr(js, args[0], NULL); 925 if (!event || vtype(args[1]) != T_FUNC) return this_obj; 926 927 ProcessEventType *evt = find_or_create_event(&stderr_events, event); 928 if (!ensure_listener_capacity(evt)) return this_obj; 929 930 evt->listeners[evt->listener_count].listener = args[1]; 931 evt->listeners[evt->listener_count].once = false; 932 evt->listener_count++; 933 934 return this_obj; 935} 936 937static ant_value_t js_stderr_once(ant_t *js, ant_value_t *args, int nargs) { 938 ant_value_t this_obj = js_getthis(js); 939 if (nargs < 2) return this_obj; 940 941 char *event = js_getstr(js, args[0], NULL); 942 if (!event || vtype(args[1]) != T_FUNC) return this_obj; 943 944 ProcessEventType *evt = find_or_create_event(&stderr_events, event); 945 if (!ensure_listener_capacity(evt)) return this_obj; 946 947 evt->listeners[evt->listener_count].listener = args[1]; 948 evt->listeners[evt->listener_count].once = true; 949 evt->listener_count++; 950 951 return this_obj; 952} 953 954static ant_value_t js_stderr_remove_all_listeners(ant_t *js, ant_value_t *args, int nargs) { 955 ant_value_t this_obj = js_getthis(js); 956 957 if (nargs < 1) { 958 ProcessEventType *evt, *tmp; 959 HASH_ITER(hh, stderr_events, evt, tmp) { 960 free_event_type(&stderr_events, evt); 961 } 962 return this_obj; 963 } 964 965 char *event = js_getstr(js, args[0], NULL); 966 if (!event) return this_obj; 967 968 ProcessEventType *evt = NULL; 969 HASH_FIND_STR(stderr_events, event, evt); 970 if (evt) free_event_type(&stderr_events, evt); 971 972 return this_obj; 973} 974 975static ant_value_t js_stderr_remove_listener(ant_t *js, ant_value_t *args, int nargs) { 976 ant_value_t this_obj = js_getthis(js); 977 if (nargs < 2) return this_obj; 978 979 char *event = js_getstr(js, args[0], NULL); 980 if (!event) return this_obj; 981 982 remove_listener_from_events(&stderr_events, event, args[1]); 983 return this_obj; 984} 985 986static ant_value_t process_uptime(ant_t *js, ant_value_t *args, int nargs) { 987 (void)args; (void)nargs; 988 uint64_t now = uv_hrtime(); 989 double seconds = (double)(now - process_start_time) / 1e9; 990 return js_mknum(seconds); 991} 992 993static ant_value_t process_hrtime(ant_t *js, ant_value_t *args, int nargs) { 994 uint64_t now = uv_hrtime(); 995 996 if (nargs > 0 && vtype(args[0]) == T_ARR) { 997 ant_value_t prev_sec = js_get(js, args[0], "0"); 998 ant_value_t prev_nsec = js_get(js, args[0], "1"); 999 if (vtype(prev_sec) == T_NUM && vtype(prev_nsec) == T_NUM) { 1000 uint64_t prev = (uint64_t)js_getnum(prev_sec) * 1000000000ULL + (uint64_t)js_getnum(prev_nsec); 1001 now = now - prev; 1002 } 1003 } 1004 1005 ant_value_t arr = js_mkarr(js); 1006 1007 uint64_t secs = now / 1000000000ULL; 1008 uint64_t nsecs = now % 1000000000ULL; 1009 1010 js_arr_push(js, arr, js_mknum((double)secs)); 1011 js_arr_push(js, arr, js_mknum((double)nsecs)); 1012 1013 return arr; 1014} 1015 1016static ant_value_t process_hrtime_bigint(ant_t *js, ant_value_t *args, int nargs) { 1017 (void)args; (void)nargs; 1018 uint64_t now = uv_hrtime(); 1019 char buf[32]; 1020 snprintf(buf, sizeof(buf), "%llu", (unsigned long long)now); 1021 return js_mkbigint(js, buf, strlen(buf), false); 1022} 1023 1024static ant_value_t process_memory_usage(ant_t *js, ant_value_t *args, int nargs) { 1025 (void)args; (void)nargs; 1026 ant_value_t obj = js_mkobj(js); 1027 1028 size_t rss = 0; 1029 uv_resident_set_memory(&rss); 1030 js_set(js, obj, "rss", js_mknum((double)rss)); 1031 1032#ifdef _WIN32 1033 PROCESS_MEMORY_COUNTERS_EX pmc; 1034 if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) { 1035 js_set(js, obj, "heapTotal", js_mknum((double)pmc.WorkingSetSize)); 1036 js_set(js, obj, "heapUsed", js_mknum((double)pmc.PrivateUsage)); 1037 } else { 1038 js_set(js, obj, "heapTotal", js_mknum(0)); 1039 js_set(js, obj, "heapUsed", js_mknum(0)); 1040 } 1041#else 1042 struct rusage usage; 1043 if (getrusage(RUSAGE_SELF, &usage) == 0) { 1044 js_set(js, obj, "heapTotal", js_mknum((double)rss)); 1045 js_set(js, obj, "heapUsed", js_mknum((double)rss)); 1046 } else { 1047 js_set(js, obj, "heapTotal", js_mknum(0)); 1048 js_set(js, obj, "heapUsed", js_mknum(0)); 1049 } 1050#endif 1051 1052 js_set(js, obj, "external", js_mknum(0)); 1053 js_set(js, obj, "arrayBuffers", js_mknum(0)); 1054 1055 return obj; 1056} 1057 1058static ant_value_t process_memory_usage_rss(ant_t *js, ant_value_t *args, int nargs) { 1059 (void)args; (void)nargs; 1060 size_t rss = 0; 1061 uv_resident_set_memory(&rss); 1062 return js_mknum((double)rss); 1063} 1064 1065static ant_value_t process_cpu_usage(ant_t *js, ant_value_t *args, int nargs) { 1066 ant_value_t obj = js_mkobj(js); 1067 uv_rusage_t rusage; 1068 1069 if (uv_getrusage(&rusage) == 0) { 1070 int64_t user_usec = rusage.ru_utime.tv_sec * 1000000LL + rusage.ru_utime.tv_usec; 1071 int64_t sys_usec = rusage.ru_stime.tv_sec * 1000000LL + rusage.ru_stime.tv_usec; 1072 1073 if (nargs > 0 && is_special_object(args[0])) { 1074 ant_value_t prev_user = js_get(js, args[0], "user"); 1075 ant_value_t prev_system = js_get(js, args[0], "system"); 1076 if (vtype(prev_user) == T_NUM) user_usec -= (int64_t)js_getnum(prev_user); 1077 if (vtype(prev_system) == T_NUM) sys_usec -= (int64_t)js_getnum(prev_system); 1078 } 1079 1080 js_set(js, obj, "user", js_mknum((double)user_usec)); 1081 js_set(js, obj, "system", js_mknum((double)sys_usec)); 1082 } else { 1083 js_set(js, obj, "user", js_mknum(0)); 1084 js_set(js, obj, "system", js_mknum(0)); 1085 } 1086 1087 return obj; 1088} 1089 1090static ant_value_t process_kill(ant_t *js, ant_value_t *args, int nargs) { 1091 if (nargs < 1) return js_mkerr(js, "process.kill requires at least 1 argument"); 1092 if (vtype(args[0]) != T_NUM) return js_mkerr(js, "pid must be a number"); 1093 1094 int pid = (int)js_getnum(args[0]); 1095 int sig = SIGTERM; 1096 1097 if (nargs > 1) { 1098 if (vtype(args[1]) == T_NUM) { 1099 sig = (int)js_getnum(args[1]); 1100 } else if (vtype(args[1]) == T_STR) { 1101 char *sig_name = js_getstr(js, args[1], NULL); 1102 if (sig_name) { 1103 int signum = get_signal_number(sig_name); 1104 if (signum > 0) sig = signum; 1105 else return js_mkerr(js, "Unknown signal"); 1106 } 1107 } 1108 } 1109 1110 int result = uv_kill(pid, sig); 1111 if (result != 0) return js_mkerr(js, "Failed to send signal"); 1112 return js_true; 1113} 1114 1115static ant_value_t process_abort(ant_params_t) { 1116 abort(); 1117 return js_mkundef(); 1118} 1119 1120static ant_value_t process_chdir(ant_t *js, ant_value_t *args, int nargs) { 1121 if (nargs < 1) return js_mkerr(js, "process.chdir requires 1 argument"); 1122 1123 char *dir = js_getstr(js, args[0], NULL); 1124 if (!dir) return js_mkerr(js, "directory must be a string"); 1125 1126 int result = uv_chdir(dir); 1127 if (result != 0) return js_mkerr(js, "ENOENT: no such file or directory, chdir"); 1128 return js_mkundef(); 1129} 1130 1131static ant_value_t process_umask(ant_t *js, ant_value_t *args, int nargs) { 1132#ifdef _WIN32 1133 (void)args; (void)nargs; 1134 return js_mknum(0); 1135#else 1136 if (nargs > 0 && vtype(args[0]) == T_NUM) { 1137 int new_mask = (int)js_getnum(args[0]); 1138 int old_mask = umask((mode_t)new_mask); 1139 return js_mknum(old_mask); 1140 } 1141 int cur = umask(0); 1142 umask((mode_t)cur); 1143 return js_mknum(cur); 1144#endif 1145} 1146 1147#ifndef _WIN32 1148static ant_value_t process_getuid(ant_t *js, ant_value_t *args, int nargs) { 1149 (void)args; (void)nargs; 1150 return js_mknum((double)getuid()); 1151} 1152 1153static ant_value_t process_geteuid(ant_t *js, ant_value_t *args, int nargs) { 1154 (void)args; (void)nargs; 1155 return js_mknum((double)geteuid()); 1156} 1157 1158static ant_value_t process_getgid(ant_t *js, ant_value_t *args, int nargs) { 1159 (void)args; (void)nargs; 1160 return js_mknum((double)getgid()); 1161} 1162 1163static ant_value_t process_getegid(ant_t *js, ant_value_t *args, int nargs) { 1164 (void)args; (void)nargs; 1165 return js_mknum((double)getegid()); 1166} 1167 1168static ant_value_t process_getgroups(ant_t *js, ant_value_t *args, int nargs) { 1169 (void)args; (void)nargs; 1170 int ngroups = getgroups(0, NULL); 1171 if (ngroups < 0) return js_mkarr(js); 1172 1173 gid_t *groups = malloc(sizeof(gid_t) * (size_t)ngroups); 1174 if (!groups) return js_mkarr(js); 1175 1176 ngroups = getgroups(ngroups, groups); 1177 ant_value_t arr = js_mkarr(js); 1178 for (int i = 0; i < ngroups; i++) { 1179 js_arr_push(js, arr, js_mknum((double)groups[i])); 1180 } 1181 free(groups); 1182 return arr; 1183} 1184 1185static ant_value_t process_setuid(ant_t *js, ant_value_t *args, int nargs) { 1186 if (nargs < 1) return js_mkerr(js, "process.setuid requires 1 argument"); 1187 1188 uid_t uid; 1189 if (vtype(args[0]) == T_NUM) { 1190 uid = (uid_t)js_getnum(args[0]); 1191 } else if (vtype(args[0]) == T_STR) { 1192 char *name = js_getstr(js, args[0], NULL); 1193 struct passwd *pwd = getpwnam(name); 1194 if (!pwd) return js_mkerr(js, "setuid user not found"); 1195 uid = pwd->pw_uid; 1196 } else { 1197 return js_mkerr(js, "uid must be a number or string"); 1198 } 1199 1200 if (setuid(uid) != 0) return js_mkerr(js, "setuid failed"); 1201 return js_mkundef(); 1202} 1203 1204static ant_value_t process_setgid(ant_t *js, ant_value_t *args, int nargs) { 1205 if (nargs < 1) return js_mkerr(js, "process.setgid requires 1 argument"); 1206 1207 gid_t gid; 1208 if (vtype(args[0]) == T_NUM) { 1209 gid = (gid_t)js_getnum(args[0]); 1210 } else if (vtype(args[0]) == T_STR) { 1211 char *name = js_getstr(js, args[0], NULL); 1212 struct group *grp = getgrnam(name); 1213 if (!grp) return js_mkerr(js, "setgid group not found"); 1214 gid = grp->gr_gid; 1215 } else { 1216 return js_mkerr(js, "gid must be a number or string"); 1217 } 1218 1219 if (setgid(gid) != 0) return js_mkerr(js, "setgid failed"); 1220 return js_mkundef(); 1221} 1222 1223static ant_value_t process_seteuid(ant_t *js, ant_value_t *args, int nargs) { 1224 if (nargs < 1) return js_mkerr(js, "process.seteuid requires 1 argument"); 1225 1226 uid_t uid; 1227 if (vtype(args[0]) == T_NUM) { 1228 uid = (uid_t)js_getnum(args[0]); 1229 } else if (vtype(args[0]) == T_STR) { 1230 char *name = js_getstr(js, args[0], NULL); 1231 struct passwd *pwd = getpwnam(name); 1232 if (!pwd) return js_mkerr(js, "seteuid user not found"); 1233 uid = pwd->pw_uid; 1234 } else { 1235 return js_mkerr(js, "uid must be a number or string"); 1236 } 1237 1238 if (seteuid(uid) != 0) return js_mkerr(js, "seteuid failed"); 1239 return js_mkundef(); 1240} 1241 1242static ant_value_t process_setegid(ant_t *js, ant_value_t *args, int nargs) { 1243 if (nargs < 1) return js_mkerr(js, "process.setegid requires 1 argument"); 1244 1245 gid_t gid; 1246 if (vtype(args[0]) == T_NUM) { 1247 gid = (gid_t)js_getnum(args[0]); 1248 } else if (vtype(args[0]) == T_STR) { 1249 char *name = js_getstr(js, args[0], NULL); 1250 struct group *grp = getgrnam(name); 1251 if (!grp) return js_mkerr(js, "setegid group not found"); 1252 gid = grp->gr_gid; 1253 } else { 1254 return js_mkerr(js, "gid must be a number or string"); 1255 } 1256 1257 if (setegid(gid) != 0) return js_mkerr(js, "setegid failed"); 1258 return js_mkundef(); 1259} 1260 1261static ant_value_t process_setgroups(ant_t *js, ant_value_t *args, int nargs) { 1262 if (nargs < 1 || vtype(args[0]) != T_ARR) { 1263 return js_mkerr(js, "process.setgroups requires an array"); 1264 } 1265 1266 ant_value_t len_val = js_get(js, args[0], "length"); 1267 int len = (int)js_getnum(len_val); 1268 1269 gid_t *groups = malloc(sizeof(gid_t) * (size_t)len); 1270 if (!groups) return js_mkerr(js, "allocation failed"); 1271 1272 for (int i = 0; i < len; i++) { 1273 char idx[16]; 1274 snprintf(idx, sizeof(idx), "%d", i); 1275 ant_value_t val = js_get(js, args[0], idx); 1276 if (vtype(val) == T_NUM) { 1277 groups[i] = (gid_t)js_getnum(val); 1278 } else if (vtype(val) == T_STR) { 1279 char *name = js_getstr(js, val, NULL); 1280 struct group *grp = getgrnam(name); 1281 if (!grp) { free(groups); return js_mkerr(js, "group not found"); } 1282 groups[i] = grp->gr_gid; 1283 } else { 1284 free(groups); 1285 return js_mkerr(js, "group id must be number or string"); 1286 } 1287 } 1288 1289 if (setgroups(len, groups) != 0) { 1290 free(groups); 1291 return js_mkerr(js, "setgroups failed"); 1292 } 1293 free(groups); 1294 return js_mkundef(); 1295} 1296 1297static ant_value_t process_initgroups(ant_t *js, ant_value_t *args, int nargs) { 1298 if (nargs < 2) return js_mkerr(js, "process.initgroups requires 2 arguments"); 1299 1300 char *user = js_getstr(js, args[0], NULL); 1301 if (!user) return js_mkerr(js, "user must be a string"); 1302 1303 gid_t gid; 1304 if (vtype(args[1]) == T_NUM) { 1305 gid = (gid_t)js_getnum(args[1]); 1306 } else if (vtype(args[1]) == T_STR) { 1307 char *name = js_getstr(js, args[1], NULL); 1308 struct group *grp = getgrnam(name); 1309 if (!grp) return js_mkerr(js, "group not found"); 1310 gid = grp->gr_gid; 1311 } else { 1312 return js_mkerr(js, "gid must be a number or string"); 1313 } 1314 1315 if (initgroups(user, gid) != 0) return js_mkerr(js, "initgroups failed"); 1316 return js_mkundef(); 1317} 1318#endif 1319 1320static ant_value_t env_getter(ant_t *js, ant_value_t obj, const char *key, size_t key_len) { 1321 CSTR_BUF(buf, 256); 1322 char *key_str = CSTR_INIT(buf, key, key_len); 1323 if (!key_str) return js_mkundef(); 1324 1325 char *value = getenv(key_str); 1326 cstr_free(&buf); 1327 1328 if (value == NULL) return js_mkundef(); 1329 return js_mkstr(js, value, strlen(value)); 1330} 1331 1332static bool env_setter(ant_t *js, ant_value_t obj, const char *key, size_t key_len, ant_value_t value) { 1333 ant_value_t str_val = coerce_to_str(js, value); 1334 if (is_err(str_val)) return false; 1335 setprop_cstr(js, obj, key, key_len, str_val); 1336 1337 CSTR_BUF(buf, 256); 1338 char *key_str = CSTR_INIT(buf, key, key_len); 1339 if (key_str) { 1340 size_t val_len; 1341 char *val_str = js_getstr(js, str_val, &val_len); 1342 if (val_str) setenv(key_str, val_str, 1); 1343 cstr_free(&buf); 1344 } 1345 1346 return true; 1347} 1348 1349static bool env_deleter(ant_t *js, ant_value_t obj, const char *key, size_t key_len) { 1350 CSTR_BUF(buf, 256); 1351 char *key_str = CSTR_INIT(buf, key, key_len); 1352 if (key_str) { unsetenv(key_str); cstr_free(&buf); } 1353 return true; 1354} 1355 1356static void load_dotenv_file(ant_t *js, ant_value_t env_obj) { 1357 FILE *fp = fopen(".env", "r"); 1358 if (fp == NULL) return; 1359 1360 char line[1024]; 1361 while (fgets(line, sizeof(line), fp) != NULL) { 1362 size_t len = strlen(line); 1363 if (len > 0 && line[len - 1] == '\n') { 1364 line[len - 1] = '\0'; 1365 len--; 1366 } 1367 if (len > 0 && line[len - 1] == '\r') { 1368 line[len - 1] = '\0'; 1369 len--; 1370 } 1371 1372 if (len == 0 || line[0] == '#') continue; 1373 char *equals = strchr(line, '='); 1374 if (equals == NULL) continue; 1375 1376 *equals = '\0'; 1377 char *key = line; 1378 char *value = equals + 1; 1379 1380 while (*key == ' ' || *key == '\t') key++; 1381 char *key_end = key + strlen(key) - 1; 1382 while (key_end > key && (*key_end == ' ' || *key_end == '\t')) { 1383 *key_end = '\0'; 1384 key_end--; 1385 } 1386 1387 while (*value == ' ' || *value == '\t') value++; 1388 char *value_end = value + strlen(value) - 1; 1389 while (value_end > value && (*value_end == ' ' || *value_end == '\t')) { 1390 *value_end = '\0'; 1391 value_end--; 1392 } 1393 1394 if (strlen(value) >= 2 && 1395 ((value[0] == '"' && value[strlen(value) - 1] == '"') 1396 || (value[0] == '\'' && value[strlen(value) - 1] == '\''))) { 1397 value[strlen(value) - 1] = '\0'; 1398 value++; 1399 } 1400 1401 js_set(js, env_obj, key, js_mkstr(js, value, strlen(value))); 1402 } 1403 1404 fclose(fp); 1405} 1406 1407static ant_value_t process_exit(ant_t *js, ant_value_t *args, int nargs) { 1408 int code = 0; 1409 1410 if (nargs > 0 && vtype(args[0]) == T_NUM) { 1411 code = (int)js_getnum(args[0]); 1412 } 1413 1414 exit(code); 1415 return js_mkundef(); 1416} 1417 1418typedef struct { 1419 char *buf; 1420 size_t pos; 1421 size_t cap; 1422} env_str_ctx; 1423 1424typedef void (*env_iter_cb)( 1425 ant_t *js, 1426 const char *key, 1427 size_t key_len, 1428 const char *value, 1429 size_t val_len, 1430 void *ctx 1431); 1432 1433static void env_foreach(ant_t *js, ant_value_t env_obj, env_iter_cb cb, void *ctx) { 1434 for (char **env = environ; *env != NULL; env++) { 1435 char *entry = *env; 1436 char *equals = strchr(entry, '='); 1437 if (equals == NULL) continue; 1438 1439 size_t key_len = (size_t)(equals - entry); 1440 char *value = equals + 1; 1441 cb(js, entry, key_len, value, strlen(value), ctx); 1442 } 1443 1444 ant_iter_t iter = js_prop_iter_begin(js, env_obj); 1445 const char *key; size_t key_len; ant_value_t value; 1446 1447 while (js_prop_iter_next(&iter, &key, &key_len, &value)) { 1448 if (vtype(value) != T_STR) continue; 1449 1450 CSTR_BUF(buf, 256); 1451 char *key_str = CSTR_INIT(buf, key, key_len); 1452 if (!key_str) continue; 1453 1454 if (getenv(key_str)) { 1455 cstr_free(&buf); 1456 continue; 1457 } cstr_free(&buf); 1458 1459 size_t val_len; 1460 char *val_str = js_getstr(js, value, &val_len); 1461 cb(js, key, key_len, val_str ? val_str : "", val_str ? val_len : 0, ctx); 1462 } 1463 1464 js_prop_iter_end(&iter); 1465} 1466 1467static void env_to_object_cb(ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx) { 1468 ant_value_t obj = *(ant_value_t *)ctx; 1469 CSTR_BUF(buf, 256); 1470 char *key_str = CSTR_INIT(buf, key, key_len); 1471 if (!key_str) return; 1472 js_set(js, obj, key_str, js_mkstr(js, value, val_len)); 1473 cstr_free(&buf); 1474} 1475 1476static ant_value_t env_to_object(ant_t *js, ant_value_t *args, int nargs) { 1477 ant_value_t obj = js_mkobj(js); 1478 env_foreach(js, js->this_val, env_to_object_cb, &obj); 1479 return obj; 1480} 1481 1482static void env_tostring_cb(ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx) { 1483 env_str_ctx *c = ctx; 1484 size_t entry_len = key_len + 1 + val_len; 1485 1486 if (c->pos + entry_len + 2 >= c->cap) { 1487 size_t new_cap = c->cap * 2 + entry_len; 1488 char *new_buf = realloc(c->buf, new_cap); 1489 if (!new_buf) return; 1490 c->buf = new_buf; 1491 c->cap = new_cap; 1492 } 1493 1494 if (c->pos > 0) c->buf[c->pos++] = '\n'; 1495 memcpy(c->buf + c->pos, key, key_len); 1496 c->pos += key_len; 1497 c->buf[c->pos++] = '='; 1498 memcpy(c->buf + c->pos, value, val_len); 1499 c->pos += val_len; 1500} 1501 1502static ant_value_t env_toString(ant_t *js, ant_value_t *args, int nargs) { 1503 env_str_ctx ctx = { .buf = malloc(4096), .pos = 0, .cap = 4096 }; 1504 if (!ctx.buf) return js_mkstr(js, "", 0); 1505 1506 env_foreach(js, js->this_val, env_tostring_cb, &ctx); 1507 ctx.buf[ctx.pos] = '\0'; 1508 1509 ant_value_t ret = js_mkstr(js, ctx.buf, ctx.pos); 1510 free(ctx.buf); 1511 return ret; 1512} 1513 1514static void env_keys_cb(ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx) { 1515 ant_value_t arr = *(ant_value_t *)ctx; 1516 js_arr_push(js, arr, js_mkstr(js, key, key_len)); 1517} 1518 1519static ant_value_t env_keys(ant_t *js, ant_value_t obj) { 1520 ant_value_t arr = js_mkarr(js); 1521 env_foreach(js, obj, env_keys_cb, &arr); 1522 return arr; 1523} 1524 1525static ant_value_t process_cwd(ant_t *js, ant_value_t *args, int nargs) { 1526 char cwd[4096]; 1527 if (getcwd(cwd, sizeof(cwd)) != NULL) { 1528 return js_mkstr(js, cwd, strlen(cwd)); 1529 } 1530 return js_mkundef(); 1531} 1532 1533static ant_value_t process_add(ant_t *js, ant_value_t *args, int nargs, bool once, bool prepend) { 1534 if (nargs < 2) { 1535 return js_mkerr(js, once ? "process.once requires 2 arguments" : "process.on requires 2 arguments"); 1536 } 1537 1538 char *event = js_getstr(js, args[0], NULL); 1539 if (!event) return js_mkerr(js, "event must be a string"); 1540 1541 uint8_t listener_type = vtype(args[1]); 1542 if (listener_type != T_FUNC && listener_type != T_CFUNC) { 1543 return js_mkerr(js, "listener must be a function"); 1544 } 1545 1546 int signum = get_signal_number(event); 1547 if (signum > 0) start_signal_watch(signum); 1548 1549 ProcessEventType *evt = find_or_create_event(&process_events, event); 1550 if (!ensure_listener_capacity(evt)) return js_mkerr(js, "failed to allocate listener"); 1551 1552 if (prepend && evt->listener_count > 0) { 1553 memmove( 1554 &evt->listeners[1], 1555 &evt->listeners[0], 1556 (size_t)evt->listener_count * sizeof(ProcessEventListener) 1557 ); 1558 evt->listeners[0].listener = args[1]; 1559 evt->listeners[0].once = once; 1560 } else { 1561 evt->listeners[evt->listener_count].listener = args[1]; 1562 evt->listeners[evt->listener_count].once = once; 1563 } 1564 1565 evt->listener_count++; 1566 check_listener_warning(event); 1567 return js_get(js, js_glob(js), "process"); 1568} 1569 1570static ant_value_t process_on(ant_t *js, ant_value_t *args, int nargs) { 1571 return process_add(js, args, nargs, false, false); 1572} 1573 1574static ant_value_t process_once(ant_t *js, ant_value_t *args, int nargs) { 1575 return process_add(js, args, nargs, true, false); 1576} 1577 1578static ant_value_t process_prepend_listener(ant_t *js, ant_value_t *args, int nargs) { 1579 return process_add(js, args, nargs, false, true); 1580} 1581 1582static ant_value_t process_prepend_once_listener(ant_t *js, ant_value_t *args, int nargs) { 1583 return process_add(js, args, nargs, true, true); 1584} 1585 1586static ant_value_t process_off(ant_t *js, ant_value_t *args, int nargs) { 1587 ant_value_t process_obj = js_get(js, js_glob(js), "process"); 1588 if (nargs < 2) return process_obj; 1589 1590 char *event = js_getstr(js, args[0], NULL); 1591 if (!event) return process_obj; 1592 1593 ProcessEventType *evt = NULL; 1594 HASH_FIND_STR(process_events, event, evt); 1595 if (!evt) return process_obj; 1596 1597 for (int i = 0; i < evt->listener_count; i++) { 1598 if (evt->listeners[i].listener == args[1]) { 1599 for (int j = i; j < evt->listener_count - 1; j++) { 1600 evt->listeners[j] = evt->listeners[j + 1]; 1601 } evt->listener_count--; 1602 break; 1603 } 1604 } 1605 1606 if (evt->listener_count == 0) { 1607 int signum = get_signal_number(event); 1608 if (signum > 0) stop_signal_watch(signum); 1609 } 1610 1611 return process_obj; 1612} 1613 1614static ant_value_t process_remove_all_listeners(ant_t *js, ant_value_t *args, int nargs) { 1615 ant_value_t process_obj = js_get(js, js_glob(js), "process"); 1616 1617 if (nargs > 0 && vtype(args[0]) == T_STR) { 1618 char *event = js_getstr(js, args[0], NULL); 1619 if (event) { 1620 ProcessEventType *evt = NULL; 1621 HASH_FIND_STR(process_events, event, evt); 1622 if (evt) { 1623 int signum = get_signal_number(event); 1624 if (signum > 0) stop_signal_watch(signum); 1625 free_event_type(&process_events, evt); 1626 } 1627 } 1628 } else { 1629 ProcessEventType *evt, *tmp; 1630 HASH_ITER(hh, process_events, evt, tmp) { 1631 int signum = get_signal_number(evt->event_type); 1632 if (signum > 0) stop_signal_watch(signum); 1633 free_event_type(&process_events, evt); 1634 } 1635 } 1636 1637 return process_obj; 1638} 1639 1640static ant_value_t process_emit(ant_t *js, ant_value_t *args, int nargs) { 1641 if (nargs < 1) return js_false; 1642 1643 char *event = js_getstr(js, args[0], NULL); 1644 if (!event) return js_false; 1645 1646 emit_process_event(event, nargs > 1 ? &args[1] : NULL, nargs - 1); 1647 return js_true; 1648} 1649 1650static bool process_is_error_object(ant_value_t value) { 1651 if (is_err(value)) return true; 1652 return is_object_type(value) && js_get_slot(value, SLOT_ERROR_BRAND) == js_true; 1653} 1654 1655static void process_get_warning_options( 1656 ant_t *js, ant_value_t options, 1657 const char **type, const char **code, const char **detail, 1658 ant_offset_t *detail_len 1659) { 1660 if (!is_object_type(options)) return; 1661 1662 ant_value_t type_val = js_get(js, options, "type"); 1663 ant_value_t code_val = js_get(js, options, "code"); 1664 ant_value_t detail_val = js_get(js, options, "detail"); 1665 1666 if (vtype(type_val) == T_STR) *type = js_getstr(js, type_val, NULL); 1667 if (vtype(code_val) == T_STR) *code = js_getstr(js, code_val, NULL); 1668 if (vtype(detail_val) == T_STR) *detail = (const char *)(uintptr_t)vstr(js, detail_val, detail_len); 1669} 1670 1671static ant_value_t process_make_warning_object( 1672 ant_t *js, const char *type, js_cstr_t msg, const char *code, 1673 const char *detail, ant_offset_t detail_len 1674) { 1675 ant_value_t warning_obj = js_mkobj(js); 1676 js_set_proto_init(warning_obj, js_get_ctor_proto(js, "Error", 5)); 1677 js_set_slot(warning_obj, SLOT_ERROR_BRAND, js_true); 1678 js_set(js, warning_obj, "name", js_mkstr(js, type, strlen(type))); 1679 js_set(js, warning_obj, "message", js_mkstr(js, msg.ptr, msg.len)); 1680 1681 if (code) js_set(js, warning_obj, "code", js_mkstr(js, code, strlen(code))); 1682 if (detail) js_set(js, warning_obj, "detail", js_mkstr(js, detail, detail_len)); 1683 1684 js_capture_stack(js, warning_obj); 1685 return warning_obj; 1686} 1687 1688static ant_value_t process_emit_warning(ant_t *js, ant_value_t *args, int nargs) { 1689 if (nargs < 1) return js_mkundef(); 1690 1691 ant_value_t warning = args[0]; 1692 const char *type = "Warning"; 1693 const char *code = NULL; 1694 const char *detail = NULL; 1695 ant_offset_t detail_len = 0; 1696 1697 if (nargs >= 2) { 1698 if (vtype(args[1]) == T_STR) type = js_getstr(js, args[1], NULL); 1699 else process_get_warning_options(js, args[1], &type, &code, &detail, &detail_len); 1700 } 1701 1702 if (nargs >= 3 && vtype(args[2]) == T_STR) code = js_getstr(js, args[2], NULL); 1703 1704 char msg_buf[512]; 1705 js_cstr_t msg = {0}; 1706 ant_value_t warning_event_arg = warning; 1707 bool is_error = process_is_error_object(warning); 1708 1709 if (is_error) { 1710 ant_value_t warning_obj = js_as_obj(warning); 1711 ant_offset_t prop_len = 0; 1712 const char *name_prop = get_str_prop(js, warning_obj, "name", 4, &prop_len); 1713 if (name_prop) type = name_prop; 1714 1715 const char *message_prop = get_str_prop(js, warning_obj, "message", 7, &prop_len); 1716 msg.ptr = message_prop ? message_prop : ""; 1717 msg.len = message_prop ? prop_len : 0; 1718 msg.needs_free = false; 1719 1720 code = get_str_prop(js, warning_obj, "code", 4, NULL); 1721 detail = get_str_prop(js, warning_obj, "detail", 6, &detail_len); 1722 warning_event_arg = warning_obj; 1723 } else { 1724 msg = js_to_cstr(js, warning, msg_buf, sizeof(msg_buf)); 1725 warning_event_arg = process_make_warning_object(js, type, msg, code, detail, detail_len); 1726 } 1727 1728 fprintf(stderr, "(%s:%d) ", "ant", (int)getpid()); 1729 if (code) fprintf(stderr, "[%s] ", code); 1730 1731 fprintf(stderr, "%s: %.*s\n", type ? type : "Warning", (int)msg.len, msg.ptr); 1732 if (detail) fprintf(stderr, "%.*s\n", (int)detail_len, detail); 1733 1734 emit_process_event("warning", &warning_event_arg, 1); 1735 if (msg.needs_free) free((void *)msg.ptr); 1736 1737 return js_mkundef(); 1738} 1739 1740static ant_value_t process_listener_count(ant_t *js, ant_value_t *args, int nargs) { 1741 if (nargs < 1) return js_mknum(0); 1742 1743 char *event = js_getstr(js, args[0], NULL); 1744 if (!event) return js_mknum(0); 1745 1746 ProcessEventType *evt = NULL; 1747 HASH_FIND_STR(process_events, event, evt); 1748 1749 return js_mknum(evt ? evt->listener_count : 0); 1750} 1751 1752static ant_value_t process_listeners_impl(ant_t *js, ant_value_t *args, int nargs, bool raw) { 1753 (void)raw; 1754 ant_value_t result = js_mkarr(js); 1755 if (nargs < 1) return result; 1756 1757 char *event = js_getstr(js, args[0], NULL); 1758 if (!event) return result; 1759 1760 ProcessEventType *evt = NULL; 1761 HASH_FIND_STR(process_events, event, evt); 1762 if (!evt) return result; 1763 1764 for (int i = 0; i < evt->listener_count; i++) { 1765 js_arr_push(js, result, evt->listeners[i].listener); 1766 } 1767 1768 return result; 1769} 1770 1771static ant_value_t process_listeners(ant_t *js, ant_value_t *args, int nargs) { 1772 return process_listeners_impl(js, args, nargs, false); 1773} 1774 1775static ant_value_t process_raw_listeners(ant_t *js, ant_value_t *args, int nargs) { 1776 return process_listeners_impl(js, args, nargs, true); 1777} 1778 1779static ant_value_t process_event_names(ant_t *js, ant_value_t *args, int nargs) { 1780 (void)args; 1781 (void)nargs; 1782 ant_value_t result = js_mkarr(js); 1783 ProcessEventType *evt = NULL; 1784 ProcessEventType *tmp = NULL; 1785 1786 HASH_ITER(hh, process_events, evt, tmp) { 1787 if (evt->listener_count > 0) { 1788 js_arr_push(js, result, js_mkstr(js, evt->event_type, strlen(evt->event_type))); 1789 } 1790 } 1791 1792 return result; 1793} 1794 1795static ant_value_t process_set_max_listeners(ant_t *js, ant_value_t *args, int nargs) { 1796 if (nargs < 1) return js_mkerr(js, "setMaxListeners requires 1 argument"); 1797 if (vtype(args[0]) != T_NUM) return js_mkerr(js, "n must be a number"); 1798 1799 int n = (int)js_getnum(args[0]); 1800 if (n < 0) return js_mkerr(js, "n must be non-negative"); 1801 1802 max_listeners = n; 1803 return js_get(js, js_glob(js), "process"); 1804} 1805 1806static ant_value_t process_get_max_listeners(ant_t *js, ant_value_t *args, int nargs) { 1807 return js_mknum(max_listeners); 1808} 1809 1810static ant_value_t process_next_tick(ant_t *js, ant_value_t *args, int nargs) { 1811 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "process.nextTick requires a callback"); 1812 1813 ant_value_t cb = args[0]; 1814 if (vtype(cb) != T_FUNC && vtype(cb) != T_CFUNC) 1815 return js_mkerr_typed(js, JS_ERR_TYPE, "process.nextTick callback is not a function"); 1816 1817 if (nargs <= 1) queue_next_tick(js, cb); 1818 else queue_next_tick_with_args(js, cb, args + 1, nargs - 1); 1819 1820 return js_mkundef(); 1821} 1822 1823static void process_set_methods(ant_t *js, ant_value_t obj, bool include_event_methods) { 1824 js_set(js, obj, "exit", js_mkfun(process_exit)); 1825 js_set(js, obj, "cwd", js_mkfun(process_cwd)); 1826 js_set(js, obj, "chdir", js_mkfun(process_chdir)); 1827 js_set(js, obj, "uptime", js_mkfun(process_uptime)); 1828 js_set(js, obj, "cpuUsage", js_mkfun(process_cpu_usage)); 1829 js_set(js, obj, "kill", js_mkfun(process_kill)); 1830 js_set(js, obj, "abort", js_mkfun(process_abort)); 1831 js_set(js, obj, "umask", js_mkfun(process_umask)); 1832 js_set(js, obj, "nextTick", js_mkfun(process_next_tick)); 1833 js_set(js, obj, "emitWarning", js_mkfun(process_emit_warning)); 1834 js_set(js, obj, "dlopen", js_mkfun(napi_process_dlopen_js)); 1835 1836 ant_value_t mem_usage_fn = js_heavy_mkfun(js, process_memory_usage, js_mkundef()); 1837 js_set(js, mem_usage_fn, "rss", js_mkfun(process_memory_usage_rss)); 1838 js_set(js, obj, "memoryUsage", mem_usage_fn); 1839 1840 ant_value_t hrtime_fn = js_heavy_mkfun(js, process_hrtime, js_mkundef()); 1841 js_set(js, hrtime_fn, "bigint", js_mkfun(process_hrtime_bigint)); 1842 js_set(js, obj, "hrtime", hrtime_fn); 1843 1844 if (include_event_methods) { 1845 js_set(js, obj, "on", js_mkfun(process_on)); 1846 js_set_exact(js, obj, "addListener", js_get(js, obj, "on")); 1847 js_set(js, obj, "once", js_mkfun(process_once)); 1848 js_set(js, obj, "prependListener", js_mkfun(process_prepend_listener)); 1849 js_set(js, obj, "prependOnceListener", js_mkfun(process_prepend_once_listener)); 1850 js_set(js, obj, "off", js_mkfun(process_off)); 1851 js_set_exact(js, obj, "removeListener", js_get(js, obj, "off")); 1852 js_set(js, obj, "removeAllListeners", js_mkfun(process_remove_all_listeners)); 1853 js_set(js, obj, "emit", js_mkfun(process_emit)); 1854 js_set(js, obj, "listenerCount", js_mkfun(process_listener_count)); 1855 js_set(js, obj, "listeners", js_mkfun(process_listeners)); 1856 js_set(js, obj, "rawListeners", js_mkfun(process_raw_listeners)); 1857 js_set(js, obj, "eventNames", js_mkfun(process_event_names)); 1858 js_set(js, obj, "setMaxListeners", js_mkfun(process_set_max_listeners)); 1859 js_set(js, obj, "getMaxListeners", js_mkfun(process_get_max_listeners)); 1860 } 1861 1862#ifndef _WIN32 1863 js_set(js, obj, "getuid", js_mkfun(process_getuid)); 1864 js_set(js, obj, "geteuid", js_mkfun(process_geteuid)); 1865 js_set(js, obj, "getgid", js_mkfun(process_getgid)); 1866 js_set(js, obj, "getegid", js_mkfun(process_getegid)); 1867 js_set(js, obj, "getgroups", js_mkfun(process_getgroups)); 1868 js_set(js, obj, "setuid", js_mkfun(process_setuid)); 1869 js_set(js, obj, "setgid", js_mkfun(process_setgid)); 1870 js_set(js, obj, "seteuid", js_mkfun(process_seteuid)); 1871 js_set(js, obj, "setegid", js_mkfun(process_setegid)); 1872 js_set(js, obj, "setgroups", js_mkfun(process_setgroups)); 1873 js_set(js, obj, "initgroups", js_mkfun(process_initgroups)); 1874#endif 1875} 1876 1877ant_value_t process_library(ant_t *js) { 1878 ant_value_t process_obj = js_get(js, js_glob(js), "process"); 1879 js_set(js, process_obj, "default", process_obj); 1880 js_set_slot_wb(js, process_obj, SLOT_DEFAULT, process_obj); 1881 return process_obj; 1882} 1883 1884void init_process_module() { 1885 ant_t *js = rt->js; 1886 ant_value_t global = js_glob(js); 1887 1888 stdin_state.decoder = js_mkundef(); 1889 process_start_time = uv_hrtime(); 1890 ant_value_t process_proto = js_mkobj(js); 1891 1892 process_set_methods(js, process_proto, true); 1893 js_set_sym(js, process_proto, get_toStringTag_sym(), js_mkstr(js, "process", 7)); 1894 1895 ant_value_t process_obj = js_mkobj(js); 1896 ant_value_t env_obj = js_mkobj(js); 1897 1898 js_set_proto_init(process_obj, process_proto); 1899 process_set_methods(js, process_obj, false); 1900 1901 load_dotenv_file(js, env_obj); 1902 js_set_keys(env_obj, env_keys); 1903 1904 js_set_getter(env_obj, env_getter); 1905 js_set_setter(env_obj, env_setter); 1906 js_set_deleter(env_obj, env_deleter); 1907 1908 js_set(js, env_obj, "toObject", js_mkfun(env_to_object)); 1909 js_set(js, env_obj, "toString", js_mkfun(env_toString)); 1910 js_set(js, process_obj, "env", env_obj); 1911 1912 ant_value_t argv_arr = js_mkarr(js); 1913 for (int i = 0; i < rt->argc; i++) { 1914 js_arr_push(js, argv_arr, js_mkstr(js, rt->argv[i], strlen(rt->argv[i]))); 1915 } 1916 1917 js_set(js, process_obj, "argv", argv_arr); 1918 js_set(js, process_obj, "execArgv", js_mkarr(js)); 1919 js_set(js, process_obj, "argv0", rt->argc > 0 ? js_mkstr(js, rt->argv[0], strlen(rt->argv[0])) : js_mkstr(js, "ant", 3)); 1920 js_set(js, process_obj, "execPath", rt->argc > 0 ? js_mkstr(js, rt->argv[0], strlen(rt->argv[0])) : js_mkundef()); 1921 1922 js_set(js, process_obj, "pid", js_mknum((double)getpid())); 1923 js_set(js, process_obj, "ppid", js_mknum((double)getppid())); 1924 1925 ant_value_t versions_obj = js_mkobj(js); 1926 js_set(js, versions_obj, "ant", js_mkstr(js, ANT_VERSION, strlen(ANT_VERSION))); 1927 char uv_ver[32]; 1928 snprintf(uv_ver, sizeof(uv_ver), "%d.%d.%d", UV_VERSION_MAJOR, UV_VERSION_MINOR, UV_VERSION_PATCH); 1929 js_set(js, versions_obj, "uv", js_mkstr(js, uv_ver, strlen(uv_ver))); 1930 js_set(js, process_obj, "versions", versions_obj); 1931 1932 ant_value_t release_obj = js_mkobj(js); 1933 js_set(js, release_obj, "name", js_mkstr(js, "ant", 3)); 1934 js_set(js, process_obj, "release", release_obj); 1935 1936 // process.platform 1937 #if defined(__APPLE__) 1938 js_set(js, process_obj, "platform", js_mkstr(js, "darwin", 6)); 1939 #elif defined(__linux__) 1940 js_set(js, process_obj, "platform", js_mkstr(js, "linux", 5)); 1941 #elif defined(_WIN32) || defined(_WIN64) 1942 js_set(js, process_obj, "platform", js_mkstr(js, "win32", 5)); 1943 #elif defined(__FreeBSD__) 1944 js_set(js, process_obj, "platform", js_mkstr(js, "freebsd", 7)); 1945 #else 1946 js_set(js, process_obj, "platform", js_mkstr(js, "unknown", 7)); 1947 #endif 1948 1949 // process.arch 1950 #if defined(__x86_64__) || defined(_M_X64) 1951 js_set(js, process_obj, "arch", js_mkstr(js, "x64", 3)); 1952 #elif defined(__i386__) || defined(_M_IX86) 1953 js_set(js, process_obj, "arch", js_mkstr(js, "ia32", 4)); 1954 #elif defined(__aarch64__) || defined(_M_ARM64) 1955 js_set(js, process_obj, "arch", js_mkstr(js, "arm64", 5)); 1956 #elif defined(__arm__) || defined(_M_ARM) 1957 js_set(js, process_obj, "arch", js_mkstr(js, "arm", 3)); 1958 #else 1959 js_set(js, process_obj, "arch", js_mkstr(js, "unknown", 7)); 1960 #endif 1961 1962 ant_value_t stdin_proto = js_mkobj(js); 1963 js_set(js, stdin_proto, "setRawMode", js_mkfun(js_stdin_set_raw_mode)); 1964 js_set(js, stdin_proto, "setEncoding", js_mkfun(js_stdin_set_encoding)); 1965 js_set(js, stdin_proto, "resume", js_mkfun(js_stdin_resume)); 1966 js_set(js, stdin_proto, "pause", js_mkfun(js_stdin_pause)); 1967 js_set(js, stdin_proto, "on", js_mkfun(js_stdin_on)); 1968 js_set(js, stdin_proto, "off", js_mkfun(js_stdin_remove_listener)); 1969 js_set_exact(js, stdin_proto, "removeListener", js_get(js, stdin_proto, "off")); 1970 js_set(js, stdin_proto, "removeAllListeners", js_mkfun(js_stdin_remove_all_listeners)); 1971 js_set_sym(js, stdin_proto, get_toStringTag_sym(), js_mkstr(js, "ReadStream", 10)); 1972 1973 ant_value_t stdin_obj = js_mkobj(js); 1974 js_set_proto_init(stdin_obj, stdin_proto); 1975 js_set(js, stdin_obj, "isTTY", js_bool(stdin_is_tty())); 1976 js_set(js, stdin_obj, "encoding", js_mkundef()); 1977 js_set(js, process_obj, "stdin", stdin_obj); 1978 1979 ant_value_t stdout_proto = js_mkobj(js); 1980 js_set(js, stdout_proto, "write", js_mkfun(js_stdout_write)); 1981 js_set(js, stdout_proto, "on", js_mkfun(js_stdout_on)); 1982 js_set(js, stdout_proto, "once", js_mkfun(js_stdout_once)); 1983 js_set(js, stdout_proto, "off", js_mkfun(js_stdout_remove_listener)); 1984 js_set_exact(js, stdout_proto, "removeListener", js_get(js, stdout_proto, "off")); 1985 js_set(js, stdout_proto, "removeAllListeners", js_mkfun(js_stdout_remove_all_listeners)); 1986 js_set(js, stdout_proto, "getWindowSize", js_mkfun(js_stdout_get_window_size)); 1987 js_set_sym(js, stdout_proto, get_toStringTag_sym(), js_mkstr(js, "WriteStream", 11)); 1988 1989 ant_value_t stdout_obj = js_mkobj(js); 1990 js_set_proto_init(stdout_obj, stdout_proto); 1991 js_set(js, stdout_obj, "isTTY", js_bool(stdout_is_tty())); 1992 js_set_getter_desc(js, stdout_obj, "rows", 4, js_mkfun(js_stdout_rows_getter), JS_DESC_E | JS_DESC_C); 1993 js_set_getter_desc(js, stdout_obj, "columns", 7, js_mkfun(js_stdout_columns_getter), JS_DESC_E | JS_DESC_C); 1994 js_set(js, process_obj, "stdout", stdout_obj); 1995 1996 ant_value_t stderr_proto = js_mkobj(js); 1997 js_set(js, stderr_proto, "write", js_mkfun(js_stderr_write)); 1998 js_set(js, stderr_proto, "on", js_mkfun(js_stderr_on)); 1999 js_set(js, stderr_proto, "once", js_mkfun(js_stderr_once)); 2000 js_set(js, stderr_proto, "off", js_mkfun(js_stderr_remove_listener)); 2001 js_set_exact(js, stderr_proto, "removeListener", js_get(js, stderr_proto, "off")); 2002 js_set(js, stderr_proto, "removeAllListeners", js_mkfun(js_stderr_remove_all_listeners)); 2003 js_set_sym(js, stderr_proto, get_toStringTag_sym(), js_mkstr(js, "WriteStream", 11)); 2004 2005 ant_value_t stderr_obj = js_mkobj(js); 2006 js_set_proto_init(stderr_obj, stderr_proto); 2007 js_set(js, stderr_obj, "isTTY", js_bool(stderr_is_tty())); 2008 js_set(js, process_obj, "stderr", stderr_obj); 2009 2010 js_set(js, global, "process", process_obj); 2011} 2012 2013 2014bool has_active_stdin(void) { 2015 return stdin_state.reading; 2016} 2017 2018void gc_mark_process(ant_t *js, gc_mark_fn mark) { 2019 ProcessEventType *tables[] = {process_events, stdin_events, stdout_events, stderr_events}; 2020 for (int t = 0; t < 4; t++) { 2021 ProcessEventType *evt, *tmp; 2022 HASH_ITER(hh, tables[t], evt, tmp) 2023 for (int i = 0; i < evt->listener_count; i++) mark(js, evt->listeners[i].listener); 2024 } 2025 if (is_object_type(stdin_state.decoder)) mark(js, stdin_state.decoder); 2026} 2027 2028void process_enable_keypress_events(void) { 2029 stdin_state.keypress_enabled = true; 2030 stdin_state.escape_state = 0; 2031 stdin_state.escape_len = 0; 2032}