hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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 };