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 const** array = (char const **)val->val.ptr;
475  if (array) {
476  for (i = 0; array[i] != NULL; i++) {
477  ckd_free(val->val.ptr);
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  /* Echo command line */
558 #ifndef _WIN32_WCE
559  E_INFO("Parsing command line:\n");
560  for (i = 0; i < argc; i++) {
561  if (argv[i][0] == '-')
562  E_INFOCONT("\\\n\t");
563  E_INFOCONT("%s ", argv[i]);
564  }
565  E_INFOCONT("\n\n");
566  fflush(stderr);
567 #endif
568 
569  /* Construct command-line object */
570  if (inout_cmdln == NULL) {
571  cmdln = ckd_calloc(1, sizeof(*cmdln));
572  cmdln->refcount = 1;
573  }
574  else
575  cmdln = inout_cmdln;
576 
577  /* Build a hash table for argument definitions */
578  defidx = hash_table_new(50, 0);
579  if (defn) {
580  for (n = 0; defn[n].name; n++) {
581  void *v;
582 
583  v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]);
584  if (strict && (v != &defn[n])) {
585  E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name);
586  goto error;
587  }
588  }
589  }
590  else {
591  /* No definitions. */
592  n = 0;
593  }
594 
595  /* Allocate memory for argument values */
596  if (cmdln->ht == NULL)
597  cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ );
598 
599 
600  /* skip argv[0] if it doesn't start with dash */
601  argstart = 0;
602  if (argc > 0 && argv[0][0] != '-') {
603  argstart = 1;
604  }
605 
606  /* Parse command line arguments (name-value pairs) */
607  for (j = argstart; j < argc; j += 2) {
608  arg_t *argdef;
609  cmd_ln_val_t *val;
610  void *v;
611 
612  if (hash_table_lookup(defidx, argv[j], &v) < 0) {
613  if (strict) {
614  E_ERROR("Unknown argument name '%s'\n", argv[j]);
615  goto error;
616  }
617  else if (defn == NULL)
618  v = NULL;
619  else
620  continue;
621  }
622  argdef = v;
623 
624  /* Enter argument value */
625  if (j + 1 >= argc) {
626  cmd_ln_print_help_r(cmdln, stderr, defn);
627  E_ERROR("Argument value for '%s' missing\n", argv[j]);
628  goto error;
629  }
630 
631  if (argdef == NULL)
632  val = cmd_ln_val_init(ARG_STRING, argv[j + 1]);
633  else {
634  if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) {
635  cmd_ln_print_help_r(cmdln, stderr, defn);
636  E_ERROR("Bad argument value for %s: %s\n", argv[j],
637  argv[j + 1]);
638  goto error;
639  }
640  }
641 
642  if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) != (void *)val) {
643  if (strict) {
644  cmd_ln_val_free(val);
645  E_ERROR("Duplicate argument name in arguments: %s\n",
646  argdef->name);
647  goto error;
648  }
649  else {
650  v = hash_table_replace(cmdln->ht, argv[j], (void *)val);
651  cmd_ln_val_free((cmd_ln_val_t *)v);
652  }
653  }
654  }
655 
656  /* Fill in default values, if any, for unspecified arguments */
657  for (i = 0; i < n; i++) {
658  cmd_ln_val_t *val;
659  void *v;
660 
661  if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) {
662  if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) {
663  E_ERROR
664  ("Bad default argument value for %s: %s\n",
665  defn[i].name, defn[i].deflt);
666  goto error;
667  }
668  hash_table_enter(cmdln->ht, defn[i].name, (void *)val);
669  }
670  }
671 
672  /* Check for required arguments; exit if any missing */
673  j = 0;
674  for (i = 0; i < n; i++) {
675  if (defn[i].type & ARG_REQUIRED) {
676  void *v;
677  if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0)
678  E_ERROR("Missing required argument %s\n", defn[i].name);
679  }
680  }
681  if (j > 0) {
682  cmd_ln_print_help_r(cmdln, stderr, defn);
683  goto error;
684  }
685 
686  if (strict && argc == 1) {
687  E_ERROR("No arguments given, exiting\n");
688  cmd_ln_print_help_r(cmdln, stderr, defn);
689  goto error;
690  }
691 
692 #ifndef _WIN32_WCE
693  /* Print configuration */
694  E_INFOCONT("Current configuration:\n");
695  arg_dump_r(cmdln, err_get_logfp(), defn, 0);
696 #endif
697  hash_table_free(defidx);
698  return cmdln;
699 
700  error:
701  if (defidx)
702  hash_table_free(defidx);
703  if (inout_cmdln == NULL)
704  cmd_ln_free_r(cmdln);
705  E_ERROR("cmd_ln_parse_r failed\n");
706  return NULL;
707 }
708 
709 cmd_ln_t *
710 cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)
711 {
712  va_list args;
713  const char *arg, *val;
714  char **f_argv;
715  int32 f_argc;
716 
717  va_start(args, strict);
718  f_argc = 0;
719  while ((arg = va_arg(args, const char *))) {
720  ++f_argc;
721  val = va_arg(args, const char*);
722  if (val == NULL) {
723  E_ERROR("Number of arguments must be even!\n");
724  return NULL;
725  }
726  ++f_argc;
727  }
728  va_end(args);
729 
730  /* Now allocate f_argv */
731  f_argv = ckd_calloc(f_argc, sizeof(*f_argv));
732  va_start(args, strict);
733  f_argc = 0;
734  while ((arg = va_arg(args, const char *))) {
735  f_argv[f_argc] = ckd_salloc(arg);
736  ++f_argc;
737  val = va_arg(args, const char*);
738  f_argv[f_argc] = ckd_salloc(val);
739  ++f_argc;
740  }
741  va_end(args);
742 
743  return parse_options(inout_cmdln, defn, f_argc, f_argv, strict);
744 }
745 
746 int
747 cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict)
748 {
749  cmd_ln_t *cmdln;
750 
751  cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict);
752  if (cmdln == NULL) {
753  /* Old, bogus behaviour... */
754  E_ERROR("cmd_ln_parse failed, forced exit\n");
755  exit(-1);
756  }
757  /* Initialize global_cmdln if not present. */
758  if (global_cmdln == NULL) {
759  global_cmdln = cmdln;
760  }
761  return 0;
762 }
763 
764 cmd_ln_t *
765 cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict)
766 {
767  FILE *file;
768  int argc;
769  int argv_size;
770  char *str;
771  int arg_max_length = 512;
772  int len = 0;
773  int quoting, ch;
774  char **f_argv;
775  int rv = 0;
776  const char separator[] = " \t\r\n";
777 
778  if ((file = fopen(filename, "r")) == NULL) {
779  E_ERROR("Cannot open configuration file %s for reading\n",
780  filename);
781  return NULL;
782  }
783 
784  ch = fgetc(file);
785  /* Skip to the next interesting character */
786  for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
787 
788  if (ch == EOF) {
789  fclose(file);
790  return NULL;
791  }
792 
793  /*
794  * Initialize default argv, argc, and argv_size.
795  */
796  argv_size = 10;
797  argc = 0;
798  f_argv = ckd_calloc(argv_size, sizeof(char *));
799  /* Silently make room for \0 */
800  str = ckd_calloc(arg_max_length + 1, sizeof(char));
801  quoting = 0;
802 
803  do {
804  /* Handle arguments that are commented out */
805  if (len == 0 && argc % 2 == 0) {
806  while (ch == '#') {
807  /* Skip everything until newline */
808  for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ;
809  /* Skip to the next interesting character */
810  for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
811  }
812 
813  /* Check if we are at the last line (without anything interesting in it) */
814  if (ch == EOF)
815  break;
816  }
817 
818  /* Handle quoted arguments */
819  if (ch == '"' || ch == '\'') {
820  if (quoting == ch) /* End a quoted section with the same type */
821  quoting = 0;
822  else if (quoting) {
823  E_ERROR("Nesting quotations is not supported!\n");
824  rv = 1;
825  break;
826  }
827  else
828  quoting = ch; /* Start a quoted section */
829  }
830  else if (ch == EOF || (!quoting && strchr(separator, ch))) {
831  /* Reallocate argv so it is big enough to contain all the arguments */
832  if (argc >= argv_size) {
833  char **tmp_argv;
834  if (!(tmp_argv =
835  ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) {
836  rv = 1;
837  break;
838  }
839  f_argv = tmp_argv;
840  argv_size *= 2;
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 = 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, 1);
917  fflush(fp);
918 }
919 
920 int
921 cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name)
922 {
923  void *val;
924  if (cmdln == NULL)
925  return FALSE;
926  return (hash_table_lookup(cmdln->ht, name, &val) == 0);
927 }
928 
929 anytype_t *
930 cmd_ln_access_r(cmd_ln_t *cmdln, const char *name)
931 {
932  void *val;
933  if (hash_table_lookup(cmdln->ht, name, &val) < 0) {
934  E_ERROR("Unknown argument: %s\n", name);
935  return NULL;
936  }
937  return (anytype_t *)val;
938 }
939 
940 char const *
941 cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
942 {
943  anytype_t *val;
944  val = cmd_ln_access_r(cmdln, name);
945  if (val == NULL)
946  return NULL;
947  return (char const *)val->ptr;
948 }
949 
950 char const **
951 cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name)
952 {
953  anytype_t *val;
954  val = cmd_ln_access_r(cmdln, name);
955  if (val == NULL)
956  return NULL;
957  return (char const **)val->ptr;
958 }
959 
960 long
961 cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
962 {
963  anytype_t *val;
964  val = cmd_ln_access_r(cmdln, name);
965  if (val == NULL)
966  return 0L;
967  return val->i;
968 }
969 
970 double
971 cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
972 {
973  anytype_t *val;
974  val = cmd_ln_access_r(cmdln, name);
975  if (val == NULL)
976  return 0.0;
977  return val->fl;
978 }
979 
980 void
981 cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
982 {
983  anytype_t *val;
984  val = cmd_ln_access_r(cmdln, name);
985  if (val == NULL) {
986  E_ERROR("Unknown argument: %s\n", name);
987  return;
988  }
989  ckd_free(val->ptr);
990  if (str == NULL)
991  val->ptr = NULL;
992  else
993  val->ptr = ckd_salloc(str);
994 }
995 
996 void
997 cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
998 {
999  anytype_t *val;
1000  val = cmd_ln_access_r(cmdln, name);
1001  if (val == NULL) {
1002  E_ERROR("Unknown argument: %s\n", name);
1003  return;
1004  }
1005  val->i = iv;
1006 }
1007 
1008 void
1009 cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
1010 {
1011  anytype_t *val;
1012  val = cmd_ln_access_r(cmdln, name);
1013  if (val == NULL) {
1014  E_ERROR("Unknown argument: %s\n", name);
1015  return;
1016  }
1017  val->fl = fv;
1018 }
1019 
1020 cmd_ln_t *
1022 {
1023  ++cmdln->refcount;
1024  return cmdln;
1025 }
1026 
1027 int
1029 {
1030  if (cmdln == NULL)
1031  return 0;
1032  if (--cmdln->refcount > 0)
1033  return cmdln->refcount;
1034 
1035  if (cmdln->ht) {
1036  glist_t entries;
1037  gnode_t *gn;
1038  int32 n;
1039 
1040  entries = hash_table_tolist(cmdln->ht, &n);
1041  for (gn = entries; gn; gn = gnode_next(gn)) {
1042  hash_entry_t *e = gnode_ptr(gn);
1043  cmd_ln_val_free((cmd_ln_val_t *)e->val);
1044  }
1045  glist_free(entries);
1046  hash_table_free(cmdln->ht);
1047  cmdln->ht = NULL;
1048  }
1049 
1050  if (cmdln->f_argv) {
1051  int32 i;
1052  for (i = 0; i < cmdln->f_argc; ++i) {
1053  ckd_free(cmdln->f_argv[i]);
1054  }
1055  ckd_free(cmdln->f_argv);
1056  cmdln->f_argv = NULL;
1057  cmdln->f_argc = 0;
1058  }
1059  ckd_free(cmdln);
1060  return 0;
1061 }
1062 
1063 void
1065 {
1066  cmd_ln_free_r(global_cmdln);
1067  global_cmdln = NULL;
1068 }