z_mirror/hare-fmm

git clone https://git.raiguard.me/z_mirror/hare-fmm

Caleb HeuerConvert to for-each loops and fix some potential memory issues74b341b

trunk
2.8 KiB110 linesraw
1use encoding::json;
2use fmt;
3use fs;
4use io;
5use os;
6use os::exec;
7use path;
8use strings;
9
10type modfile = struct {
11	dependencies: ([]dependency | void),
12	ftype: fs::mode,
13	ident: modident,
14	path: str,
15};
16
17type modfile_error = (fs::error | version_error);
18
19// Frees resources related to a [[modfile]].
20fn modfile_free(file: *modfile) void = {
21	free(file.path);
22	modident_free(&file.ident);
23	match (file.dependencies) {
24	case let deps: []dependency =>
25		dependency_free_all(deps);
26	case => void;
27	};
28};
29
30// Constructs a [[modfile]] from a directory entry. The return value must be
31// freed with [[modfile_free]].
32fn modfile_load(
33	path: str,
34	dirent: *fs::dirent
35) (modfile | void | modfile_error) = {
36	if (dirent.name == "."
37			|| dirent.name == ".."
38			|| dirent.name == "mod-list.json"
39			|| dirent.name == "mod-settings.dat")
40		return void;
41
42	let filepath = path::init(path, dirent.name)!;
43	let file = modfile {
44		dependencies = void,
45		ftype = dirent.ftype,
46		ident = modident_parse(dirent.name),
47		path = strings::dup(path::string(&filepath))!,
48	};
49	// Modfiles must have versions
50	if (file.ident.1 is void) {
51		if (!modfile_read_info(&file)) {
52			modfile_free(&file);
53			fmt::errorln("Unable to get info for", dirent.name)!;
54			return void;
55		};
56	};
57
58	return file;
59};
60
61// Extracts and parses a modfile's info.json properties.
62fn modfile_read_info(mod: *modfile) bool = {
63	// Get info.json contents
64	const json = if (fs::isdir(mod.ftype) || fs::islink(mod.ftype)) {
65		const info_path = path::init(mod.path, "info.json")!;
66		let file = os::open(path::string(&info_path))!;
67		yield json::load(file)! as json::object;
68	} else if (fs::isfile(mod.ftype)) {
69		const info_path = path::init(mod.ident.0, "info.json")!;
70		// Extract info.json from zip file
71		let cmd = exec::cmd("unzip", "-p", mod.path, path::string(&info_path))!;
72		let pipe = exec::pipe();
73		exec::addfile(&cmd, os::stdout_file, pipe.1)!;
74		let proc = exec::start(&cmd)!;
75		io::close(pipe.1)!;
76
77		let data = io::drain(pipe.0)!;
78		defer free(data);
79		io::close(pipe.0)!;
80		exec::wait(&proc)!;
81
82		yield json::loadstr(strings::fromutf8(data)!)! as json::object;
83	} else {
84		return false;
85	};
86	defer json::finish(json);
87
88	// Ident
89	const name = json::get(&json, "name") as *json::value;
90	const name = *name as str;
91	const version = json::get(&json, "version") as *json::value;
92	const version = version_parse(*version as str)!;
93	modident_free(&mod.ident);
94	mod.ident = (strings::dup(name)!, version);
95
96	// Dependencies
97	mod.dependencies = match (json::get(&json, "dependencies")) {
98	case let deps: *json::value =>
99		const deps = *deps as []json::value;
100		let output: []dependency = [];
101		for (let dep &.. deps) {
102			// TODO: Error handling
103			const dep_str = *dep as str;
104			append(output, dependency_parse(dep_str)!)!;
105		};
106		yield output;
107	};
108
109	return true;
110};