Mercurial > hg > th-libs
comparison th_config.c @ 16:0cea9c0cfce7
Sync.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 02 Nov 2010 23:22:44 +0200 |
parents | 4adf7093060c |
children | 05a44cbd1150 |
comparison
equal
deleted
inserted
replaced
15:4adf7093060c | 16:0cea9c0cfce7 |
---|---|
1 /* | 1 /* |
2 * Very simple configuration handling functions | 2 * Very simple configuration handling functions |
3 * Programmed and designed by Matti 'ccr' Hamalainen | 3 * Programmed and designed by Matti 'ccr' Hamalainen |
4 * (C) Copyright 2004-2008 Tecnic Software productions (TNSP) | 4 * (C) Copyright 2004-2010 Tecnic Software productions (TNSP) |
5 * | 5 * |
6 * Please read file 'COPYING' for information on license and distribution. | 6 * Please read file 'COPYING' for information on license and distribution. |
7 */ | 7 */ |
8 #ifdef HAVE_CONFIG_H | 8 #ifdef HAVE_CONFIG_H |
9 #include "config.h" | 9 #include "config.h" |
17 #define SET_MAX_BUF (8192) | 17 #define SET_MAX_BUF (8192) |
18 | 18 |
19 | 19 |
20 /* Free a given configuration (the values are not free'd) | 20 /* Free a given configuration (the values are not free'd) |
21 */ | 21 */ |
22 void th_config_free(cfgitem_t *cfg) | 22 void th_cfg_free(cfgitem_t *cfg) |
23 { | 23 { |
24 cfgitem_t *curr = cfg; | 24 cfgitem_t *curr = cfg; |
25 | 25 |
26 while (curr != NULL) { | 26 while (curr != NULL) { |
27 cfgitem_t *next = curr->next; | 27 cfgitem_t *next = curr->next; |
28 | 28 |
29 if (curr->type == ITEM_BLOCK) | 29 if (curr->type == ITEM_SECTION) |
30 th_config_free((cfgitem_t *) curr->data); | 30 th_cfg_free((cfgitem_t *) curr->data); |
31 | 31 |
32 th_free(curr->name); | 32 th_free(curr->name); |
33 th_free(curr); | 33 th_free(curr); |
34 curr = next; | 34 curr = next; |
35 } | 35 } |
36 } | 36 } |
37 | 37 |
38 | 38 |
39 /* Allocate and add new item to configuration | 39 /* Allocate and add new item to configuration |
40 */ | 40 */ |
41 static cfgitem_t *th_config_add(cfgitem_t **cfg, char *name, int type, | 41 static cfgitem_t *th_cfg_add(cfgitem_t **cfg, const char *name, const int type, void *data) |
42 BOOL (*validate)(cfgitem_t *), void *data) | |
43 { | 42 { |
44 cfgitem_t *node; | 43 cfgitem_t *node; |
45 | 44 |
46 if (cfg == NULL) | 45 if (cfg == NULL) |
47 return NULL; | 46 return NULL; |
52 return NULL; | 51 return NULL; |
53 | 52 |
54 /* Set values */ | 53 /* Set values */ |
55 node->type = type; | 54 node->type = type; |
56 node->data = data; | 55 node->data = data; |
57 node->validate = validate; | |
58 node->name = th_strdup(name); | 56 node->name = th_strdup(name); |
59 | 57 |
60 /* Insert into linked list */ | 58 /* Insert into linked list */ |
61 if (*cfg != NULL) { | 59 if (*cfg != NULL) { |
62 node->prev = (*cfg)->prev; | 60 node->prev = (*cfg)->prev; |
72 } | 70 } |
73 | 71 |
74 | 72 |
75 /* Add integer type setting into give configuration | 73 /* Add integer type setting into give configuration |
76 */ | 74 */ |
77 int th_config_add_int(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *), | 75 int th_cfg_add_int(cfgitem_t ** cfg, char * name, |
78 int *itemData, int itemDef) | 76 int *itemData, int itemDef) |
79 { | 77 { |
80 cfgitem_t *node; | 78 cfgitem_t *node; |
81 | 79 |
82 node = th_config_add(cfg, name, ITEM_INT, itemValidate, (void *) itemData); | 80 node = th_cfg_add(cfg, name, ITEM_INT, (void *) itemData); |
83 if (node == NULL) | 81 if (node == NULL) |
84 return -1; | 82 return -1; |
85 | 83 |
86 *itemData = itemDef; | 84 *itemData = itemDef; |
87 | 85 |
88 return 0; | 86 return 0; |
89 } | 87 } |
90 | 88 |
91 | 89 |
92 int th_config_add_hexvalue(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *), | 90 int th_cfg_add_hexvalue(cfgitem_t ** cfg, char * name, |
93 int *itemData, int itemDef) | 91 int *itemData, int itemDef) |
94 { | 92 { |
95 cfgitem_t *node; | 93 cfgitem_t *node; |
96 | 94 |
97 node = th_config_add(cfg, name, ITEM_HEX_TRIPLET, itemValidate, (void *) itemData); | 95 node = th_cfg_add(cfg, name, ITEM_HEX_TRIPLET, (void *) itemData); |
98 if (node == NULL) | 96 if (node == NULL) |
99 return -1; | 97 return -1; |
100 | 98 |
101 *itemData = itemDef; | 99 *itemData = itemDef; |
102 | 100 |
104 } | 102 } |
105 | 103 |
106 | 104 |
107 /* Add unsigned integer type setting into give configuration | 105 /* Add unsigned integer type setting into give configuration |
108 */ | 106 */ |
109 int th_config_add_uint(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *), | 107 int th_cfg_add_uint(cfgitem_t ** cfg, char * name, |
110 unsigned int * itemData, unsigned int itemDef) | 108 unsigned int * itemData, unsigned int itemDef) |
111 { | 109 { |
112 cfgitem_t *node; | 110 cfgitem_t *node; |
113 | 111 |
114 node = th_config_add(cfg, name, ITEM_UINT, itemValidate, (void *) itemData); | 112 node = th_cfg_add(cfg, name, ITEM_UINT, (void *) itemData); |
115 if (node == NULL) | 113 if (node == NULL) |
116 return -1; | 114 return -1; |
117 | 115 |
118 *itemData = itemDef; | 116 *itemData = itemDef; |
119 | 117 |
121 } | 119 } |
122 | 120 |
123 | 121 |
124 /* Add strint type setting into given configuration | 122 /* Add strint type setting into given configuration |
125 */ | 123 */ |
126 int th_config_add_string(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *), | 124 int th_cfg_add_string(cfgitem_t ** cfg, char * name, |
127 char ** itemData, char * itemDef) | 125 char ** itemData, char * itemDef) |
128 { | 126 { |
129 cfgitem_t *node; | 127 cfgitem_t *node; |
130 | 128 |
131 node = th_config_add(cfg, name, ITEM_STRING, itemValidate, (void *) itemData); | 129 node = th_cfg_add(cfg, name, ITEM_STRING, (void *) itemData); |
132 if (node == NULL) | 130 if (node == NULL) |
133 return -1; | 131 return -1; |
134 | 132 |
135 *itemData = th_strdup(itemDef); | 133 *itemData = th_strdup(itemDef); |
136 | 134 |
138 } | 136 } |
139 | 137 |
140 | 138 |
141 /* Add boolean type setting into given configuration | 139 /* Add boolean type setting into given configuration |
142 */ | 140 */ |
143 int th_config_add_bool(cfgitem_t ** cfg, char * name, BOOL(*itemValidate) (cfgitem_t *), | 141 int th_cfg_add_bool(cfgitem_t ** cfg, char * name, |
144 BOOL * itemData, BOOL itemDef) | 142 BOOL * itemData, BOOL itemDef) |
145 { | 143 { |
146 cfgitem_t *node; | 144 cfgitem_t *node; |
147 | 145 |
148 node = th_config_add(cfg, name, ITEM_BOOL, itemValidate, (void *) itemData); | 146 node = th_cfg_add(cfg, name, ITEM_BOOL, (void *) itemData); |
149 if (node == NULL) | 147 if (node == NULL) |
150 return -1; | 148 return -1; |
151 | 149 |
152 *itemData = itemDef; | 150 *itemData = itemDef; |
153 | 151 |
155 } | 153 } |
156 | 154 |
157 | 155 |
158 /* Add implicit comment | 156 /* Add implicit comment |
159 */ | 157 */ |
160 int th_config_add_comment(cfgitem_t ** cfg, char * comment) | 158 int th_cfg_add_comment(cfgitem_t ** cfg, char * comment) |
161 { | 159 { |
162 cfgitem_t *node; | 160 cfgitem_t *node; |
163 | 161 |
164 node = th_config_add(cfg, comment, ITEM_COMMENT, NULL, NULL); | 162 node = th_cfg_add(cfg, comment, ITEM_COMMENT, NULL); |
165 if (node == NULL) | 163 if (node == NULL) |
166 return -1; | 164 return -1; |
167 | 165 |
168 return 0; | 166 return 0; |
169 } | 167 } |
170 | 168 |
171 | 169 |
172 /* Add new block | 170 /* Add new section |
173 */ | 171 */ |
174 int th_config_add_section(cfgitem_t ** cfg, char * name, cfgitem_t *data) | 172 int th_cfg_add_section(cfgitem_t ** cfg, char * name, cfgitem_t *data) |
175 { | 173 { |
176 cfgitem_t *node; | 174 cfgitem_t *node; |
177 | 175 |
178 node = th_config_add(cfg, name, ITEM_BLOCK, NULL, (void *) data); | 176 node = th_cfg_add(cfg, name, ITEM_SECTION, (void *) data); |
177 if (node == NULL) | |
178 return -1; | |
179 | |
180 return 0; | |
181 } | |
182 | |
183 | |
184 int th_cfg_add_string_list(cfgitem_t ** cfg, char * name, qlist_t **data) | |
185 { | |
186 cfgitem_t *node; | |
187 | |
188 if (data == NULL) | |
189 return -5; | |
190 | |
191 node = th_cfg_add(cfg, name, ITEM_STRING_LIST, (void *) data); | |
179 if (node == NULL) | 192 if (node == NULL) |
180 return -1; | 193 return -1; |
181 | 194 |
182 return 0; | 195 return 0; |
183 } | 196 } |
194 PM_KEYNAME, | 207 PM_KEYNAME, |
195 PM_KEYSET, | 208 PM_KEYSET, |
196 PM_STRING, | 209 PM_STRING, |
197 PM_INT, | 210 PM_INT, |
198 PM_BOOL, | 211 PM_BOOL, |
199 PM_BLOCK | 212 PM_SECTION, |
213 PM_ARRAY | |
200 }; | 214 }; |
201 | 215 |
202 #define VADDCH(ch) if (strPos < SET_MAX_BUF) { tmpStr[strPos++] = ch; } | 216 #define VADDCH(ch) if (strPos < SET_MAX_BUF) { tmpStr[strPos++] = ch; } |
203 #define VISEND(ch) (ch == '\r' || ch == '\n' || ch == ';' || th_isspace(c) || ch == '#') | 217 #define VISEND(ch) (ch == '\r' || ch == '\n' || ch == ';' || th_isspace(c) || ch == '#') |
204 | 218 |
207 char *filename; | 221 char *filename; |
208 size_t line; | 222 size_t line; |
209 } conffile_t; | 223 } conffile_t; |
210 | 224 |
211 | 225 |
212 static void th_config_error(conffile_t *f, const char *fmt, ...) | 226 static void th_cfg_error(conffile_t *f, const char *fmt, ...) |
213 { | 227 { |
214 va_list ap; | 228 va_list ap; |
215 va_start(ap, fmt); | 229 va_start(ap, fmt); |
216 fprintf(stderr, "%s: '%s', line #%d: ", th_prog_name, f->filename, f->line); | 230 fprintf(stderr, "%s: '%s', line #%d: ", th_prog_name, f->filename, f->line); |
217 vfprintf(stderr, fmt, ap); | 231 vfprintf(stderr, fmt, ap); |
218 va_end(ap); | 232 va_end(ap); |
219 } | 233 } |
220 | 234 |
221 | 235 |
222 static int th_config_read_sect(conffile_t *f, cfgitem_t * cfg, int nesting) | 236 static int th_cfg_read_sect(conffile_t *f, cfgitem_t * cfg, int nesting) |
223 { | 237 { |
224 cfgitem_t *item = NULL; | 238 cfgitem_t *item = NULL; |
225 char tmpStr[SET_MAX_BUF + 1]; | 239 char tmpStr[SET_MAX_BUF + 1]; |
226 size_t strPos; | 240 size_t strPos; |
227 int c, parseMode, prevMode, nextMode, tmpCh; | 241 int c, parseMode, prevMode, nextMode, tmpCh; |
239 if (c == -1) { | 253 if (c == -1) { |
240 /* Get next character */ | 254 /* Get next character */ |
241 switch (c = fgetc(f->file)) { | 255 switch (c = fgetc(f->file)) { |
242 case EOF: | 256 case EOF: |
243 if (parseMode != PM_NORMAL) { | 257 if (parseMode != PM_NORMAL) { |
244 th_config_error(f, | 258 th_cfg_error(f, |
245 "Unexpected end of file.\n"); | 259 "Unexpected end of file.\n"); |
246 parseMode = PM_ERROR; | 260 parseMode = PM_ERROR; |
247 } else | 261 } else |
248 parseMode = PM_EOF; | 262 parseMode = PM_EOF; |
249 break; | 263 break; |
275 } else if (c == '}') { | 289 } else if (c == '}') { |
276 if (nesting > 0) { | 290 if (nesting > 0) { |
277 /* Check for validation errors */ | 291 /* Check for validation errors */ |
278 return (validError) ? 1 : 0; | 292 return (validError) ? 1 : 0; |
279 } else { | 293 } else { |
280 th_config_error(f, | 294 th_cfg_error(f, "Invalid nesting sequence encountered.\n"); |
281 "HMMM!\n"); | |
282 parseMode = PM_ERROR; | 295 parseMode = PM_ERROR; |
283 } | 296 } |
284 } else if (th_isalpha(c)) { | 297 } else if (th_isalpha(c)) { |
285 /* Start of key name found */ | 298 /* Start of key name found */ |
286 prevMode = parseMode; | 299 prevMode = parseMode; |
287 parseMode = PM_KEYNAME; | 300 parseMode = PM_KEYNAME; |
288 strPos = 0; | 301 strPos = 0; |
289 } else { | 302 } else { |
290 /* Error! Invalid character found */ | 303 /* Error! Invalid character found */ |
291 th_config_error(f, | 304 th_cfg_error(f, |
292 "Unexpected character '%c'.\n", c); | 305 "Unexpected character '%c'.\n", c); |
293 parseMode = PM_ERROR; | 306 parseMode = PM_ERROR; |
294 } | 307 } |
295 break; | 308 break; |
296 | 309 |
310 /* Add to key name string */ | 323 /* Add to key name string */ |
311 VADDCH(c) | 324 VADDCH(c) |
312 else | 325 else |
313 { | 326 { |
314 /* Error! Key name string too long! */ | 327 /* Error! Key name string too long! */ |
315 th_config_error(f, | 328 th_cfg_error(f, |
316 "Config key name too long!"); | 329 "Config key name too long!"); |
317 parseMode = PM_ERROR; | 330 parseMode = PM_ERROR; |
318 } | 331 } |
319 c = -1; | 332 c = -1; |
320 } else { | 333 } else { |
321 /* Error! Invalid character found */ | 334 /* Error! Invalid character found */ |
322 tmpStr[strPos] = 0; | 335 tmpStr[strPos] = 0; |
323 th_config_error(f, | 336 th_cfg_error(f, |
324 "Unexpected character '%c' in key name '%s'.\n", c, tmpStr); | 337 "Unexpected character '%c' in key name '%s'.\n", c, tmpStr); |
325 parseMode = PM_ERROR; | 338 parseMode = PM_ERROR; |
326 } | 339 } |
327 break; | 340 break; |
328 | 341 |
346 case ITEM_HEX_TRIPLET: | 359 case ITEM_HEX_TRIPLET: |
347 case ITEM_STRING: | 360 case ITEM_STRING: |
348 nextMode = PM_STRING; | 361 nextMode = PM_STRING; |
349 break; | 362 break; |
350 | 363 |
364 case ITEM_STRING_LIST: | |
365 nextMode = PM_ARRAY; | |
366 break; | |
367 | |
351 case ITEM_INT: | 368 case ITEM_INT: |
352 case ITEM_UINT: | 369 case ITEM_UINT: |
353 nextMode = PM_INT; | 370 nextMode = PM_INT; |
354 break; | 371 break; |
355 | 372 |
356 case ITEM_BOOL: | 373 case ITEM_BOOL: |
357 nextMode = PM_BOOL; | 374 nextMode = PM_BOOL; |
358 break; | 375 break; |
359 | 376 |
360 case ITEM_BLOCK: | 377 case ITEM_SECTION: |
361 nextMode = PM_BLOCK; | 378 nextMode = PM_SECTION; |
362 break; | 379 break; |
363 } | 380 } |
364 | 381 |
365 prevMode = parseMode; | 382 prevMode = parseMode; |
366 parseMode = PM_NEXT; | 383 parseMode = PM_NEXT; |
367 isStart = TRUE; | 384 isStart = TRUE; |
368 strPos = 0; | 385 strPos = 0; |
369 } else { | 386 } else { |
370 /* Error! No configuration key by this name found */ | 387 /* Error! No configuration key by this name found */ |
371 th_config_error(f, | 388 th_cfg_error(f, |
372 "No such configuration setting ('%s')\n", tmpStr); | 389 "No such configuration setting ('%s')\n", tmpStr); |
373 parseMode = PM_ERROR; | 390 parseMode = PM_ERROR; |
374 } | 391 } |
375 | 392 |
376 c = -1; | 393 c = -1; |
377 } else { | 394 } else { |
378 /* Error! '=' expected! */ | 395 /* Error! '=' expected! */ |
379 th_config_error(f, | 396 th_cfg_error(f, |
380 "Unexpected character '%c', assignation '=' was expected.\n", c); | 397 "Unexpected character '%c', assignation '=' was expected.\n", c); |
381 parseMode = PM_ERROR; | 398 parseMode = PM_ERROR; |
382 } | 399 } |
383 break; | 400 break; |
384 | 401 |
396 prevMode = parseMode; | 413 prevMode = parseMode; |
397 parseMode = nextMode; | 414 parseMode = nextMode; |
398 } | 415 } |
399 break; | 416 break; |
400 | 417 |
401 case PM_BLOCK: | 418 case PM_ARRAY: |
402 /* Block parsing mode */ | 419 if (isStart) { |
420 switch (item->type) { | |
421 case ITEM_STRING_LIST: | |
422 prevMode = parseMode; | |
423 parseMode = PM_STRING; | |
424 break; | |
425 } | |
426 } else if (c == ',') { | |
427 switch (item->type) { | |
428 case ITEM_STRING_LIST: | |
429 c = -1; | |
430 isStart = TRUE; | |
431 prevMode = parseMode; | |
432 parseMode = PM_NEXT; | |
433 nextMode = PM_STRING; | |
434 break; | |
435 } | |
436 } else { | |
437 prevMode = parseMode; | |
438 parseMode = PM_NORMAL; | |
439 } | |
440 break; | |
441 | |
442 case PM_SECTION: | |
443 /* Section parsing mode */ | |
403 if (c != '{') { | 444 if (c != '{') { |
404 /* Error! Block start '{' expected! */ | 445 /* Error! Section start '{' expected! */ |
405 th_config_error(f, | 446 th_cfg_error(f, |
406 "Unexpected character '%c', block start '{' was expected.\n", c); | 447 "Unexpected character '%c', section start '{' was expected.\n", c); |
407 parseMode = PM_ERROR; | 448 parseMode = PM_ERROR; |
408 } else { | 449 } else { |
409 int res = th_config_read_sect(f, (cfgitem_t *) item->data, nesting + 1); | 450 int res = th_cfg_read_sect(f, (cfgitem_t *) item->data, nesting + 1); |
410 c = -1; | 451 c = -1; |
411 if (res > 0) | 452 if (res > 0) |
412 validError = TRUE; | 453 validError = TRUE; |
413 else if (res < 0) | 454 else if (res < 0) |
414 parseMode = PM_ERROR; | 455 parseMode = PM_ERROR; |
428 strPos = 0; | 469 strPos = 0; |
429 } else if (c == tmpCh) { | 470 } else if (c == tmpCh) { |
430 /* End of string, set the value */ | 471 /* End of string, set the value */ |
431 tmpStr[strPos] = 0; | 472 tmpStr[strPos] = 0; |
432 | 473 |
433 if (item->type == ITEM_HEX_TRIPLET) { | 474 switch (item->type) { |
434 } else if (item->type == ITEM_STRING) { | 475 case ITEM_HEX_TRIPLET: |
435 th_pstrcpy((char **) item->data, tmpStr); | 476 *(int *) item->data = th_get_hex_triplet(tmpStr); |
477 prevMode = parseMode; | |
478 parseMode = PM_NORMAL; | |
479 break; | |
480 case ITEM_STRING: | |
481 th_pstrcpy((char **) item->data, tmpStr); | |
482 prevMode = parseMode; | |
483 parseMode = PM_NORMAL; | |
484 break; | |
485 case ITEM_STRING_LIST: | |
486 th_llist_append(item->list, th_strdup(tmpStr)); | |
487 prevMode = parseMode; | |
488 parseMode = PM_NEXT; | |
489 nextMode = PM_ARRAY; | |
490 break; | |
436 } | 491 } |
437 | 492 |
438 if (item->validate != NULL && !item->validate(item)) | |
439 validError = TRUE; | |
440 | |
441 prevMode = parseMode; | |
442 parseMode = PM_NORMAL; | |
443 } else { | 493 } else { |
444 /* Add character to string */ | 494 /* Add character to string */ |
445 VADDCH(c) | 495 VADDCH(c) |
446 else | 496 else |
447 { | 497 { |
448 /* Error! String too long! */ | 498 /* Error! String too long! */ |
449 th_config_error(f, | 499 th_cfg_error(f, |
450 "String too long! Maximum is %d characters.", | 500 "String too long! Maximum is %d characters.", |
451 SET_MAX_BUF); | 501 SET_MAX_BUF); |
452 parseMode = PM_ERROR; | 502 parseMode = PM_ERROR; |
453 } | 503 } |
454 } | 504 } |
458 | 508 |
459 case PM_INT: | 509 case PM_INT: |
460 /* Integer parsing mode */ | 510 /* Integer parsing mode */ |
461 if (isStart && item->type == ITEM_UINT && c == '-') { | 511 if (isStart && item->type == ITEM_UINT && c == '-') { |
462 /* Error! Negative values not allowed for unsigned ints */ | 512 /* Error! Negative values not allowed for unsigned ints */ |
463 th_config_error(f, | 513 th_cfg_error(f, |
464 "Negative value specified for %s, unsigned value expected.", | 514 "Negative value specified for %s, unsigned value expected.", |
465 item->name); | 515 item->name); |
466 parseMode = PM_ERROR; | 516 parseMode = PM_ERROR; |
467 } else if (isStart && (c == '-' || c == '+')) { | 517 } else if (isStart && (c == '-' || c == '+')) { |
468 VADDCH(c) | 518 VADDCH(c) |
482 | 532 |
483 case ITEM_UINT: | 533 case ITEM_UINT: |
484 *((unsigned int *) item->data) = atol(tmpStr); | 534 *((unsigned int *) item->data) = atol(tmpStr); |
485 break; | 535 break; |
486 } | 536 } |
487 if (item->validate != NULL && !item->validate(item)) | |
488 validError = TRUE; | |
489 | 537 |
490 prevMode = parseMode; | 538 prevMode = parseMode; |
491 parseMode = PM_NORMAL; | 539 parseMode = PM_NORMAL; |
492 } else { | 540 } else { |
493 /* Error! Unexpected character. */ | 541 /* Error! Unexpected character. */ |
494 th_config_error(f, | 542 th_cfg_error(f, |
495 "Unexpected character '%c' for integer setting '%s'.", | 543 "Unexpected character '%c' for integer setting '%s'.", |
496 c, item->name); | 544 c, item->name); |
497 parseMode = PM_ERROR; | 545 parseMode = PM_ERROR; |
498 } | 546 } |
499 | 547 |
500 if (isError) { | 548 if (isError) { |
501 /* Error! String too long! */ | 549 /* Error! String too long! */ |
502 th_config_error(f, "String too long! Maximum is %d characters.", | 550 th_cfg_error(f, "String too long! Maximum is %d characters.", |
503 SET_MAX_BUF); | 551 SET_MAX_BUF); |
504 parseMode = PM_ERROR; | 552 parseMode = PM_ERROR; |
505 } | 553 } |
506 | 554 |
507 isStart = FALSE; | 555 isStart = FALSE; |
533 default: | 581 default: |
534 isError = TRUE; | 582 isError = TRUE; |
535 } | 583 } |
536 | 584 |
537 if (isError) { | 585 if (isError) { |
538 th_config_error(f, "Invalid boolean value for '%s'.\n", item->name); | 586 th_cfg_error(f, "Invalid boolean value for '%s'.\n", item->name); |
539 parseMode = PM_ERROR; | 587 parseMode = PM_ERROR; |
540 } else { | 588 } else { |
541 *((BOOL *) item->data) = tmpBool; | 589 *((BOOL *) item->data) = tmpBool; |
542 | |
543 if (item->validate != NULL && !item->validate(item)) | |
544 validError = TRUE; | |
545 | 590 |
546 prevMode = parseMode; | 591 prevMode = parseMode; |
547 parseMode = PM_NORMAL; | 592 parseMode = PM_NORMAL; |
548 } | 593 } |
549 } | 594 } |
562 else | 607 else |
563 return 0; | 608 return 0; |
564 } | 609 } |
565 | 610 |
566 | 611 |
567 int th_config_read(FILE *inFile, char *filename, cfgitem_t * cfg) | 612 int th_cfg_read(FILE *inFile, char *filename, cfgitem_t * cfg) |
568 { | 613 { |
569 conffile_t f; | 614 conffile_t f; |
570 | 615 |
571 f.file = inFile; | 616 f.file = inFile; |
572 f.filename = filename; | 617 f.filename = filename; |
573 f.line = 1; | 618 f.line = 1; |
574 | 619 |
575 return th_config_read_sect(&f, cfg, 0); | 620 return th_cfg_read_sect(&f, cfg, 0); |
576 } | 621 } |
577 | 622 |
578 | 623 |
579 /* Write a configuration into file | 624 /* Write a configuration into file |
580 */ | 625 */ |
584 for (i = 0; i < nesting * 2; i++) | 629 for (i = 0; i < nesting * 2; i++) |
585 fputc(' ', f->file); | 630 fputc(' ', f->file); |
586 } | 631 } |
587 | 632 |
588 | 633 |
589 static int th_config_write_sect(conffile_t *f, cfgitem_t *item, int nesting) | 634 static int th_cfg_write_sect(conffile_t *f, cfgitem_t *item, int nesting) |
590 { | 635 { |
591 while (item != NULL) { | 636 while (item != NULL) { |
592 if (item->type == ITEM_COMMENT) { | 637 if (item->type == ITEM_COMMENT) { |
593 th_print_indent(f, nesting); | 638 th_print_indent(f, nesting); |
594 if (fprintf(f->file, "# %s\n", (item->name != NULL) ? item->name : "" ) < 0) | 639 if (fprintf(f->file, "# %s\n", (item->name != NULL) ? item->name : "" ) < 0) |
597 if (item->name != NULL) { | 642 if (item->name != NULL) { |
598 th_print_indent(f, nesting); | 643 th_print_indent(f, nesting); |
599 | 644 |
600 switch (item->type) { | 645 switch (item->type) { |
601 case ITEM_STRING: | 646 case ITEM_STRING: |
602 if (*((char **) item->data) == NULL) { | 647 if (*(item->val_str) == NULL) { |
603 if (fprintf(f->file, "#%s = \"\"\n", item->name) < 0) | 648 if (fprintf(f->file, "#%s = \"\"\n", item->name) < 0) |
604 return -3; | 649 return -3; |
605 } else { | 650 } else { |
606 if (fprintf(f->file, "%s = \"%s\"\n", | 651 if (fprintf(f->file, "%s = \"%s\"\n", |
607 item->name, *((char **) item->data)) < 0) | 652 item->name, *(item->val_str)) < 0) |
653 return -3; | |
654 } | |
655 break; | |
656 | |
657 case ITEM_STRING_LIST: | |
658 if (*(item->list) == NULL) { | |
659 if (fprintf(f->file, "#%s = \"\", \"\"\n", item->name) < 0) | |
660 return -3; | |
661 } else { | |
662 qlist_t *node = *(item->list); | |
663 size_t n = th_llist_length(node); | |
664 if (fprintf(f->file, "%s = ", item->name) < 0) | |
665 return -3; | |
666 | |
667 while (node != NULL) { | |
668 if (node->data != NULL) | |
669 fprintf(f->file, "\"%s\"", (char *) node->data); | |
670 | |
671 if (--n > 0) | |
672 fprintf(f->file, ", "); | |
673 | |
674 node = node->next; | |
675 } | |
676 | |
677 if (fprintf(f->file, "\n") < 0) | |
608 return -3; | 678 return -3; |
609 } | 679 } |
610 break; | 680 break; |
611 | 681 |
612 case ITEM_INT: | 682 case ITEM_INT: |
613 if (fprintf(f->file, "%s = %i\n", | 683 if (fprintf(f->file, "%s = %i\n", |
614 item->name, *((int *) item->data)) < 0) | 684 item->name, *(item->val_int)) < 0) |
615 return -4; | 685 return -4; |
616 break; | 686 break; |
617 | 687 |
618 case ITEM_UINT: | 688 case ITEM_UINT: |
619 if (fprintf(f->file, "%s = %d\n", | 689 if (fprintf(f->file, "%s = %d\n", |
620 item->name, *((unsigned int *) item->data)) < 0) | 690 item->name, *(item->val_uint)) < 0) |
621 return -5; | 691 return -5; |
622 break; | 692 break; |
623 | 693 |
624 case ITEM_BOOL: | 694 case ITEM_BOOL: |
625 if (fprintf(f->file, "%s = %s\n", | 695 if (fprintf(f->file, "%s = %s\n", |
626 item->name, *((BOOL *) item->data) ? "yes" : "no") < 0) | 696 item->name, *(item->val_bool) ? "yes" : "no") < 0) |
627 return -6; | 697 return -6; |
628 break; | 698 break; |
629 | 699 |
630 case ITEM_BLOCK: | 700 case ITEM_SECTION: |
631 { | 701 { |
632 int res; | 702 int res; |
633 if (fprintf(f->file, "\n%s = {\n", item->name) < 0) | 703 if (fprintf(f->file, "%s = {\n", item->name) < 0) |
634 return -7; | 704 return -7; |
635 res = th_config_write_sect(f, (cfgitem_t *) item->data, nesting + 1); | 705 res = th_cfg_write_sect(f, (cfgitem_t *) item->data, nesting + 1); |
636 if (res != 0) return res; | 706 if (res != 0) return res; |
637 if (fprintf(f->file, "} # End of '%s'\n\n", item->name) < 0) | 707 if (fprintf(f->file, "}\n\n") < 0) |
638 return -8; | 708 return -8; |
639 } | 709 } |
640 break; | 710 break; |
641 | 711 |
642 case ITEM_HEX_TRIPLET: | 712 case ITEM_HEX_TRIPLET: |
651 | 721 |
652 return 0; | 722 return 0; |
653 } | 723 } |
654 | 724 |
655 | 725 |
656 int th_config_write(FILE *outFile, char *filename, cfgitem_t *cfg) | 726 int th_cfg_write(FILE *outFile, char *filename, cfgitem_t *cfg) |
657 { | 727 { |
658 conffile_t f; | 728 conffile_t f; |
659 | 729 |
660 if (cfg == NULL) | 730 if (cfg == NULL) |
661 return -1; | 731 return -1; |
665 f.line = 1; | 735 f.line = 1; |
666 | 736 |
667 fprintf(outFile, "# Configuration written by %s %s\n\n", | 737 fprintf(outFile, "# Configuration written by %s %s\n\n", |
668 th_prog_fullname, th_prog_version); | 738 th_prog_fullname, th_prog_version); |
669 | 739 |
670 return th_config_write_sect(&f, cfg, 0); | 740 return th_cfg_write_sect(&f, cfg, 0); |
671 } | 741 } |
672 | 742 |
673 | 743 |