2 * libcfg+ - precise command line & config file parsing library
4 * cfg+.c - main implementation
5 * ____________________________________________________________
7 * Developed by Ondrej Jombik <nepto@platon.sk>
8 * and Lubomir Host <rajo@platon.sk>
9 * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/
10 * All rights reserved.
12 * See README file for more information about this software.
13 * See COPYING file for license information.
15 * Download the latest version from
16 * http://platon.sk/projects/libcfg+/
19 /* $Platon: libcfg+/src/cfg+.c,v 1.61 2004/01/12 06:03:08 nepto Exp $ */
35 # if !STDC_HEADERS && HAVE_MEMORY_H
44 #include <platon/str/strdyn.h>
45 #include <platon/str/strplus.h>
51 extern char *cfg_default_properties
[CFG_N_PROPS
][4];
54 cfg_get_context(options
)
55 struct cfg_option
*options
;
60 con
= (CFG_CONTEXT
) malloc(sizeof(*con
));
64 /* Setting all struct values to 0 or NULL */
65 memset(con
, '\0', sizeof(*con
));
67 /* Initializing context type and options set */
68 con
->type
= CFG_NO_CONTEXT
;
69 con
->options
= options
;
71 /* Initializaing properties to default values */
72 for (i
= 0; i
< CFG_N_PROPS
; i
++) {
73 con
->prop
[i
] = PLATON_FUNC(strdyn_create_ar
)(cfg_default_properties
[i
]);
74 if (con
->prop
[i
] == NULL
) {
75 /* TODO: possible freeing on failure */
84 cfg_get_cmdline_context(begin_pos
, size
, argv
, options
)
88 struct cfg_option
*options
;
92 con
= cfg_get_context(options
);
96 cfg_set_cmdline_context(con
, begin_pos
, size
, argv
);
102 cfg_get_cmdline_context_argc(argc
, argv
, options
)
105 struct cfg_option
*options
;
109 /* Starting from the beginning and parsing till the end */
110 con
= cfg_get_cmdline_context((long) 0, (long) argc
, argv
, options
);
114 /* When parsing by argc/argv we must skip first argument argv[0],
115 because there is the name of program. */
116 cfg_set_context_flag(con
, CFG_SKIP_FIRST
);
122 cfg_get_cfgfile_context(begin_pos
, size
, filename
, options
)
126 struct cfg_option
*options
;
130 con
= cfg_get_context(options
);
134 cfg_set_cfgfile_context(con
, begin_pos
, size
, filename
);
140 cfg_set_cmdline_context(con
, begin_pos
, size
, argv
)
141 const CFG_CONTEXT con
;
146 cfg_reset_context(con
);
148 con
->type
= CFG_CMDLINE
;
149 con
->begin_pos
= begin_pos
;
156 cfg_set_cmdline_context_argc(con
, argc
, argv
)
157 const CFG_CONTEXT con
;
162 /* This function could be macro. But appropriate `get' equivalent, function
163 cfg_get_cmdline_context_argc(), is in fact function. So this is function
166 cfg_set_cmdline_context(con
, (long) 0, (long) argc
, argv
);
171 cfg_set_cfgfile_context(con
, begin_pos
, size
, filename
)
172 const CFG_CONTEXT con
;
177 cfg_reset_context(con
);
179 con
->type
= CFG_CFGFILE
;
180 con
->begin_pos
= begin_pos
;
183 /* TODO: filename copying? (if yes than don't forget memory freeing) */
184 if (filename
!= NULL
)
185 con
->filename
= (char *) filename
;
191 cfg_reset_context(con
)
192 const CFG_CONTEXT con
;
194 con
->error_code
= CFG_OK
;
196 con
->cur_idx_tmp
= 0;
197 con
->parsing_started
= 0;
199 if (con
->used_opt_idx
!= NULL
) {
200 free(con
->used_opt_idx
);
201 con
->used_opt_idx
= NULL
;
204 __cfg_free_currents(con
);
206 /* Problematic code? */
207 if (con
->fhandle
!= NULL
) {
208 fclose(con
->fhandle
);
214 cfg_free_context(con
)
215 const CFG_CONTEXT con
;
219 cfg_reset_context(con
);
221 for (i
= 0; i
< CFG_N_PROPS
; i
++) {
223 (void) cfg_clear_property(con
, i
);
226 PLATON_FUNC(strdyn_free
)(con
->prop
[i
]);
234 con
->filename
= NULL
;
235 con
->type
= CFG_NO_CONTEXT
;
242 const CFG_CONTEXT con
;
244 cfg_fprint_error(con
, stderr
);
248 cfg_fprint_error(con
, fh
)
249 const CFG_CONTEXT con
;
254 s
= cfg_get_error_str(con
);
257 fputs("not enough memory for error printing\n", fh
);
266 cfg_get_error_str(con
)
267 const CFG_CONTEXT con
;
270 char *str_type
= con
->type
== CFG_LINE
? "on command line" : "in config file";
271 char *str_pos
= con
->type
== CFG_LINE
? /* "near" */ "at position"
272 : (con
->flags
& CFG_FILE_LINE_POS_USAGE
? "on line" : "at position");
273 char *str_opt
= cfg_get_cur_opt(con
);
274 char *str_arg
= cfg_get_cur_arg(con
);
275 char *str_filename
= con
->filename
;
276 int idx
= cfg_get_cur_idx(con
) + 1;
279 str_opt
= str_opt
== NULL
? "" : str_opt
;
280 str_arg
= str_arg
== NULL
? "" : str_arg
;
281 str_filename
= str_filename
== NULL
? "" : str_filename
;
283 /* WARNING: pay attention on possible buffer owerflow here; used constant
284 must be enough to cover str_type, str_pos, str_idx and the rest
285 of error message with deliminators. */
287 #ifndef max /* Borrowed from libplaton */
288 #define max(a, b) (((a) > (b)) ? (a) : (b))
291 size
= 300 + max(strlen(str_opt
) + strlen(str_arg
), strlen(str_filename
));
293 if ((s
= (char *) malloc(sizeof(char) * size
)) == NULL
)
296 switch (con
->error_code
) {
299 sprintf(s
, "no error on %s", str_type
);
302 case CFG_ERROR_NOARG
:
303 sprintf(s
, "argument is missing for option '%s' %s %d %s",
304 str_opt
, str_pos
, idx
, str_type
);
307 case CFG_ERROR_NOTALLOWEDARG
:
308 sprintf(s
, "option '%s' does not have allowed argument %s %d %s",
309 str_opt
, str_pos
, idx
, str_type
);
312 case CFG_ERROR_BADOPT
:
313 sprintf(s
, "argument '%s' for option '%s' could not be parsed"
315 str_arg
, str_opt
, str_pos
, idx
, str_type
);
318 case CFG_ERROR_BADQUOTE
:
319 sprintf(s
, "error in quotations in option '%s' %s %d %s",
320 str_opt
, str_pos
, idx
, str_type
);
323 case CFG_ERROR_BADNUMBER
:
324 sprintf(s
, "argument '%s' for option '%s' could not be converted"
325 " to appropriate numeric type %s %d %s",
326 str_arg
, str_opt
, str_pos
, idx
, str_type
);
329 case CFG_ERROR_OVERFLOW
:
330 sprintf(s
, "given number '%s' was too big or too small in option"
332 str_arg
, str_opt
, str_pos
, idx
, str_type
);
335 case CFG_ERROR_MULTI
:
336 sprintf(s
, "multiple arguments used for single option '%s' %s %d %s",
337 str_opt
, str_pos
, idx
, str_type
);
340 case CFG_ERROR_NOMEM
:
341 sprintf(s
, "not enough memory");
344 case CFG_ERROR_STOP_STR_FOUND
:
345 sprintf(s
, "stop string '%s' was found %s %d %s",
346 str_opt
, str_pos
, idx
, str_type
);
349 case CFG_ERROR_NOEQUAL
:
350 sprintf(s
, "no equal sign founded %s %d %s",
351 str_pos
, idx
, str_type
);
354 case CFG_ERROR_UNKNOWN
:
355 sprintf(s
, "unknown option '%s' %s %d %s",
356 str_opt
, str_pos
, idx
, str_type
);
359 case CFG_ERROR_FILE_NOT_FOUND
:
360 sprintf(s
, "config file '%s' was not found", str_filename
);
363 case CFG_ERROR_SEEK_ERROR
:
364 sprintf(s
, "seek error in %s", str_type
);
367 case CFG_ERROR_INTERNAL
:
368 sprintf(s
, "libcfg internal error");
370 sprintf(s
, "unknown error (%d)", con
->error_code
);
378 cfg_get_static_error_str(errorcode
)
386 case CFG_ERROR_NOARG
:
387 return "argument is missing for option";
389 case CFG_ERROR_NOTALLOWEDARG
:
390 return "argument is not allowed for option";
392 case CFG_ERROR_BADOPT
:
393 return "option's argument could not be parsed";
395 case CFG_ERROR_BADQUOTE
:
396 return "error in quotations";
398 case CFG_ERROR_BADNUMBER
:
399 return "option could not be converted to appropriate numeric type";
401 case CFG_ERROR_OVERFLOW
:
402 return "given number was too big or too small";
404 case CFG_ERROR_MULTI
:
405 return "multiple arguments used for single option";
407 case CFG_ERROR_NOMEM
:
408 return "not enough memory";
410 case CFG_ERROR_STOP_STR_FOUND
:
411 return "stop string was found";
413 case CFG_ERROR_NOEQUAL
:
414 return "no equal sign on the line";
416 case CFG_ERROR_UNKNOWN
:
417 return "unknown option";
419 case CFG_ERROR_FILE_NOT_FOUND
:
420 return "file not found";
422 case CFG_ERROR_SEEK_ERROR
:
423 return "file seek error";
425 case CFG_ERROR_INTERNAL
:
426 return "internal error";
429 return "unknown error";
432 #if defined(SELF) || defined(SELFTEST) || defined(SELF_CFG)
435 * Selftest compilation:
436 * gcc -Wall -I. -I.. -L. -DHAVE_CONFIG_H -DSELF -o test cfg+.c -lcfg+
440 ar_print(name
, format
, vals
)
446 if (strcmp(format
, "%s")) {
449 printf("%s: ", name
);
450 for (i
= 0; vals
[i
] != NULL
; i
++) {
452 if (! strcmp(format
, "%e") || ! strcmp(format
, "%f"))
453 printf(format
, *(((float **) vals
)[i
]));
455 printf(format
, *(((int **) vals
)[i
]));
464 s
= PLATON_FUNC(strdyn_implode_str
)((char **) vals
, "][");
465 printf("%s = [%s]\n", name
, s
);
470 PLATON_FUNC(strdyn_free
)((char **) vals
);
473 printf("%s uninitialized\n", name
);
485 int o_nice
= 20, o_verbose
= 0;
486 char *o_cfgfile
= NULL
, *o_string
= NULL
;
487 char **o_name
= NULL
, **o_leftover
= NULL
;
489 int o_int
= -33, **o_multi_int
= NULL
;
490 unsigned int o_uint
= 33, **o_multi_uint
= NULL
;
491 long o_long
= -333, **o_multi_long
= NULL
;
492 unsigned long o_ulong
= 333, **o_multi_ulong
= NULL
;
493 float o_float
= -3333.33, **o_multi_float
= NULL
;
494 double o_double
= -33333.33, **o_multi_double
= NULL
;
497 struct cfg_option options
[] = {
498 { "nice", 'n', "nice",
499 CFG_INT
, (void *) &o_nice
, 0 },
500 { "verbose", 'v', "verbose",
501 CFG_BOOLEAN
+ CFG_MULTI
, (void *) &o_verbose
, 0 },
502 { "name", 'a', "name",
503 CFG_STRING
+ CFG_MULTI_SEPARATED
, (void *) &o_name
, 0 },
504 { "config-file", 'f', NULL
,
505 CFG_STRING
, (void *) &o_cfgfile
, 0 },
507 { "bool", 'b', "boolean",
508 CFG_BOOLEAN
, (void *) &o_boolean
, 1 },
510 CFG_INT
, (void *) &o_int
, 0 },
511 { "multi_int", 'I', "multi int",
512 CFG_INT
+ CFG_MULTI_SEPARATED
, (void *) &o_multi_int
, 0 },
513 { "uint", 'u', "unsigned int",
514 CFG_UINT
, (void *) &o_uint
, 0 },
515 { "multi_uint", 'U', "multi unsigned int",
516 CFG_UINT
+ CFG_MULTI
, (void *) &o_multi_uint
, 0 },
517 { "long", 'l', "long",
518 CFG_LONG
, (void *) &o_long
, 0 },
519 { "multi_long", 'L', "multi long",
520 CFG_LONG
+ CFG_MULTI_SEPARATED
, (void *) &o_multi_long
, 0 },
521 { "ulong", 'o', "unsigned long",
522 CFG_ULONG
, (void *) &o_ulong
, 0 },
523 { "multi_ulong", 'O', "multi unsigned long",
524 CFG_ULONG
+ CFG_MULTI
, (void *) &o_multi_ulong
, 0 },
525 { "float", 'f', "float",
526 CFG_FLOAT
, (void *) &o_float
, 0 },
527 { "multi_float", 'F', "multi float",
528 CFG_FLOAT
+ CFG_MULTI_SEPARATED
, (void *) &o_multi_float
, 0 },
529 { "double", 'd', "double",
530 CFG_DOUBLE
, (void *) &o_double
, 0 },
531 { "multi_double", 'D', "mdouble",
532 CFG_DOUBLE
+ CFG_MULTI_SEPARATED
, (void *) &o_multi_double
, 0},
533 { "string", 's', "string",
534 CFG_STRING
, (void *) &o_string
, 0 },
536 CFG_STRING
+ CFG_MULTI_SEPARATED
+ CFG_LEFTOVER_ARGS
, (void*) &o_leftover
, 0 },
540 con
= cfg_get_context(options
);
544 /* This is powerful testing stuff :)
546 printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS));
547 cfg_set_context_flag(con, CFG_ADVANCED_LEFTOVERS);
548 cfg_set_context_flag(con, CFG_ADVANCED_LEFTOVERS);
549 printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS));
550 cfg_clear_context_flag(con, CFG_ADVANCED_LEFTOVERS);
551 printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS));
552 cfg_set_context_flag(con, CFG_ADVANCED_LEFTOVERS);
553 printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS));
557 cfg_set_cmdline_context(con
, 1, argc
, argv
);
558 cfg_set_context_flag(con
, CFG_ADVANCED_LEFTOVERS
);
559 cfg_set_context_flag(con
, CFG_FILE_LINE_POS_USAGE
);
560 if (0) { /* Testing if short command line options
561 works also without '-' prefix */
562 cfg_clear_property(con
, CFG_LINE_SHORT_OPTION_PREFIX
);
563 cfg_add_property(con
, CFG_LINE_SHORT_OPTION_PREFIX
, "");
565 if (0) { /* Testing if long command line options
566 works also without '--' prefix */
567 cfg_clear_property(con
, CFG_LINE_LONG_OPTION_PREFIX
);
568 cfg_add_property(con
, CFG_LINE_LONG_OPTION_PREFIX
, "");
572 cfg_set_cfgfile_context(con
, 1, 0, o_cfgfile
);
573 /* cfg_remove_cfgfile_comment_prefix(con, "//");
574 cfg_add_cfgfile_comment_prefix(con, "//"); */
575 cfg_remove_property(con
, CFG_FILE_COMMENT_PREFIX
, "//");
576 cfg_add_property(con
, CFG_FILE_COMMENT_PREFIX
, "//");
579 while ((ret
= cfg_get_next_opt(con
)) > 0) {
580 printf("ret = %d, opt = '%s', arg = '%s'", ret
,
581 cfg_get_cur_opt(con
), cfg_get_cur_arg(con
));
584 printf(", idx = %d, argv[idx] = '%s'",
585 cfg_get_cur_idx(con
),
586 argv
[cfg_get_cur_idx(con
)]);
593 "+------------------+\n"
594 "| Error printing |\n"
595 "+------------------+");
598 cfg_fprint_error(con
, stdout
);
601 printf("***** %s error %d at %d: %s\n",
602 i
== 0 ? "cmdline" : "cfgfile",
603 ret
, cfg_get_cur_idx(con
),
604 cfg_get_static_error_str(ret
));
606 printf("***** opt = '%s', arg = '%s'",
607 cfg_get_cur_opt(con
), cfg_get_cur_arg(con
));
610 printf(", idx = %d, argv[idx] = '%s'",
611 cfg_get_cur_idx(con
), argv
[cfg_get_cur_idx(con
)]);
616 if (i
== 0 && o_cfgfile
== NULL
)
623 cfg_free_context(con
);
626 "+--------------------------+\n"
627 "| Common values printing |\n"
628 "+--------------------------+");
630 printf("o_verbose = %d, o_nice = %d\n", o_verbose
, o_nice
);
631 printf("o_boolean = %d\n", o_boolean
);
632 printf("o_int = %d, o_uint = %u\n", o_int
, o_uint
);
633 printf("o_long = %ld, o_ulong = %lu\n", o_long
, o_ulong
);
634 printf("o_float = %f, o_double = %e\n", o_float
, o_double
);
635 printf("o_string = <%s>\n", o_string
);
638 "+-------------------------+\n"
639 "| Multi values printing |\n"
640 "+-------------------------+");
642 ar_print("o_multi_int", "%d", (void **) o_multi_int
);
643 ar_print("o_multi_uint", "%u", (void **) o_multi_uint
);
644 ar_print("o_multi_long", "%ld", (void **) o_multi_long
);
645 ar_print("o_multi_ulong", "%lu", (void **) o_multi_ulong
);
646 ar_print("o_multi_float", "%f", (void **) o_multi_float
);
647 ar_print("o_multi_double", "%e", (void **) o_multi_double
);
648 ar_print("o_name", "%s", (void **) o_name
);
649 ar_print("o_leftover", "%s", (void **) o_leftover
);
656 /* Modeline for ViM {{{
658 * vim600:fdm=marker fdl=0 fdc=0: