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);
}
}
|