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