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