2 * Define routines to read INI-file like files.
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
23 #include "shared/report.h"
32 typedef struct section
{
35 struct section
*next_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
);
51 static int process_config(section
**current_section
, const char *source_descr
, FILE *f
);
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
)
65 section
*curr_section
= NULL
;
68 report(RPT_NOTICE
, "Using Configuration File: %s", filename
);
70 f
= fopen(filename
, "r");
75 #if defined(LCDPROC_CONFIG_READ_STRING)
76 result
= process_config(&curr_section
, get_next_char_f
, filename
, f
);
78 result
= process_config(&curr_section
, filename
, f
);
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.*/
94 /* We use a nested fuction to transfer the characters from buffer to parser*/
95 char get_next_char() {
99 if ((s
= find_section(sectionname
)) == NULL
)
100 s
= add_section(sectionname
);
102 return process_config(&s
, get_next_char
, "command line", NULL
);
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:
116 * s = config_get_string(...);
117 * sscanf(s, "%dx%d", &w, &h); // scan format like: 20x4
119 * ...and check the w and h values...
120 * \li Copy it to a preallocated buffer like \c device[256]:
122 * s = config_get_string(...);
123 * strncpy(device, s, sizeof(device));
124 * device[sizeof(device)-1] = '\0'; // make sure it is terminated
126 * \li Copy it to a newly allocated space in \c char \c *device:
128 * s = config_get_string(...);
129 * device = malloc(strlen(s)+1);
130 * if (device == NULL) return -5; // or whatever < 0
131 * strcpy( device, s );
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
);
149 return default_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
);
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) {
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) {
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
);
219 long int v
= strtol(k
->value
, &end
, 0);
221 if ((end
!= NULL
) && (end
!= k
->value
) && (*end
== '\0'))
222 /* Conversion succesful */
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
);
246 double v
= strtod(k
->value
, &end
);
248 if ((end
!= NULL
) && (end
!= k
->value
) && (*end
== '\0'))
249 /* Conversion succesful*/
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
);
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)
291 /** Clear configuration. */
292 void config_clear(void)
297 for (s
= first_section
; s
!= NULL
; s
= next_s
) {
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
;
309 /* Advance before we destroy the current section */
310 next_s
= s
->next_section
;
316 /* Finally make everything inaccessable */
317 first_section
= NULL
;
321 /**** INTERNAL FUNCTIONS ****/
323 static section
*find_section(const char *sectionname
)
327 for (s
= first_section
; s
!= NULL
; s
= s
->next_section
) {
328 if (strcasecmp(s
->name
, sectionname
) == 0) {
332 return NULL
; /* not found */
336 static section
*add_section(const char *sectionname
)
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
;
355 static key
*find_key(section
*s
, const char *keyname
, int skip
)
359 key
*last_key
= NULL
;
361 /* Check for NULL section*/
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) {
379 return NULL
; /* not found*/
383 static key
*add_key(section
*s
, const char *keyname
, const char *value
)
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
;
405 #if defined(LCDPROC_CONFIG_READ_STRING)
406 static char get_next_char_f(FILE *f
)
410 return((c
== EOF
) ? '\0' : c
);
417 #define ST_COMMENT 257
418 #define ST_SECTIONLABEL 258
419 #define ST_KEYNAME 259
420 #define ST_ASSIGNMENT 260
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
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
)
440 static int process_config(section
**current_section
, const char *source_descr
, FILE *f
)
443 int state
= ST_INITIAL
;
445 char sectionname
[MAXSECTIONLABELLENGTH
+1];
446 int sectionname_pos
= 0;
447 char keyname
[MAXKEYNAMELENGTH
+1];
449 char value
[MAXVALUELENGTH
+1];
456 #if !defined(LCDPROC_CONFIG_READ_STRING)
461 while (state
!= ST_END
) {
463 #if defined(LCDPROC_CONFIG_READ_STRING)
473 /* Secretly keep count of the line numbers */
494 state
= ST_SECTIONLABEL
;
496 sectionname
[sectionname_pos
] = '\0';
502 keyname
[keyname_pos
++] = ch
;
503 keyname
[keyname_pos
] = '\0';
506 case ST_SECTIONLABEL
:
507 /* section label: "["{non-space chars}+"]" */
511 /* premature end of label */
512 report(RPT_WARNING
, "Unterminated section label on line %d of %s: %s",
513 line_nr
, source_descr
, sectionname
);
515 state
= ST_INITIAL
; /* alrady at the end, no resync required */
518 /* label terminated: find/create section */
519 if (!(*current_section
= find_section(sectionname
))) {
520 *current_section
= add_section(sectionname
);
522 state
= ST_SECTIONLABEL_DONE
;
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);
531 // state = ST_INVALID_SECTIONLABEL; /* resync required */
534 /* append char to section label */
535 if (sectionname_pos
< MAXSECTIONLABELLENGTH
) {
536 sectionname
[sectionname_pos
++] = ch
;
537 sectionname
[sectionname_pos
] = '\0';
540 report(RPT_WARNING
, "Section name too long on line %d of %s: %s",
541 line_nr
, source_descr
, sectionname
);
543 state
= ST_INVALID_SECTIONLABEL
; /* resync required */
547 /* key name: {non-space chars}+ */
552 /* ignore trailing spaces */
553 if (keyname_pos
!= 0)
554 state
= ST_ASSIGNMENT
;
558 /* premature end of line */
559 report(RPT_WARNING
, "Loose word found on line %d of %s: %s",
560 line_nr
, source_descr
, keyname
);
562 state
= ST_INITIAL
; /* already at the end; no resync required */
565 /* end of key reached, "=" found, now we need a value */
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);
577 // state = ST_INVALID_KEYNAME; /* resync required */
580 /* append char to key name */
581 if (keyname_pos
< MAXKEYNAMELENGTH
) {
582 keyname
[keyname_pos
++] = ch
;
583 keyname
[keyname_pos
] = '\0';
586 report(RPT_WARNING
, "Key name too long on line %d of %s: %s",
587 line_nr
, source_descr
, keyname
);
589 state
= ST_INVALID_KEYNAME
; /* resync required */
593 /* assignement: "=" */
597 /* ignore leading spaces */
600 /* "=" found, now we need a value */
606 report(RPT_WARNING
, "Assigment expected on line %d of %s: %s",
607 line_nr
, source_descr
, keyname
);
609 state
= ST_INVALID_ASSIGNMENT
;
613 /* value: {non-space char}+ | "\""{any potentially-quoted char}+"\"" */
617 /* allow comment if we already had a value */
618 /* WHY ONLY THEN ? 'xx=' can be seen as equivalent to 'xx=""' */
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
);
631 state
= ST_INVALID_VALUE
;
635 /* ignore leading spaces */
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
);
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
;
657 state
= ST_QUOTEDVALUE
;
660 /* append char to value */
661 if (value_pos
< MAXVALUELENGTH
) {
662 value
[value_pos
++] = ch
;
663 value
[value_pos
] = '\0';
666 report(RPT_WARNING
, "Value too long on line %d of %s, at key: %s",
667 line_nr
, source_descr
, keyname
);
669 state
= ST_INVALID_VALUE
;
673 /* a quoted part of a string */
677 report(RPT_WARNING
, "Premature end of quoted string on line %d of %s: %s",
678 line_nr
, source_descr
, keyname
);
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 '\') */
708 value
[value_pos
++] = ch
;
709 value
[value_pos
] = '\0';
712 case ST_SECTIONLABEL_DONE
:
727 /* illegal characters */
728 report(RPT_WARNING
, "Invalid character '%c' on line %d of %s",
729 ch
, line_nr
, source_descr
);
731 state
= ST_INVALID_VALUE
;
733 case ST_INVALID_SECTIONLABEL
:
734 /* invalid section label: resync up to end of label/next line */
738 case ST_INVALID_ASSIGNMENT
:
739 case ST_INVALID_KEYNAME
:
740 case ST_INVALID_VALUE
:
742 /* comment or error: ignore anything up to the next line */
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
);
758 return (error
) ? -1 : 0;
762 #if CONFIGFILE_DEBUGTEST
763 void config_dump(void)
767 for (s
= first_section
; s
!= NULL
; s
= s
->next_section
) {
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
[])
783 config_read_file(argv
[1]);