File: platform_cmd.ha

package info (click to toggle)
hare 0.25.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,948 kB
  • sloc: asm: 1,264; makefile: 123; sh: 114; lisp: 101
file content (124 lines) | stat: -rw-r--r-- 2,623 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use errors;
use io;
use os;
use rt;
use strings;
use types::c;

export type strlist = []nullable *const c::char;

fn free_strlist(l: strlist) void = {
	for (let i = 0z; i < len(l) - 1; i += 1) {
		free(l[i]: *const c::char);
	};
	free(l);
};

export type platform_argv = strlist;

fn platform_newargv(name: str, args: str...) (platform_argv | nomem) = {
	let ok = false;
	let argv: platform_argv = alloc([null...], len(args) + 2z)?;
	defer if (!ok) platform_free_argv(argv);

	argv[0] = c::fromstr(name)?;

	let i = 1z;
	for (let arg .. args) {
		argv[i] = c::fromstr(arg)?;
		i += 1;
	};

	ok = true;
	return argv;
};

fn platform_free_argv(argv: platform_argv) void = free_strlist(argv);

fn platform_setname(cmd: *command, name: str) (void | nomem) = {
	cmd.argv[0] = c::fromstr(name)?;
};

export type platform_env = strlist;

fn platfrom_newenv() platform_env = [];

fn platform_dup_env(env: []str) (platform_env | nomem) = {
	let ok = false;
	let dup: platform_env = [];
	defer if (!ok) platform_free_env(dup);

	for (let e .. env) {
		let centry = c::fromstr(e)?;
		if (append(dup, centry) is nomem) {
			free(centry);
			return nomem;
		};
	};
	append(dup, null)?;

	ok = true;
	return dup;
};

fn platform_free_env(env: platform_env) void = free_strlist(env);

fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!;

fn platform_setenv(
	cmd: *command,
	key: str,
	value: str
) (void | errors::invalid | nomem) = {
	if (len(cmd.env) == 0) {
		append(cmd.env, null)?;
	};

	let entry = strings::join("=", key, value)?;
	defer free(entry);
	let centry = c::fromstr(entry)?;

	if (insert(cmd.env[len(cmd.env)-1], centry) is nomem) {
		free(centry);
		return nomem;
	};
};

fn platform_unsetenv(cmd: *command, key: str) (void | errors::invalid) = {
	// XXX: This can be a binary search
	for (let i = 0z; cmd.env[i] != null; i += 1) {
		let e = c::tostr(cmd.env[i]: *const c::char)!;
		if (strings::cut(e, "=").0 == key) {
			free(cmd.env[i]);
			delete(cmd.env[i]);
			break;
		};
	};
};

export type platform_cmd = io::file;

// Same as [[cmd]] except that executable file is determined by [[io::file]].
// This function is not portable.
export fn cmdfile(file: io::file, name: str, args: str...) (command | nomem) = {
	let argv = platform_newargv(name, args...)?;

	let env = match (platform_dup_env(os::getenvs())) {
	case let env: platform_env =>
		yield env;
	case nomem =>
		platform_free_argv(argv);
		return nomem;
	};

	return command {
		platform = file,
		argv = argv,
		env = env,
		files = [],
		dir = "",
	};
};