SphinxBase  5prealpha
cmd_ln.c
1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3  * Copyright (c) 1999-2004 Carnegie Mellon University. All rights
4  * reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * This work was supported in part by funding from the Defense Advanced
19  * Research Projects Agency and the National Science Foundation of the
20  * United States of America, and the CMU Sphinx Speech Consortium.
21  *
22  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
23  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
26  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * ====================================================================
35  *
36  */
37 /*
38  * cmd_ln.c -- Command line argument parsing.
39  *
40  * **********************************************
41  * CMU ARPA Speech Project
42  *
43  * Copyright (c) 1999 Carnegie Mellon University.
44  * ALL RIGHTS RESERVED.
45  * **********************************************
46  *
47  * HISTORY
48  *
49  * 10-Sep-1998 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
50  * Changed strcasecmp() call in cmp_name() to strcmp_nocase() call.
51  *
52  * 15-Jul-1997 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
53  * Added required arguments handling.
54  *
55  * 07-Dec-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
56  * Created, based on Eric's implementation. Basically, combined several
57  * functions into one, eliminated validation, and simplified the interface.
58  */
59 
60 
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <assert.h>
65 
66 #ifdef _MSC_VER
67 #pragma warning (disable: 4996 4018)
68 #endif
69 
70 #ifdef HAVE_CONFIG_H
71 #include <config.h>
72 #endif
73 
74 #ifdef HAVE_UNISTD_H
75 #include <unistd.h>
76 #endif
77 
78 #include "sphinxbase/cmd_ln.h"
79 #include "sphinxbase/err.h"
80 #include "sphinxbase/ckd_alloc.h"
81 #include "sphinxbase/hash_table.h"
82 #include "sphinxbase/case.h"
83 #include "sphinxbase/strfuncs.h"
84 
85 typedef struct cmd_ln_val_s {
86  anytype_t val;
87  int type;
88  char *name;
89 } cmd_ln_val_t;
90 
91 struct cmd_ln_s {
92  int refcount;
93  hash_table_t *ht;
94  char **f_argv;
95  uint32 f_argc;
96 };
97 
99 cmd_ln_t *global_cmdln;
100 
101 static void
102 arg_dump_r(cmd_ln_t *, FILE *, arg_t const *, int32);
103 
104 static cmd_ln_t *
105 parse_options(cmd_ln_t *, const arg_t *, int32, char* [], int32);
106 
107 /*
108  * Find max length of name and default fields in the given defn array.
109  * Return #items in defn array.
110  */
111 static int32
112 arg_strlen(const arg_t * defn, int32 * namelen, int32 * deflen)
113 {
114  int32 i, l;
115 
116  *namelen = *deflen = 0;
117  for (i = 0; defn[i].name; i++) {
118  l = strlen(defn[i].name);
119  if (*namelen < l)
120  *namelen = l;
121 
122  if (defn[i].deflt)
123  l = strlen(defn[i].deflt);
124  else
125  l = strlen("(null)");
126  /* E_INFO("string default, %s , name %s, length %d\n",defn[i].deflt,defn[i].name,l); */
127  if (*deflen < l)
128  *deflen = l;
129  }
130 
131  return i;
132 }
133 
134 
135 static int32
136 cmp_name(const void *a, const void *b)
137 {
138  return (strcmp_nocase
139  ((* (arg_t**) a)->name,
140  (* (arg_t**) b)->name));
141 }
142 
143 static arg_t const **
144 arg_sort(const arg_t * defn, int32 n)
145 {
146  const arg_t ** pos;
147  int32 i;
148 
149  pos = (arg_t const **) ckd_calloc(n, sizeof(arg_t *));
150  for (i = 0; i < n; ++i)
151  pos[i] = &defn[i];
152  qsort(pos, n, sizeof(arg_t *), cmp_name);
153 
154  return pos;
155 }
156 
157 static size_t
158 strnappend(char **dest, size_t *dest_allocation,
159  const char *source, size_t n)
160 {
161  size_t source_len, required_allocation;
162 
163  if (dest == NULL || dest_allocation == NULL)
164  return -1;
165  if (*dest == NULL && *dest_allocation != 0)
166  return -1;
167  if (source == NULL)
168  return *dest_allocation;
169 
170  source_len = strlen(source);
171  if (n && n < source_len)
172  source_len = n;
173 
174  required_allocation = (*dest ? strlen(*dest) : 0) + source_len + 1;
175  if (*dest_allocation < required_allocation) {
176  if (*dest_allocation == 0) {
177  *dest = (char *)ckd_calloc(required_allocation * 2, 1);
178  } else {
179  *dest = (char *)ckd_realloc(*dest, required_allocation * 2);
180  }
181  *dest_allocation = required_allocation * 2;
182  }
183 
184  strncat(*dest, source, source_len);
185 
186  return *dest_allocation;
187 }
188 
189 static size_t
190 strappend(char **dest, size_t *dest_allocation,
191  const char *source)
192 {
193  return strnappend(dest, dest_allocation, source, 0);
194 }
195 
196 static char*
197 arg_resolve_env(const char *str)
198 {
199  char *resolved_str = NULL;
200  char env_name[100];
201  const char *env_val;
202  size_t alloced = 0;
203  const char *i = str, *j;
204 
205  /* calculate required resolved_str size */
206  do {
207  j = strstr(i, "$(");
208  if (j != NULL) {
209  if (j != i) {
210  strnappend(&resolved_str, &alloced, i, j - i);
211  i = j;
212  }
213  j = strchr(i + 2, ')');
214  if (j != NULL) {
215  if (j - (i + 2) < 100) {
216  strncpy(env_name, i + 2, j - (i + 2));
217  env_name[j - (i + 2)] = '\0';
218  #if !defined(_WIN32_WCE)
219  env_val = getenv(env_name);
220  if (env_val)
221  strappend(&resolved_str, &alloced, env_val);
222  #else
223  env_val = 0;
224  #endif
225  }
226  i = j + 1;
227  } else {
228  /* unclosed, copy and skip */
229  j = i + 2;
230  strnappend(&resolved_str, &alloced, i, j - i);
231  i = j;
232  }
233  } else {
234  strappend(&resolved_str, &alloced, i);
235  }
236  } while(j != NULL);
237 
238  return resolved_str;
239 }
240 
241 static void
242 arg_dump_r(cmd_ln_t *cmdln, FILE *fp, const arg_t * defn, int32 doc)
243 {
244  arg_t const **pos;
245  int32 i, n;
246  size_t l;
247  int32 namelen, deflen;
248  anytype_t *vp;
249  char const **array;
250 
251  /* No definitions, do nothing. */
252  if (defn == NULL || fp == NULL)
253  return;
254 
255  /* Find max lengths of name and default value fields, and #entries in defn */
256  n = arg_strlen(defn, &namelen, &deflen);
257  /* E_INFO("String length %d. Name length %d, Default Length %d\n",n, namelen, deflen); */
258  namelen = namelen & 0xfffffff8; /* Previous tab position */
259  deflen = deflen & 0xfffffff8; /* Previous tab position */
260 
261  fprintf(fp, "[NAME]");
262  for (l = strlen("[NAME]"); l < namelen; l += 8)
263  fprintf(fp, "\t");
264  fprintf(fp, "\t[DEFLT]");
265  for (l = strlen("[DEFLT]"); l < deflen; l += 8)
266  fprintf(fp, "\t");
267 
268  if (doc) {
269  fprintf(fp, "\t[DESCR]\n");
270  }
271  else {
272  fprintf(fp, "\t[VALUE]\n");
273  }
274 
275  /* Print current configuration, sorted by name */
276  pos = arg_sort(defn, n);
277  for (i = 0; i < n; i++) {
278  fprintf(fp, "%s", pos[i]->name);
279  for (l = strlen(pos[i]->name); l < namelen; l += 8)
280  fprintf(fp, "\t");
281 
282  fprintf(fp, "\t");
283  if (pos[i]->deflt) {
284  fprintf(fp, "%s", pos[i]->deflt);
285  l = strlen(pos[i]->deflt);
286  }
287  else
288  l = 0;
289  for (; l < deflen; l += 8)
290  fprintf(fp, "\t");
291 
292  fprintf(fp, "\t");
293  if (doc) {
294  if (pos[i]->doc)
295  fprintf(fp, "%s", pos[i]->doc);
296  }
297  else {
298  vp = cmd_ln_access_r(cmdln, pos[i]->name);
299  if (vp) {
300  switch (pos[i]->type) {
301  case ARG_INTEGER:
302  case REQARG_INTEGER:
303  fprintf(fp, "%ld", vp->i);
304  break;
305  case ARG_FLOATING:
306  case REQARG_FLOATING:
307  fprintf(fp, "%e", vp->fl);
308  break;
309  case ARG_STRING:
310  case REQARG_STRING:
311  if (vp->ptr)
312  fprintf(fp, "%s", (char *)vp->ptr);
313  break;
314  case ARG_STRING_LIST:
315  array = (char const**)vp->ptr;
316  if (array)
317  for (l = 0; array[l] != 0; l++) {
318  fprintf(fp, "%s,", array[l]);
319  }
320  break;
321  case ARG_BOOLEAN:
322  case REQARG_BOOLEAN:
323  fprintf(fp, "%s", vp->i ? "yes" : "no");
324  break;
325  default:
326  E_ERROR("Unknown argument type: %d\n", pos[i]->type);
327  }
328  }
329  }
330 
331  fprintf(fp, "\n");
332  }
333  ckd_free(pos);
334 
335  fprintf(fp, "\n");
336 }
337 
338 static char **
339 parse_string_list(const char *str)
340 {
341  int count, i, j;
342  const char *p;
343  char **result;
344 
345  p = str;
346  count = 1;
347  while (*p) {
348  if (*p == ',')
349  count++;
350  p++;
351  }
352  /* Should end with NULL */
353  result = (char **) ckd_calloc(count + 1, sizeof(char *));
354  p = str;
355  for (i = 0; i < count; i++) {
356  for (j = 0; p[j] != ',' && p[j] != 0; j++);
357  result[i] = (char *)ckd_calloc(j + 1, sizeof(char));
358  strncpy( result[i], p, j);
359  p = p + j + 1;
360  }
361  return result;
362 }
363 
364 static cmd_ln_val_t *
365 cmd_ln_val_init(int t, const char *name, const char *str)
366 {
367  cmd_ln_val_t *v;
368  anytype_t val;
369  char *e_str;
370 
371  if (!str) {
372  /* For lack of a better default value. */
373  memset(&val, 0, sizeof(val));
374  }
375  else {
376  int valid = 1;
377  e_str = arg_resolve_env(str);
378 
379  switch (t) {
380  case ARG_INTEGER:
381  case REQARG_INTEGER:
382  if (sscanf(e_str, "%ld", &val.i) != 1)
383  valid = 0;
384  break;
385  case ARG_FLOATING:
386  case REQARG_FLOATING:
387  if (e_str == NULL || e_str[0] == 0)
388  valid = 0;
389  val.fl = atof_c(e_str);
390  break;
391  case ARG_BOOLEAN:
392  case REQARG_BOOLEAN:
393  if ((e_str[0] == 'y') || (e_str[0] == 't') ||
394  (e_str[0] == 'Y') || (e_str[0] == 'T') || (e_str[0] == '1')) {
395  val.i = TRUE;
396  }
397  else if ((e_str[0] == 'n') || (e_str[0] == 'f') ||
398  (e_str[0] == 'N') || (e_str[0] == 'F') |
399  (e_str[0] == '0')) {
400  val.i = FALSE;
401  }
402  else {
403  E_ERROR("Unparsed boolean value '%s'\n", str);
404  valid = 0;
405  }
406  break;
407  case ARG_STRING:
408  case REQARG_STRING:
409  val.ptr = ckd_salloc(e_str);
410  break;
411  case ARG_STRING_LIST:
412  val.ptr = parse_string_list(e_str);
413  break;
414  default:
415  E_ERROR("Unknown argument type: %d\n", t);
416  valid = 0;
417  }
418 
419  ckd_free(e_str);
420  if (valid == 0)
421  return NULL;
422  }
423 
424  v = (cmd_ln_val_t *)ckd_calloc(1, sizeof(*v));
425  memcpy(v, &val, sizeof(val));
426  v->type = t;
427  v->name = ckd_salloc(name);
428 
429  return v;
430 }
431 
432 /*
433  * Handles option parsing for cmd_ln_parse_file_r() and cmd_ln_init()
434  * also takes care of storing argv.
435  * DO NOT call it from cmd_ln_parse_r()
436  */
437 static cmd_ln_t *
438 parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict)
439 {
440  cmd_ln_t *new_cmdln;
441 
442  new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict);
443  /* If this failed then clean up and return NULL. */
444  if (new_cmdln == NULL) {
445  int32 i;
446  for (i = 0; i < argc; ++i)
447  ckd_free(argv[i]);
448  ckd_free(argv);
449  return NULL;
450  }
451 
452  /* Otherwise, we need to add the contents of f_argv to the new object. */
453  if (new_cmdln == cmdln) {
454  /* If we are adding to a previously passed-in cmdln, then
455  * store our allocated strings in its f_argv. */
456  new_cmdln->f_argv = (char **)ckd_realloc(new_cmdln->f_argv,
457  (new_cmdln->f_argc + argc)
458  * sizeof(*new_cmdln->f_argv));
459  memcpy(new_cmdln->f_argv + new_cmdln->f_argc, argv,
460  argc * sizeof(*argv));
461  ckd_free(argv);
462  new_cmdln->f_argc += argc;
463  }
464  else {
465  /* Otherwise, store f_argc and f_argv. */
466  new_cmdln->f_argc = argc;
467  new_cmdln->f_argv = argv;
468  }
469 
470  return new_cmdln;
471 }
472 
473 void
474 cmd_ln_val_free(cmd_ln_val_t *val)
475 {
476  int i;
477  if (val->type & ARG_STRING_LIST) {
478  char ** array = (char **)val->val.ptr;
479  if (array) {
480  for (i = 0; array[i] != NULL; i++) {
481  ckd_free(array[i]);
482  }
483  ckd_free(array);
484  }
485  }
486  if (val->type & ARG_STRING)
487  ckd_free(val->val.ptr);
488  ckd_free(val->name);
489  ckd_free(val);
490 }
491 
492 cmd_ln_t *
494 {
495  return global_cmdln;
496 }
497 
498 void
499 cmd_ln_appl_enter(int argc, char *argv[],
500  const char *default_argfn,
501  const arg_t * defn)
502 {
503  /* Look for default or specified arguments file */
504  const char *str;
505 
506  str = NULL;
507 
508  if ((argc == 2) && (strcmp(argv[1], "help") == 0)) {
509  cmd_ln_print_help(stderr, defn);
510  exit(1);
511  }
512 
513  if ((argc == 2) && (argv[1][0] != '-'))
514  str = argv[1];
515  else if (argc == 1) {
516  FILE *fp;
517  E_INFO("Looking for default argument file: %s\n", default_argfn);
518 
519  if ((fp = fopen(default_argfn, "r")) == NULL) {
520  E_INFO("Can't find default argument file %s.\n",
521  default_argfn);
522  }
523  else {
524  str = default_argfn;
525  }
526  if (fp != NULL)
527  fclose(fp);
528  }
529 
530 
531  if (str) {
532  /* Build command line argument list from file */
533  E_INFO("Parsing command lines from file %s\n", str);
534  if (cmd_ln_parse_file(defn, str, TRUE)) {
535  E_INFOCONT("Usage:\n");
536  E_INFOCONT("\t%s argument-list, or\n", argv[0]);
537  E_INFOCONT("\t%s [argument-file] (default file: . %s)\n\n",
538  argv[0], default_argfn);
539  cmd_ln_print_help(stderr, defn);
540  exit(1);
541  }
542  }
543  else {
544  cmd_ln_parse(defn, argc, argv, TRUE);
545  }
546 }
547 
548 void
550 {
551  cmd_ln_free();
552 }
553 
554 
555 cmd_ln_t *
556 cmd_ln_parse_r(cmd_ln_t *inout_cmdln, const arg_t * defn, int32 argc, char *argv[], int strict)
557 {
558  int32 i, j, n, argstart;
559  hash_table_t *defidx = NULL;
560  cmd_ln_t *cmdln;
561 
562  /* Construct command-line object */
563  if (inout_cmdln == NULL) {
564  cmdln = (cmd_ln_t*)ckd_calloc(1, sizeof(*cmdln));
565  cmdln->refcount = 1;
566  }
567  else
568  cmdln = inout_cmdln;
569 
570  /* Build a hash table for argument definitions */
571  defidx = hash_table_new(50, 0);
572  if (defn) {
573  for (n = 0; defn[n].name; n++) {
574  void *v;
575 
576  v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]);
577  if (strict && (v != &defn[n])) {
578  E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name);
579  goto error;
580  }
581  }
582  }
583  else {
584  /* No definitions. */
585  n = 0;
586  }
587 
588  /* Allocate memory for argument values */
589  if (cmdln->ht == NULL)
590  cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ );
591 
592 
593  /* skip argv[0] if it doesn't start with dash */
594  argstart = 0;
595  if (argc > 0 && argv[0][0] != '-') {
596  argstart = 1;
597  }
598 
599  /* Parse command line arguments (name-value pairs) */
600  for (j = argstart; j < argc; j += 2) {
601  arg_t *argdef;
602  cmd_ln_val_t *val;
603  void *v;
604 
605  if (hash_table_lookup(defidx, argv[j], &v) < 0) {
606  if (strict) {
607  E_ERROR("Unknown argument name '%s'\n", argv[j]);
608  goto error;
609  }
610  else if (defn == NULL)
611  v = NULL;
612  else
613  continue;
614  }
615  argdef = (arg_t *)v;
616 
617  /* Enter argument value */
618  if (j + 1 >= argc) {
619  cmd_ln_print_help_r(cmdln, stderr, defn);
620  E_ERROR("Argument value for '%s' missing\n", argv[j]);
621  goto error;
622  }
623 
624  if (argdef == NULL)
625  val = cmd_ln_val_init(ARG_STRING, argv[j], argv[j + 1]);
626  else {
627  if ((val = cmd_ln_val_init(argdef->type, argv[j], argv[j + 1])) == NULL) {
628  cmd_ln_print_help_r(cmdln, stderr, defn);
629  E_ERROR("Bad argument value for %s: %s\n", argv[j],
630  argv[j + 1]);
631  goto error;
632  }
633  }
634 
635  if ((v = hash_table_enter(cmdln->ht, val->name, (void *)val)) !=
636  (void *)val)
637  {
638  if (strict) {
639  cmd_ln_val_free(val);
640  E_ERROR("Duplicate argument name in arguments: %s\n",
641  argdef->name);
642  goto error;
643  }
644  else {
645  v = hash_table_replace(cmdln->ht, val->name, (void *)val);
646  cmd_ln_val_free((cmd_ln_val_t *)v);
647  }
648  }
649  }
650 
651  /* Fill in default values, if any, for unspecified arguments */
652  for (i = 0; i < n; i++) {
653  cmd_ln_val_t *val;
654  void *v;
655 
656  if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) {
657  if ((val = cmd_ln_val_init(defn[i].type, defn[i].name, defn[i].deflt)) == NULL) {
658  E_ERROR
659  ("Bad default argument value for %s: %s\n",
660  defn[i].name, defn[i].deflt);
661  goto error;
662  }
663  hash_table_enter(cmdln->ht, val->name, (void *)val);
664  }
665  }
666 
667  /* Check for required arguments; exit if any missing */
668  j = 0;
669  for (i = 0; i < n; i++) {
670  if (defn[i].type & ARG_REQUIRED) {
671  void *v;
672  if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0)
673  E_ERROR("Missing required argument %s\n", defn[i].name);
674  }
675  }
676  if (j > 0) {
677  cmd_ln_print_help_r(cmdln, stderr, defn);
678  goto error;
679  }
680 
681  if (strict && argc == 1) {
682  E_ERROR("No arguments given, available options are:\n");
683  cmd_ln_print_help_r(cmdln, stderr, defn);
684  if (defidx)
685  hash_table_free(defidx);
686  if (inout_cmdln == NULL)
687  cmd_ln_free_r(cmdln);
688  return NULL;
689  }
690 
691  /* If we use it from something except pocketsphinx, print current values */
692  if (!cmd_ln_exists_r(cmdln, "-logfn") && err_get_logfp()) {
693  cmd_ln_print_values_r(cmdln, err_get_logfp(), defn);
694  }
695 
696  hash_table_free(defidx);
697  return cmdln;
698 
699  error:
700  if (defidx)
701  hash_table_free(defidx);
702  if (inout_cmdln == NULL)
703  cmd_ln_free_r(cmdln);
704  E_ERROR("Failed to parse arguments list\n");
705  return NULL;
706 }
707 
708 cmd_ln_t *
709 cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)
710 {
711  va_list args;
712  const char *arg, *val;
713  char **f_argv;
714  int32 f_argc;
715 
716  va_start(args, strict);
717  f_argc = 0;
718  while ((arg = va_arg(args, const char *))) {
719  ++f_argc;
720  val = va_arg(args, const char*);
721  if (val == NULL) {
722  E_ERROR("Number of arguments must be even!\n");
723  return NULL;
724  }
725  ++f_argc;
726  }
727  va_end(args);
728 
729  /* Now allocate f_argv */
730  f_argv = (char**)ckd_calloc(f_argc, sizeof(*f_argv));
731  va_start(args, strict);
732  f_argc = 0;
733  while ((arg = va_arg(args, const char *))) {
734  f_argv[f_argc] = ckd_salloc(arg);
735  ++f_argc;
736  val = va_arg(args, const char*);
737  f_argv[f_argc] = ckd_salloc(val);
738  ++f_argc;
739  }
740  va_end(args);
741 
742  return parse_options(inout_cmdln, defn, f_argc, f_argv, strict);
743 }
744 
745 int
746 cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict)
747 {
748  cmd_ln_t *cmdln;
749 
750  cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict);
751  if (cmdln == NULL) {
752  /* Old, bogus behaviour... */
753  E_ERROR("Failed to parse arguments list, forced exit\n");
754  exit(-1);
755  }
756  /* Initialize global_cmdln if not present. */
757  if (global_cmdln == NULL) {
758  global_cmdln = cmdln;
759  }
760  return 0;
761 }
762 
763 cmd_ln_t *
764 cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict)
765 {
766  FILE *file;
767  int argc;
768  int argv_size;
769  char *str;
770  int arg_max_length = 512;
771  int len = 0;
772  int quoting, ch;
773  char **f_argv;
774  int rv = 0;
775  const char separator[] = " \t\r\n";
776 
777  if ((file = fopen(filename, "r")) == NULL) {
778  E_ERROR("Cannot open configuration file %s for reading\n",
779  filename);
780  return NULL;
781  }
782 
783  ch = fgetc(file);
784  /* Skip to the next interesting character */
785  for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
786 
787  if (ch == EOF) {
788  fclose(file);
789  return NULL;
790  }
791 
792  /*
793  * Initialize default argv, argc, and argv_size.
794  */
795  argv_size = 30;
796  argc = 0;
797  f_argv = (char **)ckd_calloc(argv_size, sizeof(char *));
798  /* Silently make room for \0 */
799  str = (char* )ckd_calloc(arg_max_length + 1, sizeof(char));
800  quoting = 0;
801 
802  do {
803  /* Handle arguments that are commented out */
804  if (len == 0 && argc % 2 == 0) {
805  while (ch == '#') {
806  /* Skip everything until newline */
807  for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ;
808  /* Skip to the next interesting character */
809  for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
810  }
811 
812  /* Check if we are at the last line (without anything interesting in it) */
813  if (ch == EOF)
814  break;
815  }
816 
817  /* Handle quoted arguments */
818  if (ch == '"' || ch == '\'') {
819  if (quoting == ch) /* End a quoted section with the same type */
820  quoting = 0;
821  else if (quoting) {
822  E_ERROR("Nesting quotations is not supported!\n");
823  rv = 1;
824  break;
825  }
826  else
827  quoting = ch; /* Start a quoted section */
828  }
829  else if (ch == EOF || (!quoting && strchr(separator, ch))) {
830  /* Reallocate argv so it is big enough to contain all the arguments */
831  if (argc >= argv_size) {
832  char **tmp_argv;
833  if (!(tmp_argv =
834  (char **)ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) {
835  rv = 1;
836  break;
837  }
838  f_argv = tmp_argv;
839  argv_size *= 2;
840  }
841 
842  /* Add the string to the list of arguments */
843  f_argv[argc] = ckd_salloc(str);
844  len = 0;
845  str[0] = '\0';
846  argc++;
847 
848  if (quoting)
849  E_WARN("Unclosed quotation, having EOF close it...\n");
850 
851  /* Skip to the next interesting character */
852  for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
853 
854  if (ch == EOF)
855  break;
856 
857  /* We already have the next character */
858  continue;
859  }
860  else {
861  if (len >= arg_max_length) {
862  /* Make room for more chars (including the \0 !) */
863  char *tmp_str = str;
864  if ((tmp_str = (char *)ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) {
865  rv = 1;
866  break;
867  }
868  str = tmp_str;
869  arg_max_length *= 2;
870  }
871  /* Add the char to the argument string */
872  str[len++] = ch;
873  /* Always null terminate */
874  str[len] = '\0';
875  }
876 
877  ch = fgetc(file);
878  } while (1);
879 
880  fclose(file);
881 
882  ckd_free(str);
883 
884  if (rv) {
885  for (ch = 0; ch < argc; ++ch)
886  ckd_free(f_argv[ch]);
887  ckd_free(f_argv);
888  return NULL;
889  }
890 
891  return parse_options(inout_cmdln, defn, argc, f_argv, strict);
892 }
893 
894 int
895 cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict)
896 {
897  cmd_ln_t *cmdln;
898 
899  cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict);
900  if (cmdln == NULL) {
901  return -1;
902  }
903  /* Initialize global_cmdln if not present. */
904  if (global_cmdln == NULL) {
905  global_cmdln = cmdln;
906  }
907  return 0;
908 }
909 
910 void
911 cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE *fp, arg_t const* defn)
912 {
913  if (defn == NULL)
914  return;
915  fprintf(fp, "Arguments list definition:\n");
916  arg_dump_r(cmdln, fp, defn, TRUE);
917 }
918 
919 void
920 cmd_ln_print_values_r(cmd_ln_t *cmdln, FILE *fp, arg_t const* defn)
921 {
922  if (defn == NULL)
923  return;
924  fprintf(fp, "Current configuration:\n");
925  arg_dump_r(cmdln, fp, defn, FALSE);
926 }
927 
928 int
929 cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name)
930 {
931  void *val;
932  if (cmdln == NULL)
933  return FALSE;
934  return (hash_table_lookup(cmdln->ht, name, &val) == 0);
935 }
936 
937 anytype_t *
938 cmd_ln_access_r(cmd_ln_t *cmdln, const char *name)
939 {
940  void *val;
941  if (hash_table_lookup(cmdln->ht, name, &val) < 0) {
942  E_ERROR("Unknown argument: %s\n", name);
943  return NULL;
944  }
945  return (anytype_t *)val;
946 }
947 
948 char const *
949 cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
950 {
951  anytype_t *val;
952  val = cmd_ln_access_r(cmdln, name);
953  if (val == NULL)
954  return NULL;
955  return (char const *)val->ptr;
956 }
957 
958 char const **
959 cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name)
960 {
961  anytype_t *val;
962  val = cmd_ln_access_r(cmdln, name);
963  if (val == NULL)
964  return NULL;
965  return (char const **)val->ptr;
966 }
967 
968 long
969 cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
970 {
971  anytype_t *val;
972  val = cmd_ln_access_r(cmdln, name);
973  if (val == NULL)
974  return 0L;
975  return val->i;
976 }
977 
978 double
979 cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
980 {
981  anytype_t *val;
982  val = cmd_ln_access_r(cmdln, name);
983  if (val == NULL)
984  return 0.0;
985  return val->fl;
986 }
987 
988 void
989 cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
990 {
991  anytype_t *val;
992  val = cmd_ln_access_r(cmdln, name);
993  if (val == NULL) {
994  E_ERROR("Unknown argument: %s\n", name);
995  return;
996  }
997  ckd_free(val->ptr);
998  val->ptr = ckd_salloc(str);
999 }
1000 
1001 void
1002 cmd_ln_set_str_extra_r(cmd_ln_t *cmdln, char const *name, char const *str)
1003 {
1004  cmd_ln_val_t *val;
1005  if (hash_table_lookup(cmdln->ht, name, (void **)&val) < 0) {
1006  val = cmd_ln_val_init(ARG_STRING, name, str);
1007  hash_table_enter(cmdln->ht, val->name, (void *)val);
1008  } else {
1009  ckd_free(val->val.ptr);
1010  val->val.ptr = ckd_salloc(str);
1011  }
1012 }
1013 
1014 void
1015 cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
1016 {
1017  anytype_t *val;
1018  val = cmd_ln_access_r(cmdln, name);
1019  if (val == NULL) {
1020  E_ERROR("Unknown argument: %s\n", name);
1021  return;
1022  }
1023  val->i = iv;
1024 }
1025 
1026 void
1027 cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
1028 {
1029  anytype_t *val;
1030  val = cmd_ln_access_r(cmdln, name);
1031  if (val == NULL) {
1032  E_ERROR("Unknown argument: %s\n", name);
1033  return;
1034  }
1035  val->fl = fv;
1036 }
1037 
1038 cmd_ln_t *
1040 {
1041  ++cmdln->refcount;
1042  return cmdln;
1043 }
1044 
1045 int
1047 {
1048  if (cmdln == NULL)
1049  return 0;
1050  if (--cmdln->refcount > 0)
1051  return cmdln->refcount;
1052 
1053  if (cmdln->ht) {
1054  glist_t entries;
1055  gnode_t *gn;
1056  int32 n;
1057 
1058  entries = hash_table_tolist(cmdln->ht, &n);
1059  for (gn = entries; gn; gn = gnode_next(gn)) {
1060  hash_entry_t *e = (hash_entry_t *)gnode_ptr(gn);
1061  cmd_ln_val_free((cmd_ln_val_t *)e->val);
1062  }
1063  glist_free(entries);
1064  hash_table_free(cmdln->ht);
1065  cmdln->ht = NULL;
1066  }
1067 
1068  if (cmdln->f_argv) {
1069  int32 i;
1070  for (i = 0; i < cmdln->f_argc; ++i) {
1071  ckd_free(cmdln->f_argv[i]);
1072  }
1073  ckd_free(cmdln->f_argv);
1074  cmdln->f_argv = NULL;
1075  cmdln->f_argc = 0;
1076  }
1077  ckd_free(cmdln);
1078  return 0;
1079 }
1080 
1081 void
1083 {
1084  cmd_ln_free_r(global_cmdln);
1085  global_cmdln = NULL;
1086 }
1087 
1088 /* vim: set ts=4 sw=4: */
#define REQARG_BOOLEAN
Required boolean argument.
Definition: cmd_ln.h:139
Command-line and other configurationparsing and handling.
SPHINXBASE_EXPORT cmd_ln_t * cmd_ln_retain(cmd_ln_t *cmdln)
Retain ownership of a command-line argument set.
Definition: cmd_ln.c:1039
Miscellaneous useful string functions.
#define E_INFO(...)
Print logging information to standard error stream.
Definition: err.h:114
SPHINXBASE_EXPORT double cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
Retrieve a floating-point number from a command-line object.
Definition: cmd_ln.c:979
SPHINXBASE_EXPORT long cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
Retrieve an integer from a command-line object.
Definition: cmd_ln.c:969
SPHINXBASE_EXPORT int32 hash_table_lookup(hash_table_t *h, const char *key, void **val)
Look up a key in a hash table and optionally return the associated value.
Definition: hash_table.c:302
#define ckd_calloc(n, sz)
Macros to simplify the use of above functions.
Definition: ckd_alloc.h:248
SPHINXBASE_EXPORT FILE * err_get_logfp(void)
Get the current logging filehandle.
Definition: err.c:268
#define REQARG_INTEGER
Required integer argument.
Definition: cmd_ln.h:127
#define E_ERROR(...)
Print error message to error log.
Definition: err.h:104
#define ARG_REQUIRED
Bit indicating a required argument.
Definition: cmd_ln.h:102
#define ARG_STRING_LIST
Boolean (true/false) argument (optional).
Definition: cmd_ln.h:122
SPHINXBASE_EXPORT anytype_t * cmd_ln_access_r(cmd_ln_t *cmdln, char const *name)
Access the generic type union for a command line argument.
Definition: cmd_ln.c:938
SPHINXBASE_EXPORT void * hash_table_replace(hash_table_t *h, const char *key, void *val)
Add a new entry with given key and value to hash table h.
Definition: hash_table.c:512
Sphinx&#39;s memory allocation/deallocation routines.
SPHINXBASE_EXPORT void cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
Set an integer in a command-line object.
Definition: cmd_ln.c:1015
SPHINXBASE_EXPORT glist_t hash_table_tolist(hash_table_t *h, int32 *count)
Build a glist of valid hash_entry_t pointers from the given hash table.
Definition: hash_table.c:616
#define REQARG_FLOATING
Required floating point argument.
Definition: cmd_ln.h:131
#define E_INFOCONT(...)
Continue printing the information to standard error stream.
Definition: err.h:119
SPHINXBASE_EXPORT int cmd_ln_free_r(cmd_ln_t *cmdln)
Release a command-line argument set and all associated strings.
Definition: cmd_ln.c:1046
SPHINXBASE_EXPORT int cmd_ln_exists_r(cmd_ln_t *cmdln, char const *name)
Re-entrant version of cmd_ln_exists().
Definition: cmd_ln.c:929
SPHINXBASE_EXPORT cmd_ln_t * cmd_ln_parse_r(cmd_ln_t *inout_cmdln, arg_t const *defn, int32 argc, char *argv[], int32 strict)
Parse a list of strings into argumetns.
Definition: cmd_ln.c:556
#define ARG_STRING
String argument (optional).
Definition: cmd_ln.h:114
A node in a generic list.
Definition: glist.h:100
#define ckd_salloc(ptr)
Macro for ckd_salloc
Definition: ckd_alloc.h:264
SPHINXBASE_EXPORT char const * cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
Retrieve a string from a command-line object.
Definition: cmd_ln.c:949
SPHINXBASE_EXPORT hash_table_t * hash_table_new(int32 size, int32 casearg)
Allocate a new hash table for a given expected size.
Definition: hash_table.c:158
SPHINXBASE_EXPORT char const ** cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name)
Retrieve an array of strings from a command-line object.
Definition: cmd_ln.c:959
#define REQARG_STRING
Required string argument.
Definition: cmd_ln.h:135
SPHINXBASE_EXPORT void ckd_free(void *ptr)
Test and free a 1-D array.
Definition: ckd_alloc.c:244
SPHINXBASE_EXPORT cmd_ln_t * cmd_ln_get(void)
Retrieve the global cmd_ln_t object used by non-re-entrant functions.
Definition: cmd_ln.c:493
SPHINXBASE_EXPORT int32 strcmp_nocase(const char *str1, const char *str2)
(FIXME! The implementation is incorrect!) Case insensitive string compare.
Definition: case.c:94
#define cmd_ln_print_help(f, d)
Print a help message listing the valid argument names, and the associated attributes as given in defn...
Definition: cmd_ln.h:595
SPHINXBASE_EXPORT void cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE *fp, const arg_t *defn)
Print a help message listing the valid argument names, and the associated attributes as given in defn...
Definition: cmd_ln.c:911
SPHINXBASE_EXPORT void hash_table_free(hash_table_t *h)
Free the specified hash table; the caller is responsible for freeing the key strings pointed to by th...
Definition: hash_table.c:688
SPHINXBASE_EXPORT void cmd_ln_print_values_r(cmd_ln_t *cmdln, FILE *fp, const arg_t *defn)
Print current configuration values and defaults.
Definition: cmd_ln.c:920
A note by ARCHAN at 20050510: Technically what we use is so-called &quot;hash table with buckets&quot; which is...
Definition: hash_table.h:149
SPHINXBASE_EXPORT double atof_c(char const *str)
Locale independent version of atof().
Definition: strfuncs.c:55
SPHINXBASE_EXPORT void glist_free(glist_t g)
Free the given generic list; user-defined data contained within is not automatically freed...
Definition: glist.c:133
SPHINXBASE_EXPORT cmd_ln_t * cmd_ln_init(cmd_ln_t *inout_cmdln, arg_t const *defn, int32 strict,...)
Create a cmd_ln_t from NULL-terminated list of arguments.
Definition: cmd_ln.c:709
SPHINXBASE_EXPORT void cmd_ln_appl_exit(void)
Finalization routine corresponding to cmd_ln_appl_enter().
Definition: cmd_ln.c:549
#define gnode_ptr(g)
Head of a list of gnodes.
Definition: glist.h:109
Implementation of logging routines.
#define ARG_BOOLEAN
Boolean (true/false) argument (optional).
Definition: cmd_ln.h:118
SPHINXBASE_EXPORT void * hash_table_enter(hash_table_t *h, const char *key, void *val)
Try to add a new entry with given key and associated value to hash table h.
Definition: hash_table.c:501
SPHINXBASE_EXPORT cmd_ln_t * cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, arg_t const *defn, char const *filename, int32 strict)
Parse an arguments file by deliminating on &quot; \r\t\n&quot; and putting each tokens into an argv[] for cmd_l...
Definition: cmd_ln.c:764
Argument definition structure.
#define E_WARN(...)
Print warning message to error log.
Definition: err.h:109
Opaque structure used to hold the results of command-line parsing.
SPHINXBASE_EXPORT void cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
Set a floating-point number in a command-line object.
Definition: cmd_ln.c:1027
Union of basic types.
Definition: prim_type.h:107
Hash table implementation.
SPHINXBASE_EXPORT int32 cmd_ln_parse(const arg_t *defn, int32 argc, char *argv[], int32 strict)
Non-reentrant version of cmd_ln_parse().
Definition: cmd_ln.c:746
SPHINXBASE_EXPORT void cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
Set a string in a command-line object.
Definition: cmd_ln.c:989
#define ARG_FLOATING
Floating point argument (optional).
Definition: cmd_ln.h:110
void * val
Key-length; the key string does not have to be a C-style NULL terminated string; it can have arbitrar...
Definition: hash_table.h:155
SPHINXBASE_EXPORT void cmd_ln_free(void)
Free the global command line, if any exists.
Definition: cmd_ln.c:1082
SPHINXBASE_EXPORT void cmd_ln_set_str_extra_r(cmd_ln_t *cmdln, char const *name, char const *str)
Set a string in a command-line object even if it is not present in argument description.
Definition: cmd_ln.c:1002
#define ckd_realloc(ptr, sz)
Macro for ckd_realloc
Definition: ckd_alloc.h:258
#define ARG_INTEGER
Integer argument (optional).
Definition: cmd_ln.h:106
SPHINXBASE_EXPORT void cmd_ln_appl_enter(int argc, char *argv[], char const *default_argfn, const arg_t *defn)
Old application initialization routine for Sphinx3 code.
Definition: cmd_ln.c:499
Locale-independent implementation of case swapping operation.
SPHINXBASE_EXPORT int32 cmd_ln_parse_file(const arg_t *defn, char const *filename, int32 strict)
Parse an arguments file by deliminating on &quot; \r\t\n&quot; and putting each tokens into an argv[] for cmd_l...
Definition: cmd_ln.c:895