Base: LCDproc 0.5.2
[lcdproc-de200c.git] / shared / configfile.c
blob8f6ac4c739c03d9a4241d3f35599e2cbaafe4e3e
1 /** \file configfile.c
2 * Define routines to read INI-file like files.
3 */
5 /* This file is part of LCDd, the lcdproc server.
7 * This file is released under the GNU General Public License. Refer to the
8 * COPYING file distributed with this package.
10 * Copyright(c) 2001, Joris Robijn
11 * (c) 2003, Rene Wagner
12 * (c) 2006,2007 Peter Marschall
16 #include "config.h"
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <stdlib.h>
23 #include "shared/report.h"
26 typedef struct key {
27 char *name;
28 char *value;
29 struct key *next_key;
30 } key;
32 typedef struct section {
33 char *name;
34 key *first_key;
35 struct section *next_section;
36 } section;
39 static section *first_section = NULL;
40 /* Yes there is a static. It's C after all :)*/
43 static section *find_section(const char *sectionname);
44 static section *add_section(const char *sectionname);
45 static key *find_key(section *s, const char *keyname, int skip);
46 static key *add_key(section *s, const char *keyname, const char *value);
47 static char get_next_char_f(FILE *f);
48 #if defined(LCDPROC_CONFIG_READ_STRING)
49 static int process_config(section **current_section, char(*get_next_char)(), const char *source_descr, FILE *f);
50 #else
51 static int process_config(section **current_section, const char *source_descr, FILE *f);
52 #endif
55 /**** PUBLIC FUNCTIONS ****/
57 /** Parse configuration from INI-file style config file into memory.
58 * \param filename Name of the config file.
59 * \retval 0 config successfully parsed
60 * \retval <0 error occurred
62 int config_read_file(const char *filename)
64 FILE *f;
65 section *curr_section = NULL;
66 int result = 0;
68 report(RPT_NOTICE, "Using Configuration File: %s", filename);
70 f = fopen(filename, "r");
71 if (f == NULL) {
72 return -1;
75 #if defined(LCDPROC_CONFIG_READ_STRING)
76 result = process_config(&curr_section, get_next_char_f, filename, f);
77 #else
78 result = process_config(&curr_section, filename, f);
79 #endif
81 fclose(f);
83 return result;
87 #if defined(LCDPROC_CONFIG_READ_STRING)
88 int config_read_string(const char *sectionname, const char *str)
89 /* All the config parameters are placed in the given section in memory.*/
91 int pos = 0;
92 section *s;
94 /* We use a nested fuction to transfer the characters from buffer to parser*/
95 char get_next_char() {
96 return str[pos++];
99 if ((s = find_section(sectionname)) == NULL)
100 s = add_section(sectionname);
102 return process_config(&s, get_next_char, "command line", NULL);
104 #endif
107 /** Get string from configuration in memory.
109 * The strings returned are always NUL-terminated.
110 * They should never be modified, and used only short-term.
111 * In successive calls this function can re-use the data space !
113 * You can do some things with the returned string:
114 * \li Scan or parse it:
115 * \code
116 * s = config_get_string(...);
117 * sscanf(s, "%dx%d", &w, &h); // scan format like: 20x4
118 * \endcode
119 * ...and check the w and h values...
120 * \li Copy it to a preallocated buffer like \c device[256]:
121 * \code
122 * s = config_get_string(...);
123 * strncpy(device, s, sizeof(device));
124 * device[sizeof(device)-1] = '\0'; // make sure it is terminated
125 * \endcode
126 * \li Copy it to a newly allocated space in \c char \c *device:
127 * \code
128 * s = config_get_string(...);
129 * device = malloc(strlen(s)+1);
130 * if (device == NULL) return -5; // or whatever < 0
131 * strcpy( device, s );
132 * \endcode
134 * \param sectionname Name of the section where the key is sought.
135 * \param keyname Name of the key to look for.
136 * \param skip Number of values to skip/ignore before returning the value.
137 * This is used to iterate through the values of a multi-valued key:
138 * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last.
139 * \param default_value Default value if section/key is not found
140 * or \c skip exceeds the number of values of the key.
141 * \return Value found / \c default_value
143 const char *config_get_string(const char *sectionname, const char *keyname,
144 int skip, const char *default_value)
146 key *k = find_key(find_section(sectionname), keyname, skip);
148 if (k == NULL)
149 return default_value;
151 return k->value;
153 /* This is the safer way:*/
155 /* Reallocate memory space for the return value*/
157 string_storage = realloc(string_storage,(strlen(k->value) / 256 + 1) * 256);
158 strcpy(string_storage, k->value);
160 But then you also need a global static string_storage = NULL;
165 /** Get boolean value from configuration in memory.
167 * Legal boolean values are:
168 * \li \c 0 , \c false , \c off , \c no or \c n for FALSE.
169 * \li \c 1 , \c true , \c on , \c yes or \c y for TRUE
171 * \param sectionname Name of the section where the key is sought.
172 * \param keyname Name of the key to look for.
173 * \param skip Number of values to skip/ignore before returning the value.
174 * This is used to iterate through the values of a multi-valued key:
175 * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last.
176 * \param default_value Default value if section/key is not found, value is no legal boolean,
177 * or \c skip exceeds the number of values of the key.
178 * \return Value found / \c default_value
180 short config_get_bool(const char *sectionname, const char *keyname,
181 int skip, short default_value)
183 key *k = find_key(find_section(sectionname), keyname, skip);
185 if (k == NULL)
186 return default_value;
188 if (strcasecmp(k->value, "0") == 0 || strcasecmp(k->value, "false") == 0
189 || strcasecmp(k->value, "n") == 0 || strcasecmp(k->value, "no") == 0
190 || strcasecmp(k->value, "off") == 0) {
191 return 0;
193 if (strcasecmp(k->value, "1") == 0 || strcasecmp(k->value, "true") == 0
194 || strcasecmp(k->value, "y") == 0 || strcasecmp(k->value, "yes") == 0
195 || strcasecmp(k->value, "on") == 0) {
196 return 1;
198 return default_value;
202 /** Get integer from configuration in memory.
203 * \param sectionname Name of the section where the key is sought.
204 * \param keyname Name of the key to look for.
205 * \param skip Number of values to skip/ignore before returning the value.
206 * This is used to iterate through the values of a multi-valued key:
207 * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last.
208 * \param default_value Default value if section/key is not found, value is no integer,
209 * or \c skip exceeds the number of values of the key.
210 * \return Value found / \c default_value
212 long int config_get_int(const char *sectionname, const char *keyname,
213 int skip, long int default_value)
215 key *k = find_key(find_section(sectionname), keyname, skip);
217 if (k != NULL) {
218 char *end;
219 long int v = strtol(k->value, &end, 0);
221 if ((end != NULL) && (end != k->value) && (*end == '\0'))
222 /* Conversion succesful */
223 return v;
225 return default_value;
229 /** Get floating point number from configuration in memory.
230 * \param sectionname Name of the section where the key is sought.
231 * \param keyname Name of the key to look for.
232 * \param skip Number of values to skip/ignore before returning the value.
233 * This is used to iterate through the values of a multi-valued key:
234 * \c 0 for the first value, \c 1 for the 2nd, ... and \c -1 for the last.
235 * \param default_value Default value if section/key is not found, value is no floating point number
236 * or \c skip exceeds the number of values of the key.
237 * \return Value found / \c default_value
239 double config_get_float(const char *sectionname, const char *keyname,
240 int skip, double default_value)
242 key *k = find_key(find_section(sectionname), keyname, skip);
244 if (k != NULL) {
245 char *end;
246 double v = strtod(k->value, &end);
248 if ((end != NULL) && (end != k->value) && (*end == '\0'))
249 /* Conversion succesful*/
250 return v;
252 return default_value;
256 /** Test whether the configuration containis a specific section.
257 * \param sectionname Name of the section to look for.
258 * \retval 0 section not in config
259 * \retval 1 section in config
261 int config_has_section(const char *sectionname)
263 return (find_section(sectionname) != NULL) ? 1 : 0;
267 /** Test whether the configuration contains a specific key in a specfic section.
268 * \param sectionname Name of the section where the key is sought.
269 * \param keyname Name of the key to look for.
270 * \retval 0 key or section not found
271 * \retval n key found with \c n values (\c n > 0)
273 int config_has_key(const char *sectionname, const char *keyname)
275 section *s = find_section(sectionname);
276 int count = 0;
278 if (s != NULL) {
279 key *k;
281 for (k = s->first_key; k != NULL; k = k->next_key) {
282 /* Did we find the right key ?*/
283 if (strcasecmp(k->name, keyname) == 0)
284 count++;
287 return count;
291 /** Clear configuration. */
292 void config_clear(void)
294 section *s;
295 section *next_s;
297 for (s = first_section; s != NULL; s = next_s) {
298 key *k;
299 key *next_k;
301 for (k = s->first_key; k != NULL; k = next_k) {
302 /* Advance before we destroy the current key */
303 next_k = k->next_key;
305 free(k->name);
306 free(k->value);
307 free(k);
309 /* Advance before we destroy the current section */
310 next_s = s->next_section;
312 /* And destroy it */
313 free(s->name);
314 free(s);
316 /* Finally make everything inaccessable */
317 first_section = NULL;
321 /**** INTERNAL FUNCTIONS ****/
323 static section *find_section(const char *sectionname)
325 section *s;
327 for (s = first_section; s != NULL; s = s->next_section) {
328 if (strcasecmp(s->name, sectionname) == 0) {
329 return s;
332 return NULL; /* not found */
336 static section *add_section(const char *sectionname)
338 section *s;
339 section **place = &first_section;
341 for (s = first_section; s != NULL; s = s->next_section)
342 place = &(s->next_section);
344 *place = (section*) malloc(sizeof(section));
345 if (*place != NULL) {
346 (*place)->name = strdup(sectionname);
347 (*place)->first_key = NULL;
348 (*place)->next_section = NULL;
351 return(*place);
355 static key *find_key(section *s, const char *keyname, int skip)
357 key *k;
358 int count = 0;
359 key *last_key = NULL;
361 /* Check for NULL section*/
362 if (s == NULL)
363 return NULL;
365 for (k = s->first_key; k != NULL; k = k->next_key) {
367 /* Did we find the right key ?*/
368 if (strcasecmp(k->name, keyname) == 0) {
369 if (count == skip)
370 return k;
372 count++;
373 last_key = k;
376 if (skip == -1)
377 return last_key;
379 return NULL; /* not found*/
383 static key *add_key(section *s, const char *keyname, const char *value)
385 if (s != NULL) {
386 key *k;
387 key **place = &(s->first_key);
389 for (k = s->first_key; k != NULL; k = k->next_key)
390 place = &(k->next_key);
392 *place = (key *) malloc(sizeof(key));
393 if (*place != NULL) {
394 (*place)->name = strdup(keyname);
395 (*place)->value = strdup(value);
396 (*place)->next_key = NULL;
399 return(*place);
401 return NULL;
405 #if defined(LCDPROC_CONFIG_READ_STRING)
406 static char get_next_char_f(FILE *f)
408 int c = fgetc(f);
410 return((c == EOF) ? '\0' : c);
412 #endif
415 /* Parser states */
416 #define ST_INITIAL 0
417 #define ST_COMMENT 257
418 #define ST_SECTIONLABEL 258
419 #define ST_KEYNAME 259
420 #define ST_ASSIGNMENT 260
421 #define ST_VALUE 261
422 #define ST_QUOTEDVALUE 262
423 #define ST_SECTIONLABEL_DONE 263
424 #define ST_VALUE_DONE 264
425 #define ST_INVALID_SECTIONLABEL 265
426 #define ST_INVALID_KEYNAME 266
427 #define ST_INVALID_ASSIGNMENT 267
428 #define ST_INVALID_VALUE 268
429 #define ST_END 999
431 /* Limits */
432 #define MAXSECTIONLABELLENGTH 40
433 #define MAXKEYNAMELENGTH 40
434 #define MAXVALUELENGTH 200
437 #if defined(LCDPROC_CONFIG_READ_STRING)
438 static int process_config(section **current_section, char(*get_next_char)(), const char *source_descr, FILE *f)
439 #else
440 static int process_config(section **current_section, const char *source_descr, FILE *f)
441 #endif
443 int state = ST_INITIAL;
444 int ch;
445 char sectionname[MAXSECTIONLABELLENGTH+1];
446 int sectionname_pos = 0;
447 char keyname[MAXKEYNAMELENGTH+1];
448 int keyname_pos = 0;
449 char value[MAXVALUELENGTH+1];
450 int value_pos = 0;
451 int escape = 0;
452 key *k;
453 int line_nr = 1;
454 int error = 0;
456 #if !defined(LCDPROC_CONFIG_READ_STRING)
457 if (f == NULL)
458 return(0);
459 #endif
461 while (state != ST_END) {
463 #if defined(LCDPROC_CONFIG_READ_STRING)
464 ch = (f != NULL)
465 ? get_next_char(f)
466 : get_next_char();
467 #else
468 ch = fgetc(f);
469 if (ch == EOF)
470 ch = '\0';
471 #endif
473 /* Secretly keep count of the line numbers */
474 if (ch == '\n')
475 line_nr++;
477 switch (state) {
478 case ST_INITIAL:
479 switch (ch) {
480 case '#':
481 case ';':
482 /* comment start */
483 state = ST_COMMENT;
484 /* fall through */
485 case '\0':
486 case '\n':
487 case '\r':
488 case '\t':
489 case ' ':
490 /* ignore spaces */
491 break;
492 case '[':
493 /* section name */
494 state = ST_SECTIONLABEL;
495 sectionname_pos = 0;
496 sectionname[sectionname_pos] = '\0';
497 break;
498 default:
499 /* key word */
500 state = ST_KEYNAME;
501 keyname_pos = 0;
502 keyname[keyname_pos++] = ch;
503 keyname[keyname_pos] = '\0';
505 break;
506 case ST_SECTIONLABEL:
507 /* section label: "["{non-space chars}+"]" */
508 switch (ch) {
509 case '\0':
510 case '\n':
511 /* premature end of label */
512 report(RPT_WARNING, "Unterminated section label on line %d of %s: %s",
513 line_nr, source_descr, sectionname);
514 error = 1;
515 state = ST_INITIAL; /* alrady at the end, no resync required */
516 break;
517 case ']':
518 /* label terminated: find/create section */
519 if (!(*current_section = find_section(sectionname))) {
520 *current_section = add_section(sectionname);
522 state = ST_SECTIONLABEL_DONE;
523 break;
524 // case '\r':
525 // case '\t':
526 // case ' ':
527 // /* no spaces allowed in section labels WHY? */
528 // report(RPT_WARNING, "Invalid character in section label on line %d of %s: %s",
529 // line_nr, source_descr, sectionname);
530 // error = 1;
531 // state = ST_INVALID_SECTIONLABEL; /* resync required */
532 // break;
533 default:
534 /* append char to section label */
535 if (sectionname_pos < MAXSECTIONLABELLENGTH) {
536 sectionname[sectionname_pos++] = ch;
537 sectionname[sectionname_pos] = '\0';
538 break;
540 report(RPT_WARNING, "Section name too long on line %d of %s: %s",
541 line_nr, source_descr, sectionname);
542 error = 1;
543 state = ST_INVALID_SECTIONLABEL; /* resync required */
545 break;
546 case ST_KEYNAME:
547 /* key name: {non-space chars}+ */
548 switch (ch) {
549 case '\r':
550 case '\t':
551 case ' ':
552 /* ignore trailing spaces */
553 if (keyname_pos != 0)
554 state = ST_ASSIGNMENT;
555 break;
556 case '\0':
557 case '\n':
558 /* premature end of line */
559 report(RPT_WARNING, "Loose word found on line %d of %s: %s",
560 line_nr, source_descr, keyname);
561 error = 1;
562 state = ST_INITIAL; /* already at the end; no resync required */
563 break;
564 case '=':
565 /* end of key reached, "=" found, now we need a value */
566 state = ST_VALUE;
567 value[0] = '\0';
568 value_pos = 0;
569 break;
570 // case '"':
571 // case '[':
572 // case ']':
573 // /* character invalid in key names WHY ? */
574 // report(RPT_WARNING, "Invalid character in key name on line %d of %s: %s",
575 // line_nr, source_descr, keyname);
576 // error = 1;
577 // state = ST_INVALID_KEYNAME; /* resync required */
578 // break;
579 default:
580 /* append char to key name */
581 if (keyname_pos < MAXKEYNAMELENGTH) {
582 keyname[keyname_pos++] = ch;
583 keyname[keyname_pos] = '\0';
584 break;
586 report(RPT_WARNING, "Key name too long on line %d of %s: %s",
587 line_nr, source_descr, keyname);
588 error = 1;
589 state = ST_INVALID_KEYNAME; /* resync required */
591 break;
592 case ST_ASSIGNMENT:
593 /* assignement: "=" */
594 switch (ch) {
595 case '\t':
596 case ' ':
597 /* ignore leading spaces */
598 break;
599 case '=':
600 /* "=" found, now we need a value */
601 state = ST_VALUE;
602 value[0] = '\0';
603 value_pos = 0;
604 break;
605 default:
606 report(RPT_WARNING, "Assigment expected on line %d of %s: %s",
607 line_nr, source_descr, keyname);
608 error = 1;
609 state = ST_INVALID_ASSIGNMENT;
611 break;
612 case ST_VALUE:
613 /* value: {non-space char}+ | "\""{any potentially-quoted char}+"\"" */
614 switch (ch) {
615 case '#':
616 case ';':
617 /* allow comment if we already had a value */
618 /* WHY ONLY THEN ? 'xx=' can be seen as equivalent to 'xx=""' */
619 if (value_pos > 0) {
620 state = ST_COMMENT;
621 break;
623 /* fall through */
624 case '[':
625 case ']':
626 case '=':
627 /* illegal characters WHY? */
628 report(RPT_WARNING, "Invalid character '%c' in value on line %d of %s, at key: %s",
629 ch, line_nr, source_descr, keyname);
630 error = 1;
631 state = ST_INVALID_VALUE;
632 break;
633 case '\t':
634 case ' ':
635 /* ignore leading spaces */
636 if (value_pos == 0)
637 break;
638 /* fall through */
639 case '\0':
640 case '\n':
641 case '\r':
642 /* value complete */
643 if (!*current_section) {
644 report(RPT_WARNING, "Data outside sections on line %d of %s with key: %s",
645 line_nr, source_descr, keyname);
646 error = 1;
648 else {
649 /* Store the value*/
650 k = add_key(*current_section, keyname, value);
652 /* And be ready for next thing...*/
653 state = ((ch == ' ') || (ch == '\t')) ? ST_VALUE_DONE : ST_INITIAL;
654 break;
655 case '"':
656 /* quoted string */
657 state = ST_QUOTEDVALUE;
658 break;
659 default:
660 /* append char to value */
661 if (value_pos < MAXVALUELENGTH) {
662 value[value_pos++] = ch;
663 value[value_pos] = '\0';
664 break;
666 report(RPT_WARNING, "Value too long on line %d of %s, at key: %s",
667 line_nr, source_descr, keyname);
668 error = 1;
669 state = ST_INVALID_VALUE;
671 break;
672 case ST_QUOTEDVALUE:
673 /* a quoted part of a string */
674 switch (ch) {
675 case '\0':
676 case '\n':
677 report(RPT_WARNING, "Premature end of quoted string on line %d of %s: %s",
678 line_nr, source_descr, keyname);
679 error = 1;
680 state = ST_INITIAL;
681 break;
682 case '\\':
683 if (!escape) {
684 escape = 1;
685 break;
687 /* fall though */
688 case '"':
689 if (!escape) {
690 state = ST_VALUE;
691 break;
693 /* fall though */
694 default:
695 if (escape) {
696 switch (ch) {
697 case 'a': ch = '\a'; break;
698 case 'b': ch = '\b'; break;
699 case 'f': ch = '\f'; break;
700 case 'n': ch = '\n'; break;
701 case 'r': ch = '\r'; break;
702 case 't': ch = '\t'; break;
703 case 'v': ch = '\v'; break;
704 /* default: literal char (i.e. ignore '\') */
706 escape = 0;
708 value[value_pos++] = ch;
709 value[value_pos] = '\0';
711 break;
712 case ST_SECTIONLABEL_DONE:
713 case ST_VALUE_DONE:
714 switch (ch) {
715 case ';':
716 case '#':
717 state = ST_COMMENT;
718 break;
719 case '\0':
720 case '\n':
721 state = ST_INITIAL;
722 break;
723 case '\t':
724 case ' ':
725 break;
726 default:
727 /* illegal characters */
728 report(RPT_WARNING, "Invalid character '%c' on line %d of %s",
729 ch, line_nr, source_descr);
730 error = 1;
731 state = ST_INVALID_VALUE;
733 case ST_INVALID_SECTIONLABEL:
734 /* invalid section label: resync up to end of label/next line */
735 if (ch == ']')
736 state = ST_INITIAL;
737 /* fall through */
738 case ST_INVALID_ASSIGNMENT:
739 case ST_INVALID_KEYNAME:
740 case ST_INVALID_VALUE:
741 case ST_COMMENT:
742 /* comment or error: ignore anything up to the next line */
743 if (ch == '\n')
744 state = ST_INITIAL;
746 if (ch == '\0') {
747 if ((!error) && (state != ST_INITIAL) && (state != ST_COMMENT) &&
748 (state != ST_SECTIONLABEL_DONE) && (state != ST_VALUE_DONE)) {
749 report(RPT_WARNING, "Premature end of configuration on line %d of %s: %d",
750 line_nr, source_descr, state);
752 error = 1;
754 state = ST_END;
758 return (error) ? -1 : 0;
762 #if CONFIGFILE_DEBUGTEST
763 void config_dump(void)
765 section *s;
767 for (s = first_section; s != NULL; s = s->next_section) {
768 key *k;
770 fprintf(stderr, "[%s]\n", s->name);
772 for (k = s->first_key; k != NULL; k = k->next_key)
773 fprintf(stderr, "%s = \"%s\"\n", k->name, k->value);
775 fprintf(stderr, "\n");
780 int main(int argc, char *argv[])
782 if (argc > 0)
783 config_read_file(argv[1]);
784 config_dump();
786 #endif