hare

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

environ.ha (3646B)


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