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