Mercurial > hg > nnchat
annotate th_config.c @ 322:b9c15c57dc8f
Clean up message functions, add new printMsgQ() helper function for messages that should not
go into the log file. Add skeleton help function, accessible via F1 key. And other cleanups.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 11 Jun 2011 09:48:26 +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 |