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