environ+libc.ha (3069B)
1 // License: MPL-2.0 2 // (c) 2022 Alexey Yerin <yyp@disroot.org> 3 use bytes; 4 use rt; 5 use strings; 6 use types::c; 7 8 // The command line arguments provided to the program. By convention, the first 9 // member is usually the name of the program. 10 export let args: []str = []; 11 12 // Statically allocate arg strings if there are few enough arguments, saves a 13 // syscall if we don't need it. 14 let args_static: [32]str = [""...]; 15 16 @init fn init_environ() void = { 17 rt::start_linux(); 18 if (rt::argc < len(args_static)) { 19 args = args_static[..rt::argc]; 20 for (let i = 0z; i < rt::argc; i += 1) { 21 args[i] = c::tostr(rt::argv[i]: *const c::char)!; 22 }; 23 } else { 24 args = alloc([], rt::argc); 25 for (let i = 0z; i < rt::argc; i += 1) { 26 append(args, c::tostr(rt::argv[i]: *const c::char)!); 27 }; 28 }; 29 30 }; 31 32 @fini fn fini_environ() void = { 33 if (rt::argc >= len(args_static)) { 34 free(args); 35 }; 36 free(envp); 37 }; 38 39 // Looks up an environment variable and returns its value, or void if unset. 40 export fn getenv(name: const str) (str | void) = { 41 const name_b = strings::toutf8(name); 42 for (let i = 0z; rt::envp[i] != null; i += 1) { 43 const item = rt::envp[i]: *[*]u8; 44 const ln = c::strlen(item: *c::char); 45 const eq: size = match (bytes::index(item[..ln], '=')) { 46 case void => 47 abort("Environment violates System-V invariants"); 48 case let i: size => 49 yield i; 50 }; 51 if (bytes::equal(name_b, item[..eq])) { 52 const ln = c::strlen(item: *const c::char); 53 return strings::fromutf8(item[eq+1..ln])!; 54 }; 55 }; 56 }; 57 58 // Looks up an environment variable and returns its value, or a default value if 59 // unset. 60 export fn tryenv(name: const str, default: str) str = match (getenv(name)) { 61 case let s: str => 62 yield s; 63 case void => 64 yield default; 65 }; 66 67 let envp: []str = []; 68 69 // Returns a slice of the environment strings in the form KEY=VALUE. 70 export fn getenvs() []str = { 71 if (len(envp) != 0) { 72 return envp; 73 }; 74 for (let i = 0z; rt::envp[i] != null; i += 1) { 75 append(envp, c::tostr(rt::envp[i]: *const c::char)!); 76 }; 77 return envp; 78 }; 79 80 let uts: rt::utsname = rt::utsname { ... }; 81 let uts_valid: bool = false; 82 83 // Returns the host kernel name 84 export fn sysname() const str = { 85 if (!uts_valid) { 86 rt::uname(&uts) as void; 87 uts_valid = true; 88 }; 89 return c::tostr(&uts.sysname: *const c::char)!; 90 }; 91 92 // Returns the host system hostname 93 export fn hostname() const str = { 94 if (!uts_valid) { 95 rt::uname(&uts) as void; 96 uts_valid = true; 97 }; 98 return c::tostr(&uts.nodename: *const c::char)!; 99 }; 100 101 // Returns the host kernel version 102 export fn release() const str = { 103 if (!uts_valid) { 104 rt::uname(&uts) as void; 105 uts_valid = true; 106 }; 107 return c::tostr(&uts.release: *const c::char)!; 108 }; 109 110 // Returns the host operating system version 111 export fn version() const str = { 112 if (!uts_valid) { 113 rt::uname(&uts) as void; 114 uts_valid = true; 115 }; 116 return c::tostr(&uts.version: *const c::char)!; 117 }; 118 119 // Returns the host CPU architecture 120 export fn machine() const str = { 121 if (!uts_valid) { 122 rt::uname(&uts) as void; 123 uts_valid = true; 124 }; 125 return c::tostr(&uts.machine: *const c::char)!; 126 };