qLibc
qaconf.c
Go to the documentation of this file.
1 /******************************************************************************
2  * qLibc
3  *
4  * Copyright (c) 2010-2015 Seungyoung Kim.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
28 
29 /**
30  * @file qaconf.c Apache-style configuration file parser.
31  *
32  * Apache-style Configuration is a configuration file syntax and format
33  * originally introduced by Apache HTTPd project. This format is powerful,
34  * flexible and human friendly. Even though this code gets distributed
35  * as a part of qLibc project, the code is written not to have any external
36  * dependencies to make this single file stands alone for better portability.
37  * It is purely written from the ground up and dedicated to the public
38  * by Seungyoung Kim.
39  *
40  * Sample Apache-style Configuration Syntax:
41  * @code
42  * # Lines that begin with the hash character "#" are considered comments.
43  * Listen 53
44  * Protocols UDP TCP
45  * IPSEC On
46  *
47  * <Domain "qdecoder.org">
48  * TTL 86400
49  * MX 10 mail.qdecoder.org
50  *
51  * <Host mail>
52  * IPv4 192.168.10.1
53  * TXT "US Rack-13D-18 \"San Jose's\""
54  * </Host>
55  *
56  * <Host www>
57  * IPv4 192.168.10.2
58  * TXT 'KR Rack-48H-31 "Seoul\'s"'
59  * TTL 3600
60  * </Host>
61  * </Domain>
62  *
63  * <Domain "ringfs.org">
64  * <Host www>
65  * CNAME www.qdecoder.org
66  * </Host>
67  * </Domain>
68  * @endcode
69  *
70  * @code
71  * // THIS EXAMPLE CODE CAN BE FOUND IN EXAMPLES DIRECTORY.
72  *
73  * // Define scope.
74  * // QAC_SCOPE_ALL and QAC_SCOPE_ROOT are predefined.
75  * // Custum scope should be defined from 2(1 << 1).
76  * // Note) These values are ORed(bit operation), so the number should be
77  * // 2(1<<1), 4(1<<2), 6(1<<3), 8(1<<4), ...
78  * enum {
79  * OPT_SECTION_ALL = QAC_SECTION_ALL, // pre-defined
80  * OPT_SECTION_ROOT = QAC_SECTION_ROOT, // pre-defined
81  * OPT_SECTION_DOMAIN = (1 << 1), // user-defined section
82  * OPT_SECTION_HOST = (1 << 2), // user-defined section
83  * };
84  *
85  * // Define callback proto-types.
86  * static QAC_CB(confcb_debug);
87  *
88  * // Define options and callbacks.
89  * static qaconf_option_t options[] = {
90  * {"Listen", QAC_TAKE_INT, confcb_debug, 0, OPT_SECTION_ALL},
91  * {"Protocols", QAC_TAKEALL, confcb_debug, 0, OPT_SECTION_ROOT},
92  * {"IPSEC", QAC_TAKE_BOOL, confcb_debug, 0, OPT_SECTION_ROOT},
93  * {"Domain", QAC_TAKE_STR, confcb_debug, OPT_SECTION_DOMAIN, OPT_SECTION_ROOT},
94  * { "TTL", QAC_TAKE_INT, confcb_debug, 0, OPT_SECTION_DOMAIN | OPT_SECTION_HOST},
95  * { "MX", QAC_TAKE2 | QAC_A1_INT, confcb_debug, 0, OPT_SECTION_DOMAIN},
96  * { "Host", QAC_TAKE_STR, confcb_debug, OPT_SECTION_HOST, OPT_SECTION_DOMAIN},
97  * { "IPv4", QAC_TAKE_STR, confcb_debug, 0, OPT_SECTION_HOST},
98  * { "TXT", QAC_TAKE_STR, confcb_debug, 0, OPT_SECTION_HOST},
99  * { "CNAME", QAC_TAKE_STR, confcb_debug, 0, OPT_SECTION_HOST},
100  * QAC_OPTION_END
101  * };
102  *
103  * int user_main(void)
104  * {
105  * // Create a userdata structure.
106  * struct MyConf myconf;
107  *
108  * // Initialize and create a qaconf object.
109  * qaconf_t *conf = qaconf();
110  * if (conf == NULL) {
111  * printf("Failed to open '" CONF_PATH "'.\n");
112  * return -1;
113  * }
114  *
115  * // Register options.
116  * conf->addoptions(conf, options);
117  *
118  * // Set callback userdata
119  * // This is a userdata which will be provided on callback
120  * conf->setuserdata(conf, &myconf);
121  *
122  * // Run parser.
123  * int count = conf->parse(conf, CONF_PATH, QAC_CASEINSENSITIVE);
124  * if (count < 0) {
125  * printf("Error: %s\n", conf->errmsg(conf));
126  * } else {
127  * printf("Successfully loaded.\n");
128  * }
129  *
130  * // Verify userdata structure.
131  * if (conf->errmsg(conf) == NULL) { // another way to check parsing error.
132  * // codes here
133  * }
134  *
135  * // Release resources.
136  * conf->free(conf);
137  * }
138  *
139  * static QAC_CB(confcb_debug)
140  * {
141  * int i;
142  * for (i = 0; i < data->level; i++) {
143  * printf (" ");
144  * }
145  *
146  * // Print option name
147  * if (data->otype == QAC_OTYPE_SECTIONOPEN) {
148  * printf("<%s>", data->argv[0]);
149  * } else if (data->otype == QAC_OTYPE_SECTIONCLOSE) {
150  * printf("</%s>", data->argv[0]);
151  * } else { // This is QAC_OTYPE_OPTION type.
152  * printf("%s", data->argv[0]);
153  * }
154  *
155  * // Print parent names
156  * qaconf_cbdata_t *parent;
157  * for (parent = data->parent; parent != NULL; parent = parent->parent) {
158  * printf(" ::%s(%s)", parent->argv[0], parent->argv[1]);
159  * }
160  *
161  * // Print option arguments
162  * for (i = 1; i < data->argc; i++) {
163  * printf(" [%d:%s]", i, data->argv[i]);
164  * }
165  * printf("\n");
166  *
167  * // Return OK
168  * return NULL;
169  * }
170  * @endcode
171  *
172  * @code
173  * [Output]
174  * Listen [1:53]
175  * Protocols [1:UDP] [2:TCP]
176  * IPSEC [1:1]
177  * <Domain> [1:qdecoder.org]
178  * TTL ::Domain(qdecoder.org) [1:86400]
179  * MX ::Domain(qdecoder.org) [1:10] [2:mail.qdecoder.org]
180  * <Host> ::Domain(qdecoder.org) [1:mail]
181  * IPv4 ::Host(mail) ::Domain(qdecoder.org) [1:192.168.10.1]
182  * TXT ::Host(mail) ::Domain(qdecoder.org) [1:US Rack-13D-18 "San Jose's"]
183  * </Host> ::Domain(qdecoder.org) [1:mail]
184  * <Host> ::Domain(qdecoder.org) [1:www]
185  * IPv4 ::Host(www) ::Domain(qdecoder.org) [1:192.168.10.2]
186  * TXT ::Host(www) ::Domain(qdecoder.org) [1:KR Rack-48H-31 "Seoul's"]
187  * TTL ::Host(www) ::Domain(qdecoder.org) [1:3600]
188  * </Host> ::Domain(qdecoder.org) [1:www]
189  * </Domain> [1:qdecoder.org]
190  * <Domain> [1:ringfs.org]
191  * <Host> ::Domain(ringfs.org) [1:www]
192  * CNAME ::Host(www) ::Domain(ringfs.org) [1:www.qdecoder.org]
193  * </Host> ::Domain(ringfs.org) [1:www]
194  * </Domain> [1:ringfs.org]
195  * Successfully loaded.
196  * @endcode
197  */
198 
199 #ifndef DISABLE_QACONF
200 
201 #include <stdio.h>
202 #include <stdlib.h>
203 #include <stdbool.h>
204 #include <stdarg.h>
205 #include <string.h>
206 #include <assert.h>
207 #include <errno.h>
208 #include "qinternal.h"
209 #include "utilities/qstring.h"
210 #include "extensions/qaconf.h"
211 
212 #ifndef _DOXYGEN_SKIP
213 #define MAX_LINESIZE (1024*4)
214 
215 /* internal functions */
216 static int addoptions(qaconf_t *qaconf, const qaconf_option_t *options);
217 static void setdefhandler(qaconf_t *qaconf, qaconf_cb_t *callback);
218 static void setuserdata(qaconf_t *qaconf, const void *userdata);
219 static int parse(qaconf_t *qaconf, const char *filepath, uint8_t flags);
220 static const char *errmsg(qaconf_t *qaconf);
221 static void reseterror(qaconf_t *qaconf);
222 static void free_(qaconf_t *qaconf);
223 
224 static int _parse_inline(qaconf_t *qaconf, FILE *fp, uint8_t flags,
225  enum qaconf_section sectionid,
226  qaconf_cbdata_t *cbdata_parent);
227 static void _seterrmsg(qaconf_t *qaconf, const char *format, ...);
228 static void _free_cbdata(qaconf_cbdata_t *cbdata);
229 static int _is_str_number(const char *s);
230 static int _is_str_bool(const char *s);
231 #endif
232 
233 /**
234  * Create a new configuration object.
235  *
236  * @return a pointer of new qaconf_t object.
237  *
238  * @code
239  * qaconf_t *conf = qaconf();
240  * if (conf == NULL) {
241  * // Insufficient memory.
242  * }
243  * @endcode
244  */
245 qaconf_t *qaconf(void) {
246  // Malloc qaconf_t structure
247  qaconf_t *qaconf = (qaconf_t *) malloc(sizeof(qaconf_t));
248  if (qaconf == NULL)
249  return NULL;
250 
251  // Initialize the structure
252  memset((void *) (qaconf), '\0', sizeof(qaconf_t));
253 
254  // member methods
255  qaconf->addoptions = addoptions;
256  qaconf->setdefhandler = setdefhandler;
257  qaconf->setuserdata = setuserdata;
258  qaconf->parse = parse;
259  qaconf->errmsg = errmsg;
260  qaconf->reseterror = reseterror;
261  qaconf->free = free_;
262 
263  return qaconf;
264 }
265 
266 /**
267  * qaconf_t->addoptions(): Register option directives.
268  *
269  * @param qaconf qaconf_t object.
270  * @param options array pointer of qaconf_option_t.
271  *
272  * @return a number of options registered(added).
273  *
274  * @code
275  * qaconf_option_t options[] = {
276  * {"Listen", QAC_TAKE_INT, confcb_debug, 0, OPT_SECTION_ALL},
277  * {"Protocols", QAC_TAKEALL, confcb_debug, 0, OPT_SECTION_ROOT},
278  * {"IPSEC", QAC_TAKE_BOOL, confcb_debug, 0, OPT_SECTION_ROOT},
279  * {"Domain", QAC_TAKE_STR, confcb_debug, OPT_SECTION_DOMAIN, OPT_SECTION_ROOT},
280  * { "TTL", QAC_TAKE_INT, confcb_debug, 0, OPT_SECTION_DOMAIN | OPT_SECTION_HOST},
281  * { "MX", QAC_TAKE2 | QAC_A1_INT, confcb_debug, 0, OPT_SECTION_DOMAIN},
282  * { "Host", QAC_TAKE_STR, confcb_debug, OPT_SECTION_HOST, OPT_SECTION_DOMAIN},
283  * { "IPv4", QAC_TAKE_STR, confcb_debug, 0, OPT_SECTION_HOST},
284  * { "TXT", QAC_TAKE_STR, confcb_debug, 0, OPT_SECTION_HOST},
285  * { "CNAME", QAC_TAKE_STR, confcb_debug, 0, OPT_SECTION_HOST},
286  * QAC_OPTION_END
287  * };
288  *
289  * // Register options.
290  * qaconf_t *conf = qaconf();
291  * conf->addoptions(conf, options);
292  * (...codes goes...)
293  * @endcode
294  *
295  * It takes an array of options as provided in the sample codes.
296  * Each option consists of 5 parameters as below
297  *
298  * @code
299  * 1st) Option Name : A option directive name.
300  * 2nd) Arguments : A number of arguments this option takes and their types.
301  * 3rd) Callback : A function pointer for callback.
302  * 4th) Section ID : Section ID if this option is a section like <Option>.
303  * Otherwise 0 for regular option.
304  * 5th) Sections : ORed section IDs where this option can be specified.
305  * @endcode
306  *
307  * Example:
308  *
309  * @code
310  * {"TTL", QAC_TAKE_INT, confcb_debug, 0, OPT_SECTION_DOMAIN | OPT_SECTION_HOST}
311  * 1st) Option name is "TTL"
312  * 2nd) It takes 1 argument and its type must be integer.
313  * 3rd) Callback function, confcb_debug, will be called.
314  * 4th) This is a regular option and does not have section id.
315  * 5th) This option can be specified in OPT_SECTION_DOMAIN and OPT_SECTION_HOST.
316  * @endcode
317  *
318  * OPTION NAME field:
319  *
320  * Option name is a unique string. Even an option is section type like <option>
321  * only name part without bracket needs to be specifed.
322  *
323  * ARGUMENT field:
324  *
325  * This field is for providing argument checking in parser level. So in user's
326  * callback routine can go simple. This provides checking of number of arguments
327  * this option can take and those argument type.
328  *
329  * In terms of argument types. There are 4 argument types as below.
330  * And first 5 arguments can be checked individually with different types.
331  *
332  * @code
333  * STR type : any type
334  * INT type : integer type. ex) 23, -12, 0
335  * FLOAT type : integer + floating point type. ex) 1.32, -32.5, 23, -12, 0
336  * BOOL type : bool type ex) 1/0, true/false, on/off, yes/no
337  * @endcode
338  *
339  * When a BOOL type is specified, the argument passed to callback will be
340  * replaced to "1" or "0" for convenience use. For example, if "On" is specified
341  * as a argument and if BOOL type checking is specified, then actual argument
342  * which will be passed to callback will have "1". So we can simply determine it
343  * like "bool enabled = atoi(data->argv[1])".
344  *
345  * If original input argument needs to be passed to callback, specify STR type.
346  *
347  * Here is some examples of how to specify "Arguments" field.
348  *
349  * @code
350  * An option takes 1 argument.
351  * QAC_TAKE_STR <= String(any) type
352  * QAC_TAKE_INT <= Integer type
353  * QAC_TAKE_FLOAT <= Float type
354  * QAC_TAKE_BOOL <= Bool type
355  *
356  * QAC_TAKE1 <= Equavalent to QAC_TAKE_STR
357  * QAC_TAKE1 | QAC_A1_BOOL <= Equavalent to QAC_TAKE_BOOL
358  *
359  * An option takes 2 arguments, bool and float.
360  * QAC_TAKE2 | QAC_A1_BOOL | QAC_A2_FLOAT
361  *
362  * An option takes any number of arguments in any type.
363  * QAC_TAKEALL
364  *
365  * An option takes any number of arguments but 1st one must be bool and
366  * 2nd one must be integer and rest of them must be float.
367  * QAC_TAKEALL | QAC_A1_BOOL | QAC_A2_INT | QAC_AA_FLOAT
368  * @endcode
369  *
370  * CALLBACK field:
371  *
372  * User defined callback function. We provide a macro, QAC_CB, for function
373  * proto type. Always use QAC_CB macro.
374  *
375  * @code
376  * QAC_CB(sample_cb) {
377  * (...codes...)
378  * }
379  *
380  * is equavalent to
381  *
382  * char *sample_cb(qaconf_cbdata_t *data, void *userdata) {
383  * (...codes...)
384  * }
385  * @endcode
386  *
387  * Callback function will be called with 2 arguments. One is callback data and
388  * the other one is userdata. Userdata is the data pointer set by setuserdata().
389  *
390  * Here is data structure. Arguments belong to the option can be accessed via
391  * argv variables like data->argv[1]. argv[0] is for the option name.
392  *
393  * @code
394  * struct qaconf_cbdata_s {
395  * enum qaconf_otype otype; // option type
396  * uint64_t section; // current section where this option is located
397  * uint64_t sections; // ORed all parent's sectionid(s) including current sections
398  * uint8_t level; // number of parents(level), root level is 0
399  * qaconf_cbdata_t *parent; // upper parent link
400  *
401  * int argc; // number arguments. always equal or greater than 1.
402  * char **argv; // argument pointers. argv[0] is option name.
403  * }
404  * @endcode
405  *
406  * SECTION ID field:
407  *
408  * If an option is an section like <Option>, section id can be assigned.
409  * This section id can be used to limit some other option directives to be
410  * located only inside of that section. So this is your choice. If it doesn't
411  * require to check directory scope, we can just specify 0 here.
412  *
413  * There are 2 pre-defined section id, QAC_SECTION_ALL and QAC_SECTION_ROOT.
414  * When we define user section, it has to be defined from 2(1 << 1)as below.
415  *
416  * @code
417  * enum {
418  * OPT_SECTION_ALL = QAC_SECTION_ALL, // pre-defined
419  * OPT_SECTION_ROOT = QAC_SECTION_ROOT, // pre-defined
420  * OPT_SECTION_DOMAIN = (1 << 1), // user-defined section
421  * OPT_SECTION_HOST = (1 << 2), // user-defined section
422  * };
423  * @endcode
424  *
425  * Please note that this section IDs are ORed. So the section id should be
426  * assigned in bit operation manner as 2(1<<1), 4(1<<2), 6(1<<3), 8(1<<4), ...
427  *
428  * SECTION IDS field:
429  *
430  * This field is to limit the scope where an option is allowed to be specified.
431  * Multiple section IDs can be ORed.
432  *
433  * QAC_SECTION_ALL means an option can be appeared in anywhere.
434  *
435  * QAC_SECTION_ROOT means an option can be appeared only in top level and not
436  * inside of any sections.
437  */
438 static int addoptions(qaconf_t *qaconf, const qaconf_option_t *options) {
439  if (qaconf == NULL || options == NULL) {
440  _seterrmsg(qaconf, "Invalid parameters.");
441  return -1;
442  }
443 
444  // Count a number of options
445  uint32_t numopts;
446  for (numopts = 0; options[numopts].name != NULL; numopts++)
447  ;
448  if (numopts == 0)
449  return 0;
450 
451  // Realloc
452  size_t newsize = sizeof(qaconf_option_t) * (qaconf->numoptions + numopts);
453  qaconf->options = (qaconf_option_t *) realloc(qaconf->options, newsize);
454  memcpy(&qaconf->options[qaconf->numoptions], options,
455  sizeof(qaconf_option_t) * numopts);
456  qaconf->numoptions += numopts;
457 
458  return numopts;
459 }
460 
461 /**
462  * Set default callback function.
463  *
464  * Default callback function will be called for unregistered option directives.
465  * QAC_IGNOREUNKNOWN flag will be ignored when default callback has set.
466  *
467  * @param qaconf qaconf_t object.
468  * @param callback callback function pointer
469  */
470 static void setdefhandler(qaconf_t *qaconf, qaconf_cb_t *callback) {
471  qaconf->defcb = callback;
472 }
473 
474 /**
475  * qaconf_t->setuserdata(): Set userdata which will be provided on callback.
476  *
477  * @param qaconf qaconf_t object.
478  * @param userdata a pointer of userdata.
479  *
480  * @code
481  * // Define an example userdata
482  * struct MyConf {
483  * int sample;
484  * };
485  *
486  * int user_main(void) {
487  * struct MyConf myconf;
488  *
489  * (...codes...)
490  *
491  * // Set callback userdata.
492  * conf->setuserdata(conf, &myconf);
493  * (...codes...)
494  * }
495  *
496  * QAC_CB(confcb_callback_func) {
497  * (...codes...)
498  * // Type casting userdata for convenient use.
499  * struct MyConf *myconf = (struct MyConf *)userdata;
500  * myconf->sample++;
501  * (...codes...)
502  * return NULL;
503  * }
504  * @endcode
505  */
506 static void setuserdata(qaconf_t *qaconf, const void *userdata) {
507  qaconf->userdata = (void *) userdata;
508 }
509 
510 /**
511  * qaconf_t->parse(): Run parser.
512  *
513  * @param qaconf qaconf_t object.
514  * @param filepath configuration file path.
515  * @param flags parser options. (0 for default)
516  *
517  * @return A number of option directives parsed. -1 will be returned in case of
518  * error.
519  *
520  * Here is a list of flags. Multiple flags can be ORed.
521  *
522  * QAC_CASEINSENSITIVE: Option name is case-insensitive.
523  *
524  * QAC_IGNOREUNKNOWN : Ignore unknown option directives.
525  * This flag will be ignored if setdefhandler() has set.
526  *
527  * @code
528  * int c;
529  * c = conf->parse(conf, "sm1.conf", 0);
530  * c = conf->parse(conf, "sm2.conf", QAC_CASEINSENSITIVE);
531  * c = conf->parse(conf, "sm3.conf", QAC_CASEINSENSITIVE | QAC_IGNOREUNKNOWN);
532  * @endcode
533  */
534 static int parse(qaconf_t *qaconf, const char *filepath, uint8_t flags) {
535  // Open file
536  FILE *fp = fopen(filepath, "r");
537  if (fp == NULL) {
538  _seterrmsg(qaconf, "Failed to open file '%s'.", filepath);
539  return -1;
540  }
541 
542  // Set info
543  if (qaconf->filepath != NULL)
544  free(qaconf->filepath);
545  qaconf->filepath = strdup(filepath);
546  qaconf->lineno = 0;
547 
548  // Parse
549  int optcount = _parse_inline(qaconf, fp, flags, QAC_SECTION_ROOT, NULL);
550 
551  // Clean up
552  fclose(fp);
553 
554  return optcount;
555 }
556 
557 /**
558  * qaconf_t->errmsg(): Get last error message.
559  *
560  * @param qaconf qaconf_t object.
561  *
562  * @return A const pointer of error message string.
563  *
564  * @code
565  * int c = conf->parse(conf, "sample.conf", 0);
566  * if (c < 0) {
567  * // ERROR
568  * printf("%s\n", conf->errmsg(conf));
569  * }
570  * @endcode
571  */
572 static const char *errmsg(qaconf_t *qaconf) {
573  return (const char*) qaconf->errstr;
574 }
575 
576 /**
577  * qaconf_t->reseterror(): Clear error message.
578  *
579  * @param qaconf qaconf_t object.
580  *
581  * @code
582  * conf->reseterror(conf);
583  * conf->parse(conf, "sample.conf", 0);
584  * if (conf->errmsg(conf) != NULL) {
585  * // ERROR
586  * }
587  * @endcode
588  */
589 static void reseterror(qaconf_t *qaconf) {
590  if (qaconf->errstr != NULL) {
591  free(qaconf->errstr);
592  qaconf->errstr = NULL;
593  }
594 }
595 
596 /**
597  * qaconf_t->free(): Release resources.
598  *
599  * @param qaconf qaconf_t object.
600  *
601  * @code
602  * conf->free(conf);
603  * @endcode
604  */
605 static void free_(qaconf_t *qaconf) {
606  if (qaconf->filepath != NULL)
607  free(qaconf->filepath);
608  if (qaconf->errstr != NULL)
609  free(qaconf->errstr);
610  if (qaconf->options != NULL)
611  free(qaconf->options);
612  free(qaconf);
613 }
614 
615 #ifndef _DOXYGEN_SKIP
616 
617 #define ARGV_INIT_SIZE (4)
618 #define ARGV_INCR_STEP (8)
619 #define MAX_TYPECHECK (5)
620 static int _parse_inline(qaconf_t *qaconf, FILE *fp, uint8_t flags,
621  enum qaconf_section sectionid,
622  qaconf_cbdata_t *cbdata_parent) {
623  // Assign compare function.
624  int (*cmpfunc)(const char *, const char *) = strcmp;
625  if (flags & QAC_CASEINSENSITIVE)
626  cmpfunc = strcasecmp;
627 
628  char buf[MAX_LINESIZE];
629  bool doneloop = false;
630  bool exception = false;
631  int optcount = 0; // number of option entry processed.
632  int newsectionid = 0; // temporary store
633  void *freethis = NULL; // userdata to free
634  while (doneloop == false && exception == false) {
635 
636 #define EXITLOOP(fmt, args...) do { \
637  _seterrmsg(qaconf, "%s:%d " fmt, \
638  qaconf->filepath, qaconf->lineno, ##args); \
639  exception = true; \
640  goto exitloop; \
641 } while (0);
642 
643  if (fgets(buf, MAX_LINESIZE, fp) == NULL) {
644  // Check if section was opened and never closed
645  if (cbdata_parent != NULL) {
646  EXITLOOP("<%s> section was not closed.", cbdata_parent->argv[0]);
647  }
648  break;
649  }
650 
651  // Increase line number counter
652  qaconf->lineno++;
653 
654  // Trim white spaces
655  qstrtrim(buf);
656 
657  // Skip blank like and comments.
658  if (IS_EMPTY_STR(buf) || *buf == '#') {
659  continue;
660  }
661 
662  DEBUG("%s (line=%d)", buf, qaconf->lineno);
663 
664  // Create a callback data
665  qaconf_cbdata_t *cbdata = (qaconf_cbdata_t*) malloc(
666  sizeof(qaconf_cbdata_t));
667  ASSERT(cbdata != NULL);
668  memset(cbdata, '\0', sizeof(qaconf_cbdata_t));
669  if (cbdata_parent != NULL) {
670  cbdata->section = sectionid;
671  cbdata->sections = cbdata_parent->sections | sectionid;
672  cbdata->level = cbdata_parent->level + 1;
673  cbdata->parent = cbdata_parent;
674  } else {
675  cbdata->section = sectionid;
676  cbdata->sections = sectionid;
677  cbdata->level = 0;
678  cbdata->parent = NULL;
679  }
680 
681  // Escape section option
682  char *sp = buf;
683  if (*sp == '<') {
684  if (ENDING_CHAR(sp) != '>') {
685  EXITLOOP("Missing closing bracket. - '%s'.", buf);
686  }
687 
688  sp++;
689  if (*sp == '/') {
690  cbdata->otype = QAC_OTYPE_SECTIONCLOSE;
691  sp++;
692  } else {
693  cbdata->otype = QAC_OTYPE_SECTIONOPEN;
694  }
695 
696  // Remove tailing bracket
697  ENDING_CHAR(sp) = '\0';
698  } else {
699  cbdata->otype = QAC_OTYPE_OPTION;
700  }
701 
702  // Brackets has removed at this point
703  // Copy data into cbdata buffer.
704  cbdata->data = strdup(sp);
705  ASSERT(cbdata->data != NULL);
706 
707  // Parse and tokenize.
708  int argvsize = 0;
709  char *wp1, *wp2;
710  bool doneparsing = false;
711  for (wp1 = (char *) cbdata->data; doneparsing == false; wp1 = wp2) {
712  // Allocate/Realloc argv array
713  if (argvsize == cbdata->argc) {
714  argvsize += (argvsize == 0) ? ARGV_INIT_SIZE : ARGV_INCR_STEP;
715  cbdata->argv = (char**) realloc((void *) cbdata->argv,
716  sizeof(char*) * argvsize);
717  ASSERT(cbdata->argv != NULL);
718  }
719 
720  // Skip whitespaces
721  for (; (*wp1 == ' ' || *wp1 == '\t'); wp1++)
722  ;
723 
724  // Quote handling
725  int qtmark = 0; // 1 for singlequotation, 2 for doublequotation
726  if (*wp1 == '\'') {
727  qtmark = 1;
728  wp1++;
729  } else if (*wp1 == '"') {
730  qtmark = 2;
731  wp1++;
732  }
733 
734  // Parse a word
735  for (wp2 = wp1;; wp2++) {
736  if (*wp2 == '\0') {
737  doneparsing = true;
738  break;
739  } else if (*wp2 == '\'') {
740  if (qtmark == 1) {
741  qtmark = 0;
742  break;
743  }
744  } else if (*wp2 == '"') {
745  if (qtmark == 2) {
746  qtmark = 0;
747  break;
748  }
749  } else if (*wp2 == '\\') {
750  if (qtmark > 0) {
751  size_t wordlen = wp2 - wp1;
752  if (wordlen > 0)
753  memmove(wp1 + 1, wp1, wordlen);
754  wp1++;
755  wp2++;
756  }
757  } else if (*wp2 == ' ' || *wp2 == '\t') {
758  if (qtmark == 0)
759  break;
760  }
761  }
762  *wp2 = '\0';
763  wp2++;
764 
765  // Check quotations has paired.
766  if (qtmark > 0) {
767  EXITLOOP("Quotation hasn't properly closed.");
768  }
769 
770  // Store a argument
771  cbdata->argv[cbdata->argc] = wp1;
772  cbdata->argc++;
773  DEBUG(" argv[%d]=%s", cbdata->argc - 1, wp1);
774 
775  // For quoted string, this case can be happened.
776  if (*wp2 == '\0') {
777  doneparsing = true;
778  }
779  }
780 
781  // Check mismatch sectionclose
782  if (cbdata->otype == QAC_OTYPE_SECTIONCLOSE) {
783  if (cbdata_parent == NULL
784  || cmpfunc(cbdata->argv[0], cbdata_parent->argv[0])) {
785  EXITLOOP("Trying to close <%s> section that wasn't opened.",
786  cbdata->argv[0]);
787  }
788  }
789 
790  // Find matching option
791  bool optfound = false;
792  int i;
793  for (i = 0; optfound == false && i < qaconf->numoptions; i++) {
794  qaconf_option_t *option = &qaconf->options[i];
795 
796  if (!cmpfunc(cbdata->argv[0], option->name)) {
797  // Check sections
798  if ((cbdata->otype != QAC_OTYPE_SECTIONCLOSE)
799  && (option->sections != QAC_SECTION_ALL)
800  && (option->sections & sectionid) == 0) {
801  EXITLOOP("Option '%s' is in wrong section.", option->name);
802  }
803 
804  // Check argument types
805  if (cbdata->otype != QAC_OTYPE_SECTIONCLOSE) {
806  // Check number of arguments
807  int numtake = option->take & QAC_TAKEALL;
808  if (numtake != QAC_TAKEALL
809  && numtake != (cbdata->argc - 1)) {
810  EXITLOOP("'%s' option takes %d arguments.",
811  option->name, numtake);
812  }
813 
814  // Check argument types
815  int deftype; // 0:str, 1:int, 2:float, 3:bool
816  if (option->take & QAC_AA_INT)
817  deftype = 1;
818  else if (option->take & QAC_AA_FLOAT)
819  deftype = 2;
820  else if (option->take & QAC_AA_BOOL)
821  deftype = 3;
822  else
823  deftype = 0;
824 
825  int j;
826  for (j = 1; j < cbdata->argc && j <= MAX_TYPECHECK; j++) {
827  int argtype;
828  if (option->take & (QAC_A1_INT << (j - 1)))
829  argtype = 1;
830  else if (option->take & (QAC_A1_FLOAT << (j - 1)))
831  argtype = 2;
832  else if (option->take & (QAC_A1_BOOL << (j - 1)))
833  argtype = 3;
834  else
835  argtype = deftype;
836 
837  if (argtype == 1) {
838  // integer type
839  if (_is_str_number(cbdata->argv[j]) != 1) {
840  EXITLOOP(
841  "%dth argument of '%s' must be integer type.",
842  j, option->name);
843  }
844  } else if (argtype == 2) {
845  // floating point type
846  if (_is_str_number(cbdata->argv[j]) == 0) {
847  EXITLOOP(
848  "%dth argument of '%s' must be floating point. type",
849  j, option->name);
850  }
851  } else if (argtype == 3) {
852  // bool type
853  if (_is_str_bool(cbdata->argv[j]) != 0) {
854  // Change argument to "1".
855  strcpy(cbdata->argv[j], "1");
856  } else {
857  EXITLOOP(
858  "%dth argument of '%s' must be bool type.",
859  j, option->name);
860  }
861  }
862  }
863  }
864 
865  // Callback
866  //DEBUG("Callback %s", option->name);
867  qaconf_cb_t *usercb = option->cb;
868  if (usercb == NULL)
869  usercb = qaconf->defcb;
870  if (usercb != NULL) {
871  char *cberrmsg = NULL;
872 
873  if (cbdata->otype != QAC_OTYPE_SECTIONCLOSE) {
874  // Normal option and sectionopen
875  cberrmsg = usercb(cbdata, qaconf->userdata);
876  } else {
877  // QAC_OTYPE_SECTIONCLOSE
878 
879  // Change otype
880  ASSERT(cbdata_parent != NULL);
881  enum qaconf_otype orig_otype = cbdata_parent->otype;
882  cbdata_parent->otype = QAC_OTYPE_SECTIONCLOSE;
883 
884  // Callback
885  cberrmsg = usercb(cbdata_parent, qaconf->userdata);
886 
887  // Restore type
888  cbdata_parent->otype = orig_otype;
889  }
890 
891  // Error handling
892  if (cberrmsg != NULL) {
893  freethis = cberrmsg;
894  EXITLOOP("%s", cberrmsg);
895  }
896  }
897 
898  if (cbdata->otype == QAC_OTYPE_SECTIONOPEN) {
899  // Store it for later
900  newsectionid = option->sectionid;
901  }
902 
903  // Set found flag
904  optfound = true;
905  }
906  }
907 
908  // If not found.
909  if (optfound == false) {
910  if (qaconf->defcb != NULL) {
911  qaconf->defcb(cbdata, qaconf->userdata);
912  } else if ((flags & QAC_IGNOREUNKNOWN) == 0) {
913  EXITLOOP("Unregistered option '%s'.", cbdata->argv[0]);
914  }
915  }
916 
917  // Section handling
918  if (cbdata->otype == QAC_OTYPE_SECTIONOPEN) {
919  // Enter recursive call
920  DEBUG("Entering next level %d.", cbdata->level+1);
921  int optcount2 = _parse_inline(qaconf, fp, flags, newsectionid,
922  cbdata);
923  if (optcount2 >= 0) {
924  optcount += optcount2;
925  } else {
926  exception = true;
927  }DEBUG("Returned to previous level %d.", cbdata->level);
928  } else if (cbdata->otype == QAC_OTYPE_SECTIONCLOSE) {
929  // Leave recursive call
930  doneloop = true;
931  }
932 
933  exitloop:
934  // Release resources
935  if (freethis != NULL) {
936  free(freethis);
937  }
938 
939  if (cbdata != NULL) {
940  _free_cbdata(cbdata);
941  cbdata = NULL;
942  }
943 
944  if (exception == true) {
945  break;
946  }
947 
948  // Go up and down
949  // if (otype
950 
951  // Increase process counter
952  optcount++;
953  }
954 
955  return (exception == false) ? optcount : -1;
956 }
957 
958 static void _seterrmsg(qaconf_t *qaconf, const char *format, ...) {
959  if (qaconf->errstr != NULL)
960  free(qaconf->errstr);
961  DYNAMIC_VSPRINTF(qaconf->errstr, format);
962 }
963 
964 static void _free_cbdata(qaconf_cbdata_t *cbdata) {
965  if (cbdata->argv != NULL)
966  free(cbdata->argv);
967  if (cbdata->data != NULL)
968  free(cbdata->data);
969  free(cbdata);
970 }
971 
972 // return 2 for floating point .
973 // return 1 for integer
974 // return 0 for non number
975 static int _is_str_number(const char *s) {
976  char *op = (char *) s;
977  if (*op == '-') {
978  op++;
979  }
980 
981  char *cp, *dp;
982  for (cp = op, dp = NULL; *cp != '\0'; cp++) {
983  if ('0' <= *cp && *cp <= '9') {
984  continue;
985  }
986 
987  if (*cp == '.') {
988  if (cp == op)
989  return 0; // dot can't be at the beginning.
990  if (dp != NULL)
991  return 0; // dot can't be appeared more than once.
992  dp = cp;
993  continue;
994  }
995 
996  return 0;
997  }
998 
999  if (cp == op) {
1000  return 0; // empty string
1001  }
1002 
1003  if (dp != NULL) {
1004  if (dp + 1 == cp)
1005  return 0; // dot can't be at the end.
1006  return 2; // float point
1007  }
1008 
1009  // integer
1010  return 1;
1011 }
1012 
1013 static int _is_str_bool(const char *s) {
1014  if (!strcasecmp(s, "true"))
1015  return 1;
1016  else if (!strcasecmp(s, "on"))
1017  return 1;
1018  else if (!strcasecmp(s, "yes"))
1019  return 1;
1020  else if (!strcasecmp(s, "1"))
1021  return 1;
1022  return 0;
1023 }
1024 
1025 #endif /* _DOXYGEN_SKIP */
1026 
1027 #endif /* DISABLE_QACONF */
1028 
static int parse(qaconf_t *qaconf, const char *filepath, uint8_t flags)
qaconf_t->parse(): Run parser.
Definition: qaconf.c:534
static void setuserdata(qaconf_t *qaconf, const void *userdata)
qaconf_t->setuserdata(): Set userdata which will be provided on callback.
Definition: qaconf.c:506
static int addoptions(qaconf_t *qaconf, const qaconf_option_t *options)
qaconf_t->addoptions(): Register option directives.
Definition: qaconf.c:438
char * qstrtrim(char *str)
Remove white spaces(including CR, LF) from head and tail of the string.
Definition: qstring.c:55
static void free_(qaconf_t *qaconf)
qaconf_t->free(): Release resources.
Definition: qaconf.c:605
qaconf_t * qaconf(void)
Create a new configuration object.
Definition: qaconf.c:245
static void setdefhandler(qaconf_t *qaconf, qaconf_cb_t *callback)
Set default callback function.
Definition: qaconf.c:470
static const char * errmsg(qaconf_t *qaconf)
qaconf_t->errmsg(): Get last error message.
Definition: qaconf.c:572
static void reseterror(qaconf_t *qaconf)
qaconf_t->reseterror(): Clear error message.
Definition: qaconf.c:589