Added hidden options to be able to define your own device delay before loading ART...
[open-ps2-loader.git] / src / config.c
blob20a91e0e3db9dcb1ee9dab8241a890e061ac0e86
1 /*
2 Copyright 2009, Ifcaro & volca
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include "include/usbld.h"
8 #include "include/util.h"
9 #include "include/ioman.h"
10 #include <string.h>
12 #define CONFIG_INDEX_OPL 0
13 #define CONFIG_INDEX_LAST 1
14 #define CONFIG_INDEX_APPS 2
16 static u32 currentUID = 0;
17 static config_set_t configFiles[CONFIG_FILE_NUM];
18 static char configPath[255] = "mc?:SYS-CONF/IPCONFIG.DAT";
20 static int strToColor(const char *string, unsigned char *color) {
21 int cnt=0, n=0;
22 color[0]=0;
23 color[1]=0;
24 color[2]=0;
26 if (!string || !*string) return 0;
27 if (string[0]!='#') return 0;
29 string++;
31 while (*string) {
32 int fh = fromHex(*string);
33 if (fh >= 0) {
34 color[n] = color[n] * 16 + fh;
35 } else {
36 break;
39 // Two characters per color
40 if(cnt==1) {
41 cnt=0;
42 n++;
43 }else{
44 cnt++;
47 string++;
50 return 1;
53 /// true if given a whitespace character
54 int isWS(char c) {
55 return c == ' ' || c == '\t';
58 static int splitAssignment(char* line, char* key, size_t keymax, char* val, size_t valmax) {
59 // skip whitespace
60 for (;isWS(*line); ++line);
62 // find "=".
63 // If found, the text before is key, after is val.
64 // Otherwise malformed string is encountered
66 char* eqpos = strchr(line, '=');
68 if (eqpos) {
69 // copy the name and the value
70 size_t keylen = min(keymax, eqpos - line);
72 strncpy(key, line, keylen);
74 eqpos++;
76 size_t vallen = min(valmax, strlen(line) - (eqpos - line));
77 strncpy(val, eqpos, vallen);
80 return (int) eqpos;
83 static int parsePrefix(char* line, char* prefix) {
84 // find "=".
85 // If found, the text before is key, after is val.
86 // Otherwise malformed string is encountered
87 char* colpos = strchr(line, ':');
89 if (colpos && colpos != line) {
90 // copy the name and the value
91 strncpy(prefix, line, colpos - line);
93 return 1;
94 } else {
95 return 0;
99 static int configKeyValidate(const char* key) {
100 if (strlen(key) == 0)
101 return 0;
103 return !strchr(key, '=');
106 static struct config_value_t* allocConfigItem(const char* key, const char* val) {
107 struct config_value_t* it = (struct config_value_t*) malloc(sizeof(struct config_value_t));
108 strncpy(it->key, key, 32);
109 it->key[min(strlen(key), 31)] = '\0';
110 strncpy(it->val, val, 255);
111 it->val[min(strlen(val), 254)] = '\0';
112 it->next = NULL;
114 return it;
117 /// Low level key addition. Does not check for uniqueness.
118 static void addConfigValue(config_set_t* configSet, const char* key, const char* val) {
119 if (!configSet->tail) {
120 configSet->head = allocConfigItem(key, val);
121 configSet->tail = configSet->head;
122 } else {
123 configSet->tail->next = allocConfigItem(key, val);
124 configSet->tail = configSet->tail->next;
128 static struct config_value_t* getConfigItemForName(config_set_t* configSet, const char* name) {
129 struct config_value_t* val = configSet->head;
131 while (val) {
132 if (strncmp(val->key, name, 32) == 0)
133 break;
135 val = val->next;
138 return val;
141 void configInit(char *prefix) {
142 char path[255];
144 if (prefix)
145 snprintf(configPath, 255, "%s/IPCONFIG.DAT", prefix);
146 else
147 prefix = gBaseMCDir;
149 snprintf(path, 255, "%s/conf_opl.cfg", prefix);
150 configAlloc(CONFIG_OPL, &configFiles[CONFIG_INDEX_OPL], path);
151 snprintf(path, 255, "%s/conf_last.cfg", prefix);
152 configAlloc(CONFIG_LAST, &configFiles[CONFIG_INDEX_LAST], path);
153 snprintf(path, 255, "%s/conf_apps.cfg", prefix);
154 configAlloc(CONFIG_APPS, &configFiles[CONFIG_INDEX_APPS], path);
157 void configEnd() {
158 int index = 0;
159 while(index < CONFIG_FILE_NUM) {
160 config_set_t *configSet = &configFiles[index];
162 configClear(configSet);
163 free(configSet->filename);
164 configSet->filename = NULL;
165 index++;
169 config_set_t *configAlloc(int type, config_set_t *configSet, char *fileName) {
170 if (!configSet)
171 configSet = (config_set_t*) malloc(sizeof(config_set_t));
173 configSet->uid = ++currentUID;
174 configSet->type = type;
175 configSet->head = NULL;
176 configSet->tail = NULL;
177 if (fileName) {
178 int length = strlen(fileName) + 1;
179 configSet->filename = (char*) malloc(length * sizeof(char));
180 memcpy(configSet->filename, fileName, length);
181 } else
182 configSet->filename = NULL;
183 configSet->modified = 0;
184 return configSet;
187 void configFree(config_set_t *configSet) {
188 configClear(configSet);
189 free(configSet->filename);
190 free(configSet);
191 configSet = NULL;
194 config_set_t *configGetByType(int type) {
195 int index = 0;
196 while(index < CONFIG_FILE_NUM) {
197 config_set_t *configSet = &configFiles[index];
199 if (configSet->type == type)
200 return configSet;
201 index++;
203 return NULL;
206 int configSetStr(config_set_t* configSet, const char* key, const char* value) {
207 if (!configKeyValidate(key))
208 return 0;
210 struct config_value_t *it = getConfigItemForName(configSet, key);
212 if (it) {
213 if (strncmp(it->val, value, 255) != 0) {
214 strncpy(it->val, value, 255);
215 it->val[min(strlen(value), 254)] = '\0';
216 if (it->key[0] != '#')
217 configSet->modified = 1;
219 } else {
220 addConfigValue(configSet, key, value);
221 if (key[0] != '#')
222 configSet->modified = 1;
225 return 1;
228 // sets the value to point to the value str in the config. Do not overwrite - it will overwrite the string in config
229 int configGetStr(config_set_t* configSet, const char* key, char** value) {
230 if (!configKeyValidate(key))
231 return 0;
233 struct config_value_t *it = getConfigItemForName(configSet, key);
235 if (it) {
236 *value = it->val;
237 return 1;
238 } else
239 return 0;
242 void configGetStrCopy(config_set_t* configSet, const char* key, char* value) {
243 char *valref = NULL;
244 if (configGetStr(configSet, key, &valref))
245 strncpy(value, valref, 32);
246 else
247 value[0] = '\0';
250 int configSetInt(config_set_t* configSet, const char* key, const int value) {
251 char tmp[12];
252 snprintf(tmp, 12, "%d", value);
253 return configSetStr(configSet, key, tmp);
256 int configGetInt(config_set_t* configSet, const char* key, int* value) {
257 char *valref = NULL;
258 if (configGetStr(configSet, key, &valref)) {
259 *value = atoi(valref);
260 return 1;
261 } else {
262 return 0;
266 int configSetColor(config_set_t* configSet, const char* key, unsigned char* color) {
267 char tmp[8];
268 snprintf(tmp, 8, "#%02X%02X%02X", color[0], color[1], color[2]);
269 return configSetStr(configSet, key, tmp);
272 int configGetColor(config_set_t* configSet, const char* key, unsigned char* color) {
273 char *valref = NULL;
274 if (configGetStr(configSet, key, &valref)) {
275 strToColor(valref, color);
276 return 1;
277 } else {
278 return 0;
282 int configRemoveKey(config_set_t* configSet, const char* key) {
283 if (!configKeyValidate(key))
284 return 0;
286 struct config_value_t* val = configSet->head;
287 struct config_value_t* prev = NULL;
289 while (val) {
290 if (strncmp(val->key, key, 32) == 0) {
291 if (key[0] != '#')
292 configSet->modified = 1;
294 if (val == configSet->tail)
295 configSet->tail = prev;
297 val = val->next;
298 if (prev) {
299 free(prev->next);
300 prev->next = val;
302 else {
303 free(configSet->head);
304 configSet->head = val;
306 } else {
307 prev = val;
308 val = val->next;
312 return 1;
315 void configReadIP() {
316 int fd = openFile(configPath, O_RDONLY);
317 if (fd >= 0) {
318 char ipconfig[255];
319 int size = getFileSize(fd);
320 fioRead(fd, &ipconfig, size);
321 fioClose(fd);
323 sscanf(ipconfig, "%d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d", &ps2_ip[0], &ps2_ip[1], &ps2_ip[2], &ps2_ip[3],
324 &ps2_netmask[0], &ps2_netmask[1], &ps2_netmask[2], &ps2_netmask[3],
325 &ps2_gateway[0], &ps2_gateway[1], &ps2_gateway[2], &ps2_gateway[3]);
328 return;
331 void configWriteIP() {
332 int fd = openFile(configPath, O_WRONLY | O_CREAT);
333 if (fd >= 0) {
334 char ipconfig[255];
335 sprintf(ipconfig, "%d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d\r\n", ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3],
336 ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3],
337 ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
339 fioWrite(fd, ipconfig, strlen(ipconfig));
340 fioClose(fd);
341 gIPConfigChanged = 0;
345 // dst has to have 5 bytes space
346 void configGetDiscIDBinary(config_set_t* configSet, void* dst) {
347 memset(dst, 0, 5);
349 char *gid = NULL;
350 if (configGetStr(configSet, CONFIG_ITEM_DNAS, &gid)) {
351 // convert from hex to binary
352 char* cdst = dst;
353 int p = 0;
354 while (*gid && p < 10) {
355 int dv = -1;
357 while (dv < 0 && *gid) // skip spaces, etc
358 dv = fromHex(*(gid++));
360 if (dv < 0)
361 break;
363 *cdst = *cdst * 16 + dv;
364 if ((++p & 1) == 0)
365 cdst++;
370 int configRead(config_set_t* configSet) {
371 file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_RDONLY, 0, 4096);
372 if (!fileBuffer) {
373 LOG("CONFIG No file %s.\n", configSet->filename);
374 configSet->modified = 0;
375 return 0;
378 char* line;
379 unsigned int lineno = 0;
381 char prefix[32];
382 memset(prefix, 0, sizeof(prefix));
384 while (readFileBuffer(fileBuffer, &line)) {
385 lineno++;
387 char key[32], val[255];
388 memset(key, 0, sizeof(key));
389 memset(val, 0, sizeof(val));
391 if (splitAssignment(line, key, sizeof(key), val, sizeof(val))) {
392 /* if the line does not start with whitespace,
393 * the prefix ends and we have to reset it
395 if (!isWS(line[0]))
396 memset(prefix, 0, sizeof(prefix));
398 // insert config value
399 if (prefix[0]) {
400 // we have a prefix
401 char composedKey[66];
403 snprintf(composedKey, 65, "%s_%s", prefix, key);
404 composedKey[65] = '\0';
406 configSetStr(configSet, composedKey, val);
407 } else {
408 configSetStr(configSet, key, val);
410 } else if (parsePrefix(line, prefix)) {
411 // prefix is set, that's about it
412 } else {
413 LOG("CONFIG Malformed file '%s' line %d: '%s'\n", configSet->filename, lineno, line);
416 closeFileBuffer(fileBuffer);
417 configSet->modified = 0;
418 return configSet->type;
421 int configWrite(config_set_t* configSet) {
422 if (configSet->modified) {
423 // BUG in PFS: O_TRUNC doesn't work, so we remove the file and re-create it
424 if (strncmp(configSet->filename, "pfs0:", 5) == 0)
425 fioRemove(configSet->filename);
427 file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_WRONLY | O_CREAT | O_TRUNC, 0, 4096);
428 if (fileBuffer) {
429 char line[512];
431 struct config_value_t* cur = configSet->head;
432 while (cur) {
433 if ((cur->key[0] != '\0') && (cur->key[0] != '#')) {
434 snprintf(line, 512, "%s=%s\r\n", cur->key, cur->val); // add windows CR+LF (0x0D 0x0A)
435 writeFileBuffer(fileBuffer, line, strlen(line));
438 // and advance
439 cur = cur->next;
442 closeFileBuffer(fileBuffer);
443 configSet->modified = 0;
444 return 1;
446 return 0;
448 return 1;
451 void configClear(config_set_t* configSet) {
452 while (configSet->head) {
453 struct config_value_t* cur = configSet->head;
454 configSet->head = cur->next;
456 free(cur);
459 configSet->head = NULL;
460 configSet->tail = NULL;
461 configSet->modified = 1;
464 int configReadMulti(int types) {
465 int result = 0;
467 if (CONFIG_OPL & types)
468 configReadIP();
470 int index = 0;
471 while(index < CONFIG_FILE_NUM) {
472 config_set_t *configSet = &configFiles[index];
474 if (configSet->type & types) {
475 configClear(configSet);
476 result |= configRead(configSet);
478 index++;
481 return result;
484 int configWriteMulti(int types) {
485 int result = 0;
487 if ((CONFIG_OPL & types) && gIPConfigChanged)
488 configWriteIP();
490 int index = 0;
491 while(index < CONFIG_FILE_NUM) {
492 config_set_t *configSet = &configFiles[index];
494 if (configSet->type & types)
495 result += configWrite(configSet);
496 index++;
499 return result;
502 #ifdef VMC
503 void configGetVMC(config_set_t* configSet, char* vmc, int slot) {
504 char *valref = NULL;
505 char gkey[255];
506 snprintf(gkey, 255, "%s_%d", CONFIG_ITEM_VMC, slot);
507 if (configGetStr(configSet, gkey, &valref))
508 strncpy(vmc, valref, 32);
509 else
510 vmc[0] = '\0';
513 void configSetVMC(config_set_t* configSet, const char* vmc, int slot) {
514 char gkey[255];
515 if(vmc[0] == '\0') {
516 configRemoveVMC(configSet, slot);
517 return;
519 snprintf(gkey, 255, "%s_%d", CONFIG_ITEM_VMC, slot);
520 configSetStr(configSet, gkey, vmc);
523 void configRemoveVMC(config_set_t* configSet, int slot) {
524 char gkey[255];
525 snprintf(gkey, 255, "%s_%d", CONFIG_ITEM_VMC, slot);
526 configRemoveKey(configSet, gkey);
528 #endif