extracted code branching from ItemsList drawing and main drawing method
[open-ps2-loader.git] / src / config.c
blobcf02c0273719bd15abc53198b75a7cbf594c3f23
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_COMPAT 1
14 #define CONFIG_INDEX_DNAS 2
15 #define CONFIG_INDEX_VMC 3
16 #define CONFIG_INDEX_LAST 4
17 #define CONFIG_INDEX_APPS 5
18 #define CONFIG_INDEX_VMODE 6
20 static config_set_t configFiles[CONFIG_FILE_NUM];
21 static char configPath[255] = "mc?:SYS-CONF/IPCONFIG.DAT";
23 static int strToColor(const char *string, unsigned char *color) {
24 int cnt=0, n=0;
25 color[0]=0;
26 color[1]=0;
27 color[2]=0;
29 if (!string || !*string) return 0;
30 if (string[0]!='#') return 0;
32 string++;
34 while (*string) {
35 int fh = fromHex(*string);
36 if (fh >= 0) {
37 color[n] = color[n] * 16 + fh;
38 } else {
39 break;
42 // Two characters per color
43 if(cnt==1) {
44 cnt=0;
45 n++;
46 }else{
47 cnt++;
50 string++;
53 return 1;
56 /// true if given a whitespace character
57 int isWS(char c) {
58 return c == ' ' || c == '\t';
61 static int splitAssignment(char* line, char* key, size_t keymax, char* val, size_t valmax) {
62 // skip whitespace
63 for (;isWS(*line); ++line);
65 // find "=".
66 // If found, the text before is key, after is val.
67 // Otherwise malformed string is encountered
69 char* eqpos = strchr(line, '=');
71 if (eqpos) {
72 // copy the name and the value
73 size_t keylen = min(keymax, eqpos - line);
75 strncpy(key, line, keylen);
77 eqpos++;
79 size_t vallen = min(valmax, strlen(line) - (eqpos - line));
80 strncpy(val, eqpos, vallen);
83 return (int) eqpos;
86 static int parsePrefix(char* line, char* prefix) {
87 // find "=".
88 // If found, the text before is key, after is val.
89 // Otherwise malformed string is encountered
90 char* colpos = strchr(line, ':');
92 if (colpos && colpos != line) {
93 // copy the name and the value
94 strncpy(prefix, line, colpos - line);
96 return 1;
97 } else {
98 return 0;
102 static int configKeyValidate(const char* key) {
103 if (strlen(key) == 0)
104 return 0;
106 return !strchr(key, '=');
109 static struct config_value_t* allocConfigItem(const char* key, const char* val) {
110 struct config_value_t* it = (struct config_value_t*) malloc(sizeof(struct config_value_t));
111 strncpy(it->key, key, 32);
112 it->key[min(strlen(key), 31)] = '\0';
113 strncpy(it->val, val, 255);
114 it->val[min(strlen(val), 254)] = '\0';
115 it->next = NULL;
117 return it;
120 /// Low level key addition. Does not check for uniqueness.
121 static void addConfigValue(config_set_t* configSet, const char* key, const char* val) {
122 if (!configSet->tail) {
123 configSet->head = allocConfigItem(key, val);
124 configSet->tail = configSet->head;
125 } else {
126 configSet->tail->next = allocConfigItem(key, val);
127 configSet->tail = configSet->tail->next;
131 static struct config_value_t* getConfigItemForName(config_set_t* configSet, const char* name) {
132 struct config_value_t* val = configSet->head;
134 while (val) {
135 if (strncmp(val->key, name, 32) == 0)
136 break;
138 val = val->next;
141 return val;
144 void configInit(char *prefix) {
145 char path[255];
147 if (prefix)
148 snprintf(configPath, 255, "%s/IPCONFIG.DAT", prefix);
149 else
150 prefix = gBaseMCDir;
152 snprintf(path, 255, "%s/conf_opl.cfg", prefix);
153 configAlloc(CONFIG_OPL, &configFiles[CONFIG_INDEX_OPL], path);
154 snprintf(path, 255, "%s/conf_compatibility.cfg", prefix);
155 configAlloc(CONFIG_COMPAT, &configFiles[CONFIG_INDEX_COMPAT], path);
156 snprintf(path, 255, "%s/conf_dnas.cfg", prefix);
157 configAlloc(CONFIG_DNAS, &configFiles[CONFIG_INDEX_DNAS], path);
158 snprintf(path, 255, "%s/conf_vmc.cfg", prefix);
159 configAlloc(CONFIG_VMC, &configFiles[CONFIG_INDEX_VMC], path);
160 snprintf(path, 255, "%s/conf_last.cfg", prefix);
161 configAlloc(CONFIG_LAST, &configFiles[CONFIG_INDEX_LAST], path);
162 snprintf(path, 255, "%s/conf_apps.cfg", prefix);
163 configAlloc(CONFIG_APPS, &configFiles[CONFIG_INDEX_APPS], path);
164 snprintf(path, 255, "%s/conf_vmode.cfg", prefix);
165 configAlloc(CONFIG_VMODE, &configFiles[CONFIG_INDEX_VMODE], path);
168 void configEnd() {
169 int index = 0;
170 while(index < CONFIG_FILE_NUM) {
171 config_set_t *configSet = &configFiles[index];
173 configClear(configSet);
174 free(configSet->filename);
175 configSet->filename = NULL;
176 index++;
180 config_set_t *configAlloc(int type, config_set_t *configSet, char *fileName) {
181 if (!configSet)
182 configSet = (config_set_t*) malloc(sizeof(config_set_t));
184 configSet->type = type;
185 configSet->head = NULL;
186 configSet->tail = NULL;
187 if (fileName) {
188 int length = strlen(fileName) + 1;
189 configSet->filename = (char*) malloc(length * sizeof(char));
190 memcpy(configSet->filename, fileName, length);
191 } else
192 configSet->filename = NULL;
193 configSet->modified = 0;
194 return configSet;
197 void configFree(config_set_t *configSet) {
198 configClear(configSet);
199 free(configSet->filename);
200 free(configSet);
201 configSet = NULL;
204 config_set_t *configGetByType(int type) {
205 int index = 0;
206 while(index < CONFIG_FILE_NUM) {
207 config_set_t *configSet = &configFiles[index];
209 if (configSet->type == type)
210 return configSet;
211 index++;
213 return NULL;
216 int configSetStr(config_set_t* configSet, const char* key, const char* value) {
217 if (!configKeyValidate(key))
218 return 0;
220 struct config_value_t *it = getConfigItemForName(configSet, key);
222 if (it) {
223 if (strncmp(it->val, value, 255) != 0) {
224 strncpy(it->val, value, 255);
225 it->val[min(strlen(value), 254)] = '\0';
226 if (it->key[0] != '#')
227 configSet->modified = 1;
229 } else {
230 addConfigValue(configSet, key, value);
231 if (key[0] != '#')
232 configSet->modified = 1;
235 return 1;
238 // sets the value to point to the value str in the config. Do not overwrite - it will overwrite the string in config
239 int configGetStr(config_set_t* configSet, const char* key, char** value) {
240 if (!configKeyValidate(key))
241 return 0;
243 struct config_value_t *it = getConfigItemForName(configSet, key);
245 if (it) {
246 *value = it->val;
247 return 1;
248 } else
249 return 0;
252 int configSetInt(config_set_t* configSet, const char* key, const int value) {
253 char tmp[12];
254 snprintf(tmp, 12, "%d", value);
255 return configSetStr(configSet, key, tmp);
258 int configGetInt(config_set_t* configSet, char* key, int* value) {
259 char *valref = NULL;
260 if (configGetStr(configSet, key, &valref)) {
261 *value = atoi(valref);
262 return 1;
263 } else {
264 return 0;
268 int configSetColor(config_set_t* configSet, const char* key, unsigned char* color) {
269 char tmp[8];
270 snprintf(tmp, 8, "#%02X%02X%02X", color[0], color[1], color[2]);
271 return configSetStr(configSet, key, tmp);
274 int configGetColor(config_set_t* configSet, const char* key, unsigned char* color) {
275 char *valref = NULL;
276 if (configGetStr(configSet, key, &valref)) {
277 strToColor(valref, color);
278 return 1;
279 } else {
280 return 0;
284 int configRemoveKey(config_set_t* configSet, const char* key) {
285 if (!configKeyValidate(key))
286 return 0;
288 struct config_value_t* val = configSet->head;
289 struct config_value_t* prev = NULL;
291 while (val) {
292 if (strncmp(val->key, key, 32) == 0) {
293 if (key[0] != '#')
294 configSet->modified = 1;
296 if (val == configSet->tail)
297 configSet->tail = prev;
299 val = val->next;
300 if (prev) {
301 free(prev->next);
302 prev->next = val;
304 else {
305 free(configSet->head);
306 configSet->head = val;
308 } else {
309 prev = val;
310 val = val->next;
314 return 1;
317 void configReadIP() {
318 int fd = openFile(configPath, O_RDONLY);
319 if (fd >= 0) {
320 char ipconfig[255];
321 int size = getFileSize(fd);
322 fioRead(fd, &ipconfig, size);
323 fioClose(fd);
325 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],
326 &ps2_netmask[0], &ps2_netmask[1], &ps2_netmask[2], &ps2_netmask[3],
327 &ps2_gateway[0], &ps2_gateway[1], &ps2_gateway[2], &ps2_gateway[3]);
330 return;
333 void configWriteIP() {
334 int fd = openFile(configPath, O_WRONLY | O_CREAT);
335 if (fd >= 0) {
336 char ipconfig[255];
337 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],
338 ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3],
339 ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
341 fioWrite(fd, ipconfig, strlen(ipconfig));
342 fioClose(fd);
346 void configGetDiscID(char* startup, char* discID) {
347 char *valref = NULL;
348 char gkey[255];
349 snprintf(gkey, 255, "%s_discID", startup);
350 if (configGetStr(&configFiles[CONFIG_INDEX_DNAS], gkey, &valref))
351 strncpy(discID, valref, 32);
352 else
353 discID[0] = '\0';
356 void configSetDiscID(char* startup, const char *discID) {
357 char gkey[255];
358 snprintf(gkey, 255, "%s_discID", startup);
359 configSetStr(&configFiles[CONFIG_INDEX_DNAS], gkey, discID);
362 void configRemoveDiscID(char* startup) {
363 char gkey[255];
364 snprintf(gkey, 255, "%s_discID", startup);
365 configRemoveKey(&configFiles[CONFIG_INDEX_DNAS], gkey);
368 // dst has to have 5 bytes space
369 void configGetDiscIDBinary(char* startup, void* dst) {
370 memset(dst, 0, 5);
372 char *gid = NULL;
373 char gkey[255];
374 snprintf(gkey, 255, "%s_discID", startup);
375 if (configGetStr(&configFiles[CONFIG_INDEX_DNAS], gkey, &gid)) {
376 // convert from hex to binary
377 char* cdst = dst;
378 int p = 0;
379 while (*gid && p < 10) {
380 int dv = -1;
382 while (dv < 0 && *gid) // skip spaces, etc
383 dv = fromHex(*(gid++));
385 if (dv < 0)
386 break;
388 *cdst = *cdst * 16 + dv;
389 if ((++p & 1) == 0)
390 cdst++;
395 int configRead(config_set_t* configSet) {
396 file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_RDONLY, 0, 4096);
397 if (!fileBuffer) {
398 LOG("No config %s.\n", configSet->filename);
399 configSet->modified = 0;
400 return 0;
403 char* line;
404 unsigned int lineno = 0;
406 char prefix[32];
407 memset(prefix, 0, sizeof(prefix));
409 while (readFileBuffer(fileBuffer, &line)) {
410 lineno++;
412 char key[32], val[255];
413 memset(key, 0, sizeof(key));
414 memset(val, 0, sizeof(val));
416 if (splitAssignment(line, key, sizeof(key), val, sizeof(val))) {
417 /* if the line does not start with whitespace,
418 * the prefix ends and we have to reset it
420 if (!isWS(line[0]))
421 memset(prefix, 0, sizeof(prefix));
423 // insert config value
424 if (prefix[0]) {
425 // we have a prefix
426 char composedKey[66];
428 snprintf(composedKey, 65, "%s_%s", prefix, key);
429 composedKey[65] = '\0';
431 configSetStr(configSet, composedKey, val);
432 } else {
433 configSetStr(configSet, key, val);
435 } else if (parsePrefix(line, prefix)) {
436 // prefix is set, that's about it
437 } else {
438 LOG("Malformed config file '%s' line %d: '%s'\n", configSet->filename, lineno, line);
441 closeFileBuffer(fileBuffer);
442 configSet->modified = 0;
443 return configSet->type;
446 int configWrite(config_set_t* configSet) {
447 if (configSet->modified) {
448 file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_WRONLY | O_CREAT | O_TRUNC, 0, 4096);
449 if (fileBuffer) {
450 char line[512];
451 struct config_value_t* cur = configSet->head;
453 while (cur) {
454 if ((cur->key[0] != '\0') && (cur->key[0] != '#')) {
455 snprintf(line, 512, "%s=%s\r\n", cur->key, cur->val); // add windows CR+LF (0x0D 0x0A)
456 writeFileBuffer(fileBuffer, line, strlen(line));
459 // and advance
460 cur = cur->next;
463 closeFileBuffer(fileBuffer);
464 configSet->modified = 0;
465 return 1;
467 return 0;
469 return 1;
472 void configClear(config_set_t* configSet) {
473 while (configSet->head) {
474 struct config_value_t* cur = configSet->head;
475 configSet->head = cur->next;
477 free(cur);
480 configSet->head = NULL;
481 configSet->tail = NULL;
482 configSet->modified = 1;
485 int configGetCompatibility(char* startup, int mode, int *dmaMode) {
486 char gkey[255];
487 snprintf(gkey, 255, "%s_%d", startup, mode);
489 unsigned int compatMode;
490 if (!configGetInt(&configFiles[CONFIG_INDEX_COMPAT], gkey, &compatMode))
491 compatMode = 0;
493 if (dmaMode) {
494 *dmaMode = 7; // defaulting to UDMA 4
495 snprintf(gkey, 255, "%s_DMA", startup);
496 configGetInt(&configFiles[CONFIG_INDEX_COMPAT], gkey, dmaMode);
499 return compatMode;
502 void configSetCompatibility(char* startup, int mode, int compatMode, int dmaMode) {
503 char gkey[255];
504 snprintf(gkey, 255, "%s_%d", startup, mode);
505 if (compatMode == 0) // means we want to delete the setting
506 configRemoveKey(&configFiles[CONFIG_INDEX_COMPAT], gkey);
507 else
508 configSetInt(&configFiles[CONFIG_INDEX_COMPAT], gkey, compatMode);
510 if (dmaMode != -1) {
511 snprintf(gkey, 255, "%s_DMA", startup);
512 if (dmaMode == 7) // UDMA 4 is the default so don't save it (useless lines into the conf file)
513 configRemoveKey(&configFiles[CONFIG_INDEX_COMPAT], gkey);
514 else
515 configSetInt(&configFiles[CONFIG_INDEX_COMPAT], gkey, dmaMode);
519 int configReadMulti(int types) {
520 int result = 0;
522 if (CONFIG_OPL & types)
523 configReadIP();
525 int index = 0;
526 while(index < CONFIG_FILE_NUM) {
527 config_set_t *configSet = &configFiles[index];
529 if (configSet->type & types) {
530 configClear(configSet);
531 result |= configRead(configSet);
533 index++;
536 return result;
539 int configWriteMulti(int types) {
540 int result = 0;
542 if ((CONFIG_OPL & types) && gIPConfigChanged)
543 configWriteIP();
545 int index = 0;
546 while(index < CONFIG_FILE_NUM) {
547 config_set_t *configSet = &configFiles[index];
549 if (configSet->type & types)
550 result += configWrite(configSet);
551 index++;
554 return result;
557 #ifdef VMC
558 void configGetVMC(char* startup, char* vmc, int mode, int slot) {
559 char *valref = NULL;
560 char gkey[255];
561 snprintf(gkey, 255, "%s_%d_%d", startup, mode, slot);
562 if (configGetStr(&configFiles[CONFIG_INDEX_VMC], gkey, &valref))
563 strncpy(vmc, valref, 32);
564 else
565 vmc[0] = '\0';
568 void configSetVMC(char* startup, const char* vmc, int mode, int slot) {
569 char gkey[255];
570 if(vmc[0] == '\0') {
571 configRemoveVMC(startup, mode, slot);
572 return;
574 snprintf(gkey, 255, "%s_%d_%d", startup, mode, slot);
575 configSetStr(&configFiles[CONFIG_INDEX_VMC], gkey, vmc);
578 void configRemoveVMC(char *startup, int mode, int slot) {
579 char gkey[255];
580 snprintf(gkey, 255, "%s_%d_%d", startup, mode, slot);
581 configRemoveKey(&configFiles[CONFIG_INDEX_VMC], gkey);
583 #endif