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;
char *name;
} 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 *, FILE *, arg_t const *, int32);
static cmd_ln_t *
parse_options(cmd_ln_t *, const arg_t *, int32, char* [], int32);
/*
* 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 arg_t const **
arg_sort(const arg_t * defn, int32 n)
{
const arg_t ** pos;
int32 i;
pos = (arg_t const **) 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 = (char *)ckd_calloc(required_allocation * 2, 1);
} else {
*dest = (char *)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)
{
arg_t const **pos;
int32 i, n;
size_t l;
int32 namelen, deflen;
anytype_t *vp;
char const **array;
/* No definitions, do nothing. */
if (defn == NULL || 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");
}
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] = (char *)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 *name, 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 = (cmd_ln_val_t *)ckd_calloc(1, sizeof(*v));
memcpy(v, &val, sizeof(val));
v->type = t;
v->name = ckd_salloc(name);
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 = (char **)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->name);
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 = (cmd_ln_t*)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 = (arg_t *)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], argv[j + 1]);
else {
if ((val = cmd_ln_val_init(argdef->type, argv[j], 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, val->name, (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, val->name, (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].name, 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, val->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;
}
/* If we use it from something except pocketsphinx, print current values */
if (!cmd_ln_exists_r(cmdln, "-logfn") && err_get_logfp()) {
cmd_ln_print_values_r(cmdln, err_get_logfp(), defn);
}
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 = (char**)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 = 30;
argc = 0;
f_argv = (char **)ckd_calloc(argv_size, sizeof(char *));
/* Silently make room for \0 */
str = (char* )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 =
(char **)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 = (char *)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, TRUE);
}
void
cmd_ln_print_values_r(cmd_ln_t *cmdln, FILE *fp, arg_t const* defn)
{
if (defn == NULL)
return;
fprintf(fp, "Current configuration:\n");
arg_dump_r(cmdln, fp, defn, FALSE);
}
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);
val->ptr = ckd_salloc(str);
}
void
cmd_ln_set_str_extra_r(cmd_ln_t *cmdln, char const *name, char const *str)
{
cmd_ln_val_t *val;
if (hash_table_lookup(cmdln->ht, name, (void **)&val) < 0) {
val = cmd_ln_val_init(ARG_STRING, name, str);
hash_table_enter(cmdln->ht, val->name, (void *)val);
} else {
ckd_free(val->val.ptr);
val->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 = (hash_entry_t *)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;
}
/* vim: set ts=4 sw=4: */
case.h
Locale-independent implementation of case swapping operation.
strcmp_nocase
SPHINXBASE_EXPORT int32 strcmp_nocase(const char *str1, const char *str2)
(FIXME!
Definition case.c:94
ckd_alloc.h
Sphinx's memory allocation/deallocation routines.
ckd_free
SPHINXBASE_EXPORT void ckd_free(void *ptr)
Test and free a 1-D array.
Definition ckd_alloc.c:244
ckd_calloc
#define ckd_calloc(n, sz)
Macros to simplify the use of above functions.
Definition ckd_alloc.h:248
ckd_salloc
#define ckd_salloc(ptr)
Macro for ckd_salloc.
Definition ckd_alloc.h:264
ckd_realloc
#define ckd_realloc(ptr, sz)
Macro for ckd_realloc.
Definition ckd_alloc.h:258
cmd_ln.h
Command-line and other configurationparsing and handling.
cmd_ln_print_values_r
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
ARG_STRING_LIST
#define ARG_STRING_LIST
Boolean (true/false) argument (optional).
Definition cmd_ln.h:122
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:911
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:1046
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_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
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
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:746
cmd_ln_free
SPHINXBASE_EXPORT void cmd_ln_free(void)
Free the global command line, if any exists.
Definition cmd_ln.c:1082
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:764
ARG_STRING
#define ARG_STRING
String argument (optional).
Definition cmd_ln.h:114
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
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:709
ARG_INTEGER
#define ARG_INTEGER
Integer argument (optional).
Definition cmd_ln.h:106
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:493
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:1027
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:499
REQARG_INTEGER
#define REQARG_INTEGER
Required integer argument.
Definition cmd_ln.h:127
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
REQARG_FLOATING
#define REQARG_FLOATING
Required floating point argument.
Definition cmd_ln.h:131
cmd_ln_appl_exit
SPHINXBASE_EXPORT void cmd_ln_appl_exit(void)
Finalization routine corresponding to cmd_ln_appl_enter().
Definition cmd_ln.c:549
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:1039
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:595
ARG_REQUIRED
#define ARG_REQUIRED
Bit indicating a required argument.
Definition cmd_ln.h:102
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_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:895
REQARG_STRING
#define REQARG_STRING
Required string argument.
Definition cmd_ln.h:135
cmd_ln_set_str_extra_r
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
ARG_BOOLEAN
#define ARG_BOOLEAN
Boolean (true/false) argument (optional).
Definition cmd_ln.h:118
ARG_FLOATING
#define ARG_FLOATING
Floating point argument (optional).
Definition cmd_ln.h:110
REQARG_BOOLEAN
#define REQARG_BOOLEAN
Required boolean argument.
Definition cmd_ln.h:139
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
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:556
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:1015
err.h
Implementation of logging routines.
E_ERROR
#define E_ERROR(...)
Print error message to error log.
Definition err.h:104
E_INFO
#define E_INFO(...)
Print logging information to standard error stream.
Definition err.h:114
E_INFOCONT
#define E_INFOCONT(...)
Continue printing the information to standard error stream.
Definition err.h:119
err_get_logfp
SPHINXBASE_EXPORT FILE * err_get_logfp(void)
Get the current logging filehandle.
Definition err.c:268
E_WARN
#define E_WARN(...)
Print warning message to error log.
Definition err.h:109
gnode_t
struct gnode_s gnode_t
A node in a generic list.
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
gnode_ptr
#define gnode_ptr(g)
Head of a list of gnodes.
Definition glist.h:109
hash_table.h
Hash table implementation.
hash_entry_t
struct hash_entry_s hash_entry_t
A note by ARCHAN at 20050510: Technically what we use is so-called "hash table with buckets" which is...
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:688
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:512
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:616
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:302
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:501
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
anytype_t
union anytype_s anytype_t
Union of basic types.
strfuncs.h
Miscellaneous useful string functions.
atof_c
SPHINXBASE_EXPORT double atof_c(char const *str)
Locale independent version of atof().
Definition strfuncs.c:55
arg_t
Argument definition structure.
cmd_ln_s
Definition cmd_ln.c:91
cmd_ln_t
Opaque structure used to hold the results of command-line parsing.
cmd_ln_val_s
Definition cmd_ln.c:85
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