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"
82#include "sphinxbase/case.h"
83#include "sphinxbase/strfuncs.h"
84
85typedef struct cmd_ln_val_s {
86 anytype_t val;
87 int type;
89
90struct cmd_ln_s {
91 int refcount;
92 hash_table_t *ht;
93 char **f_argv;
94 uint32 f_argc;
95};
96
98cmd_ln_t *global_cmdln;
99static void arg_dump_r(cmd_ln_t *cmdln, FILE * fp, arg_t const *defn, int32 doc);
100static 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 */
106static int32
107arg_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
130static int32
131cmp_name(const void *a, const void *b)
132{
133 return (strcmp_nocase
134 ((* (arg_t**) a)->name,
135 (* (arg_t**) b)->name));
136}
137
138static const arg_t **
139arg_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
152static size_t
153strnappend(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
184static size_t
185strappend(char **dest, size_t *dest_allocation,
186 const char *source)
187{
188 return strnappend(dest, dest_allocation, source, 0);
189}
190
191static char*
192arg_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
236static void
237arg_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
335static char **
336parse_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
361static cmd_ln_val_t *
362cmd_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 */
433static cmd_ln_t *
434parse_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
469void
470cmd_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
487cmd_ln_t *
489{
490 return global_cmdln;
491}
492
493void
494cmd_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
543void
545{
546 cmd_ln_free();
547}
548
549
550cmd_ln_t *
551cmd_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
717cmd_ln_t *
718cmd_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
754int
755cmd_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
772cmd_ln_t *
773cmd_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
902int
903cmd_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
918void
919cmd_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
928int
929cmd_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
937anytype_t *
938cmd_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
948char const *
949cmd_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
958char const **
959cmd_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
968long
969cmd_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
978double
979cmd_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
988void
989cmd_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
1004void
1005cmd_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
1016void
1017cmd_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
1028cmd_ln_t *
1030{
1031 ++cmdln->refcount;
1032 return cmdln;
1033}
1034
1035int
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
1071void
1073{
1074 cmd_ln_free_r(global_cmdln);
1075 global_cmdln = NULL;
1076}
Locale-independent implementation of case swapping operation.
SPHINXBASE_EXPORT int32 strcmp_nocase(const char *str1, const char *str2)
(FIXME! The implementation is incorrect!) Case insensitive string compare.
Definition case.c:94
Sphinx's memory allocation/deallocation routines.
SPHINXBASE_EXPORT void ckd_free(void *ptr)
Test and free a 1-D array.
Definition ckd_alloc.c:241
#define ckd_calloc(n, sz)
Macros to simplify the use of above functions.
Definition ckd_alloc.h:248
#define ckd_salloc(ptr)
Macro for ckd_salloc
Definition ckd_alloc.h:264
#define ckd_realloc(ptr, sz)
Macro for ckd_realloc
Definition ckd_alloc.h:258
Command-line and other configurationparsing and handling.
#define ARG_STRING_LIST
Boolean (true/false) argument (optional).
Definition cmd_ln.h:122
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 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 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 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
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 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_free(void)
Free the global command line, if any exists.
Definition cmd_ln.c:1072
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
#define ARG_STRING
String argument (optional).
Definition cmd_ln.h:114
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 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
#define ARG_INTEGER
Integer argument (optional).
Definition cmd_ln.h:106
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
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
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
#define REQARG_INTEGER
Required integer argument.
Definition cmd_ln.h:127
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
#define REQARG_FLOATING
Required floating point argument.
Definition cmd_ln.h:131
SPHINXBASE_EXPORT void cmd_ln_appl_exit(void)
Finalization routine corresponding to cmd_ln_appl_enter().
Definition cmd_ln.c:544
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
#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
#define ARG_REQUIRED
Bit indicating a required argument.
Definition cmd_ln.h:102
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 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
#define REQARG_STRING
Required string argument.
Definition cmd_ln.h:135
#define ARG_BOOLEAN
Boolean (true/false) argument (optional).
Definition cmd_ln.h:118
#define ARG_FLOATING
Floating point argument (optional).
Definition cmd_ln.h:110
#define REQARG_BOOLEAN
Required boolean argument.
Definition cmd_ln.h:139
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
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
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
Implementation of logging routines.
#define E_ERROR
Print error message to standard error stream.
Definition err.h:169
#define E_WARN
Print warning information to standard error stream.
Definition err.h:164
SPHINXBASE_EXPORT int err_set_logfile(char const *file)
Append all log messages to a given file.
Definition err.c:190
#define E_INFO
Print logging information to standard error stream.
Definition err.h:147
SPHINXBASE_EXPORT FILE * err_get_logfp(void)
Get the current logging filehandle.
Definition err.c:157
#define E_INFOCONT
Print logging information without header, to standard error stream.
Definition err.h:153
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
#define gnode_ptr(g)
Head of a list of gnodes.
Definition glist.h:109
Hash table implementation.
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 * 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
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
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
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 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
Miscellaneous useful string functions.
SPHINXBASE_EXPORT double atof_c(char const *str)
Locale independent version of atof().
Definition strfuncs.c:56
Argument definition structure.
Opaque structure used to hold the results of command-line parsing.
A node in a generic list.
Definition glist.h:100
A note by ARCHAN at 20050510: Technically what we use is so-called "hash table with buckets" which is...
Definition hash_table.h:149
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
Union of basic types.
Definition prim_type.h:107