comparison ini.c @ 79:fd817a7dbf2f

Switched a lot of things in ini
author David Demelier <markand@malikania.fr>
date Tue, 15 Nov 2011 20:12:48 +0100
parents inifile.c@4c5f69f5f409
children f42bcb9e7b4a
comparison
equal deleted inserted replaced
78:ad60e5ebd92c 79:fd817a7dbf2f
1 /*
2 * ini.c -- parse .ini like files
3 *
4 * Copyright (c) 2011, David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/queue.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <errno.h>
26
27 #include "ini.h"
28
29 /* --------------------------------------------------------
30 * structure definitions
31 * -------------------------------------------------------- */
32
33 struct ini_option {
34 char *key; /* option name */
35 char *value; /* option value */
36 STAILQ_ENTRY(ini_option) next;
37 };
38
39 struct ini_section {
40 char *key; /* section key */
41 STAILQ_HEAD(, ini_option) options;
42 STAILQ_ENTRY(ini_section) next;
43 };
44
45 struct ini_config {
46 const char *path; /* file path */
47 int flags; /* optional flags */
48 int ignore; /* must ignore (no redefine) */
49
50 /* Current section in file */
51 struct ini_section *current;
52
53 /* Current file line properties */
54 char *line; /* line buffer */
55 int lineno; /* number of line */
56 int linesize; /* initial line size */
57
58 /* For querying functions */
59 STAILQ_HEAD(, ini_section) sections;
60 };
61
62 static char iniError[1024 + 1];
63
64 /* --------------------------------------------------------
65 * prototypes
66 * -------------------------------------------------------- */
67
68 static void *ini_read(struct ini_config *, FILE *);
69 static int ini_getline(struct ini_config *, FILE *);
70 static void *ini_readline(struct ini_config *);
71 static int ini_switch(struct ini_config *, char **);
72 static int ini_register(struct ini_config *, char **);
73 static void *ini_fatal(struct ini_config *, FILE *, const char *, ...);
74 static char *xstrndup(const char *, size_t);
75 static struct ini_option *xoptiondup(const struct ini_option *option);
76
77 #define I_VERBOSE(file) ((file)->flags & INI_VERBOSE)
78 #define I_NOREDEFINE(file) ((file)->flags & INI_NOREDEFINE)
79 #define I_FAILERROR(file) ((file)->flags & INI_FAILERROR)
80
81 #define SKIP_SPACES(lp) while (isspace(*lp) && *lp != '\0') ++lp
82 #define WARN(file, fmt, ...) \
83 if (I_VERBOSE((file))) \
84 fprintf(stderr, fmt, __VA_ARGS__)
85
86 /* --------------------------------------------------------
87 * public functions
88 * -------------------------------------------------------- */
89
90 struct ini_config *
91 ini_load(const char *path, int flags)
92 {
93 FILE *fp;
94 struct ini_config *conf;
95
96 if ((conf = calloc(1, sizeof (struct ini_config))) == NULL)
97 return ini_fatal(conf, fp, "%s", strerror(errno));
98
99 if ((fp = fopen(path, "r")) == NULL)
100 return ini_fatal(conf, fp, "%s: %s", path, strerror(errno));
101
102 if ((conf->line = calloc(1024 + 1, 1)) == NULL)
103 return ini_fatal(conf, fp, "%s", strerror(errno));
104
105 STAILQ_INIT(&conf->sections);
106 conf->path = path;
107 conf->flags = flags;
108 conf->ignore = 1;
109 conf->lineno = 1;
110 conf->linesize = 1024;
111
112 return ini_read(conf, fp);
113 }
114
115 /*
116 * Returns a NULL terminated list of section names. If parameter
117 * number is not NULL, number is set to the total number of
118 * section correctly parsed.
119 */
120
121 char **
122 ini_get_sections_names(struct ini_config *conf, int *number)
123 {
124 struct ini_section *s;
125 char **list;
126 int i;
127
128 i = 0;
129 STAILQ_FOREACH(s, &conf->sections, next)
130 ++ i;
131
132 if ((list = calloc(i + 1, sizeof (char *))) == NULL)
133 return NULL;
134
135 if (number != NULL)
136 *number = i;
137
138 i = 0;
139 STAILQ_FOREACH(s, &conf->sections, next)
140 list[i++] = s->key;
141
142 return list;
143 }
144
145 /*
146 * Returns a NULL terminated list of struct ini_section that could be used
147 * with ini_get_option(). This function makes sense only when the config
148 * has multiple definition enabled.
149 */
150
151 struct ini_section **
152 ini_get_sections(const struct ini_config *conf, const char *key, int *nb)
153 {
154 struct ini_section **list;
155 struct ini_section *s;
156 int i;
157
158 /* Do not use this function on simple config */
159 if (I_NOREDEFINE(conf)) {
160 errno = EINVAL;
161 return NULL;
162 }
163
164 i = 0;
165 STAILQ_FOREACH(s, &conf->sections, next)
166 if (strcmp(s->key, key) == 0)
167 ++ i;
168
169 if ((list = calloc(i + 1, sizeof (struct ini_section *))) == NULL)
170 return NULL;
171
172 if (nb != NULL)
173 *nb = i;
174
175 i = 0;
176 STAILQ_FOREACH(s, &conf->sections, next)
177 if (strcmp(s->key, key) == 0)
178 list[i++] = s;
179
180 return list;
181 }
182
183 /*
184 * Select the section for further query. This improves performance as it does
185 * not need to seek each time the section. It can't be used when multiple
186 * definition is enabled because it seek from the beginning, you should use
187 * ini_get_sections() and then ini_get_option() for each section.
188 */
189
190 struct ini_section *
191 ini_select_section(struct ini_config *conf, const char *section)
192 {
193 struct ini_section *s;
194
195 STAILQ_FOREACH(s, &conf->sections, next)
196 if (strcmp(s->key, section) == 0)
197 return s;
198
199 return NULL;
200 }
201
202 /*
203 * Wrapper for a simpler usage of ini_select and ini_option. This
204 * does not modify the selector so you can safely continue the
205 * call to ini_option independantly. Warning, this function returns the
206 * first occurence of the option so it is not advised to use it
207 */
208
209 char *
210 ini_option_once(struct ini_config *conf, const char *sect, const char *key)
211 {
212 struct ini_option *o;
213 struct ini_section *s;
214
215 STAILQ_FOREACH(s, &conf->sections, next)
216 if (strcmp(s->key, sect) == 0)
217 break;
218
219 STAILQ_FOREACH(o, &s->options, next)
220 if (strcmp(o->key, key) == 0)
221 return o->value;
222
223 return NULL;
224 }
225
226 /*
227 * Return a NULL list of all available options in the section.
228 */
229
230 char **
231 ini_get_option_names(struct ini_section *section, int *nb)
232 {
233 char **list;
234 struct ini_option *o;
235 int i;
236
237 i = 0;
238 STAILQ_FOREACH(o, &section->options, next)
239 ++ i;
240
241 if ((list = calloc(i + 1, sizeof (char *))) == NULL)
242 return NULL;
243
244 if (nb != NULL)
245 *nb = i;
246
247 i = 0;
248 STAILQ_FOREACH(o, &section->options, next)
249 list[i++] = o->key;
250
251 return list;
252 }
253
254 /*
255 * Get the option in the current selected option. Note, you must call
256 * ini_select() before using this function. Returns the value of
257 * key or NULL if the option does not exists.
258 */
259
260 char *
261 ini_get_option(struct ini_section *section, const char *key)
262 {
263 struct ini_option *o;
264
265 STAILQ_FOREACH(o, &section->options, next)
266 if (strcmp(o->key, key) == 0)
267 return o->value;
268
269 return NULL;
270 }
271
272 /*
273 * Return the last error or "No error" if there is not error at all.
274 */
275
276 char *
277 ini_error(void)
278 {
279 if (iniError[0] == '\0')
280 return "No error";
281
282 return iniError;
283 }
284
285 void
286 ini_free(struct ini_config *conf, int freeSections, int freeOptions)
287 {
288 struct ini_section *s, *stmp;
289 struct ini_option *o, *otmp;
290
291 STAILQ_FOREACH_SAFE(s, &conf->sections, next, stmp) {
292 STAILQ_FOREACH_SAFE(o, &s->options, next, otmp) {
293 if (freeOptions) {
294 free(o->key);
295 free(o->value);
296
297 STAILQ_REMOVE(&s->options, o, ini_option, next);
298 free(o);
299 }
300 }
301
302 if (freeSections)
303 free(s->key);
304
305 STAILQ_REMOVE(&conf->sections, s, ini_section, next);
306 free(s);
307 }
308
309 free(conf);
310 }
311
312 /* --------------------------------------------------------
313 * private functions
314 * -------------------------------------------------------- */
315
316 /*
317 * Read file line per line and try to parse ini like file. Lines
318 * starting with # or empty line are ignored. Returns the file
319 * on success and NULL on failure.
320 */
321
322 static void *
323 ini_read(struct ini_config *conf, FILE *fp)
324 {
325 while (ini_getline(conf, fp) == 0) {
326 if (ini_readline(conf) == NULL) {
327 free(conf->line);
328 ini_free(conf, 1, 1);
329
330 fclose(fp);
331 return NULL;
332 }
333
334 ++ conf->lineno;
335 }
336
337 /* Clean up */
338 free(conf->line);
339 fclose(fp);
340
341 return conf;
342 }
343
344 /*
345 * Read the next line until the next '\n' character is found. Returns 0
346 * if the system had enough memory or -1 on allocation failure or on
347 * end of file.
348 */
349
350 static int
351 ini_getline(struct ini_config *conf, FILE *fp)
352 {
353 int ch, pos;
354
355 memset(conf->line, 0, conf->linesize);
356 pos = 0;
357
358 while ((ch = fgetc(fp)) != '\n') {
359 if (feof(fp) || ferror(fp))
360 return -1;
361
362 /* End of buffer, realloc */
363 if (pos == conf->linesize) {
364 conf->line = realloc(conf->line, conf->linesize + 513);
365 if (conf->line == NULL)
366 return -1;
367
368 conf->linesize += 512;
369 }
370
371 conf->line[pos++] = ch;
372 }
373
374 conf->line[pos] = '\0';
375
376 return 0;
377 }
378
379 /*
380 * Read the next line that have been successfully read. Returns NULL
381 * on allocation failure (instanciation of new section or option)
382 * or the file on success.
383 */
384
385 static void *
386 ini_readline(struct ini_config *conf)
387 {
388 char *lp;
389 int (*handler)(struct ini_config *, char **);
390
391 lp = conf->line;
392 SKIP_SPACES(lp);
393
394 /* Ignore empty line or comment */
395 if (*lp == '\0' || *lp == '#' || *lp == ';')
396 return conf;
397
398 while (*lp != '\0') {
399 SKIP_SPACES(lp);
400
401 /* Skip comments again and empty lines */
402 if (*lp == '\0' || *lp == '#' || *lp == ';')
403 return conf;
404
405 #ifdef INI_DEBUG
406 printf("-- line[%d] == [%s]\n", conf->lineno, conf->line);
407 #endif
408
409 if (*lp == '[')
410 handler = &ini_switch;
411 else if (!conf->ignore)
412 handler = &ini_register;
413 else
414 handler = NULL;
415
416 /* Success or not? */
417 if (handler != NULL && handler(conf, &lp) < 0)
418 return (I_FAILERROR(conf)) ? NULL : conf;
419
420 SKIP_SPACES(lp);
421 }
422
423 return conf;
424 }
425
426 /* On failure, seek next space */
427 #define SEEK_NEXT(lp) \
428 for (; !isspace(**lp) && **lp != '\0'; ++(*lp)) \
429 continue;
430
431 /* On other failure seek until the next line '\0' */
432 #define SEEK_NL(lp) \
433 for (; !isspace(**lp) && **lp != '\0'; ++(*lp))
434
435 /*
436 * Parse the new section (function called when '[' is found). Returns
437 * 0 or parse error (to avoid ini_readling from stopping) or -1 on
438 * allocation failure.
439 */
440
441 static int
442 ini_switch(struct ini_config *conf, char **lp)
443 {
444 char *endSection;
445
446 /* Section not parsed, ignore next option to prevent breakage */
447 if ((endSection = strchr(*lp, ']')) == NULL) {
448 WARN(conf, "line %d: parse error\n", conf->lineno);
449 SEEK_NEXT(lp);
450 return (conf->ignore = 1) - 2; /* single line rocks */
451 }
452
453 /* Redefinition of previous and not allowed */
454 ++(*lp);
455 if (conf->current != NULL && I_NOREDEFINE(conf) &&
456 (strncmp(conf->current->key, *lp, endSection - *lp)) == 0) {
457 WARN(conf, "line %d: redefining %s\n", conf->lineno, conf->current->key);
458 SEEK_NEXT(lp);
459 return (conf->ignore = 1) - 2;
460 }
461
462 if ((conf->current = malloc(sizeof (struct ini_section))) == NULL)
463 return -1;
464
465 if ((conf->current->key = xstrndup(*lp, endSection - *lp)) == NULL) {
466 free(conf->current);
467 return -1;
468 }
469
470 *lp = endSection + 1;
471
472 #ifdef INI_DEBUG
473 printf("-- current section is now [%s]\n", conf->current->key);
474 #endif
475
476 /* Finally add the new section to the config */
477 STAILQ_INIT(&conf->current->options);
478 STAILQ_INSERT_TAIL(&conf->sections, conf->current, next);
479
480 return (conf->ignore = 0);
481 }
482
483 /*
484 * Store the new option that have been parsed. Returns 0 on success or
485 * on parse error (to avoid ini_readline from stopping) and -1 on
486 * allocation failure.
487 */
488
489 static int
490 ini_register(struct ini_config *conf, char **lp)
491 {
492 char *assignKey, *endKey, *endValue, token = '\0';
493 int length = 0;
494 struct ini_option *option, tmp;
495
496 /* No '=' found */
497 if ((assignKey = strchr(*lp, '=')) == NULL) {
498 WARN(conf, "line %d: missing '='\n", conf->lineno);
499 SEEK_NEXT(lp);
500 return -1;
501 }
502
503 /* Find end of option */
504 endKey = *lp;
505 for (; !isspace(*endKey) && *endKey != '\0' && *endKey != '='; ++endKey)
506 continue;
507
508 /* Do not register empty option name */
509 if (endKey - *lp <= 0) {
510 WARN(conf, "line %d: 0-length option\n", conf->lineno);
511 SEEK_NL(lp);
512 return -1;
513 }
514
515 memset(&tmp, 0, sizeof (struct ini_option));
516 if ((tmp.key = xstrndup(*lp, endKey - *lp)) == NULL)
517 return -1;
518
519 endValue = &assignKey[1];
520 SKIP_SPACES(endValue);
521
522 /* Find end of option value */
523 token = *endValue;
524 if (token == '\'' || token == '"') {
525 for (*lp = ++endValue; *endValue != token && *endValue != '\0'; ++endValue)
526 continue;
527
528 length = endValue - *lp;
529
530 /* Correctly closed */
531 if (token != '\0' && *endValue == token)
532 ++ endValue;
533 else
534 WARN(conf, "line %d: missing '%c'\n", conf->lineno, token);
535 } else {
536 for (*lp = endValue; !isspace(*endValue) && *endValue != '\0'; ++endValue)
537 continue;
538
539 length = endValue - *lp;
540 }
541
542 if (length != 0)
543 tmp.value = xstrndup(*lp, length);
544
545 if ((option = xoptiondup(&tmp)) == NULL)
546 return -1;
547
548 #ifdef INI_DEBUG
549 printf("-- next option [%s] is set to [%s]\n", tmp.key, tmp.value);
550 #endif
551
552 /* Finally add the new option to the current section */
553 *lp = endValue;
554 STAILQ_INSERT_TAIL(&conf->current->options, option, next);
555
556 return 0;
557 }
558
559 static void *
560 ini_fatal(struct ini_config *conf, FILE *fp, const char *fmt, ...)
561 {
562 va_list ap;
563
564 if (conf != NULL) {
565 struct ini_section *s, *stmp;
566 struct ini_option *o, *otmp;
567
568 if (conf->line != NULL)
569 free(conf->line);
570
571 STAILQ_FOREACH_SAFE(s, &conf->sections, next, stmp) {
572 STAILQ_FOREACH_SAFE(o, &s->options, next, otmp) {
573 free(o->key);
574 free(o->value);
575
576 STAILQ_REMOVE(&s->options, o, ini_option, next);
577
578 free(o);
579 }
580
581 free(s->key);
582 free(s);
583 }
584
585 }
586
587 if (fp != NULL)
588 fclose(fp);
589
590 va_start(ap, fmt);
591 vsnprintf(iniError, 1024, fmt, ap);
592 va_end(ap);
593
594 /* Directly print error if VERBOSE is enabled */
595 WARN(conf, "%s\n", iniError);
596
597 free(conf);
598
599 return NULL;
600 }
601
602 static char *
603 xstrndup(const char *src, size_t max)
604 {
605 char *res;
606 size_t length;
607
608 for (length = 0; length < max && src[length] != '\0'; ++length)
609 continue;
610
611 if ((res = malloc(length + 1)) == NULL)
612 return NULL;
613
614 memcpy(res, src, length);
615 res[length] = '\0';
616
617 return res;
618 }
619
620 static struct ini_option *
621 xoptiondup(const struct ini_option *option)
622 {
623 struct ini_option *res;
624
625 /*
626 * Value may be NULL but not option's key.
627 */
628 if (option->key == NULL) {
629 if (option->value != NULL)
630 free(option->value);
631
632 return NULL;
633 }
634
635 if ((res = malloc(sizeof (struct ini_option))) == NULL)
636 return NULL;
637
638 res->key = option->key;
639 res->value = option->value;
640
641 return res;
642 }