]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added batch support to certtool. Now can use templates.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Wed, 14 Apr 2004 12:17:09 +0000 (12:17 +0000)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Wed, 14 Apr 2004 12:17:09 +0000 (12:17 +0000)
34 files changed:
NEWS
configure.in
doc/TODO
src/Makefile.am
src/certtool-cfg.c [new file with mode: 0644]
src/certtool-cfg.h [new file with mode: 0644]
src/certtool-gaa.c
src/certtool-gaa.h
src/certtool.c
src/certtool.cfg [new file with mode: 0644]
src/certtool.gaa
src/cfg/Makefile.am [new file with mode: 0644]
src/cfg/cfg+.c [new file with mode: 0644]
src/cfg/cfg+.h [new file with mode: 0644]
src/cfg/cfgfile.c [new file with mode: 0644]
src/cfg/cfgfile.h [new file with mode: 0644]
src/cfg/cmdline.c [new file with mode: 0644]
src/cfg/cmdline.h [new file with mode: 0644]
src/cfg/parse.c [new file with mode: 0644]
src/cfg/platon/Makefile.am [new file with mode: 0644]
src/cfg/platon/str/Makefile.am [new file with mode: 0644]
src/cfg/platon/str/dynfgets.c [new file with mode: 0644]
src/cfg/platon/str/dynfgets.h [new file with mode: 0644]
src/cfg/platon/str/strctype.c [new file with mode: 0644]
src/cfg/platon/str/strctype.h [new file with mode: 0644]
src/cfg/platon/str/strdyn.c [new file with mode: 0644]
src/cfg/platon/str/strdyn.h [new file with mode: 0644]
src/cfg/platon/str/strplus.c [new file with mode: 0644]
src/cfg/platon/str/strplus.h [new file with mode: 0644]
src/cfg/props.c [new file with mode: 0644]
src/cfg/shared.c [new file with mode: 0644]
src/cfg/shared.h [new file with mode: 0644]
src/getpass.c
src/getpass.h

diff --git a/NEWS b/NEWS
index 63620d625dd69a6a43d4cfaa16c5faeb6cdd626a..01c3008b6fb9cca479274655e27876b7838e8848 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ Version 1.1.9
 - Added support for authority key identifier and the extended key usage
   X.509 extension fields. The certtoool was updated to support them.
 - The RC2 cipher is no more included. The one in libgcrypt is now used.
+- Added batch support to certtool. Now can use templates.
 
 Version 1.1.8 (07/04/2004)
 - Implemented all the tests for the SRP group parameters in
index 71f8ef1c39dfd5b24d208ac49e0ad866c0066b52..c8752e2565f65a8e75735c30b49fd35207e99c17 100644 (file)
@@ -172,6 +172,7 @@ AC_HEADER_TIME
 AC_CHECK_HEADERS(unistd.h strings.h stddef.h alloca.h)
 AC_CHECK_HEADERS(sys/stat.h sys/types.h sys/socket.h)
 AC_CHECK_HEADERS(errno.h sys/time.h time.h)
+AC_CHECK_HEADERS(math.h limits.h float.h stdarg.h)
 AC_CHECK_FUNCS(isascii memmove strnstr mmap gmtime_r inet_ntop,,)
 AC_FUNC_ALLOCA
 
