Fix use of deprecated types, for now and the future.
[gnutls.git] / src / cfg / cfg+.c
blobdb019114c6199b553d21d7f9a4728e85a4022bee
1 /*
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 $ */
21 /* Includes {{{ */
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <stdio.h>
27 #if STDC_HEADERS
28 # include <stdlib.h>
29 #else
30 # if HAVE_STDLIB_H
31 # include <stdlib.h>
32 # endif
33 #endif
34 #if HAVE_STRING_H
35 # if !STDC_HEADERS && HAVE_MEMORY_H
36 # include <memory.h>
37 # endif
38 # include <string.h>
39 #endif
40 #if HAVE_STRINGS_H
41 # include <strings.h>
42 #endif
44 #include <platon/str/strdyn.h>
45 #include <platon/str/strplus.h>
47 #include "cfg+.h"
48 #include "shared.h"
49 /* }}} */
51 extern char *cfg_default_properties[CFG_N_PROPS][4];
53 CFG_CONTEXT
54 cfg_get_context(options)
55 struct cfg_option *options;
56 { /* {{{ */
57 register int i;
58 CFG_CONTEXT con;
60 con = (CFG_CONTEXT) malloc(sizeof(*con));
61 if (con == NULL)
62 return NULL;
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 */
76 return NULL;
80 return con;
81 } /* }}} */
83 CFG_CONTEXT
84 cfg_get_cmdline_context(begin_pos, size, argv, options)
85 long begin_pos;
86 long size;
87 char **argv;
88 struct cfg_option *options;
89 { /* {{{ */
90 CFG_CONTEXT con;
92 con = cfg_get_context(options);
93 if (con == NULL)
94 return NULL;
96 cfg_set_cmdline_context(con, begin_pos, size, argv);
98 return con;
99 } /* }}} */
101 CFG_CONTEXT
102 cfg_get_cmdline_context_argc(argc, argv, options)
103 int argc;
104 char **argv;
105 struct cfg_option *options;
106 { /* {{{ */
107 CFG_CONTEXT con;
109 /* Starting from the beginning and parsing till the end */
110 con = cfg_get_cmdline_context((long) 0, (long) argc, argv, options);
111 if (con == NULL)
112 return con;
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);
118 return con;
119 } /* }}} */
121 CFG_CONTEXT
122 cfg_get_cfgfile_context(begin_pos, size, filename, options)
123 long begin_pos;
124 long size;
125 char *filename;
126 struct cfg_option *options;
127 { /* {{{ */
128 CFG_CONTEXT con;
130 con = cfg_get_context(options);
131 if (con == NULL)
132 return NULL;
134 cfg_set_cfgfile_context(con, begin_pos, size, filename);
136 return con;
137 } /* }}} */
139 void
140 cfg_set_cmdline_context(con, begin_pos, size, argv)
141 const CFG_CONTEXT con;
142 long begin_pos;
143 long size;
144 char **argv;
145 { /* {{{ */
146 cfg_reset_context(con);
148 con->type = CFG_CMDLINE;
149 con->begin_pos = begin_pos;
150 con->size = size;
151 con->argv = argv;
153 } /* }}} */
155 void
156 cfg_set_cmdline_context_argc(con, argc, argv)
157 const CFG_CONTEXT con;
158 int argc;
159 char **argv;
160 { /* {{{ */
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
164 analogically too. */
166 cfg_set_cmdline_context(con, (long) 0, (long) argc, argv);
168 } /* }}} */
170 void
171 cfg_set_cfgfile_context(con, begin_pos, size, filename)
172 const CFG_CONTEXT con;
173 long begin_pos;
174 long size;
175 char *filename;
176 { /* {{{ */
177 cfg_reset_context(con);
179 con->type = CFG_CFGFILE;
180 con->begin_pos = begin_pos;
181 con->size = size;
183 /* TODO: filename copying? (if yes than don't forget memory freeing) */
184 if (filename != NULL)
185 con->filename = (char *) filename;
187 con->fhandle = NULL;
188 } /* }}} */
190 void
191 cfg_reset_context(con)
192 const CFG_CONTEXT con;
193 { /* {{{ */
194 con->error_code = CFG_OK;
195 con->cur_idx = 0;
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);
209 con->fhandle = NULL;
211 } /* }}} */
213 void
214 cfg_free_context(con)
215 const CFG_CONTEXT con;
216 { /* {{{ */
217 register int i;
219 cfg_reset_context(con);
221 for (i = 0; i < CFG_N_PROPS; i++) {
222 #if 0
223 (void) cfg_clear_property(con, i);
224 free(con->prop[i]);
225 #else
226 PLATON_FUNC(strdyn_free)(con->prop[i]);
227 #endif
228 con->prop[i] = NULL;
231 con->begin_pos = 0;
232 con->size = 0;
233 con->argv = NULL;
234 con->filename = NULL;
235 con->type = CFG_NO_CONTEXT;
237 free((void *) con);
238 } /* }}} */
240 void
241 cfg_print_error(con)
242 const CFG_CONTEXT con;
243 { /* {{{ */
244 cfg_fprint_error(con, stderr);
245 } /* }}} */
247 void
248 cfg_fprint_error(con, fh)
249 const CFG_CONTEXT con;
250 FILE *fh;
251 { /* {{{ */
252 char *s;
254 s = cfg_get_error_str(con);
256 if (s == NULL) {
257 fputs("not enough memory for error printing\n", fh);
259 else {
260 fputs(s, fh);
261 free(s);
263 } /* }}} */
265 char *
266 cfg_get_error_str(con)
267 const CFG_CONTEXT con;
268 { /* {{{ */
269 char *s;
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;
277 int size;
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))
289 #endif
291 size = 300 + max(strlen(str_opt) + strlen(str_arg), strlen(str_filename));
293 if ((s = (char *) malloc(sizeof(char) * size)) == NULL)
294 return NULL;
296 switch (con->error_code) {
298 case CFG_OK:
299 sprintf(s, "no error on %s", str_type);
300 break;
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);
305 break;
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);
310 break;
312 case CFG_ERROR_BADOPT:
313 sprintf(s, "argument '%s' for option '%s' could not be parsed"
314 " %s %d %s",
315 str_arg, str_opt, str_pos, idx, str_type);
316 break;
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);
321 break;
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);
327 break;
329 case CFG_ERROR_OVERFLOW:
330 sprintf(s, "given number '%s' was too big or too small in option"
331 " '%s' %s %d %s",
332 str_arg, str_opt, str_pos, idx, str_type);
333 break;
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);
338 break;
340 case CFG_ERROR_NOMEM:
341 sprintf(s, "not enough memory");
342 break;
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);
347 break;
349 case CFG_ERROR_NOEQUAL:
350 sprintf(s, "no equal sign founded %s %d %s",
351 str_pos, idx, str_type);
352 break;
354 case CFG_ERROR_UNKNOWN:
355 sprintf(s, "unknown option '%s' %s %d %s",
356 str_opt, str_pos, idx, str_type);
357 break;
359 case CFG_ERROR_FILE_NOT_FOUND:
360 sprintf(s, "config file '%s' was not found", str_filename);
361 break;
363 case CFG_ERROR_SEEK_ERROR:
364 sprintf(s, "seek error in %s", str_type);
365 break;
367 case CFG_ERROR_INTERNAL:
368 sprintf(s, "libcfg internal error");
369 default:
370 sprintf(s, "unknown error (%d)", con->error_code);
371 break;
374 return s;
375 } /* }}} */
377 char *
378 cfg_get_static_error_str(errorcode)
379 const int errorcode;
380 { /* {{{ */
381 switch (errorcode) {
383 case CFG_OK:
384 return "no error";
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";
430 } /* }}} */
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+
439 void
440 ar_print(name, format, vals)
441 char *name;
442 char *format;
443 void **vals;
444 { /* {{{ */
445 if (vals != NULL) {
446 if (strcmp(format, "%s")) {
447 register int i;
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]));
454 else
455 printf(format, *(((int **) vals)[i]));
457 printf(", ");
460 puts("NULL");
462 else {
463 register char *s;
464 s = PLATON_FUNC(strdyn_implode_str)((char **) vals, "][");
465 printf("%s = [%s]\n", name, s);
466 if (s != NULL)
467 free(s);
470 PLATON_FUNC(strdyn_free)((char **) vals);
472 else
473 printf("%s uninitialized\n", name);
474 } /* }}} */
477 main(argc, argv)
478 int argc;
479 char **argv;
480 { /* {{{ */
482 CFG_CONTEXT con;
483 int ret, i;
485 int o_nice = 20, o_verbose = 0;
486 char *o_cfgfile = NULL, *o_string = NULL;
487 char **o_name = NULL, **o_leftover = NULL;
488 int o_boolean = 0;
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 },
509 { "int", 'i', "int",
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 },
535 { NULL, '\0',"argv",
536 CFG_STRING + CFG_MULTI_SEPARATED + CFG_LEFTOVER_ARGS, (void*) &o_leftover, 0 },
537 CFG_END_OF_LIST
540 con = cfg_get_context(options);
542 for (i = 0; ; i++) {
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));
556 if (i == 0) {
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, "");
571 else {
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));
583 if (i == 0)
584 printf(", idx = %d, argv[idx] = '%s'",
585 cfg_get_cur_idx(con),
586 argv[cfg_get_cur_idx(con)]);
588 putchar('\n');
591 if (ret != CFG_OK) {
592 puts(
593 "+------------------+\n"
594 "| Error printing |\n"
595 "+------------------+");
597 printf("***** ");
598 cfg_fprint_error(con, stdout);
599 putchar('\n');
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));
609 if (i == 0)
610 printf(", idx = %d, argv[idx] = '%s'",
611 cfg_get_cur_idx(con), argv[cfg_get_cur_idx(con)]);
613 putchar('\n');
616 if (i == 0 && o_cfgfile == NULL)
617 break;
619 if (i > 0)
620 break;
623 cfg_free_context(con);
625 puts(
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);
637 puts(
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);
651 return 0;
652 } /* }}} */
654 #endif
656 /* Modeline for ViM {{{
657 * vim:set ts=4:
658 * vim600:fdm=marker fdl=0 fdc=0:
659 * }}} */