diff options
34 files changed, 6275 insertions, 82 deletions
@@ -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]) @@ -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, "e_idx); + p_sep = NULL; /* pointer to separator */ + sep_ar_idx = -1; /* index of separator */ + sep_size = 0; /* length of separator string */ + + /* Searching first separator string (p_sep) */ + for (i = 0; separator_ar[i] != NULL; i++) { + if ((tmp_s = PLATON_FUNC(str_white_str)(arg, separator_ar[i], &tmp_sep_size)) + != NULL && (p_sep == NULL || tmp_s < p_sep)) { + p_sep = tmp_s; + sep_ar_idx = i; + sep_size = tmp_sep_size; + } + } + + /* Process quotation + if is is on lower position than separator */ + if ((p_quote != NULL && p_sep == NULL) + || (p_quote != NULL && p_sep != NULL && p_quote < p_sep)) { + + register char *end_ptr, *prefix, *postfix; + register int prefix_len, postfix_len; + + if (quote_idx < 0 /* not optimized */ + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_prefix_ar) - 1 + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_postfix_ar) - 1 + || (prefix = quote_prefix_ar[quote_idx]) == NULL + || (postfix = quote_postfix_ar[quote_idx]) == NULL) + return CFG_ERROR_INTERNAL; + + prefix_len = strlen(prefix); + postfix_len = strlen(postfix); + + memmove(p_quote, p_quote + prefix_len, + strlen(p_quote + prefix_len) + 1); + + end_ptr = strstr(p_quote, postfix); + + if (end_ptr == NULL) + return CFG_ERROR_BADQUOTE; + + memmove(end_ptr, end_ptr + postfix_len, + strlen(end_ptr + postfix_len) + 1); + + arg = end_ptr; + } + /* Separator processing otherwise */ + else if ((p_sep != NULL && p_quote == NULL) + || (p_sep != NULL && p_quote != NULL && p_sep <= p_quote)) { + + register char c; + + c = *p_sep; + *p_sep = '\0'; + *ar = PLATON_FUNC(strdyn_add_va)(*ar, arg_base, NULL); + *p_sep = c; + arg = arg_base = p_sep + sep_size; + + if (*ar == NULL) + return CFG_ERROR_NOMEM; + } + + } while (p_quote != NULL || p_sep != NULL); + + if ((*ar = PLATON_FUNC(strdyn_add_va)(*ar, arg_base, NULL)) == NULL) + return CFG_ERROR_NOMEM; + + return CFG_OK; +} /* }}} */ + +/* + * unquote_single_arg() + * + * Unquotes signle argument passed by reference as arg parameter. + * Returns cfg_error type and modyfies arg parameter. + */ + + static int +unquote_single_arg(arg, quote_prefix_ar, quote_postfix_ar) + char *arg; + char **quote_prefix_ar; + char **quote_postfix_ar; +{ /* {{{ */ + register char *p_quote; + int quote_idx; + + do { + p_quote = PLATON_FUNC(strdyn_str2)(arg, quote_prefix_ar, "e_idx); + + /* If beginning of quotation was found */ + if (p_quote != NULL) { + register char *end_ptr, *prefix, *postfix; + register int prefix_len, postfix_len; + + if (quote_idx < 0 /* not optimized */ + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_prefix_ar) - 1 + || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_postfix_ar) - 1 + || (prefix = quote_prefix_ar[quote_idx]) == NULL + || (postfix = quote_postfix_ar[quote_idx]) == NULL) + return CFG_ERROR_INTERNAL; + + prefix_len = strlen(prefix); + postfix_len = strlen(postfix); + + memmove(p_quote, p_quote + prefix_len, + strlen(p_quote + prefix_len) + 1); + + end_ptr = strstr(p_quote, postfix); + + if (end_ptr == NULL) + return CFG_ERROR_BADQUOTE; + + memmove(end_ptr, end_ptr + postfix_len, + strlen(end_ptr + postfix_len) + 1); + + arg = end_ptr; + } + } while (p_quote != NULL); + + return CFG_OK; +} /* }}} */ + +/* Modeline for ViM {{{ + * vim:set ts=4: + * vim600:fdm=marker fdl=0 fdc=0: + * }}} */ + diff --git a/src/cfg/shared.h b/src/cfg/shared.h new file mode 100644 index 0000000000..8cbb97d560 --- /dev/null +++ b/src/cfg/shared.h @@ -0,0 +1,74 @@ +/* + * libcfg+ - precise command line & config file parsing library + * + * shared.h - shared stuff for command line and config file + * parsing header file + * ____________________________________________________________ + * + * Developed by Ondrej Jombik <nepto@platon.sk> + * and Lubomir Host <rajo@platon.sk> + * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/ + * All rights reserved. + * + * See README file for more information about this software. + * See COPYING file for license information. + * + * Download the latest version from + * http://platon.sk/projects/libcfg+/ + */ + +/* $Platon: libcfg+/src/shared.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ */ + +/** + * @file shared.h + * @brief shared stuff for command line and config file parsing header file + * @author Ondrej Jombik <nepto@platon.sk> + * @author Lubomir Host <rajo@platon.sk> + * @version \$Platon: libcfg+/src/shared.h,v 1.13 2004/01/12 06:03:09 nepto Exp $ + * @date 2001-2004 + */ + +#ifndef _PLATON_CFG_SHARED_H +#define _PLATON_CFG_SHARED_H + +/** + * Free current variables (cur_opt, cur_arg) in context + * and sets cur_opt_type to CFG_NONE_OPTION. + * + * @param con initialized context with initialized current variables + * @return void + */ +void __cfg_free_currents(const CFG_CONTEXT con); + +/** + * Process current option and argument. It suppose that in context con + * are cur_opt, cur_arg and cur_type set. + * + * @param con initialized context + * @param ret_val option return value (val) @see cfg_context + * @param arg_used if option argument was used + * @return CFG_OK on success, CFG_ERROR_* on error + */ +int __cfg_process_currents(const CFG_CONTEXT con, int *ret_val, int *arg_used); + +/** + * Allocate and initialize variables cur_opt and cur_arg in initialized + * command line context according to con->argv[con->cur_idx]. + * + * @param con initialized command line context + * @return CFG_OK on success, CFG_ERR_NOMEM on not enough memory error + */ +int __cfg_cmdline_set_currents(const CFG_CONTEXT con); + +/** + * Allocate and initialize variables cur_opt and cur_arg in initialized + * config file context according to input string (parameter buf). + * + * @param con initialized command line context + * @param buf input string + * @return CFG_OK on success, CFG_ERR_NOMEM on not enough memory error + */ +int __cfg_cfgfile_set_currents(const CFG_CONTEXT con, char *buf); + +#endif /* #ifndef _PLATON_CFG_SHARED_H */ + 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); |