cmd_ln.c
/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* ====================================================================
* Copyright (c) 1999-2004 Carnegie Mellon University. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* This work was supported in part by funding from the Defense Advanced
* Research Projects Agency and the National Science Foundation of the
* United States of America, and the CMU Sphinx Speech Consortium.
*
* THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ====================================================================
*
*/
/*
* cmd_ln.c -- Command line argument parsing.
*
* **********************************************
* CMU ARPA Speech Project
*
* Copyright (c) 1999 Carnegie Mellon University.
* ALL RIGHTS RESERVED.
* **********************************************
*
* HISTORY
*
* 10-Sep-1998 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
* Changed strcasecmp() call in cmp_name() to strcmp_nocase() call.
*
* 15-Jul-1997 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
* Added required arguments handling.
*
* 07-Dec-96 M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
* Created, based on Eric's implementation. Basically, combined several
* functions into one, eliminated validation, and simplified the interface.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef _MSC_VER
#pragma warning (disable: 4996 4018)
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "sphinxbase/cmd_ln.h"
#include "sphinxbase/err.h"
#include "sphinxbase/ckd_alloc.h"
#include "sphinxbase/hash_table.h"
#include "sphinxbase/case.h"
#include "sphinxbase/strfuncs.h"
typedef struct cmd_ln_val_s {
anytype_t val;
int type;
} cmd_ln_val_t;
struct cmd_ln_s {
int refcount;
hash_table_t *ht;
char **f_argv;
uint32 f_argc;
};
cmd_ln_t *global_cmdln;
static void arg_dump_r(cmd_ln_t *cmdln, FILE * fp, arg_t const *defn, int32 doc);
static cmd_ln_t * parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict);
/*
* Find max length of name and default fields in the given defn array.
* Return #items in defn array.
*/
static int32
arg_strlen(const arg_t * defn, int32 * namelen, int32 * deflen)
{
int32 i, l;
*namelen = *deflen = 0;
for (i = 0; defn[i].name; i++) {
l = strlen(defn[i].name);
if (*namelen < l)
*namelen = l;
if (defn[i].deflt)
l = strlen(defn[i].deflt);
else
l = strlen("(null)");
/* E_INFO("string default, %s , name %s, length %d\n",defn[i].deflt,defn[i].name,l); */
if (*deflen < l)
*deflen = l;
}
return i;
}
static int32
cmp_name(const void *a, const void *b)
{
return (strcmp_nocase
((* (arg_t**) a)->name,
(* (arg_t**) b)->name));
}
static const arg_t **
arg_sort(const arg_t * defn, int32 n)
{
const arg_t ** pos;
int32 i;
pos = (const arg_t **) ckd_calloc(n, sizeof(arg_t *));
for (i = 0; i < n; ++i)
pos[i] = &defn[i];
qsort(pos, n, sizeof(arg_t *), cmp_name);
return pos;
}
static size_t
strnappend(char **dest, size_t *dest_allocation,
const char *source, size_t n)
{
size_t source_len, required_allocation;
if (dest == NULL || dest_allocation == NULL)
return -1;
if (*dest == NULL && *dest_allocation != 0)
return -1;
if (source == NULL)
return *dest_allocation;
source_len = strlen(source);
if (n && n < source_len)
source_len = n;
required_allocation = (*dest ? strlen(*dest) : 0) + source_len + 1;
if (*dest_allocation < required_allocation) {
if (*dest_allocation == 0) {
*dest = ckd_calloc(required_allocation * 2, 1);
} else {
*dest = ckd_realloc(*dest, required_allocation * 2);
}
*dest_allocation = required_allocation * 2;
}
strncat(*dest, source, source_len);
return *dest_allocation;
}
static size_t
strappend(char **dest, size_t *dest_allocation,
const char *source)
{
return strnappend(dest, dest_allocation, source, 0);
}
static char*
arg_resolve_env(const char *str)
{
char *resolved_str = NULL;
char env_name[100];
const char *env_val;
size_t alloced = 0;
const char *i = str, *j;
/* calculate required resolved_str size */
do {
j = strstr(i, "$(");
if (j != NULL) {
if (j != i) {
strnappend(&resolved_str, &alloced, i, j - i);
i = j;
}
j = strchr(i + 2, ')');
if (j != NULL) {
if (j - (i + 2) < 100) {
strncpy(env_name, i + 2, j - (i + 2));
env_name[j - (i + 2)] = '\0';
#if !defined(_WIN32_WCE)
env_val = getenv(env_name);
if (env_val)
strappend(&resolved_str, &alloced, env_val);
#else
env_val = 0;
#endif
}
i = j + 1;
} else {
/* unclosed, copy and skip */
j = i + 2;
strnappend(&resolved_str, &alloced, i, j - i);
i = j;
}
} else {
strappend(&resolved_str, &alloced, i);
}
} while(j != NULL);
return resolved_str;
}
static void
arg_dump_r(cmd_ln_t *cmdln, FILE * fp, const arg_t * defn, int32 doc)
{
const arg_t **pos;
int32 i, l, n;
int32 namelen, deflen;
anytype_t *vp;
char const **array;
/* No definitions, do nothing. */
if (defn == NULL)
return;
if (fp == NULL)
return;
/* Find max lengths of name and default value fields, and #entries in defn */
n = arg_strlen(defn, &namelen, &deflen);
/* E_INFO("String length %d. Name length %d, Default Length %d\n",n, namelen, deflen); */
namelen = namelen & 0xfffffff8; /* Previous tab position */
deflen = deflen & 0xfffffff8; /* Previous tab position */
fprintf(fp, "[NAME]");
for (l = strlen("[NAME]"); l < namelen; l += 8)
fprintf(fp, "\t");
fprintf(fp, "\t[DEFLT]");
for (l = strlen("[DEFLT]"); l < deflen; l += 8)
fprintf(fp, "\t");
if (doc) {
fprintf(fp, "\t[DESCR]\n");
}
else {
fprintf(fp, "\t[VALUE]\n");
}
/* Print current configuration, sorted by name */
pos = arg_sort(defn, n);
for (i = 0; i < n; i++) {
fprintf(fp, "%s", pos[i]->name);
for (l = strlen(pos[i]->name); l < namelen; l += 8)
fprintf(fp, "\t");
fprintf(fp, "\t");
if (pos[i]->deflt) {
fprintf(fp, "%s", pos[i]->deflt);
l = strlen(pos[i]->deflt);
}
else
l = 0;
for (; l < deflen; l += 8)
fprintf(fp, "\t");
fprintf(fp, "\t");
if (doc) {
if (pos[i]->doc)
fprintf(fp, "%s", pos[i]->doc);
}
else {
vp = cmd_ln_access_r(cmdln, pos[i]->name);
if (vp) {
switch (pos[i]->type) {
case ARG_INTEGER:
case REQARG_INTEGER:
fprintf(fp, "%ld", vp->i);
break;
case ARG_FLOATING:
case REQARG_FLOATING:
fprintf(fp, "%e", vp->fl);
break;
case ARG_STRING:
case REQARG_STRING:
if (vp->ptr)
fprintf(fp, "%s", (char *)vp->ptr);
break;
case ARG_STRING_LIST:
array = (char const**)vp->ptr;
if (array)
for (l = 0; array[l] != 0; l++) {
fprintf(fp, "%s,", array[l]);
}
break;
case ARG_BOOLEAN:
case REQARG_BOOLEAN:
fprintf(fp, "%s", vp->i ? "yes" : "no");
break;
default:
E_ERROR("Unknown argument type: %d\n", pos[i]->type);
}
}
}
fprintf(fp, "\n");
}
ckd_free(pos);
fprintf(fp, "\n");
fflush(fp);
}
static char **
parse_string_list(const char *str)
{
int count, i, j;
const char *p;
char ** result;
p = str;
count = 1;
while (*p) {
if (*p == ',')
count++;
p++;
}
/* Should end with NULL */
result = (char **) ckd_calloc(count + 1, sizeof(char *));
p = str;
for (i = 0; i < count; i++) {
for (j = 0; p[j] != ',' && p[j] != 0; j++);
result[i] = ckd_calloc(j + 1, sizeof(char));
strncpy( result[i], p, j);
p = p + j + 1;
}
return result;
}
static cmd_ln_val_t *
cmd_ln_val_init(int t, const char *str)
{
cmd_ln_val_t *v;
anytype_t val;
char *e_str;
if (!str) {
/* For lack of a better default value. */
memset(&val, 0, sizeof(val));
}
else {
int valid = 1;
e_str = arg_resolve_env(str);
switch (t) {
case ARG_INTEGER:
case REQARG_INTEGER:
if (sscanf(e_str, "%ld", &val.i) != 1)
valid = 0;
break;
case ARG_FLOATING:
case REQARG_FLOATING:
if (e_str == NULL || e_str[0] == 0)
valid = 0;
val.fl = atof_c(e_str);
break;
case ARG_BOOLEAN:
case REQARG_BOOLEAN:
if ((e_str[0] == 'y') || (e_str[0] == 't') ||
(e_str[0] == 'Y') || (e_str[0] == 'T') || (e_str[0] == '1')) {
val.i = TRUE;
}
else if ((e_str[0] == 'n') || (e_str[0] == 'f') ||
(e_str[0] == 'N') || (e_str[0] == 'F') |
(e_str[0] == '0')) {
val.i = FALSE;
}
else {
E_ERROR("Unparsed boolean value '%s'\n", str);
valid = 0;
}
break;
case ARG_STRING:
case REQARG_STRING:
val.ptr = ckd_salloc(e_str);
break;
case ARG_STRING_LIST:
val.ptr = parse_string_list(e_str);
break;
default:
E_ERROR("Unknown argument type: %d\n", t);
valid = 0;
}
ckd_free(e_str);
if (valid == 0)
return NULL;
}
v = ckd_calloc(1, sizeof(*v));
memcpy(v, &val, sizeof(val));
v->type = t;
return v;
}
/*
* Handles option parsing for cmd_ln_parse_file_r() and cmd_ln_init()
* also takes care of storing argv.
* DO NOT call it from cmd_ln_parse_r()
*/
static cmd_ln_t *
parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict)
{
cmd_ln_t *new_cmdln;
new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict);
/* If this failed then clean up and return NULL. */
if (new_cmdln == NULL) {
int32 i;
for (i = 0; i < argc; ++i)
ckd_free(argv[i]);
ckd_free(argv);
return NULL;
}
/* Otherwise, we need to add the contents of f_argv to the new object. */
if (new_cmdln == cmdln) {
/* If we are adding to a previously passed-in cmdln, then
* store our allocated strings in its f_argv. */
new_cmdln->f_argv = ckd_realloc(new_cmdln->f_argv,
(new_cmdln->f_argc + argc)
* sizeof(*new_cmdln->f_argv));
memcpy(new_cmdln->f_argv + new_cmdln->f_argc, argv,
argc * sizeof(*argv));
ckd_free(argv);
new_cmdln->f_argc += argc;
}
else {
/* Otherwise, store f_argc and f_argv. */
new_cmdln->f_argc = argc;
new_cmdln->f_argv = argv;
}
return new_cmdln;
}
void
cmd_ln_val_free(cmd_ln_val_t *val)
{
int i;
if (val->type & ARG_STRING_LIST) {
char ** array = (char **)val->val.ptr;
if (array) {
for (i = 0; array[i] != NULL; i++) {
ckd_free(array[i]);
}
ckd_free(array);
}
}
if (val->type & ARG_STRING)
ckd_free(val->val.ptr);
ckd_free(val);
}
cmd_ln_t *
cmd_ln_get(void)
{
return global_cmdln;
}
void
cmd_ln_appl_enter(int argc, char *argv[],
const char *default_argfn,
const arg_t * defn)
{
/* Look for default or specified arguments file */
const char *str;
str = NULL;
if ((argc == 2) && (strcmp(argv[1], "help") == 0)) {
cmd_ln_print_help(stderr, defn);
exit(1);
}
if ((argc == 2) && (argv[1][0] != '-'))
str = argv[1];
else if (argc == 1) {
FILE *fp;
E_INFO("Looking for default argument file: %s\n", default_argfn);
if ((fp = fopen(default_argfn, "r")) == NULL) {
E_INFO("Can't find default argument file %s.\n",
default_argfn);
}
else {
str = default_argfn;
}
if (fp != NULL)
fclose(fp);
}
if (str) {
/* Build command line argument list from file */
E_INFO("Parsing command lines from file %s\n", str);
if (cmd_ln_parse_file(defn, str, TRUE)) {
E_INFOCONT("Usage:\n");
E_INFOCONT("\t%s argument-list, or\n", argv[0]);
E_INFOCONT("\t%s [argument-file] (default file: . %s)\n\n",
argv[0], default_argfn);
cmd_ln_print_help(stderr, defn);
exit(1);
}
}
else {
cmd_ln_parse(defn, argc, argv, TRUE);
}
}
void
cmd_ln_appl_exit()
{
cmd_ln_free();
}
cmd_ln_t *
cmd_ln_parse_r(cmd_ln_t *inout_cmdln, const arg_t * defn, int32 argc, char *argv[], int strict)
{
int32 i, j, n, argstart;
hash_table_t *defidx = NULL;
cmd_ln_t *cmdln;
/* Construct command-line object */
if (inout_cmdln == NULL) {
cmdln = ckd_calloc(1, sizeof(*cmdln));
cmdln->refcount = 1;
}
else
cmdln = inout_cmdln;
/* Build a hash table for argument definitions */
defidx = hash_table_new(50, 0);
if (defn) {
for (n = 0; defn[n].name; n++) {
void *v;
v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]);
if (strict && (v != &defn[n])) {
E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name);
goto error;
}
}
}
else {
/* No definitions. */
n = 0;
}
/* Allocate memory for argument values */
if (cmdln->ht == NULL)
cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ );
/* skip argv[0] if it doesn't start with dash */
argstart = 0;
if (argc > 0 && argv[0][0] != '-') {
argstart = 1;
}
/* Parse command line arguments (name-value pairs) */
for (j = argstart; j < argc; j += 2) {
arg_t *argdef;
cmd_ln_val_t *val;
void *v;
if (hash_table_lookup(defidx, argv[j], &v) < 0) {
if (strict) {
E_ERROR("Unknown argument name '%s'\n", argv[j]);
goto error;
}
else if (defn == NULL)
v = NULL;
else
continue;
}
argdef = v;
/* Enter argument value */
if (j + 1 >= argc) {
cmd_ln_print_help_r(cmdln, stderr, defn);
E_ERROR("Argument value for '%s' missing\n", argv[j]);
goto error;
}
if (argdef == NULL)
val = cmd_ln_val_init(ARG_STRING, argv[j + 1]);
else {
if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) {
cmd_ln_print_help_r(cmdln, stderr, defn);
E_ERROR("Bad argument value for %s: %s\n", argv[j],
argv[j + 1]);
goto error;
}
}
if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) != (void *)val) {
if (strict) {
cmd_ln_val_free(val);
E_ERROR("Duplicate argument name in arguments: %s\n",
argdef->name);
goto error;
}
else {
v = hash_table_replace(cmdln->ht, argv[j], (void *)val);
cmd_ln_val_free((cmd_ln_val_t *)v);
}
}
}
/* Fill in default values, if any, for unspecified arguments */
for (i = 0; i < n; i++) {
cmd_ln_val_t *val;
void *v;
if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) {
if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) {
E_ERROR
("Bad default argument value for %s: %s\n",
defn[i].name, defn[i].deflt);
goto error;
}
hash_table_enter(cmdln->ht, defn[i].name, (void *)val);
}
}
/* Check for required arguments; exit if any missing */
j = 0;
for (i = 0; i < n; i++) {
if (defn[i].type & ARG_REQUIRED) {
void *v;
if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0)
E_ERROR("Missing required argument %s\n", defn[i].name);
}
}
if (j > 0) {
cmd_ln_print_help_r(cmdln, stderr, defn);
goto error;
}
if (strict && argc == 1) {
E_ERROR("No arguments given, available options are:\n");
cmd_ln_print_help_r(cmdln, stderr, defn);
if (defidx)
hash_table_free(defidx);
if (inout_cmdln == NULL)
cmd_ln_free_r(cmdln);
return NULL;
}
#ifndef _WIN32_WCE
/* Set up logging. We need to do this earlier because we want to dump
* the information to the configured log, not to the stderr. */
if (cmd_ln_exists_r(cmdln, "-logfn") && cmd_ln_str_r(cmdln, "-logfn"))
err_set_logfile(cmd_ln_str_r(cmdln, "-logfn"));
/* Echo command line */
E_INFO("Parsing command line:\n");
for (i = 0; i < argc; i++) {
if (argv[i][0] == '-')
E_INFOCONT("\\\n\t");
E_INFOCONT("%s ", argv[i]);
}
E_INFOCONT("\n\n");
fflush(stderr);
/* Print configuration */
E_INFOCONT("Current configuration:\n");
arg_dump_r(cmdln, err_get_logfp(), defn, 0);
#endif
hash_table_free(defidx);
return cmdln;
error:
if (defidx)
hash_table_free(defidx);
if (inout_cmdln == NULL)
cmd_ln_free_r(cmdln);
E_ERROR("Failed to parse arguments list\n");
return NULL;
}
cmd_ln_t *
cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)
{
va_list args;
const char *arg, *val;
char **f_argv;
int32 f_argc;
va_start(args, strict);
f_argc = 0;
while ((arg = va_arg(args, const char *))) {
++f_argc;
val = va_arg(args, const char*);
if (val == NULL) {
E_ERROR("Number of arguments must be even!\n");
return NULL;
}
++f_argc;
}
va_end(args);
/* Now allocate f_argv */
f_argv = ckd_calloc(f_argc, sizeof(*f_argv));
va_start(args, strict);
f_argc = 0;
while ((arg = va_arg(args, const char *))) {
f_argv[f_argc] = ckd_salloc(arg);
++f_argc;
val = va_arg(args, const char*);
f_argv[f_argc] = ckd_salloc(val);
++f_argc;
}
va_end(args);
return parse_options(inout_cmdln, defn, f_argc, f_argv, strict);
}
int
cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict)
{
cmd_ln_t *cmdln;
cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict);
if (cmdln == NULL) {
/* Old, bogus behaviour... */
E_ERROR("Failed to parse arguments list, forced exit\n");
exit(-1);
}
/* Initialize global_cmdln if not present. */
if (global_cmdln == NULL) {
global_cmdln = cmdln;
}
return 0;
}
cmd_ln_t *
cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict)
{
FILE *file;
int argc;
int argv_size;
char *str;
int arg_max_length = 512;
int len = 0;
int quoting, ch;
char **f_argv;
int rv = 0;
const char separator[] = " \t\r\n";
if ((file = fopen(filename, "r")) == NULL) {
E_ERROR("Cannot open configuration file %s for reading\n",
filename);
return NULL;
}
ch = fgetc(file);
/* Skip to the next interesting character */
for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
if (ch == EOF) {
fclose(file);
return NULL;
}
/*
* Initialize default argv, argc, and argv_size.
*/
argv_size = 10;
argc = 0;
f_argv = ckd_calloc(argv_size, sizeof(char *));
/* Silently make room for \0 */
str = ckd_calloc(arg_max_length + 1, sizeof(char));
quoting = 0;
do {
/* Handle arguments that are commented out */
if (len == 0 && argc % 2 == 0) {
while (ch == '#') {
/* Skip everything until newline */
for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ;
/* Skip to the next interesting character */
for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
}
/* Check if we are at the last line (without anything interesting in it) */
if (ch == EOF)
break;
}
/* Handle quoted arguments */
if (ch == '"' || ch == '\'') {
if (quoting == ch) /* End a quoted section with the same type */
quoting = 0;
else if (quoting) {
E_ERROR("Nesting quotations is not supported!\n");
rv = 1;
break;
}
else
quoting = ch; /* Start a quoted section */
}
else if (ch == EOF || (!quoting && strchr(separator, ch))) {
/* Reallocate argv so it is big enough to contain all the arguments */
if (argc >= argv_size) {
char **tmp_argv;
if (!(tmp_argv =
ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) {
rv = 1;
break;
}
f_argv = tmp_argv;
argv_size *= 2;
}
/* Add the string to the list of arguments */
f_argv[argc] = ckd_salloc(str);
len = 0;
str[0] = '\0';
argc++;
if (quoting)
E_WARN("Unclosed quotation, having EOF close it...\n");
/* Skip to the next interesting character */
for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
if (ch == EOF)
break;
/* We already have the next character */
continue;
}
else {
if (len >= arg_max_length) {
/* Make room for more chars (including the \0 !) */
char *tmp_str = str;
if ((tmp_str = ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) {
rv = 1;
break;
}
str = tmp_str;
arg_max_length *= 2;
}
/* Add the char to the argument string */
str[len++] = ch;
/* Always null terminate */
str[len] = '\0';
}
ch = fgetc(file);
} while (1);
fclose(file);
ckd_free(str);
if (rv) {
for (ch = 0; ch < argc; ++ch)
ckd_free(f_argv[ch]);
ckd_free(f_argv);
return NULL;
}
return parse_options(inout_cmdln, defn, argc, f_argv, strict);
}
int
cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict)
{
cmd_ln_t *cmdln;
cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict);
if (cmdln == NULL) {
return -1;
}
/* Initialize global_cmdln if not present. */
if (global_cmdln == NULL) {
global_cmdln = cmdln;
}
return 0;
}
void
cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE * fp, arg_t const* defn)
{
if (defn == NULL)
return;
fprintf(fp, "Arguments list definition:\n");
arg_dump_r(cmdln, fp, defn, 1);
fflush(fp);
}
int
cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name)
{
void *val;
if (cmdln == NULL)
return FALSE;
return (hash_table_lookup(cmdln->ht, name, &val) == 0);
}
anytype_t *
cmd_ln_access_r(cmd_ln_t *cmdln, const char *name)
{
void *val;
if (hash_table_lookup(cmdln->ht, name, &val) < 0) {
E_ERROR("Unknown argument: %s\n", name);
return NULL;
}
return (anytype_t *)val;
}
char const *
cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
{
anytype_t *val;
val = cmd_ln_access_r(cmdln, name);
if (val == NULL)
return NULL;
return (char const *)val->ptr;
}
char const **
cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name)
{
anytype_t *val;
val = cmd_ln_access_r(cmdln, name);
if (val == NULL)
return NULL;
return (char const **)val->ptr;
}
long
cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
{
anytype_t *val;
val = cmd_ln_access_r(cmdln, name);
if (val == NULL)
return 0L;
return val->i;
}
double
cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
{
anytype_t *val;
val = cmd_ln_access_r(cmdln, name);
if (val == NULL)
return 0.0;
return val->fl;
}
void
cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
{
anytype_t *val;
val = cmd_ln_access_r(cmdln, name);
if (val == NULL) {
E_ERROR("Unknown argument: %s\n", name);
return;
}
ckd_free(val->ptr);
if (str == NULL)
val->ptr = NULL;
else
val->ptr = ckd_salloc(str);
}
void
cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
{
anytype_t *val;
val = cmd_ln_access_r(cmdln, name);
if (val == NULL) {
E_ERROR("Unknown argument: %s\n", name);
return;
}
val->i = iv;
}
void
cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
{
anytype_t *val;
val = cmd_ln_access_r(cmdln, name);
if (val == NULL) {
E_ERROR("Unknown argument: %s\n", name);
return;
}
val->fl = fv;
}
cmd_ln_t *
cmd_ln_retain(cmd_ln_t *cmdln)
{
++cmdln->refcount;
return cmdln;
}
int
cmd_ln_free_r(cmd_ln_t *cmdln)
{
if (cmdln == NULL)
return 0;
if (--cmdln->refcount > 0)
return cmdln->refcount;
if (cmdln->ht) {
glist_t entries;
gnode_t *gn;
int32 n;
entries = hash_table_tolist(cmdln->ht, &n);
for (gn = entries; gn; gn = gnode_next(gn)) {
hash_entry_t *e = gnode_ptr(gn);
cmd_ln_val_free((cmd_ln_val_t *)e->val);
}
glist_free(entries);
hash_table_free(cmdln->ht);
cmdln->ht = NULL;
}
if (cmdln->f_argv) {
int32 i;
for (i = 0; i < cmdln->f_argc; ++i) {
ckd_free(cmdln->f_argv[i]);
}
ckd_free(cmdln->f_argv);
cmdln->f_argv = NULL;
cmdln->f_argc = 0;
}
ckd_free(cmdln);
return 0;
}
void
cmd_ln_free(void)
{
cmd_ln_free_r(global_cmdln);
global_cmdln = NULL;
}
REQARG_BOOLEAN
#define REQARG_BOOLEAN
Required boolean argument.
Definition: cmd_ln.h:139
cmd_ln.h
Command-line and other configurationparsing and handling.
cmd_ln_retain
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
strfuncs.h
Miscellaneous useful string functions.
cmd_ln_float_r
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
cmd_ln_int_r
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
hash_table_lookup
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
ckd_calloc
#define ckd_calloc(n, sz)
Macros to simplify the use of above functions.
Definition: ckd_alloc.h:248
err_get_logfp
SPHINXBASE_EXPORT FILE * err_get_logfp(void)
Get the current logging filehandle.
Definition: err.c:157
REQARG_INTEGER
#define REQARG_INTEGER
Required integer argument.
Definition: cmd_ln.h:127
ARG_REQUIRED
#define ARG_REQUIRED
Bit indicating a required argument.
Definition: cmd_ln.h:102
cmd_ln_val_s
Definition: cmd_ln.c:85
ARG_STRING_LIST
#define ARG_STRING_LIST
Boolean (true/false) argument (optional).
Definition: cmd_ln.h:122
cmd_ln_access_r
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
hash_table_replace
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
E_INFO
#define E_INFO
Print logging information to standard error stream.
Definition: err.h:147
ckd_alloc.h
Sphinx's memory allocation/deallocation routines.
cmd_ln_set_int_r
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
hash_table_tolist
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
REQARG_FLOATING
#define REQARG_FLOATING
Required floating point argument.
Definition: cmd_ln.h:131
cmd_ln_free_r
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
cmd_ln_exists_r
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
cmd_ln_parse_r
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
ARG_STRING
#define ARG_STRING
String argument (optional).
Definition: cmd_ln.h:114
gnode_s
A node in a generic list.
Definition: glist.h:100
ckd_salloc
#define ckd_salloc(ptr)
Macro for ckd_salloc
Definition: ckd_alloc.h:264
cmd_ln_str_r
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
hash_table_new
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
cmd_ln_str_list_r
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
REQARG_STRING
#define REQARG_STRING
Required string argument.
Definition: cmd_ln.h:135
ckd_free
SPHINXBASE_EXPORT void ckd_free(void *ptr)
Test and free a 1-D array.
Definition: ckd_alloc.c:241
cmd_ln_get
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
E_WARN
#define E_WARN
Print warning information to standard error stream.
Definition: err.h:164
strcmp_nocase
SPHINXBASE_EXPORT int32 strcmp_nocase(const char *str1, const char *str2)
(FIXME! The implementation is incorrect!) Case insensitive string compare.
Definition: case.c:94
cmd_ln_print_help
#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
err_set_logfile
SPHINXBASE_EXPORT int err_set_logfile(char const *file)
Append all log messages to a given file.
Definition: err.c:190
cmd_ln_print_help_r
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
hash_table_free
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
hash_entry_s
A note by ARCHAN at 20050510: Technically what we use is so-called "hash table with buckets" which is...
Definition: hash_table.h:149
atof_c
SPHINXBASE_EXPORT double atof_c(char const *str)
Locale independent version of atof().
Definition: strfuncs.c:56
hash_table_t
Definition: hash_table.h:159
glist_free
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
cmd_ln_s
Definition: cmd_ln.c:90
cmd_ln_init
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
cmd_ln_appl_exit
SPHINXBASE_EXPORT void cmd_ln_appl_exit(void)
Finalization routine corresponding to cmd_ln_appl_enter().
Definition: cmd_ln.c:544
gnode_ptr
#define gnode_ptr(g)
Head of a list of gnodes.
Definition: glist.h:109
E_INFOCONT
#define E_INFOCONT
Print logging information without header, to standard error stream.
Definition: err.h:153
err.h
Implementation of logging routines.
ARG_BOOLEAN
#define ARG_BOOLEAN
Boolean (true/false) argument (optional).
Definition: cmd_ln.h:118
hash_table_enter
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
cmd_ln_parse_file_r
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
arg_t
Argument definition structure.
cmd_ln_t
Opaque structure used to hold the results of command-line parsing.
cmd_ln_set_float_r
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
E_ERROR
#define E_ERROR
Print error message to standard error stream.
Definition: err.h:169
anytype_s
Union of basic types.
Definition: prim_type.h:107
hash_table.h
Hash table implementation.
cmd_ln_parse
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
cmd_ln_set_str_r
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
ARG_FLOATING
#define ARG_FLOATING
Floating point argument (optional).
Definition: cmd_ln.h:110
hash_entry_s::val
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
cmd_ln_free
SPHINXBASE_EXPORT void cmd_ln_free(void)
Free the global command line, if any exists.
Definition: cmd_ln.c:1072
ckd_realloc
#define ckd_realloc(ptr, sz)
Macro for ckd_realloc
Definition: ckd_alloc.h:258
ARG_INTEGER
#define ARG_INTEGER
Integer argument (optional).
Definition: cmd_ln.h:106
cmd_ln_appl_enter
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
case.h
Locale-independent implementation of case swapping operation.
cmd_ln_parse_file
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