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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
// MIT License, Copyright (c) 2021 Marvin Borner
#include <cfg.h>
#include <dev.h>
#include <lib.h>
#include <log.h>
#include <pnc.h>
// Keys
#define TIMEOUT "TIMEOUT"
#define PATH "PATH"
// Config struct (gettable using cfg_get)
struct {
u32 timeout;
struct {
u8 exists : 1;
char name[64];
char path[64];
} elem[16]; // Up to 16 different selections
} cfg = { 0 };
// Config file contents (if found)
static char file[1024] = { 0 };
// Find config file
static u8 cfg_find(struct dev *dev)
{
if (!dev->fs.read)
return 0; // No fs found or not readable - continue!
s32 res = dev->fs.read("/boot/segelboot.cfg", file, 0, sizeof(file), dev);
if (res > 0)
return 1; // Break foreach
// Continue foreach
return 0;
}
// Checks if index is appropriate as some key/value need to be in element
static void cfg_in_element(u8 index)
{
if (index == 0xff)
panic("No element name given\n");
}
// Add/overwrite value by key and element index
static void cfg_add(u8 index, enum cfg_key key, const char *value)
{
cfg.elem[index].exists = 1;
switch (key) {
case CFG_NAME:
cfg_in_element(index);
strlcpy(cfg.elem[index].name, value, sizeof(cfg.elem[index].name));
break;
case CFG_TIMEOUT:
cfg.timeout = atoi(value);
break;
case CFG_PATH:
cfg_in_element(index);
strlcpy(cfg.elem[index].path, value, sizeof(cfg.elem[index].path));
break;
case CFG_NONE:
default:
panic("Invalid config\n");
}
}
// TODO: This code is kind of messy
// Structure per line: KEY=VALUE
static void cfg_parse(void)
{
// Element index
u8 elem = 0xff;
// Value per key
char value[64] = { 0 };
u8 value_index = 0;
// States
enum cfg_key current = CFG_NONE; // Value key type
u8 state = 0; // 0 is key, 1 is value, 2 is elem
const char *start = file; // Start is at the beginning of the key
for (const char *p = start; *p; p++) {
if (state == 0) {
// We're at key parsing
if (*p == '\n') { // A key can't just end but ok
start = p + 1;
} else if (*p == '#') {
state = 2; // Let's parse the element name
p++;
continue;
} else if (*p != '=') {
continue;
}
// The key is now at start until p
u8 diff = p - start;
// Timeout key
if (diff == sizeof(TIMEOUT) - 1 && memcmp(start, TIMEOUT, diff) == 0) {
current = CFG_TIMEOUT;
state = 1;
continue;
}
// Path key
if (diff == sizeof(PATH) - 1 && memcmp(start, PATH, diff) == 0) {
current = CFG_PATH;
state = 1;
continue;
}
} else if (state == 1) {
// We're at value parsing
assert(value_index + 1 < (u8)sizeof(value));
if (*p == '\n') { // Finished
value[value_index] = 0;
cfg_add(elem, current, value);
value_index = 0;
state = 0;
p--; // Repeat parse normally
} else {
value[value_index++] = *p;
}
} else if (state == 2) {
// We're at element name parsing
assert(value_index + 1 < (u8)sizeof(value));
if (*p == '\n') { // Finished
elem = elem == 0xff ? 0 : elem + 1;
value[value_index] = 0;
cfg_add(elem, CFG_NAME, value);
value_index = 0;
state = 0;
p--; // Repeat parse normally
} else {
value[value_index++] = *p;
}
}
}
}
const void *cfg_get(u8 index, enum cfg_key key)
{
switch (key) {
case CFG_NAME:
return &cfg.elem[index].path;
case CFG_TIMEOUT:
return &cfg.timeout;
case CFG_PATH:
return &cfg.elem[index].path;
case CFG_NONE:
default:
return NULL;
}
}
void cfg_print(void)
{
log("[CFG] Global: %d\n", cfg.timeout);
for (u8 i = 0; i < COUNT(cfg.elem) && cfg.elem[i].exists; i++)
log("[CFG] Element: %s at %s\n", cfg.elem[i].name, cfg.elem[i].path);
}
void cfg_exec(void)
{
dev_foreach(DEV_DISK, &cfg_find);
if (!file[0])
panic("No config found\n");
cfg_parse();
}
|