@@ -504,6 +505,7 @@ AC_CONFIG_COMMANDS([includes/gnutls/gnutls.h],[[
 AC_CONFIG_FILES([Makefile src/Makefile libextra/Makefile lib/Makefile \
 libextra/openpgp/Makefile lib/libgnutls-config libextra/libgnutls-extra-config \
 doc/Makefile src/x509/Makefile src/srp/Makefile src/openpgp/Makefile \
+src/cfg/Makefile src/cfg/platon/Makefile src/cfg/platon/str/Makefile \
 doc/tex/Makefile doc/tex/cover.tex doc/scripts/Makefile \
 doc/examples/Makefile lib/minitasn1/Makefile lib/x509/Makefile \
 includes/Makefile includes/gnutls/Makefile doc/manpages/Makefile])
index 0b32e3ccdc614b1e241a4299c272cab56a61e1ea..2eb24712861acd2c57c9de6d281797aa7bc2c6ac 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -4,7 +4,6 @@ in order to avoid having people working on the same thing.
 
 Current list:
 * Document the format for the supported DN attributes.
-* Add batch support to certtool with template files
 * Add support for Certificate Extensions Profile for Qualified 
   Certificates (rfc3039)
 * Audit the code
index 78ecd3862cc36e4852814bd768fcc0dbf122176c..81309b2f235a9d3849996b4089bb907e728819fd 100644 (file)
@@ -1,11 +1,11 @@
 EXTRA_DIST = common.h crypt.gaa crypt-gaa.h README.srpcrypt \
        README cli.gaa cli-gaa.h serv-gaa.h serv.gaa tls_test.gaa \
        tls_test-gaa.h tests.h gnutls-http-serv list.h certtool-gaa.h \
-       certtool.gaa getpass.h
+       certtool.gaa getpass.h certtool-cfg.h
 
-SUBDIRS = srp x509 openpgp
+SUBDIRS = srp x509 openpgp cfg
 
-INCLUDES = -I../lib -I../libtasn1/lib -I../includes $(LIBOPENCDK_CFLAGS)
+INCLUDES = -I../lib -I../libtasn1/lib -I../includes $(LIBOPENCDK_CFLAGS) -Icfg/
 
 bin_PROGRAMS = gnutls-serv gnutls-cli gnutls-srpcrypt gnutls-cli-debug certtool
 gnutls_serv_SOURCES = serv-gaa.c serv.c common.c
@@ -22,7 +22,10 @@ noinst_PROGRAMS = retcodes
 retcodes_SOURCES = retcodes.c
 retcodes_LDADD = ../lib/libgnutls.la $(LIBGCRYPT_LIBS)
 
-certtool_SOURCES = certtool-gaa.c certtool.c prime.c getpass.c
+certtool_SOURCES = certtool-gaa.c certtool.c prime.c getpass.c certtool-cfg.c \
+       cfg/cfg+.c cfg/cfgfile.c cfg/cmdline.c cfg/parse.c cfg/props.c \
+       cfg/shared.c cfg/platon/str/dynfgets.c cfg/platon/str/strctype.c \
+       cfg/platon/str/strdyn.c cfg/platon/str/strplus.c
 certtool_LDADD = ../lib/libgnutls.la $(LIBGCRYPT_LIBS)
 
 
diff --git a/src/certtool-cfg.c b/src/certtool-cfg.c
new file mode 100644 (file)
index 0000000..a11afd1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is part of GNUTLS.
+ *
+ * GNUTLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GNUTLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cfg+.h>
+
+char *organization = NULL, *unit = NULL, *locality = NULL, *state = NULL;
+char *cn = NULL, *challenge_password = NULL, *pkcs9_email = NULL, *country = NULL;
+char *dns_name = NULL, *email = NULL, *crl_dist_points = NULL, *password= NULL;
+int serial = 0, expiration_days=0, ca=0, tls_www_client=0, tls_www_server=0, signing_key=0;
+int encryption_key=0, cert_sign_key=0, crl_sign_key=0, code_sign_key=0, ocsp_sign_key=0;
+int time_stamping_key=0;
+
+int parse_template(const char *template)
+{
+       /* libcfg+ parsing context */
+       CFG_CONTEXT con;
+
+       /* Parsing return code */
+       register int ret;
+
+       /* Option variables */
+
+       /* Option set */
+       struct cfg_option options[] = {
+               {NULL, '\0', "organization", CFG_STR, (void *) &organization, 0},
+               {NULL, '\0', "unit", CFG_STR, (void *) &unit, 0},
+               {NULL, '\0', "locality", CFG_STR, (void *) &locality, 0},
+               {NULL, '\0', "state", CFG_STR, (void *) &state, 0},
+               {NULL, '\0', "cn", CFG_STR, (void *) &cn, 0},
+               {NULL, '\0', "challenge_password", CFG_STR, (void *) &challenge_password, 0},
+               {NULL, '\0', "password", CFG_STR, (void *) &password, 0},
+               {NULL, '\0', "pkcs9_email", CFG_STR, (void *) &pkcs9_email, 0},
+               {NULL, '\0', "country", CFG_STR, (void *) &country, 0},
+               {NULL,    '\0', "dns_name",      CFG_STR,          (void *) &dns_name,     0},
+               {NULL,    '\0', "email",      CFG_STR,          (void *) &email,     0},
+               {NULL, '\0', "crl_dist_points", CFG_STR, (void *) &crl_dist_points, 0},
+
+               {NULL,    '\0', "serial",      CFG_INT,          (void *) &serial,     0},
+               {NULL,    '\0', "expiration_days",      CFG_INT,          (void *) &expiration_days,     0},
+
+               {NULL,    '\0', "ca",      CFG_BOOL,          (void *) &ca,     0},
+               {NULL,    '\0', "tls_www_client",      CFG_BOOL,          (void *) &tls_www_client,     0},
+               {NULL,    '\0', "tls_www_server",      CFG_BOOL,          (void *) &tls_www_server,     0},
+               {NULL,    '\0', "signing_key",      CFG_BOOL,          (void *) &signing_key,     0},
+               {NULL,    '\0', "encryption_key",      CFG_BOOL,          (void *) &encryption_key,     0},
+               {NULL,    '\0', "cert_signing_key",      CFG_BOOL,          (void *) &cert_sign_key,     0},
+               {NULL,    '\0', "crl_signing_key",      CFG_BOOL,          (void *) &crl_sign_key,     0},
+               {NULL,    '\0', "code_signing_key",      CFG_BOOL,          (void *) &code_sign_key,     0},
+               {NULL,    '\0', "ocsp_signing_key",      CFG_BOOL,          (void *) &ocsp_sign_key,     0},
+               {NULL,    '\0', "time_stamping_key",      CFG_BOOL,          (void *) &time_stamping_key, 0},
+               CFG_END_OF_LIST
+       };
+
+       /* Creating context */
+       con = cfg_get_context(options);
+       if (con == NULL) {
+               puts("Not enough memory");
+               exit(1);
+       }
+
+       cfg_set_cfgfile_context(con, 0, -1, template);
+
+       /* Parsing command line */
+       ret = cfg_parse(con);
+
+       if (ret != CFG_OK) {
+               printf("error parsing command line: %s: ", template);
+               cfg_fprint_error(con, stdout);
+               putchar('\n');
+               exit( ret < 0 ? -ret : ret);
+       }
+
+       return 0;
+}
diff --git a/src/certtool-cfg.h b/src/certtool-cfg.h
new file mode 100644 (file)
index 0000000..5cee167
--- /dev/null
@@ -0,0 +1,8 @@
+extern char *organization, *unit, *locality, *state;
+extern char *cn, *challenge_password, *password, *pkcs9_email, *country;
+extern char *dns_name, *email, *crl_dist_points;
+extern int serial, expiration_days, ca, tls_www_client, tls_www_server, signing_key;
+extern int encryption_key, cert_sign_key, crl_sign_key, code_sign_key, ocsp_sign_key;
+extern int time_stamping_key;
+
+int parse_template(const char *template);
index fac7e054ef77ea41f891221486f749d2f809beca..a0b1e02d9fcc660b6a00c1aabb67d2a6ba59e720 100644 (file)
@@ -159,6 +159,7 @@ void gaa_help(void)
        __gaa_helpsingle(0, "bits", "BITS ", "specify the number of bits for key generation.");
        __gaa_helpsingle(0, "outfile", "FILE ", "Output file.");
        __gaa_helpsingle(0, "infile", "FILE ", "Output file.");
+       __gaa_helpsingle(0, "template", "FILE ", "Template file to use for non interactive operation.");
        __gaa_helpsingle('d', "debug", "LEVEL ", "specify the debug level. Default is 1.");
        __gaa_helpsingle('h', "help", "", "shows this help text");
        __gaa_helpsingle('v', "version", "", "shows the program's version");
@@ -177,8 +178,10 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 90 "certtool.gaa"
+#line 94 "certtool.gaa"
        int debug;
+#line 90 "certtool.gaa"
+       char *template;
 #line 87 "certtool.gaa"
        char *infile;
 #line 84 "certtool.gaa"
@@ -263,40 +266,41 @@ int gaa_error = 0;
 #define GAA_MULTIPLE_OPTION     3
 
 #define GAA_REST                0
-#define GAA_NB_OPTION           33
+#define GAA_NB_OPTION           34
 #define GAAOPTID_copyright     1
 #define GAAOPTID_version       2
 #define GAAOPTID_help  3
 #define GAAOPTID_debug 4
-#define GAAOPTID_infile        5
-#define GAAOPTID_outfile       6
-#define GAAOPTID_bits  7
-#define GAAOPTID_outder        8
-#define GAAOPTID_inder 9
-#define GAAOPTID_export_ciphers        10
-#define GAAOPTID_dsa   11
-#define GAAOPTID_pkcs8 12
-#define GAAOPTID_to_p12        13
-#define GAAOPTID_key_info      14
-#define GAAOPTID_p7_info       15
-#define GAAOPTID_p12_info      16
-#define GAAOPTID_crl_info      17
-#define GAAOPTID_certificate_info      18
-#define GAAOPTID_password      19
-#define GAAOPTID_load_ca_certificate   20
-#define GAAOPTID_load_ca_privkey       21
-#define GAAOPTID_load_certificate      22
-#define GAAOPTID_load_request  23
-#define GAAOPTID_load_privkey  24
-#define GAAOPTID_generate_dh_params    25
-#define GAAOPTID_verify_crl    26
-#define GAAOPTID_verify_chain  27
-#define GAAOPTID_generate_request      28
-#define GAAOPTID_generate_privkey      29
-#define GAAOPTID_update_certificate    30
-#define GAAOPTID_generate_crl  31
-#define GAAOPTID_generate_certificate  32
-#define GAAOPTID_generate_self_signed  33
+#define GAAOPTID_template      5
+#define GAAOPTID_infile        6
+#define GAAOPTID_outfile       7
+#define GAAOPTID_bits  8
+#define GAAOPTID_outder        9
+#define GAAOPTID_inder 10
+#define GAAOPTID_export_ciphers        11
+#define GAAOPTID_dsa   12
+#define GAAOPTID_pkcs8 13
+#define GAAOPTID_to_p12        14
+#define GAAOPTID_key_info      15
+#define GAAOPTID_p7_info       16
+#define GAAOPTID_p12_info      17
+#define GAAOPTID_crl_info      18
+#define GAAOPTID_certificate_info      19
+#define GAAOPTID_password      20
+#define GAAOPTID_load_ca_certificate   21
+#define GAAOPTID_load_ca_privkey       22
+#define GAAOPTID_load_certificate      23
+#define GAAOPTID_load_request  24
+#define GAAOPTID_load_privkey  25
+#define GAAOPTID_generate_dh_params    26
+#define GAAOPTID_verify_crl    27
+#define GAAOPTID_verify_chain  28
+#define GAAOPTID_generate_request      29
+#define GAAOPTID_generate_privkey      30
+#define GAAOPTID_update_certificate    31
+#define GAAOPTID_generate_crl  32
+#define GAAOPTID_generate_certificate  33
+#define GAAOPTID_generate_self_signed  34
 
 #line 168 "gaa.skel"
 
@@ -489,6 +493,12 @@ struct GAAOPTION_debug
        int size1;
 };
 
+struct GAAOPTION_template 
+{
+       char* arg1;
+       int size1;
+};
+
 struct GAAOPTION_infile 
 {
        char* arg1;
@@ -573,6 +583,7 @@ int gaa_get_option_num(char *str, int status)
         {
         case GAA_LETTER_OPTION:
                        GAA_CHECK1STR("d", GAAOPTID_debug);
+                       GAA_CHECK1STR("", GAAOPTID_template);
                        GAA_CHECK1STR("", GAAOPTID_infile);
                        GAA_CHECK1STR("", GAAOPTID_outfile);
                        GAA_CHECK1STR("", GAAOPTID_bits);
@@ -615,6 +626,7 @@ int gaa_get_option_num(char *str, int status)
                        GAA_CHECKSTR("version", GAAOPTID_version);
                        GAA_CHECKSTR("help", GAAOPTID_help);
                        GAA_CHECKSTR("debug", GAAOPTID_debug);
+                       GAA_CHECKSTR("template", GAAOPTID_template);
                        GAA_CHECKSTR("infile", GAAOPTID_infile);
                        GAA_CHECKSTR("outfile", GAAOPTID_outfile);
                        GAA_CHECKSTR("bits", GAAOPTID_bits);
@@ -657,6 +669,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
     int OK = 0;
     int gaa_last_non_option;
        struct GAAOPTION_debug GAATMP_debug;
+       struct GAAOPTION_template GAATMP_template;
        struct GAAOPTION_infile GAATMP_infile;
        struct GAAOPTION_outfile GAATMP_outfile;
        struct GAAOPTION_bits GAATMP_bits;
@@ -688,21 +701,21 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
     {
        case GAAOPTID_copyright:
        OK = 0;
-#line 96 "certtool.gaa"
+#line 100 "certtool.gaa"
 { print_license(); exit(0); ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_version:
        OK = 0;
-#line 95 "certtool.gaa"
+#line 99 "certtool.gaa"
 { certtool_version(); exit(0); ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_help:
        OK = 0;
-#line 93 "certtool.gaa"
+#line 97 "certtool.gaa"
 { gaa_help(); exit(0); ;};
 
                return GAA_OK;
@@ -712,9 +725,19 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1);
                gaa_index++;
-#line 91 "certtool.gaa"
+#line 95 "certtool.gaa"
 { gaaval->debug = GAATMP_debug.arg1 ;};
 
+               return GAA_OK;
+               break;
+       case GAAOPTID_template:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_template.arg1, gaa_getstr, GAATMP_template.size1);
+               gaa_index++;
+#line 91 "certtool.gaa"
+{ gaaval->template = GAATMP_template.arg1 ;};
+
                return GAA_OK;
                break;
        case GAAOPTID_infile:
@@ -971,11 +994,11 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
     if(inited == 0)
     {
 
-#line 98 "certtool.gaa"
+#line 102 "certtool.gaa"
 { gaaval->bits = 1024; gaaval->pkcs8 = 0; gaaval->privkey = NULL; gaaval->ca=NULL; gaaval->ca_privkey = NULL; 
        gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; gaaval->outfile = NULL; gaaval->cert = NULL; 
        gaaval->incert_format = 0; gaaval->outcert_format = 0; gaaval->action=-1; gaaval->pass = NULL; 
-       gaaval->export = 0; ;};
+       gaaval->export = 0; gaaval->template = NULL; ;};
 
     }
     inited = 1;
index 2bef4af05b9ba569dea353921a39d108494b3470..958994773c55c6aca85e15c79f1fc1ffa717dacd 100644 (file)
@@ -8,8 +8,10 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 90 "certtool.gaa"
+#line 94 "certtool.gaa"
        int debug;
+#line 90 "certtool.gaa"
+       char *template;
 #line 87 "certtool.gaa"
        char *infile;
 #line 84 "certtool.gaa"
index 9293fad64c49438310fb707a1fdcda84182f866d..01fa8bb8676552b5c5b912ab31bdebbaf43e296c 100644 (file)
@@ -33,6 +33,7 @@
 #include <gnutls/pkcs12.h>
 #include <unistd.h>
 #include <getpass.h>
+#include <certtool-cfg.h>
 
 static void print_crl_info( gnutls_x509_crl crl, FILE* out, int all);
 int generate_prime(int bits);
@@ -58,8 +59,12 @@ gnutls_x509_crt* load_cert_list(int mand, int *size);
 static gaainfo info;
 FILE* outfile;
 FILE* infile;
-int in_cert_format;
-int out_cert_format;
+static int in_cert_format;
+static int out_cert_format;
+
+/* non interactive operation if set
+ */
+static int batch;
 
 unsigned char buffer[50*1024];
 const int buffer_size = sizeof(buffer);
@@ -234,6 +239,296 @@ static void print_key_purpose( const char* x, FILE* out)
        else fprintf(out,"\t\t%s\n", x);
 }
 
+
+/* Wrapper functions for non-interactive mode.
+ */
+const char* get_pass(const char* str)
+{
+       if (batch)
+               return password;
+       else
+               return read_pass(str);
+}
+
+void get_country_crt_set( gnutls_x509_crt crt)
+{
+int ret;
+
+       if (batch) {
+               if (!country) return;
+               ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, 
+                       country, strlen(country));
+               if (ret < 0) {
+                       fprintf(stderr, "set_dn: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
+       } else {
+               read_crt_set( crt, "Country name (2 chars): ", GNUTLS_OID_X520_COUNTRY_NAME);
+       }
+
+}
+
+void get_organization_crt_set( gnutls_x509_crt crt)
+{
+int ret;
+
+       if (batch) {
+               if (!organization) return;
+
+               ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, 
+                       organization, strlen(organization));
+               if (ret < 0) {
+                       fprintf(stderr, "set_dn: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
+       } else {
+               read_crt_set( crt, "Organization name: ", GNUTLS_OID_X520_ORGANIZATION_NAME);
+       }
+
+}
+
+void get_unit_crt_set( gnutls_x509_crt crt)
+{
+int ret;
+
+       if (batch) {
+               if (!unit) return;
+               
+               ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0, 
+                       unit, strlen(unit));
+               if (ret < 0) {
+                       fprintf(stderr, "set_dn: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
+       } else {
+               read_crt_set( crt, "Organizational unit name: ", GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME);
+       }
+
+}
+
+void get_state_crt_set( gnutls_x509_crt crt)
+{
+int ret;
+
+       if (batch) {
+               if (!state) return;
+               ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, 
+                       state, strlen(state));
+               if (ret < 0) {
+                       fprintf(stderr, "set_dn: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
+       } else {
+               read_crt_set( crt, "State or province name: ", GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME);
+       }
+
+}
+
+void get_locality_crt_set( gnutls_x509_crt crt)
+{
+int ret;
+
+       if (batch) {
+               if (!locality) return;
+               ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, 
+                       locality, strlen(locality));
+               if (ret < 0) {
+                       fprintf(stderr, "set_dn: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
+       } else {
+               read_crt_set( crt, "Locality name: ", GNUTLS_OID_X520_LOCALITY_NAME);
+       }
+
+}
+
+void get_cn_crt_set( gnutls_x509_crt crt)
+{
+int ret;
+
+       if (batch) {
+               if (!cn) return;
+               ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, 
+                       cn, strlen(cn));
+               if (ret < 0) {
+                       fprintf(stderr, "set_dn: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
+       } else {
+               read_crt_set( crt, "Common name: ", GNUTLS_OID_X520_COMMON_NAME);
+       }
+
+}
+
+void get_pkcs9_email_crt_set( gnutls_x509_crt crt)
+{
+int ret;
+
+       if (batch) {
+               if (!pkcs9_email) return;
+               ret = gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, 
+                       pkcs9_email, strlen(pkcs9_email));
+               if (ret < 0) {
+                       fprintf(stderr, "set_dn: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
+       } else {
+               read_crt_set( crt, "E-mail: ", GNUTLS_OID_PKCS9_EMAIL);
+       }
+
+}
+
+int get_serial( void) 
+{
+       if (batch) {
+               if (!serial) return 0;
+               return serial;
+       } else {
+               return read_int( "Enter the certificate's serial number (decimal): ");
+       }
+}
+
+int get_days( void)
+{
+int days;
+
+       if (batch) {
+               if (expiration_days <= 0) return 365;
+               else return expiration_days;
+       } else {
+               do {
+                       days = read_int( "The generated certificate will expire in (days): ");
+               } while( days==0);
+               return days;
+       }
+}
+
+int get_ca_status( void)
+{
+       if (batch) {
+               return ca;
+       } else {
+               return read_yesno( "Does the certificate belong to an authority? (Y/N): ");
+       }
+}
+
+int get_tls_client_status( void)
+{
+       if (batch) {
+               return tls_www_client;
+       } else {
+               return read_yesno( "Is this a TLS web client certificate? (Y/N): ");
+       }
+}
+
+int get_tls_server_status( void)
+{
+       if (batch) {
+               return tls_www_server;
+       } else {
+               return read_yesno( "Is this also a TLS web server certificate? (Y/N): ");
+       }
+}
+
+const char* get_dns_name( void)
+{
+       if (batch) {
+               return dns_name;
+       } else {
+               return read_str( "Enter the dnsName of the subject of the certificate: ");
+       }
+}
+
+const char* get_email( void)
+{
+       if (batch) {
+               return email;
+       } else {
+               return read_str( "Enter the e-mail of the subject of the certificate: ");
+       }
+}
+
+int get_sign_status( int server)
+{
+const char* msg;
+
+       if (batch) {
+               return signing_key;
+       } else {
+               if (server) msg = "Will the certificate be used for signing (DHE and RSA-EXPORT ciphersuites)? (Y/N): ";
+               else msg = "Will the certificate be used for signing (required for TLS)? (Y/N): ";
+               return read_yesno( msg);
+       }
+}
+
+int get_encrypt_status( int server)
+{
+const char* msg;
+
+       if (batch) {
+               return encryption_key;
+       } else {
+               if (server) msg = "Will the certificate be used for encryption (RSA ciphersuites)? (Y/N): ";
+               else msg = "Will the certificate be used for encryption (not required for TLS)? (Y/N): ";
+               return read_yesno( msg);
+       }
+}
+
+int get_cert_sign_status(void)
+{
+       if (batch) {
+               return cert_sign_key;
+       } else {
+               return read_yesno( "Will the certificate be used to sign other certificates? (Y/N): ");
+       }
+}
+
+int get_crl_sign_status(void)
+{
+       if (batch) {
+               return crl_sign_key;
+       } else {
+               return read_yesno( "Will the certificate be used to sign CRLs? (Y/N): ");
+       }
+}
+
+int get_code_sign_status(void)
+{
+       if (batch) {
+               return code_sign_key;
+       } else {
+               return read_yesno( "Will the certificate be used to sign code? (Y/N): ");
+       }
+}
+
+int get_ocsp_sign_status(void)
+{
+       if (batch) {
+               return ocsp_sign_key;
+       } else {
+               return read_yesno( "Will the certificate be used to sign OCSP requests? (Y/N): ");
+       }
+}
+
+int get_time_stamp_status( void)
+{
+       if (batch) {
+               return time_stamping_key;
+       } else {
+               return read_yesno( "Will the certificate be used for time stamping? (Y/N): ");
+       }
+}
+
+
+
+
+
+
+
+
+
+
+
 static void print_private_key( gnutls_x509_privkey key)
 {
 int ret;
@@ -254,7 +549,7 @@ size_t size;
                
                if (info.export) flags = GNUTLS_PKCS_USE_PKCS12_RC2_40;
                else flags = GNUTLS_PKCS_USE_PKCS12_3DES;
-               if ((pass=read_pass("Enter password: ")) == NULL) flags = GNUTLS_PKCS_PLAIN;
+               if ((pass=get_pass("Enter password: ")) == NULL) flags = GNUTLS_PKCS_PLAIN;
 
                size = sizeof(buffer);
                ret = gnutls_x509_privkey_export_pkcs8( key, out_cert_format, pass, flags, buffer, &size);
@@ -307,18 +602,20 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
 
                key = load_private_key(1);
 
+               if (!batch)
                fprintf(stderr, "Please enter the details of the certificate's distinguished name. "
                "Just press enter to ignore a field.\n");
 
-               read_crt_set( crt, "Country name (2 chars): ", GNUTLS_OID_X520_COUNTRY_NAME);
-               read_crt_set( crt, "Organization name: ", GNUTLS_OID_X520_ORGANIZATION_NAME);
-               read_crt_set( crt, "Organizational unit name: ", GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME);
-               read_crt_set( crt, "Locality name: ", GNUTLS_OID_X520_LOCALITY_NAME);
-               read_crt_set( crt, "State or province name: ", GNUTLS_OID_X520_LOCALITY_NAME);
-               read_crt_set( crt, "Common name: ", GNUTLS_OID_X520_COMMON_NAME);
+               get_country_crt_set( crt);
+               get_organization_crt_set(crt);
+               get_unit_crt_set( crt);
+               get_locality_crt_set( crt);
+               get_state_crt_set( crt);
+               get_cn_crt_set( crt);
        
-               fprintf(stderr, "This field should not be used in new certificates.\n");
-               read_crt_set( crt, "E-mail: ", GNUTLS_OID_PKCS9_EMAIL);
+               if (!batch) fprintf(stderr, "This field should not be used in new certificates.\n");
+
+               get_pkcs9_email_crt_set( crt);
 
                result = gnutls_x509_crt_set_key( crt, key);
                if (result < 0) {
@@ -335,7 +632,7 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
        }
 
 
-       serial = read_int( "Enter the certificate's serial number (decimal): ");
+       serial = get_serial();
        buffer[3] = serial & 0xff;
        buffer[2] = (serial >> 8) & 0xff;
        buffer[1] = (serial >> 16) & 0xff;
@@ -348,12 +645,11 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
        }
 
 
-       fprintf(stderr, "\n\nActivation/Expiration time.\n");   
+       if (!batch) fprintf(stderr, "\n\nActivation/Expiration time.\n");       
+
        gnutls_x509_crt_set_activation_time( crt, time(NULL));
 
-       do {
-               days = read_int( "The generated certificate will expire in (days): ");
-       } while( days==0);
+       days = get_days();
        
        result = gnutls_x509_crt_set_expiration_time( crt, time(NULL)+days*24*60*60);
        if (result < 0) {
@@ -362,9 +658,9 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
        }
        
 
-       fprintf(stderr, "\n\nExtensions.\n");   
+       if (!batch) fprintf(stderr, "\n\nExtensions.\n");       
 
-       ca_status = read_yesno( "Does the certificate belong to an authority? (Y/N): ");
+       ca_status = get_ca_status();
 
        result = gnutls_x509_crt_set_ca_status( crt, ca_status);
        if (result < 0) {
@@ -372,7 +668,7 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
                exit(1);
        }
 
-       client = read_yesno( "Is this a TLS web client certificate? (Y/N): ");
+       client = get_tls_client_status();
        if (client != 0) {
                result = gnutls_x509_crt_set_key_purpose_oid( crt, GNUTLS_KP_TLS_WWW_CLIENT, 0);
                if (result < 0) {
@@ -381,9 +677,9 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
                }
        }
 
-       server = read_yesno( "Is this also a TLS web server certificate? (Y/N): ");
+       server = get_tls_server_status();
        if (server != 0) {
-               str = read_str( "Enter the dnsName of the subject of the certificate: ");
+               str = get_dns_name();
                if (str != NULL) {
                        result = gnutls_x509_crt_set_subject_alternative_name( crt, GNUTLS_SAN_DNSNAME, str);
                        if (result < 0) {
@@ -400,7 +696,7 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
                
        } else {
 
-               str = read_str( "Enter the e-mail of the subject of the certificate: ");
+               str = get_email();
        
                if (str != NULL) {
                        result = gnutls_x509_crt_set_subject_alternative_name( crt, GNUTLS_SAN_RFC822NAME, str);
@@ -414,35 +710,29 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
 
        if (!ca_status || server) {
                int pk;
-               const char* msg1, *msg2;
-               
-               if (server) msg1 = "Will the certificate be used for signing (DHE and RSA-EXPORT ciphersuites)? (Y/N): ";
-               else msg1 = "Will the certificate be used for signing (required for TLS)? (Y/N): ";
 
-               if (server) msg2 = "Will the certificate be used for encryption (RSA ciphersuites)? (Y/N): ";
-               else msg2 = "Will the certificate be used for encryption (not required for TLS)? (Y/N): ";
 
                pk = gnutls_x509_crt_get_pk_algorithm( crt, NULL);
 
                if (pk != GNUTLS_PK_DSA) { /* DSA keys can only sign.
                                            */
-                       result = read_yesno( msg1);
+                       result = get_sign_status(server);
                        if (result) usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
 
-                       result = read_yesno( msg2);
+                       result = get_encrypt_status( server);
                        if (result) usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
                } else usage |= GNUTLS_KEY_DIGITAL_SIGNATURE;
        }
 
 
        if (ca_status) {
-               result = read_yesno( "Will the certificate be used to sign other certificates? (Y/N): ");
+               result = get_cert_sign_status();
                if (result) usage |= GNUTLS_KEY_KEY_CERT_SIGN;
 
-               result = read_yesno( "Will the certificate be used to sign CRLs? (Y/N): ");
+               result = get_crl_sign_status();
                if (result) usage |= GNUTLS_KEY_CRL_SIGN;
 
-               result = read_yesno( "Will the certificate be used to sign code? (Y/N): ");
+               result = get_code_sign_status();
                if (result) {
                        result = gnutls_x509_crt_set_key_purpose_oid( crt, GNUTLS_KP_CODE_SIGNING, 0);
                        if (result < 0) {
@@ -451,7 +741,7 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
                        }
                }
 
-               result = read_yesno( "Will the certificate be used to sign OCSP requests? (Y/N): ");
+               result = get_ocsp_sign_status();
                if (result) {
                        result = gnutls_x509_crt_set_key_purpose_oid( crt, GNUTLS_KP_OCSP_SIGNING, 0);
                        if (result < 0) {
@@ -460,7 +750,7 @@ gnutls_x509_crt generate_certificate( gnutls_x509_privkey *ret_key,
                        }
                }
 
-               result = read_yesno( "Will the certificate be used for time stamping? (Y/N): ");
+               result = get_time_stamp_status();
                if (result) {
                        result = gnutls_x509_crt_set_key_purpose_oid( crt, GNUTLS_KP_TIME_STAMPING, 0);
                        if (result < 0) {
@@ -793,6 +1083,12 @@ int ret;
        if (info.outcert_format) out_cert_format = GNUTLS_X509_FMT_DER;
        else out_cert_format = GNUTLS_X509_FMT_PEM;
 
+       batch = 0;
+       if (info.template) {
+               batch = 1;
+               parse_template( info.template);
+       }
+
        gnutls_global_set_log_function( tls_log_func);
        gnutls_global_set_log_level(info.debug);
 
@@ -1235,7 +1531,7 @@ static void print_certificate_info( gnutls_x509_crt crt, FILE* out, unsigned int
 
        fprintf(out, "\n");
 
-       if (out==stderr) /* interactive */
+       if (out==stderr && batch == 0) /* interactive */
        if (read_yesno( "Is the above information ok? (Y/N): ")==0) {
                exit(1);
        }
diff --git a/src/certtool.cfg b/src/certtool.cfg
new file mode 100644 (file)
index 0000000..4c5cc50
--- /dev/null
@@ -0,0 +1,88 @@
+# X.509 Certificate options
+#
+# DN options
+
+# The organization of the subject.
+organization = "Koko inc."
+
+# The organizational unit of the subject.
+unit = "sleeping dept."
+
+# The locality of the subject.
+# locality = 
+
+# The state of the certificate owner.
+state = "Attiki"
+
+# The country of the subject. Two letter code.
+country = GR
+
+# The common name of the certificate owner.
+cn = "Cindy Lauper"
+
+# This is deprecated and should not be used in new
+# certificates.
+# pkcs9_email = "none@none.org"
+
+# The serial number of the certificate
+serial = 007
+
+# In how many days, counting from today, this certificate will expire.
+expiration_days = 700
+
+
+# X.509 v3 extensions
+
+# A dnsname in case of a WWW server.
+#dns_name = "www.none.org"
+
+# An email in case of a person
+email = "none@none.org"
+
+# An URL that has CRLs (certificate revocation lists)
+# available. Needed in CA certificates.
+#crl_dist_points = "http://www.getcrl.crl/getcrl/"
+
+# Whether this is a CA certificate or not
+ca = 0
+
+# Whether this certificate will be used for a TLS client
+#tls_www_client = 0
+
+# Whether this certificate will be used for a TLS server
+#tls_www_server = 0
+
+# Whether this certificate will be used to sign data (needed
+# in TLS DHE ciphersuites).
+signing_key = 0
+
+# Whether this certificate will be used to encrypt data (needed
+# in TLS RSA ciphersuites). Note that it is prefered to use different
+# keys for encryption and signing.
+#encryption_key = 0
+
+# Whether this key will be used to sign other certificates.
+#cert_signing_key = 0
+
+# Whether this key will be used to sign CRLs.
+#crl_signing_key = 0
+
+# Whether this key will be used to sign code.
+#code_signing_key = 0
+
+# Whether this key will be used to sign OCSP data.
+#ocsp_signing_key = 0
+
+# Whether this key will be used for time stamping.
+#time_stamping_key = 0
+
+
+# Things for PKCS #10 certificate Requests
+
+# A challenge password for the request.
+#challenge_password = "My challenge password"
+
+# Other things.
+
+# A password to be used while encrypting/decrypting.
+#password = "my pass"
index 9fb257e93f13e1a468747d547fb3990897f02c84..3793fca9fc20f2cbf0626f0968827f2cda9d970e 100644 (file)
@@ -87,6 +87,10 @@ option (outfile) STR "FILE" { $outfile = $1 } "Output file."
 #char *infile;
 option (infile) STR "FILE" { $infile = $1 } "Output file."
 
+#char *template;
+option (template) STR "FILE" { $template = $1 } "Template file to use for non interactive operation."
+
+
 #int debug;
 option (d, debug) INT "LEVEL" { $debug = $1 } "specify the debug level. Default is 1."
 
@@ -98,5 +102,5 @@ option ( copyright) { print_license(); exit(0); } "shows the program's license"
 init { $bits = 1024; $pkcs8 = 0; $privkey = NULL; $ca=NULL; $ca_privkey = NULL; 
        $debug=1; $request = NULL; $infile = NULL; $outfile = NULL; $cert = NULL; 
        $incert_format = 0; $outcert_format = 0; $action=-1; $pass = NULL; 
-       $export = 0; }
+       $export = 0; $template = NULL; }
 
diff --git a/src/cfg/Makefile.am b/src/cfg/Makefile.am
new file mode 100644 (file)
index 0000000..5ba55fa
--- /dev/null
@@ -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 (file)
index 0000000..db01911
--- /dev/null
@@ -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 (file)
index 0000000..2bdb1b7
--- /dev/null
@@ -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 (file)
index 0000000..398ac47
--- /dev/null
@@ -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 (file)
index 0000000..7ed9d4e
--- /dev/null
@@ -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 (file)
index 0000000..c6a08d5
--- /dev/null
@@ -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 (file)
index 0000000..2c2e782
--- /dev/null
@@ -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 (file)
index 0000000..f2cea03
--- /dev/null
@@ -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 (file)
index 0000000..a15898a
--- /dev/null
@@ -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 (file)
index 0000000..0510349
--- /dev/null
@@ -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 (file)
index 0000000..3341ef6
--- /dev/null
@@ -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 (file)
index 0000000..ab7ee50
--- /dev/null
@@ -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 (file)
index 0000000..5fcc55c
--- /dev/null
@@ -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 (file)
index 0000000..82627a3
--- /dev/null
@@ -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 (file)
index 0000000..2883fe4
--- /dev/null
@@ -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 (file)
index 0000000..d8370a9
--- /dev/null
@@ -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 (file)
index 0000000..ba9e144
--- /dev/null
@@ -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 (file)
index 0000000..f3c4b43
--- /dev/null
@@ -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 (file)
index 0000000..ff6437a
--- /dev/null
@@ -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 (file)
index 0000000..1219f47
--- /dev/null
@@ -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, &quote_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, &quote_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 (file)
index 0000000..8cbb97d
--- /dev/null
@@ -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 */
+
index 6ce6dde4e49ef33de0e939f4f7ec0f5b3c1b9a6b..21827072bfd751ae6fec415a768e89781410245c 100644 (file)
@@ -9,7 +9,7 @@
 
 #define OUT_STREAM stdout
 
-const char *read_pass(char *msg)
+const char *read_pass(const char *msg)
 {
 #ifndef _WIN32
        struct termios old, new;
index 3562b688c17772412324676fcfa3bc3105c0a04c..d044cd5af530a7db05490f6c54c211586db4f13f 100644 (file)
@@ -1 +1 @@
-const char* read_pass (char *msg);
+const char* read_pass (const char *msg);