SphinxBase 0.6
|
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 const** array = (char const **)val->val.ptr; 00475 if (array) { 00476 for (i = 0; array[i] != NULL; i++) { 00477 ckd_free(val->val.ptr); 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 /* Echo command line */ 00558 #ifndef _WIN32_WCE 00559 E_INFO("Parsing command line:\n"); 00560 for (i = 0; i < argc; i++) { 00561 if (argv[i][0] == '-') 00562 E_INFOCONT("\\\n\t"); 00563 E_INFOCONT("%s ", argv[i]); 00564 } 00565 E_INFOCONT("\n\n"); 00566 fflush(stderr); 00567 #endif 00568 00569 /* Construct command-line object */ 00570 if (inout_cmdln == NULL) { 00571 cmdln = ckd_calloc(1, sizeof(*cmdln)); 00572 cmdln->refcount = 1; 00573 } 00574 else 00575 cmdln = inout_cmdln; 00576 00577 /* Build a hash table for argument definitions */ 00578 defidx = hash_table_new(50, 0); 00579 if (defn) { 00580 for (n = 0; defn[n].name; n++) { 00581 void *v; 00582 00583 v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]); 00584 if (strict && (v != &defn[n])) { 00585 E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name); 00586 goto error; 00587 } 00588 } 00589 } 00590 else { 00591 /* No definitions. */ 00592 n = 0; 00593 } 00594 00595 /* Allocate memory for argument values */ 00596 if (cmdln->ht == NULL) 00597 cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ ); 00598 00599 00600 /* skip argv[0] if it doesn't start with dash */ 00601 argstart = 0; 00602 if (argc > 0 && argv[0][0] != '-') { 00603 argstart = 1; 00604 } 00605 00606 /* Parse command line arguments (name-value pairs) */ 00607 for (j = argstart; j < argc; j += 2) { 00608 arg_t *argdef; 00609 cmd_ln_val_t *val; 00610 void *v; 00611 00612 if (hash_table_lookup(defidx, argv[j], &v) < 0) { 00613 if (strict) { 00614 E_ERROR("Unknown argument name '%s'\n", argv[j]); 00615 goto error; 00616 } 00617 else if (defn == NULL) 00618 v = NULL; 00619 else 00620 continue; 00621 } 00622 argdef = v; 00623 00624 /* Enter argument value */ 00625 if (j + 1 >= argc) { 00626 cmd_ln_print_help_r(cmdln, stderr, defn); 00627 E_ERROR("Argument value for '%s' missing\n", argv[j]); 00628 goto error; 00629 } 00630 00631 if (argdef == NULL) 00632 val = cmd_ln_val_init(ARG_STRING, argv[j + 1]); 00633 else { 00634 if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) { 00635 cmd_ln_print_help_r(cmdln, stderr, defn); 00636 E_ERROR("Bad argument value for %s: %s\n", argv[j], 00637 argv[j + 1]); 00638 goto error; 00639 } 00640 } 00641 00642 if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) != (void *)val) { 00643 if (strict) { 00644 cmd_ln_val_free(val); 00645 E_ERROR("Duplicate argument name in arguments: %s\n", 00646 argdef->name); 00647 goto error; 00648 } 00649 else { 00650 v = hash_table_replace(cmdln->ht, argv[j], (void *)val); 00651 cmd_ln_val_free((cmd_ln_val_t *)v); 00652 } 00653 } 00654 } 00655 00656 /* Fill in default values, if any, for unspecified arguments */ 00657 for (i = 0; i < n; i++) { 00658 cmd_ln_val_t *val; 00659 void *v; 00660 00661 if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) { 00662 if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) { 00663 E_ERROR 00664 ("Bad default argument value for %s: %s\n", 00665 defn[i].name, defn[i].deflt); 00666 goto error; 00667 } 00668 hash_table_enter(cmdln->ht, defn[i].name, (void *)val); 00669 } 00670 } 00671 00672 /* Check for required arguments; exit if any missing */ 00673 j = 0; 00674 for (i = 0; i < n; i++) { 00675 if (defn[i].type & ARG_REQUIRED) { 00676 void *v; 00677 if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0) 00678 E_ERROR("Missing required argument %s\n", defn[i].name); 00679 } 00680 } 00681 if (j > 0) { 00682 cmd_ln_print_help_r(cmdln, stderr, defn); 00683 goto error; 00684 } 00685 00686 if (strict && argc == 1) { 00687 E_ERROR("No arguments given, exiting\n"); 00688 cmd_ln_print_help_r(cmdln, stderr, defn); 00689 goto error; 00690 } 00691 00692 #ifndef _WIN32_WCE 00693 /* Print configuration */ 00694 E_INFOCONT("Current configuration:\n"); 00695 arg_dump_r(cmdln, err_get_logfp(), defn, 0); 00696 #endif 00697 hash_table_free(defidx); 00698 return cmdln; 00699 00700 error: 00701 if (defidx) 00702 hash_table_free(defidx); 00703 if (inout_cmdln == NULL) 00704 cmd_ln_free_r(cmdln); 00705 E_ERROR("cmd_ln_parse_r failed\n"); 00706 return NULL; 00707 } 00708 00709 cmd_ln_t * 00710 cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...) 00711 { 00712 va_list args; 00713 const char *arg, *val; 00714 char **f_argv; 00715 int32 f_argc; 00716 00717 va_start(args, strict); 00718 f_argc = 0; 00719 while ((arg = va_arg(args, const char *))) { 00720 ++f_argc; 00721 val = va_arg(args, const char*); 00722 if (val == NULL) { 00723 E_ERROR("Number of arguments must be even!\n"); 00724 return NULL; 00725 } 00726 ++f_argc; 00727 } 00728 va_end(args); 00729 00730 /* Now allocate f_argv */ 00731 f_argv = ckd_calloc(f_argc, sizeof(*f_argv)); 00732 va_start(args, strict); 00733 f_argc = 0; 00734 while ((arg = va_arg(args, const char *))) { 00735 f_argv[f_argc] = ckd_salloc(arg); 00736 ++f_argc; 00737 val = va_arg(args, const char*); 00738 f_argv[f_argc] = ckd_salloc(val); 00739 ++f_argc; 00740 } 00741 va_end(args); 00742 00743 return parse_options(inout_cmdln, defn, f_argc, f_argv, strict); 00744 } 00745 00746 int 00747 cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict) 00748 { 00749 cmd_ln_t *cmdln; 00750 00751 cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict); 00752 if (cmdln == NULL) { 00753 /* Old, bogus behaviour... */ 00754 E_ERROR("cmd_ln_parse failed, forced exit\n"); 00755 exit(-1); 00756 } 00757 /* Initialize global_cmdln if not present. */ 00758 if (global_cmdln == NULL) { 00759 global_cmdln = cmdln; 00760 } 00761 return 0; 00762 } 00763 00764 cmd_ln_t * 00765 cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict) 00766 { 00767 FILE *file; 00768 int argc; 00769 int argv_size; 00770 char *str; 00771 int arg_max_length = 512; 00772 int len = 0; 00773 int quoting, ch; 00774 char **f_argv; 00775 int rv = 0; 00776 const char separator[] = " \t\r\n"; 00777 00778 if ((file = fopen(filename, "r")) == NULL) { 00779 E_ERROR("Cannot open configuration file %s for reading\n", 00780 filename); 00781 return NULL; 00782 } 00783 00784 ch = fgetc(file); 00785 /* Skip to the next interesting character */ 00786 for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; 00787 00788 if (ch == EOF) { 00789 fclose(file); 00790 return NULL; 00791 } 00792 00793 /* 00794 * Initialize default argv, argc, and argv_size. 00795 */ 00796 argv_size = 10; 00797 argc = 0; 00798 f_argv = ckd_calloc(argv_size, sizeof(char *)); 00799 /* Silently make room for \0 */ 00800 str = ckd_calloc(arg_max_length + 1, sizeof(char)); 00801 quoting = 0; 00802 00803 do { 00804 /* Handle arguments that are commented out */ 00805 if (len == 0 && argc % 2 == 0) { 00806 while (ch == '#') { 00807 /* Skip everything until newline */ 00808 for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ; 00809 /* Skip to the next interesting character */ 00810 for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; 00811 } 00812 00813 /* Check if we are at the last line (without anything interesting in it) */ 00814 if (ch == EOF) 00815 break; 00816 } 00817 00818 /* Handle quoted arguments */ 00819 if (ch == '"' || ch == '\'') { 00820 if (quoting == ch) /* End a quoted section with the same type */ 00821 quoting = 0; 00822 else if (quoting) { 00823 E_ERROR("Nesting quotations is not supported!\n"); 00824 rv = 1; 00825 break; 00826 } 00827 else 00828 quoting = ch; /* Start a quoted section */ 00829 } 00830 else if (ch == EOF || (!quoting && strchr(separator, ch))) { 00831 /* Reallocate argv so it is big enough to contain all the arguments */ 00832 if (argc >= argv_size) { 00833 char **tmp_argv; 00834 if (!(tmp_argv = 00835 ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) { 00836 rv = 1; 00837 break; 00838 } 00839 f_argv = tmp_argv; 00840 argv_size *= 2; 00841 } 00842 /* Add the string to the list of arguments */ 00843 f_argv[argc] = ckd_salloc(str); 00844 len = 0; 00845 str[0] = '\0'; 00846 argc++; 00847 00848 if (quoting) 00849 E_WARN("Unclosed quotation, having EOF close it...\n"); 00850 00851 /* Skip to the next interesting character */ 00852 for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; 00853 00854 if (ch == EOF) 00855 break; 00856 00857 /* We already have the next character */ 00858 continue; 00859 } 00860 else { 00861 if (len >= arg_max_length) { 00862 /* Make room for more chars (including the \0 !) */ 00863 char *tmp_str = str; 00864 if ((tmp_str = ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) { 00865 rv = 1; 00866 break; 00867 } 00868 str = tmp_str; 00869 arg_max_length *= 2; 00870 } 00871 /* Add the char to the argument string */ 00872 str[len++] = ch; 00873 /* Always null terminate */ 00874 str[len] = '\0'; 00875 } 00876 00877 ch = fgetc(file); 00878 } while (1); 00879 00880 fclose(file); 00881 00882 ckd_free(str); 00883 00884 if (rv) { 00885 for (ch = 0; ch < argc; ++ch) 00886 ckd_free(f_argv[ch]); 00887 ckd_free(f_argv); 00888 return NULL; 00889 } 00890 00891 return parse_options(inout_cmdln, defn, argc, f_argv, strict); 00892 } 00893 00894 int 00895 cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict) 00896 { 00897 cmd_ln_t *cmdln; 00898 00899 cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict); 00900 if (cmdln == NULL) { 00901 return -1; 00902 } 00903 /* Initialize global_cmdln if not present. */ 00904 if (global_cmdln == NULL) { 00905 global_cmdln = cmdln; 00906 } 00907 return 0; 00908 } 00909 00910 void 00911 cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE * fp, arg_t const* defn) 00912 { 00913 if (defn == NULL) 00914 return; 00915 fprintf(fp, "Arguments list definition:\n"); 00916 arg_dump_r(cmdln, fp, defn, 1); 00917 fflush(fp); 00918 } 00919 00920 int 00921 cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name) 00922 { 00923 void *val; 00924 if (cmdln == NULL) 00925 return FALSE; 00926 return (hash_table_lookup(cmdln->ht, name, &val) == 0); 00927 } 00928 00929 anytype_t * 00930 cmd_ln_access_r(cmd_ln_t *cmdln, const char *name) 00931 { 00932 void *val; 00933 if (hash_table_lookup(cmdln->ht, name, &val) < 0) { 00934 E_ERROR("Unknown argument: %s\n", name); 00935 return NULL; 00936 } 00937 return (anytype_t *)val; 00938 } 00939 00940 char const * 00941 cmd_ln_str_r(cmd_ln_t *cmdln, char const *name) 00942 { 00943 anytype_t *val; 00944 val = cmd_ln_access_r(cmdln, name); 00945 if (val == NULL) 00946 return NULL; 00947 return (char const *)val->ptr; 00948 } 00949 00950 char const ** 00951 cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name) 00952 { 00953 anytype_t *val; 00954 val = cmd_ln_access_r(cmdln, name); 00955 if (val == NULL) 00956 return NULL; 00957 return (char const **)val->ptr; 00958 } 00959 00960 long 00961 cmd_ln_int_r(cmd_ln_t *cmdln, char const *name) 00962 { 00963 anytype_t *val; 00964 val = cmd_ln_access_r(cmdln, name); 00965 if (val == NULL) 00966 return 0L; 00967 return val->i; 00968 } 00969 00970 double 00971 cmd_ln_float_r(cmd_ln_t *cmdln, char const *name) 00972 { 00973 anytype_t *val; 00974 val = cmd_ln_access_r(cmdln, name); 00975 if (val == NULL) 00976 return 0.0; 00977 return val->fl; 00978 } 00979 00980 void 00981 cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str) 00982 { 00983 anytype_t *val; 00984 val = cmd_ln_access_r(cmdln, name); 00985 if (val == NULL) { 00986 E_ERROR("Unknown argument: %s\n", name); 00987 return; 00988 } 00989 ckd_free(val->ptr); 00990 if (str == NULL) 00991 val->ptr = NULL; 00992 else 00993 val->ptr = ckd_salloc(str); 00994 } 00995 00996 void 00997 cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv) 00998 { 00999 anytype_t *val; 01000 val = cmd_ln_access_r(cmdln, name); 01001 if (val == NULL) { 01002 E_ERROR("Unknown argument: %s\n", name); 01003 return; 01004 } 01005 val->i = iv; 01006 } 01007 01008 void 01009 cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv) 01010 { 01011 anytype_t *val; 01012 val = cmd_ln_access_r(cmdln, name); 01013 if (val == NULL) { 01014 E_ERROR("Unknown argument: %s\n", name); 01015 return; 01016 } 01017 val->fl = fv; 01018 } 01019 01020 cmd_ln_t * 01021 cmd_ln_retain(cmd_ln_t *cmdln) 01022 { 01023 ++cmdln->refcount; 01024 return cmdln; 01025 } 01026 01027 int 01028 cmd_ln_free_r(cmd_ln_t *cmdln) 01029 { 01030 if (cmdln == NULL) 01031 return 0; 01032 if (--cmdln->refcount > 0) 01033 return cmdln->refcount; 01034 01035 if (cmdln->ht) { 01036 glist_t entries; 01037 gnode_t *gn; 01038 int32 n; 01039 01040 entries = hash_table_tolist(cmdln->ht, &n); 01041 for (gn = entries; gn; gn = gnode_next(gn)) { 01042 hash_entry_t *e = gnode_ptr(gn); 01043 cmd_ln_val_free((cmd_ln_val_t *)e->val); 01044 } 01045 glist_free(entries); 01046 hash_table_free(cmdln->ht); 01047 cmdln->ht = NULL; 01048 } 01049 01050 if (cmdln->f_argv) { 01051 int32 i; 01052 for (i = 0; i < cmdln->f_argc; ++i) { 01053 ckd_free(cmdln->f_argv[i]); 01054 } 01055 ckd_free(cmdln->f_argv); 01056 cmdln->f_argv = NULL; 01057 cmdln->f_argc = 0; 01058 } 01059 ckd_free(cmdln); 01060 return 0; 01061 } 01062 01063 void 01064 cmd_ln_free(void) 01065 { 01066 cmd_ln_free_r(global_cmdln); 01067 global_cmdln = NULL; 01068 }