File: system.ha

package info (click to toggle)
hare 0.26.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 7,352 kB
  • sloc: asm: 1,374; makefile: 123; sh: 117; lisp: 101
file content (87 lines) | stat: -rw-r--r-- 2,039 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
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>

use bufio;
use encoding::utf8;
use fs;
use io;
use os;
use strings;

@init fn init() void = {
	// Done in a separate function so we can discard errors here
	_ = load_systemdb();
};

fn load_systemdb() (void | fs::error | io::error | utf8::invalid | nomem) = {
	const file = os::open(SYSTEM_DB)?;
	defer io::close(file)!;

	let sc = bufio::newscanner(file);
	defer bufio::finish(&sc);

	for (let line => bufio::scan_line(&sc)?) {
		line = strings::trim(line);
		if (strings::hasprefix(line, "#") || len(line) == 0) {
			continue;
		};

		const (mime, exts) = strings::cut(line, "\t");
		exts = strings::trim(exts);
		if (len(exts) == 0) {
			continue;
		};
		mime = strings::trim(mime);

		mime = strings::dup(mime)?;

		let entry = match (alloc(mimetype { mime = mime, exts = [] })) {
		case let mt: *mimetype =>
			yield mt;
		case nomem =>
			// We intentionally free on the error path here
			// instead of having a `defer if (err)` block above.
			// Once the mimetype is allocated, the mimetype_free
			// function will take care of freeing the duplicated
			// mime string. So freeing both the mimetype and the
			// mime string on error would be a double-free.
			free(mime);
			return nomem;
		};
		let err = false;
		defer if (err) mimetype_free(entry);

		const tok = strings::tokenize(exts, " ");
		for (let ext => strings::next_token(&tok)) {
			ext = match(strings::dup(ext)) {
			case let s: str =>
				yield s;
			case nomem =>
				err = true;
				return nomem;
			};
			match (append(entry.exts, ext)) {
			case void => void;
			case nomem =>
				// This case is similar to the comment above.
				free(ext);
				err = true;
				return nomem;
			};
		};
		match (register_heap(entry)) {
		case void => void;
		case nomem =>
			err = true;
			return nomem;
		};
	};
};

fn register_heap(mime: *mimetype) (void | nomem) = {
	let i = len(heap_db);
	append(heap_db, mime)?;
	for (i < len(heap_db); i += 1) {
		hashtable_insert(heap_db[i])?;
	};
};