diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2004-07-27 21:35:20 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2004-07-27 21:35:20 +0000 |
commit | f79774c1009099c22b19bea8309435a5fc76dd5f (patch) | |
tree | 89facca909ff7564685db70b0b19a9ca0f90c2e1 /src | |
parent | ac837245a29c3a136ceaab722db1b42895dfdb93 (diff) | |
download | gnutls-f79774c1009099c22b19bea8309435a5fc76dd5f.tar.gz |
added missing files.
Diffstat (limited to 'src')
-rw-r--r-- | src/cfg/Makefile.am | 5 | ||||
-rw-r--r-- | src/cfg/cfg+.c | 660 | ||||
-rw-r--r-- | src/cfg/cfg+.h | 968 | ||||
-rw-r--r-- | src/cfg/cfgfile.c | 285 | ||||
-rw-r--r-- | src/cfg/cfgfile.h | 46 | ||||
-rw-r--r-- | src/cfg/cmdline.c | 183 | ||||
-rw-r--r-- | src/cfg/cmdline.h | 46 | ||||
-rw-r--r-- | src/cfg/parse.c | 101 | ||||
-rw-r--r-- | src/cfg/platon/Makefile.am | 2 | ||||
-rw-r--r-- | src/cfg/platon/str/Makefile.am | 4 | ||||
-rw-r--r-- | src/cfg/platon/str/dynfgets.c | 44 | ||||
-rw-r--r-- | src/cfg/platon/str/dynfgets.h | 46 | ||||
-rw-r--r-- | src/cfg/platon/str/strctype.c | 99 | ||||
-rw-r--r-- | src/cfg/platon/str/strctype.h | 40 | ||||
-rw-r--r-- | src/cfg/platon/str/strdyn.c | 682 | ||||
-rw-r--r-- | src/cfg/platon/str/strdyn.h | 77 | ||||
-rw-r--r-- | src/cfg/platon/str/strplus.c | 436 | ||||
-rw-r--r-- | src/cfg/platon/str/strplus.h | 273 | ||||
-rw-r--r-- | src/cfg/props.c | 625 | ||||
-rw-r--r-- | src/cfg/shared.c | 977 | ||||
-rw-r--r-- | src/cfg/shared.h | 74 |
21 files changed, 5673 insertions, 0 deletions
diff --git a/src/cfg/Makefile.am b/src/cfg/Makefile.am new file mode 100644 index 0000000000..5ba55faa16 --- /dev/null +++ b/src/cfg/Makefile.am @@ -0,0 +1,5 @@ +EXTRA_DIST = cfg+.h cfgfile.h cmdline.h shared.h \ + cfg+.c cfgfile.c cmdline.c parse.c props.c shared.c + +SUBDIRS = platon + diff --git a/src/cfg/cfg+.c b/src/cfg/cfg+.c new file mode 100644 index 0000000000..db019114c6 --- /dev/null +++ b/src/cfg/cfg+.c @@ -0,0 +1,660 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * cfg+.c - main implementation + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/cfg+.c,v 1.61 2004/01/12 06:03:08 nepto Exp $ */ + +/* Includes {{{ */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#if STDC_HEADERS +# include <stdlib.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif + +#include <platon/str/strdyn.h> +#include <platon/str/strplus.h> + +#include "cfg+.h" +#include "shared.h" +/* }}} */ + +extern char *cfg_default_properties[CFG_N_PROPS][4]; + + CFG_CONTEXT +cfg_get_context(options) + struct cfg_option *options; +{ /* {{{ */ + register int i; + CFG_CONTEXT con; + + con = (CFG_CONTEXT) malloc(sizeof(*con)); + if (con == NULL) + return NULL; + + /* Setting all struct values to 0 or NULL */ + memset(con, '\0', sizeof(*con)); + + /* Initializing context type and options set */ + con->type = CFG_NO_CONTEXT; + con->options = options; + + /* Initializaing properties to default values */ + for (i = 0; i < CFG_N_PROPS; i++) { + con->prop[i] = PLATON_FUNC(strdyn_create_ar)(cfg_default_properties[i]); + if (con->prop[i] == NULL) { + /* TODO: possible freeing on failure */ + return NULL; + } + } + + return con; +} /* }}} */ + + CFG_CONTEXT +cfg_get_cmdline_context(begin_pos, size, argv, options) + long begin_pos; + long size; + char **argv; + struct cfg_option *options; +{ /* {{{ */ + CFG_CONTEXT con; + + con = cfg_get_context(options); + if (con == NULL) + return NULL; + + cfg_set_cmdline_context(con, begin_pos, size, argv); + + return con; +} /* }}} */ + + CFG_CONTEXT +cfg_get_cmdline_context_argc(argc, argv, options) + int argc; + char **argv; + struct cfg_option *options; +{ /* {{{ */ + CFG_CONTEXT con; + + /* Starting from the beginning and parsing till the end */ + con = cfg_get_cmdline_context((long) 0, (long) argc, argv, options); + if (con == NULL) + return con; + + /* When parsing by argc/argv we must skip first argument argv[0], + because there is the name of program. */ + cfg_set_context_flag(con, CFG_SKIP_FIRST); + + return con; +} /* }}} */ + + CFG_CONTEXT +cfg_get_cfgfile_context(begin_pos, size, filename, options) + long begin_pos; + long size; + char *filename; + struct cfg_option *options; +{ /* {{{ */ + CFG_CONTEXT con; + + con = cfg_get_context(options); + if (con == NULL) + return NULL; + + cfg_set_cfgfile_context(con, begin_pos, size, filename); + + return con; +} /* }}} */ + + void +cfg_set_cmdline_context(con, begin_pos, size, argv) + const CFG_CONTEXT con; + long begin_pos; + long size; + char **argv; +{ /* {{{ */ + cfg_reset_context(con); + + con->type = CFG_CMDLINE; + con->begin_pos = begin_pos; + con->size = size; + con->argv = argv; + +} /* }}} */ + + void +cfg_set_cmdline_context_argc(con, argc, argv) + const CFG_CONTEXT con; + int argc; + char **argv; +{ /* {{{ */ + + /* This function could be macro. But appropriate `get' equivalent, function + cfg_get_cmdline_context_argc(), is in fact function. So this is function + analogically too. */ + + cfg_set_cmdline_context(con, (long) 0, (long) argc, argv); + +} /* }}} */ + + void +cfg_set_cfgfile_context(con, begin_pos, size, filename) + const CFG_CONTEXT con; + long begin_pos; + long size; + char *filename; +{ /* {{{ */ + cfg_reset_context(con); + + con->type = CFG_CFGFILE; + con->begin_pos = begin_pos; + con->size = size; + + /* TODO: filename copying? (if yes than don't forget memory freeing) */ + if (filename != NULL) + con->filename = (char *) filename; + + con->fhandle = NULL; +} /* }}} */ + + void +cfg_reset_context(con) + const CFG_CONTEXT con; +{ /* {{{ */ + con->error_code = CFG_OK; + con->cur_idx = 0; + con->cur_idx_tmp = 0; + con->parsing_started = 0; + + if (con->used_opt_idx != NULL) { + free(con->used_opt_idx); + con->used_opt_idx = NULL; + } + + __cfg_free_currents(con); + + /* Problematic code? */ + if (con->fhandle != NULL) { + fclose(con->fhandle); + con->fhandle = NULL; + } +} /* }}} */ + + void +cfg_free_context(con) + const CFG_CONTEXT con; +{ /* {{{ */ + register int i; + + cfg_reset_context(con); + + for (i = 0; i < CFG_N_PROPS; i++) { +#if 0 + (void) cfg_clear_property(con, i); + free(con->prop[i]); +#else + PLATON_FUNC(strdyn_free)(con->prop[i]); +#endif + con->prop[i] = NULL; + } + + con->begin_pos = 0; + con->size = 0; + con->argv = NULL; + con->filename = NULL; + con->type = CFG_NO_CONTEXT; + + free((void *) con); +} /* }}} */ + + void +cfg_print_error(con) + const CFG_CONTEXT con; +{ /* {{{ */ + cfg_fprint_error(con, stderr); +} /* }}} */ + + void +cfg_fprint_error(con, fh) + const CFG_CONTEXT con; + FILE *fh; +{ /* {{{ */ + char *s; + + s = cfg_get_error_str(con); + + if (s == NULL) { + fputs("not enough memory for error printing\n", fh); + } + else { + fputs(s, fh); + free(s); + } +} /* }}} */ + + char * +cfg_get_error_str(con) + const CFG_CONTEXT con; +{ /* {{{ */ + char *s; + char *str_type = con->type == CFG_LINE ? "on command line" : "in config file"; + char *str_pos = con->type == CFG_LINE ? /* "near" */ "at position" + : (con->flags & CFG_FILE_LINE_POS_USAGE ? "on line" : "at position"); + char *str_opt = cfg_get_cur_opt(con); + char *str_arg = cfg_get_cur_arg(con); + char *str_filename = con->filename; + int idx = cfg_get_cur_idx(con) + 1; + int size; + + str_opt = str_opt == NULL ? "" : str_opt; + str_arg = str_arg == NULL ? "" : str_arg; + str_filename = str_filename == NULL ? "" : str_filename; + + /* WARNING: pay attention on possible buffer owerflow here; used constant + must be enough to cover str_type, str_pos, str_idx and the rest + of error message with deliminators. */ + +#ifndef max /* Borrowed from libplaton */ +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + + size = 300 + max(strlen(str_opt) + strlen(str_arg), strlen(str_filename)); + + if ((s = (char *) malloc(sizeof(char) * size)) == NULL) + return NULL; + + switch (con->error_code) { + + case CFG_OK: + sprintf(s, "no error on %s", str_type); + break; + + case CFG_ERROR_NOARG: + sprintf(s, "argument is missing for option '%s' %s %d %s", + str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_NOTALLOWEDARG: + sprintf(s, "option '%s' does not have allowed argument %s %d %s", + str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_BADOPT: + sprintf(s, "argument '%s' for option '%s' could not be parsed" + " %s %d %s", + str_arg, str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_BADQUOTE: + sprintf(s, "error in quotations in option '%s' %s %d %s", + str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_BADNUMBER: + sprintf(s, "argument '%s' for option '%s' could not be converted" + " to appropriate numeric type %s %d %s", + str_arg, str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_OVERFLOW: + sprintf(s, "given number '%s' was too big or too small in option" + " '%s' %s %d %s", + str_arg, str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_MULTI: + sprintf(s, "multiple arguments used for single option '%s' %s %d %s", + str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_NOMEM: + sprintf(s, "not enough memory"); + break; + + case CFG_ERROR_STOP_STR_FOUND: + sprintf(s, "stop string '%s' was found %s %d %s", + str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_NOEQUAL: + sprintf(s, "no equal sign founded %s %d %s", + str_pos, idx, str_type); + break; + + case CFG_ERROR_UNKNOWN: + sprintf(s, "unknown option '%s' %s %d %s", + str_opt, str_pos, idx, str_type); + break; + + case CFG_ERROR_FILE_NOT_FOUND: + sprintf(s, "config file '%s' was not found", str_filename); + break; + + case CFG_ERROR_SEEK_ERROR: + sprintf(s, "seek error in %s", str_type); + break; + + case CFG_ERROR_INTERNAL: + sprintf(s, "libcfg internal error"); + default: + sprintf(s, "unknown error (%d)", con->error_code); + break; + } + + return s; +} /* }}} */ + + char * +cfg_get_static_error_str(errorcode) + const int errorcode; +{ /* {{{ */ + switch (errorcode) { + + case CFG_OK: + return "no error"; + + case CFG_ERROR_NOARG: + return "argument is missing for option"; + + case CFG_ERROR_NOTALLOWEDARG: + return "argument is not allowed for option"; + + case CFG_ERROR_BADOPT: + return "option's argument could not be parsed"; + + case CFG_ERROR_BADQUOTE: + return "error in quotations"; + + case CFG_ERROR_BADNUMBER: + return "option could not be converted to appropriate numeric type"; + + case CFG_ERROR_OVERFLOW: + return "given number was too big or too small"; + + case CFG_ERROR_MULTI: + return "multiple arguments used for single option"; + + case CFG_ERROR_NOMEM: + return "not enough memory"; + + case CFG_ERROR_STOP_STR_FOUND: + return "stop string was found"; + + case CFG_ERROR_NOEQUAL: + return "no equal sign on the line"; + + case CFG_ERROR_UNKNOWN: + return "unknown option"; + + case CFG_ERROR_FILE_NOT_FOUND: + return "file not found"; + + case CFG_ERROR_SEEK_ERROR: + return "file seek error"; + + case CFG_ERROR_INTERNAL: + return "internal error"; + } + + return "unknown error"; +} /* }}} */ + +#if defined(SELF) || defined(SELFTEST) || defined(SELF_CFG) + +/* + * Selftest compilation: + * gcc -Wall -I. -I.. -L. -DHAVE_CONFIG_H -DSELF -o test cfg+.c -lcfg+ + */ + + void +ar_print(name, format, vals) + char *name; + char *format; + void **vals; +{ /* {{{ */ + if (vals != NULL) { + if (strcmp(format, "%s")) { + register int i; + + printf("%s: ", name); + for (i = 0; vals[i] != NULL; i++) { + + if (! strcmp(format, "%e") || ! strcmp(format, "%f")) + printf(format, *(((float **) vals)[i])); + else + printf(format, *(((int **) vals)[i])); + + printf(", "); + } + + puts("NULL"); + } + else { + register char *s; + s = PLATON_FUNC(strdyn_implode_str)((char **) vals, "]["); + printf("%s = [%s]\n", name, s); + if (s != NULL) + free(s); + } + + PLATON_FUNC(strdyn_free)((char **) vals); + } + else + printf("%s uninitialized\n", name); +} /* }}} */ + + int +main(argc, argv) + int argc; + char **argv; +{ /* {{{ */ + + CFG_CONTEXT con; + int ret, i; + + int o_nice = 20, o_verbose = 0; + char *o_cfgfile = NULL, *o_string = NULL; + char **o_name = NULL, **o_leftover = NULL; + int o_boolean = 0; + int o_int = -33, **o_multi_int = NULL; + unsigned int o_uint = 33, **o_multi_uint = NULL; + long o_long = -333, **o_multi_long = NULL; + unsigned long o_ulong = 333, **o_multi_ulong = NULL; + float o_float = -3333.33, **o_multi_float = NULL; + double o_double = -33333.33, **o_multi_double = NULL; + + + struct cfg_option options[] = { + { "nice", 'n', "nice", + CFG_INT, (void *) &o_nice, 0 }, + { "verbose", 'v', "verbose", + CFG_BOOLEAN + CFG_MULTI, (void *) &o_verbose, 0 }, + { "name", 'a', "name", + CFG_STRING + CFG_MULTI_SEPARATED, (void *) &o_name, 0 }, + { "config-file", 'f', NULL, + CFG_STRING, (void *) &o_cfgfile, 0 }, + + { "bool", 'b', "boolean", + CFG_BOOLEAN, (void *) &o_boolean, 1 }, + { "int", 'i', "int", + CFG_INT, (void *) &o_int, 0 }, + { "multi_int", 'I', "multi int", + CFG_INT + CFG_MULTI_SEPARATED, (void *) &o_multi_int, 0 }, + { "uint", 'u', "unsigned int", + CFG_UINT, (void *) &o_uint, 0 }, + { "multi_uint", 'U', "multi unsigned int", + CFG_UINT + CFG_MULTI, (void *) &o_multi_uint, 0 }, + { "long", 'l', "long", + CFG_LONG, (void *) &o_long, 0 }, + { "multi_long", 'L', "multi long", + CFG_LONG + CFG_MULTI_SEPARATED, (void *) &o_multi_long, 0 }, + { "ulong", 'o', "unsigned long", + CFG_ULONG, (void *) &o_ulong, 0 }, + { "multi_ulong", 'O', "multi unsigned long", + CFG_ULONG + CFG_MULTI, (void *) &o_multi_ulong, 0 }, + { "float", 'f', "float", + CFG_FLOAT, (void *) &o_float, 0 }, + { "multi_float", 'F', "multi float", + CFG_FLOAT + CFG_MULTI_SEPARATED, (void *) &o_multi_float, 0 }, + { "double", 'd', "double", + CFG_DOUBLE, (void *) &o_double, 0 }, + { "multi_double", 'D', "mdouble", + CFG_DOUBLE + CFG_MULTI_SEPARATED, (void *) &o_multi_double, 0}, + { "string", 's', "string", + CFG_STRING, (void *) &o_string, 0 }, + { NULL, '\0',"argv", + CFG_STRING + CFG_MULTI_SEPARATED + CFG_LEFTOVER_ARGS, (void*) &o_leftover, 0 }, + CFG_END_OF_LIST + }; + + con = cfg_get_context(options); + + for (i = 0; ; i++) { + + /* This is powerful testing stuff :) + + printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS)); + cfg_set_context_flag(con, CFG_ADVANCED_LEFTOVERS); + cfg_set_context_flag(con, CFG_ADVANCED_LEFTOVERS); + printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS)); + cfg_clear_context_flag(con, CFG_ADVANCED_LEFTOVERS); + printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS)); + cfg_set_context_flag(con, CFG_ADVANCED_LEFTOVERS); + printf("advanced leftovers: %d\n", cfg_get_context_flag(con, CFG_ADVANCED_LEFTOVERS)); + */ + + if (i == 0) { + cfg_set_cmdline_context(con, 1, argc, argv); + cfg_set_context_flag(con, CFG_ADVANCED_LEFTOVERS); + cfg_set_context_flag(con, CFG_FILE_LINE_POS_USAGE); + if (0) { /* Testing if short command line options + works also without '-' prefix */ + cfg_clear_property(con, CFG_LINE_SHORT_OPTION_PREFIX); + cfg_add_property(con, CFG_LINE_SHORT_OPTION_PREFIX, ""); + } + if (0) { /* Testing if long command line options + works also without '--' prefix */ + cfg_clear_property(con, CFG_LINE_LONG_OPTION_PREFIX); + cfg_add_property(con, CFG_LINE_LONG_OPTION_PREFIX, ""); + } + } + else { + cfg_set_cfgfile_context(con, 1, 0, o_cfgfile); + /* cfg_remove_cfgfile_comment_prefix(con, "//"); + cfg_add_cfgfile_comment_prefix(con, "//"); */ + cfg_remove_property(con, CFG_FILE_COMMENT_PREFIX, "//"); + cfg_add_property(con, CFG_FILE_COMMENT_PREFIX, "//"); + } + + while ((ret = cfg_get_next_opt(con)) > 0) { + printf("ret = %d, opt = '%s', arg = '%s'", ret, + cfg_get_cur_opt(con), cfg_get_cur_arg(con)); + + if (i == 0) + printf(", idx = %d, argv[idx] = '%s'", + cfg_get_cur_idx(con), + argv[cfg_get_cur_idx(con)]); + + putchar('\n'); + } + + if (ret != CFG_OK) { + puts( + "+------------------+\n" + "| Error printing |\n" + "+------------------+"); + + printf("***** "); + cfg_fprint_error(con, stdout); + putchar('\n'); + + printf("***** %s error %d at %d: %s\n", + i == 0 ? "cmdline" : "cfgfile", + ret, cfg_get_cur_idx(con), + cfg_get_static_error_str(ret)); + + printf("***** opt = '%s', arg = '%s'", + cfg_get_cur_opt(con), cfg_get_cur_arg(con)); + + if (i == 0) + printf(", idx = %d, argv[idx] = '%s'", + cfg_get_cur_idx(con), argv[cfg_get_cur_idx(con)]); + + putchar('\n'); + } + + if (i == 0 && o_cfgfile == NULL) + break; + + if (i > 0) + break; + } + + cfg_free_context(con); + + puts( + "+--------------------------+\n" + "| Common values printing |\n" + "+--------------------------+"); + + printf("o_verbose = %d, o_nice = %d\n", o_verbose, o_nice); + printf("o_boolean = %d\n", o_boolean); + printf("o_int = %d, o_uint = %u\n", o_int, o_uint); + printf("o_long = %ld, o_ulong = %lu\n", o_long, o_ulong); + printf("o_float = %f, o_double = %e\n", o_float, o_double); + printf("o_string = <%s>\n", o_string); + + puts( + "+-------------------------+\n" + "| Multi values printing |\n" + "+-------------------------+"); + + ar_print("o_multi_int", "%d", (void **) o_multi_int); + ar_print("o_multi_uint", "%u", (void **) o_multi_uint); + ar_print("o_multi_long", "%ld", (void **) o_multi_long); + ar_print("o_multi_ulong", "%lu", (void **) o_multi_ulong); + ar_print("o_multi_float", "%f", (void **) o_multi_float); + ar_print("o_multi_double", "%e", (void **) o_multi_double); + ar_print("o_name", "%s", (void **) o_name); + ar_print("o_leftover", "%s", (void **) o_leftover); + + return 0; +} /* }}} */ + +#endif + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/cfg+.h b/src/cfg/cfg+.h new file mode 100644 index 0000000000..2bdb1b7200 --- /dev/null +++ b/src/cfg/cfg+.h @@ -0,0 +1,968 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * cfg+.h - main implementation header file + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/cfg+.h,v 1.60 2004/01/12 06:03:08 nepto Exp $ */ + +/** + * @file cfg+.h + * @brief main implementation header file + * @author Ondrej Jombik <nepto@platon.sk> + * @author Lubomir Host <rajo@platon.sk> + * @version \$Platon: libcfg+/src/cfg+.h,v 1.60 2004/01/12 06:03:08 nepto Exp $ + * @date 2001-2004 + */ + +#ifndef _PLATON_CFG_H +#define _PLATON_CFG_H + +#include <stdio.h> + +/** End of options list marker */ +#define CFG_END_OPTION { NULL, '\0', NULL, CFG_END, NULL, 0 } +#define CFG_END_OF_LIST CFG_END_OPTION /**< Alias for @ref CFG_END_OPTION */ + +/** + * @name Error codes + */ +/*@{*/ +/** + * Possible return values returned by parsing functions. + */ +enum cfg_error { /* {{{ */ + + /*@{*/ + /** OK, all is right. */ + CFG_ERR_OK = 0, + CFG_ERROR_OK = 0, + CFG_OK = 0, + /*@}*/ + + /** An argument is missing for an option. */ + CFG_ERR_NOARG = -1, + CFG_ERROR_NOARG = -1, + + /** An argument is not allowed for an option. */ + CFG_ERR_NOTALLOWEDARG = -2, + CFG_ERROR_NOTALLOWEDARG = -2, + + /** An option's argument could not be parsed. */ + CFG_ERR_BADOPT = -3, + CFG_ERROR_BADOPT = -3, + + /** Error in quotations. */ + CFG_ERR_BADQUOTE = -4, + CFG_ERROR_BADQUOTE = -4, + + /** An option could not be converted to appropriate numeric type. */ + CFG_ERR_BADNUMBER = -5, + CFG_ERROR_BADNUMBER = -5, + + /** A given number was too big or too small. */ + CFG_ERR_OVERFLOW = -6, + CFG_ERROR_OVERFLOW = -6, + + /** Multiple arguments used for single option. */ + CFG_ERR_MULTI = -7, + CFG_ERROR_MULTI = -7, + + /** Not enough memory. */ + CFG_ERR_NOMEM = -8, + CFG_ERROR_NOMEM = -8, + + /** Stop string was found. */ + CFG_ERR_STOP_STR = -9, + CFG_ERR_STOP_STR_FOUND = -9, + CFG_ERROR_STOP_STR = -9, + CFG_ERROR_STOP_STR_FOUND = -9, + + /** No equal sign on the line. */ + CFG_ERR_NOEQUAL = -10, + CFG_ERROR_NOEQUAL = -10, + + /** An unknown option. */ + CFG_ERR_UNKNOWN = -11, + CFG_ERROR_UNKNOWN = -11, + + /** File not found error. */ + CFG_ERR_FILE_NOT_FOUND = -12, + CFG_ERROR_FILE_NOT_FOUND = -12, + + /** Seek error (fseek() failure). */ + CFG_ERR_SEEK_ERROR = -13, + CFG_ERROR_SEEK_ERROR = -13, + + /** Internal error. */ + CFG_ERR_INTERNAL = -20, + CFG_ERROR_INTERNAL = -20 + +}; /* }}} */ /*@}*/ + +/** + * @name Context flags + */ +/*@{*/ +/** + * By default are @ref CFG_PROCESS_FIRST, @ref CFG_POSIXLY_LEFTOVERS and + * @ref CFG_NORMAL_LEFTOVERS initialized. + * @todo CFG_APPEND, CFG_OVERWRITE, CFG_APPEND_MULTI_ONLY + */ +enum cfg_flag { /* {{{ */ + + /** Ignore multiple arguments for single option. */ + CFG_IGNORE_MULTI = 1, + + /** Ignore unknown options. */ + CFG_IGNORE_UNKNOWN = 2, + + /** Process also the first argument on command line. */ + CFG_PROCESS_FIRST = 0, + + /** Skip processing of the first argument on command line. */ + CFG_SKIP_FIRST = 4, + + /** Posixly correct leftover arguments. */ + CFG_POSIXLY_LEFTOVERS = 0, + + /** Advanced leftover arguments. */ + CFG_ADVANCED_LEFTOVERS = 8, + + /** Normal leftover arguments initialization in file. + This flag is not used and it is kept from historical reasons. */ + CFG_NORMAL_LEFTOVERS = 0, + + /** Strict leftover arguments initialization in file. + This flag is not used and it is kept from historical reasons. */ + CFG_STRICT_LEFTOVERS = 16, + + /** Byte type position usage in file. */ + CFG_FILE_BYTE_POS_USAGE = 0, + + /** Line type position usage in file. */ + CFG_FILE_LINE_POS_USAGE = 32 + + /* Ignore all quotations in options arguments. */ + /* + CFG_USE_QUOTE = 0, + CFG_IGNORE_QUOTE = 16 + */ + /* Advanced quotations are things like option = va"'l'"ue + which resolves to va'l'ue. + + We really want this strange stuff? Any volunter? + + CFG_ADVANCED_QUOTE = 32 + 16 + */ + +}; /* }}} */ /*@}*/ + +/** + * @name Option types + */ +/*@{*/ +/** + * Possible types of options + * @todo Thinking about case insensitivy of option + * ("--input" is the same as "--INPUT") + */ +enum cfg_option_type { /* {{{ */ + + /** Boolean */ + CFG_BOOL = 1, + CFG_BOOLEAN = 1, + + /** Integer */ + CFG_INT = 2, + CFG_INTEGER = 2, + + /** Unsigned int */ + CFG_UINT = 3, + CFG_UNSIGNED = 3, + CFG_UNSIGNED_INT = 3, + + /** Long */ + CFG_LONG = 4, + + /** Unsigned long */ + CFG_ULONG = 5, + CFG_UNSIGNED_LONG = 5, + + /** Float */ + CFG_FLOAT = 6, + + /** Double */ + CFG_DOUBLE = 7, + + /** String */ + CFG_STR = 8, + CFG_STRING = 8, + + /** End (to mark last item in list) */ + CFG_END = 0, + + /** Data type mask (used internally) */ + CFG_DATA_TYPE_MASK = 31, + + /** + * Single, multi or multi separated. Single by default. + * Tells if option can be repeated. + * In multi case value is array of poiters to type ended with NULL. + */ + CFG_SINGLE = 0, + CFG_MULTI = 32, + CFG_MULTI_ARRAY = 32, + CFG_MULTI_SEPARATED = 32 + 64, + + /** + * Leftover arguments specification. + * Mark option which will contain leftover arguments. + */ + CFG_LAST_ARGS = 128, + CFG_LAST_ARGUMENTS = 128, + CFG_LEFTOVER_ARGS = 128, + CFG_LEFTOVER_ARGUMENTS = 128 + +}; /* }}} */ /*@}*/ + +/** + * @name Property types + */ +/*@{*/ +enum cfg_property_type { /* {{{ */ + + /** + * @name Property codes + */ + /*@{*/ + + /** Array of strings which forces to stop command line parsing. + By default it is empty. */ + CFG_LINE_STOP_STRING = 0, + + /** Command line short option prefix. + By default is "-" initialized. */ + CFG_LINE_SHORT_OPTION_PREFIX = 1, + + /** Command line long option prefix. + By default is "--" initialized. */ + CFG_LINE_LONG_OPTION_PREFIX = 2, + + /** Command line option argument separator. + By default is "=" initialized. */ + CFG_LINE_OPTION_ARG_SEPARATOR = 3, + + /** Command line multi values separator. + By default are "," and ";" initialized. */ + CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR = 4, + + /** Command line multi values leftover arguments separator. + By default it is empty. */ + CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR = 5, + + /** Command line quote prefix & postfix. + By default are apostrophes (') and quotations (") initlized for both.*/ + CFG_LINE_QUOTE_PREFIX = 6, + CFG_LINE_QUOTE_POSTFIX = 7, + + /** Array of strings prefixes which forces to stop config file parsing. + By default it is empty. */ + CFG_FILE_STOP_PREFIX = 8, + + /** Array of string prefixes which mark comment line. + By default are "#" and ";" initialized. */ + CFG_FILE_COMMENT_PREFIX = 9, + + /** Array of string postfixes to determine multi lines. + By default is "\\" initialized. */ + CFG_FILE_MULTI_LINE_POSTFIX = 10, + + /** Config file option argument separator. + By default is "=" initialized. */ + CFG_FILE_OPTION_ARG_SEPARATOR = 11, + + /** Config file multi values separator. + By default are ",", ";" and " " initialized. */ + CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR = 12, + + /** Command line multi values leftover arguments separator. + By default is " " initialized. */ + CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR = 13, + + /** Config file quote prefix & postfix. + By default are apostrophes (') and quotations (\") initlized for both.*/ + CFG_FILE_QUOTE_PREFIX = 14, + CFG_FILE_QUOTE_POSTFIX = 15, + + /*@}*/ + + /** + * @name Count of normal properties + */ + /*@{*/ + /** Special properties count */ + CFG_N_PROPS = 16, + /*@}*/ + + /** + * @name Virtual property codes + */ + /*@{*/ + + /** File quote prefix & postfix */ + CFG_QUOTE = 50, + CFG_LINE_QUOTE = 51, + CFG_FILE_QUOTE = 52, + CFG_QUOTE_PREFIX = 53, + CFG_QUOTE_POSTFIX = 54, + + /** Multi values separator */ + CFG_MULTI_VALS_SEPARATOR = 55, + CFG_FILE_MULTI_VALS_SEPARATOR = 56, + CFG_LINE_MULTI_VALS_SEPARATOR = 57, + CFG_NORMAL_MULTI_VALS_SEPARATOR = 58, + CFG_LEFTOVER_MULTI_VALS_SEPARATOR = 59, + + /** Option argument separator */ + CFG_OPTION_ARG_SEPARATOR = 60 + /*@}*/ +}; /* }}} */ + +/** + * Terminators of variable number arguments in functions cfg_add_properties(), + * cfg_set_properties(), cfg_get_properties() and similar. + */ +#define CFG_EOT CFG_N_PROPS +#define CFG_END_TYPE CFG_N_PROPS + +/*@}*/ + +/** + * @name Internal enumerations + */ +/*@{*/ +/** + * Context type + * + * Possible types of context (used internally) + */ +enum cfg_context_type { /* {{{ */ + + /** No context */ + CFG_NO_CONTEXT = 0, + + /** Command line context type */ + CFG_CMDLINE = 1, + CFG_LINE = 1, + + /** Config file context type */ + CFG_CFGFILE = 2, + CFG_FILE = 2 +}; /* }}} */ + +/** + * Command line option type. + * + * Possible types of command line option (used internally) + */ +enum cfg_line_option_type { /* {{{ */ + + /** Not long and not short option */ + CFG_NONE_OPTION = 0, + + /** Short command line option */ + CFG_SHORT_OPTION = 1, + + /** Long command line option */ + CFG_LONG_OPTION = 2, + + /** Short command line options */ + CFG_SHORT_OPTIONS = 4, + + /** Long command line option argument initialized with separator */ + CFG_LONG_SEPINIT = 8, + + /** Long command line option argument initialized without separator (default) */ + CFG_LONG_NOSEPINIT = 0 +}; /* }}} */ /*@}*/ + +/** + * @brief Structure for defining one config option + */ +struct cfg_option { /* {{{ */ + /** Command line long name (may be NULL) */ + const char *cmdline_long_name; + /** Command line short name (may be '\0') */ + const char cmdline_short_name; + /** Config file name (may be NULL) */ + const char *cfgfile_name; + + /** Option type + @see cfg_option_type */ + const enum cfg_option_type type; + + /** Pointer where to store value of option */ + void *value; + + /** Return value (set to 0 for not return) */ + int val; +}; /* }}} */ + +/** + * @brief Main structure for defining context + */ +struct cfg_context { /* {{{ */ + + /** + * @name Shared properties + */ + /*@{*/ + + /** Context type (command line or config file) */ + enum cfg_context_type type; + + /** Flags */ + int flags; + + /** Options table */ + const struct cfg_option *options; + + /** Starting parsing position */ + long begin_pos; + + /** Number of elements (array arguments, bytes or lines) to parse + (value of -1 means infinite) */ + long size; + + /** Array of used options indexes */ + int *used_opt_idx; + + /** Error code of last occured error. */ + enum cfg_error error_code; + + /** Special properties */ + char **prop[CFG_N_PROPS]; + + /** Currents */ + long cur_idx; + long cur_idx_tmp; + int cur_opt_type; + + /** Current option string */ + char *cur_opt; + + /** Current option argument*/ + char *cur_arg; + + /*@}*/ + + /** + * @name Command line specific properties + */ + /*@{*/ + + /** Flag to detect if parsing already started */ + int parsing_started:1; + + /** NULL terminated array of argument */ + char **argv; + + /*@}*/ + + /** + * @name Config file specific properties. + */ + /*@{*/ + + /** Filename (name of file) */ + char *filename; + + /** Pointer to FILE* structure of parsed file */ + FILE *fhandle; + + /*@}*/ +}; /* }}} */ + +/** + * @brief Context data type + */ +typedef struct cfg_context * CFG_CONTEXT; + +/* + * Functions + */ + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @name Functions and macros for creating and manipulating context + */ + /*@{*/ /* {{{ */ + + /** + * Initialize core context + * + * @param options pointer to options table + * @return initialized core context; further specification + * to command line or config file is required + */ + CFG_CONTEXT cfg_get_context(struct cfg_option *options); + + /** + * Initialize command line context + * + * @param begin_pos index of beginning argument of arguments array + * @param size maximal number of array elements to parse + * (set value of -1 for infinite) + * @param argv arguments array + * @param options pointer to options table + * @return initialized command line context + */ + CFG_CONTEXT cfg_get_cmdline_context( + long begin_pos, + long size, + char **argv, + struct cfg_option *options); + +#define cfg_get_cmdline_context_pos(begin_pos, end_pos, argv, options) \ + cfg_get_cmdline_context( \ + begin_pos, \ + end_pos - begin_pos + 1, \ + argv, \ + options) + + /** + * Initialize command line context by argc and argv passed to main() + * + * @param argc argumet count (argc) passed to function main() + * @param argv arguments array (argv) passed to function main() + * @param options pointer to options table + * @return initialized command line context + */ + CFG_CONTEXT cfg_get_cmdline_context_argc( + int argc, + char **argv, + struct cfg_option *options); + + /** + * Initialize configuration file context + * + * @param begin_pos starting position in file to parse + * @param size maximal number of bytes/lines in file to parse + * (set value of -1 for infinite) + * @param filename parsed filename + * @param options pointer to options table + * @return initialized command line context + */ + CFG_CONTEXT cfg_get_cfgfile_context( + long begin_pos, + long size, + char *filename, + struct cfg_option *options); + +#define cfg_get_cfgfile_context_pos(begin_pos, end_pos, argv, options) \ + cfg_get_cfgfile_context( \ + begin_pos, \ + end_pos - begin_pos + 1, \ + argv, \ + options) + + /** + * Set context to command line + * + * @param con initialized context + * @param begin_pos index of beginning argument of arguments array + * @param size maximal number of array elements to parse + * (set value of -1 for infinite) + * @param argv arguments array + * @return void + */ + void cfg_set_cmdline_context( + const CFG_CONTEXT con, + long begin_pos, + long size, + char **argv); + +#define cfg_set_cmdline_context_pos(con, begin_pos, end_pos, argv) \ + cfg_get_cmdline_context( \ + con \ + begin_pos, \ + end_pos - begin_pos + 1, \ + argv) + + /** + * Set context to command line by argc and argv passed to main() + * + * @param con initialized context + * @param argc argumet count (argc) passed to function main() + * @param argv arguments array (argv) passed to function main() + * @return initialized command line context + */ + void cfg_set_cmdline_context_argc( + const CFG_CONTEXT con, + int argc, + char **argv); + + /** + * Set context to configuration file + * + * @param con initialized context + * @param begin_pos starting position in file to parse + * @param size maximal number of bytes/lines in file to parse + * (set value of -1 for infinite) + * @param filename parsed filename + * @return void + */ + void cfg_set_cfgfile_context( + const CFG_CONTEXT con, + long begin_pos, + long size, + char *filename); + +#define cfg_set_cfgfile_context_pos(con, begin_pos, end_pos, argv) \ + cfg_get_cfgfile_context( \ + con \ + begin_pos, \ + end_pos - begin_pos + 1, \ + argv) + + /** + * Reinitialize popt context + * + * @param con initialized context + * @return void + */ + void cfg_reset_context(const CFG_CONTEXT con); + + /** + * Destroy context + * + * @param con initialized context + * @return void + */ + void cfg_free_context(const CFG_CONTEXT con); + + /* }}} */ /*@}*/ + + /** + * @name Functions for setting and clearing context flags + */ + /*@{*/ /* {{{ */ + + /** + * Set context flag + * + * @param con initialized context + * @param flag context flag + * @return void + */ + void cfg_set_context_flag(const CFG_CONTEXT con, int flag); + + /** + * Clear context flag + * + * @param con initialized context + * @param flag context flag + * @return void + */ + void cfg_clear_context_flag(const CFG_CONTEXT con, int flag); + + /** + * Get context flag + * + * @param con initialized context + * @param flag context flag + * @return 0 on false, non-zero on true + */ + int cfg_get_context_flag(const CFG_CONTEXT con, int flag); + +#define cfg_is_context_flag(con, flag) cfg_get_context_flag(con, flag) + + /** + * Overwrite context flags + * + * @param con initialized context + * @param flags context flags + * @return void + */ + void cfg_set_context_flags(const CFG_CONTEXT con, int flags); + + /** + * Get all context flags + * + * @param con initialized context + * @return all context flags + */ + int cfg_get_context_flags(const CFG_CONTEXT con); + + /* }}} */ /*@}*/ + + /** + * @name Functions and macros for properties manipulation + */ + /*@{*/ /* {{{ */ + + /** + * Clear all strings of property + * + * @param con initialized context + * @param type property type + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + */ + int cfg_clear_property( + const CFG_CONTEXT con, enum cfg_property_type type); + + /** + * Clear all strings of property + * + * @param con initialized context + * @param type property type + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + */ + int cfg_clear_properties( + const CFG_CONTEXT con, enum cfg_property_type type, ...); + + + /** + * Add string to property + * + * @param con initialized context + * @param type property type + * @param str string for addition + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + */ + int cfg_add_property( + const CFG_CONTEXT con, enum cfg_property_type type, char *str); + + /** + * Add multiple strings to particular properties + * + * @param con initialized context + * @param type property type(s) + * @param str string(s) for addition + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + * + * Argument list must be terminated with typeN = CFG_EOT or strN = NULL. + * Use constructions like this:<br> + * cfg_add_properties(con, type1, str1, type2, str2, type3=CFG_EOT) + */ + int cfg_add_properties( + const CFG_CONTEXT con, enum cfg_property_type type, char *str, ...); + + /** + * Add string to multiple properties + * + * @param con initialized context + * @param str string for addition + * @param type property type(s) + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + * + * Argument list must be terminated with typeN = CFG_EOT. Use constructions + * like this:<br> + * cfg_add_properties(con, str, type1, type2, type3=CFG_EOT) + */ + int cfg_add_properties_str( + const CFG_CONTEXT con, char *str, enum cfg_property_type type, ...); + + /** + * Add multiple strings to one property + * + * @param con initialized context + * @param type property type + * @param str string(s) for addition + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + * + * Argument list must be terminated with strN = NULL. Use constructions + * like this:<br> + * cfg_add_properties(con, type, str1, str2, str3=NULL) + */ + int cfg_add_properties_type( + const CFG_CONTEXT con, enum cfg_property_type type, char *str, ...); + + /** + * Remove string from property + * + * @param con initialized context + * @param type property type + * @param str string for removal + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + */ + int cfg_remove_property( + const CFG_CONTEXT con, enum cfg_property_type type, char *str); + + /** + * Remove multiple strings from particular properties + * + * @param con initialized context + * @param type property type(s) + * @param str string(s) for removal + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + * + * Argument list must be terminated with typeN = CFG_EOT or strN = NULL. + * Use constructions like this:<br> + * cfg_remove_properties(con, type1, str1, type2, str2, type3=CFG_EOT) + */ + int cfg_remove_properties( + const CFG_CONTEXT con, enum cfg_property_type type, char *str, ...); + + /** + * Remove string from multiple properties + * + * @param con initialized context + * @param str string for removal + * @param type property type(s) + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + * + * Argument list must be terminated with typeN = CFG_EOT. Use constructions + * like this:<br> + * cfg_remove_properties(con, str, type1, type2, type3=CFG_EOT) + */ + int cfg_remove_properties_str( + const CFG_CONTEXT con, char *str, enum cfg_property_type type, ...); + + /** + * Remove multiple strings from one property + * + * @param con initialized context + * @param type property type + * @param str string(s) for removal + * @return 1 on success, 0 on not enough memory error + * @see cfg_property_type + * + * Argument list must be terminated with strN = NULL. Use constructions + * like this:<br> + * cfg_add_properties(con, type, str1, str2, str3=NULL) + */ + int cfg_remove_properties_type( + const CFG_CONTEXT con, enum cfg_property_type type, char *str, ...); + + /* }}} */ /*@}*/ + + /** + * @name Functions for processing context options + */ + /*@{*/ /* {{{ */ + + /** + * Parse context + * + * @param con initialized context + * @return code of error (CFG_ERROR_*) + * or CFG_OK if parsing was sucessfull + * @see cfg_error + */ + int cfg_parse(const CFG_CONTEXT con); + + /** + * Parse next option(s) and return its value (if non-zero) or error code. + * + * @param con initialized context + * @return next option val, code of error (CFG_ERROR_*) + * or CFG_OK on end + * @see cfg_error + * @see cfg_context + */ + int cfg_get_next_opt(const CFG_CONTEXT con); + + /** + * Return currently processed option name + * + * @param con initialized context + * @return pointer to current option name + */ + char *cfg_get_cur_opt(const CFG_CONTEXT con); + + /** + * Return currently processed option argument + * + * @param con initialized context + * @return pointer to current option argument + */ + char *cfg_get_cur_arg(const CFG_CONTEXT con); + + /** + * Return currently processed option index (argv index in command line + * context, file byte position or line position in config file context) + * + * @param con initialized context @return index of current option + */ + int cfg_get_cur_idx(const CFG_CONTEXT con); + + /* }}} */ /*@}*/ + + /** + * @name Error handling functions + */ + /*@{*/ /* {{{ */ + + /** + * Print error string to stderr + * + * @param con initialized context + * @return void + */ + void cfg_print_error(const CFG_CONTEXT con); + + /** + * Print error string to stream + * + * @param con initialized context + * @param fh stream opened for writting + * @return void + */ + void cfg_fprint_error(const CFG_CONTEXT con, FILE *fh); + + /** + * Get error string; error string is dynamically allocated, it needs to be + * freed after use. + * + * @param con initialized context + * @return dynamically allocated error string + */ + char *cfg_get_error_str(const CFG_CONTEXT con); + + /** + * Get static error string + * + * @param errorcode code of libcfg error + * @return static error string + */ + char *cfg_get_static_error_str(const int errorcode); + + /* }}} */ /*@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _PLATON_CFG_H */ + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/cfgfile.c b/src/cfg/cfgfile.c new file mode 100644 index 0000000000..398ac47505 --- /dev/null +++ b/src/cfg/cfgfile.c @@ -0,0 +1,285 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * cfgfile.c - config file parsing + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2003 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/cfgfile.c,v 1.26 2003/11/07 17:26:48 nepto Exp $ */ + +/* Includes {{{ */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if STDC_HEADERS +# include <stdlib.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <platon/str/strdyn.h> +#include <platon/str/strplus.h> +#include <platon/str/dynfgets.h> + +#include "cfg+.h" +#include "shared.h" +/* }}} */ + +/* Static function declarations {{{ */ +static int get_multi_line(const CFG_CONTEXT con, char **buf); +/* }}} */ + + int +cfg_cfgfile_get_next_opt(con) + const CFG_CONTEXT con; +{ /* {{{ */ + char *buf; + int ret_val; + + con->error_code = CFG_OK; + + /* Initial position seek */ + if (con->fhandle == NULL) { + con->fhandle = con->filename != NULL + ? fopen(con->filename, "r") + : NULL; + if (con->fhandle == NULL) { + con->error_code = CFG_ERROR_FILE_NOT_FOUND; + return con->error_code; + } + + if (con->flags & CFG_FILE_LINE_POS_USAGE) { + /* If negative line is specified, returns seek error. + If 0 is specified, do nothing. + If number > 0 is specified make appropriate line seek. */ + if (con->begin_pos < 0) { + con->error_code = CFG_ERROR_SEEK_ERROR; + return con->error_code; + } + + if (con->begin_pos > 0) { + con->cur_idx = 0; + con->cur_idx_tmp = 0; + + /* Moving to begin_pos line */ + while (con->cur_idx_tmp < con->begin_pos) { + switch (fgetc(con->fhandle)) { + case EOF: + con->error_code = CFG_ERROR_SEEK_ERROR; + return con->error_code; + case '\n': + con->cur_idx_tmp++; + } + } + } + } + else { + if (/* always do: con->begin_pos > 0 && */ + fseek(con->fhandle, con->begin_pos, SEEK_SET) != 0) { + con->error_code = CFG_ERROR_SEEK_ERROR; + return con->error_code; + } + } + } + + /* + * Main loop + */ + while (1) { + /* Updating cur_idx to set current line position */ + if (con->flags & CFG_FILE_LINE_POS_USAGE) { + con->cur_idx += con->cur_idx_tmp; + con->cur_idx_tmp = 0; + } + + /* Reading multi line and exit on error */ + con->error_code = get_multi_line(con, &buf); + if (con->error_code != CFG_OK) { + if (buf != NULL) + free(buf); + + return con->error_code; + } + + /* Testing if file stop prefix was found */ + if (buf != NULL && con->prop[CFG_FILE_STOP_PREFIX] != NULL) { + if (buf == PLATON_FUNC(strdyn_str2)(buf, + con->prop[CFG_FILE_STOP_PREFIX], NULL)) { + __cfg_free_currents(con); + con->cur_opt = buf; + con->error_code = CFG_ERROR_STOP_STR; + return con->error_code; + } + } + + /* Finished? */ + if ((con->size >= 0 && cfg_get_cur_idx(con) >= con->begin_pos + con->size) + || feof(con->fhandle)) { + if (buf != NULL) + free(buf); + + return con->error_code; /* always CFG_OK */ + } + + __cfg_free_currents(con); + + if (__cfg_cfgfile_set_currents(con, buf) != CFG_OK) { + con->error_code = CFG_ERROR_NOMEM; + return con->error_code; + } + + free(buf); + + con->error_code = __cfg_process_currents(con, &ret_val, NULL); + if (con->error_code != CFG_OK) + return con->error_code; + + if (ret_val > 0) + return ret_val; + } + + return con->error_code; /* CFG_OK */ +} /* }}} */ + +/* + * get_multi_line() + * + * Gets single line from file. If line continues on next line, returns + * the whole line concatenated. Coments, remarks and empty lines are + * skipped. If end of file is reached CFG_OK is returned and higher + * level should determine that fact using feof() function. + */ + + static int +get_multi_line(con, buf) + const CFG_CONTEXT con; + char **buf; +{ /* {{{ */ + register char **ar = NULL; + register char *my_buf = NULL; + register int state = 0; + + *buf = NULL; + + if ((ar = PLATON_FUNC(strdyn_create)()) == NULL) + return CFG_ERROR_NOMEM; + + while (1) { + if (state > 1) + state = 1; + + if (my_buf != NULL) + free(my_buf); + + my_buf = PLATON_FUNC(dynamic_fgets)(con->fhandle); + if (my_buf == NULL) { + if (feof(con->fhandle)) + return CFG_OK; + + return CFG_ERROR_NOMEM; + } + + str_trim(my_buf); + + /* Is empty line or comment? */ + if (strlen(my_buf) == 0 || strdyn_str(my_buf, + con->prop[CFG_FILE_COMMENT_PREFIX]) == my_buf) { + + if (con->flags & CFG_FILE_LINE_POS_USAGE) + con->cur_idx++; + + if (state == 0) + continue; + else + break; + } + else { + if (con->flags & CFG_FILE_LINE_POS_USAGE) + con->cur_idx_tmp++; + } + + /* Multi line detection. */ + { + register char **pos; + register int max_len = 0; + register int len; + + for (pos = con->prop[CFG_FILE_MULTI_LINE_POSTFIX]; + pos != NULL && *pos != NULL; + pos++) { + + len = strlen(my_buf) - strlen(*pos); + + if (len > max_len && ! strcmp(*pos, my_buf + len)) + max_len = len; + } + + /* Multi line postfix found? */ + if (max_len > 0) { + my_buf[max_len] = '\0'; + state = 2; + + len = strlen(my_buf); + PLATON_FUNC(str_right_trim)(my_buf); + if (len - strlen(my_buf) > 0) { + /* Could be replaced with + strcpy(my_buf + strlen(my_buf), " "); */ + my_buf[strlen(my_buf) + 1] = '\0'; + my_buf[strlen(my_buf)] = ' '; + } + } + } + + ar = PLATON_FUNC(strdyn_add)(ar, my_buf); + if (ar == NULL) + return CFG_ERROR_NOMEM; + + if (state != 2) + break; + } + + if (my_buf != NULL) + free(my_buf); + + my_buf = PLATON_FUNC(str_right_trim)(strdyn_implode(ar, "")); + PLATON_FUNC(strdyn_free)(ar); + + if (my_buf == NULL) + return CFG_ERROR_NOMEM; + + *buf = my_buf; + + return CFG_OK; +} /* }}} */ + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/cfgfile.h b/src/cfg/cfgfile.h new file mode 100644 index 0000000000..7ed9d4ed8b --- /dev/null +++ b/src/cfg/cfgfile.h @@ -0,0 +1,46 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * cfgfile.h - config file parsing header file + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/cfgfile.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ */ + +/** + * @file cfgfile.h + * @brief config file parsing header file + * @author Ondrej Jombik <nepto@platon.sk> + * @author Lubomir Host <rajo@platon.sk> + * @version \$Platon: libcfg+/src/cfgfile.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ + * @date 2001-2004 + */ + +#ifndef _PLATON_CFG_CFGFILE_H +#define _PLATON_CFG_CFGFILE_H + +/** + * Parse next config file option(s) and return its value (if non-zero) + * or error code. + * + * @param con initialized config file context + * @return next option val, code of error (CFG_ERROR_*) + * or CFG_OK on end + * @see cfg_error + * @see cfg_context + */ +int cfg_cfgfile_get_next_opt(const CFG_CONTEXT con); + +#endif /* _PLATON_CFG_CFGFILE_H */ + diff --git a/src/cfg/cmdline.c b/src/cfg/cmdline.c new file mode 100644 index 0000000000..c6a08d5747 --- /dev/null +++ b/src/cfg/cmdline.c @@ -0,0 +1,183 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * cmdline.c - command line parsing + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/cmdline.c,v 1.36 2004/01/12 06:03:09 nepto Exp $ */ + +/* Includes {{{ */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if STDC_HEADERS +# include <stdlib.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif + +#include <platon/str/strplus.h> +#include <platon/str/strdyn.h> + +#include "cfg+.h" +#include "shared.h" +/* }}} */ + + int +cfg_cmdline_get_next_opt(con) + const CFG_CONTEXT con; +{ /* {{{ */ + int arg_used; + int ret_val; + + con->error_code = CFG_OK; + + /* Initial position seek */ + if (! con->parsing_started) { + con->parsing_started = 1; + + if (con->begin_pos < 0) { + con->error_code = CFG_ERROR_SEEK_ERROR; + return con->error_code; + } + + if (con->begin_pos > 0) { + for (; con->cur_idx < con->begin_pos; con->cur_idx++) + if (con->argv[con->cur_idx] == NULL) { + con->error_code = CFG_ERROR_SEEK_ERROR; + return con->error_code; + } + } + + if (con->flags & CFG_SKIP_FIRST) + con->cur_idx_tmp = 1; + else + con->cur_idx_tmp = 0; + } + + /* + * Main loop + */ + while (1) { + + arg_used = 0; + + /* Updating cur_idx step by step and testing for NULL in argv. */ + for (; con->cur_idx_tmp > 0; con->cur_idx_tmp--, con->cur_idx++) + if (con->argv[con->cur_idx] == NULL) + break; + + /* Finished? (size is reached) */ + if (con->size >= 0 && con->cur_idx >= con->begin_pos + con->size) + break; + + /* Finished? (NULL is detected) */ + if (con->argv[con->cur_idx] == NULL) + break; + + if (con->cur_opt_type & CFG_SHORT_OPTIONS) { + + con->cur_opt[0] = con->cur_arg[0]; + PLATON_FUNC(strdel)(con->cur_arg); + + if (strlen(con->cur_arg) == 0) { + con->cur_opt_type -= CFG_SHORT_OPTIONS; + free(con->cur_arg); + + /* strdup() doesn't accept NULL as parameter */ + con->cur_arg = con->argv[con->cur_idx + 1] != NULL + ? strdup(con->argv[con->cur_idx + 1]) + : NULL; + } + } + else { + register int leftover_init = 0; + + /* Test if previous argument was leftover and also there is not + advanced leftovers initializations set in context flags. */ + if (! (con->flags & CFG_ADVANCED_LEFTOVERS) + && con->cur_opt_type == CFG_NONE_OPTION + && con->cur_opt == NULL && con->cur_arg != NULL + && con->argv[con->cur_idx - 1] != NULL + && ! strcmp(con->cur_arg, con->argv[con->cur_idx - 1])) + leftover_init = 1; + + __cfg_free_currents(con); + + if (! PLATON_FUNC(strdyn_compare)(con->prop[CFG_LINE_STOP_STRING], + con->argv[con->cur_idx])) { + con->error_code = CFG_ERROR_STOP_STR_FOUND; + return con->error_code; + } + + /* Skip option analyze in __cfg_cmdline_set_currents(), + count it as leftover. */ + if (leftover_init) { + con->cur_opt_type = CFG_NONE_OPTION; + con->cur_opt = NULL; + if ((con->cur_arg = strdup(con->argv[con->cur_idx])) == NULL) { + con->error_code = CFG_ERROR_NOMEM; + return con->error_code; + } + } + else { + if (__cfg_cmdline_set_currents(con) != CFG_OK) { + con->error_code = CFG_ERROR_NOMEM; + return con->error_code; + } + } + } + + con->error_code = __cfg_process_currents(con, &ret_val, &arg_used); + if (con->error_code != CFG_OK) + return con->error_code; + + if (arg_used) { + if (! (con->cur_opt_type & CFG_LONG_SEPINIT) + && !(con->cur_opt_type & CFG_SHORT_OPTIONS) + && !(con->cur_opt_type == CFG_NONE_OPTION)) + con->cur_idx_tmp++; + + if (con->cur_opt_type & CFG_SHORT_OPTIONS) + con->cur_opt_type -= CFG_SHORT_OPTIONS; + } + + if (! (con->cur_opt_type & CFG_SHORT_OPTIONS)) + con->cur_idx_tmp++; + + if (ret_val > 0) + return ret_val; + } + + return con->error_code; /* CFG_OK */ +} /* }}} */ + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/cmdline.h b/src/cfg/cmdline.h new file mode 100644 index 0000000000..2c2e782e6d --- /dev/null +++ b/src/cfg/cmdline.h @@ -0,0 +1,46 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * cmdline.h - command line parsing header file + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/cmdline.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ */ + +/** + * @file cmdline.h + * @brief command line parsing header file + * @author Ondrej Jombik <nepto@platon.sk> + * @author Lubomir Host <rajo@platon.sk> + * @version \$Platon: libcfg+/src/cmdline.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ + * @date 2001-2004 + */ + +#ifndef _PLATON_CFG_CMDLINE_H +#define _PLATON_CFG_CMDLINE_H + +/** + * Parse next command line option(s) and return its value (if non-zero) + * or error code. + * + * @param con initialized command line context + * @return next option val, code of error (CFG_ERROR_*) + * or CFG_OK on end + * @see cfg_error + * @see cfg_context + */ +int cfg_cmdline_get_next_opt(const CFG_CONTEXT con); + +#endif /* _PLATON_CFG_CMDLINE_H */ + diff --git a/src/cfg/parse.c b/src/cfg/parse.c new file mode 100644 index 0000000000..f2cea0397e --- /dev/null +++ b/src/cfg/parse.c @@ -0,0 +1,101 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * parse.c - universal parsing functions + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/parse.c,v 1.24 2004/01/12 06:03:09 nepto Exp $ */ + +/* Includes {{{ */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#if STDC_HEADERS +# include <stdlib.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif + +#include "cfg+.h" +#include "cmdline.h" +#include "cfgfile.h" +/* }}} */ + +/* Processing context options. */ + + int +cfg_parse(con) + const CFG_CONTEXT con; +{ /* {{{ */ + register int ret; + + while ((ret = cfg_get_next_opt(con)) > 0) + ; + + return ret; +} /* }}} */ + + int +cfg_get_next_opt(con) + const CFG_CONTEXT con; +{ /* {{{ */ + return con->type == CFG_CMDLINE + ? cfg_cmdline_get_next_opt(con) + : cfg_cfgfile_get_next_opt(con); +} /* }}} */ + + char * +cfg_get_cur_opt(con) + const CFG_CONTEXT con; +{ /* {{{ */ + return con->cur_opt; +} /* }}} */ + + char * +cfg_get_cur_arg(con) + const CFG_CONTEXT con; +{ /* {{{ */ + return con->cur_arg; +} /* }}} */ + + int +cfg_get_cur_idx(con) + const CFG_CONTEXT con; +{ /* {{{ */ + return con->type == CFG_CMDLINE + ? con->cur_idx + : (con->flags & CFG_FILE_LINE_POS_USAGE + ? con->cur_idx + : (con->fhandle != NULL ? (int) ftell(con->fhandle) : 0)); +} /* }}} */ + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/platon/Makefile.am b/src/cfg/platon/Makefile.am new file mode 100644 index 0000000000..a15898a2b4 --- /dev/null +++ b/src/cfg/platon/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = str + diff --git a/src/cfg/platon/str/Makefile.am b/src/cfg/platon/str/Makefile.am new file mode 100644 index 0000000000..0510349997 --- /dev/null +++ b/src/cfg/platon/str/Makefile.am @@ -0,0 +1,4 @@ +EXTRA_DIST = dynfgets.c dynfgets.h strctype.c strctype.h \ + strdyn.c strdyn.h strplus.c strplus.h + + diff --git a/src/cfg/platon/str/dynfgets.c b/src/cfg/platon/str/dynfgets.c new file mode 100644 index 0000000000..3341ef6ae4 --- /dev/null +++ b/src/cfg/platon/str/dynfgets.c @@ -0,0 +1,44 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <platon/str/dynfgets.h> + + char * +PLATON_FUNC(dynamic_fgets)(fp) + FILE *fp; +{ + char temp[DYNAMIC_FGETS_BUFSIZE]; + register char *ptr; + register int i; + + if ((ptr = (char *) malloc(1)) == NULL) + return NULL; + + for (*ptr = '\0', i = 0; ; i++) { + if (fgets(temp, DYNAMIC_FGETS_BUFSIZE, fp) == NULL) { + if (ferror(fp) != 0 || i == 0) { + free(ptr); + return NULL; + } + + return ptr; + } + + ptr = (char *) realloc(ptr, (DYNAMIC_FGETS_BUFSIZE - 1) * (i + 1) + 1); + if (ptr == NULL) + return NULL; + + strcat(ptr, temp); + + if (strchr(temp, '\n') != NULL) { + *strchr(ptr, '\n') = '\0'; + return ptr; + } + } +} + diff --git a/src/cfg/platon/str/dynfgets.h b/src/cfg/platon/str/dynfgets.h new file mode 100644 index 0000000000..ab7ee50f5a --- /dev/null +++ b/src/cfg/platon/str/dynfgets.h @@ -0,0 +1,46 @@ +/** + * Unlimited dynamic fgets() routine + * + * @file platon/str/dynfgets.h + * @author Yuuki Ninomiya <gm@debian.or.jp> + * @author Ondrej Jombik <nepto@platon.sk> + * @version \$Platon: libcfg+/src/platon/str/dynfgets.h,v 1.12 2004/01/12 06:03:09 nepto Exp $ + * @date 2001-2004 + */ + +#ifndef _PLATON_STR_DYNFGETS_H +#define _PLATON_STR_DYNFGETS_H + +#include <stdio.h> + +#ifndef PLATON_FUNC +# define PLATON_FUNC(_name) _name +#endif +#ifndef PLATON_FUNC_STR +# define PLATON_FUNC_STR(_name) #_name +#endif + +/** Size of input buffer. In others words, size of realloc() step. */ +#define DYNAMIC_FGETS_BUFSIZE (128) + +/** Macro alias */ +#define dynfgets(f) dynamic_fgets(f) + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Dynamic fgets() with unlimited line length + * + * @param fp stream (FILE * pointer) + * @return dynamically allocated buffer or NULL on not enough memory error + */ + char *PLATON_FUNC(dynamic_fgets)(FILE *fp); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef _PLATON_STR_DYNFGETS_H */ + diff --git a/src/cfg/platon/str/strctype.c b/src/cfg/platon/str/strctype.c new file mode 100644 index 0000000000..5fcc55ce76 --- /dev/null +++ b/src/cfg/platon/str/strctype.c @@ -0,0 +1,99 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <string.h> +#include <ctype.h> + +#include <platon/str/strctype.h> + + int +PLATON_FUNC(strctype_fnc)(s, fnc) + const char *s; + int (* fnc)(int); +{ + register int i; + + for (i = 0; s[i] != '\0'; i++) + if (! fnc(s[i])) + return 0; + + return 1; +} + + char * +PLATON_FUNC(strtolower)(s) + char *s; +{ + register int i; + + for (i = 0; s[i] != '\0'; i++) + s[i] = tolower(s[i]); + + return s; +} + + char * +PLATON_FUNC(strtoupper)(s) + char *s; +{ + register int i; + + for (i = 0; s[i] != '\0'; i++) + s[i] = toupper(s[i]); + + return s; +} + +#if defined(SELF) || defined(SELFTEST) || defined(SELF_STRCTYPE) + +#include <stdio.h> +#include <stdlib.h> + +#define TESTSTR1 "___AAA_BBBB__C_DaDaD____" +#define TESTSTR2 "aaa~!@#$%^&*()_+|{];':\",./<>?" +#define TESTSTR3 "abcdefghijklmnoprstu" +#define TESTSTR4 "ABCDEFGHIJKLMNOPRSTU" + + int +main(void) +{ + + /* Testing strisXXX() functions. */ + + printf("strislower(\"%s\") = %d\n", TESTSTR1, strislower(TESTSTR1)); + printf("strisupper(\"%s\") = %d\n", TESTSTR1, strisupper(TESTSTR1)); + printf("strislower(\"%s\") = %d\n", TESTSTR2, strislower(TESTSTR2)); + printf("strisupper(\"%s\") = %d\n", TESTSTR2, strisupper(TESTSTR2)); + printf("strislower(\"%s\") = %d\n", TESTSTR3, strislower(TESTSTR3)); + printf("strisupper(\"%s\") = %d\n", TESTSTR3, strisupper(TESTSTR3)); + printf("strislower(\"%s\") = %d\n", TESTSTR4, strislower(TESTSTR4)); + printf("strisupper(\"%s\") = %d\n", TESTSTR4, strisupper(TESTSTR4)); + + /* Testing strtoXXX() functions. */ + + { + char *s1, *s2; + + s1 = strdup(TESTSTR1); + s2 = strdup(TESTSTR2); + + if (s1 == NULL || s2 == NULL) + return 1; + + printf("strtolower(\"%s\") =", s1); + printf(" \"%s\"\n", strtolower(s1)); + + printf("strtoupper(\"%s\") =", s2); + printf(" \"%s\"\n", strtoupper(s2)); + + free(s1); + free(s2); + + } + + return 0; +} + +#endif /* #if defined(SELF) || defined(SELFTEST) || defined(SELF_STRCTYPE) */ + diff --git a/src/cfg/platon/str/strctype.h b/src/cfg/platon/str/strctype.h new file mode 100644 index 0000000000..82627a3735 --- /dev/null +++ b/src/cfg/platon/str/strctype.h @@ -0,0 +1,40 @@ +#ifndef _PLATON_STR_STRCTYPE_H +#define _PLATON_STR_STRCTYPE_H + +#ifndef PLATON_FUNC +# define PLATON_FUNC(_name) _name +#endif +#ifndef PLATON_FUNC_STR +# define PLATON_FUNC_STR(_name) #_name +#endif + +# define strisalnum(s) PLATON_FUNC(strctype_fnc)(s, isalnum) +# define strisalpha(s) PLATON_FUNC(strctype_fnc)(s, isalpha) +# define strisascii(s) PLATON_FUNC(strctype_fnc)(s, isascii) +# define strisblank(s) PLATON_FUNC(strctype_fnc)(s, isblank) +# define striscntrl(s) PLATON_FUNC(strctype_fnc)(s, iscntrl) +# define strisdigit(s) PLATON_FUNC(strctype_fnc)(s, isdigit) +# define strisgraph(s) PLATON_FUNC(strctype_fnc)(s, isgraph) +# define strislower(s) PLATON_FUNC(strctype_fnc)(s, islower) +# define strisprint(s) PLATON_FUNC(strctype_fnc)(s, isprint) +# define strispunct(s) PLATON_FUNC(strctype_fnc)(s, ispunct) +# define strisspace(s) PLATON_FUNC(strctype_fnc)(s, isspace) +# define strisupper(s) PLATON_FUNC(strctype_fnc)(s, isupper) +# define strisxdigit(s) PLATON_FUNC(strctype_fnc)(s, isxdigit) +# define strlwr(s) PLATON_FUNC(strtolower)(s) +# define strupr(s) PLATON_FUNC(strtoupper)(s) + +#ifdef __cplusplus +extern "C" { +#endif + + char *PLATON_FUNC(strtolower)(char *s); + char *PLATON_FUNC(strtoupper)(char *s); + int PLATON_FUNC(strctype_fnc)(const char *s, int (*fnc)(int)); + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef _PLATON_STR_STRCTYPE_H */ + diff --git a/src/cfg/platon/str/strdyn.c b/src/cfg/platon/str/strdyn.c new file mode 100644 index 0000000000..2883fe4ff7 --- /dev/null +++ b/src/cfg/platon/str/strdyn.c @@ -0,0 +1,682 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#include <platon/str/strplus.h> +#include <platon/str/strdyn.h> + + void +PLATON_FUNC(strdyn_free)(ar) + char **ar; +{ + register int i; + + for (i = 0; ar[i] != NULL; i++) + free(ar[i]); + + free(ar); +} + + void +PLATON_FUNC(strdyn_safe_free)(ar) + char **ar; +{ + if (ar == NULL) + return; + + PLATON_FUNC(strdyn_free)(ar); + + return; +} + + int +PLATON_FUNC(strdyn_get_size)(ar) + char **ar; +{ + register int i; + + for (i = 0; ar[i] != NULL; i++) + ; + + return i; +} + + char ** +PLATON_FUNC(strdyn_create)(void) +{ + register char **ar; + + if ((ar = (char **) malloc(1 * sizeof(char *))) == NULL) + return NULL; + + ar[0] = NULL; + + return ar; +} + +char ** +PLATON_FUNC(strdyn_create_va)( + char *s1, + ...) +{ + register char **ar; + + if ((ar = PLATON_FUNC(strdyn_create)()) == NULL) + return NULL; + + if (s1 != NULL) { + register char *s; + va_list ap; + + if ((ar = PLATON_FUNC(strdyn_add)(ar, s1)) == NULL) + return NULL; + + va_start(ap, s1); + + while ((s = va_arg(ap, char *)) != NULL) + if ((ar = PLATON_FUNC(strdyn_add)(ar, s)) == NULL) + return NULL; + + va_end(ap); + } + + return ar; +} + + char ** +PLATON_FUNC(strdyn_create_ar)(ar) + char **ar; +{ + register int i; + register char **new_ar; + + if ((new_ar = (char**) malloc((PLATON_FUNC(strdyn_get_size)(ar) + 1) + * sizeof(char*))) == NULL) + return NULL; + + for (i = 0; ar[i] != NULL; i++) + new_ar[i] = strdup(ar[i]); + + new_ar[i] = NULL; + + return new_ar; +} + +char ** +PLATON_FUNC(strdyn_safe_create_ar)(ar) + char **ar; +{ + if (ar == NULL) + return NULL; + + return PLATON_FUNC(strdyn_create_ar)(ar); +} + +char ** +PLATON_FUNC(strdyn_add)(ar, s) + char **ar; + const char *s; +{ + register int count; + + if (ar == NULL) + if ((ar = PLATON_FUNC(strdyn_create)()) == NULL) + return NULL; + + count = PLATON_FUNC(strdyn_get_size)(ar); + + if ((ar = (char **) realloc(ar, (count + 2) * sizeof(char *))) == NULL) + return NULL; + + ar[count] = strdup(s); + ar[count + 1] = NULL; + + return ar; +} + +char ** +PLATON_FUNC(strdyn_add_va)( + char **ar, + ...) +{ + register char *s; + va_list ap; + + if (ar == NULL) + if ((ar = PLATON_FUNC(strdyn_create)()) == NULL) + return NULL; + + va_start(ap, ar); + + while ((s = va_arg(ap, char *)) != NULL) + if ((ar = PLATON_FUNC(strdyn_add)(ar, s)) == NULL) + return NULL; + + va_end(ap); + + return ar; +} + +char ** +PLATON_FUNC(strdyn_add_ar)(ar, s_ar) + char **ar; + char * const *s_ar; +{ + register int k; + + for (k = 0; s_ar[k] != NULL; k++) + if ((ar = PLATON_FUNC(strdyn_add)(ar, s_ar[k])) == NULL) + return NULL; + + return ar; +} + +char ** +PLATON_FUNC(strdyn_remove_idx)(ar, idx) + char **ar; + int idx; +{ + register int i; + + for (i = 0; ar[i] != NULL; i++) { + if (i == idx) + free(ar[i]); + + if (i >= idx) + ar[i] = ar[i + 1]; + } + + if ((ar = (char**) realloc(ar, i * sizeof(char*))) == NULL) + return NULL; + + return ar; +} + +char ** +PLATON_FUNC(strdyn_remove_str)(ar, s) + char **ar; + char *s; +{ + register int idx; + + idx = PLATON_FUNC(strdyn_search)(ar, s); + + if (idx < 0) + return ar; + + return PLATON_FUNC(strdyn_remove_idx)(ar, idx); +} + +char ** +PLATON_FUNC(strdyn_remove_str_all)(ar, s) + char **ar; + char *s; +{ + char **new_ar = NULL; + + while (new_ar != ar) { + if (new_ar != NULL) + ar = new_ar; + + if ((new_ar = PLATON_FUNC(strdyn_remove_str)(ar, s)) == NULL) + return NULL; + } + + return ar; +} + +char ** +PLATON_FUNC(strdyn_remove_empty)(ar) + char **ar; +{ + register int i, j; + + for (i = 0; ar[i] != NULL; ) { + + if (strlen(ar[i]) == 0) { + free(ar[i]); + + for (j = i; ar[j] != NULL; j++) + ar[j] = ar[j + 1]; + } + else + i++; + } + + if ((ar = (char**) realloc(ar, (i + 1) * sizeof(char*))) == NULL) + return NULL; + + return ar; +} + +char ** +PLATON_FUNC(strdyn_remove_all)(ar) + char **ar; +{ + register int i; + + for (i = 0; ar[i] != NULL; i++) + free(ar[i]); + + if ((ar = (char**) realloc(ar, /* 1 * */ sizeof(char*))) == NULL) + return NULL; + + ar[0] = NULL; + + return ar; +} + +char ** +PLATON_FUNC(strdyn_explode_chr)(str, sep) + char *str; + int sep; +{ + char sep_str[2]; + + sep_str[0] = (char) sep; + sep_str[1] = '\0'; + + return PLATON_FUNC(strdyn_explode_str)(str, sep_str); +} + +char ** +PLATON_FUNC(strdyn_explode2_chr)(str, sep) + char *str; + int sep; +{ + + return PLATON_FUNC(strdyn_remove_empty)(PLATON_FUNC(strdyn_explode_chr)(str, sep)); +} + +char ** +PLATON_FUNC(strdyn_explode_str)(str, sep) + char *str; + char *sep; +{ + register char **ar; + register char *s; + register int ar_size, s_size, sep_size, i; + + if (str == NULL || sep == NULL) + return NULL; + + ar_size = PLATON_FUNC(strcnt_sepstr)(str, sep); + + if ((ar = (char**) malloc((ar_size + 2) * sizeof(char*))) == NULL) + return NULL; + + sep_size = strlen(sep); + + for (s = str, i = 0; i < ar_size; i++, s += s_size + sep_size) { + + s_size = strstr(s, sep) - s; + + if ((ar[i] = (char*) malloc((s_size + 1) * sizeof(char))) == NULL) + return NULL; + + strncpy(ar[i], s, s_size); + ar[i][s_size] = '\0'; + } + + if ((ar[ar_size] = strdup(s)) == NULL) + return NULL; + + ar[ar_size + 1] = NULL; + + return ar; + +} + +char ** +PLATON_FUNC(strdyn_explode2_str)(str, sep) + char *str; + char *sep; +{ + return PLATON_FUNC(strdyn_remove_empty)(PLATON_FUNC(strdyn_explode_str)(str, sep)); +} + +char ** +PLATON_FUNC(strdyn_explode_ar)(str, sep) + char *str; + char **sep; +{ + /* WARNING: Unefective recursion used! */ + /* TODO: Various code optimalizations. */ + + char **ar, **ar1; + + if ((ar1 = PLATON_FUNC(strdyn_explode_str)(str, sep[0])) == NULL) + return NULL; + + if (sep[1] != NULL) { + char **ar2; + register int i; + + if ((ar = PLATON_FUNC(strdyn_create)()) == NULL) { + PLATON_FUNC(strdyn_free)(ar1); + return NULL; + } + + for (i = 0; i < strdyn_count(ar1); i++) { + if ((ar2 = PLATON_FUNC(strdyn_explode_ar)(ar1[i], sep + 1)) == NULL) { + PLATON_FUNC(strdyn_free)(ar1); + PLATON_FUNC(strdyn_free)(ar); + return NULL; + } + + if ((ar = PLATON_FUNC(strdyn_add_ar)(ar, ar2)) == NULL) { + PLATON_FUNC(strdyn_free)(ar1); + PLATON_FUNC(strdyn_free)(ar); + PLATON_FUNC(strdyn_free)(ar2); + return NULL; + } + + PLATON_FUNC(strdyn_free)(ar2); + } + + PLATON_FUNC(strdyn_free)(ar1); + } + else + ar = ar1; + + return ar; +} + +char ** +PLATON_FUNC(strdyn_explode2_ar)(str, sep) + char *str; + char **sep; +{ + return PLATON_FUNC(strdyn_remove_empty)(PLATON_FUNC(strdyn_explode_ar)(str, sep)); +} + +char * +PLATON_FUNC(strdyn_implode_chr)(ar, sep) + char **ar; + int sep; +{ + char sep_str[2]; + + sep_str[0] = (char) sep; + sep_str[1] = '\0'; + + return PLATON_FUNC(strdyn_implode_str)(ar, sep_str); +} + +char * +PLATON_FUNC(strdyn_implode2_chr)(ar, sep) + char **ar; + int sep; +{ + register char **new_ar; + register char *s; + + new_ar = PLATON_FUNC(strdyn_remove_empty)(strdyn_duplicate(ar)); + + s = PLATON_FUNC(strdyn_implode_chr)(new_ar, sep); + + PLATON_FUNC(strdyn_free)(new_ar); + + return s; +} + +char * +PLATON_FUNC(strdyn_implode_str)(ar, sep) + char **ar; + char *sep; +{ + register int i, str_size, sep_size; + register char *str, *s; + + sep_size = strlen(sep); + + for (i = 0, str_size = 0; ar[i] != NULL; i++) + str_size += strlen(ar[i]) + sep_size; + + str_size -= sep_size; + + if ((str = (char*) malloc((str_size + 1) * sizeof(char))) == NULL) + return NULL; + + for (i = 0, s = str; ar[i] != NULL; i++) { + strcpy(s, ar[i]); + s += strlen(ar[i]); + + if (ar[i + 1] != NULL) + strcpy(s, sep); + s += sep_size; + } + + return str; +} + +char * +PLATON_FUNC(strdyn_implode2_str)(ar, str) + char **ar; + char *str; +{ + register char **new_ar; + register char *s; + + new_ar = PLATON_FUNC(strdyn_remove_empty)(strdyn_duplicate(ar)); + + s = PLATON_FUNC(strdyn_implode_str)(new_ar, str); + + PLATON_FUNC(strdyn_free)(new_ar); + + return s; +} + +char ** +PLATON_FUNC(strdyn_conjunct)(ar1, ar2) + char **ar1; + char **ar2; +{ + register int i; + register char **ar; + + if ((ar = PLATON_FUNC(strdyn_create)()) == NULL) + return NULL; + + for (i = 0; ar2[i] != NULL; i++) { + if (! PLATON_FUNC(strdyn_compare)(ar1, ar2[i])) { + if ((ar = PLATON_FUNC(strdyn_add)(ar, ar2[i])) == NULL) + return NULL; + } + } + + return ar; +} + +char ** +PLATON_FUNC(strdyn_consolide)(ar1, ar2) + char **ar1; + char **ar2; +{ + register int i; + register char **ar; + + if ((ar = PLATON_FUNC(strdyn_create)()) == NULL) + return NULL; + + for (i = 0; ar1[i] != NULL; i++) { + if (PLATON_FUNC(strdyn_compare)(ar, ar1[i])) { + if ((ar = PLATON_FUNC(strdyn_add)(ar, ar1[i])) == NULL) + return NULL; + } + } + + for (i = 0; ar2[i] != NULL; i++) { + if (PLATON_FUNC(strdyn_compare)(ar, ar2[i])) { + if ((ar = PLATON_FUNC(strdyn_add)(ar, ar2[i])) == NULL) + return NULL; + } + } + + return ar; +} + +int +PLATON_FUNC(strdyn_search)(ar, s) + char **ar; + char *s; +{ + register int i; + + for (i = 0; ar[i] != NULL; i++) + if (! strcmp(ar[i], s)) + return i; + + return -1; +} + +int +PLATON_FUNC(strdyn_casesearch)(ar, s) + char **ar; + char *s; +{ + register int i; + + for (i = 0; ar[i] != NULL; i++) + if (! strcasecmp(ar[i], s)) + return i; + + return -1; +} + +int +PLATON_FUNC(strdyn_compare)(ar, s) + char **ar; + char *s; +{ + return PLATON_FUNC(strdyn_search)(ar, s) < 0 ? -1 : 0; +} + +int +PLATON_FUNC(strdyn_casecompare)(ar, s) + char **ar; + char *s; +{ + return PLATON_FUNC(strdyn_casesearch)(ar, s) < 0 ? -1 : 0; + return PLATON_FUNC(strdyn_casesearch)(ar, s) < 0 ? -1 : 0; +} + +int +PLATON_FUNC(strdyn_compare_all)(ar, s) + char **ar; + char *s; +{ + register int i; + + for (i = 0; ar[i] != NULL; i++) + if (strcmp(ar[i], s)) + return -1; + + return 0; +} + +char * +PLATON_FUNC(strdyn_str2)(s, ar, idx) + char *s; + char **ar; + int *idx; +{ + register char *ret, *tmp_s; + register int i; + + for (ret = NULL, i = 0; ar[i] != NULL; i++) + if ((tmp_s = strstr(s, ar[i])) != NULL + && (ret == NULL || tmp_s < ret)) { + ret = tmp_s; + + if (idx != NULL) + *idx = i; + } + + return ret; +} + +#if defined(SELF) || defined(SELFTEST) || defined(SELF_STRDYN) + +#define TESTSTR1 "___AAA_BBBB__C_DaDaD____" +#define TESTSEP1 '_' +#define TESTSEP2 "__" + + int +main(void) +{ + + register int i; + char **ar1, **ar2, **ar_join, **ar_intersect; + char *s; + + ar2 = strdyn_create_va("A", "B", "C", "D", NULL); + + i = 0; + while (ar2[i] != NULL) { + printf("ar2[%d] = \"%s\"\n", i, ar2[i]); + i++; + } + + printf("strdyn_explode2_chr(\"%s\", '%c') = ar1\n", TESTSTR1, TESTSEP1); + ar1 = strdyn_explode2_chr(TESTSTR1, TESTSEP1); + + puts("strdyn_free(ar1)"); + strdyn_free(ar1); + + printf("strdyn_explode_str(\"%s\", \"%s\") = ar1\n", TESTSTR1, TESTSEP2); + ar1 = strdyn_explode_str(TESTSTR1, TESTSEP2); + + for (i = 0; ar1[i] != NULL; i++) + printf("ar1[%d] = \"%s\"\n", i, ar1[i]); + + s = strdyn_implode2_chr(ar1, TESTSEP1); + printf("strdyn_implode2_chr(ar1, '%c') = \"%s\"\n", TESTSEP1, s); + + puts("free(s)"); + free(s); + + s = strdyn_implode2_str(ar1, TESTSEP2); + printf("strdyn_implode2_str(ar1, \"%s\") = \"%s\"\n", TESTSEP2, s); + + puts("free(s)"); + free(s); + + ar_join = strdyn_join(ar1, ar2); + ar_intersect = strdyn_intersect(ar1, ar2); + + i = 0; + while (ar_join[i] != NULL) { + printf("ar_join[%d] = \"%s\"\n", i, ar_join[i]); + i++; + } + + i = 0; + while (ar_intersect[i] != NULL) { + printf("ar_intersect[%d] = \"%s\"\n", i, ar_intersect[i]); + i++; + } + + puts("strdyn_free(ar1)"); + strdyn_free(ar1); + + puts("strdyn_free(ar2)"); + strdyn_free(ar2); + + puts("strdyn_free(ar_join)"); + strdyn_free(ar_join); + + puts("strdyn_free(ar_intersect)"); + strdyn_free(ar_intersect); + + + return 0; +} + +#endif + diff --git a/src/cfg/platon/str/strdyn.h b/src/cfg/platon/str/strdyn.h new file mode 100644 index 0000000000..d8370a9b7e --- /dev/null +++ b/src/cfg/platon/str/strdyn.h @@ -0,0 +1,77 @@ +#ifndef _PLATON_STR_STRDYN_H +#define _PLATON_STR_STRDYN_H + +/* + * TODO list: + * + * 1. Functions for removing from array. + * 2. Optimalizations (in strdyn_explode_ar() and similar). + */ + +#ifndef PLATON_FUNC +# define PLATON_FUNC(_name) _name +#endif +#ifndef PLATON_FUNC_STR +# define PLATON_FUNC_STR(_name) #_name +#endif + +#define strdyn_count(ar) PLATON_FUNC(strdyn_get_size)(ar) +#define strdyn_duplicate(ar) PLATON_FUNC(strdyn_create_ar)(ar) +#define strdyn_safe_duplicate(ar) PLATON_FUNC(strdyn_safe_create_ar)(ar) +#define strdyn_remove(ar, s) PLATON_FUNC(strdyn_remove_str)(ar, s) +#define strdyn_intersect(ar1, ar2) PLATON_FUNC(strdyn_conjunct)(ar1, ar2) +#define strdyn_join(ar1, ar2) PLATON_FUNC(strdyn_consolide)(ar1, ar2) +#define strdyn_union(ar1, ar2) PLATON_FUNC(strdyn_consolide)(ar1, ar2) +#define strdyn_explode(str, sep) PLATON_FUNC(strdyn_explode_str)(str, sep) +#define strdyn_explode2(str, sep) PLATON_FUNC(strdyn_explode2_str)(str, sep) +#define strdyn_implode(str, sep) PLATON_FUNC(strdyn_implode_str)(str, sep) +#define strdyn_implode2(str, sep) PLATON_FUNC(strdyn_implode2_str)(str, sep) +#define strdyn_cmp(ar, s) PLATON_FUNC(strdyn_compare)(ar, s) +#define strdyn_casecmp(ar, s) PLATON_FUNC(strdyn_casecompare)(ar, s) +#define strdyn_str(s, ar) PLATON_FUNC(strdyn_str2)(s, ar, NULL) + + +#ifdef __cplusplus +extern "C" { +#endif + + void PLATON_FUNC(strdyn_free)(char **ar); + void PLATON_FUNC(strdyn_safe_free)(char **ar); + int PLATON_FUNC(strdyn_get_size)(char **ar); + char **PLATON_FUNC(strdyn_create)(void); + char **PLATON_FUNC(strdyn_create_va)(char *s1, ...); + char **PLATON_FUNC(strdyn_create_ar)(char **ar); + char **PLATON_FUNC(strdyn_safe_create_ar)(char **ar); + char **PLATON_FUNC(strdyn_add)(char **ar, const char *s); + char **PLATON_FUNC(strdyn_add_va)(char **ar, ...); + char **PLATON_FUNC(strdyn_add_ar)(char **ar, char * const *s_ar); + char **PLATON_FUNC(strdyn_remove_idx)(char **ar, int idx); + char **PLATON_FUNC(strdyn_remove_str)(char **ar, char *s); + char **PLATON_FUNC(strdyn_remove_str_all)(char **ar, char *s); + char **PLATON_FUNC(strdyn_remove_empty)(char **ar); + char **PLATON_FUNC(strdyn_remove_all)(char **ar); + char **PLATON_FUNC(strdyn_explode_chr)(char *str, int sep); + char **PLATON_FUNC(strdyn_explode2_chr)(char *str, int sep); + char **PLATON_FUNC(strdyn_explode_str)(char *str, char *sep); + char **PLATON_FUNC(strdyn_explode2_str)(char *str, char *sep); + char **PLATON_FUNC(strdyn_explode_ar)(char *str, char **sep); + char **PLATON_FUNC(strdyn_explode2_ar)(char *str, char **sep); + char *PLATON_FUNC(strdyn_implode_chr)(char **ar, int sep); + char *PLATON_FUNC(strdyn_implode2_chr)(char **ar, int sep); + char *PLATON_FUNC(strdyn_implode_str)(char **ar, char *sep); + char *PLATON_FUNC(strdyn_implode2_str)(char **ar, char *str); + char **PLATON_FUNC(strdyn_conjunct)(char **ar1, char **ar2); + char **PLATON_FUNC(strdyn_consolide)(char **ar1, char **ar2); + int PLATON_FUNC(strdyn_search)(char **ar, char *s); + int PLATON_FUNC(strdyn_casesearch)(char **ar, char *s); + int PLATON_FUNC(strdyn_compare)(char **ar, char *s); + int PLATON_FUNC(strdyn_casecompare)(char **ar, char *s); + int PLATON_FUNC(strdyn_compare_all)(char **ar, char *s); + char *PLATON_FUNC(strdyn_str2)(char *s, char **ar, int *idx); + +#ifdef __cplusplus +} +#endif + +#endif /* _PLATON_STR_STRDYN_H */ + diff --git a/src/cfg/platon/str/strplus.c b/src/cfg/platon/str/strplus.c new file mode 100644 index 0000000000..ba9e14464c --- /dev/null +++ b/src/cfg/platon/str/strplus.c @@ -0,0 +1,436 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> + +#include <platon/str/strplus.h> +#include <platon/str/strctype.h> + + char * +PLATON_FUNC(strestr)(s1, s2) + const char *s1; + const char *s2; +{ + return strstr(s1,s2) == NULL ? NULL : strendstr(s1,s2); +} + +#if ! defined(SELF) && ! defined(SELFTEST) && ! defined(SELF_STRPLUS) + +/* + * Functions strtolower() and strtoupper(), used by function below, + * are defined in strctype.c so when we are building self-testing + * binary, skip this section. + */ + + char * +PLATON_FUNC(stristr)(s1, s2) + const char *s1; + const char *s2; +{ + char *a_s1, *a_s2; + register char *ret = NULL; + + a_s1 = strdup(s1); + a_s2 = strdup(s2); + + if (a_s1 != NULL && a_s2 != NULL) { + ret = strstr(PLATON_FUNC(strtolower)(a_s1), + PLATON_FUNC(strtolower)(a_s2)); + if (ret != NULL) + ret = (char *) s1 + (ret - a_s1); + } + + if (a_s2 != NULL) + free(a_s2); + + if (a_s1 != NULL) + free(a_s1); + + return ret; +} + +#endif + + char * +PLATON_FUNC(str_white_str)(str, substr, size) + char *str; + char *substr; + int *size; +{ +#if 0 + /* + * This is fastfix code substitution for str_white_str() function, + * because new wersion from 'Crasher' was not fully tested yet. + */ + + *size = strlen(substr); + return strstr(str, substr); + +#else + register int slen, plen, ssize; + register char *pptr, *sptr, *start; + + slen = strlen(str); + plen = strlen(substr); + + for (start = str, pptr = substr; slen >= plen; start++, slen--) { + + /* Find start of pattern in string. */ + while (*start != *substr) { + + if ((isspace(*start)) && (isspace(*substr))) + break; + + start++; + slen--; + /* If pattern longer than string. */ + if (slen < plen) + return NULL; + } + + ssize = 0; + sptr = start; + pptr = substr; + + while (1) { + +#ifdef DEBUG_STRPLUS /* if str_white_str() works properly, delete this */ + printf("comparing %d [%s] with %d [%s]\n", + *sptr, sptr, *pptr, pptr); +#endif + + if ((isspace(*sptr)) && (isspace(*pptr))) { + while (isspace(*sptr)) { + ++sptr; + + if (isspace(*pptr)) { + ++ssize; + ++pptr; + } + else + ++ssize; + } + } + else if (*sptr == *pptr) { + while (*sptr == *pptr && *sptr != '\0' && ! isspace(*sptr)) { + sptr++; + pptr++; + ssize++; + } + } + else { + break; + } + + /* If end of pattern then pattern was found. */ + if (*pptr == '\0') { + if (size != NULL) + *size = ssize; + return start; + } + } + } + + return NULL; +#endif +} + + + int +PLATON_FUNC(strcnt)(str, c) + const char *str; + const int c; +{ + register int i = 0; + + if (str != NULL) + while (*str != '\0') + if (*str++ == (char) c) + i++; + + return i; +} + + int +PLATON_FUNC(strcnt_str)(str, substr) + const char *str; + const char *substr; +{ + register char *s; + register int count; + + for (count = 0; ; count++) { + if ((s = strstr(str, substr)) == NULL) + break; + else + str += (s - str) + 1; + } + + return count; +} + + int +PLATON_FUNC(strcnt_sepstr)(str, substr) + const char *str; + const char *substr; +{ + register char *s; + register int count, substr_size; + + substr_size = strlen(substr); + + for (count = 0; ; count++) { + if ((s = strstr(str, substr)) == NULL) + break; + else + str += (s - str) + substr_size; + } + + return count; +} + + char * +PLATON_FUNC(strdel)(s) + char *s; +{ +#if 1 + return (char *) memmove(s, s + 1, strlen(s)); +#else + register int i; + + for (i = 0; s[i] != '\0'; i++) + s[i] = s[i + 1]; + + return s; +#endif +} + + char * +PLATON_FUNC(strrmlf)(s) + char *s; +{ + register char *p_lf; + + while ((p_lf = strchr(s, '\n')) != NULL) + PLATON_FUNC(strdel)(p_lf); + + return s; +} + + char * +PLATON_FUNC(strrmcr)(s) + char *s; +{ + register char *p_cr; + + while ((p_cr = strchr(s, '\r')) != NULL) + PLATON_FUNC(strdel)(p_cr); + + return s; +} + + char * +PLATON_FUNC(str_left_trim)(s) + char *s; +{ + register char *pos; + + for (pos = s; *pos != '\0' && isspace(*pos); pos++) ; + + if (pos > s) + memmove((void *) s, (void *) pos, strlen(pos) + 1); + + return s; +} + + char * +PLATON_FUNC(str_right_trim)(s) + char *s; +{ + register char *pos; + + for (pos = s + (strlen(s) - 1); pos >= s && isspace(*pos); pos--) ; + + *(pos + 1) = '\0'; + + return s; +} + + char * +PLATON_FUNC(str_trim_whitechars)(s) + char *s; +{ + register char *pos, *start; + + for (pos = s, start = NULL; ; pos++) { + if (isspace(*pos)) { + if (start == NULL) + start = pos; + } + else { + if (start != NULL) { + memmove(start + 1, pos, strlen(pos) + 1); + *start = ' '; + + pos = start + 1; + start = NULL; + } + } + + if (*pos == '\0') + break; + } + + return s; +} + + char * +PLATON_FUNC(strins)(str, ins) + char *str; + char *ins; +{ + register int ins_len = strlen(ins); + + memmove(str + ins_len, str, strlen(str) + 1); + strncpy(str, ins, ins_len); + + return str; +} + + char * +PLATON_FUNC(strrev)(str) + char *str; +{ + register int i, c, len = strlen(str); + + /* Code borrowed from PHP: Hypertext Preprocessor, http://www.php.net/ */ + for (i = 0; i < len - 1 - i; i++) { + c = str[i]; + str[i] = str[len - 1 - i]; + str[len - 1 - i] = c; + } + + return str; +} + + int +PLATON_FUNC(strrcmp)(s1, s2) + const char *s1; + const char *s2; +{ + register char *x1, *x2; + + x1 = strchr(s1,'\0'); + x2 = strchr(s2,'\0'); + + while (x1 > s1 && x2 > s2) { + x1--; + x2--; + if (strcmp(x1,x2)) + return strcmp(x1,x2); + } + + return strlen(s1) - strlen(s2); +} + +#if defined(SELF) || defined(SELFTEST) || defined(SELF_STRPLUS) || defined(SELF_STRPLUS2) + +#include <stdio.h> + +#define TESTSTR1 "___AAA_BBBB__C_DaDaD____" +#define TESTSEP1 '_' +#define TESTSEP2 "BB" + +#define TESTSTR2 " \t AAA\nBBBB__C D\taDa D \t \t" + + static void +strins_selftest(void) +{ + char long_str[80]; + +#define SEARCH_STR "56" +#define INSERT_STR "<-now-goes-56->" + + strcpy(long_str, "1234567890"); + printf(" long_str before: %s\n", long_str); + + printf(" Now we're searching '%s' and want to insert '%s' before it.\n", + SEARCH_STR, INSERT_STR); + + strins(strstr(long_str, SEARCH_STR), INSERT_STR); + printf(" long_str after: %s\n", long_str); + + return; +} + + int +main(argc, argv) + int argc; + char **argv; +{ + char *str2; + + puts("Entering str_white_str() selftest:"); + + if (argc > 2) { + int size; + + str2 = PLATON_FUNC(str_white_str)(argv[1], argv[2], &size); + /* str2 = str_white_str("telnet \t atlantis.sk 5678", "t a", &size); + */ + printf(" ptr = [%s], size = %d\n", str2, size); + + return 0; + } + + printf(" Usage: %s <string> <substring>\n\n", argv[0]); + + str2 = strdup(TESTSTR2); + + printf("strcnt(\"%s\", '%c') = %d\n", + TESTSTR1, TESTSEP1, + PLATON_FUNC(strcnt)(TESTSTR1, TESTSEP1)); + + printf("strcnt_str(\"%s\", \"%s\") = %d\n", + TESTSTR1, TESTSEP2, + PLATON_FUNC(strcnt_str)(TESTSTR1, TESTSEP2)); + + printf("strcnt_sepstr(\"%s\", \"%s\") = %d\n", + TESTSTR1, TESTSEP2, + PLATON_FUNC(strcnt_sepstr)(TESTSTR1, TESTSEP2)); + + printf("str_trim_whitechars(\"%s\") = \"%s\"\n", + TESTSTR2, + PLATON_FUNC(str_trim_whitechars)(str2)); + + printf("strdel(\"%s\") = ", str2); + printf("\"%s\"\n", PLATON_FUNC(strdel)(str2)); + + printf("strrev(\"%s\") = ", str2); + printf("\"%s\"\n", PLATON_FUNC(strrev)(str2)); + strrev(str2); /* Reversing back, just for sure */ + free(str2); + +#if ! defined(SELF) && ! defined(SELFTEST) && ! defined(SELF_STRPLUS) + { /* stristr() selftest */ + char *ptr = "Reply-To"; + char *search = "reply-to"; + char *output = stristr(ptr, search); + printf("stristr(\"%s\", \"%s\") = \"%s\"\n", ptr, search, output); + printf(" (\"%s\" == \"%s\") == %d\n", ptr, output, ptr == output); + } +#endif + + + puts("\nEntering strins_selftest():"); + strins_selftest(); + + return 0; +} + +#endif /* #if defined(SELF) || defined(SELFTEST) || defined(SELF_STRPLUS) || defined(SELF_STRPLUS2) */ + diff --git a/src/cfg/platon/str/strplus.h b/src/cfg/platon/str/strplus.h new file mode 100644 index 0000000000..f3c4b43e22 --- /dev/null +++ b/src/cfg/platon/str/strplus.h @@ -0,0 +1,273 @@ +/************************************************************************** + * * + * Advanced string locate, counting, removing, altering * + * and comparing functions * + * * + * Programmed by Ondrej Jombik <nepto@platon.sk> * + * Copyright (c) 1997-2000 Condy software inc. * + * Copyright (c) 2001-2004 Platon Software Development Group * + * All rights reserved. * + * * + * Updates: 16.4.2000, 8.11.2000, 5.10.2001, 21.10.2001, 5.12.2001 * + * 20.12.2001 - str_white_str() added (thanks to <rbarlik@yahoo.com>) * + * 4. 2.2002 - strins() added * + * 28. 2.2002 - str_white_str() bugfix * + * 24. 9.2003 - stristr() rewritten * + * * + **************************************************************************/ + +/** + * Advanced string locate, counting, removing, inserting + * and comparing functions + * + * @file platon/str/strplus.h + * @author Ondrej Jombik <nepto@platon.sk> + * @version \$Platon: libcfg+/src/platon/str/strplus.h,v 1.27 2004/01/12 06:03:09 nepto Exp $ + * @date 1997-2004 + */ + +#ifndef _PLATON_STR_STRPLUS_H +#define _PLATON_STR_STRPLUS_H + +#ifndef PLATON_FUNC +# define PLATON_FUNC(_name) _name +#endif +#ifndef PLATON_FUNC_STR +# define PLATON_FUNC_STR(_name) #_name +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @name Locate functions + */ + /**@{*/ + + /** + * Macro that locates end of substring + * + * @param __s1 where to search (haystack) + * @param __s2 what to search (needle) + * @return pointer to character after __s2 + * @warning use only if you are sure, that substring is located in string; + * otherwise use strestr() function + */ +#define strendstr(__s1,__s2) (strstr(__s1,__s2) + strlen(__s2)) + + /** + * Locates a end of substring + * + * @param s1 where to search (haystack) + * @param s2 what to search (needle) + * @return pointer to character after s2 or NULL if not found + */ + char *PLATON_FUNC(strestr)(const char *s1, const char *s2); + + /** + * Locates a substring case-insensitive + * + * @param s1 where to search (haystack) + * @param s2 what to search (needle) + * @return pointer to s2 in s1 or NULL if not found + */ + char *PLATON_FUNC(stristr)(const char *s1, const char *s2); + +#define strcasestr(__s1, __s2) stristr(__s1, __s2) /**< alias to stristr() */ + + /** + * Searches substr in str with special whitespaces handling + * + * @param str where to search (haystack) + * @param substr what to search (needle) + * @retval size size of matched patern if found, undefined if not found + * @return pointer to substr in str on NULL if not found + * @author Rastislav 'Crasher' Barlik <rbarlik@yahoo.com>\n + * (patched by: Ondrej Jombik <nepto@platon.sk> [28/2/2002]) + * + * This function works just like classical strstr() call, with following + * advanced feature. Every white char in substr can be substitued with one + * or more white chars in str. In size, if not NULL was passed, will be the + * length of matched patern. + */ + char *PLATON_FUNC(str_white_str)(char *str, char *substr, int *size); + + /* TODO: remove this (???) */ + /** alias to str_white_str() */ +#define strwhitestr(str, substr, size) str_white_str(str, substr, size) + + /** + * Function str_white_str() without usage of matched pattern size. + * + * This function works just like str_white_str(), but third return value + * parameter (pattern length) is unused. + */ +#define strwstr(str, substr) str_white_str(str, substr, NULL) + + /**@}*/ + /** + * @name Counting functions + */ + /**@{*/ + + /** + * Counts number of characters in string + * + * @param str input string + * @param c character to count + * @return number of c occurences in str + */ + int PLATON_FUNC(strcnt)(const char *str, const int c); + + /** + * Counts number of substrings in string + * + * @param str input string + * @param substr substring to count + * @return number of substr occurences in str + * + * Note that in this function strings may overlay. For separate strings + * counting use strcnt_sepstr() function. + */ + int PLATON_FUNC(strcnt_str)(const char *str, const char *substr); + + /** + * Count number of separate substrings in string + * + * @param str input string + * @param substr substring to count + * @return number of separate substr occurences in str + * + * Note that in this function will be only not overlayed strings counted. + * For counting overlayed strings use strcnt_str() function. Also note, + * that counting is performed from beginning of string. Result count may, + * but MUST NOT be the highest number of separate substr substrings in str. + */ + int PLATON_FUNC(strcnt_sepstr)(const char *str, const char *substr); + + /**@}*/ + /** + * @name Removing functions + */ + /**@{*/ + + /** + * Deletes a one character + * + * @param s where to delete one character + * @return modified string + */ + char *PLATON_FUNC(strdel)(char *s); + + /** + * Removes all occurences of LF (Line Feed) + * + * @param s string where to remove all LF (\\n) characters + * @return modified string + */ + char *PLATON_FUNC(strrmlf)(char *s); + + /** + * Removes all occurences of CR (Carriage Return) + * + * @param s string where to remove all CR (\r) characters + * @return modified string + */ + char *PLATON_FUNC(strrmcr)(char *s); + + /** alias that removes all occurences of LF and CR characters */ +#define strrmeol(__s) strrmcr(strrmlf(__s)) +#define strrmcrlf(__s) strrmeol(__s) /**< alias to strrmeol() */ +#define strrmlfcr(__s) strrmeol(__s) /**< alias to strrmeol() */ + + /** + * Removes white characters from the beginning of string + * + * @param s string + * @param modified string + */ + char *PLATON_FUNC(str_left_trim)(char *s); + + /** + * Removes white characters from the end of string + * + * @param s string + * @param modified string + */ + char *PLATON_FUNC(str_right_trim)(char *s); + +#define ltrim(s) PLATON_FUNC(str_left_trim)(s) /**< alias to str_left_trim() */ +#define rtrim(s) PLATON_FUNC(str_right_trim)(s)/**< alias to str_right_trim()*/ + + /** + * Removes white characters from beginning and end of string + * + * @param s string + * @return modified string + */ +#define trim(s) rtrim(ltrim(s)) + +#define strtrim(s) trim(s) /**< alias to trim() */ +#define str_trim(s) trim(s) /**< alias to trim() */ + + /** + * Substitute every group of whitespaces for one space + * + * @param s string + * @return modified string + */ + char *PLATON_FUNC(str_trim_whitechars)(char *s); + + /**@}*/ + /** + * @name Altering functions + */ + /**@{*/ + + /** + * Inserts string into string + * + * @param str where to insert + * @param ins what to insert + * @return modified string + * + * This function inserts string ins at position str. Note that there MUST + * be enough memory allocated in str to avoid memory ovelaping after str. + */ + char *PLATON_FUNC(strins)(char *str, char *ins); + + /** + * Reverse string + * + * @param str where to insert + * @return reversed string + * + * This function reverses passed string. + */ + char *PLATON_FUNC(strrev)(char *str); + + /**@}*/ + /** + * @name Comparing functions + */ + /**@{*/ + + /** + * Compares two string in reverse order + * + * @param s1 first string to compare + * @param s2 second string to compare + * @return 0 if strings are indetical, strcmp() difference of the shortest + * different substrings otherwise + */ + int PLATON_FUNC(strrcmp)(const char *s1, const char *s2); + + /**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef _PLATON_STR_STRPLUS_H */ + diff --git a/src/cfg/props.c b/src/cfg/props.c new file mode 100644 index 0000000000..ff6437a8f5 --- /dev/null +++ b/src/cfg/props.c @@ -0,0 +1,625 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * props.c - context properties manipulation + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/props.c,v 1.34 2004/01/12 06:03:09 nepto Exp $ */ + +/* Includes {{{ */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdarg.h> + +#include <platon/str/strdyn.h> +#include "cfg+.h" +/* }}} */ + +/* Default properties {{{ */ +char *cfg_default_properties[CFG_N_PROPS][4] = { + /* CFG_LINE_STOP_STRING */ { NULL, NULL, NULL, NULL }, + /* CFG_LINE_SHORT_OPTION_PREFIX */ { "-", NULL, NULL, NULL }, + /* CFG_LINE_LONG_OPTION_PREFIX */ { "--", NULL, NULL, NULL }, + /* CFG_LINE_OPTION_ARG_SEPARATOR */ { "=", NULL, NULL, NULL }, + /* CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR */ { ",", ";", NULL, NULL }, + /* CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR */ { NULL, NULL, NULL, NULL }, + /* CFG_LINE_QUOTE_PREFIX */ { NULL, NULL, NULL, NULL }, + /* CFG_LINE_QUOTE_POSTFIX */ { NULL, NULL, NULL, NULL }, + /* CFG_FILE_STOP_PREFIX */ { NULL, NULL, NULL, NULL }, + /* CFG_FILE_COMMENT_PREFIX */ { "#", ";", NULL, NULL }, + /* CFG_FILE_MULTI_LINE_POSTFIX */ { "\\", NULL, NULL, NULL }, + /* CFG_FILE_OPTION_ARG_SEPARATOR */ { "=", NULL, NULL, NULL }, + /* CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR */ { ",", ";", " ", NULL }, + /* CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR */ { " ", NULL, NULL, NULL }, + /* CFG_FILE_QUOTE_PREFIX */ { "\"", "'", NULL, NULL }, + /* CFG_FILE_QUOTE_POSTFIX */ { "\"", "'", NULL, NULL }, + }; /* }}} */ + +/* + * Static functions for strdyn manipulation + */ + + static int +strdyn_array_clear(where) + char ***where; +{ /* {{{ */ + +#if 0 + if (*where != NULL) +#endif + *where = PLATON_FUNC(strdyn_remove_all)(*where); + + return *where != NULL; +} /* }}} */ + + static int +strdyn_array_add(where, str) + char ***where; + char *str; +{ /* {{{ */ + +#if 0 + if (*where == NULL) + *where = strdyn_create(); +#endif + + *where = PLATON_FUNC(strdyn_add)(*where, str); + + return *where != NULL; +} /* }}} */ + + static int +strdyn_array_remove(where, str) + char ***where; + char *str; +{ /* {{{ */ + +#if 0 + if (*where != NULL) +#endif + *where = PLATON_FUNC(strdyn_remove_str_all)(*where, str); + + return *where != NULL; +} /* }}} */ + + +/* + * Functions for context flags manipulation. + */ + + void +cfg_set_context_flag(con, flag) + const CFG_CONTEXT con; + int flag; +{ /* {{{ */ + con->flags |= flag; +} /* }}} */ + + void +cfg_clear_context_flag(con, flag) + const CFG_CONTEXT con; + int flag; +{ /* {{{ */ + con->flags &= ~flag; +} /* }}} */ + + int +cfg_get_context_flag(con, flag) + const CFG_CONTEXT con; + int flag; +{ /* {{{ */ + return con->flags & flag; +} /* }}} */ + + + void +cfg_set_context_flags(con, flags) + const CFG_CONTEXT con; + int flags; +{ /* {{{ */ + con->flags = flags; + con->cur_idx_tmp = con->flags & CFG_PROCESS_FIRST ? 0 : 1; +} /* }}} */ + + int +cfg_get_context_flags(con) + const CFG_CONTEXT con; +{ /* {{{ */ + return con->flags; +} /* }}} */ + +/* + * Macros + */ + +#define cfg_normal_property_type(type) ((type) >= 0 && (type) < CFG_N_PROPS) +#define cfg_virtual_property_type(type) ((type) > CFG_N_PROPS) + +/* + * Clear functions + */ + + int +cfg_clear_property(con, type) + const CFG_CONTEXT con; + enum cfg_property_type type; +{ /* {{{ */ + if (cfg_normal_property_type(type)) { + return strdyn_array_clear(&(con->prop[type])); + } + else if (cfg_virtual_property_type(type)) { + register int ret = 1; + switch (type) { + default: /* unknown special property; do nothing */ + ret = 0; + break; + case CFG_QUOTE: + ret &= cfg_clear_property(con, CFG_LINE_QUOTE); + ret &= cfg_clear_property(con, CFG_FILE_QUOTE); + break; + case CFG_LINE_QUOTE: + ret &= cfg_clear_property(con, CFG_LINE_QUOTE_PREFIX); + ret &= cfg_clear_property(con, CFG_LINE_QUOTE_POSTFIX); + break; + case CFG_FILE_QUOTE: + ret &= cfg_clear_property(con, CFG_FILE_QUOTE_PREFIX); + ret &= cfg_clear_property(con, CFG_FILE_QUOTE_POSTFIX); + break; + case CFG_QUOTE_PREFIX: + ret &= cfg_clear_property(con, CFG_LINE_QUOTE_PREFIX); + ret &= cfg_clear_property(con, CFG_FILE_QUOTE_PREFIX); + break; + case CFG_QUOTE_POSTFIX: + ret &= cfg_clear_property(con, CFG_LINE_QUOTE_POSTFIX); + ret &= cfg_clear_property(con, CFG_FILE_QUOTE_POSTFIX); + break; + case CFG_MULTI_VALS_SEPARATOR: + ret &= cfg_clear_property(con, CFG_LINE_MULTI_VALS_SEPARATOR); + ret &= cfg_clear_property(con, CFG_FILE_MULTI_VALS_SEPARATOR); + break; + case CFG_LINE_MULTI_VALS_SEPARATOR: + ret &= cfg_clear_property(con, + CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR); + ret &= cfg_clear_property(con, + CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR); + break; + case CFG_FILE_MULTI_VALS_SEPARATOR: + ret &= cfg_clear_property(con, + CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR); + ret &= cfg_clear_property(con, + CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR); + break; + case CFG_NORMAL_MULTI_VALS_SEPARATOR: + ret &= cfg_clear_property(con, + CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR); + ret &= cfg_clear_property(con, + CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR); + break; + case CFG_LEFTOVER_MULTI_VALS_SEPARATOR: + ret &= cfg_clear_property(con, + CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR); + ret &= cfg_clear_property(con, + CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR); + break; + case CFG_OPTION_ARG_SEPARATOR: + ret &= cfg_clear_property(con, CFG_LINE_OPTION_ARG_SEPARATOR); + ret &= cfg_clear_property(con, CFG_FILE_OPTION_ARG_SEPARATOR); + break; + } + + return ret; + } + + return 0; /* failure */ +} /* }}} */ + +int +cfg_clear_properties( + const CFG_CONTEXT con, + enum cfg_property_type type, ...) +{ /* {{{ */ + va_list ap; + enum cfg_property_type tmp_type; + int ret = 1; + + /* initialization */ + tmp_type = type; + va_start(ap, type); + + /* argument list must be termited with typeN = CFG_EOT */ + while (tmp_type != CFG_EOT) { + ret &= cfg_clear_property(con, tmp_type); + if (!ret) + break; + tmp_type = va_arg(ap, enum cfg_property_type); + } + + /* cleanup */ + va_end(ap); + + return ret; +} /* }}} */ + +/* + * Add functions + */ + + int +cfg_add_property(con, type, str) + const CFG_CONTEXT con; + enum cfg_property_type type; + char *str; +{ /* {{{ */ + + /* TODO: + remove cfg_add_property_old() calls from here, + substitute it by new function cfg_add_properties() */ + + if (cfg_normal_property_type(type)) { + return strdyn_array_add(&(con->prop[type]), str); + } + else if (cfg_virtual_property_type(type)) { + register int ret = 1; + switch (type) { + default: /* unknown special property; do nothing */ + ret = 0; + break; + case CFG_QUOTE: + ret &= cfg_add_property(con, CFG_LINE_QUOTE, str); + ret &= cfg_add_property(con, CFG_FILE_QUOTE, str); + break; + case CFG_LINE_QUOTE: + ret &= cfg_add_property(con, CFG_LINE_QUOTE_PREFIX, str); + ret &= cfg_add_property(con, CFG_LINE_QUOTE_POSTFIX, str); + break; + case CFG_FILE_QUOTE: + ret &= cfg_add_property(con, CFG_FILE_QUOTE_PREFIX, str); + ret &= cfg_add_property(con, CFG_FILE_QUOTE_POSTFIX, str); + break; + case CFG_QUOTE_PREFIX: + ret &= cfg_add_property(con, CFG_LINE_QUOTE_PREFIX, str); + ret &= cfg_add_property(con, CFG_FILE_QUOTE_PREFIX, str); + break; + case CFG_QUOTE_POSTFIX: + ret &= cfg_add_property(con, CFG_LINE_QUOTE_POSTFIX, str); + ret &= cfg_add_property(con, CFG_FILE_QUOTE_POSTFIX, str); + break; + case CFG_MULTI_VALS_SEPARATOR: + ret &= cfg_add_property(con, + CFG_LINE_MULTI_VALS_SEPARATOR, str); + ret &= cfg_add_property(con, + CFG_FILE_MULTI_VALS_SEPARATOR, str); + break; + case CFG_LINE_MULTI_VALS_SEPARATOR: + ret &= cfg_add_property(con, + CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR, str); + ret &= cfg_add_property(con, + CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + break; + case CFG_FILE_MULTI_VALS_SEPARATOR: + ret &= cfg_add_property(con, + CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR, str); + ret &= cfg_add_property(con, + CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + break; + case CFG_NORMAL_MULTI_VALS_SEPARATOR: + ret &= cfg_add_property(con, + CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR, str); + ret &= cfg_add_property(con, + CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR, str); + break; + case CFG_LEFTOVER_MULTI_VALS_SEPARATOR: + ret &= cfg_add_property(con, + CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + ret &= cfg_add_property(con, + CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + break; + case CFG_OPTION_ARG_SEPARATOR: + ret &= cfg_add_property(con, + CFG_LINE_OPTION_ARG_SEPARATOR, str); + ret &= cfg_add_property(con, + CFG_FILE_OPTION_ARG_SEPARATOR, str); + break; + } + + return ret; + } + + return 0; /* failure */ +} /* }}} */ + +int +cfg_add_properties( + const CFG_CONTEXT con, + enum cfg_property_type type, + char *str, ...) +{ /* {{{ */ + va_list ap; + enum cfg_property_type tmp_type; + char * tmp_str; + int ret = 1; + + /* initialization */ + tmp_type = type; + tmp_str = str; + va_start(ap, str); + + /* argument list must be termited with typeN = CFG_EOT or + * str = NULL + */ + while (tmp_type != CFG_EOT && tmp_str != NULL) { + ret &= cfg_add_property(con, tmp_type, tmp_str); + if (!ret) + break; + tmp_type = va_arg(ap, enum cfg_property_type); + if (tmp_type == CFG_EOT) /* if typeN == CFG_EOT, strN may be not specified! */ + break; + tmp_str = va_arg(ap, char *); + } + + /* cleanup */ + va_end(ap); + + return ret; +} /* }}} */ + +int +cfg_add_properties_str( + const CFG_CONTEXT con, + char *str, + enum cfg_property_type type, ...) +{ /* {{{ */ + va_list ap; + enum cfg_property_type tmp_type; + int ret = 1; + + /* initialization */ + tmp_type = type; + va_start(ap, type); + + /* argument list must be termited with typeN = CFG_EOT or */ + if (str != NULL) + while (tmp_type != CFG_EOT) { + ret &= cfg_add_property(con, tmp_type, str); + if (!ret) + break; + tmp_type = va_arg(ap, enum cfg_property_type); + } + + /* cleanup */ + va_end(ap); + + return ret; +} /* }}} */ + +int +cfg_add_properties_type( + const CFG_CONTEXT con, + enum cfg_property_type type, + char *str, ...) +{ /* {{{ */ + va_list ap; + char * tmp_str; + int ret = 1; + + /* initialization */ + tmp_str = str; + va_start(ap, str); + + /* argument list must be termited with str = NULL */ + if (type != CFG_EOT) + while (tmp_str != NULL) { + ret &= cfg_add_property(con, type, tmp_str); + if (!ret) + break; + tmp_str = va_arg(ap, char *); + } + + /* cleanup */ + va_end(ap); + + return ret; +} /* }}} */ + +/* + * Remove functions + */ + + int +cfg_remove_property(con, type, str) + const CFG_CONTEXT con; + enum cfg_property_type type; + char *str; +{ /* {{{ */ + + /* TODO: + remove cfg_remove_property_old() calls from here, + substitute it by new function cfg_remove_properties() */ + + if (cfg_normal_property_type(type)) { + return strdyn_array_remove(&(con->prop[type]), str); + } + else if (cfg_virtual_property_type(type)) { + register int ret = 1; + switch (type) { + default: /* unknown special property; do nothing */ + ret = 0; + break; + case CFG_QUOTE: + ret &= cfg_remove_property(con, CFG_LINE_QUOTE, str); + ret &= cfg_remove_property(con, CFG_FILE_QUOTE, str); + break; + case CFG_LINE_QUOTE: + ret &= cfg_remove_property(con, CFG_LINE_QUOTE_PREFIX, str); + ret &= cfg_remove_property(con, CFG_LINE_QUOTE_POSTFIX, str); + break; + case CFG_FILE_QUOTE: + ret &= cfg_remove_property(con, CFG_FILE_QUOTE_PREFIX, str); + ret &= cfg_remove_property(con, CFG_FILE_QUOTE_POSTFIX, str); + break; + case CFG_QUOTE_PREFIX: + ret &= cfg_remove_property(con, CFG_LINE_QUOTE_PREFIX, str); + ret &= cfg_remove_property(con, CFG_FILE_QUOTE_PREFIX, str); + break; + case CFG_QUOTE_POSTFIX: + ret &= cfg_remove_property(con, CFG_LINE_QUOTE_POSTFIX, str); + ret &= cfg_remove_property(con, CFG_FILE_QUOTE_POSTFIX, str); + break; + case CFG_MULTI_VALS_SEPARATOR: + ret &= cfg_remove_property(con, + CFG_LINE_MULTI_VALS_SEPARATOR, str); + ret &= cfg_remove_property(con, + CFG_FILE_MULTI_VALS_SEPARATOR, str); + break; + case CFG_LINE_MULTI_VALS_SEPARATOR: + ret &= cfg_remove_property(con, + CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR, str); + ret &= cfg_remove_property(con, + CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + break; + case CFG_FILE_MULTI_VALS_SEPARATOR: + ret &= cfg_remove_property(con, + CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR, str); + ret &= cfg_remove_property(con, + CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + break; + case CFG_NORMAL_MULTI_VALS_SEPARATOR: + ret &= cfg_remove_property(con, + CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR, str); + ret &= cfg_remove_property(con, + CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR, str); + break; + case CFG_LEFTOVER_MULTI_VALS_SEPARATOR: + ret &= cfg_remove_property(con, + CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + ret &= cfg_remove_property(con, + CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR, str); + break; + case CFG_OPTION_ARG_SEPARATOR: + ret &= cfg_remove_property(con, + CFG_LINE_OPTION_ARG_SEPARATOR, str); + ret &= cfg_remove_property(con, + CFG_FILE_OPTION_ARG_SEPARATOR, str); + break; + } + + return ret; + } + + return 0; /* failure */ +} /* }}} */ + +int +cfg_remove_properties( /* code same like cfg_add_properties() */ + const CFG_CONTEXT con, + enum cfg_property_type type, + char *str, ...) +{ /* {{{ */ + va_list ap; + enum cfg_property_type tmp_type; + char * tmp_str; + int ret = 1; + + /* initialization */ + tmp_type = type; + tmp_str = str; + va_start(ap, str); + + /* argument list must be termited with typeN = CFG_EOT or + * str = NULL + */ + while (tmp_type != CFG_EOT && tmp_str != NULL) { + ret &= cfg_remove_property(con, tmp_type, tmp_str); + if (!ret) + break; + tmp_type = va_arg(ap, enum cfg_property_type); + if (tmp_type == CFG_EOT) /* if typeN == CFG_EOT, strN may be not specified! */ + break; + tmp_str = va_arg(ap, char *); + } + + /* cleanup */ + va_end(ap); + + return ret; +} /* }}} */ + +int +cfg_remove_properties_str( + const CFG_CONTEXT con, + char *str, + enum cfg_property_type type, ...) +{ /* {{{ */ + va_list ap; + enum cfg_property_type tmp_type; + int ret = 1; + + /* initialization */ + tmp_type = type; + va_start(ap, type); + + /* argument list must be termited with typeN = CFG_EOT or */ + if (str != NULL) + while (tmp_type != CFG_EOT) { + ret &= cfg_remove_property(con, tmp_type, str); + if (!ret) + break; + tmp_type = va_arg(ap, enum cfg_property_type); + } + + /* cleanup */ + va_end(ap); + + return ret; +} /* }}} */ + +int +cfg_remove_properties_type( + const CFG_CONTEXT con, + enum cfg_property_type type, + char *str, ...) +{ /* {{{ */ + va_list ap; + char * tmp_str; + int ret = 1; + + /* initialization */ + tmp_str = str; + va_start(ap, str); + + /* argument list must be termited with str = NULL */ + if (type != CFG_EOT) + while (tmp_str != NULL) { + ret &= cfg_remove_property(con, type, tmp_str); + if (!ret) + break; + tmp_str = va_arg(ap, char *); + } + + /* cleanup */ + va_end(ap); + + return ret; +} /* }}} */ + + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/shared.c b/src/cfg/shared.c new file mode 100644 index 0000000000..1219f47059 --- /dev/null +++ b/src/cfg/shared.c @@ -0,0 +1,977 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * shared.c - shared stuff for command line and config file + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/shared.c,v 1.36 2004/01/12 06:03:09 nepto Exp $ */ + +/* Includes {{{ */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if STDC_HEADERS +# include <stdlib.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_MATH_H +# include <math.h> +#endif +#if HAVE_LIMITS_H +# include <limits.h> +#endif +#if HAVE_FLOAT_H +# include <float.h> +#endif +#if HAVE_CTYPE_H +# include <ctype.h> +#endif +#if HAVE_ERRNO_H +# include <errno.h> +#endif + +#include <platon/str/strplus.h> +#include <platon/str/strdyn.h> + +#include "cfg+.h" +/* }}} */ + +/* Static function declarations {{{ */ +static int search_cur_opt_idx(const CFG_CONTEXT con); +static int add_to_used_opt_idx(const CFG_CONTEXT con, int opt_idx); +static int store_multi_arg( + const int type, + const char **multi_arg, + void ***ar); +static int store_single_arg( + const int type, + const char *arg, + const void *where); +static int split_multi_arg( + char *arg, + char ***ar, + char **quote_prefix_ar, + char **quote_postfix_ar, + char **separator_ar); +static int unquote_single_arg( + char *arg, + char **quote_prefix_ar, + char **quote_postfix_ar); +/* }}} */ + +/* + * EXTERN PLATON_FUNCS + */ + + void +__cfg_free_currents(con) + const CFG_CONTEXT con; +{ /* {{{ */ + if (con->cur_opt != NULL) + free(con->cur_opt); + if (con->cur_arg != NULL) + free(con->cur_arg); + + con->cur_opt = con->cur_arg = NULL; + con->cur_opt_type = CFG_NONE_OPTION; +} /* }}} */ + + int +__cfg_process_currents(con, ret_val, arg_used) + const CFG_CONTEXT con; + int *ret_val; + int *arg_used; +{ /* {{{ */ + register int ret = 0; + register int opt_idx; + register int opt_type, opt_data_type, opt_f_multi, opt_f_multi_sep; + register char **quote_prefix_ar, **quote_postfix_ar, **separator_ar; + + *ret_val = 0; + if (arg_used != NULL) + *arg_used = 0; + + opt_idx = search_cur_opt_idx(con); + +#if defined(DEBUG) && DEBUG + fprintf(stderr, "%s|%ld|%s|%s|%s|%d|flags=%x[", + con->type == CFG_LINE ? "cmdline" : "cfgfile", + con->type == CFG_LINE ? con->cur_idx : 0, + con->type == CFG_LINE ? con->argv[con->cur_idx] : "N/A", + con->cur_opt == NULL ? "[NULL]" : con->cur_opt, + con->cur_arg == NULL ? "[NULL]" : con->cur_arg, + opt_idx, con->cur_opt_type); + + if (con->cur_opt_type & CFG_LONG_OPTION) + fputs("-LONG-", stderr); + if (con->cur_opt_type & CFG_SHORT_OPTION) + fputs("-SHORT-", stderr); + if (con->cur_opt_type & CFG_SHORT_OPTIONS) + fputs("-SHORTS-", stderr); + if (con->cur_opt_type & CFG_LONG_SEPINIT) + fputs("-SEPINIT-", stderr); + + fputs("]\n", stderr); +#endif + + if (opt_idx < 0) + return CFG_ERROR_UNKNOWN; /* unknown option reached */ + + if (! (con->flags & CFG_IGNORE_MULTI) + && ! (con->options[opt_idx].type & CFG_MULTI)) { + ret = add_to_used_opt_idx(con, opt_idx); + + if (ret < 0) + return CFG_ERROR_NOMEM; + else if (ret > 0) + return CFG_ERROR_MULTI; + } + + /* Setting others opt_XXX constants according to *opt_idx. */ + /* opt_data_type - option data type, opt_f_XXX - option flags */ + opt_type = con->options[opt_idx].type; + opt_data_type = opt_type & CFG_DATA_TYPE_MASK; + opt_f_multi = opt_type & CFG_MULTI; + opt_f_multi_sep = opt_type & (CFG_MULTI_SEPARATED & ~CFG_MULTI); + + if (con->type == CFG_LINE) { + quote_prefix_ar = con->prop[CFG_LINE_QUOTE_PREFIX]; + quote_postfix_ar = con->prop[CFG_LINE_QUOTE_POSTFIX]; + separator_ar = (opt_type & CFG_LEFTOVER_ARGS) + ? con->prop[CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR] + : con->prop[CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR]; + } + else { + quote_prefix_ar = con->prop[CFG_FILE_QUOTE_PREFIX]; + quote_postfix_ar = con->prop[CFG_FILE_QUOTE_POSTFIX]; + separator_ar = (opt_type & CFG_LEFTOVER_ARGS) + ? con->prop[CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR] + : con->prop[CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR]; + } + + switch (opt_data_type) { + default: + return CFG_ERROR_INTERNAL; + break; + + /* Boolean data type */ + + case CFG_BOOLEAN: + if (con->cur_opt_type & CFG_LONG_SEPINIT + && con->cur_arg != NULL) + return CFG_ERROR_NOTALLOWEDARG; + + if (con->options[opt_idx].value != NULL) + (*((int *) con->options[opt_idx].value))++; + break; + + /* Numeric (int, long, float and double) data types */ + + case CFG_INT: + case CFG_UINT: + case CFG_LONG: + case CFG_ULONG: + case CFG_FLOAT: + case CFG_DOUBLE: + + if (con->cur_arg == NULL) + return CFG_ERROR_NOARG; + + if (opt_f_multi) { + char **add; + char *static_add[2] = {NULL, NULL}; + + if (opt_f_multi_sep) { + + ret = split_multi_arg(con->cur_arg, &add, + quote_prefix_ar, quote_postfix_ar, separator_ar); + + if (ret != CFG_OK) { + PLATON_FUNC(strdyn_safe_free)(add); + return ret; + } + } + else { + add = static_add; + add[0] = con->cur_arg; + } + + ret = store_multi_arg(opt_data_type, + (const char **) add, + con->options[opt_idx].value); + + if (add != static_add) + PLATON_FUNC(strdyn_free)((char **) add); + } + else { + ret = unquote_single_arg(con->cur_arg, + quote_prefix_ar, quote_postfix_ar); + + if (ret != CFG_OK) + return ret; + + ret = store_single_arg(opt_data_type, con->cur_arg, + con->options[opt_idx].value); + } + + if (ret != CFG_OK) + return ret; + + if (arg_used != NULL) + *arg_used = 1; + break; + + /* String data type */ + + case CFG_STRING: + + if (con->cur_arg == NULL) + return CFG_ERROR_NOARG; + + if (con->options[opt_idx].value != NULL) { + if (opt_f_multi) { + register char ***p; + p = (char ***) con->options[opt_idx].value; + + if (opt_f_multi_sep) { + char **ar; + ret = split_multi_arg(con->cur_arg, &ar, + quote_prefix_ar, quote_postfix_ar, + separator_ar); + + if (ret != CFG_OK) { + PLATON_FUNC(strdyn_safe_free)(ar); + return ret; + } + + if ((*p = PLATON_FUNC(strdyn_add_ar)(*p, ar)) == NULL) + return CFG_ERROR_NOMEM; + + PLATON_FUNC(strdyn_free)(ar); + } + else { + ret = unquote_single_arg(con->cur_arg, + quote_prefix_ar, quote_postfix_ar); + + if (ret != CFG_OK) + return ret; + + if ((*p = PLATON_FUNC(strdyn_add)(*p, con->cur_arg)) == NULL) + return CFG_ERROR_NOMEM; + } + } + else { + ret = unquote_single_arg(con->cur_arg, + quote_prefix_ar, quote_postfix_ar); + + if (ret != CFG_OK) + return ret; + + *((char **) con->options[opt_idx].value) = + strdup(con->cur_arg); + } + } + + if (arg_used != NULL) + *arg_used = 1; + break; + } + + *ret_val = con->options[opt_idx].val; + + return CFG_OK; +} /* }}} */ + + int +__cfg_cmdline_set_currents(con) + const CFG_CONTEXT con; +{ /* {{{ */ + register int i, size; + register char *s, *s_sep, *s_tmp; + register char *ptr; + + size = -1; /* size of matched prefix (0 is also valid) */ + s = con->argv[con->cur_idx]; /* string to scan */ + + /* Explicit `size_t' to `int' typecastings are required here near strlen() + calls, else strlen("") == 0 will be considered as smaller than -1. */ + + for (i = 0; (ptr = con->prop[CFG_LINE_SHORT_OPTION_PREFIX][i]) != NULL; i++) + if ((int) strlen(ptr) > size && strstr(s, ptr) == s) { + size = strlen(ptr); + con->cur_opt_type = CFG_SHORT_OPTION; + } + + for (i = 0; (ptr = con->prop[CFG_LINE_LONG_OPTION_PREFIX][i]) != NULL; i++) + if ((int) strlen(ptr) > size && strstr(s, ptr) == s) { + size = strlen(ptr); + con->cur_opt_type = CFG_LONG_OPTION; + } + + s_sep = NULL; + + switch (con->cur_opt_type) { + default: + case CFG_NONE_OPTION: /* None option prefix */ + break; + + case CFG_SHORT_OPTION: /* Short option prefix */ + s += size; + s_sep = strlen(s) > 0 ? s + 1 : s; + + if (strlen(s_sep) > 0) { + con->cur_opt_type += CFG_SHORT_OPTIONS; + + if ((con->cur_arg = strdup(s_sep)) == NULL) + return CFG_ERROR_NOMEM; + } + else { + if (con->argv[con->cur_idx + 1] != NULL) { + con->cur_arg = strdup(con->argv[con->cur_idx + 1]); + if (con->cur_arg == NULL) + return CFG_ERROR_NOMEM; + } + else + con->cur_arg = NULL; + } + break; + + case CFG_LONG_OPTION: /* Long option prefix */ + s += size; + size = 0; + + for (i = 0; (ptr = con->prop[CFG_LINE_OPTION_ARG_SEPARATOR][i]) + != NULL; i++) + if ((s_tmp = strstr(s, ptr)) != NULL) + if (s_sep == NULL || s_tmp < s_sep + || (s_tmp == s_sep && strlen(ptr) > size)) { + s_sep = s_tmp; + size = strlen(ptr); + } + + if (s_sep == NULL) { + if (con->argv[con->cur_idx + 1] != NULL) { + con->cur_arg = strdup(con->argv[con->cur_idx + 1]); + if (con->cur_arg == NULL) + return CFG_ERROR_NOMEM; + } + else + con->cur_arg = NULL; + } + else { + con->cur_opt_type += CFG_LONG_SEPINIT; + if ((con->cur_arg = strdup(s_sep + size)) == NULL) + return CFG_ERROR_NOMEM; + } + } + + if (s_sep == NULL) + s_sep = s + strlen(s); + + con->cur_opt = (char *) malloc((s_sep - s + 1) * sizeof(char)); + if (con->cur_opt == NULL) + return CFG_ERROR_NOMEM; + + strncpy(con->cur_opt, s, s_sep - s); + con->cur_opt[s_sep - s] = '\0'; + + if (con->cur_opt_type == CFG_NONE_OPTION) { + register char *tmp_str; + tmp_str = con->cur_opt; + con->cur_opt = con->cur_arg; + con->cur_arg = tmp_str; + } + + return CFG_OK; +} /* }}} */ + + int +__cfg_cfgfile_set_currents(con, buf) + const CFG_CONTEXT con; + char *buf; +{ /* {{{ */ + register char **pos; + register char *s_sep, *s_tmp; + register int size; + + s_sep = NULL; + size = 0; + for (pos = con->prop[CFG_FILE_OPTION_ARG_SEPARATOR]; + pos != NULL && *pos != NULL; pos++) { + + if ((s_tmp = strstr(buf, *pos)) != NULL) + if (s_sep == NULL || s_tmp < s_sep + || (s_tmp == s_sep && strlen(*pos) > size)) { + s_sep = s_tmp; + size = strlen(*pos); + } + } + + if (s_sep == NULL) { + con->cur_arg = NULL; + + con->cur_opt = strdup(buf); + if (con->cur_opt == NULL) + return CFG_ERROR_NOMEM; + } + else { + con->cur_opt = (char *) malloc((s_sep - buf + 1) * sizeof(char)); + if (con->cur_opt == NULL) + return CFG_ERROR_NOMEM; + + strncpy(con->cur_opt, buf, s_sep - buf); + con->cur_opt[s_sep - buf] = '\0'; + + if ((con->cur_arg = strdup(s_sep + size)) == NULL) + return CFG_ERROR_NOMEM; + + PLATON_FUNC(str_right_trim)(con->cur_opt); + PLATON_FUNC(str_left_trim)(con->cur_arg); + } + + return CFG_OK; +} /* }}} */ + +/* + * STATIC PLATON_FUNCS + */ + +/* + * search_cur_opt_idx() + * + * Function searches con->options for con->cur_opt. + * Returns index on success or -1 if not found. + */ + + static int +search_cur_opt_idx(con) + const CFG_CONTEXT con; +{ /* {{{ */ + register int i; + + for (i = 0; con->options[i].cmdline_long_name != NULL + || con->options[i].cmdline_short_name != '\0' + || con->options[i].cfgfile_name != NULL + || con->options[i].type != CFG_END + || con->options[i].value != NULL + || con->options[i].val != 0; + i++) + { + if (con->type == CFG_CMDLINE) { /* Command line context type */ + if ((con->cur_opt_type & CFG_LONG_OPTION && con->cur_opt != NULL + && con->options[i].cmdline_long_name != NULL + && ! strcmp(con->cur_opt, + con->options[i].cmdline_long_name)) + || (con->cur_opt_type & CFG_SHORT_OPTION && + con->cur_opt[0] != '\0' && /* to prevent '-' option */ + con->cur_opt[0] == con->options[i].cmdline_short_name) + || (con->cur_opt_type == CFG_NONE_OPTION && + con->options[i].type & CFG_LEFTOVER_ARGS)) + + return i; + } + else { /* Configuration file context type */ + int len; + + if (con->cur_opt != NULL + && con->options[i].cfgfile_name != NULL + && con->cur_opt == PLATON_FUNC(str_white_str)(con->cur_opt, + (char *)(con->options[i].cfgfile_name), &len) + && len == strlen(con->cur_opt)) + + return i; + } + } + + return -1; +} /* }}} */ + + +/* + * Size of realloc() step for used_opt member of cfg_context structure. + * Value must be grater than 0. + */ + +#ifdef CFG_USED_OPT_IDX_STEP +# undef CFG_USED_OPT_IDX_STEP +#endif + +#if defined(DEBUG) && DEBUG +# define CFG_USED_OPT_IDX_STEP (1) +#else +# define CFG_USED_OPT_IDX_STEP (10) +#endif + +/* + * add_to_used_opt_idx() + * + * Function adds opt_idx to dynamic array con->used_opt_idx. If array is full, + * it is realloc()-ed according to CFG_USED_OPT_IDX_STEP constant. Array + * used_opt_idx is primary used for detecting multiple options on command line. + * + * Note, that in array -1 means empty cell, which can be overwritten by option + * index value and -255 means end of array. If there is no -1 left in array, + * array must be resized to add new option index value. + * + * Retuns -1 on not enough memory error, 1 if opt_idx founded in array and 0 if + * opt_idx was sucessfully added to array. + */ + + static int +add_to_used_opt_idx(con, opt_idx) + const CFG_CONTEXT con; + int opt_idx; +{ /* {{{ */ + int *p_i = NULL; + + if (opt_idx < 0) + return 1; + + if (con->used_opt_idx != NULL) + for (p_i = con->used_opt_idx; *p_i >= 0; p_i++) + if (*p_i == opt_idx) + return 1; + + if (p_i == NULL || *p_i == -255) { + register int *p_j; + register int new_size; + + new_size = (p_i == NULL ? 0 : p_i - con->used_opt_idx) + + 1 + CFG_USED_OPT_IDX_STEP; + + con->used_opt_idx = (int *) realloc(con->used_opt_idx, + new_size * sizeof(int)); + +#if defined(DEBUG) && DEBUG + printf("add_to_used_opt_idx(con, %d): realloc(%d) = %p\n", + opt_idx, new_size, (void *) con->used_opt_idx); +#endif + + if (con->used_opt_idx == NULL) + return -1; + + if (p_i == NULL) + p_i = con->used_opt_idx; + else /* Searching for new p_i after realloc(). */ + for (p_i = con->used_opt_idx; *p_i >= 0; p_i++) ; + + for (p_j = p_i; p_j - p_i < CFG_USED_OPT_IDX_STEP; p_j++) + *p_j = -1; + + *p_j = -255; + } + + *p_i = opt_idx; + + return 0; +} /* }}} */ + +/* + * store_multi_arg() + * + * According to option date type (type) parses and stores multiple arguments + * (multi_arg) by adding to *ar dynamic array. Array resizing is done as first + * and than is store_single_arg() function called with appropriate parameters. + */ + + static int +store_multi_arg(type, multi_arg, ar) + const int type; + const char **multi_arg; + void ***ar; +{ /* {{{ */ + register int ptr_len, item_len; + register int size_plus, size; + register int k, ret; + + switch (type) { + default: + return CFG_ERROR_INTERNAL; + break; + + case CFG_INT: + ptr_len = sizeof(int *); + item_len = sizeof(int); + break; + + case CFG_UINT: + ptr_len = sizeof(unsigned int *); + item_len = sizeof(unsigned int); + break; + + case CFG_LONG: + ptr_len = sizeof(long *); + item_len = sizeof(long); + break; + + case CFG_ULONG: + ptr_len = sizeof(unsigned long *); + item_len = sizeof(unsigned long); + break; + + case CFG_FLOAT: + ptr_len = sizeof(float *); + item_len = sizeof(float); + break; + + case CFG_DOUBLE: + ptr_len = sizeof(double *); + item_len = sizeof(double); + break; + } + + for (size_plus = 0; multi_arg[size_plus] != NULL; size_plus++) ; + for (size = 0; *ar != NULL && (*ar)[size] != NULL; size++) ; + + *ar = realloc(*ar, (size + 1 + size_plus) * ptr_len); + + if (*ar == NULL) + return CFG_ERROR_NOMEM; + + /* Array terminated NULL pointer (end of array). */ + (*ar)[size + size_plus] = NULL; + + for (k = 0; k < size_plus; k++) { + (*ar)[size + k] = malloc(item_len); + if ((*ar)[size + k] == NULL) + return CFG_ERROR_NOMEM; + + ret = store_single_arg(type, multi_arg[k], (*ar)[size + k]); + + if (ret != CFG_OK) { + /* To prevent having random value at size + k position in *ar. */ + (*ar)[size + k] = NULL; + return ret; + } + } + + return CFG_OK; +} /* }}} */ + +/* + * store_single_arg() + * + * According to option date type (type) parses and stores single argument (arg) + * to specified place pointed by where. + */ + + static int +store_single_arg(type, arg, where) + const int type; + const char *arg; + const void *where; +{ /* {{{ */ + register long long_val = 0; + register unsigned long ulong_val = 0; + register double double_val = 0.0; + register int f_integer = 0; /* Searching for integer value? */ + char *end; + + if (where == NULL) + return CFG_OK; + + /* Conveting to numeric value. */ + switch (type) { + default: + return CFG_ERROR_INTERNAL; + break; + + case CFG_INT: + case CFG_UINT: + case CFG_LONG: + case CFG_ULONG: + f_integer = 1; + if (type == CFG_ULONG) { + ulong_val = strtoul(arg, &end, 0); + } else { + long_val = strtol(arg, &end, 0); + } + if (! (end == NULL || *end != '\0')) + /* Decimal number conversion succeed */ + break; + + /* If conversion for integer number failed, we are going to try + further integer number initialization in float-like style. */ + + case CFG_FLOAT: + case CFG_DOUBLE: + double_val = strtod(arg, &end); + if (*end) + return CFG_ERROR_BADNUMBER; + + if (double_val == +HUGE_VAL || double_val == -HUGE_VAL) + /* Purpously always return overflow error */ + return f_integer ? CFG_ERROR_OVERFLOW : CFG_ERROR_OVERFLOW; +#if HAVE_ERRNO_H + if (double_val == 0.0 && errno == ERANGE) +#else + if (double_val == 0.0 && end == arg) +#endif + /* Again always return overflow error */ + return f_integer ? CFG_ERROR_OVERFLOW : CFG_ERROR_OVERFLOW; + + /* Validating coversion results */ + if (end == NULL || *end != '\0') + return CFG_ERROR_BADNUMBER; + + if (! f_integer) + break; + + if (type == CFG_ULONG) { + register double diff; + ulong_val = (unsigned long) double_val; + diff = double_val - (double) long_val; + if (diff >= 1.0 || diff <= -1.0) + return CFG_ERROR_OVERFLOW; + if (diff != 0.0) + return CFG_ERROR_BADNUMBER; + } else { + register double diff; + long_val = (long) double_val; + diff = double_val - (double) long_val; + if (diff >= 1.0 || diff <= -1.0) + return CFG_ERROR_OVERFLOW; + if (diff != 0.0) + return CFG_ERROR_BADNUMBER; + } + break; + } + + /* Range checking and value storing. */ + switch (type) { + default: + return CFG_ERROR_INTERNAL; + break; + + case CFG_INT: + if (long_val >= INT_MAX || long_val <= INT_MIN) + return CFG_ERROR_OVERFLOW; + + *((int *) where) = (int) long_val; + break; + + case CFG_UINT: + if (long_val > UINT_MAX || long_val < 0) + return CFG_ERROR_OVERFLOW; + + *((unsigned int *) where) = (unsigned int) long_val; + break; + + case CFG_LONG: + if (long_val == LONG_MIN || long_val == LONG_MAX) + return CFG_ERROR_OVERFLOW; + + *((long *) where) = long_val; + break; + + case CFG_ULONG: + /* Fix strange strtoul() behaviour. */ + for (end = (char *) arg; isspace(*end); end++) ; + + /* Testing errno after strtoul() is not needed here. */ + if (*end == '-' || ulong_val == ULONG_MAX /* || ulong_val == 0 */) + return CFG_ERROR_OVERFLOW; + + *((unsigned long *) where) = (unsigned long) ulong_val; + break; + + case CFG_FLOAT: +#ifdef ABS /* Borrowed from popt library. */ +# undef ABS +#endif +#define ABS(a) (((a) < 0) ? -(a) : (a)) + + if (double_val != 0.0) + if (ABS(double_val) > FLT_MAX || ABS(double_val) < FLT_MIN) + return CFG_ERROR_OVERFLOW; + + *((float *) where) = (float) double_val; + break; + + case CFG_DOUBLE: + *((double *) where) = (double) double_val; + break; + } + + return CFG_OK; +} /* }}} */ + +/* + * split_multi_arg() + * + * Splits multi argument with separators with focusing on quotations. + * Returns cfg_error type and in ar is result array stored. + */ + + static int +split_multi_arg(arg, ar, quote_prefix_ar, quote_postfix_ar, separator_ar) + char *arg; + char ***ar; + char **quote_prefix_ar; + char **quote_postfix_ar; + char **separator_ar; +{ /* {{{ */ + register int i; + int sep_ar_idx, quote_idx, sep_size, tmp_sep_size; + char *p_quote, *p_sep, *tmp_s; + char *arg_base = arg; + + if ((*ar = PLATON_FUNC(strdyn_create)()) == NULL) + return CFG_ERROR_NOMEM; + + do { + + /* Searching first quotation string (p_quote) + and set quotation variables */ + p_quote = PLATON_FUNC(strdyn_str2)(arg, quote_prefix_ar, "e_idx); + p_sep = NULL; /* pointer to separator */ + sep_ar_idx = -1; /* index of separator */ + sep_size = 0; /* length of separator string */ + + /* Searching first separator string (p_sep) */ + for (i = 0; separator_ar[i] != NULL; i++) { + if ((tmp_s = PLATON_FUNC(str_white_str)(arg, separator_ar[i], &tmp_sep_size)) + != NULL && (p_sep == NULL || tmp_s < p_sep)) { + p_sep = tmp_s; + sep_ar_idx = i; + sep_size = tmp_sep_size; + } + } + + /* Process quotation + if is is on lower position than separator */ + if ((p_quote != NULL && p_sep == NULL) + || (p_quote != NULL && p_sep != NULL && p_quote < p_sep)) { + + register char *end_ptr, *prefix, *postfix; + register int prefix_len, postfix_len; + + if (quote_idx < 0 /* not optimized */ + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_prefix_ar) - 1 + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_postfix_ar) - 1 + || (prefix = quote_prefix_ar[quote_idx]) == NULL + || (postfix = quote_postfix_ar[quote_idx]) == NULL) + return CFG_ERROR_INTERNAL; + + prefix_len = strlen(prefix); + postfix_len = strlen(postfix); + + memmove(p_quote, p_quote + prefix_len, + strlen(p_quote + prefix_len) + 1); + + end_ptr = strstr(p_quote, postfix); + + if (end_ptr == NULL) + return CFG_ERROR_BADQUOTE; + + memmove(end_ptr, end_ptr + postfix_len, + strlen(end_ptr + postfix_len) + 1); + + arg = end_ptr; + } + /* Separator processing otherwise */ + else if ((p_sep != NULL && p_quote == NULL) + || (p_sep != NULL && p_quote != NULL && p_sep <= p_quote)) { + + register char c; + + c = *p_sep; + *p_sep = '\0'; + *ar = PLATON_FUNC(strdyn_add_va)(*ar, arg_base, NULL); + *p_sep = c; + arg = arg_base = p_sep + sep_size; + + if (*ar == NULL) + return CFG_ERROR_NOMEM; + } + + } while (p_quote != NULL || p_sep != NULL); + + if ((*ar = PLATON_FUNC(strdyn_add_va)(*ar, arg_base, NULL)) == NULL) + return CFG_ERROR_NOMEM; + + return CFG_OK; +} /* }}} */ + +/* + * unquote_single_arg() + * + * Unquotes signle argument passed by reference as arg parameter. + * Returns cfg_error type and modyfies arg parameter. + */ + + static int +unquote_single_arg(arg, quote_prefix_ar, quote_postfix_ar) + char *arg; + char **quote_prefix_ar; + char **quote_postfix_ar; +{ /* {{{ */ + register char *p_quote; + int quote_idx; + + do { + p_quote = PLATON_FUNC(strdyn_str2)(arg, quote_prefix_ar, "e_idx); + + /* If beginning of quotation was found */ + if (p_quote != NULL) { + register char *end_ptr, *prefix, *postfix; + register int prefix_len, postfix_len; + + if (quote_idx < 0 /* not optimized */ + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_prefix_ar) - 1 + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_postfix_ar) - 1 + || (prefix = quote_prefix_ar[quote_idx]) == NULL + || (postfix = quote_postfix_ar[quote_idx]) == NULL) + return CFG_ERROR_INTERNAL; + + prefix_len = strlen(prefix); + postfix_len = strlen(postfix); + + memmove(p_quote, p_quote + prefix_len, + strlen(p_quote + prefix_len) + 1); + + end_ptr = strstr(p_quote, postfix); + + if (end_ptr == NULL) + return CFG_ERROR_BADQUOTE; + + memmove(end_ptr, end_ptr + postfix_len, + strlen(end_ptr + postfix_len) + 1); + + arg = end_ptr; + } + } while (p_quote != NULL); + + return CFG_OK; +} /* }}} */ + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/shared.h b/src/cfg/shared.h new file mode 100644 index 0000000000..8cbb97d560 --- /dev/null +++ b/src/cfg/shared.h @@ -0,0 +1,74 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * shared.h - shared stuff for command line and config file + * parsing header file + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/shared.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ */ + +/** + * @file shared.h + * @brief shared stuff for command line and config file parsing header file + * @author Ondrej Jombik <nepto@platon.sk> + * @author Lubomir Host <rajo@platon.sk> + * @version \$Platon: libcfg+/src/shared.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ + * @date 2001-2004 + */ + +#ifndef _PLATON_CFG_SHARED_H +#define _PLATON_CFG_SHARED_H + +/** + * Free current variables (cur_opt, cur_arg) in context + * and sets cur_opt_type to CFG_NONE_OPTION. + * + * @param con initialized context with initialized current variables + * @return void + */ +void __cfg_free_currents(const CFG_CONTEXT con); + +/** + * Process current option and argument. It suppose that in context con + * are cur_opt, cur_arg and cur_type set. + * + * @param con initialized context + * @param ret_val option return value (val) @see cfg_context + * @param arg_used if option argument was used + * @return CFG_OK on success, CFG_ERROR_* on error + */ +int __cfg_process_currents(const CFG_CONTEXT con, int *ret_val, int *arg_used); + +/** + * Allocate and initialize variables cur_opt and cur_arg in initialized + * command line context according to con->argv[con->cur_idx]. + * + * @param con initialized command line context + * @return CFG_OK on success, CFG_ERR_NOMEM on not enough memory error + */ +int __cfg_cmdline_set_currents(const CFG_CONTEXT con); + +/** + * Allocate and initialize variables cur_opt and cur_arg in initialized + * config file context according to input string (parameter buf). + * + * @param con initialized command line context + * @param buf input string + * @return CFG_OK on success, CFG_ERR_NOMEM on not enough memory error + */ +int __cfg_cfgfile_set_currents(const CFG_CONTEXT con, char *buf); + +#endif /* #ifndef _PLATON_CFG_SHARED_H */ + |