• Main Page
  • Related Pages
  • Data Structures
  • Files
  • File List
  • Globals

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 "cmd_ln.h"
00079 #include "err.h"
00080 #include "ckd_alloc.h"
00081 #include "hash_table.h"
00082 #include "case.h"
00083 #include "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 
00244     /* No definitions, do nothing. */
00245     if (defn == NULL)
00246         return;
00247     if (fp == NULL)
00248         return;
00249 
00250     /* Find max lengths of name and default value fields, and #entries in defn */
00251     n = arg_strlen(defn, &namelen, &deflen);
00252     /*    E_INFO("String length %d. Name length %d, Default Length %d\n",n, namelen, deflen); */
00253     namelen = namelen & 0xfffffff8;     /* Previous tab position */
00254     deflen = deflen & 0xfffffff8;       /* Previous tab position */
00255 
00256     fprintf(fp, "[NAME]");
00257     for (l = strlen("[NAME]"); l < namelen; l += 8)
00258         fprintf(fp, "\t");
00259     fprintf(fp, "\t[DEFLT]");
00260     for (l = strlen("[DEFLT]"); l < deflen; l += 8)
00261         fprintf(fp, "\t");
00262 
00263     if (doc) {
00264         fprintf(fp, "\t[DESCR]\n");
00265     }
00266     else {
00267         fprintf(fp, "\t[VALUE]\n");
00268     }
00269 
00270     /* Print current configuration, sorted by name */
00271     pos = arg_sort(defn, n);
00272     for (i = 0; i < n; i++) {
00273         fprintf(fp, "%s", pos[i]->name);
00274         for (l = strlen(pos[i]->name); l < namelen; l += 8)
00275             fprintf(fp, "\t");
00276 
00277         fprintf(fp, "\t");
00278         if (pos[i]->deflt) {
00279             fprintf(fp, "%s", pos[i]->deflt);
00280             l = strlen(pos[i]->deflt);
00281         }
00282         else
00283             l = 0;
00284         for (; l < deflen; l += 8)
00285             fprintf(fp, "\t");
00286 
00287         fprintf(fp, "\t");
00288         if (doc) {
00289             if (pos[i]->doc)
00290                 fprintf(fp, "%s", pos[i]->doc);
00291         }
00292         else {
00293             vp = cmd_ln_access_r(cmdln, pos[i]->name);
00294             if (vp) {
00295                 switch (pos[i]->type) {
00296                 case ARG_INTEGER:
00297                 case REQARG_INTEGER:
00298                     fprintf(fp, "%ld", vp->i);
00299                     break;
00300                 case ARG_FLOATING:
00301                 case REQARG_FLOATING:
00302                     fprintf(fp, "%e", vp->fl);
00303                     break;
00304                 case ARG_STRING:
00305                 case REQARG_STRING:
00306                     if (vp->ptr)
00307                         fprintf(fp, "%s", (char *)vp->ptr);
00308                     break;
00309                 case ARG_BOOLEAN:
00310                 case REQARG_BOOLEAN:
00311                     fprintf(fp, "%s", vp->i ? "yes" : "no");
00312                     break;
00313                 default:
00314                     E_ERROR("Unknown argument type: %d\n", pos[i]->type);
00315                 }
00316             }
00317         }
00318 
00319         fprintf(fp, "\n");
00320     }
00321     ckd_free(pos);
00322 
00323     fprintf(fp, "\n");
00324     fflush(fp);
00325 }
00326 
00327 static cmd_ln_val_t *
00328 cmd_ln_val_init(int t, const char *str)
00329 {
00330     cmd_ln_val_t *v;
00331     anytype_t val;
00332     char *e_str;
00333 
00334     if (!str) {
00335         /* For lack of a better default value. */
00336         memset(&val, 0, sizeof(val));
00337     }
00338     else {
00339         int valid = 1;
00340         e_str = arg_resolve_env(str);
00341 
00342         switch (t) {
00343         case ARG_INTEGER:
00344         case REQARG_INTEGER:
00345             if (sscanf(e_str, "%ld", &val.i) != 1)
00346                 valid = 0;
00347             break;
00348         case ARG_FLOATING:
00349         case REQARG_FLOATING:
00350             if (e_str == NULL || e_str[0] == 0)
00351                 valid = 0;
00352             val.fl = atof_c(e_str);
00353             break;
00354         case ARG_BOOLEAN:
00355         case REQARG_BOOLEAN:
00356             if ((e_str[0] == 'y') || (e_str[0] == 't') ||
00357                 (e_str[0] == 'Y') || (e_str[0] == 'T') || (e_str[0] == '1')) {
00358                 val.i = TRUE;
00359             }
00360             else if ((e_str[0] == 'n') || (e_str[0] == 'f') ||
00361                      (e_str[0] == 'N') || (e_str[0] == 'F') |
00362                      (e_str[0] == '0')) {
00363                 val.i = FALSE;
00364             }
00365             else {
00366                 E_ERROR("Unparsed boolean value '%s'\n", str);
00367                 valid = 0;
00368             }
00369             break;
00370         case ARG_STRING:
00371         case REQARG_STRING:
00372             val.ptr = ckd_salloc(e_str);
00373             break;
00374         default:
00375             E_ERROR("Unknown argument type: %d\n", t);
00376             valid = 0;
00377         }
00378 
00379         ckd_free(e_str);
00380         if (valid == 0)
00381             return NULL;
00382     }
00383 
00384     v = ckd_calloc(1, sizeof(*v));
00385     memcpy(v, &val, sizeof(val));
00386     v->type = t;
00387 
00388     return v;
00389 }
00390 
00391 /*
00392  * Handles option parsing for cmd_ln_parse_file_r() and cmd_ln_init()
00393  * also takes care of storing argv.
00394  * DO NOT call it from cmd_ln_parse_r()
00395  */
00396 static cmd_ln_t *
00397 parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict)
00398 {
00399     cmd_ln_t *new_cmdln;
00400 
00401     new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict);
00402     /* If this failed then clean up and return NULL. */
00403     if (new_cmdln == NULL) {
00404         int32 i;
00405         for (i = 0; i < argc; ++i)
00406             ckd_free(argv[i]);
00407         ckd_free(argv);
00408         return NULL;
00409     }
00410 
00411     /* Otherwise, we need to add the contents of f_argv to the new object. */
00412     if (new_cmdln == cmdln) {
00413         /* If we are adding to a previously passed-in cmdln, then
00414          * store our allocated strings in its f_argv. */
00415         new_cmdln->f_argv = ckd_realloc(new_cmdln->f_argv,
00416                                         (new_cmdln->f_argc + argc)
00417                                         * sizeof(*new_cmdln->f_argv));
00418         memcpy(new_cmdln->f_argv + new_cmdln->f_argc, argv,
00419                argc * sizeof(*argv));
00420         ckd_free(argv);
00421         new_cmdln->f_argc += argc;
00422     }
00423     else {
00424         /* Otherwise, store f_argc and f_argv. */
00425         new_cmdln->f_argc = argc;
00426         new_cmdln->f_argv = argv;
00427     }
00428 
00429     return new_cmdln;
00430 }
00431 
00432 void
00433 cmd_ln_val_free(cmd_ln_val_t *val)
00434 {
00435     if (val->type & ARG_STRING)
00436         ckd_free(val->val.ptr);
00437     ckd_free(val);
00438 }
00439 
00440 cmd_ln_t *
00441 cmd_ln_get(void)
00442 {
00443     return global_cmdln;
00444 }
00445 
00446 void
00447 cmd_ln_appl_enter(int argc, char *argv[],
00448                   const char *default_argfn,
00449                   const arg_t * defn)
00450 {
00451     /* Look for default or specified arguments file */
00452     const char *str;
00453 
00454     str = NULL;
00455 
00456     if ((argc == 2) && (strcmp(argv[1], "help") == 0)) {
00457         cmd_ln_print_help(stderr, defn);
00458         exit(1);
00459     }
00460 
00461     if ((argc == 2) && (argv[1][0] != '-'))
00462         str = argv[1];
00463     else if (argc == 1) {
00464         FILE *fp;
00465         E_INFO("Looking for default argument file: %s\n", default_argfn);
00466 
00467         if ((fp = fopen(default_argfn, "r")) == NULL) {
00468             E_INFO("Can't find default argument file %s.\n",
00469                    default_argfn);
00470         }
00471         else {
00472             str = default_argfn;
00473         }
00474         if (fp != NULL)
00475             fclose(fp);
00476     }
00477 
00478 
00479     if (str) {
00480         /* Build command line argument list from file */
00481         E_INFO("Parsing command lines from file %s\n", str);
00482         if (cmd_ln_parse_file(defn, str, TRUE)) {
00483             E_INFOCONT("Usage:\n");
00484             E_INFOCONT("\t%s argument-list, or\n", argv[0]);
00485             E_INFOCONT("\t%s [argument-file] (default file: . %s)\n\n",
00486                     argv[0], default_argfn);
00487             cmd_ln_print_help(stderr, defn);
00488             exit(1);
00489         }
00490     }
00491     else {
00492         cmd_ln_parse(defn, argc, argv, TRUE);
00493     }
00494 }
00495 
00496 void
00497 cmd_ln_appl_exit()
00498 {
00499     cmd_ln_free();
00500 }
00501 
00502 
00503 cmd_ln_t *
00504 cmd_ln_parse_r(cmd_ln_t *inout_cmdln, const arg_t * defn, int32 argc, char *argv[], int strict)
00505 {
00506     int32 i, j, n;
00507     hash_table_t *defidx = NULL;
00508     cmd_ln_t *cmdln;
00509 
00510     /* Echo command line */
00511 #ifndef _WIN32_WCE
00512     E_INFO("Parsing command line:\n");
00513     for (i = 0; i < argc; i++) {
00514         if (argv[i][0] == '-')
00515             E_INFOCONT("\\\n\t");
00516         E_INFOCONT("%s ", argv[i]);
00517     }
00518     E_INFOCONT("\n\n");
00519     fflush(stderr);
00520 #endif
00521 
00522     /* Construct command-line object */
00523     if (inout_cmdln == NULL) {
00524         cmdln = ckd_calloc(1, sizeof(*cmdln));
00525         cmdln->refcount = 1;
00526     }
00527     else
00528         cmdln = inout_cmdln;
00529 
00530     /* Build a hash table for argument definitions */
00531     defidx = hash_table_new(50, 0);
00532     if (defn) {
00533         for (n = 0; defn[n].name; n++) {
00534             void *v;
00535 
00536             v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]);
00537             if (strict && (v != &defn[n])) {
00538                 E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name);
00539                 goto error;
00540             }
00541         }
00542     }
00543     else {
00544         /* No definitions. */
00545         n = 0;
00546     }
00547 
00548     /* Allocate memory for argument values */
00549     if (cmdln->ht == NULL)
00550         cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ );
00551 
00552     /* Parse command line arguments (name-value pairs); skip argv[0] if argc is odd */
00553     for (j = argc % 2; j < argc; j += 2) {
00554         arg_t *argdef;
00555         cmd_ln_val_t *val;
00556         void *v;
00557 
00558         if (j + 1 >= argc) {
00559             cmd_ln_print_help_r(cmdln, stderr, defn);
00560             E_ERROR("Argument value for '%s' missing\n", argv[j]);
00561             goto error;
00562         }
00563         if (hash_table_lookup(defidx, argv[j], &v) < 0) {
00564             if (strict) {
00565                 E_ERROR("Unknown argument name '%s'\n", argv[j]);
00566                 goto error;
00567             }
00568             else if (defn == NULL)
00569                 v = NULL;
00570             else
00571                 continue;
00572         }
00573         argdef = v;
00574 
00575         /* Enter argument value */
00576         if (argdef == NULL)
00577             val = cmd_ln_val_init(ARG_STRING, argv[j + 1]);
00578         else {
00579             if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) {
00580                 cmd_ln_print_help_r(cmdln, stderr, defn);
00581                 E_ERROR("Bad argument value for %s: %s\n", argv[j],
00582                         argv[j + 1]);
00583                 goto error;
00584             }
00585         }
00586 
00587         if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) != (void *)val) {
00588             if (strict) {
00589                 cmd_ln_val_free(val);
00590                 E_ERROR("Duplicate argument name in arguments: %s\n",
00591                         argdef->name);
00592                 goto error;
00593             }
00594             else {
00595                 v = hash_table_replace(cmdln->ht, argv[j], (void *)val);
00596                 cmd_ln_val_free((cmd_ln_val_t *)v);
00597             }
00598         }
00599     }
00600 
00601     /* Fill in default values, if any, for unspecified arguments */
00602     for (i = 0; i < n; i++) {
00603         cmd_ln_val_t *val;
00604         void *v;
00605 
00606         if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) {
00607             if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) {
00608                 E_ERROR
00609                     ("Bad default argument value for %s: %s\n",
00610                      defn[i].name, defn[i].deflt);
00611                 goto error;
00612             }
00613             hash_table_enter(cmdln->ht, defn[i].name, (void *)val);
00614         }
00615     }
00616 
00617     /* Check for required arguments; exit if any missing */
00618     j = 0;
00619     for (i = 0; i < n; i++) {
00620         if (defn[i].type & ARG_REQUIRED) {
00621             void *v;
00622             if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0)
00623                 E_ERROR("Missing required argument %s\n", defn[i].name);
00624         }
00625     }
00626     if (j > 0) {
00627         cmd_ln_print_help_r(cmdln, stderr, defn);
00628         goto error;
00629     }
00630 
00631     if (strict && argc == 1) {
00632         E_ERROR("No arguments given, exiting\n");
00633         cmd_ln_print_help_r(cmdln, stderr, defn);
00634         goto error;
00635     }
00636 
00637 #ifndef _WIN32_WCE
00638     /* Print configuration */
00639     E_INFOCONT("Current configuration:\n");
00640     arg_dump_r(cmdln, err_get_logfp(), defn, 0);
00641 #endif
00642     hash_table_free(defidx);
00643     return cmdln;
00644 
00645   error:
00646     if (defidx)
00647         hash_table_free(defidx);
00648     if (inout_cmdln == NULL)
00649         cmd_ln_free_r(cmdln);
00650     E_ERROR("cmd_ln_parse_r failed\n");
00651     return NULL;
00652 }
00653 
00654 cmd_ln_t *
00655 cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)
00656 {
00657     va_list args;
00658     const char *arg, *val;
00659     char **f_argv;
00660     int32 f_argc;
00661 
00662     va_start(args, strict);
00663     f_argc = 0;
00664     while ((arg = va_arg(args, const char *))) {
00665         ++f_argc;
00666         val = va_arg(args, const char*);
00667         if (val == NULL) {
00668             E_ERROR("Number of arguments must be even!\n");
00669             return NULL;
00670         }
00671         ++f_argc;
00672     }
00673     va_end(args);
00674 
00675     /* Now allocate f_argv */
00676     f_argv = ckd_calloc(f_argc, sizeof(*f_argv));
00677     va_start(args, strict);
00678     f_argc = 0;
00679     while ((arg = va_arg(args, const char *))) {
00680         f_argv[f_argc] = ckd_salloc(arg);
00681         ++f_argc;
00682         val = va_arg(args, const char*);
00683         f_argv[f_argc] = ckd_salloc(val);
00684         ++f_argc;
00685     }
00686     va_end(args);
00687 
00688     return parse_options(inout_cmdln, defn, f_argc, f_argv, strict);
00689 }
00690 
00691 int
00692 cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict)
00693 {
00694     cmd_ln_t *cmdln;
00695 
00696     cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict);
00697     if (cmdln == NULL) {
00698         /* Old, bogus behaviour... */
00699         E_ERROR("cmd_ln_parse failed, forced exit\n");
00700         exit(-1);
00701     }
00702     /* Initialize global_cmdln if not present. */
00703     if (global_cmdln == NULL) {
00704         global_cmdln = cmdln;
00705     }
00706     return 0;
00707 }
00708 
00709 cmd_ln_t *
00710 cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict)
00711 {
00712     FILE *file;
00713     int argc;
00714     int argv_size;
00715     char *str;
00716     int arg_max_length = 512;
00717     int len = 0;
00718     int quoting, ch;
00719     char **f_argv;
00720     int rv = 0;
00721     const char separator[] = " \t\r\n";
00722 
00723     if ((file = fopen(filename, "r")) == NULL) {
00724         E_ERROR("Cannot open configuration file %s for reading\n",
00725                 filename);
00726         return NULL;
00727     }
00728 
00729     ch = fgetc(file);
00730     /* Skip to the next interesting character */
00731     for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
00732 
00733     if (ch == EOF) {
00734         fclose(file);
00735         return NULL;
00736     }
00737 
00738     /*
00739      * Initialize default argv, argc, and argv_size.
00740      */
00741     argv_size = 10;
00742     argc = 0;
00743     f_argv = ckd_calloc(argv_size, sizeof(char *));
00744     /* Silently make room for \0 */
00745     str = ckd_calloc(arg_max_length + 1, sizeof(char));
00746     quoting = 0;
00747 
00748     do {
00749         /* Handle arguments that are commented out */
00750         if (len == 0 && argc % 2 == 0) {
00751             while (ch == '#') {
00752                 /* Skip everything until newline */
00753                 for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ;
00754                 /* Skip to the next interesting character */
00755                 for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
00756             }
00757 
00758             /* Check if we are at the last line (without anything interesting in it) */
00759             if (ch == EOF)
00760                 break;
00761         }
00762 
00763         /* Handle quoted arguments */
00764         if (ch == '"' || ch == '\'') {
00765             if (quoting == ch) /* End a quoted section with the same type */
00766                 quoting = 0;
00767             else if (quoting) {
00768                 E_ERROR("Nesting quotations is not supported!\n");
00769                 rv = 1;
00770                 break;
00771             }
00772             else
00773                 quoting = ch; /* Start a quoted section */
00774         }
00775         else if (ch == EOF || (!quoting && strchr(separator, ch))) {
00776             /* Reallocate argv so it is big enough to contain all the arguments */
00777             if (argc >= argv_size) {
00778                 char **tmp_argv;
00779                 if (!(tmp_argv =
00780                        ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) {
00781                     rv = 1;
00782                     break;
00783                 }
00784                 f_argv = tmp_argv;
00785                 argv_size *= 2;
00786             }
00787             /* Add the string to the list of arguments */
00788             f_argv[argc] = ckd_salloc(str);
00789             len = 0;
00790             str[0] = '\0';
00791             argc++;
00792 
00793             if (quoting)
00794                 E_WARN("Unclosed quotation, having EOF close it...\n");
00795 
00796             /* Skip to the next interesting character */
00797             for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
00798 
00799             if (ch == EOF)
00800                 break;
00801 
00802             /* We already have the next character */
00803             continue;
00804         }
00805         else {
00806             if (len >= arg_max_length) {
00807                 /* Make room for more chars (including the \0 !) */
00808                 char *tmp_str = str;
00809                 if ((tmp_str = ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) {
00810                     rv = 1;
00811                     break;
00812                 }
00813                 str = tmp_str;
00814                 arg_max_length *= 2;
00815             }
00816             /* Add the char to the argument string */
00817             str[len++] = ch;
00818             /* Always null terminate */
00819             str[len] = '\0';
00820         }
00821 
00822         ch = fgetc(file);
00823     } while (1);
00824 
00825     fclose(file);
00826 
00827     ckd_free(str);
00828 
00829     if (rv) {
00830         for (ch = 0; ch < argc; ++ch)
00831             ckd_free(f_argv[ch]);
00832         ckd_free(f_argv);
00833         return NULL;
00834     }
00835 
00836     return parse_options(inout_cmdln, defn, argc, f_argv, strict);
00837 }
00838 
00839 int
00840 cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict)
00841 {
00842     cmd_ln_t *cmdln;
00843 
00844     cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict);
00845     if (cmdln == NULL) {
00846         return -1;
00847     }
00848     /* Initialize global_cmdln if not present. */
00849     if (global_cmdln == NULL) {
00850         global_cmdln = cmdln;
00851     }
00852     return 0;
00853 }
00854 
00855 void
00856 cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE * fp, arg_t const* defn)
00857 {
00858     if (defn == NULL)
00859         return;
00860     fprintf(fp, "Arguments list definition:\n");
00861     arg_dump_r(cmdln, fp, defn, 1);
00862     fflush(fp);
00863 }
00864 
00865 int
00866 cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name)
00867 {
00868     void *val;
00869     if (cmdln == NULL)
00870         return FALSE;
00871     return (hash_table_lookup(cmdln->ht, name, &val) == 0);
00872 }
00873 
00874 anytype_t *
00875 cmd_ln_access_r(cmd_ln_t *cmdln, const char *name)
00876 {
00877     void *val;
00878     if (hash_table_lookup(cmdln->ht, name, &val) < 0) {
00879         E_ERROR("Unknown argument: %s\n", name);
00880         return NULL;
00881     }
00882     return (anytype_t *)val;
00883 }
00884 
00885 char const *
00886 cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
00887 {
00888     anytype_t *val;
00889     val = cmd_ln_access_r(cmdln, name);
00890     if (val == NULL)
00891         return NULL;
00892     return (char const *)val->ptr;
00893 }
00894 
00895 long
00896 cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
00897 {
00898     anytype_t *val;
00899     val = cmd_ln_access_r(cmdln, name);
00900     if (val == NULL)
00901         return 0L;
00902     return val->i;
00903 }
00904 
00905 double
00906 cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
00907 {
00908     anytype_t *val;
00909     val = cmd_ln_access_r(cmdln, name);
00910     if (val == NULL)
00911         return 0.0;
00912     return val->fl;
00913 }
00914 
00915 void
00916 cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
00917 {
00918     anytype_t *val;
00919     val = cmd_ln_access_r(cmdln, name);
00920     if (val == NULL) {
00921         E_ERROR("Unknown argument: %s\n", name);
00922         return;
00923     }
00924     ckd_free(val->ptr);
00925     if (str == NULL)
00926         val->ptr = NULL;
00927     else
00928         val->ptr = ckd_salloc(str);
00929 }
00930 
00931 void
00932 cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
00933 {
00934     anytype_t *val;
00935     val = cmd_ln_access_r(cmdln, name);
00936     if (val == NULL) {
00937         E_ERROR("Unknown argument: %s\n", name);
00938         return;
00939     }
00940     val->i = iv;
00941 }
00942 
00943 void
00944 cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
00945 {
00946     anytype_t *val;
00947     val = cmd_ln_access_r(cmdln, name);
00948     if (val == NULL) {
00949         E_ERROR("Unknown argument: %s\n", name);
00950         return;
00951     }
00952     val->fl = fv;
00953 }
00954 
00955 cmd_ln_t *
00956 cmd_ln_retain(cmd_ln_t *cmdln)
00957 {
00958     ++cmdln->refcount;
00959     return cmdln;
00960 }
00961 
00962 int
00963 cmd_ln_free_r(cmd_ln_t *cmdln)
00964 {
00965     if (cmdln == NULL)
00966         return 0;
00967     if (--cmdln->refcount > 0)
00968         return cmdln->refcount;
00969 
00970     if (cmdln->ht) {
00971         glist_t entries;
00972         gnode_t *gn;
00973         int32 n;
00974 
00975         entries = hash_table_tolist(cmdln->ht, &n);
00976         for (gn = entries; gn; gn = gnode_next(gn)) {
00977             hash_entry_t *e = gnode_ptr(gn);
00978             cmd_ln_val_free((cmd_ln_val_t *)e->val);
00979         }
00980         glist_free(entries);
00981         hash_table_free(cmdln->ht);
00982         cmdln->ht = NULL;
00983     }
00984 
00985     if (cmdln->f_argv) {
00986         int32 i;
00987         for (i = 0; i < cmdln->f_argc; ++i) {
00988             ckd_free(cmdln->f_argv[i]);
00989         }
00990         ckd_free(cmdln->f_argv);
00991         cmdln->f_argv = NULL;
00992         cmdln->f_argc = 0;
00993     }
00994     ckd_free(cmdln);
00995     return 0;
00996 }
00997 
00998 void
00999 cmd_ln_free(void)
01000 {
01001     cmd_ln_free_r(global_cmdln);
01002     global_cmdln = NULL;
01003 }

Generated on Mon Aug 29 2011 for SphinxBase by  doxygen 1.7.1