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