fix for wrapping artefact when display_mode=ALWAYS
[open-ps2-loader.git] / src / config.c
blob8a9a21a60abcaa45e093464d1bcb486ab1e70fdb
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 config_set_t configFiles[CONFIG_FILE_NUM];
17 static char configPath[255] = "mc?:SYS-CONF/IPCONFIG.DAT";
19 static int strToColor(const char *string, unsigned char *color) {
20 int cnt=0, n=0;
21 color[0]=0;
22 color[1]=0;
23 color[2]=0;
25 if (!string || !*string) return 0;
26 if (string[0]!='#') return 0;
28 string++;
30 while (*string) {
31 int fh = fromHex(*string);
32 if (fh >= 0) {
33 color[n] = color[n] * 16 + fh;
34 } else {
35 break;
38 // Two characters per color
39 if(cnt==1) {
40 cnt=0;
41 n++;
42 }else{
43 cnt++;
46 string++;
49 return 1;
52 /// true if given a whitespace character
53 int isWS(char c) {
54 return c == ' ' || c == '\t';
57 static int splitAssignment(char* line, char* key, size_t keymax, char* val, size_t valmax) {
58 // skip whitespace
59 for (;isWS(*line); ++line);
61 // find "=".
62 // If found, the text before is key, after is val.
63 // Otherwise malformed string is encountered
65 char* eqpos = strchr(line, '=');
67 if (eqpos) {
68 // copy the name and the value
69 size_t keylen = min(keymax, eqpos - line);
71 strncpy(key, line, keylen);
73 eqpos++;
75 size_t vallen = min(valmax, strlen(line) - (eqpos - line));
76 strncpy(val, eqpos, vallen);
79 return (int) eqpos;
82 static int parsePrefix(char* line, char* prefix) {
83 // find "=".
84 // If found, the text before is key, after is val.
85 // Otherwise malformed string is encountered
86 char* colpos = strchr(line, ':');
88 if (colpos && colpos != line) {
89 // copy the name and the value
90 strncpy(prefix, line, colpos - line);
92 return 1;
93 } else {
94 return 0;
98 static int configKeyValidate(const char* key) {
99 if (strlen(key) == 0)
100 return 0;
102 return !strchr(key, '=');
105 static struct config_value_t* allocConfigItem(const char* key, const char* val) {
106 struct config_value_t* it = (struct config_value_t*) malloc(sizeof(struct config_value_t));
107 strncpy(it->key, key, 32);
108 it->key[min(strlen(key), 31)] = '\0';
109 strncpy(it->val, val, 255);
110 it->val[min(strlen(val), 254)] = '\0';
111 it->next = NULL;
113 return it;
116 /// Low level key addition. Does not check for uniqueness.
117 static void addConfigValue(config_set_t* configSet, const char* key, const char* val) {
118 if (!configSet->tail) {
119 configSet->head = allocConfigItem(key, val);
120 configSet->tail = configSet->head;
121 } else {
122 configSet->tail->next = allocConfigItem(key, val);
123 configSet->tail = configSet->tail->next;
127 static struct config_value_t* getConfigItemForName(config_set_t* configSet, const char* name) {
128 struct config_value_t* val = configSet->head;
130 while (val) {
131 if (strncmp(val->key, name, 32) == 0)
132 break;
134 val = val->next;
137 return val;
140 void configInit(char *prefix) {
141 char path[255];
143 if (prefix)
144 snprintf(configPath, 255, "%s/IPCONFIG.DAT", prefix);
145 else
146 prefix = gBaseMCDir;
148 snprintf(path, 255, "%s/conf_opl.cfg", prefix);
149 configAlloc(CONFIG_OPL, &configFiles[CONFIG_INDEX_OPL], path);
150 snprintf(path, 255, "%s/conf_last.cfg", prefix);
151 configAlloc(CONFIG_LAST, &configFiles[CONFIG_INDEX_LAST], path);
152 snprintf(path, 255, "%s/conf_apps.cfg", prefix);
153 configAlloc(CONFIG_APPS, &configFiles[CONFIG_INDEX_APPS], path);
156 void configEnd() {
157 int index = 0;
158 while(index < CONFIG_FILE_NUM) {
159 config_set_t *configSet = &configFiles[index];
161 configClear(configSet);
162 free(configSet->filename);
163 configSet->filename = NULL;
164 index++;
168 config_set_t *configAlloc(int type, config_set_t *configSet, char *fileName) {
169 if (!configSet)
170 configSet = (config_set_t*) malloc(sizeof(config_set_t));
172 configSet->type = type;
173 configSet->head = NULL;
174 configSet->tail = NULL;
175 if (fileName) {
176 int length = strlen(fileName) + 1;
177 configSet->filename = (char*) malloc(length * sizeof(char));
178 memcpy(configSet->filename, fileName, length);
179 } else
180 configSet->filename = NULL;
181 configSet->modified = 0;
182 return configSet;
185 void configFree(config_set_t *configSet) {
186 configClear(configSet);
187 free(configSet->filename);
188 free(configSet);
189 configSet = NULL;
192 config_set_t *configGetByType(int type) {
193 int index = 0;
194 while(index < CONFIG_FILE_NUM) {
195 config_set_t *configSet = &configFiles[index];
197 if (configSet->type == type)
198 return configSet;
199 index++;
201 return NULL;
204 int configSetStr(config_set_t* configSet, const char* key, const char* value) {
205 if (!configKeyValidate(key))
206 return 0;
208 struct config_value_t *it = getConfigItemForName(configSet, key);
210 if (it) {
211 if (strncmp(it->val, value, 255) != 0) {
212 strncpy(it->val, value, 255);
213 it->val[min(strlen(value), 254)] = '\0';
214 if (it->key[0] != '#')
215 configSet->modified = 1;
217 } else {
218 addConfigValue(configSet, key, value);
219 if (key[0] != '#')
220 configSet->modified = 1;
223 return 1;
226 // sets the value to point to the value str in the config. Do not overwrite - it will overwrite the string in config
227 int configGetStr(config_set_t* configSet, const char* key, char** value) {
228 if (!configKeyValidate(key))
229 return 0;
231 struct config_value_t *it = getConfigItemForName(configSet, key);
233 if (it) {
234 *value = it->val;
235 return 1;
236 } else
237 return 0;
240 void configGetStrCopy(config_set_t* configSet, const char* key, char* value) {
241 char *valref = NULL;
242 if (configGetStr(configSet, key, &valref))
243 strncpy(value, valref, 32);
244 else
245 value[0] = '\0';
248 int configSetInt(config_set_t* configSet, const char* key, const int value) {
249 char tmp[12];
250 snprintf(tmp, 12, "%d", value);
251 return configSetStr(configSet, key, tmp);
254 int configGetInt(config_set_t* configSet, const char* key, int* value) {
255 char *valref = NULL;
256 if (configGetStr(configSet, key, &valref)) {
257 *value = atoi(valref);
258 return 1;
259 } else {
260 return 0;
264 int configSetColor(config_set_t* configSet, const char* key, unsigned char* color) {
265 char tmp[8];
266 snprintf(tmp, 8, "#%02X%02X%02X", color[0], color[1], color[2]);
267 return configSetStr(configSet, key, tmp);
270 int configGetColor(config_set_t* configSet, const char* key, unsigned char* color) {
271 char *valref = NULL;
272 if (configGetStr(configSet, key, &valref)) {
273 strToColor(valref, color);
274 return 1;
275 } else {
276 return 0;
280 int configRemoveKey(config_set_t* configSet, const char* key) {
281 if (!configKeyValidate(key))
282 return 0;
284 struct config_value_t* val = configSet->head;
285 struct config_value_t* prev = NULL;
287 while (val) {
288 if (strncmp(val->key, key, 32) == 0) {
289 if (key[0] != '#')
290 configSet->modified = 1;
292 if (val == configSet->tail)
293 configSet->tail = prev;
295 val = val->next;
296 if (prev) {
297 free(prev->next);
298 prev->next = val;
300 else {
301 free(configSet->head);
302 configSet->head = val;
304 } else {
305 prev = val;
306 val = val->next;
310 return 1;
313 void configReadIP() {
314 int fd = openFile(configPath, O_RDONLY);
315 if (fd >= 0) {
316 char ipconfig[255];
317 int size = getFileSize(fd);
318 fioRead(fd, &ipconfig, size);
319 fioClose(fd);
321 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],
322 &ps2_netmask[0], &ps2_netmask[1], &ps2_netmask[2], &ps2_netmask[3],
323 &ps2_gateway[0], &ps2_gateway[1], &ps2_gateway[2], &ps2_gateway[3]);
326 return;
329 void configWriteIP() {
330 int fd = openFile(configPath, O_WRONLY | O_CREAT);
331 if (fd >= 0) {
332 char ipconfig[255];
333 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],
334 ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3],
335 ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
337 fioWrite(fd, ipconfig, strlen(ipconfig));
338 fioClose(fd);
339 gIPConfigChanged = 0;
343 // dst has to have 5 bytes space
344 void configGetDiscIDBinary(config_set_t* configSet, void* dst) {
345 memset(dst, 0, 5);
347 char *gid = NULL;
348 if (configGetStr(configSet, CONFIG_ITEM_DNAS, &gid)) {
349 // convert from hex to binary
350 char* cdst = dst;
351 int p = 0;
352 while (*gid && p < 10) {
353 int dv = -1;
355 while (dv < 0 && *gid) // skip spaces, etc
356 dv = fromHex(*(gid++));
358 if (dv < 0)
359 break;
361 *cdst = *cdst * 16 + dv;
362 if ((++p & 1) == 0)
363 cdst++;
368 int configRead(config_set_t* configSet) {
369 file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_RDONLY, 0, 4096);
370 if (!fileBuffer) {
371 LOG("CONFIG No file %s.\n", configSet->filename);
372 configSet->modified = 0;
373 return 0;
376 char* line;
377 unsigned int lineno = 0;
379 char prefix[32];
380 memset(prefix, 0, sizeof(prefix));
382 while (readFileBuffer(fileBuffer, &line)) {
383 lineno++;
385 char key[32], val[255];
386 memset(key, 0, sizeof(key));
387 memset(val, 0, sizeof(val));
389 if (splitAssignment(line, key, sizeof(key), val, sizeof(val))) {
390 /* if the line does not start with whitespace,
391 * the prefix ends and we have to reset it
393 if (!isWS(line[0]))
394 memset(prefix, 0, sizeof(prefix));
396 // insert config value
397 if (prefix[0]) {
398 // we have a prefix
399 char composedKey[66];
401 snprintf(composedKey, 65, "%s_%s", prefix, key);
402 composedKey[65] = '\0';
404 configSetStr(configSet, composedKey, val);
405 } else {
406 configSetStr(configSet, key, val);
408 } else if (parsePrefix(line, prefix)) {
409 // prefix is set, that's about it
410 } else {
411 LOG("CONFIG Malformed file '%s' line %d: '%s'\n", configSet->filename, lineno, line);
414 closeFileBuffer(fileBuffer);
415 configSet->modified = 0;
416 return configSet->type;
419 int configWrite(config_set_t* configSet) {
420 if (configSet->modified) {
421 // BUG in PFS: O_TRUNC doesn't work, so we remove the file and re-create it
422 if (strncmp(configSet->filename, "pfs0:", 5) == 0)
423 fioRemove(configSet->filename);
425 file_buffer_t* fileBuffer = openFileBuffer(configSet->filename, O_WRONLY | O_CREAT | O_TRUNC, 0, 4096);
426 if (fileBuffer) {
427 char line[512];
429 struct config_value_t* cur = configSet->head;
430 while (cur) {
431 if ((cur->key[0] != '\0') && (cur->key[0] != '#')) {
432 snprintf(line, 512, "%s=%s\r\n", cur->key, cur->val); // add windows CR+LF (0x0D 0x0A)
433 writeFileBuffer(fileBuffer, line, strlen(line));
436 // and advance
437 cur = cur->next;
440 closeFileBuffer(fileBuffer);
441 configSet->modified = 0;
442 return 1;
444 return 0;
446 return 1;
449 void configClear(config_set_t* configSet) {
450 while (configSet->head) {
451 struct config_value_t* cur = configSet->head;
452 configSet->head = cur->next;
454 free(cur);
457 configSet->head = NULL;
458 configSet->tail = NULL;
459 configSet->modified = 1;
462 int configReadMulti(int types) {
463 int result = 0;
465 if (CONFIG_OPL & types)
466 configReadIP();
468 int index = 0;
469 while(index < CONFIG_FILE_NUM) {
470 config_set_t *configSet = &configFiles[index];
472 if (configSet->type & types) {
473 configClear(configSet);
474 result |= configRead(configSet);
476 index++;
479 return result;
482 int configWriteMulti(int types) {
483 int result = 0;
485 if ((CONFIG_OPL & types) && gIPConfigChanged)
486 configWriteIP();
488 int index = 0;
489 while(index < CONFIG_FILE_NUM) {
490 config_set_t *configSet = &configFiles[index];
492 if (configSet->type & types)
493 result += configWrite(configSet);
494 index++;
497 return result;
500 #ifdef VMC
501 void configGetVMC(config_set_t* configSet, char* vmc, int slot) {
502 char *valref = NULL;
503 char gkey[255];
504 snprintf(gkey, 255, "%s_%d", CONFIG_ITEM_VMC, slot);
505 if (configGetStr(configSet, gkey, &valref))
506 strncpy(vmc, valref, 32);
507 else
508 vmc[0] = '\0';
511 void configSetVMC(config_set_t* configSet, const char* vmc, int slot) {
512 char gkey[255];
513 if(vmc[0] == '\0') {
514 configRemoveVMC(configSet, slot);
515 return;
517 snprintf(gkey, 255, "%s_%d", CONFIG_ITEM_VMC, slot);
518 configSetStr(configSet, gkey, vmc);
521 void configRemoveVMC(config_set_t* configSet, int slot) {
522 char gkey[255];
523 snprintf(gkey, 255, "%s_%d", CONFIG_ITEM_VMC, slot);
524 configRemoveKey(configSet, gkey);
526 #endif