SphinxBase 0.6

src/libsphinxbase/util/cmd_ln.c

00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
00002 /* ====================================================================
00003  * Copyright (c) 1999-2004 Carnegie Mellon University.  All rights
00004  * reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer. 
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * This work was supported in part by funding from the Defense Advanced 
00019  * Research Projects Agency and the National Science Foundation of the 
00020  * United States of America, and the CMU Sphinx Speech Consortium.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
00023  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00024  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00025  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
00026  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
00028  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
00029  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
00030  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
00031  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
00032  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * ====================================================================
00035  *
00036  */
00037 /*
00038  * cmd_ln.c -- Command line argument parsing.
00039  *
00040  * **********************************************
00041  * CMU ARPA Speech Project
00042  *
00043  * Copyright (c) 1999 Carnegie Mellon University.
00044  * ALL RIGHTS RESERVED.
00045  * **********************************************
00046  * 
00047  * HISTORY
00048  * 
00049  * 10-Sep-1998  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00050  *              Changed strcasecmp() call in cmp_name() to strcmp_nocase() call.
00051  * 
00052  * 15-Jul-1997  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00053  *              Added required arguments handling.
00054  * 
00055  * 07-Dec-96    M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
00056  *              Created, based on Eric's implementation.  Basically, combined several
00057  *              functions into one, eliminated validation, and simplified the interface.
00058  */
00059 
00060 
00061 #include <stdio.h>
00062 #include <stdlib.h>
00063 #include <string.h>
00064 #include <assert.h>
00065 
00066 #ifdef _MSC_VER
00067 #pragma warning (disable: 4996 4018)
00068 #endif
00069 
00070 #ifdef HAVE_CONFIG_H
00071 #include <config.h>
00072 #endif
00073 
00074 #ifdef HAVE_UNISTD_H
00075 #include <unistd.h>
00076 #endif
00077 
00078 #include "sphinxbase/cmd_ln.h"
00079 #include "sphinxbase/err.h"
00080 #include "sphinxbase/ckd_alloc.h"
00081 #include "sphinxbase/hash_table.h"
00082 #include "sphinxbase/case.h"
00083 #include "sphinxbase/strfuncs.h"
00084 
00085 typedef struct cmd_ln_val_s {
00086     anytype_t val;
00087     int type;
00088 } cmd_ln_val_t;
00089 
00090 struct cmd_ln_s {
00091     int refcount;
00092     hash_table_t *ht;
00093     char **f_argv;
00094     uint32 f_argc;
00095 };
00096 
00098 cmd_ln_t *global_cmdln;
00099 static void arg_dump_r(cmd_ln_t *cmdln, FILE * fp, arg_t const *defn, int32 doc);
00100 static cmd_ln_t * parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict);
00101 
00102 /*
00103  * Find max length of name and default fields in the given defn array.
00104  * Return #items in defn array.
00105  */
00106 static int32
00107 arg_strlen(const arg_t * defn, int32 * namelen, int32 * deflen)
00108 {
00109     int32 i, l;
00110 
00111     *namelen = *deflen = 0;
00112     for (i = 0; defn[i].name; i++) {
00113         l = strlen(defn[i].name);
00114         if (*namelen < l)
00115             *namelen = l;
00116 
00117         if (defn[i].deflt)
00118             l = strlen(defn[i].deflt);
00119         else
00120             l = strlen("(null)");
00121         /*      E_INFO("string default, %s , name %s, length %d\n",defn[i].deflt,defn[i].name,l); */
00122         if (*deflen < l)
00123             *deflen = l;
00124     }
00125 
00126     return i;
00127 }
00128 
00129 
00130 static int32
00131 cmp_name(const void *a, const void *b)
00132 {
00133     return (strcmp_nocase
00134             ((* (arg_t**) a)->name,
00135              (* (arg_t**) b)->name));
00136 }
00137 
00138 static const arg_t **
00139 arg_sort(const arg_t * defn, int32 n)
00140 {
00141     const arg_t ** pos;
00142     int32 i;
00143 
00144     pos = (const arg_t **) ckd_calloc(n, sizeof(arg_t *));
00145     for (i = 0; i < n; ++i)
00146         pos[i] = &defn[i];
00147     qsort(pos, n, sizeof(arg_t *), cmp_name);
00148 
00149     return pos;
00150 }
00151 
00152 static size_t
00153 strnappend(char **dest, size_t *dest_allocation, 
00154        const char *source, size_t n)
00155 {
00156     size_t source_len, required_allocation;
00157 
00158     if (dest == NULL || dest_allocation == NULL)
00159         return -1;
00160     if (*dest == NULL && *dest_allocation != 0)
00161         return -1;
00162     if (source == NULL)
00163         return *dest_allocation;
00164 
00165     source_len = strlen(source);
00166     if (n && n < source_len)
00167         source_len = n;
00168 
00169     required_allocation = (*dest ? strlen(*dest) : 0) + source_len + 1;
00170     if (*dest_allocation < required_allocation) {
00171         if (*dest_allocation == 0) {
00172             *dest = ckd_calloc(required_allocation * 2, 1);
00173         } else {
00174             *dest = ckd_realloc(*dest, required_allocation * 2);
00175         }
00176         *dest_allocation = required_allocation * 2;
00177     } 
00178 
00179     strncat(*dest, source, source_len);
00180 
00181     return *dest_allocation;
00182 }
00183 
00184 static size_t
00185 strappend(char **dest, size_t *dest_allocation, 
00186        const char *source)
00187 {
00188     return strnappend(dest, dest_allocation, source, 0);
00189 }
00190 
00191 static char*
00192 arg_resolve_env(const char *str)
00193 {
00194     char *resolved_str = NULL;
00195     char env_name[100];
00196     const char *env_val;
00197     size_t alloced = 0;
00198     const char *i = str, *j;
00199 
00200     /* calculate required resolved_str size */
00201     do {
00202         j = strstr(i, "$(");
00203         if (j != NULL) {
00204             if (j != i) {
00205                 strnappend(&resolved_str, &alloced, i, j - i);
00206                 i = j;
00207             }
00208             j = strchr(i + 2, ')');
00209             if (j != NULL) {
00210                 if (j - (i + 2) < 100) {
00211                     strncpy(env_name, i + 2, j - (i + 2));
00212                     env_name[j - (i + 2)] = '\0';
00213                     #if !defined(_WIN32_WCE)
00214                     env_val = getenv(env_name);
00215                     if (env_val)
00216                         strappend(&resolved_str, &alloced, env_val);
00217                     #else
00218                     env_val = 0;
00219                     #endif
00220                 }
00221                 i = j + 1;
00222             } else {
00223                 /* unclosed, copy and skip */
00224                 j = i + 2;
00225                 strnappend(&resolved_str, &alloced, i, j - i);
00226                 i = j;
00227             }
00228         } else {
00229             strappend(&resolved_str, &alloced, i);
00230         }
00231     } while(j != NULL);
00232 
00233     return resolved_str;
00234 }
00235 
00236 static void
00237 arg_dump_r(cmd_ln_t *cmdln, FILE * fp, const arg_t * defn, int32 doc)
00238 {
00239     const arg_t **pos;
00240     int32 i, l, n;
00241     int32 namelen, deflen;
00242     anytype_t *vp;
00243     char const **array;
00244 
00245     /* No definitions, do nothing. */
00246     if (defn == NULL)
00247         return;
00248     if (fp == NULL)
00249         return;
00250 
00251     /* Find max lengths of name and default value fields, and #entries in defn */
00252     n = arg_strlen(defn, &namelen, &deflen);
00253     /*    E_INFO("String length %d. Name length %d, Default Length %d\n",n, namelen, deflen); */
00254     namelen = namelen & 0xfffffff8;     /* Previous tab position */
00255     deflen = deflen & 0xfffffff8;       /* Previous tab position */
00256 
00257     fprintf(fp, "[NAME]");
00258     for (l = strlen("[NAME]"); l < namelen; l += 8)
00259         fprintf(fp, "\t");
00260     fprintf(fp, "\t[DEFLT]");
00261     for (l = strlen("[DEFLT]"); l < deflen; l += 8)
00262         fprintf(fp, "\t");
00263 
00264     if (doc) {
00265         fprintf(fp, "\t[DESCR]\n");
00266     }
00267     else {
00268         fprintf(fp, "\t[VALUE]\n");
00269     }
00270 
00271     /* Print current configuration, sorted by name */
00272     pos = arg_sort(defn, n);
00273     for (i = 0; i < n; i++) {
00274         fprintf(fp, "%s", pos[i]->name);
00275         for (l = strlen(pos[i]->name); l < namelen; l += 8)
00276             fprintf(fp, "\t");
00277 
00278         fprintf(fp, "\t");
00279         if (pos[i]->deflt) {
00280             fprintf(fp, "%s", pos[i]->deflt);
00281             l = strlen(pos[i]->deflt);
00282         }
00283         else
00284             l = 0;
00285         for (; l < deflen; l += 8)
00286             fprintf(fp, "\t");
00287 
00288         fprintf(fp, "\t");
00289         if (doc) {
00290             if (pos[i]->doc)
00291                 fprintf(fp, "%s", pos[i]->doc);
00292         }
00293         else {
00294             vp = cmd_ln_access_r(cmdln, pos[i]->name);
00295             if (vp) {
00296                 switch (pos[i]->type) {
00297                 case ARG_INTEGER:
00298                 case REQARG_INTEGER:
00299                     fprintf(fp, "%ld", vp->i);
00300                     break;
00301                 case ARG_FLOATING:
00302                 case REQARG_FLOATING:
00303                     fprintf(fp, "%e", vp->fl);
00304                     break;
00305                 case ARG_STRING:
00306                 case REQARG_STRING:
00307                     if (vp->ptr)
00308                         fprintf(fp, "%s", (char *)vp->ptr);
00309                     break;
00310                 case ARG_STRING_LIST:
00311                     array = (char const**)vp->ptr;
00312                     if (array)
00313                         for (l = 0; array[l] != 0; l++) {
00314                             fprintf(fp, "%s,", array[l]);
00315                         }
00316                     break;
00317                 case ARG_BOOLEAN:
00318                 case REQARG_BOOLEAN:
00319                     fprintf(fp, "%s", vp->i ? "yes" : "no");
00320                     break;
00321                 default:
00322                     E_ERROR("Unknown argument type: %d\n", pos[i]->type);
00323                 }
00324             }
00325         }
00326 
00327         fprintf(fp, "\n");
00328     }
00329     ckd_free(pos);
00330 
00331     fprintf(fp, "\n");
00332     fflush(fp);
00333 }
00334 
00335 static char **
00336 parse_string_list(const char *str)
00337 {
00338     int count, i, j;
00339     const char *p;
00340     char ** result;
00341 
00342     p = str;
00343     count = 1;
00344     while (*p) {
00345         if (*p == ',')
00346             count++;
00347         p++;
00348     }
00349     /* Should end with NULL */
00350     result = (char **) ckd_calloc(count + 1, sizeof(char *));
00351     p = str;
00352     for (i = 0; i < count; i++) {
00353         for (j = 0; p[j] != ',' && p[j] != 0; j++);
00354         result[i] = ckd_calloc(j + 1, sizeof(char));
00355         strncpy( result[i], p, j);
00356         p = p + j + 1;
00357     }
00358     return result;
00359 }
00360 
00361 static cmd_ln_val_t *
00362 cmd_ln_val_init(int t, const char *str)
00363 {
00364     cmd_ln_val_t *v;
00365     anytype_t val;
00366     char *e_str;
00367 
00368     if (!str) {
00369         /* For lack of a better default value. */
00370         memset(&val, 0, sizeof(val));
00371     }
00372     else {
00373         int valid = 1;
00374         e_str = arg_resolve_env(str);
00375 
00376         switch (t) {
00377         case ARG_INTEGER:
00378         case REQARG_INTEGER:
00379             if (sscanf(e_str, "%ld", &val.i) != 1)
00380                 valid = 0;
00381             break;
00382         case ARG_FLOATING:
00383         case REQARG_FLOATING:
00384             if (e_str == NULL || e_str[0] == 0)
00385                 valid = 0;
00386             val.fl = atof_c(e_str);
00387             break;
00388         case ARG_BOOLEAN:
00389         case REQARG_BOOLEAN:
00390             if ((e_str[0] == 'y') || (e_str[0] == 't') ||
00391                 (e_str[0] == 'Y') || (e_str[0] == 'T') || (e_str[0] == '1')) {
00392                 val.i = TRUE;
00393             }
00394             else if ((e_str[0] == 'n') || (e_str[0] == 'f') ||
00395                      (e_str[0] == 'N') || (e_str[0] == 'F') |
00396                      (e_str[0] == '0')) {
00397                 val.i = FALSE;
00398             }
00399             else {
00400                 E_ERROR("Unparsed boolean value '%s'\n", str);
00401                 valid = 0;
00402             }
00403             break;
00404         case ARG_STRING:
00405         case REQARG_STRING:
00406             val.ptr = ckd_salloc(e_str);
00407             break;
00408         case ARG_STRING_LIST:
00409             val.ptr = parse_string_list(e_str);
00410             break;
00411         default:
00412             E_ERROR("Unknown argument type: %d\n", t);
00413             valid = 0;
00414         }
00415 
00416         ckd_free(e_str);
00417         if (valid == 0)
00418             return NULL;
00419     }
00420 
00421     v = ckd_calloc(1, sizeof(*v));
00422     memcpy(v, &val, sizeof(val));
00423     v->type = t;
00424 
00425     return v;
00426 }
00427 
00428 /*
00429  * Handles option parsing for cmd_ln_parse_file_r() and cmd_ln_init()
00430  * also takes care of storing argv.
00431  * DO NOT call it from cmd_ln_parse_r()
00432  */
00433 static cmd_ln_t *
00434 parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict)
00435 {
00436     cmd_ln_t *new_cmdln;
00437 
00438     new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict);
00439     /* If this failed then clean up and return NULL. */
00440     if (new_cmdln == NULL) {
00441         int32 i;
00442         for (i = 0; i < argc; ++i)
00443             ckd_free(argv[i]);
00444         ckd_free(argv);
00445         return NULL;
00446     }
00447 
00448     /* Otherwise, we need to add the contents of f_argv to the new object. */
00449     if (new_cmdln == cmdln) {
00450         /* If we are adding to a previously passed-in cmdln, then
00451          * store our allocated strings in its f_argv. */
00452         new_cmdln->f_argv = ckd_realloc(new_cmdln->f_argv,
00453                                         (new_cmdln->f_argc + argc)
00454                                         * sizeof(*new_cmdln->f_argv));
00455         memcpy(new_cmdln->f_argv + new_cmdln->f_argc, argv,
00456                argc * sizeof(*argv));
00457         ckd_free(argv);
00458         new_cmdln->f_argc += argc;
00459     }
00460     else {
00461         /* Otherwise, store f_argc and f_argv. */
00462         new_cmdln->f_argc = argc;
00463         new_cmdln->f_argv = argv;
00464     }
00465 
00466     return new_cmdln;
00467 }
00468 
00469 void
00470 cmd_ln_val_free(cmd_ln_val_t *val)
00471 {
00472     int i;
00473     if (val->type & ARG_STRING_LIST) {
00474         char ** array = (char **)val->val.ptr;
00475         if (array) {
00476             for (i = 0; array[i] != NULL; i++) {
00477                 ckd_free(array[i]);
00478             }
00479             ckd_free(array);
00480         }
00481     }
00482     if (val->type & ARG_STRING)
00483         ckd_free(val->val.ptr);
00484     ckd_free(val);
00485 }
00486 
00487 cmd_ln_t *
00488 cmd_ln_get(void)
00489 {
00490     return global_cmdln;
00491 }
00492 
00493 void
00494 cmd_ln_appl_enter(int argc, char *argv[],
00495                   const char *default_argfn,
00496                   const arg_t * defn)
00497 {
00498     /* Look for default or specified arguments file */
00499     const char *str;
00500 
00501     str = NULL;
00502 
00503     if ((argc == 2) && (strcmp(argv[1], "help") == 0)) {
00504         cmd_ln_print_help(stderr, defn);
00505         exit(1);
00506     }
00507 
00508     if ((argc == 2) && (argv[1][0] != '-'))
00509         str = argv[1];
00510     else if (argc == 1) {
00511         FILE *fp;
00512         E_INFO("Looking for default argument file: %s\n", default_argfn);
00513 
00514         if ((fp = fopen(default_argfn, "r")) == NULL) {
00515             E_INFO("Can't find default argument file %s.\n",
00516                    default_argfn);
00517         }
00518         else {
00519             str = default_argfn;
00520         }
00521         if (fp != NULL)
00522             fclose(fp);
00523     }
00524 
00525 
00526     if (str) {
00527         /* Build command line argument list from file */
00528         E_INFO("Parsing command lines from file %s\n", str);
00529         if (cmd_ln_parse_file(defn, str, TRUE)) {
00530             E_INFOCONT("Usage:\n");
00531             E_INFOCONT("\t%s argument-list, or\n", argv[0]);
00532             E_INFOCONT("\t%s [argument-file] (default file: . %s)\n\n",
00533                     argv[0], default_argfn);
00534             cmd_ln_print_help(stderr, defn);
00535             exit(1);
00536         }
00537     }
00538     else {
00539         cmd_ln_parse(defn, argc, argv, TRUE);
00540     }
00541 }
00542 
00543 void
00544 cmd_ln_appl_exit()
00545 {
00546     cmd_ln_free();
00547 }
00548 
00549 
00550 cmd_ln_t *
00551 cmd_ln_parse_r(cmd_ln_t *inout_cmdln, const arg_t * defn, int32 argc, char *argv[], int strict)
00552 {
00553     int32 i, j, n, argstart;
00554     hash_table_t *defidx = NULL;
00555     cmd_ln_t *cmdln;
00556     
00557     /* Construct command-line object */
00558     if (inout_cmdln == NULL) {
00559         cmdln = ckd_calloc(1, sizeof(*cmdln));
00560         cmdln->refcount = 1;
00561     }
00562     else
00563         cmdln = inout_cmdln;
00564 
00565     /* Build a hash table for argument definitions */
00566     defidx = hash_table_new(50, 0);
00567     if (defn) {
00568         for (n = 0; defn[n].name; n++) {
00569             void *v;
00570 
00571             v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]);
00572             if (strict && (v != &defn[n])) {
00573                 E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name);
00574                 goto error;
00575             }
00576         }
00577     }
00578     else {
00579         /* No definitions. */
00580         n = 0;
00581     }
00582 
00583     /* Allocate memory for argument values */
00584     if (cmdln->ht == NULL)
00585         cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ );
00586 
00587 
00588     /* skip argv[0] if it doesn't start with dash */
00589     argstart = 0;
00590     if (argc > 0 && argv[0][0] != '-') {
00591         argstart = 1;
00592     } 
00593 
00594     /* Parse command line arguments (name-value pairs) */
00595     for (j = argstart; j < argc; j += 2) {
00596         arg_t *argdef;
00597         cmd_ln_val_t *val;
00598         void *v;
00599 
00600         if (hash_table_lookup(defidx, argv[j], &v) < 0) {
00601             if (strict) {
00602                 E_ERROR("Unknown argument name '%s'\n", argv[j]);
00603                 goto error;
00604             }
00605             else if (defn == NULL)
00606                 v = NULL;
00607             else
00608                 continue;
00609         }
00610         argdef = v;
00611 
00612         /* Enter argument value */      
00613         if (j + 1 >= argc) {
00614             cmd_ln_print_help_r(cmdln, stderr, defn);
00615             E_ERROR("Argument value for '%s' missing\n", argv[j]);
00616             goto error;
00617         }
00618 
00619         if (argdef == NULL)
00620             val = cmd_ln_val_init(ARG_STRING, argv[j + 1]);
00621         else {
00622             if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) {
00623                 cmd_ln_print_help_r(cmdln, stderr, defn);
00624                 E_ERROR("Bad argument value for %s: %s\n", argv[j],
00625                         argv[j + 1]);
00626                 goto error;
00627             }
00628         }
00629 
00630         if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) != (void *)val) {
00631             if (strict) {
00632                 cmd_ln_val_free(val);
00633                 E_ERROR("Duplicate argument name in arguments: %s\n",
00634                         argdef->name);
00635                 goto error;
00636             }
00637             else {
00638                 v = hash_table_replace(cmdln->ht, argv[j], (void *)val);
00639                 cmd_ln_val_free((cmd_ln_val_t *)v);
00640             }
00641         }
00642     }
00643 
00644     /* Fill in default values, if any, for unspecified arguments */
00645     for (i = 0; i < n; i++) {
00646         cmd_ln_val_t *val;
00647         void *v;
00648 
00649         if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) {
00650             if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) {
00651                 E_ERROR
00652                     ("Bad default argument value for %s: %s\n",
00653                      defn[i].name, defn[i].deflt);
00654                 goto error;
00655             }
00656             hash_table_enter(cmdln->ht, defn[i].name, (void *)val);
00657         }
00658     }
00659 
00660     /* Check for required arguments; exit if any missing */
00661     j = 0;
00662     for (i = 0; i < n; i++) {
00663         if (defn[i].type & ARG_REQUIRED) {
00664             void *v;
00665             if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0)
00666                 E_ERROR("Missing required argument %s\n", defn[i].name);
00667         }
00668     }
00669     if (j > 0) {
00670         cmd_ln_print_help_r(cmdln, stderr, defn);
00671         goto error;
00672     }
00673 
00674     if (strict && argc == 1) {
00675         E_ERROR("No arguments given, available options are:\n");
00676         cmd_ln_print_help_r(cmdln, stderr, defn);
00677         if (defidx)
00678             hash_table_free(defidx);
00679         if (inout_cmdln == NULL)
00680             cmd_ln_free_r(cmdln);
00681         return NULL;
00682     }
00683 
00684 #ifndef _WIN32_WCE
00685     /* Set up logging. We need to do this earlier because we want to dump
00686      * the information to the configured log, not to the stderr. */
00687     if (cmd_ln_exists_r(cmdln, "-logfn") && cmd_ln_str_r(cmdln, "-logfn"))
00688         err_set_logfile(cmd_ln_str_r(cmdln, "-logfn"));
00689 
00690     /* Echo command line */
00691     E_INFO("Parsing command line:\n");
00692     for (i = 0; i < argc; i++) {
00693         if (argv[i][0] == '-')
00694             E_INFOCONT("\\\n\t");
00695         E_INFOCONT("%s ", argv[i]);
00696     }
00697     E_INFOCONT("\n\n");
00698     fflush(stderr);
00699 
00700     /* Print configuration */
00701     E_INFOCONT("Current configuration:\n");
00702     arg_dump_r(cmdln, err_get_logfp(), defn, 0);
00703 #endif
00704 
00705     hash_table_free(defidx);
00706     return cmdln;
00707 
00708   error:
00709     if (defidx)
00710         hash_table_free(defidx);
00711     if (inout_cmdln == NULL)
00712         cmd_ln_free_r(cmdln);
00713     E_ERROR("Failed to parse arguments list\n");
00714     return NULL;
00715 }
00716 
00717 cmd_ln_t *
00718 cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)
00719 {
00720     va_list args;
00721     const char *arg, *val;
00722     char **f_argv;
00723     int32 f_argc;
00724 
00725     va_start(args, strict);
00726     f_argc = 0;
00727     while ((arg = va_arg(args, const char *))) {
00728         ++f_argc;
00729         val = va_arg(args, const char*);
00730         if (val == NULL) {
00731             E_ERROR("Number of arguments must be even!\n");
00732             return NULL;
00733         }
00734         ++f_argc;
00735     }
00736     va_end(args);
00737 
00738     /* Now allocate f_argv */
00739     f_argv = ckd_calloc(f_argc, sizeof(*f_argv));
00740     va_start(args, strict);
00741     f_argc = 0;
00742     while ((arg = va_arg(args, const char *))) {
00743         f_argv[f_argc] = ckd_salloc(arg);
00744         ++f_argc;
00745         val = va_arg(args, const char*);
00746         f_argv[f_argc] = ckd_salloc(val);
00747         ++f_argc;
00748     }
00749     va_end(args);
00750 
00751     return parse_options(inout_cmdln, defn, f_argc, f_argv, strict);
00752 }
00753 
00754 int
00755 cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict)
00756 {
00757     cmd_ln_t *cmdln;
00758 
00759     cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict);
00760     if (cmdln == NULL) {
00761         /* Old, bogus behaviour... */
00762         E_ERROR("Failed to parse arguments list, forced exit\n");
00763         exit(-1);
00764     }
00765     /* Initialize global_cmdln if not present. */
00766     if (global_cmdln == NULL) {
00767         global_cmdln = cmdln;
00768     }
00769     return 0;
00770 }
00771 
00772 cmd_ln_t *
00773 cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict)
00774 {
00775     FILE *file;
00776     int argc;
00777     int argv_size;
00778     char *str;
00779     int arg_max_length = 512;
00780     int len = 0;
00781     int quoting, ch;
00782     char **f_argv;
00783     int rv = 0;
00784     const char separator[] = " \t\r\n";
00785 
00786     if ((file = fopen(filename, "r")) == NULL) {
00787         E_ERROR("Cannot open configuration file %s for reading\n",
00788                 filename);
00789         return NULL;
00790     }
00791 
00792     ch = fgetc(file);
00793     /* Skip to the next interesting character */
00794     for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
00795 
00796     if (ch == EOF) {
00797         fclose(file);
00798         return NULL;
00799     }
00800 
00801     /*
00802      * Initialize default argv, argc, and argv_size.
00803      */
00804     argv_size = 10;
00805     argc = 0;
00806     f_argv = ckd_calloc(argv_size, sizeof(char *));
00807     /* Silently make room for \0 */
00808     str = ckd_calloc(arg_max_length + 1, sizeof(char));
00809     quoting = 0;
00810 
00811     do {
00812         /* Handle arguments that are commented out */
00813         if (len == 0 && argc % 2 == 0) {
00814             while (ch == '#') {
00815                 /* Skip everything until newline */
00816                 for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ;
00817                 /* Skip to the next interesting character */
00818                 for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
00819             }
00820 
00821             /* Check if we are at the last line (without anything interesting in it) */
00822             if (ch == EOF)
00823                 break;
00824         }
00825 
00826         /* Handle quoted arguments */
00827         if (ch == '"' || ch == '\'') {
00828             if (quoting == ch) /* End a quoted section with the same type */
00829                 quoting = 0;
00830             else if (quoting) {
00831                 E_ERROR("Nesting quotations is not supported!\n");
00832                 rv = 1;
00833                 break;
00834             }
00835             else
00836                 quoting = ch; /* Start a quoted section */
00837         }
00838         else if (ch == EOF || (!quoting && strchr(separator, ch))) {
00839             /* Reallocate argv so it is big enough to contain all the arguments */
00840             if (argc >= argv_size) {
00841                 char **tmp_argv;
00842                 if (!(tmp_argv =
00843                        ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) {
00844                     rv = 1;
00845                     break;
00846                 }
00847                 f_argv = tmp_argv;
00848                 argv_size *= 2;
00849             }
00850             /* Add the string to the list of arguments */
00851             f_argv[argc] = ckd_salloc(str);
00852             len = 0;
00853             str[0] = '\0';
00854             argc++;
00855 
00856             if (quoting)
00857                 E_WARN("Unclosed quotation, having EOF close it...\n");
00858 
00859             /* Skip to the next interesting character */
00860             for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
00861 
00862             if (ch == EOF)
00863                 break;
00864 
00865             /* We already have the next character */
00866             continue;
00867         }
00868         else {
00869             if (len >= arg_max_length) {
00870                 /* Make room for more chars (including the \0 !) */
00871                 char *tmp_str = str;
00872                 if ((tmp_str = ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) {
00873                     rv = 1;
00874                     break;
00875                 }
00876                 str = tmp_str;
00877                 arg_max_length *= 2;
00878             }
00879             /* Add the char to the argument string */
00880             str[len++] = ch;
00881             /* Always null terminate */
00882             str[len] = '\0';
00883         }
00884 
00885         ch = fgetc(file);
00886     } while (1);
00887 
00888     fclose(file);
00889 
00890     ckd_free(str);
00891 
00892     if (rv) {
00893         for (ch = 0; ch < argc; ++ch)
00894             ckd_free(f_argv[ch]);
00895         ckd_free(f_argv);
00896         return NULL;
00897     }
00898 
00899     return parse_options(inout_cmdln, defn, argc, f_argv, strict);
00900 }
00901 
00902 int
00903 cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict)
00904 {
00905     cmd_ln_t *cmdln;
00906 
00907     cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict);
00908     if (cmdln == NULL) {
00909         return -1;
00910     }
00911     /* Initialize global_cmdln if not present. */
00912     if (global_cmdln == NULL) {
00913         global_cmdln = cmdln;
00914     }
00915     return 0;
00916 }
00917 
00918 void
00919 cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE * fp, arg_t const* defn)
00920 {
00921     if (defn == NULL)
00922         return;
00923     fprintf(fp, "Arguments list definition:\n");
00924     arg_dump_r(cmdln, fp, defn, 1);
00925     fflush(fp);
00926 }
00927 
00928 int
00929 cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name)
00930 {
00931     void *val;
00932     if (cmdln == NULL)
00933         return FALSE;
00934     return (hash_table_lookup(cmdln->ht, name, &val) == 0);
00935 }
00936 
00937 anytype_t *
00938 cmd_ln_access_r(cmd_ln_t *cmdln, const char *name)
00939 {
00940     void *val;
00941     if (hash_table_lookup(cmdln->ht, name, &val) < 0) {
00942         E_ERROR("Unknown argument: %s\n", name);
00943         return NULL;
00944     }
00945     return (anytype_t *)val;
00946 }
00947 
00948 char const *
00949 cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
00950 {
00951     anytype_t *val;
00952     val = cmd_ln_access_r(cmdln, name);
00953     if (val == NULL)
00954         return NULL;
00955     return (char const *)val->ptr;
00956 }
00957 
00958 char const **
00959 cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name)
00960 {
00961     anytype_t *val;
00962     val = cmd_ln_access_r(cmdln, name);
00963     if (val == NULL)
00964         return NULL;
00965     return (char const **)val->ptr;
00966 }
00967 
00968 long
00969 cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
00970 {
00971     anytype_t *val;
00972     val = cmd_ln_access_r(cmdln, name);
00973     if (val == NULL)
00974         return 0L;
00975     return val->i;
00976 }
00977 
00978 double
00979 cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
00980 {
00981     anytype_t *val;
00982     val = cmd_ln_access_r(cmdln, name);
00983     if (val == NULL)
00984         return 0.0;
00985     return val->fl;
00986 }
00987 
00988 void
00989 cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
00990 {
00991     anytype_t *val;
00992     val = cmd_ln_access_r(cmdln, name);
00993     if (val == NULL) {
00994         E_ERROR("Unknown argument: %s\n", name);
00995         return;
00996     }
00997     ckd_free(val->ptr);
00998     if (str == NULL)
00999         val->ptr = NULL;
01000     else
01001         val->ptr = ckd_salloc(str);
01002 }
01003 
01004 void
01005 cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
01006 {
01007     anytype_t *val;
01008     val = cmd_ln_access_r(cmdln, name);
01009     if (val == NULL) {
01010         E_ERROR("Unknown argument: %s\n", name);
01011         return;
01012     }
01013     val->i = iv;
01014 }
01015 
01016 void
01017 cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
01018 {
01019     anytype_t *val;
01020     val = cmd_ln_access_r(cmdln, name);
01021     if (val == NULL) {
01022         E_ERROR("Unknown argument: %s\n", name);
01023         return;
01024     }
01025     val->fl = fv;
01026 }
01027 
01028 cmd_ln_t *
01029 cmd_ln_retain(cmd_ln_t *cmdln)
01030 {
01031     ++cmdln->refcount;
01032     return cmdln;
01033 }
01034 
01035 int
01036 cmd_ln_free_r(cmd_ln_t *cmdln)
01037 {
01038     if (cmdln == NULL)
01039         return 0;
01040     if (--cmdln->refcount > 0)
01041         return cmdln->refcount;
01042 
01043     if (cmdln->ht) {
01044         glist_t entries;
01045         gnode_t *gn;
01046         int32 n;
01047 
01048         entries = hash_table_tolist(cmdln->ht, &n);
01049         for (gn = entries; gn; gn = gnode_next(gn)) {
01050             hash_entry_t *e = gnode_ptr(gn);
01051             cmd_ln_val_free((cmd_ln_val_t *)e->val);
01052         }
01053         glist_free(entries);
01054         hash_table_free(cmdln->ht);
01055         cmdln->ht = NULL;
01056     }
01057 
01058     if (cmdln->f_argv) {
01059         int32 i;
01060         for (i = 0; i < cmdln->f_argc; ++i) {
01061             ckd_free(cmdln->f_argv[i]);
01062         }
01063         ckd_free(cmdln->f_argv);
01064         cmdln->f_argv = NULL;
01065         cmdln->f_argc = 0;
01066     }
01067     ckd_free(cmdln);
01068     return 0;
01069 }
01070 
01071 void
01072 cmd_ln_free(void)
01073 {
01074     cmd_ln_free_r(global_cmdln);
01075     global_cmdln = NULL;
01076 }