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

Generated on Fri Jan 14 2011 for SphinxBase by  doxygen 1.7.1