Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499#include <compat.h> // IWYU pragma: keep
#include <stdlib.h>#include <stdio.h>#include <string.h>#include <signal.h>#include <stdatomic.h>#include <time.h>#include <uthash.h>#include <uv.h>
#ifdef _WIN32#define WIN32_LEAN_AND_MEAN#include <windows.h>#include <io.h>#include <psapi.h>#define STDIN_FILENO 0#define STDOUT_FILENO 1#define STDERR_FILENO 2#else#include <termios.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/stat.h>#include <grp.h>#include <pwd.h>#endif
#include "ant.h"#include "cfunc.h"#include "errors.h"#include "output.h"#include "utils.h"#include "tty_ctrl.h"#include "internal.h"#include "interrupt.h"#include "descriptors.h"#include "silver/call.h"#include "silver/engine.h"#include "gc/roots.h"#include "gc/modules.h"#include "esm/loader.h"#include "esm/commonjs.h"
#include "modules/events.h"#include "modules/process.h"#include "sandbox/sandbox.h"#include "modules/tty.h"#include "modules/buffer.h"#include "modules/napi.h"#include "modules/worker_threads.h"#include "sync.h"#include "modules/timer.h"#include "modules/fs.h"#include "modules/stream.h"
#ifndef _WIN32extern char **environ;#else#define environ _environ#endif
static constexpr size_t STDIN_FILE_CHUNK = 65536;
typedef struct { uv_signal_t handle; int signum; UT_hash_handle hh;} SignalHandle;
typedef struct { uv_fs_t req; ant_t *js; bool pending; bool detached; char buf[STDIN_FILE_CHUNK];} stdin_file_read_t;
typedef struct { union { uv_handle_t handle; uv_stream_t stream; uv_tty_t tty; uv_pipe_t pipe; uv_tcp_t tcp; } h; stdin_file_read_t *file; uv_handle_type kind; bool opened; bool closed; bool reading; bool eof; bool started; bool read_requested; bool paused; bool refed; bool keypress_enabled; int escape_state; int escape_len; char escape_buf[16];} stdin_state_t;
typedef struct env_entry { char *key; char *value; UT_hash_handle hh;} env_entry_t;
struct ant_process_state { env_entry_t *private_env; bool has_private_env; ant_value_t process_obj; ant_value_t cached_cwd; uint64_t cwd_epoch; ant_value_t stdin_obj; ant_value_t stdout_obj; ant_value_t stderr_obj; SignalHandle *signal_handles;
stdin_state_t stdin_state; uint64_t process_start_time; int32_t exit_code; bool has_exit_code; bool exiting;
stdin_byte_consumer_fn stdin_byte_consumer; stdin_eof_fn stdin_byte_eof;
uint32_t sandbox_terminal_capabilities; uint16_t sandbox_tty_rows; uint16_t sandbox_tty_cols; bool sandbox_terminal_enabled; bool sandbox_color_saved; char *sandbox_no_color; char *sandbox_force_color;
#ifndef _WIN32 uv_signal_t sigwinch_handle; bool sigwinch_initialized; bool sigwinch_closing; bool sigwinch_requested; #endif};
static void private_env_free(env_entry_t **table);static atomic_uint_fast64_t process_cwd_epoch;
uint64_t process_cwd_epoch_get(void) { return atomic_load_explicit(&process_cwd_epoch, memory_order_acquire);}
static ant_process_state_t *process_state(ant_t *js) { if (js->process_state) return js->process_state;
ant_process_state_t *ps = calloc(1, sizeof(*ps)); if (!ps) return NULL;
ps->sandbox_tty_rows = 24; ps->sandbox_tty_cols = 80; ps->cached_cwd = js_mkundef(); ps->stdin_state.refed = true;
js->process_state = ps; return ps;}
typedef struct { const char *name; int signum; UT_hash_handle hh_name; UT_hash_handle hh_num;} SignalEntry;
static SignalEntry *signals_by_name = NULL;static SignalEntry *signals_by_num = NULL;
static uv_once_t signal_map_once = UV_ONCE_INIT;
static void build_signal_map(void) { #define S(sig) { #sig, sig, {0}, {0} } static SignalEntry entries[] = { S(SIGINT), S(SIGILL), S(SIGABRT), S(SIGFPE), S(SIGSEGV), S(SIGTERM), #ifdef SIGHUP S(SIGHUP), #endif #ifdef SIGQUIT S(SIGQUIT), #endif #ifdef SIGTRAP S(SIGTRAP), #endif #ifdef SIGKILL S(SIGKILL), #endif #ifdef SIGBUS S(SIGBUS), #endif #ifdef SIGSYS S(SIGSYS), #endif #ifdef SIGPIPE S(SIGPIPE), #endif #ifdef SIGALRM S(SIGALRM), #endif #ifdef SIGURG S(SIGURG), #endif #ifdef SIGSTOP S(SIGSTOP), #endif #ifdef SIGTSTP S(SIGTSTP), #endif #ifdef SIGCONT S(SIGCONT), #endif #ifdef SIGCHLD S(SIGCHLD), #endif #ifdef SIGTTIN S(SIGTTIN), #endif #ifdef SIGTTOU S(SIGTTOU), #endif #ifdef SIGXCPU S(SIGXCPU), #endif #ifdef SIGXFSZ S(SIGXFSZ), #endif #ifdef SIGVTALRM S(SIGVTALRM), #endif #ifdef SIGPROF S(SIGPROF), #endif #ifdef SIGUSR1 S(SIGUSR1), #endif #ifdef SIGUSR2 S(SIGUSR2), #endif #ifdef SIGEMT S(SIGEMT), #endif #ifdef SIGIO S(SIGIO), #endif #ifdef SIGWINCH S(SIGWINCH), #endif #ifdef SIGINFO S(SIGINFO), #endif #ifdef SIGPWR S(SIGPWR), #endif #ifdef SIGSTKFLT S(SIGSTKFLT), #endif #ifdef SIGPOLL S(SIGPOLL), #endif }; #undef S size_t count = sizeof(entries) / sizeof(entries[0]); for (size_t i = 0; i < count; i++) { SignalEntry *existing = NULL; HASH_ADD_KEYPTR(hh_name, signals_by_name, entries[i].name, strlen(entries[i].name), &entries[i]); HASH_FIND(hh_num, signals_by_num, &entries[i].signum, sizeof(int), existing); if (!existing) HASH_ADD(hh_num, signals_by_num, signum, sizeof(int), &entries[i]); }}
static void init_signal_map(void) { uv_once(&signal_map_once, build_signal_map);}
int process_signal_number(const char *name) { if (!name || name[0] != 'S') return -1; init_signal_map(); SignalEntry *entry = NULL; HASH_FIND(hh_name, signals_by_name, name, strlen(name), entry); return entry ? entry->signum : -1;}
const char *process_signal_name(int signum) { init_signal_map(); SignalEntry *entry = NULL; HASH_FIND(hh_num, signals_by_num, &signum, sizeof(int), entry); return entry ? entry->name : NULL;}
static void uv_signal_handler(uv_signal_t *handle, int signum) { ant_t *js = handle->data; const char *name = process_signal_name(signum); if (name) { ant_value_t sig_arg = js_mkstr(js, name, strlen(name)); emit_process_event(js, name, &sig_arg, 1); }}
static void start_signal_watch(ant_t *js, int signum) { if (js->worker) return; ant_process_state_t *ps = process_state(js); SignalHandle *sh = NULL; if (!ps) return; HASH_FIND_INT(ps->signal_handles, &signum, sh); if (sh) return;
sh = malloc(sizeof(SignalHandle)); sh->signum = signum; uv_signal_init(js->loop, &sh->handle); sh->handle.data = js; uv_signal_start(&sh->handle, uv_signal_handler, signum); uv_unref((uv_handle_t *)&sh->handle); HASH_ADD_INT(ps->signal_handles, signum, sh);}
static void on_signal_handle_close(uv_handle_t *handle) { SignalHandle *sh = (SignalHandle *)handle; free(sh);}
static void stop_signal_watch(ant_t *js, int signum) { ant_process_state_t *ps = process_state(js); SignalHandle *sh = NULL; if (!ps) return; HASH_FIND_INT(ps->signal_handles, &signum, sh); if (!sh) return; HASH_DEL(ps->signal_handles, sh); uv_signal_stop(&sh->handle); uv_close((uv_handle_t *)&sh->handle, on_signal_handle_close);}
void emit_process_event(ant_t *js, const char *event_type, ant_value_t *args, int nargs) { ant_process_state_t *ps = js->process_state; if (!ps || !is_object_type(ps->process_obj)) return; eventemitter_emit_args(js, ps->process_obj, event_type, args, nargs);}
bool process_has_event_listeners(ant_t *js, const char *event_type) { ant_process_state_t *ps = js->process_state; if (!ps || !event_type || !is_object_type(ps->process_obj)) return false; return eventemitter_listener_count(js, ps->process_obj, event_type) > 0;}
bool process_report_uncaught_exception(ant_t *js) { if (!js || !Ant_Exception_Pending(js)) return false;
if (js_is_termination(Ant_Exception_Peek(js))) { js_take_thrown(js, js_mkundef()); return false; }
GC_ROOT_SAVE(root_mark, js); ant_value_t stack = Ant_Exception_Stack(js, Ant_Exception_Peek(js)); ant_value_t reason = js_take_thrown(js, js_mkundef()); GC_ROOT_PIN(js, reason); GC_ROOT_PIN(js, stack);
if (process_has_event_listeners(js, "uncaughtException")) { ant_value_t origin = js_mkstr(js, "uncaughtException", 17); GC_ROOT_PIN(js, origin);
ant_value_t event_args[2] = { reason, origin }; emit_process_event(js, "uncaughtException", event_args, 2);
if (Ant_Exception_Pending(js)) { ant_value_t thrown = js_take_thrown(js, js_mkundef()); if (js->worker) ant_worker_report_uncaught(js, thrown); else if (!js->uncaught_nonfatal) exit(7); }
GC_ROOT_RESTORE(js, root_mark); return true; }
if (js->worker) { ant_worker_report_uncaught(js, reason); GC_ROOT_RESTORE(js, root_mark); return true; }
print_error_value(js, reason, stack, NULL); if (!js->uncaught_nonfatal) process_exit_with(js, EXIT_FAILURE);
GC_ROOT_RESTORE(js, root_mark); return true;}
static const char *stdin_escape_name(const char *seq, int len) { if (len < 2) return NULL;
if (seq[0] == '[') { if (seq[1] >= '0' && seq[1] <= '9') { int num = 0; int idx = 1;
while (idx < len && seq[idx] >= '0' && seq[idx] <= '9') { num = num * 10 + (seq[idx] - '0'); idx++; }
if (idx < len && seq[idx] == '~') { typedef struct { int code; const char *name; } esc_num_map_t;
static const esc_num_map_t esc_num_map[] = { { 1, "home" }, { 2, "insert" }, { 3, "delete" }, { 4, "end" }, { 5, "pageup" }, { 6, "pagedown" }, { 7, "home" }, { 8, "end" }, { 15, "f5" }, { 17, "f6" }, { 18, "f7" }, { 19, "f8" }, { 20, "f9" }, { 21, "f10" }, { 23, "f11" }, { 24, "f12" }, };
for (size_t i = 0; i < sizeof(esc_num_map) / sizeof(esc_num_map[0]); i++) { if (esc_num_map[i].code == num) return esc_num_map[i].name; } } return NULL; }
typedef struct { char code; bool needs_tilde; const char *name; } esc_map_t;
static const esc_map_t esc_map[] = { { 'A', false, "up" }, { 'B', false, "down" }, { 'C', false, "right" }, { 'D', false, "left" }, { 'H', false, "home" }, { 'F', false, "end" }, { 'Z', false, "tab" }, { '2', true, "insert" }, { '3', true, "delete" }, { '5', true, "pageup" }, { '6', true, "pagedown" }, };
for (size_t i = 0; i < sizeof(esc_map) / sizeof(esc_map[0]); i++) { if (seq[1] != esc_map[i].code) continue; if (esc_map[i].needs_tilde) { return (len >= 3 && seq[2] == '~') ? esc_map[i].name : NULL; } return esc_map[i].name; } return NULL; }
if (seq[0] == 'O') { switch (seq[1]) { case 'P': return "f1"; case 'Q': return "f2"; case 'R': return "f3"; case 'S': return "f4"; default: return NULL; } }
return NULL;}
static void emit_keypress_event( ant_t *js, const char *str, size_t str_len, const char *name, bool ctrl, bool meta, bool shift, const char *sequence, size_t sequence_len) { ant_process_state_t *ps = process_state(js); if (!ps) return; ant_value_t str_val = js_mkstr(js, str ? str : "", str ? str_len : 0); ant_value_t key_obj = Ant_Object_CreateBare(js);
if (name) { js_set(js, key_obj, "name", js_mkstr(js, name, strlen(name))); } else { js_set(js, key_obj, "name", js_mkundef()); }
js_set(js, key_obj, "ctrl", js_bool(ctrl)); js_set(js, key_obj, "meta", js_bool(meta)); js_set(js, key_obj, "shift", js_bool(shift));
if (sequence) { js_set(js, key_obj, "sequence", js_mkstr(js, sequence, sequence_len)); }
ant_value_t args[2] = { str_val, key_obj }; eventemitter_emit_args(js, ps->stdin_obj, "keypress", args, 2);}
static void process_keypress_data(ant_t *js, const char *data, size_t len) { ant_process_state_t *ps = process_state(js); if (!ps) return; for (size_t i = 0; i < len; i++) { unsigned char c = (unsigned char)data[i];
if (ps->stdin_state.escape_state == 1) { ps->stdin_state.escape_buf[ps->stdin_state.escape_len++] = (char)c; if (c == '[' || c == 'O') { ps->stdin_state.escape_state = 2; continue; }
emit_keypress_event(js, "\x1b", 1, "escape", false, false, false, "\x1b", 1); ps->stdin_state.escape_state = 0; ps->stdin_state.escape_len = 0; }
if (ps->stdin_state.escape_state == 2) { ps->stdin_state.escape_buf[ps->stdin_state.escape_len++] = (char)c; if ((c >= 'A' && c <= 'Z') || c == '~' || ps->stdin_state.escape_len >= 15) { char sequence[18]; size_t seq_len = 0; sequence[seq_len++] = '\x1b'; memcpy(sequence + seq_len, ps->stdin_state.escape_buf, (size_t)ps->stdin_state.escape_len); seq_len += (size_t)ps->stdin_state.escape_len;
const char *name = stdin_escape_name(ps->stdin_state.escape_buf, ps->stdin_state.escape_len); if (!name) name = "escape";
emit_keypress_event(js, "", 0, name, false, false, false, sequence, seq_len); ps->stdin_state.escape_state = 0; ps->stdin_state.escape_len = 0; } continue; }
if (c == 27) { ps->stdin_state.escape_state = 1; ps->stdin_state.escape_len = 0; continue; }
if (c == '\r' || c == '\n') { emit_keypress_event(js, "\r", 1, "return", false, false, false, "\r", 1); continue; }
if (c == 127 || c == 8) { emit_keypress_event(js, "", 0, "backspace", false, false, false, NULL, 0); continue; }
if (c == '\t') { emit_keypress_event(js, "\t", 1, "tab", false, false, false, "\t", 1); continue; }
if (c < 32) { char name_buf[2] = { (char)('a' + c - 1), '\0' }; char seq = (char)c; emit_keypress_event(js, &seq, 1, name_buf, true, false, false, &seq, 1); continue; }
char ch = (char)c; char name_buf[2] = { ch, '\0' }; emit_keypress_event(js, &ch, 1, name_buf, false, false, false, &ch, 1); }}
static void process_keypress_flush(ant_t *js) { ant_process_state_t *ps = process_state(js); if (!ps) return; if (ps->stdin_state.escape_state == 1) { emit_keypress_event(js, "\x1b", 1, "escape", false, false, false, "\x1b", 1); ps->stdin_state.escape_state = 0; ps->stdin_state.escape_len = 0; }}
static bool stdin_is_tty(void) { return uv_guess_handle(STDIN_FILENO) == UV_TTY;}
static bool stdout_is_tty(ant_t *js) { ant_process_state_t *ps = process_state(js); if (!ps) return false; if (ps->sandbox_terminal_enabled) return (ps->sandbox_terminal_capabilities & ANT_SANDBOX_CAP_STDOUT_TTY) != 0; return uv_guess_handle(STDOUT_FILENO) == UV_TTY;}
static bool stderr_is_tty(ant_t *js) { ant_process_state_t *ps = process_state(js); if (!ps) return false; if (ps->sandbox_terminal_enabled) return (ps->sandbox_terminal_capabilities & ANT_SANDBOX_CAP_STDERR_TTY) != 0; return uv_guess_handle(STDERR_FILENO) == UV_TTY;}
static ant_value_t process_binding(ant_params_t) { const char *name; ant_value_t constants;
if (nargs < 1 || vtype(args[0]) != kTypeString) return js_mkerr_typed(js, JS_ERR_TYPE, "process.binding() requires a module name");
name = js_getstr(js, args[0], NULL); if (!name || strcmp(name, "constants") != 0) return js_mkerr_typed(js, JS_ERR_TYPE, "No such module: %s", name ? name : "");
constants = Ant_Object_CreateBare(js); js_set(js, constants, "fs", fs_make_constants(js)); return constants;}
static void get_tty_size(ant_t *js, int fd, int *rows, int *cols) { ant_process_state_t *ps = process_state(js); int out_rows = 24, out_cols = 80; if (ps && ps->sandbox_terminal_enabled && (fd == STDOUT_FILENO || fd == STDERR_FILENO)) { *rows = ps->sandbox_tty_rows ? ps->sandbox_tty_rows : 24; *cols = ps->sandbox_tty_cols ? ps->sandbox_tty_cols : 80; return; }#ifndef _WIN32 struct winsize ws; if (ioctl(fd, TIOCGWINSZ, &ws) == 0) { if (ws.ws_row > 0) out_rows = ws.ws_row; if (ws.ws_col > 0) out_cols = ws.ws_col; }#else CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { int width = csbi.srWindow.Right - csbi.srWindow.Left + 1; int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; if (height > 0) out_rows = height; if (width > 0) out_cols = width; }#endif if (rows) *rows = out_rows; if (cols) *cols = out_cols;}
static char *env_dup(const char *name) { const char *value = getenv(name); return value ? strdup(value) : NULL;}
static void env_restore(const char *name, const char *saved) { if (saved) setenv(name, saved, 1); else unsetenv(name);}
static void process_update_sandbox_env(ant_t *js) { ant_process_state_t *ps = process_state(js); if (!ps || !ps->sandbox_terminal_enabled) return; if (!ps->sandbox_color_saved) { ps->sandbox_no_color = env_dup("NO_COLOR"); ps->sandbox_force_color = env_dup("FORCE_COLOR"); ps->sandbox_color_saved = true; } env_restore("NO_COLOR", ps->sandbox_no_color); env_restore("FORCE_COLOR", ps->sandbox_force_color);
if (ps->sandbox_terminal_capabilities & ANT_SANDBOX_CAP_COLOR_STRIP) { setenv("NO_COLOR", "1", 1); unsetenv("FORCE_COLOR"); } else if (ps->sandbox_terminal_capabilities & ANT_SANDBOX_CAP_COLOR_FORCE) { unsetenv("NO_COLOR"); setenv("FORCE_COLOR", "1", 1); }}
static ant_value_t process_exec_path(ant_t *js) { char path[PATH_MAX]; if (ant_get_exe_path(path, sizeof(path), js->runtime.argc, js->runtime.argv) == 0 && path[0] != '\0') return js_mkstr(js, path, strlen(path)); if (js->runtime.argc > 0) return js_mkstr(js, js->runtime.argv[0], strlen(js->runtime.argv[0])); return js_mkundef();}
void process_refresh_sandbox_argv(ant_t *js) { ant_value_t process_obj = js_get(js, js_glob(js), "process"); if (!is_special_object(process_obj)) return;
ant_value_t argv_arr = js_mkarr(js); for (int i = 0; i < js->runtime.argc; i++) js_arr_push(js, argv_arr, js_mkstr(js, js->runtime.argv[i], strlen(js->runtime.argv[i])));
js_set(js, process_obj, "argv", argv_arr); js_set(js, process_obj, "argv0", js->runtime.argc > 0 ? js_mkstr(js, js->runtime.argv[0], strlen(js->runtime.argv[0])) : js_mkstr(js, "ant", 3)); js_set(js, process_obj, "execPath", process_exec_path(js));}
void process_set_sandbox_terminal(ant_t *js, uint32_t capabilities, uint16_t rows, uint16_t cols) { ant_process_state_t *ps = process_state(js); if (!ps) return; ps->sandbox_terminal_enabled = true; ps->sandbox_terminal_capabilities = capabilities;
ps->sandbox_tty_rows = rows ? rows : 24; ps->sandbox_tty_cols = cols ? cols : 80;
process_update_sandbox_env(js); ant_value_t process_obj = js_get(js, js_glob(js), "process"); if (!is_special_object(process_obj)) return;
ant_value_t stdout_obj = js_get(js, process_obj, "stdout"); if (is_special_object(stdout_obj)) js_set(js, stdout_obj, "isTTY", js_bool(stdout_is_tty(js)));
ant_value_t stderr_obj = js_get(js, process_obj, "stderr"); if (is_special_object(stderr_obj)) js_set(js, stderr_obj, "isTTY", js_bool(stderr_is_tty(js)));}
static bool stdin_set_raw_mode(bool enable) { if (!stdin_is_tty()) return false; return tty_set_raw_mode(STDIN_FILENO, enable);}
static bool stdin_is_stream_kind(uv_handle_type kind) { return kind == UV_TTY || kind == UV_NAMED_PIPE || kind == UV_TCP;}
static bool stdin_handle_live(stdin_state_t *st) { return st->opened && !st->closed && stdin_is_stream_kind(st->kind);}
static void stdin_alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { buf->base = malloc(suggested_size);#ifdef _WIN32 buf->len = (ULONG)suggested_size;#else buf->len = suggested_size;#endif}
static ant_value_t stdin_uv_error(ant_t *js, int status, const char *syscall) { const char *code = uv_err_name(status); ant_value_t props = Ant_Object_CreateBare(js); js_set(js, props, "code", js_mkstr(js, code, strlen(code))); js_set(js, props, "errno", js_mknum(status)); js_set(js, props, "syscall", js_mkstr(js, syscall, strlen(syscall))); return js_take_thrown(js, js_mkerr_props(js, JS_ERR_GENERIC, props, "%s %s", syscall, code));}
static bool stdin_open(ant_t *js, ant_process_state_t *ps) { stdin_state_t *st = &ps->stdin_state; if (st->opened) return !st->closed;
int rc = UV_EINVAL; st->opened = true; st->kind = uv_guess_handle(STDIN_FILENO);
switch (st->kind) { case UV_TTY: rc = uv_tty_init(js->loop, &st->h.tty, STDIN_FILENO, 1); break; case UV_NAMED_PIPE: rc = uv_pipe_init(js->loop, &st->h.pipe, 0); if (rc == 0 && (rc = uv_pipe_open(&st->h.pipe, STDIN_FILENO)) != 0) uv_close(&st->h.handle, NULL); break; case UV_TCP: rc = uv_tcp_init(js->loop, &st->h.tcp); if (rc == 0 && (rc = uv_tcp_open(&st->h.tcp, (uv_os_sock_t)(uintptr_t)uv_get_osfhandle(STDIN_FILENO))) != 0) uv_close(&st->h.handle, NULL); break; case UV_FILE: st->file = calloc(1, sizeof(*st->file)); rc = st->file ? 0 : UV_ENOMEM; if (st->file) st->file->js = js; break; default: break; }
if (rc != 0) { st->closed = true; return false; }
if (stdin_is_stream_kind(st->kind)) { st->h.handle.data = js; if (!st->refed) uv_unref(&st->h.handle); } return true;}
static void stdin_release_file(stdin_state_t *st) { stdin_file_read_t *file = st->file; if (!file) return; st->file = NULL;
if (!file->pending) { free(file); return; }
file->detached = true; uv_cancel((uv_req_t *)&file->req);}
static void stdin_close(ant_process_state_t *ps) { stdin_state_t *st = &ps->stdin_state; bool live = stdin_handle_live(st);
stdin_release_file(st); if (live && st->reading) uv_read_stop(&st->h.stream); st->reading = false; if (st->opened) st->closed = true; if (live && !uv_is_closing(&st->h.handle)) uv_close(&st->h.handle, NULL);}
static void stdin_finish(ant_t *js, ant_value_t error) { ant_process_state_t *ps = process_state(js); if (!ps || ps->stdin_state.eof) return;
GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, error);
ps->stdin_state.eof = true; ps->stdin_state.read_requested = false; stdin_update_reading(js); if (ps->stdin_byte_eof) ps->stdin_byte_eof(js);
if (is_undefined(error)) stream_readable_push(js, ps->stdin_obj, js_mknull(), js_mkundef()); else stream_destroy(js, ps->stdin_obj, error);
GC_ROOT_RESTORE(js, root_mark);}
static void stdin_deliver(ant_t *js, const char *base, size_t len) { ant_process_state_t *ps = process_state(js); if (!ps) return; stdin_state_t *st = &ps->stdin_state;
if (st->started) { ArrayBufferData *ab = create_array_buffer_data(js, len); if (!ab) { stdin_finish(js, stdin_uv_error(js, UV_ENOMEM, "read")); return; }
memcpy(ab->data, base, len); ant_value_t chunk = create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, len, js->builtins.buffer_proto); if (is_err(chunk)) { stdin_finish(js, js_take_thrown(js, chunk)); return; }
GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, chunk); ant_value_t pushed = stream_readable_push(js, ps->stdin_obj, chunk, js_mkundef()); if (is_err(pushed)) js_take_thrown(js, pushed); else if (pushed == js_false) st->read_requested = false; GC_ROOT_RESTORE(js, root_mark); }
bool want_keypress = st->keypress_enabled && eventemitter_listener_count(js, ps->stdin_obj, "keypress") > 0; bool fed_keypress = false;
for (size_t i = 0; i < len; i++) { if (st->paused) break; if (ps->stdin_byte_consumer) ps->stdin_byte_consumer(js, base + i, 1); if (want_keypress) { process_keypress_data(js, base + i, 1); fed_keypress = true; } } if (fed_keypress && !st->paused) process_keypress_flush(js);}
static void stdin_handle_read(ant_t *js, const char *base, ssize_t nread) { if (nread > 0) { stdin_deliver(js, base, (size_t)nread); stdin_update_reading(js); } else if (nread == UV_EOF) stdin_finish(js, js_mkundef()); else if (nread < 0) stdin_finish(js, stdin_uv_error(js, (int)nread, "read"));}
static void on_stdin_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { ant_t *js = stream->data; if (js) stdin_handle_read(js, buf->base, nread); free(buf->base);}
static void on_stdin_file_read(uv_fs_t *req) { stdin_file_read_t *file = req->data; ssize_t result = req->result; uv_fs_req_cleanup(req); file->pending = false;
if (file->detached) free(file); else stdin_handle_read(file->js, file->buf, result == 0 ? UV_EOF : result);}
static void stdin_file_read_next(ant_t *js) { ant_process_state_t *ps = process_state(js); if (!ps) return; stdin_state_t *st = &ps->stdin_state; stdin_file_read_t *file = st->file; if (!st->reading || !file || file->pending || st->eof) return;
uv_buf_t buf = uv_buf_init(file->buf, (unsigned int)STDIN_FILE_CHUNK); file->req.data = file; int rc = uv_fs_read(js->loop, &file->req, STDIN_FILENO, &buf, 1, -1, on_stdin_file_read); if (rc == 0) file->pending = true; else stdin_finish(js, stdin_uv_error(js, rc, "read"));}
static bool stdin_wants_bytes(ant_t *js, ant_process_state_t *ps) { stdin_state_t *st = &ps->stdin_state; if (st->eof) return false; if (st->read_requested) return true; if (st->paused) return false; if (ps->stdin_byte_consumer) return true; return eventemitter_listener_count(js, ps->stdin_obj, "keypress") > 0;}
void stdin_update_reading(ant_t *js) { if (js->worker) return; ant_process_state_t *ps = process_state(js); if (!ps) return; stdin_state_t *st = &ps->stdin_state; bool want = stdin_wants_bytes(js, ps);
if (!want) { if (st->reading && stdin_handle_live(st)) uv_read_stop(&st->h.stream); st->reading = false; return; }
if (st->reading) { if (st->kind == UV_FILE) stdin_file_read_next(js); return; }
if (!stdin_open(js, ps)) { stdin_finish(js, js_mkundef()); return; }
st->reading = true; if (st->kind == UV_FILE) { stdin_file_read_next(js); return; }
int rc = uv_read_start(&st->h.stream, stdin_alloc_buffer, on_stdin_read); if (rc != 0) { st->reading = false; stdin_finish(js, stdin_uv_error(js, rc, "read")); }}
void process_stdin_attach_reader(ant_t *js, stdin_byte_consumer_fn on_bytes, stdin_eof_fn on_eof) { ant_process_state_t *ps = process_state(js); if (!ps) return; ps->stdin_byte_consumer = on_bytes; ps->stdin_byte_eof = on_eof; ps->stdin_state.paused = false; stdin_update_reading(js);}
void process_stdin_detach_reader(ant_t *js) { ant_process_state_t *ps = process_state(js); if (!ps) return; ps->stdin_byte_consumer = NULL; ps->stdin_byte_eof = NULL; stdin_update_reading(js);}
#ifndef _WIN32static void on_sigwinch(uv_signal_t *handle, int signum) { ant_t *js = handle->data; if (!js) return;
ant_process_state_t *ps = process_state(js); if (!ps) return; ant_value_t process_obj = js_get(js, js_glob(js), "process"); if (!is_special_object(process_obj)) return;
ant_value_t stdout_obj = js_get(js, process_obj, "stdout"); if (!is_special_object(stdout_obj)) return;
eventemitter_emit_args(js, ps->stdout_obj, "resize", NULL, 0);}#endif
static void start_sigwinch_handler(ant_t *js);
#ifndef _WIN32static void on_sigwinch_close(uv_handle_t *handle) { ant_t *js = handle ? (ant_t *)handle->data : NULL; ant_process_state_t *ps = js ? js->process_state : NULL; if (!ps) return;
ps->sigwinch_initialized = false; ps->sigwinch_closing = false; if (ps->sigwinch_requested) start_sigwinch_handler(js);}#endif
static void start_sigwinch_handler(ant_t *js) {#ifndef _WIN32 ant_process_state_t *ps = process_state(js); if (!ps) return; ps->sigwinch_requested = true; if (ps->sigwinch_initialized || ps->sigwinch_closing) return;
uv_loop_t *loop = js->loop; if (uv_signal_init(loop, &ps->sigwinch_handle) != 0) return; ps->sigwinch_initialized = true; ps->sigwinch_handle.data = js; if (uv_signal_start(&ps->sigwinch_handle, on_sigwinch, SIGWINCH) != 0) { ps->sigwinch_requested = false; ps->sigwinch_closing = true; uv_close((uv_handle_t *)&ps->sigwinch_handle, on_sigwinch_close); return; } uv_unref((uv_handle_t *)&ps->sigwinch_handle);#endif}
static void stop_sigwinch_handler(ant_t *js) {#ifndef _WIN32 ant_process_state_t *ps = js ? js->process_state : NULL; if (!ps) return; ps->sigwinch_requested = false; if (!ps->sigwinch_initialized || ps->sigwinch_closing) return;
uv_signal_stop(&ps->sigwinch_handle); ps->sigwinch_closing = true; uv_close((uv_handle_t *)&ps->sigwinch_handle, on_sigwinch_close);#endif}
void cleanup_process_module(ant_t *js) { ant_process_state_t *ps = js->process_state; if (!ps) return;
SignalHandle *sh, *tmp; HASH_ITER(hh, ps->signal_handles, sh, tmp) { HASH_DEL(ps->signal_handles, sh); uv_signal_stop(&sh->handle); uv_close((uv_handle_t *)&sh->handle, on_signal_handle_close); }
stdin_close(ps);
stop_sigwinch_handler(js);}
void free_process_module(ant_t *js) { ant_process_state_t *ps = js->process_state; if (!ps) return; private_env_free(&ps->private_env); stdin_release_file(&ps->stdin_state); free(ps->sandbox_no_color); free(ps->sandbox_force_color); free(ps); js->process_state = NULL;}
static ant_value_t js_stdin_set_raw_mode(ant_params_t) { bool enable = nargs > 0 ? js_truthy(js, args[0]) : true; return js_bool(stdin_set_raw_mode(enable));}
static ant_value_t js_stdin__read(ant_params_t) { ant_process_state_t *ps = process_state(js); if (!ps) return js_mkerr(js, "out of memory"); ps->stdin_state.started = true; ps->stdin_state.read_requested = true; ps->stdin_state.paused = false; stdin_update_reading(js); return js_mkundef();}
static ant_value_t js_stdin__destroy(ant_params_t) { ant_process_state_t *ps = process_state(js); ant_value_t error = nargs > 0 ? args[0] : js_mknull(); ant_value_t callback = nargs > 1 ? args[1] : js_mkundef();
if (ps) { ps->stdin_state.eof = true; ps->stdin_state.read_requested = false; stdin_update_reading(js); stdin_close(ps); }
if (is_callable(callback)) sv_call_value(js, callback, js_mkundef(), &error, 1); return js_mkundef();}
static ant_value_t stdin_set_paused(ant_t *js, bool paused) { ant_process_state_t *ps = process_state(js); if (!ps) return js_mkerr(js, "out of memory");
if (paused) stream_readable_pause(js, ps->stdin_obj); else stream_readable_resume(js, ps->stdin_obj);
ps->stdin_state.paused = paused; if (paused) ps->stdin_state.read_requested = false; stdin_update_reading(js); return ps->stdin_obj;}
static ant_value_t js_stdin_resume(ant_params_t) { return stdin_set_paused(js, false);}
static ant_value_t js_stdin_pause(ant_params_t) { return stdin_set_paused(js, true);}
static ant_value_t js_stdin_ref(ant_params_t) { ant_process_state_t *ps = process_state(js); if (!ps) return js_mkerr(js, "out of memory"); ps->stdin_state.refed = true; if (stdin_handle_live(&ps->stdin_state)) uv_ref(&ps->stdin_state.h.handle); return js_getthis(js);}
static ant_value_t js_stdin_unref(ant_params_t) { ant_process_state_t *ps = process_state(js); if (!ps) return js_mkerr(js, "out of memory"); ps->stdin_state.refed = false; if (stdin_handle_live(&ps->stdin_state)) uv_unref(&ps->stdin_state.h.handle); return js_getthis(js);}
static ant_value_t process_write_stream(ant_native_params_t, FILE *stream, int fd) { if (nargs < 1) return js_false;
size_t len = 0; const char *data = NULL; const uint8_t *bytes = NULL; ant_output_stream_t *out = NULL;
if (buffer_source_get_bytes(js, args[0], &bytes, &len)) data = (const char *)bytes; else data = js_getstr(js, args[0], &len);
if (!data) return js_false; if (!ant_output_has_writer() && uv_guess_handle(fd) == UV_TTY) return js_bool(tty_ctrl_write_fd(fd, data, len));
out = ant_output_stream(stream); ant_output_stream_begin(out);
if (!ant_output_stream_append(out, data, len)) return js_false; return ant_output_stream_flush(out) ? js_true : js_false;}
static ant_value_t js_stdout_write(ant_params_t) { return process_write_stream(js, args, nargs, stdout, STDOUT_FILENO);}
static ant_value_t js_stdout_get_window_size(ant_params_t) { (void)args; (void)nargs; int rows = 0, cols = 0; get_tty_size(js, STDOUT_FILENO, &rows, &cols); ant_value_t arr = js_mkarr(js); js_arr_push(js, arr, js_mknum(cols)); js_arr_push(js, arr, js_mknum(rows)); return arr;}
static ant_value_t js_stdout_rows_getter(ant_params_t) { (void)args; (void)nargs; int rows = 0, cols = 0; get_tty_size(js, STDOUT_FILENO, &rows, &cols); return js_mknum(rows);}
static ant_value_t js_stdout_columns_getter(ant_params_t) { int rows = 0, cols = 0; get_tty_size(js, STDOUT_FILENO, &rows, &cols); return js_mknum(cols);}
static ant_value_t js_stderr_write(ant_params_t) { return process_write_stream(js, args, nargs, stderr, STDERR_FILENO);}
static ant_value_t process_uptime(ant_params_t) { (void)args; (void)nargs; ant_process_state_t *ps = process_state(js); if (!ps) return js_mkerr(js, "out of memory"); uint64_t now = uv_hrtime(); double seconds = (double)(now - ps->process_start_time) / 1e9; return js_mknum(seconds);}
static ant_value_t process_hrtime(ant_params_t) { uint64_t now = uv_hrtime(); if (nargs > 0 && vtype(args[0]) != kTypeUndefined) { bool time_is_array = false; ant_value_t checked = js_is_array_value_checked(js, args[0], &time_is_array); if (is_err(checked)) return checked; if (!time_is_array) return Ant_Error_CreateInvalidArgType(js, "time", "an instance of Array", args[0]); ant_value_t time_len = js_get(js, args[0], "length"); if (is_err(time_len)) return time_len; if (vtype(time_len) != kTypeNumber || js_getnum(time_len) != 2) { char message[96]; snprintf(message, sizeof(message), "The value of \"time\" is out of range. It must be 2. Received %s", js_str(js, time_len)); return js_mkerr_code(js, JS_ERR_RANGE, "ERR_OUT_OF_RANGE", message); } ant_value_t prev_sec = js_get(js, args[0], "0"); ant_value_t prev_nsec = js_get(js, args[0], "1"); if (vtype(prev_sec) == kTypeNumber && vtype(prev_nsec) == kTypeNumber) { uint64_t prev = (uint64_t)js_getnum(prev_sec) * 1000000000ULL + (uint64_t)js_getnum(prev_nsec); now = now - prev; } } ant_value_t arr = js_mkarr(js); uint64_t secs = now / 1000000000ULL; uint64_t nsecs = now % 1000000000ULL; js_arr_push(js, arr, js_mknum((double)secs)); js_arr_push(js, arr, js_mknum((double)nsecs)); return arr;}
static ant_value_t process_hrtime_bigint(ant_params_t) { (void)args; (void)nargs; uint64_t now = uv_hrtime(); char buf[32]; snprintf(buf, sizeof(buf), "%llu", (unsigned long long)now); return js_mkbigint(js, buf, strlen(buf), false);}
static ant_value_t process_memory_usage(ant_params_t) { (void)args; (void)nargs; ant_value_t obj = Ant_Object_Create(js); size_t rss = 0; uv_resident_set_memory(&rss); js_set(js, obj, "rss", js_mknum((double)rss)); #ifdef _WIN32 PROCESS_MEMORY_COUNTERS_EX pmc; if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) { js_set(js, obj, "heapTotal", js_mknum((double)pmc.WorkingSetSize)); js_set(js, obj, "heapUsed", js_mknum((double)pmc.PrivateUsage)); } else { js_set(js, obj, "heapTotal", js_mknum(0)); js_set(js, obj, "heapUsed", js_mknum(0)); }#else struct rusage usage; if (getrusage(RUSAGE_SELF, &usage) == 0) { js_set(js, obj, "heapTotal", js_mknum((double)rss)); js_set(js, obj, "heapUsed", js_mknum((double)rss)); } else { js_set(js, obj, "heapTotal", js_mknum(0)); js_set(js, obj, "heapUsed", js_mknum(0)); }#endif js_set(js, obj, "external", js_mknum(0)); js_set(js, obj, "arrayBuffers", js_mknum(0)); return obj;}
static ant_value_t process_memory_usage_rss(ant_params_t) { (void)args; (void)nargs; size_t rss = 0; uv_resident_set_memory(&rss); return js_mknum((double)rss);}
static ant_value_t process_cpu_usage(ant_params_t) { ant_value_t obj = Ant_Object_Create(js); uv_rusage_t rusage; if (uv_getrusage(&rusage) == 0) { int64_t user_usec = rusage.ru_utime.tv_sec * 1000000LL + rusage.ru_utime.tv_usec; int64_t sys_usec = rusage.ru_stime.tv_sec * 1000000LL + rusage.ru_stime.tv_usec; if (nargs > 0 && is_special_object(args[0])) { ant_value_t prev_user = js_get(js, args[0], "user"); ant_value_t prev_system = js_get(js, args[0], "system"); if (vtype(prev_user) == kTypeNumber) user_usec -= (int64_t)js_getnum(prev_user); if (vtype(prev_system) == kTypeNumber) sys_usec -= (int64_t)js_getnum(prev_system); } js_set(js, obj, "user", js_mknum((double)user_usec)); js_set(js, obj, "system", js_mknum((double)sys_usec)); } else { js_set(js, obj, "user", js_mknum(0)); js_set(js, obj, "system", js_mknum(0)); } return obj;}
static ant_value_t process_resource_usage(ant_params_t) { uv_rusage_t ru; int rc = uv_getrusage(&ru); if (rc != 0) return js_mkerr_typed(js, JS_ERR_GENERIC, "uv_getrusage: %s", uv_strerror(rc));
const struct { const char *name; double value; } fields[] = { { "userCPUTime", (double)ru.ru_utime.tv_sec * 1e6 + (double)ru.ru_utime.tv_usec }, { "systemCPUTime", (double)ru.ru_stime.tv_sec * 1e6 + (double)ru.ru_stime.tv_usec }, { "maxRSS", (double)ru.ru_maxrss }, { "sharedMemorySize", (double)ru.ru_ixrss }, { "unsharedDataSize", (double)ru.ru_idrss }, { "unsharedStackSize", (double)ru.ru_isrss }, { "minorPageFault", (double)ru.ru_minflt }, { "majorPageFault", (double)ru.ru_majflt }, { "swappedOut", (double)ru.ru_nswap }, { "fsRead", (double)ru.ru_inblock }, { "fsWrite", (double)ru.ru_oublock }, { "ipcSent", (double)ru.ru_msgsnd }, { "ipcReceived", (double)ru.ru_msgrcv }, { "signalsCount", (double)ru.ru_nsignals }, { "voluntaryContextSwitches", (double)ru.ru_nvcsw }, { "involuntaryContextSwitches", (double)ru.ru_nivcsw }, };
ant_value_t obj = Ant_Object_Create(js); for (size_t i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) js_set(js, obj, fields[i].name, js_mknum(fields[i].value)); return obj;}
static ant_value_t process_kill(ant_params_t) { if (nargs < 1) return js_mkerr(js, "process.kill requires at least 1 argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "pid must be a number"); int pid = (int)js_getnum(args[0]); int sig = SIGTERM; if (nargs > 1) { if (vtype(args[1]) == kTypeNumber) { sig = (int)js_getnum(args[1]); } else if (vtype(args[1]) == kTypeString) { char *sig_name = js_getstr(js, args[1], NULL); if (sig_name) { int signum = process_signal_number(sig_name); if (signum > 0) sig = signum; else return js_mkerr(js, "Unknown signal"); } } } int result = uv_kill(pid, sig); if (result != 0) { const char *code = uv_err_name(result); ant_value_t props = Ant_Object_CreateBare(js); js_set(js, props, "code", js_mkstr(js, code, strlen(code))); js_set(js, props, "errno", js_mknum(result)); js_set(js, props, "syscall", js_mkstr(js, "kill", 4)); return js_mkerr_props(js, JS_ERR_GENERIC, props, "kill %s", code); } return js_true;}
static ant_value_t process_abort(ant_params_t) { abort(); return js_mkundef();}
static ant_value_t process_chdir(ant_params_t) { if (js->worker) return js_mkerr_code(js, JS_ERR_TYPE, "ERR_WORKER_UNSUPPORTED_OPERATION", "process.chdir() is not supported in workers"); if (nargs < 1) return js_mkerr(js, "process.chdir requires 1 argument"); char *dir = js_getstr(js, args[0], NULL); if (!dir) return js_mkerr(js, "directory must be a string"); int result = uv_chdir(dir); if (result != 0) return js_mkerr(js, "ENOENT: no such file or directory, chdir"); atomic_fetch_add_explicit(&process_cwd_epoch, 1, memory_order_release); return js_mkundef();}
static ant_value_t process_umask(ant_params_t) {#ifdef _WIN32 (void)args; (void)nargs; return js_mknum(0);#else if (nargs > 0 && vtype(args[0]) == kTypeNumber) { int new_mask = (int)js_getnum(args[0]); int old_mask = umask((mode_t)new_mask); return js_mknum(old_mask); } int cur = umask(0); umask((mode_t)cur); return js_mknum(cur);#endif}
#ifndef _WIN32static ant_value_t process_getuid(ant_params_t) { (void)args; (void)nargs; return js_mknum((double)getuid());}
static ant_value_t process_geteuid(ant_params_t) { (void)args; (void)nargs; return js_mknum((double)geteuid());}
static ant_value_t process_getgid(ant_params_t) { (void)args; (void)nargs; return js_mknum((double)getgid());}
static ant_value_t process_getegid(ant_params_t) { (void)args; (void)nargs; return js_mknum((double)getegid());}
static ant_value_t process_getgroups(ant_params_t) { (void)args; (void)nargs; int ngroups = getgroups(0, NULL); if (ngroups < 0) return js_mkarr(js); gid_t *groups = malloc(sizeof(gid_t) * (size_t)ngroups); if (!groups) return js_mkarr(js); ngroups = getgroups(ngroups, groups); ant_value_t arr = js_mkarr(js); for (int i = 0; i < ngroups; i++) { js_arr_push(js, arr, js_mknum((double)groups[i])); } free(groups); return arr;}
static ant_value_t process_setuid(ant_params_t) { if (nargs < 1) return js_mkerr(js, "process.setuid requires 1 argument"); uid_t uid; if (vtype(args[0]) == kTypeNumber) { uid = (uid_t)js_getnum(args[0]); } else if (vtype(args[0]) == kTypeString) { char *name = js_getstr(js, args[0], NULL); struct passwd *pwd = getpwnam(name); if (!pwd) return js_mkerr(js, "setuid user not found"); uid = pwd->pw_uid; } else { return js_mkerr(js, "uid must be a number or string"); } if (setuid(uid) != 0) return js_mkerr(js, "setuid failed"); return js_mkundef();}
static ant_value_t process_setgid(ant_params_t) { if (nargs < 1) return js_mkerr(js, "process.setgid requires 1 argument"); gid_t gid; if (vtype(args[0]) == kTypeNumber) { gid = (gid_t)js_getnum(args[0]); } else if (vtype(args[0]) == kTypeString) { char *name = js_getstr(js, args[0], NULL); struct group *grp = getgrnam(name); if (!grp) return js_mkerr(js, "setgid group not found"); gid = grp->gr_gid; } else { return js_mkerr(js, "gid must be a number or string"); } if (setgid(gid) != 0) return js_mkerr(js, "setgid failed"); return js_mkundef();}
static ant_value_t process_seteuid(ant_params_t) { if (nargs < 1) return js_mkerr(js, "process.seteuid requires 1 argument"); uid_t uid; if (vtype(args[0]) == kTypeNumber) { uid = (uid_t)js_getnum(args[0]); } else if (vtype(args[0]) == kTypeString) { char *name = js_getstr(js, args[0], NULL); struct passwd *pwd = getpwnam(name); if (!pwd) return js_mkerr(js, "seteuid user not found"); uid = pwd->pw_uid; } else { return js_mkerr(js, "uid must be a number or string"); } if (seteuid(uid) != 0) return js_mkerr(js, "seteuid failed"); return js_mkundef();}
static ant_value_t process_setegid(ant_params_t) { if (nargs < 1) return js_mkerr(js, "process.setegid requires 1 argument"); gid_t gid; if (vtype(args[0]) == kTypeNumber) { gid = (gid_t)js_getnum(args[0]); } else if (vtype(args[0]) == kTypeString) { char *name = js_getstr(js, args[0], NULL); struct group *grp = getgrnam(name); if (!grp) return js_mkerr(js, "setegid group not found"); gid = grp->gr_gid; } else { return js_mkerr(js, "gid must be a number or string"); } if (setegid(gid) != 0) return js_mkerr(js, "setegid failed"); return js_mkundef();}
static ant_value_t process_setgroups(ant_params_t) { if (nargs < 1 || !js_is_array(args[0])) { return js_mkerr(js, "process.setgroups requires an array"); } ant_value_t len_val = js_get(js, args[0], "length"); int len = (int)js_getnum(len_val); gid_t *groups = malloc(sizeof(gid_t) * (size_t)len); if (!groups) return js_mkerr(js, "allocation failed"); for (int i = 0; i < len; i++) { char idx[16]; snprintf(idx, sizeof(idx), "%d", i); ant_value_t val = js_get(js, args[0], idx); if (vtype(val) == kTypeNumber) { groups[i] = (gid_t)js_getnum(val); } else if (vtype(val) == kTypeString) { char *name = js_getstr(js, val, NULL); struct group *grp = getgrnam(name); if (!grp) { free(groups); return js_mkerr(js, "group not found"); } groups[i] = grp->gr_gid; } else { free(groups); return js_mkerr(js, "group id must be number or string"); } } if (setgroups(len, groups) != 0) { free(groups); return js_mkerr(js, "setgroups failed"); } free(groups); return js_mkundef();}
static ant_value_t process_initgroups(ant_params_t) { if (nargs < 2) return js_mkerr(js, "process.initgroups requires 2 arguments"); char *user = js_getstr(js, args[0], NULL); if (!user) return js_mkerr(js, "user must be a string"); gid_t gid; if (vtype(args[1]) == kTypeNumber) { gid = (gid_t)js_getnum(args[1]); } else if (vtype(args[1]) == kTypeString) { char *name = js_getstr(js, args[1], NULL); struct group *grp = getgrnam(name); if (!grp) return js_mkerr(js, "group not found"); gid = grp->gr_gid; } else { return js_mkerr(js, "gid must be a number or string"); } if (initgroups(user, gid) != 0) return js_mkerr(js, "initgroups failed"); return js_mkundef();}#endif
static bool env_name_ok(const char *key, size_t key_len) { return key_len > 0 && !memchr(key, '=', key_len) && !memchr(key, '\0', key_len);}
static ant_mutex_t env_lock = ANT_MUTEX_INIT;
static env_entry_t **private_env(ant_t *js) { ant_process_state_t *ps = js->process_state; return ps && ps->has_private_env ? &ps->private_env : NULL;}
static bool private_env_put(env_entry_t **table, const char *key, size_t key_len, const char *value, size_t val_len) { env_entry_t *entry = NULL; HASH_FIND(hh, *table, key, key_len, entry); char *copy = strndup(value, val_len); if (!copy) return false; if (entry) { free(entry->value); entry->value = copy; return true; } if (!(entry = calloc(1, sizeof(*entry))) || !(entry->key = strndup(key, key_len))) { free(entry); free(copy); return false; } entry->value = copy; HASH_ADD_KEYPTR(hh, *table, entry->key, key_len, entry); return true;}
static void private_env_free(env_entry_t **table) { env_entry_t *entry, *tmp; HASH_ITER(hh, *table, entry, tmp) { HASH_DEL(*table, entry); free(entry->key); free(entry->value); free(entry); }}
void process_set_private_env(ant_t *js, char **entries) { ant_process_state_t *ps = process_state(js); if (!ps) return; private_env_free(&ps->private_env); ps->has_private_env = true; for (char **it = entries; it && *it; it++) { const char *eq = strchr(*it, '='); if (eq) private_env_put(&ps->private_env, *it, (size_t)(eq - *it), eq + 1, strlen(eq + 1)); }}
static char *env_join(const char *key, size_t key_len, const char *value) { size_t val_len = strlen(value); char *out = malloc(key_len + val_len + 2); if (!out) return NULL; memcpy(out, key, key_len); out[key_len] = '='; memcpy(out + key_len + 1, value, val_len + 1); return out;}
char **process_env_snapshot(ant_t *js) { env_entry_t **table = private_env(js); size_t count = 0, i = 0; char **out = NULL;
if (table) { count = HASH_COUNT(*table); if (!(out = calloc(count + 1, sizeof(*out)))) return NULL; for (env_entry_t *e = *table; e; e = e->hh.next) out[i++] = env_join(e->key, strlen(e->key), e->value); return out; }
ant_mutex_lock(&env_lock); for (char **env = environ; env && *env; env++) count++; if ((out = calloc(count + 1, sizeof(*out)))) for (char **env = environ; env && *env && i < count; env++) out[i++] = strdup(*env); ant_mutex_unlock(&env_lock); return out;}
char **process_private_env_snapshot(ant_t *js) { return private_env(js) ? process_env_snapshot(js) : NULL;}
static ant_value_t env_get(ant_t *js, ant_value_t target, const char *key, size_t key_len) { if (!env_name_ok(key, key_len)) return js_mkundef();
env_entry_t **table = private_env(js); if (table) { env_entry_t *entry = NULL; HASH_FIND(hh, *table, key, key_len, entry); return entry ? js_mkstr(js, entry->value, strlen(entry->value)) : js_mkundef(); } CSTR_BUF(buf, 256); char *key_str = CSTR_INIT(buf, key, key_len); if (!key_str) return js_mkundef(); ant_mutex_lock(&env_lock); char *value = getenv(key_str); ant_value_t result = value ? js_mkstr(js, value, strlen(value)) : js_mkundef(); ant_mutex_unlock(&env_lock); cstr_free(&buf); return result;}
static ant_value_t env_set(ant_t *js, ant_value_t target, const char *key, size_t key_len, ant_value_t value) { if (vtype(value) == kTypeSymbol) return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert a Symbol value to a string"); ant_value_t str_val = coerce_to_str(js, value); if (is_err(str_val)) return str_val; size_t val_len = 0; const char *val_str = js_getstr(js, str_val, &val_len); if (!val_str) return js_mkerr(js, "out of memory"); if (!env_name_ok(key, key_len)) return js_true;
env_entry_t **table = private_env(js); if (table) return private_env_put(table, key, key_len, val_str, val_len) ? js_true : js_mkerr(js, "out of memory"); CSTR_BUF(buf, 256); char *key_str = CSTR_INIT(buf, key, key_len); if (!key_str) return js_mkerr(js, "out of memory"); ant_mutex_lock(&env_lock); const char *current = getenv(key_str); bool changed = !current || strlen(current) != val_len || memcmp(current, val_str, val_len) != 0; bool stored = !changed || setenv(key_str, val_str, 1) == 0; ant_mutex_unlock(&env_lock); cstr_free(&buf); return stored ? js_true : js_mkerr(js, "out of memory");}
static ant_value_t env_del(ant_t *js, ant_value_t target, const char *key, size_t key_len) { if (!env_name_ok(key, key_len)) return js_true;
env_entry_t **table = private_env(js); if (table) { env_entry_t *entry = NULL; HASH_FIND(hh, *table, key, key_len, entry); if (entry) { HASH_DEL(*table, entry); free(entry->key); free(entry->value); free(entry); } return js_true; } CSTR_BUF(buf, 256); char *key_str = CSTR_INIT(buf, key, key_len); if (!key_str) return js_mkerr(js, "out of memory"); ant_mutex_lock(&env_lock); unsetenv(key_str); ant_mutex_unlock(&env_lock); cstr_free(&buf); return js_true;}
static void load_dotenv_file(void) { FILE *fp = fopen(".env", "r"); if (fp == NULL) return; char line[1024]; while (fgets(line, sizeof(line), fp) != NULL) { size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; len--; } if (len > 0 && line[len - 1] == '\r') { line[len - 1] = '\0'; len--; } if (len == 0 || line[0] == '#') continue; char *equals = strchr(line, '='); if (equals == NULL) continue; *equals = '\0'; char *key = line; char *value = equals + 1; while (*key == ' ' || *key == '\t') key++; char *key_end = key + strlen(key) - 1; while (key_end > key && (*key_end == ' ' || *key_end == '\t')) { *key_end = '\0'; key_end--; } while (*value == ' ' || *value == '\t') value++; char *value_end = value + strlen(value) - 1; while (value_end > value && (*value_end == ' ' || *value_end == '\t')) { *value_end = '\0'; value_end--; } if (strlen(value) >= 2 && ((value[0] == '"' && value[strlen(value) - 1] == '"') || (value[0] == '\'' && value[strlen(value) - 1] == '\''))) { value[strlen(value) - 1] = '\0'; value++; } setenv(key, value, 0); } fclose(fp);}
static ant_value_t process_set_exit_code(ant_t *js, ant_process_state_t *ps, ant_value_t code) { if (vtype(code) == kTypeUndefined || vtype(code) == kTypeNull) { ps->has_exit_code = false; return js_mkundef(); }
size_t len = 0; ant_value_type_t type = vtype(code); if (type == kTypeString) js_getstr(js, code, &len); double n = type == kTypeNumber ? js_getnum(code) : len > 0 ? tod(js_to_numeric(js, code)) : JS_NAN; if (isnan(n) && type != kTypeNumber) return Ant_Error_CreateInvalidArgType(js, "code", "of type number", code);
if (!isfinite(n) || n != trunc(n) || fabs(n) > 9007199254740991.0) { char buf[64], message[160]; js_cstr_t received = js_to_cstr(js, js_mknum(n), buf, sizeof(buf)); snprintf( message, sizeof(message), "The value of \"code\" is out of range. It must be %s. Received %s", isfinite(n) && n == trunc(n) ? ">= -9007199254740991 && <= 9007199254740991" : "an integer", received.ptr ); if (received.needs_free) free((void *)received.ptr); return js_mkerr_code(js, JS_ERR_RANGE, "ERR_OUT_OF_RANGE", message); }
ps->exit_code = (int32_t)(uint32_t)(int64_t)n; ps->has_exit_code = true; return js_mkundef();}
static ant_value_t process_exit_code_getter(ant_params_t) { ant_process_state_t *ps = process_state(js); return ps && ps->has_exit_code ? js_mknum(ps->exit_code) : js_mkundef();}
static ant_value_t process_exit_code_setter(ant_params_t) { ant_process_state_t *ps = process_state(js); if (!ps) return js_mkundef(); return process_set_exit_code(js, ps, nargs > 0 ? args[0] : js_mkundef());}
int process_exit_code(ant_t *js) { ant_process_state_t *ps = js->process_state; return ps && ps->has_exit_code ? ps->exit_code : 0;}
int process_run_exit_handlers(ant_t *js, int status) { ant_process_state_t *ps = js->process_state; if (!ps) return status;
if (status != EXIT_SUCCESS) { ps->exit_code = status; ps->has_exit_code = true; }
if (ps->exiting || !is_object_type(ps->process_obj)) return process_exit_code(js); ps->exiting = true; js_set(js, ps->process_obj, "_exiting", js_true);
ant_value_t code = js_mknum(process_exit_code(js)); emit_process_event(js, "exit", &code, 1); if (print_uncaught_throw(js) && !ps->has_exit_code) { ps->exit_code = EXIT_FAILURE; ps->has_exit_code = true; }
return process_exit_code(js);}
void process_exit_with(ant_t *js, int status) { int code = process_run_exit_handlers(js, status); if (js->worker) ant_worker_exit(js, code); else exit(code);}
static ant_value_t process_exit(ant_params_t) { ant_process_state_t *ps = process_state(js); if (ps && nargs > 0 && vtype(args[0]) != kTypeUndefined) { ant_value_t result = process_set_exit_code(js, ps, args[0]); if (is_err(result)) return result; } if (js->worker) return ant_worker_exit(js, process_run_exit_handlers(js, EXIT_SUCCESS)); process_exit_with(js, EXIT_SUCCESS); return js_mkundef();}
typedef struct { char *buf; size_t pos; size_t cap;} env_str_ctx;
typedef void (*env_iter_cb)( ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx);
static void env_foreach(ant_t *js, env_iter_cb cb, void *ctx) { char **snapshot = process_env_snapshot(js); for (char **env = snapshot; env && *env != NULL; env++) { char *entry = *env; char *equals = strchr(entry, '='); if (equals == NULL) continue; size_t key_len = (size_t)(equals - entry); char *value = equals + 1; cb(js, entry, key_len, value, strlen(value), ctx); } for (char **env = snapshot; env && *env; env++) free(*env); free(snapshot);}
static void env_to_object_cb(ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx) { ant_value_t obj = *(ant_value_t *)ctx; CSTR_BUF(buf, 256); char *key_str = CSTR_INIT(buf, key, key_len); if (!key_str) return; js_set(js, obj, key_str, js_mkstr(js, value, val_len)); cstr_free(&buf);}
static ant_value_t env_to_object(ant_params_t) { ant_value_t obj = Ant_Object_CreateBare(js); env_foreach(js, env_to_object_cb, &obj); return obj;}
static void env_tostring_cb(ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx) { env_str_ctx *c = ctx; size_t entry_len = key_len + 1 + val_len; if (c->pos + entry_len + 2 >= c->cap) { size_t new_cap = c->cap * 2 + entry_len; char *new_buf = realloc(c->buf, new_cap); if (!new_buf) return; c->buf = new_buf; c->cap = new_cap; } if (c->pos > 0) c->buf[c->pos++] = '\n'; memcpy(c->buf + c->pos, key, key_len); c->pos += key_len; c->buf[c->pos++] = '='; memcpy(c->buf + c->pos, value, val_len); c->pos += val_len;}
static ant_value_t env_toString(ant_params_t) { env_str_ctx ctx = { .buf = malloc(4096), .pos = 0, .cap = 4096 }; if (!ctx.buf) return js_mkstr(js, "", 0); env_foreach(js, env_tostring_cb, &ctx); ctx.buf[ctx.pos] = '\0'; ant_value_t ret = js_mkstr(js, ctx.buf, ctx.pos); free(ctx.buf); return ret;}
static void env_keys_cb( ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx) { js_arr_push(js, *(ant_value_t *)ctx, js_mkstr(js, key, key_len));}
static ant_value_t env_keys(ant_t *js, ant_value_t target) { GC_ROOT_SAVE(root_mark, js); ant_value_t arr = js_mkarr(js); GC_ROOT_PIN(js, arr); env_foreach(js, env_keys_cb, &arr); GC_ROOT_RESTORE(js, root_mark); return arr;}
static void env_entries_cb( ant_t *js, const char *key, size_t key_len, const char *value, size_t val_len, void *ctx) { ant_value_t pairs = *(ant_value_t *)ctx; js_arr_push(js, pairs, js_mkstr(js, key, key_len)); js_arr_push(js, pairs, js_mkstr(js, value, val_len));}
static ant_value_t env_entries(ant_t *js, ant_value_t target) { GC_ROOT_SAVE(root_mark, js); ant_value_t pairs = js_mkarr(js); GC_ROOT_PIN(js, pairs); env_foreach(js, env_entries_cb, &pairs); GC_ROOT_RESTORE(js, root_mark); return pairs;}
static const ant_host_proxy_ops_t env_host_ops = { .name = "process.env", .get = env_get, .set = env_set, .del = env_del, .keys = env_keys, .flat_entries = env_entries,};
static ant_value_t process_cwd(ant_params_t) { ant_process_state_t *ps = process_state(js); if (!ps) return js_mkerr(js, "Out of memory"); uint64_t epoch = atomic_load_explicit(&process_cwd_epoch, memory_order_acquire); if (ps->cwd_epoch == epoch && vtype(ps->cached_cwd) == kTypeString) return ps->cached_cwd;
char inline_cwd[4096]; char *cwd = inline_cwd; size_t size = sizeof(inline_cwd); int status = uv_cwd(cwd, &size); if (status == UV_ENOBUFS) { cwd = malloc(size); if (!cwd) return js_mkerr(js, "Out of memory"); status = uv_cwd(cwd, &size); } ant_value_t result; if (status == 0) result = js_mkstr(js, cwd, size); else { const char *code = uv_err_name(status); ant_value_t props = Ant_Object_CreateBare(js); js_set(js, props, "code", js_mkstr(js, code, strlen(code))); js_set(js, props, "errno", js_mknum(status)); js_set(js, props, "syscall", js_mkstr(js, "uv_cwd", 6)); result = js_mkerr_props(js, JS_ERR_GENERIC, props, "%s: %s, uv_cwd", code, uv_strerror(status)); } if (cwd != inline_cwd) free(cwd); if (vtype(result) == kTypeString) { ps->cached_cwd = result; ps->cwd_epoch = epoch; } return result;}
static bool process_is_error_object(ant_value_t value) { if (is_err(value)) return true; return is_object_type(value) && js_get_slot(value, SLOT_ERROR_BRAND) == js_true;}
static void process_get_warning_options( ant_t *js, ant_value_t options, const char **type, const char **code, const char **detail, ant_offset_t *detail_len) { if (!is_object_type(options)) return;
ant_value_t type_val = js_get(js, options, "type"); ant_value_t code_val = js_get(js, options, "code"); ant_value_t detail_val = js_get(js, options, "detail");
if (vtype(type_val) == kTypeString) *type = js_getstr(js, type_val, NULL); if (vtype(code_val) == kTypeString) *code = js_getstr(js, code_val, NULL); if (vtype(detail_val) == kTypeString) *detail = (const char *)(uintptr_t)vstr(js, detail_val, detail_len);}
static ant_value_t process_make_warning_object( ant_t *js, const char *type, js_cstr_t msg, const char *code, const char *detail, ant_offset_t detail_len) { ant_value_t warning_obj = Ant_Object_CreateBare(js); js_set_proto_init(warning_obj, js->builtins.error_protos[JS_ERR_GENERIC]); js_set_slot(warning_obj, SLOT_ERROR_BRAND, js_true); js_set(js, warning_obj, "name", js_mkstr(js, type, strlen(type))); js_set(js, warning_obj, "message", js_mkstr(js, msg.ptr, msg.len));
if (code) js_set(js, warning_obj, "code", js_mkstr(js, code, strlen(code))); if (detail) js_set(js, warning_obj, "detail", js_mkstr(js, detail, detail_len));
js_capture_stack(js, warning_obj); return warning_obj;}
static ant_value_t process_emit_warning(ant_params_t) { if (nargs < 1) return js_mkundef();
ant_value_t warning = args[0]; const char *type = "Warning"; const char *code = NULL; const char *detail = NULL; ant_offset_t detail_len = 0;
if (nargs >= 2) { if (vtype(args[1]) == kTypeString) type = js_getstr(js, args[1], NULL); else process_get_warning_options(js, args[1], &type, &code, &detail, &detail_len); }
if (nargs >= 3 && vtype(args[2]) == kTypeString) code = js_getstr(js, args[2], NULL);
char msg_buf[512]; js_cstr_t msg = {0}; ant_value_t warning_event_arg = warning; bool is_error = process_is_error_object(warning);
if (is_error) { ant_value_t warning_obj = js_as_obj(warning); ant_offset_t prop_len = 0; const char *name_prop = get_str_prop(js, warning_obj, "name", 4, &prop_len); if (name_prop) type = name_prop; const char *message_prop = get_str_prop(js, warning_obj, "message", 7, &prop_len); msg.ptr = message_prop ? message_prop : ""; msg.len = message_prop ? prop_len : 0; msg.needs_free = false; code = get_str_prop(js, warning_obj, "code", 4, NULL); detail = get_str_prop(js, warning_obj, "detail", 6, &detail_len); warning_event_arg = warning_obj; } else { msg = js_to_cstr(js, warning, msg_buf, sizeof(msg_buf)); warning_event_arg = process_make_warning_object(js, type, msg, code, detail, detail_len); }
fprintf(stderr, "(%s:%d) ", "ant", (int)getpid()); if (code) fprintf(stderr, "[%s] ", code); fprintf(stderr, "%s: %.*s\n", type ? type : "Warning", (int)msg.len, msg.ptr); if (detail) fprintf(stderr, "%.*s\n", (int)detail_len, detail);
emit_process_event(js, "warning", &warning_event_arg, 1); if (msg.needs_free) free((void *)msg.ptr); return js_mkundef();}
static ant_value_t process_next_tick(ant_params_t) { if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "process.nextTick requires a callback"); ant_value_t cb = args[0]; if (vtype(cb) != kTypeFunction && vtype(cb) != kTypeBuiltin) return js_mkerr_typed(js, JS_ERR_TYPE, "process.nextTick callback is not a function"); if (nargs <= 1) queue_next_tick(js, cb); else queue_next_tick_with_args(js, cb, args + 1, nargs - 1); return js_mkundef();}
static bool process_event_key_is( ant_t *js, ant_value_t key, const char *expected) { const char *value = NULL; size_t len = 0; size_t expected_len = strlen(expected);
if (vtype(key) != kTypeString) return false; value = js_getstr(js, key, &len); return value && len == expected_len && memcmp(value, expected, len) == 0;}
static void process_listener_change( ant_t *js, ant_value_t target, ant_value_t key, ant_offset_t listener_count, void *context) { ant_process_state_t *ps = (ant_process_state_t *)context; if (!ps || vtype(key) != kTypeString) return;
if (target == ps->process_obj) { const char *event = js_getstr(js, key, NULL); int signum = event ? process_signal_number(event) : -1; if (signum > 0) { if (listener_count > 0) start_signal_watch(js, signum); else stop_signal_watch(js, signum); } else if (listener_count > 0 && process_event_key_is(js, key, "workerMessage")) ant_worker_messaging_listen(js); return; }
if (target == ps->stdin_obj && process_event_key_is(js, key, "keypress")) { if (listener_count > 0) ps->stdin_state.paused = false; stdin_update_reading(js); return; }
if ( target == ps->stdout_obj && process_event_key_is(js, key, "resize") ) { if (listener_count > 0) start_sigwinch_handler(js); else stop_sigwinch_handler(js); }}
static ant_value_t process_get_builtin_module(ant_params_t) { ant_value_t id = nargs > 0 ? args[0] : js_mkundef(); if (vtype(id) != kTypeString) return Ant_Error_CreateInvalidArgType(js, "id", "of type string", id);
size_t len = 0; const char *name = js_getstr(js, id, &len); if (!name) return js_mkundef();
bool found = false; ant_value_t ns = js_esm_load_node_builtin(js, name, len, &found); return found ? esm_require_unwrap(js, ns) : js_mkundef();}
static void process_set_methods(ant_t *js, ant_value_t obj, bool include_event_methods) { js_set(js, obj, "exit", Ant_Function_CreateWithArity(process_exit, 1)); js_set(js, obj, "cwd", Ant_Function_Create(process_cwd)); js_set(js, obj, "chdir", Ant_Function_CreateWithArity(process_chdir, 1)); js_set(js, obj, "uptime", Ant_Function_Create(process_uptime)); js_set(js, obj, "cpuUsage", Ant_Function_CreateWithArity(process_cpu_usage, 1)); js_set(js, obj, "resourceUsage", Ant_Function_Create(process_resource_usage)); js_set(js, obj, "kill", Ant_Function_CreateWithArity(process_kill, 2)); js_set(js, obj, "abort", Ant_Function_Create(process_abort)); js_set(js, obj, "umask", Ant_Function_CreateWithArity(process_umask, 1)); js_set(js, obj, "nextTick", Ant_Function_CreateWithArity(process_next_tick, 1)); js_set(js, obj, "emitWarning", Ant_Function_CreateWithArity(process_emit_warning, 4)); js_set(js, obj, "getBuiltinModule", Ant_Function_CreateWithArity(process_get_builtin_module, 1)); js_set(js, obj, "dlopen", Ant_Function_Create(napi_process_dlopen_js));
ant_value_t mem_usage_fn = Ant_Function_CreateWithData(js, process_memory_usage, "memoryUsage", 0, js_mkundef()); js_set(js, mem_usage_fn, "rss", Ant_Function_Create(process_memory_usage_rss)); js_set(js, obj, "memoryUsage", mem_usage_fn);
ant_value_t hrtime_fn = Ant_Function_CreateWithData(js, process_hrtime, "hrtime", 1, js_mkundef()); js_set(js, hrtime_fn, "bigint", Ant_Function_Create(process_hrtime_bigint)); js_set(js, obj, "hrtime", hrtime_fn);
if (include_event_methods) { ant_value_t ee_proto = eventemitter_prototype(js); if (is_object_type(ee_proto)) js_set_proto_init(obj, ee_proto); }
#ifndef _WIN32 js_set(js, obj, "getuid", Ant_Function_Create(process_getuid)); js_set(js, obj, "geteuid", Ant_Function_Create(process_geteuid)); js_set(js, obj, "getgid", Ant_Function_Create(process_getgid)); js_set(js, obj, "getegid", Ant_Function_Create(process_getegid)); js_set(js, obj, "getgroups", Ant_Function_Create(process_getgroups)); js_set(js, obj, "setuid", Ant_Function_CreateWithArity(process_setuid, 1)); js_set(js, obj, "setgid", Ant_Function_CreateWithArity(process_setgid, 1)); js_set(js, obj, "seteuid", Ant_Function_CreateWithArity(process_seteuid, 1)); js_set(js, obj, "setegid", Ant_Function_CreateWithArity(process_setegid, 1)); js_set(js, obj, "setgroups", Ant_Function_CreateWithArity(process_setgroups, 1)); js_set(js, obj, "initgroups", Ant_Function_CreateWithArity(process_initgroups, 2));#endif}
ant_value_t process_library(ant_t *js) { ant_value_t process_obj = js_get(js, js_glob(js), "process"); js_set(js, process_obj, "default", process_obj); js_set_slot_wb(js, process_obj, SLOT_DEFAULT, process_obj); return process_obj;}
static void process_set_string(ant_t *js, ant_value_t obj, const char *key, const char *value) { js_set(js, obj, key, js_mkstr(js, value, strlen(value)));}
void init_process_module(ant_t *js) { ant_process_state_t *ps = process_state(js); ant_value_t ee_proto = eventemitter_prototype(js);
if (!ps) return;
ps->process_start_time = uv_hrtime(); ant_value_t process_proto = Ant_Object_Create(js);
process_set_methods(js, process_proto, true); js_set_tostringtag(js, process_proto, js_mkstr(js, "process", 7));
ant_value_t process_obj = Ant_Object_CreateBare(js); ant_value_t env_obj = Ant_Object_Create(js); js_set_proto_init(process_obj, process_proto); ps->process_obj = process_obj; eventemitter_set_listener_change_hook(js, process_obj, process_listener_change, ps); process_set_methods(js, process_obj, false); js_set(js, process_obj, "binding", Ant_Function_CreateWithArity(process_binding, 1)); js_set(js, process_obj, "_exiting", js_false); js_set_accessor_desc( js, process_obj, "exitCode", 8, Ant_Function_Create(process_exit_code_getter), Ant_Function_Create(process_exit_code_setter), JS_DESC_E );
if (!js->worker) load_dotenv_file(); defmethod(js, env_obj, "toObject", 8, Ant_Function_Create(env_to_object)); defmethod(js, env_obj, "toString", 8, Ant_Function_Create(env_toString)); ant_value_t env_proxy = js_mkproxy_host(js, env_obj, &env_host_ops); if (is_err(env_proxy)) return; js->builtins.process_env = env_proxy; js_set(js, process_obj, "env", env_proxy); process_update_sandbox_env(js); ant_value_t argv_arr = js_mkarr(js); for (int i = 0; i < js->runtime.argc; i++) js_arr_push( js, argv_arr, js_mkstr(js, js->runtime.argv[i], strlen(js->runtime.argv[i])) );
js_set(js, process_obj, "argv", argv_arr); js_set(js, process_obj, "execArgv", js_mkarr(js)); js_set(js, process_obj, "argv0", js->runtime.argc > 0 ? js_mkstr(js, js->runtime.argv[0], strlen(js->runtime.argv[0])) : js_mkstr(js, "ant", 3) ); js_set(js, process_obj, "execPath", process_exec_path(js)); js_set(js, process_obj, "pid", js_mknum((double)getpid())); js_set(js, process_obj, "ppid", js_mknum((double)getppid()));
ant_value_t features_obj = Ant_Object_Create(js); js_set(js, features_obj, "uv", js_true); process_set_string(js, features_obj, "tls", "BoringSSL"); process_set_string(js, features_obj, "typescript", "transform"); js_set(js, process_obj, "features", features_obj); process_set_string(js, process_obj, "version", "v26.8.1"); ant_value_t versions_obj = Ant_Object_Create(js); process_set_string(js, versions_obj, "ant", ANT_VERSION); process_set_string(js, versions_obj, "silver", ANT_VERSION); process_set_string(js, versions_obj, "skim", SKIM_VERSION); char uv_ver[32]; snprintf(uv_ver, sizeof(uv_ver), "%d.%d.%d", UV_VERSION_MAJOR, UV_VERSION_MINOR, UV_VERSION_PATCH); process_set_string(js, versions_obj, "uv", uv_ver); process_set_string(js, versions_obj, "node", "26.8.1"); process_set_string(js, versions_obj, "brotli", "1.1.0"); process_set_string(js, versions_obj, "llhttp", "9.3.1"); process_set_string(js, versions_obj, "simdjson", "0.12.0"); process_set_string(js, versions_obj, "pcre2", "10.47"); process_set_string(js, versions_obj, "libffi", "3.5.2"); process_set_string(js, versions_obj, "lmdb", "0.9.33"); process_set_string(js, versions_obj, "utf8proc", "2.10.0"); process_set_string(js, versions_obj, "zlib", "2.3.3"); process_set_string(js, versions_obj, "v8", "14.6.202.34-node.28"); process_set_string(js, versions_obj, "modules", "147"); process_set_string(js, versions_obj, "napi", "10"); process_set_string(js, versions_obj, "wamr", "26756a5c5846c262c9e5c89f3fc8e1e693ee2539"); process_set_string(js, versions_obj, "boringssl", "297b11798a0ed6bc7736aa57328909a4afbbf67a"); js_set(js, process_obj, "versions", versions_obj); ant_value_t release_obj = Ant_Object_Create(js); js_set(js, release_obj, "name", js_mkstr(js, "ant", 3)); js_set(js, process_obj, "release", release_obj); // process.platform #if defined(__APPLE__) js_set(js, process_obj, "platform", js_mkstr(js, "darwin", 6)); #elif defined(__linux__) js_set(js, process_obj, "platform", js_mkstr(js, "linux", 5)); #elif defined(_WIN32) || defined(_WIN64) js_set(js, process_obj, "platform", js_mkstr(js, "win32", 5)); #elif defined(__FreeBSD__) js_set(js, process_obj, "platform", js_mkstr(js, "freebsd", 7)); #else js_set(js, process_obj, "platform", js_mkstr(js, "unknown", 7)); #endif // process.arch #if defined(__x86_64__) || defined(_M_X64) js_set(js, process_obj, "arch", js_mkstr(js, "x64", 3)); #elif defined(__i386__) || defined(_M_IX86) js_set(js, process_obj, "arch", js_mkstr(js, "ia32", 4)); #elif defined(__aarch64__) || defined(_M_ARM64) js_set(js, process_obj, "arch", js_mkstr(js, "arm64", 5)); #elif defined(__arm__) || defined(_M_ARM) js_set(js, process_obj, "arch", js_mkstr(js, "arm", 3)); #else js_set(js, process_obj, "arch", js_mkstr(js, "unknown", 7)); #endif ant_value_t stdin_proto = Ant_Object_CreateBare(js); js_set_proto_init(stdin_proto, stream_readable_prototype(js)); js_set(js, stdin_proto, "setRawMode", Ant_Function_Create(js_stdin_set_raw_mode)); js_set(js, stdin_proto, "_read", Ant_Function_CreateWithArity(js_stdin__read, 1)); js_set(js, stdin_proto, "_destroy", Ant_Function_CreateWithArity(js_stdin__destroy, 2)); js_set(js, stdin_proto, "resume", Ant_Function_Create(js_stdin_resume)); js_set(js, stdin_proto, "pause", Ant_Function_Create(js_stdin_pause)); js_set(js, stdin_proto, "ref", Ant_Function_Create(js_stdin_ref)); js_set(js, stdin_proto, "unref", Ant_Function_Create(js_stdin_unref)); js_set_tostringtag(js, stdin_proto, js_mkstr(js, "ReadStream", 10)); ant_value_t stdin_obj = stream_construct_readable(js, stdin_proto, js_mkundef(), js_mkundef()); ps->stdin_obj = stdin_obj; eventemitter_set_listener_change_hook(js, stdin_obj, process_listener_change, ps); js_set(js, stdin_obj, "isTTY", js_bool(stdin_is_tty())); js_set(js, process_obj, "stdin", stdin_obj); ant_value_t stdout_proto = Ant_Object_CreateBare(js); if (is_object_type(ee_proto)) js_set_proto_init(stdout_proto, ee_proto); js_set(js, stdout_proto, "write", Ant_Function_Create(js_stdout_write)); js_set(js, stdout_proto, "getWindowSize", Ant_Function_Create(js_stdout_get_window_size)); js_set_tostringtag(js, stdout_proto, js_mkstr(js, "WriteStream", 11)); ant_value_t stdout_obj = Ant_Object_CreateBare(js); js_set_proto_init(stdout_obj, stdout_proto); ps->stdout_obj = stdout_obj; eventemitter_set_listener_change_hook(js, stdout_obj, process_listener_change, ps); js_set(js, stdout_obj, "isTTY", js_bool(stdout_is_tty(js))); js_set_getter_desc(js, stdout_obj, "rows", 4, Ant_Function_Create(js_stdout_rows_getter), JS_DESC_E | JS_DESC_C); js_set_getter_desc(js, stdout_obj, "columns", 7, Ant_Function_Create(js_stdout_columns_getter), JS_DESC_E | JS_DESC_C); js_set(js, process_obj, "stdout", stdout_obj); ant_value_t stderr_proto = Ant_Object_CreateBare(js); if (is_object_type(ee_proto)) js_set_proto_init(stderr_proto, ee_proto); js_set(js, stderr_proto, "write", Ant_Function_Create(js_stderr_write)); js_set_tostringtag(js, stderr_proto, js_mkstr(js, "WriteStream", 11)); ant_value_t stderr_obj = Ant_Object_CreateBare(js); js_set_proto_init(stderr_obj, stderr_proto); ps->stderr_obj = stderr_obj; eventemitter_set_listener_change_hook(js, stderr_obj, process_listener_change, ps); js_set(js, stderr_obj, "isTTY", js_bool(stderr_is_tty(js))); js_set(js, process_obj, "stderr", stderr_obj); js_set_global_builtin(js, "process", process_obj);}
bool has_active_stdin(ant_t *js) { ant_process_state_t *ps = js->process_state; return ps && ps->stdin_state.reading && ps->stdin_state.refed;}
void gc_mark_process(ant_t *js, gc_mark_fn mark) { ant_process_state_t *ps = js->process_state; if (!ps) return; mark(js, ps->cached_cwd); if (is_object_type(ps->process_obj)) mark(js, ps->process_obj); if (is_object_type(ps->stdin_obj)) mark(js, ps->stdin_obj); if (is_object_type(ps->stdout_obj)) mark(js, ps->stdout_obj); if (is_object_type(ps->stderr_obj)) mark(js, ps->stderr_obj);}
void process_enable_keypress_events(ant_t *js) { ant_process_state_t *ps = process_state(js); if (!ps) return; ps->stdin_state.keypress_enabled = true; ps->stdin_state.escape_state = 0; ps->stdin_state.escape_len = 0;}