| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| #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 "util/cmd_ln.h" |
| #include "util/ckd_alloc.h" |
| #include "util/hash_table.h" |
| #include "util/case.h" |
| #include "util/strfuncs.h" |
|
|
| #include "pocketsphinx_internal.h" |
|
|
| static void |
| arg_log_r(ps_config_t *, ps_arg_t const *, int32, int32); |
|
|
| static ps_config_t * |
| parse_options(ps_config_t *, const ps_arg_t *, int32, char* [], int32); |
|
|
| |
| |
| |
| |
| static int32 |
| arg_strlen(const ps_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) + 1; |
| if (*namelen < l) |
| *namelen = l; |
|
|
| if (defn[i].deflt) |
| l = strlen(defn[i].deflt); |
| else |
| l = strlen("(null)"); |
| |
| if (*deflen < l) |
| *deflen = l; |
| } |
|
|
| return i; |
| } |
|
|
| static int32 |
| cmp_name(const void *a, const void *b) |
| { |
| return (strcmp_nocase |
| ((* (ps_arg_t**) a)->name, |
| (* (ps_arg_t**) b)->name)); |
| } |
|
|
| static ps_arg_t const ** |
| arg_sort(const ps_arg_t * defn, int32 n) |
| { |
| const ps_arg_t ** pos; |
| int32 i; |
|
|
| pos = (ps_arg_t const **) ckd_calloc(n, sizeof(ps_arg_t *)); |
| for (i = 0; i < n; ++i) |
| pos[i] = &defn[i]; |
| qsort(pos, n, sizeof(ps_arg_t *), cmp_name); |
|
|
| return pos; |
| } |
|
|
| cmd_ln_val_t * |
| cmd_ln_access_r(ps_config_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 (cmd_ln_val_t *)val; |
| } |
|
|
| cmd_ln_val_t * |
| cmd_ln_val_init(int t, const char *name, const char *str) |
| { |
| cmd_ln_val_t *v; |
|
|
| v = ckd_calloc(1, sizeof(*v)); |
| if (anytype_from_str(&v->val, t, str) == NULL) { |
| ckd_free(v); |
| return NULL; |
| } |
| v->type = t; |
| v->name = ckd_salloc(name); |
|
|
| return v; |
| } |
|
|
| void |
| cmd_ln_val_free(cmd_ln_val_t *val) |
| { |
| if (val->type & ARG_STRING) |
| ckd_free(val->val.ptr); |
| ckd_free(val->name); |
| ckd_free(val); |
| } |
|
|
|
|
| static void |
| arg_log_r(ps_config_t *cmdln, const ps_arg_t * defn, int32 doc, int32 lineno) |
| { |
| ps_arg_t const **pos; |
| int32 i, n; |
| int32 namelen, deflen; |
| cmd_ln_val_t const *vp; |
|
|
| |
| if (defn == NULL) |
| return; |
|
|
| |
| n = arg_strlen(defn, &namelen, &deflen); |
| namelen += 4; |
| deflen += 4; |
| if (lineno) |
| E_INFO("%-*s", namelen, "[NAME]"); |
| else |
| E_INFOCONT("%-*s", namelen, "[NAME]"); |
| E_INFOCONT("%-*s", deflen, "[DEFLT]"); |
| if (doc) { |
| E_INFOCONT(" [DESCR]\n"); |
| } |
| else { |
| E_INFOCONT(" [VALUE]\n"); |
| } |
|
|
| |
| pos = arg_sort(defn, n); |
| for (i = 0; i < n; i++) { |
| if (lineno) |
| E_INFO("-%-*s", namelen, pos[i]->name); |
| else |
| E_INFOCONT("-%-*s", namelen, pos[i]->name); |
| if (pos[i]->deflt) |
| E_INFOCONT("%-*s", deflen, pos[i]->deflt); |
| else |
| E_INFOCONT("%-*s", deflen, ""); |
| if (doc) { |
| if (pos[i]->doc) |
| E_INFOCONT(" %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: |
| E_INFOCONT(" %ld", vp->val.i); |
| break; |
| case ARG_FLOATING: |
| case REQARG_FLOATING: |
| E_INFOCONT(" %e", vp->val.fl); |
| break; |
| case ARG_STRING: |
| case REQARG_STRING: |
| if (vp->val.ptr) |
| E_INFOCONT(" %s", (char *)vp->val.ptr); |
| break; |
| case ARG_BOOLEAN: |
| case REQARG_BOOLEAN: |
| E_INFOCONT(" %s", vp->val.i ? "yes" : "no"); |
| break; |
| default: |
| E_ERROR("Unknown argument type: %d\n", pos[i]->type); |
| } |
| } |
| } |
|
|
| E_INFOCONT("\n"); |
| } |
| ckd_free(pos); |
| E_INFOCONT("\n"); |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| static ps_config_t * |
| parse_options(ps_config_t *cmdln, const ps_arg_t *defn, int32 argc, char* argv[], int32 strict) |
| { |
| ps_config_t *new_cmdln; |
|
|
| new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict); |
| |
| if (new_cmdln == NULL) { |
| int32 i; |
| for (i = 0; i < argc; ++i) |
| ckd_free(argv[i]); |
| ckd_free(argv); |
| return NULL; |
| } |
|
|
| |
| if (new_cmdln == cmdln) { |
| |
| |
| 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 { |
| |
| new_cmdln->f_argc = argc; |
| new_cmdln->f_argv = argv; |
| } |
|
|
| return new_cmdln; |
| } |
|
|
| ps_config_t * |
| cmd_ln_parse_r(ps_config_t *inout_cmdln, const ps_arg_t * defn, |
| int32 argc, char *argv[], int strict) |
| { |
| int32 i, j, n, argstart; |
| hash_table_t *defidx = NULL; |
| ps_config_t *cmdln; |
|
|
| |
| if (inout_cmdln == NULL) { |
| cmdln = ps_config_init(defn); |
| cmdln->defn = defn; |
| } |
| else |
| cmdln = inout_cmdln; |
|
|
| |
| 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 { |
| |
| n = 0; |
| } |
|
|
| |
| |
| argstart = 0; |
| if (argc > 0 && argv[0][0] != '-') { |
| argstart = 1; |
| } |
|
|
| |
| for (j = argstart; j < argc; j += 2) { |
| ps_arg_t *argdef; |
| cmd_ln_val_t *val; |
| char *name; |
| void *v; |
|
|
| name = argv[j]; |
| if (*name && *name == '-') |
| ++name; |
| if (*name && *name == '-') |
| ++name; |
| if (hash_table_lookup(defidx, name, &v) < 0) { |
| if (strict) { |
| E_ERROR("Unknown argument name '%s'\n", name); |
| goto error; |
| } |
| else if (defn == NULL) |
| v = NULL; |
| else |
| continue; |
| } |
| argdef = (ps_arg_t *)v; |
|
|
| |
| if (j + 1 >= argc) { |
| E_ERROR("Argument value for '%s' missing\n", name); |
| goto error; |
| } |
|
|
| if (argdef == NULL) |
| val = cmd_ln_val_init(ARG_STRING, name, argv[j + 1]); |
| else { |
| if ((val = cmd_ln_val_init(argdef->type, name, argv[j + 1])) == NULL) { |
| E_ERROR("Bad argument value for %s: %s\n", name, argv[j + 1]); |
| goto error; |
| } |
| } |
|
|
| if ((v = hash_table_enter(cmdln->ht, val->name, (void *)val)) != |
| (void *)val) |
| { |
| v = hash_table_replace(cmdln->ht, val->name, (void *)val); |
| cmd_ln_val_free((cmd_ln_val_t *)v); |
| } |
| } |
|
|
| |
| 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) { |
| goto error; |
| } |
|
|
| if (strict && argc == 1) { |
| E_ERROR("No arguments given\n"); |
| if (defidx) |
| hash_table_free(defidx); |
| if (inout_cmdln == NULL) |
| ps_config_free(cmdln); |
| return NULL; |
| } |
|
|
| hash_table_free(defidx); |
| return cmdln; |
|
|
| error: |
| if (defidx) |
| hash_table_free(defidx); |
| if (inout_cmdln == NULL) |
| ps_config_free(cmdln); |
| E_ERROR("Failed to parse arguments list\n"); |
| return NULL; |
| } |
|
|
| ps_config_t * |
| cmd_ln_parse_file_r(ps_config_t *inout_cmdln, const ps_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); |
| |
| for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; |
|
|
| if (ch == EOF) { |
| fclose(file); |
| return NULL; |
| } |
|
|
| |
| |
| |
| argv_size = 30; |
| argc = 0; |
| f_argv = (char **)ckd_calloc(argv_size, sizeof(char *)); |
| |
| str = (char* )ckd_calloc(arg_max_length + 1, sizeof(char)); |
| quoting = 0; |
|
|
| do { |
| |
| if (len == 0 && argc % 2 == 0) { |
| while (ch == '#') { |
| |
| for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ; |
| |
| for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; |
| } |
|
|
| |
| if (ch == EOF) |
| break; |
| } |
|
|
| |
| if (ch == '"' || ch == '\'') { |
| if (quoting == ch) |
| quoting = 0; |
| else if (quoting) { |
| E_ERROR("Nesting quotations is not supported!\n"); |
| rv = 1; |
| break; |
| } |
| else |
| quoting = ch; |
| } |
| else if (ch == EOF || (!quoting && strchr(separator, ch))) { |
| |
| 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; |
| } |
|
|
| |
| f_argv[argc] = ckd_salloc(str); |
| len = 0; |
| str[0] = '\0'; |
| argc++; |
|
|
| if (quoting) |
| E_WARN("Unclosed quotation, having EOF close it...\n"); |
|
|
| |
| for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ; |
|
|
| if (ch == EOF) |
| break; |
|
|
| |
| continue; |
| } |
| else { |
| if (len >= arg_max_length) { |
| |
| 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; |
| } |
| |
| str[len++] = ch; |
| |
| 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); |
| } |
|
|
| void |
| cmd_ln_log_help_r(ps_config_t *cmdln, ps_arg_t const* defn) |
| { |
| if (defn == NULL) |
| return; |
| E_INFO("Arguments list definition:\n"); |
| if (cmdln == NULL) { |
| cmdln = cmd_ln_parse_r(NULL, defn, 0, NULL, FALSE); |
| arg_log_r(cmdln, defn, TRUE, FALSE); |
| ps_config_free(cmdln); |
| } |
| else |
| arg_log_r(cmdln, defn, TRUE, FALSE); |
| } |
|
|
| void |
| cmd_ln_log_values_r(ps_config_t *cmdln, ps_arg_t const* defn) |
| { |
| if (defn == NULL) |
| return; |
| E_INFO("Current configuration:\n"); |
| arg_log_r(cmdln, defn, FALSE, FALSE); |
| } |
|
|
| void |
| cmd_ln_set_str_extra_r(ps_config_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 { |
| if (!(val->type & ARG_STRING)) { |
| E_ERROR("Argument %s does not have string type\n", name); |
| return; |
| } |
| ckd_free(val->val.ptr); |
| val->val.ptr = ckd_salloc(str); |
| } |
| } |
|
|
| |
|
|