summaryrefslogtreecommitdiff
path: root/config.c
blob: 821839956f840db87d859913e135b89efc1c2bb6 (plain)
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
// Read a configuration file.
// Config files are formatted as several sections, each containing key = value pairs.
// e.g.:
// [section1]
// thing1 = 33
// thing2 = 454
// [section2]
// asdf = 123

typedef enum {
	SECTION_NONE,
	SECTION_KEYBOARD
} Section;

void config_read(Ted *ted, char const *filename) {
	FILE *fp = fopen(filename, "rb");
	if (fp) {
		u32 line_number = 1;
		int line_cap = 4096;
		char *line = ted_malloc(ted, (size_t)line_cap);
		if (line) {
			Section section = SECTION_NONE;

			while (fgets(line, line_cap, fp)) {
				char *newline = strchr(line, '\n');
				if (newline || feof(fp)) {
					if (newline) *newline = '\0';

					bool error = false;

					// ok, we've now read a line.
					switch (line[0]) {
					case '#': // comment
					case '\0': // blank line
						break;
					case '[': { // section header
					#define SECTION_HEADER_HELP "Section headers should look like this: [section-name]"
						char *closing = strchr(line, ']');
						if (!closing) {
							ted_seterr(ted, "%s:" U32_FMT ": Unmatched [. " SECTION_HEADER_HELP, filename, line_number);
							error = true;
						} else if (closing[1] != '\0') {
							ted_seterr(ted, "%s:" U32_FMT ": Text after section. " SECTION_HEADER_HELP, filename, line_number);
							error = true;
						} else {
							*closing = '\0';
							char *section_name = line + 1;
							if (streq(section_name, "keyboard")) {
								section = SECTION_KEYBOARD;
							} else {
								ted_seterr(ted, "%s:" U32_FMT ": Unrecognized section: [%s].", filename, line_number, section_name);
								error = true;
							}
						}
					} break;
					}

					if (error) break;

					++line_number;
				} else {
					ted_seterr(ted, "%s:" U32_FMT ": Line is too long.", filename, line_number);
					break;
				}
			}
		}
		free(line);
		if (ferror(fp))
			ted_seterr(ted, "Error reading %s.", filename);
		fclose(fp);
	} else {
		ted_seterr(ted, "Couldn't open file %s.", filename);
	}
}