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