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 } cmd_ln_val_t;
89 
90 struct cmd_ln_s {
91  int refcount;
92  hash_table_t *ht;
93  char **f_argv;
94  uint32 f_argc;
95 };
96 
98 cmd_ln_t *global_cmdln;
99 
100 static void
101 arg_dump_r(cmd_ln_t *, FILE *, arg_t const *, int32);
102 
103 static cmd_ln_t *
104 parse_options(cmd_ln_t *, const arg_t *, int32, char* [], int32);
105 
106 /*
107  * Find max length of name and default fields in the given defn array.
108  * Return #items in defn array.
109  */
110 static int32
111 arg_strlen(const arg_t * defn, int32 * namelen, int32 * deflen)
112 {
113  int32 i, l;
114 
115  *namelen = *deflen = 0;
116  for (i = 0; defn[i].name; i++) {
117  l = strlen(defn[i].name);
118  if (*namelen < l)
119  *namelen = l;
120 
121  if (defn[i].deflt)
122  l = strlen(defn[i].deflt);
123  else
124  l = strlen("(null)");
125  /* E_INFO("string default, %s , name %s, length %d\n",defn[i].deflt,defn[i].name,l); */
126  if (*deflen < l)
127  *deflen = l;
128  }
129 
130  return i;
131 }
132 
133 
134 static int32
135 cmp_name(const void *a, const void *b)
136 {
137  return (strcmp_nocase
138  ((* (arg_t**) a)->name,
139  (* (arg_t**) b)->name));
140 }
141 
142 static arg_t const **
143 arg_sort(const arg_t * defn, int32 n)
144 {
145  const arg_t ** pos;
146  int32 i;
147 
148  pos = (arg_t const **) ckd_calloc(n, sizeof(arg_t *));
149  for (i = 0; i < n; ++i)
150  pos[i] = &defn[i];
151  qsort(pos, n, sizeof(arg_t *), cmp_name);
152 
153  return pos;
154 }
155 
156 static size_t
157 strnappend(char **dest, size_t *dest_allocation,
158  const char *source, size_t n)
159 {
160  size_t source_len, required_allocation;
161 
162  if (dest == NULL || dest_allocation == NULL)
163  return -1;
164  if (*dest == NULL && *dest_allocation != 0)
165  return -1;
166  if (source == NULL)
167  return *dest_allocation;
168 
169  source_len = strlen(source);
170  if (n && n < source_len)
171  source_len = n;
172 
173  required_allocation = (*dest ? strlen(*dest) : 0) + source_len + 1;
174  if (*dest_allocation < required_allocation) {
175  if (*dest_allocation == 0) {
176  *dest = (char *)ckd_calloc(required_allocation * 2, 1);
177  } else {
178  *dest = (char *)ckd_realloc(*dest, required_allocation * 2);
179  }
180  *dest_allocation = required_allocation * 2;
181  }
182 
183  strncat(*dest, source, source_len);
184 
185  return *dest_allocation;
186 }
187 
188 static size_t
189 strappend(char **dest, size_t *dest_allocation,
190  const char *source)
191 {
192  return strnappend(dest, dest_allocation, source, 0);
193 }
194 
195 static char*
196 arg_resolve_env(const char *str)
197 {
198  char *resolved_str = NULL;
199  char env_name[100];
200  const char *env_val;
201  size_t alloced = 0;
202  const char *i = str, *j;
203 
204  /* calculate required resolved_str size */
205  do {
206  j = strstr(i, "$(");
207  if (j != NULL) {
208  if (j != i) {
209  strnappend(&resolved_str, &alloced, i, j - i);
210  i = j;
211  }
212  j = strchr(i + 2, ')');
213  if (j != NULL) {
214  if (j - (i + 2) < 100) {
215  strncpy(env_name, i + 2, j - (i + 2));
216  env_name[j - (i + 2)] = '\0';
217  #if !defined(_WIN32_WCE)
218  env_val = getenv(env_name);
219  if (env_val)
220  strappend(&resolved_str, &alloced, env_val);
221  #else
222  env_val = 0;
223  #endif
224  }
225  i = j + 1;
226  } else {
227  /* unclosed, copy and skip */
228  j = i + 2;
229  strnappend(&resolved_str, &alloced, i, j - i);
230  i = j;
231  }
232  } else {
233  strappend(&resolved_str, &alloced, i);
234  }
235  } while(j != NULL);
236 
237  return resolved_str;
238 }
239 
240 static void
241 arg_dump_r(cmd_ln_t *cmdln, FILE *fp, const arg_t * defn, int32 doc)
242 {
243  arg_t const **pos;
244  int32 i, n;
245  size_t l;
246  int32 namelen, deflen;
247  anytype_t *vp;
248  char const **array;
249 
250  /* No definitions, do nothing. */
251  if (defn == NULL || fp == NULL)
252  return;
253 
254  /* Find max lengths of name and default value fields, and #entries in defn */
255  n = arg_strlen(defn, &namelen, &deflen);
256  /* E_INFO("String length %d. Name length %d, Default Length %d\n",n, namelen, deflen); */
257  namelen = namelen & 0xfffffff8; /* Previous tab position */
258  deflen = deflen & 0xfffffff8; /* Previous tab position */
259 
260  fprintf(fp, "[NAME]");
261  for (l = strlen("[NAME]"); l < namelen; l += 8)
262  fprintf(fp, "\t");
263  fprintf(fp, "\t[DEFLT]");
264  for (l = strlen("[DEFLT]"); l < deflen; l += 8)
265  fprintf(fp, "\t");
266 
267  if (doc) {
268  fprintf(fp, "\t[DESCR]\n");
269  }
270  else {
271  fprintf(fp, "\t[VALUE]\n");
272  }
273 
274  /* Print current configuration, sorted by name */
275  pos = arg_sort(defn, n);
276  for (i = 0; i < n; i++) {
277  fprintf(fp, "%s", pos[i]->name);
278  for (l = strlen(pos[i]->name); l < namelen; l += 8)
279  fprintf(fp, "\t");
280 
281  fprintf(fp, "\t");
282  if (pos[i]->deflt) {
283  fprintf(fp, "%s", pos[i]->deflt);
284  l = strlen(pos[i]->deflt);
285  }
286  else
287  l = 0;
288  for (; l < deflen; l += 8)
289  fprintf(fp, "\t");
290 
291  fprintf(fp, "\t");
292  if (doc) {
293  if (pos[i]->doc)
294  fprintf(fp, "%s", pos[i]->doc);
295  }
296  else {
297  vp = cmd_ln_access_r(cmdln, pos[i]->name);
298  if (vp) {
299  switch (pos[i]->type) {
300  case ARG_INTEGER:
301  case REQARG_INTEGER:
302  fprintf(fp, "%ld", vp->i);
303  break;
304  case ARG_FLOATING:
305  case REQARG_FLOATING:
306  fprintf(fp, "%e", vp->fl);
307  break;
308  case ARG_STRING:
309  case REQARG_STRING:
310  if (vp->ptr)
311  fprintf(fp, "%s", (char *)vp->ptr);
312  break;
313  case ARG_STRING_LIST:
314  array = (char const**)vp->ptr;
315  if (array)
316  for (l = 0; array[l] != 0; l++) {
317  fprintf(fp, "%s,", array[l]);
318  }
319  break;
320  case ARG_BOOLEAN:
321  case REQARG_BOOLEAN:
322  fprintf(fp, "%s", vp->i ? "yes" : "no");
323  break;
324  default:
325  E_ERROR("Unknown argument type: %d\n", pos[i]->type);
326  }
327  }
328  }
329 
330  fprintf(fp, "\n");
331  }
332  ckd_free(pos);
333 
334  fprintf(fp, "\n");
335 }
336 
337 static char **
338 parse_string_list(const char *str)
339 {
340  int count, i, j;
341  const char *p;
342  char **result;
343 
344  p = str;
345  count = 1;
346  while (*p) {
347  if (*p == ',')
348  count++;
349  p++;
350  }
351  /* Should end with NULL */
352  result = (char **) ckd_calloc(count + 1, sizeof(char *));
353  p = str;
354  for (i = 0; i < count; i++) {
355  for (j = 0; p[j] != ',' && p[j] != 0; j++);
356  result[i] = (char *)ckd_calloc(j + 1, sizeof(char));
357  strncpy( result[i], p, j);
358  p = p + j + 1;
359  }
360  return result;
361 }
362 
363 static cmd_ln_val_t *
364 cmd_ln_val_init(int t, const char *str)
365 {
366  cmd_ln_val_t *v;
367  anytype_t val;
368  char *e_str;
369 
370  if (!str) {
371  /* For lack of a better default value. */
372  memset(&val, 0, sizeof(val));
373  }
374  else {
375  int valid = 1;
376  e_str = arg_resolve_env(str);
377 
378  switch (t) {
379  case ARG_INTEGER:
380  case REQARG_INTEGER:
381  if (sscanf(e_str, "%ld", &val.i) != 1)
382  valid = 0;
383  break;
384  case ARG_FLOATING:
385  case REQARG_FLOATING:
386  if (e_str == NULL || e_str[0] == 0)
387  valid = 0;
388  val.fl = atof_c(e_str);
389  break;
390  case ARG_BOOLEAN:
391  case REQARG_BOOLEAN:
392  if ((e_str[0] == 'y') || (e_str[0] == 't') ||
393  (e_str[0] == 'Y') || (e_str[0] == 'T') || (e_str[0] == '1')) {
394  val.i = TRUE;
395  }
396  else if ((e_str[0] == 'n') || (e_str[0] == 'f') ||
397  (e_str[0] == 'N') || (e_str[0] == 'F') |
398  (e_str[0] == '0')) {
399  val.i = FALSE;
400  }
401  else {
402  E_ERROR("Unparsed boolean value '%s'\n", str);
403  valid = 0;
404  }
405  break;
406  case ARG_STRING:
407  case REQARG_STRING:
408  val.ptr = ckd_salloc(e_str);
409  break;
410  case ARG_STRING_LIST:
411  val.ptr = parse_string_list(e_str);
412  break;
413  default:
414  E_ERROR("Unknown argument type: %d\n", t);
415  valid = 0;
416  }
417 
418  ckd_free(e_str);
419  if (valid == 0)
420  return NULL;
421  }
422 
423  v = (cmd_ln_val_t *)ckd_calloc(1, sizeof(*v));
424  memcpy(v, &val, sizeof(val));
425  v->type = t;
426 
427  return v;
428 }
429 
430 /*
431  * Handles option parsing for cmd_ln_parse_file_r() and cmd_ln_init()
432  * also takes care of storing argv.
433  * DO NOT call it from cmd_ln_parse_r()
434  */
435 static cmd_ln_t *
436 parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict)
437 {
438  cmd_ln_t *new_cmdln;
439 
440  new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict);
441  /* If this failed then clean up and return NULL. */
442  if (new_cmdln == NULL) {
443  int32 i;
444  for (i = 0; i < argc; ++i)
445  ckd_free(argv[i]);
446  ckd_free(argv);
447  return NULL;
448  }
449 
450  /* Otherwise, we need to add the contents of f_argv to the new object. */
451  if (new_cmdln == cmdln) {
452  /* If we are adding to a previously passed-in cmdln, then
453  * store our allocated strings in its f_argv. */
454  new_cmdln->f_argv = (char **)ckd_realloc(new_cmdln->f_argv,
455  (new_cmdln->f_argc + argc)
456  * sizeof(*new_cmdln->f_argv));
457  memcpy(new_cmdln->f_argv + new_cmdln->f_argc, argv,
458  argc * sizeof(*argv));
459  ckd_free(argv);
460  new_cmdln->f_argc += argc;
461  }
462  else {
463  /* Otherwise, store f_argc and f_argv. */
464  new_cmdln->f_argc = argc;
465  new_cmdln->f_argv = argv;
466  }
467 
468  return new_cmdln;
469 }
470 
471 void
472 cmd_ln_val_free(cmd_ln_val_t *val)
473 {
474  int i;
475  if (val->type & ARG_STRING_LIST) {
476  char ** array = (char **)val->val.ptr;
477  if (array) {
478  for (i = 0; array[i] != NULL; i++) {
479  ckd_free(array[i]);
480  }
481  ckd_free(array);
482  }
483  }
484  if (val->type & ARG_STRING)
485  ckd_free(val->val.ptr);
486  ckd_free(val);
487 }
488 
489 cmd_ln_t *
491 {
492  return global_cmdln;
493 }
494 
495 void
496 cmd_ln_appl_enter(int argc, char *argv[],
497  const char *default_argfn,
498  const arg_t * defn)
499 {
500  /* Look for default or specified arguments file */
501  const char *str;
502 
503  str = NULL;
504 
505  if ((argc == 2) && (strcmp(argv[1], "help") == 0)) {
506  cmd_ln_print_help(stderr, defn);
507  exit(1);
508  }
509 
510  if ((argc == 2) && (argv[1][0] != '-'))
511  str = argv[1];
512  else if (argc == 1) {
513  FILE *fp;
514  E_INFO("Looking for default argument file: %s\n", default_argfn);
515 
516  if ((fp = fopen(default_argfn, "r")) == NULL) {
517  E_INFO("Can't find default argument file %s.\n",
518  default_argfn);
519  }
520  else {
521  str = default_argfn;
522  }
523  if (fp != NULL)
524  fclose(fp);
525  }
526 
527 
528  if (str) {
529  /* Build command line argument list from file */
530  E_INFO("Parsing command lines from file %s\n", str);
531  if (cmd_ln_parse_file(defn, str, TRUE)) {
532  E_INFOCONT("Usage:\n");
533  E_INFOCONT("\t%s argument-list, or\n", argv[0]);
534  E_INFOCONT("\t%s [argument-file] (default file: . %s)\n\n",
535  argv[0], default_argfn);
536  cmd_ln_print_help(stderr, defn);
537  exit(1);
538  }
539  }
540  else {
541  cmd_ln_parse(defn, argc, argv, TRUE);
542  }
543 }
544 
545 void
547 {
548  cmd_ln_free();
549 }
550 
551 
552 cmd_ln_t *
553 cmd_ln_parse_r(cmd_ln_t *inout_cmdln, const arg_t * defn, int32 argc, char *argv[], int strict)
554 {
555  int32 i, j, n, argstart;
556  hash_table_t *defidx = NULL;
557  cmd_ln_t *cmdln;
558 
559  /* Construct command-line object */
560  if (inout_cmdln == NULL) {
561  cmdln = (cmd_ln_t*)ckd_calloc(1, sizeof(*cmdln));
562  cmdln->refcount = 1;
563  }
564  else
565  cmdln = inout_cmdln;
566 
567  /* Build a hash table for argument definitions */
568  defidx = hash_table_new(50, 0);
569  if (defn) {
570  for (n = 0; defn[n].name; n++) {
571  void *v;
572 
573  v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]);
574  if (strict && (v != &defn[n])) {
575  E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name);
576  goto error;
577  }
578  }
579  }
580  else {
581  /* No definitions. */
582  n = 0;
583  }
584 
585  /* Allocate memory for argument values */
586  if (cmdln->ht == NULL)
587  cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ );
588 
589 
590  /* skip argv[0] if it doesn't start with dash */
591  argstart = 0;
592  if (argc > 0 && argv[0][0] != '-') {
593  argstart = 1;
594  }
595 
596  /* Parse command line arguments (name-value pairs) */
597  for (j = argstart; j < argc; j += 2) {
598  arg_t *argdef;
599  cmd_ln_val_t *val;
600  void *v;
601 
602  if (hash_table_lookup(defidx, argv[j], &v) < 0) {
603  if (strict) {
604  E_ERROR("Unknown argument name '%s'\n", argv[j]);
605  goto error;
606  }
607  else if (defn == NULL)
608  v = NULL;
609  else
610  continue;
611  }
612  argdef = (arg_t *)v;
613 
614  /* Enter argument value */
615  if (j + 1 >= argc) {
616  cmd_ln_print_help_r(cmdln, stderr, defn);
617  E_ERROR("Argument value for '%s' missing\n", argv[j]);
618  goto error;
619  }
620 
621  if (argdef == NULL)
622  val = cmd_ln_val_init(ARG_STRING, argv[j + 1]);
623  else {
624  if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) {
625  cmd_ln_print_help_r(cmdln, stderr, defn);
626  E_ERROR("Bad argument value for %s: %s\n", argv[j],
627  argv[j + 1]);
628  goto error;
629  }
630  }
631 
632  if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) !=
633  (void *)val)
634  {
635  if (strict) {
636  cmd_ln_val_free(val);
637  E_ERROR("Duplicate argument name in arguments: %s\n",
638  argdef->name);
639  goto error;
640  }
641  else {
642  v = hash_table_replace(cmdln->ht, argv[j], (void *)val);
643  cmd_ln_val_free((cmd_ln_val_t *)v);
644  }
645  }
646  }
647 
648  /* Fill in default values, if any, for unspecified arguments */
649  for (i = 0; i < n; i++) {
650  cmd_ln_val_t *val;
651  void *v;
652 
653  if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) {
654  if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) {
655  E_ERROR
656  ("Bad default argument value for %s: %s\n",
657  defn[i].name, defn[i].deflt);
658  goto error;
659  }
660  hash_table_enter(cmdln->ht, defn[i].name, (void *)val);
661  }
662  }
663 
664  /* Check for required arguments; exit if any missing */
665  j = 0;
666  for (i = 0; i < n; i++) {
667  if (defn[i].type & ARG_REQUIRED) {
668  void *v;
669  if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0)
670  E_ERROR("Missing required argument %s\n", defn[i].name);
671  }
672  }
673  if (j > 0) {
674  cmd_ln_print_help_r(cmdln, stderr, defn);
675  goto error;
676  }
677 
678  if (strict && argc == 1) {
679  E_ERROR("No arguments given, available options are:\n");
680  cmd_ln_print_help_r(cmdln, stderr, defn);
681  if (defidx)
682  hash_table_free(defidx);
683  if (inout_cmdln == NULL)
684  cmd_ln_free_r(cmdln);
685  return NULL;
686  }
687 
688  /* If we use it from something except pocketsphinx, print current values */
689  if (!cmd_ln_exists_r(cmdln, "-logfn") && err_get_logfp()) {
690  cmd_ln_print_values_r(cmdln, err_get_logfp(), defn);
691  }
692 
693  hash_table_free(defidx);
694  return cmdln;
695 
696  error:
697  if (defidx)
698  hash_table_free(defidx);
699  if (inout_cmdln == NULL)
700  cmd_ln_free_r(cmdln);
701  E_ERROR("Failed to parse arguments list\n");
702  return NULL;
703 }
704 
705 cmd_ln_t *
706 cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)
707 {
708  va_list args;
709  const char *arg, *val;
710  char **f_argv;
711  int32 f_argc;
712 
713  va_start(args, strict);
714  f_argc = 0;
715  while ((arg = va_arg(args, const char *))) {
716  ++f_argc;
717  val = va_arg(args, const char*);
718  if (val == NULL) {
719  E_ERROR("Number of arguments must be even!\n");
720  return NULL;
721  }
722  ++f_argc;
723  }
724  va_end(args);
725 
726  /* Now allocate f_argv */
727  f_argv = (char**)ckd_calloc(f_argc, sizeof(*f_argv));
728  va_start(args, strict);
729  f_argc = 0;
730  while ((arg = va_arg(args, const char *))) {
731  f_argv[f_argc] = ckd_salloc(arg);
732  ++f_argc;
733  val = va_arg(args, const char*);
734  f_argv[f_argc] = ckd_salloc(val);
735  ++f_argc;
736  }
737  va_end(args);
738 
739  return parse_options(inout_cmdln, defn, f_argc, f_argv, strict);
740 }
741 
742 int
743 cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict)
744 {
745  cmd_ln_t *cmdln;
746 
747  cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict);
748  if (cmdln == NULL) {
749  /* Old, bogus behaviour... */
750  E_ERROR("Failed to parse arguments list, forced exit\n");
751  exit(-1);
752  }
753  /* Initialize global_cmdln if not present. */
754  if (global_cmdln == NULL) {
755  global_cmdln = cmdln;
756  }
757  return 0;
758 }
759 
760 cmd_ln_t *
761 cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict)
762 {
763  FILE *file;
764  int argc;
765  int argv_size;
766  char *str;
767  int arg_max_length = 512;
768  int len = 0;
769  int quoting, ch;
770  char **f_argv;
771  int rv = 0;
772  const char separator[] = " \t\r\n";
773 
774  if ((file = fopen(filename, "r")) == NULL) {
775  E_ERROR("Cannot open configuration file %s for reading\n",
776  filename);
777  return NULL;
778  }
779 
780  ch = fgetc(file);
781  /* Skip to the next interesting character */
782  for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
783 
784  if (ch == EOF) {
785  fclose(file);
786  return NULL;
787  }
788 
789  /*
790  * Initialize default argv, argc, and argv_size.
791  */
792  argv_size = 10;
793  argc = 0;
794  f_argv = (char **)ckd_calloc(argv_size, sizeof(char *));
795  /* Silently make room for \0 */
796  str = (char* )ckd_calloc(arg_max_length + 1, sizeof(char));
797  quoting = 0;
798 
799  do {
800  /* Handle arguments that are commented out */
801  if (len == 0 && argc % 2 == 0) {
802  while (ch == '#') {
803  /* Skip everything until newline */
804  for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ;
805  /* Skip to the next interesting character */
806  for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
807  }
808 
809  /* Check if we are at the last line (without anything interesting in it) */
810  if (ch == EOF)
811  break;
812  }
813 
814  /* Handle quoted arguments */
815  if (ch == '"' || ch == '\'') {
816  if (quoting == ch) /* End a quoted section with the same type */
817  quoting = 0;
818  else if (quoting) {
819  E_ERROR("Nesting quotations is not supported!\n");
820  rv = 1;
821  break;
822  }
823  else
824  quoting = ch; /* Start a quoted section */
825  }
826  else if (ch == EOF || (!quoting && strchr(separator, ch))) {
827  /* Reallocate argv so it is big enough to contain all the arguments */
828  if (argc >= argv_size) {
829  char **tmp_argv;
830  if (!(tmp_argv =
831  (char **)ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) {
832  rv = 1;
833  break;
834  }
835  f_argv = tmp_argv;
836  argv_size *= 2;
837  }
838  /* Add the string to the list of arguments */
839  f_argv[argc] = ckd_salloc(str);
840  len = 0;
841  str[0] = '\0';
842  argc++;
843 
844  if (quoting)
845  E_WARN("Unclosed quotation, having EOF close it...\n");
846 
847  /* Skip to the next interesting character */
848  for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
849 
850  if (ch == EOF)
851  break;
852 
853  /* We already have the next character */
854  continue;
855  }
856  else {
857  if (len >= arg_max_length) {
858  /* Make room for more chars (including the \0 !) */
859  char *tmp_str = str;
860  if ((tmp_str = (char *)ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) {
861  rv = 1;
862  break;
863  }
864  str = tmp_str;
865  arg_max_length *= 2;
866  }
867  /* Add the char to the argument string */
868  str[len++] = ch;
869  /* Always null terminate */
870  str[len] = '\0';
871  }
872 
873  ch = fgetc(file);
874  } while (1);
875 
876  fclose(file);
877 
878  ckd_free(str);
879 
880  if (rv) {
881  for (ch = 0; ch < argc; ++ch)
882  ckd_free(f_argv[ch]);
883  ckd_free(f_argv);
884  return NULL;
885  }
886 
887  return parse_options(inout_cmdln, defn, argc, f_argv, strict);
888 }
889 
890 int
891 cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict)
892 {
893  cmd_ln_t *cmdln;
894 
895  cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict);
896  if (cmdln == NULL) {
897  return -1;
898  }
899  /* Initialize global_cmdln if not present. */
900  if (global_cmdln == NULL) {
901  global_cmdln = cmdln;
902  }
903  return 0;
904 }
905 
906 void
907 cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE *fp, arg_t const* defn)
908 {
909  if (defn == NULL)
910  return;
911  fprintf(fp, "Arguments list definition:\n");
912  arg_dump_r(cmdln, fp, defn, TRUE);
913 }
914 
915 void
916 cmd_ln_print_values_r(cmd_ln_t *cmdln, FILE *fp, arg_t const* defn)
917 {
918  if (defn == NULL)
919  return;
920  fprintf(fp, "Current configuration:\n");
921  arg_dump_r(cmdln, fp, defn, FALSE);
922 }
923 
924 int
925 cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name)
926 {
927  void *val;
928  if (cmdln == NULL)
929  return FALSE;
930  return (hash_table_lookup(cmdln->ht, name, &val) == 0);
931 }
932 
933 anytype_t *
934 cmd_ln_access_r(cmd_ln_t *cmdln, const char *name)
935 {
936  void *val;
937  if (hash_table_lookup(cmdln->ht, name, &val) < 0) {
938  E_ERROR("Unknown argument: %s\n", name);
939  return NULL;
940  }
941  return (anytype_t *)val;
942 }
943 
944 char const *
945 cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
946 {
947  anytype_t *val;
948  val = cmd_ln_access_r(cmdln, name);
949  if (val == NULL)
950  return NULL;
951  return (char const *)val->ptr;
952 }
953 
954 char const **
955 cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name)
956 {
957  anytype_t *val;
958  val = cmd_ln_access_r(cmdln, name);
959  if (val == NULL)
960  return NULL;
961  return (char const **)val->ptr;
962 }
963 
964 long
965 cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
966 {
967  anytype_t *val;
968  val = cmd_ln_access_r(cmdln, name);
969  if (val == NULL)
970  return 0L;
971  return val->i;
972 }
973 
974 double
975 cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
976 {
977  anytype_t *val;
978  val = cmd_ln_access_r(cmdln, name);
979  if (val == NULL)
980  return 0.0;
981  return val->fl;
982 }
983 
984 void
985 cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
986 {
987  anytype_t *val;
988  val = cmd_ln_access_r(cmdln, name);
989  if (val == NULL) {
990  E_ERROR("Unknown argument: %s\n", name);
991  return;
992  }
993  ckd_free(val->ptr);
994  if (str == NULL)
995  val->ptr = NULL;
996  else
997  val->ptr = ckd_salloc(str);
998 }
999 
1000 void
1001 cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
1002 {
1003  anytype_t *val;
1004  val = cmd_ln_access_r(cmdln, name);
1005  if (val == NULL) {
1006  E_ERROR("Unknown argument: %s\n", name);
1007  return;
1008  }
1009  val->i = iv;
1010 }
1011 
1012 void
1013 cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
1014 {
1015  anytype_t *val;
1016  val = cmd_ln_access_r(cmdln, name);
1017  if (val == NULL) {
1018  E_ERROR("Unknown argument: %s\n", name);
1019  return;
1020  }
1021  val->fl = fv;
1022 }
1023 
1024 cmd_ln_t *
1026 {
1027  ++cmdln->refcount;
1028  return cmdln;
1029 }
1030 
1031 int
1033 {
1034  if (cmdln == NULL)
1035  return 0;
1036  if (--cmdln->refcount > 0)
1037  return cmdln->refcount;
1038 
1039  if (cmdln->ht) {
1040  glist_t entries;
1041  gnode_t *gn;
1042  int32 n;
1043 
1044  entries = hash_table_tolist(cmdln->ht, &n);
1045  for (gn = entries; gn; gn = gnode_next(gn)) {
1046  hash_entry_t *e = (hash_entry_t *)gnode_ptr(gn);
1047  cmd_ln_val_free((cmd_ln_val_t *)e->val);
1048  }
1049  glist_free(entries);
1050  hash_table_free(cmdln->ht);
1051  cmdln->ht = NULL;
1052  }
1053 
1054  if (cmdln->f_argv) {
1055  int32 i;
1056  for (i = 0; i < cmdln->f_argc; ++i) {
1057  ckd_free(cmdln->f_argv[i]);
1058  }
1059  ckd_free(cmdln->f_argv);
1060  cmdln->f_argv = NULL;
1061  cmdln->f_argc = 0;
1062  }
1063  ckd_free(cmdln);
1064  return 0;
1065 }
1066 
1067 void
1069 {
1070  cmd_ln_free_r(global_cmdln);
1071  global_cmdln = NULL;
1072 }
1073 
1074 /* 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:1025
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:975
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:965
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:309
#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:934
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:519
Sphinx'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:1001
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:623
#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:1032
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:925
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:553
#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:945
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:955
#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:490
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:580
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:907
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:695
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:916
A note by ARCHAN at 20050510: Technically what we use is so-called "hash table with buckets" 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:706
SPHINXBASE_EXPORT void cmd_ln_appl_exit(void)
Finalization routine corresponding to cmd_ln_appl_enter().
Definition: cmd_ln.c:546
#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:508
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 " \r\t\n" and putting each tokens into an argv[] for cmd_l...
Definition: cmd_ln.c:761
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:1013
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:743
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:985
#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:1068
#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:496
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 " \r\t\n" and putting each tokens into an argv[] for cmd_l...
Definition: cmd_ln.c:891