hare

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

xdg.ha (3403B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use errors;
      5 use fmt;
      6 use fs;
      7 use os;
      8 use path;
      9 use unix;
     10 
     11 fn lookup(prog: str, var: str, default: str) str = {
     12 	static let buf = path::buffer { ... };
     13 	path::set(&buf)!;
     14 	match (os::getenv(var)) {
     15 	case let s: str =>
     16 		const path = path::push(&buf, s, prog)!;
     17 		if (!path::abs(path)) {
     18 			yield;
     19 		};
     20 		match (os::stat(path)) {
     21 		case let err: fs::error =>
     22 			os::mkdirs(path, 0o755)!;
     23 			return path;
     24 		case let st: fs::filestat =>
     25 			if (fs::isdir(st.mode)) {
     26 				return path;
     27 			};
     28 		};
     29 	case void => void;
     30 	};
     31 
     32 	const home = os::getenv("HOME") as str;
     33 	const path = path::set(&buf, home, default, prog)!;
     34 	match (os::mkdirs(path, 0o755)) {
     35 	case let err: fs::error =>
     36 		fmt::fatalf("Error creating {}: {}",
     37 			path, fs::strerror(err));
     38 	case void => void;
     39 	};
     40 	return path;
     41 };
     42 
     43 // Returns a directory suitable for storing config files. The "prog" parameter
     44 // should be a descriptive name unique to this program. The return value is
     45 // statically allocated and will be overwritten on subsequent calls to any
     46 // function in the dirs module.
     47 export fn config(prog: str) str = lookup(prog, "XDG_CONFIG_HOME", ".config");
     48 
     49 // Returns a directory suitable for cache files. The "prog" parameter should be
     50 // a descriptive name unique to this program. The return value is statically
     51 // allocated and will be overwritten on subsequent calls to any function in the
     52 // dirs module.
     53 export fn cache(prog: str) str = lookup(prog, "XDG_CACHE_HOME", ".cache");
     54 
     55 // Returns a directory suitable for persistent data files. The "prog" parameter
     56 // should be a descriptive name unique to this program. The return value is
     57 // statically allocated and will be overwritten on subsequent calls to any
     58 // function in the dirs module.
     59 export fn data(prog: str) str = {
     60 	static let buf = path::buffer { ... };
     61 	const fragment = path::set(&buf, ".local", "share")!;
     62 	return lookup(prog, "XDG_DATA_HOME", fragment);
     63 };
     64 
     65 // Returns a directory suitable for storing program state data. The "prog"
     66 // parameter should be a descriptive name unique to this program. The return
     67 // value is statically allocated and will be overwritten on subsequent calls to
     68 // any function in the dirs module.
     69 export fn state(prog: str) str = {
     70 	static let buf = path::buffer { ... };
     71 	const fragment = path::set(&buf, ".local", "state")!;
     72 	return lookup(prog, "XDG_STATE_HOME", fragment);
     73 };
     74 
     75 // Returns a directory suitable for storing non-essential runtime files and
     76 // other file objects (such as sockets, named pipes, and so on). Applications
     77 // should use this directory for communication and synchronization purposes and
     78 // should not place larger files in it, since it might reside in runtime memory
     79 // and cannot necessarily be swapped out to disk.
     80 //
     81 // The specification requires the directory to be owned by the current user and
     82 // not be world-readable. No fallback is implemented in case XDG_RUNTIME_DIR is
     83 // unset or incorrectly set up.
     84 export fn runtime() (str | fs::error) = {
     85 	let path = match (os::getenv("XDG_RUNTIME_DIR")) {
     86 	case let path: str =>
     87 		yield path;
     88 	case void =>
     89 		return errors::noentry;
     90 	};
     91 
     92 	const st = os::stat(path)?;
     93 	const uid = unix::getuid(): uint;
     94 	if (st.uid != uid || fs::mode_perm(st.mode) != fs::mode::USER_RWX) {
     95 		return errors::noaccess;
     96 	};
     97 	if (!fs::isdir(st.mode)) {
     98 		return fs::wrongtype;
     99 	};
    100 
    101 	return path;
    102 };