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