Something went wrong. Try again.
Jam Programming Language jamlang.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157// std.process — access to the program's command-line arguments.//// `args()` returns an `Args` cursor; `next(cursor)` yields each argument// as a `[]u8` (argv[0] is the program path, by convention) until done://// var it: Args = args();// match (next(it)) {// Option([]u8).Some(arg) { /* arg is a []u8 */ }// Option([]u8).None { /* exhausted */ }// }//// The cursor API is function-style (`next(it)`, `count(it)`) rather than// method-style: Jam can't currently dispatch a method on a local var// whose type comes from another module.//// The capture mechanism is chosen at comptime via `@isDarwin()`, so the// inactive branch is dead-code-eliminated — no `_NSGetArgv` reference// survives on a non-Darwin target, where that symbol doesn't exist:// * Darwin: libSystem's _NSGetArgc / _NSGetArgv (live pointers).// * Linux: /proc/self/cmdline — argv joined by NULs. The buffer and// argv table are malloc'd once and intentionally leaked,// since they must outlive every `args()`/`next()` call.
const { Option } = import("option");
// `pub extern` so the declarations are visible when these functions are// codegen'd in an importer's compilation context (mirrors std.collections).pub extern fn strlen(s: *const[] u8) u64;pub extern fn _NSGetArgc() u64; // C: int* (Darwin / libSystem)pub extern fn _NSGetArgv() u64; // C: char***pub extern fn fopen(path: *const[] u8, mode: *const[] u8) *mut[] u8;pub extern fn fread(buf: *mut[] u8, size: u64, n: u64, f: *mut[] u8) u64;pub extern fn fclose(f: *mut[] u8) i32;pub extern fn malloc(size: u64) *mut[] u8;pub extern fn free(ptr: *mut[] u8);
// Terminate the process with status `code`, never returning. A noreturn// binding to libc exit(3) — the same model as Rust's// `std::process::exit(code: i32) -> !` and Zig's `std.os.exit`, both of// which bottom out in the C `exit` when linked against libc. The status// is an i32 to match C's `exit(int)`; POSIX masks it to the low 8 bits.// `noreturn` lets callers treat the call site as diverging (no return /// dead code after it required).pub extern fn exit(code: i32) noreturn;
// Abnormal termination: raise SIGABRT (core dump / debugger trap) and// never return. A noreturn binding to libc abort(3) — mirrors Rust's// `std::process::abort()` and Zig's `std.os.abort` (both noreturn// libc-abort bindings; Zig raises SIGABRT by hand when not linked// against libc). Use for unrecoverable invariant violations where no// meaningful exit status exists; prefer `exit(code)` for normal failure.pub extern fn abort() noreturn;
// Cursor over argv. `table` points at the argv array (each slot an// 8-byte `char*`); `index` is the next slot to yield; `n` is argc.pub const Args = struct { table: *mut[] u64, index: u32, n: u32,};
fn emptyArgs() Args { var zero: u64 = 0; var none: *mut[] u64 = zero as *mut[] u64; return Args { table: none, index: 0, n: 0 };}
// Parse /proc/self/cmdline into a (table, argc) pair. The kernel writes// the args joined by NULs (and usually ends with a final NUL too). We// read into a growable malloc'd buffer, count NULs to determine argc,// then allocate a u64 table of pointers — table[0] points at the start// of the buffer; each subsequent slot at the byte after the previous// NUL. Both buffer and table are leaked (process-lifetime).fn linuxArgs() Args { var path: []u8 = "/proc/self/cmdline"; var mode: []u8 = "rb"; var f: *mut[] u8 = fopen(path.ptr, mode.ptr); if ((f as u64) == 0) { return emptyArgs(); }
var cap: u64 = 4096; var buf: *mut[] u8 = malloc(cap); var total: u64 = 0; loop { var room: u64 = cap - total; var dst: *mut[] u8 = (buf as u64 + total) as *mut[] u8; var got: u64 = fread(dst, 1, room, f); total = total + got; if (got < room) { break; } var newCap: u64 = cap * 2; var newBuf: *mut[] u8 = malloc(newCap); var j: u64 = 0; while (j < total) { newBuf[j] = buf[j]; j = j + 1; } free(buf); buf = newBuf; cap = newCap; } fclose(f);
if (total == 0) { return emptyArgs(); } // Count NUL-terminated segments. If the kernel didn't emit a trailing // NUL (rare), the final unterminated chunk still counts as one arg. var argc: u32 = 0; var k: u64 = 0; while (k < total) { if (buf[k] == 0) { argc = argc + 1; } k = k + 1; } if (buf[total - 1] != 0) { argc = argc + 1; } if (argc == 0) { return emptyArgs(); }
var table: *mut[] u64 = malloc((argc as u64) * 8) as *mut[] u64; table[0] = buf as u64; var slot: u32 = 1; var p: u64 = 0; while (p < total && slot < argc) { if (buf[p] == 0) { table[slot] = (buf as u64) + p + 1; slot = slot + 1; } p = p + 1; } return Args { table: table, index: 0, n: argc };}
pub fn args() Args { if (@isDarwin()) { // _NSGetArgc() -> int* : deref for argc. // _NSGetArgv() -> char***: deref once for the char** argv table. var argcPtr: *mut[] i32 = _NSGetArgc() as *mut[] i32; var argc: u32 = argcPtr[0] as u32; var pp: *mut[] u64 = _NSGetArgv() as *mut[] u64; // &argv var table: *mut[] u64 = pp[0] as *mut[] u64; // argv table return Args { table: table, index: 0, n: argc }; } if (@isLinux()) { return linuxArgs(); } return emptyArgs();}
// Next argument as a []u8 (borrows argv's memory — valid for the process// lifetime), advancing the cursor; None once every argument is consumed.pub fn next(it: mut Args) Option([]u8) { if (it.index >= it.n) { return Option([]u8).None(); } var cstr: *const[] u8 = it.table[it.index] as *const[] u8; it.index = it.index + 1; var s: []u8 = cstr[0..strlen(cstr)]; return Option([]u8).Some(s);}
// Total number of arguments (argc), including argv[0].pub fn count(it: Args) u32 { return it.n;}