home *** CD-ROM | disk | FTP | other *** search
-
- /* This module handles dynamic changes to V9t9's state through the use
- of a generalized text parser. The configuration file is the most
- obvious use of this parser. */
-
- #include <stdarg.h>
- #include <stdlib.h>
- #include "v9t9_common.h"
- #include "log.h"
- #define _L LOG_COMMANDS | LOG_INFO
- #include "command.h"
- #include "command_lexer.h"
- #include "command_parser.h"
-
- char *ca_types[] = {
- "void", "symbol", "number", "string",
- "filepath", "directory", "filename",
- "boolean"
- };
-
- command_symbol_table *universe;
-
- static bool session_only;
-
- /***********************************/
-
- /* We consider a symbol to match if 'name' is a prefix
- of an item in 'list'. 'list' can use '|' to separate
- distinct spellings. We are only allowed to use a prefix
- if it is at least five characters.
-
- Returns 0 if no match, 1 if a definite match, and
- -1 if a prefix match. */
- static int
- symbol_match(const char *list, const char *name, int need_prefix)
- {
- const char *nptr = name;
- int match = 0;
-
- while (*list) {
- if (*list == '|') { /* aaa|bbb , aaabadab */
- if (!*nptr)
- match = 1;
- nptr = name;
- list++;
- if (*list == '|')
- list++;
- } else if (!*nptr) { /* aaa|bbb , a */
- if (!match && (!need_prefix || (nptr - name >= 5)))
- match = -1;
- nptr = name;
- } else if (tolower(*list) == tolower(*nptr)) {
- *list++;
- *nptr++;
- } else {
- while (*list && *list != '|')
- list++;
- if (*list)
- list++;
- nptr = name;
- }
- }
- if (!*nptr)
- match = 1;
- return match;
- }
-
- /* Returns 0 for no match, 1 for a definite match, and -1 for a prefix match */
- int
- command_match_symbol(const command_symbol_table * table,
- const char *name, command_symbol ** sym)
- {
- command_symbol *match = NULL;
- int ret = 0;
-
- while (table != NULL) {
- command_symbol *lst = table->list;
- int subret;
-
- // note: comment out "ret != 1" to debug options
- while (lst != NULL && ret != 1) {
- subret = symbol_match(lst->name, name, 1);
- if (subret) {
- if (match) {
- // only report this if we don't already have a good idea
- if (subret < 0 && ret <= 0)
- parse_error
- ("%s: ambiguous identifier (collides with '%s')",
- name, lst->name);
- } else {
- match = lst;
- ret = subret;
- }
- }
- lst = lst->next;
- }
-
- // note: comment out "ret != 1" to debug options
- if (table->sub && ret != 1) {
- subret = command_match_symbol(table->sub, name, &lst);
- if (subret) {
- if (!match) {
- match = lst;
- ret = subret;
- }
- }
- }
-
- table = table->next;
- }
-
- if (match)
- logger(LOG_COMMANDS | L_1, "for '%s', matched '%s' (%d)\n", name,
- match->name, ret);
-
- *sym = match;
-
- return ret;
- }
-
- /* Return list of matching symbols. */
-
- #define ADD_DELTA 16
- static void
- add_match(command_symbol *** matches, int *nmatches, command_symbol * match)
- {
- if (*nmatches % ADD_DELTA == 0) {
- *matches = (command_symbol **) xrealloc(*matches,
- sizeof(command_symbol *) *
- (*nmatches + ADD_DELTA));
- }
- (*matches)[(*nmatches)++] = match;
- }
-
- void
- command_match_symbols(const command_symbol_table * table,
- const char *name,
- command_symbol *** matches, int *nmatches)
- {
- while (table != NULL) {
- command_symbol *lst = table->list;
- int subret;
-
- while (lst != NULL) {
- subret = symbol_match(lst->name, name, 0);
- if (subret)
- add_match(matches, nmatches, lst);
- lst = lst->next;
- }
-
- if (table->sub)
- command_match_symbols(table->sub, name, matches, nmatches);
-
- table = table->next;
- }
- }
-
- command_symbol_table *
- command_symbol_table_new(char *name, char *help,
- command_symbol * list, command_symbol_table * sub,
- command_symbol_table * next)
- {
- command_symbol_table *tbl =
- (command_symbol_table *) xmalloc(sizeof(command_symbol_table));
- tbl->name = name;
- tbl->help = help;
- tbl->list = list;
- tbl->sub = sub;
- tbl->next = next;
- return tbl;
- }
-
- command_symbol_table *
- command_symbol_table_add_subtable(command_symbol_table * parent,
- command_symbol_table * table)
- {
- command_symbol_table **ptr = &parent->sub;
-
- while (*ptr)
- ptr = &(*ptr)->next;
- *ptr = table;
- return parent;
- }
-
- command_symbol_table *
- command_symbol_table_add(command_symbol_table * parent, command_symbol * list)
- {
- command_symbol **ptr = &parent->list;
-
- while (*ptr)
- ptr = &(*ptr)->next;
- *ptr = list;
- return parent;
- }
-
- command_symbol *
- command_symbol_new(char *name, char *help, command_symbol_flags flags,
- command_symbol_action action, command_arg * ret,
- command_arg * args, command_symbol * next)
- {
- command_symbol *sym = (command_symbol *) xmalloc(sizeof(command_symbol));
-
- sym->name = name ? name : "<unnamed>";
- sym->help = help; // ? help : "<no help>";
- sym->flags = flags;
- sym->action = action;
- sym->ret = ret == RET_FIRST_ARG ? args : ret;
- sym->args = args;
- sym->next = next;
- return sym;
- }
-
- command_arg *
- command_arg_new_num(char *name, char *help, command_arg_action action,
- int sz, void *mem, command_arg * next)
- {
- command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
-
- sym->name = name ? name : "<unnamed>";
- sym->help = help ? help : "a number";
- sym->action = action;
- sym->type = ca_NUM;
- sym->u.num.sz = sz;
- sym->u.num.mem = mem;
- sym->next = next;
- return sym;
- }
-
- command_arg *
- command_arg_new_string(char *name, char *help, command_arg_action action,
- int maxlen, void *mem, command_arg * next)
- {
- command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
-
- sym->name = name ? name : "<unnamed>";
- sym->help = help ? help : "a string";
- sym->action = action;
- sym->type = ca_STRING;
- sym->u.string.maxlen = maxlen;
- if (maxlen >= 0)
- sym->u.string.m.mem = (char *) mem;
- else
- sym->u.string.m.ptr = (char **) mem;
-
- sym->next = next;
- return sym;
- }
-
- command_arg *
- command_arg_new_spec(char *name, char *help, command_arg_action action,
- OSSpec * spec, command_arg * next)
- {
- command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
-
- sym->name = name ? name : "<unnamed>";
- sym->help = help ? help : "a filespec";
- sym->action = action;
- sym->type = ca_SPEC;
- sym->u.spec.mem = spec;
- sym->next = next;
- return sym;
- }
-
- command_arg *
- command_arg_new_pathspec(char *name, char *help, command_arg_action action,
- OSPathSpec * pathspec, command_arg * next)
- {
- command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
-
- sym->name = name ? name : "<unnamed>";
- sym->help = help ? help : "a pathspec";
- sym->action = action;
- sym->type = ca_PATHSPEC;
- sym->u.pathspec.mem = pathspec;
- sym->next = next;
- return sym;
- }
-
- command_arg *
- command_arg_new_namespec(char *name, char *help, command_arg_action action,
- OSNameSpec * namespec, command_arg * next)
- {
- command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
-
- sym->name = name ? name : "<unnamed>";
- sym->help = help ? help : "a filename";
- sym->action = action;
- sym->type = ca_NAMESPEC;
- sym->u.namespec.mem = namespec;
- sym->next = next;
- return sym;
- }
-
- command_arg *
- command_arg_new_toggle(char *name, char *help, command_arg_action action,
- int sz, void *mem, int val, command_arg * next)
- {
- command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
-
- sym->name = name ? name : "<unnamed>";
- sym->help = help ? help : "a number";
- sym->action = action;
- sym->type = ca_TOGGLE;
- sym->u.toggle.sz = sz;
- sym->u.toggle.mem = mem;
- sym->u.toggle.flag = val;
- sym->next = next;
- return sym;
- }
-
- /*************************************************/
-
- void
- command_arg_read_num(command_arg *arg, int *val)
- {
- switch (arg->u.num.sz) {
- case 1:
- {
- u8 u8val;
-
- u8val = *(u8 *) arg->u.num.mem;
- *val = u8val;
- break;
- }
- case 2:
- {
- u16 u16val;
-
- u16val = *(u16 *) arg->u.num.mem;
- *val = u16val;
- break;
- }
- case 4:
- {
- u32 u32val;
-
- u32val = *(u32 *) arg->u.num.mem;
- *val = u32val;
- break;
- }
- default:
- logger(_L | LOG_FATAL, "Unhandled size in command_arg_read_num (%d)\n",
- arg->u.num.sz);
- break;
- }
- }
-
- int
- command_arg_get_num(command_arg * arg, int *val)
- {
- if (!arg) {
- *val = 0;
- return 0;
- }
- my_assert(arg->type == ca_NUM || arg->type == ca_TOGGLE);
-
- if (arg->action)
- if (!arg->action(arg, caa_READ))
- return 0;
-
- command_arg_read_num(arg, val);
- return 1;
- }
-
- int
- command_arg_set_num(command_arg * arg, int val)
- {
- if (!arg) {
- return 0;
- }
- my_assert(arg->type == ca_NUM || arg->type == ca_TOGGLE);
- switch (arg->u.num.sz) {
- case 1:
- {
- u8 u8val = val;
-
- *(u8 *) arg->u.num.mem = u8val;
- break;
- }
- case 2:
- {
- u16 u16val = val;
-
- *(u16 *) arg->u.num.mem = u16val;
- break;
- }
- case 4:
- {
- u32 u32val = val;
-
- *(u32 *) arg->u.num.mem = u32val;
- break;
- }
- default:
- logger(_L | LOG_FATAL, "Unhandled size in command_arg_set_num (%d)\n",
- arg->u.num.sz);
- break;
- }
-
- if (arg->action)
- if (!arg->action(arg, caa_WRITE))
- return 0;
-
- return 1;
- }
-
- void
- command_arg_read_string(command_arg * arg, char **str)
- {
- if (arg->u.string.maxlen >= 0)
- *str = arg->u.string.m.mem;
- else
- *str = *arg->u.string.m.ptr;
- }
-
- int
- command_arg_get_string(command_arg * arg, char **str)
- {
- if (!arg) {
- *str = 0L;
- return 0;
- }
- my_assert(arg->type == ca_STRING);
- if (arg->action)
- if (!arg->action(arg, caa_READ))
- return 0;
- command_arg_read_string(arg, str);
- return 1;
- }
-
- int
- command_arg_set_string(command_arg * arg, const char *str)
- {
- if (!arg) {
- return 0;
- }
- my_assert(arg->type == ca_STRING);
-
- if (arg->u.string.maxlen >= 0) {
- if (str) {
- strncpy(arg->u.string.m.mem, str, arg->u.string.maxlen);
- arg->u.string.m.mem[arg->u.string.maxlen - 1] = 0;
- } else {
- *arg->u.string.m.mem = 0;
- }
- } else {
- if (str) {
- *arg->u.string.m.ptr = (char *) xrealloc(*arg->u.string.m.ptr,
- strlen(str) + 1);
- strcpy(*arg->u.string.m.ptr, str);
- } else {
- if (*arg->u.string.m.ptr) {
- xfree(arg->u.string.m.ptr);
- }
- *arg->u.string.m.ptr = 0L;
- }
- }
-
- if (arg->action)
- if (!arg->action(arg, caa_WRITE))
- return 0;
-
- return 1;
- }
-
- void
- command_arg_read_spec(command_arg * arg, char **str)
- {
- if (arg->type == ca_SPEC)
- *str = OS_SpecToString1(arg->u.spec.mem);
- else if (arg->type == ca_PATHSPEC)
- *str = OS_PathSpecToString1(arg->u.pathspec.mem);
- else /* if (arg->type == ca_NAMESPEC) */
- *str = OS_NameSpecToString1(arg->u.namespec.mem);
- }
-
- int
- command_arg_get_spec(command_arg * arg, char **str)
- {
- if (!arg) {
- *str = 0L;
- return 0;
- }
- my_assert(ca_ISSPEC(arg->type));
- if (arg->action)
- if (!arg->action(arg, caa_READ))
- return 0;
- command_arg_read_spec(arg, str);
- return 1;
- }
-
- int
- command_arg_set_spec(command_arg * arg, const char *str)
- {
- OSError err = OS_FNFERR;
-
- if (!arg) {
- return 0;
- }
-
- my_assert(ca_ISSPEC(arg->type));
-
- if (str) {
- if (arg->type == ca_SPEC)
- err = OS_MakeSpec(str, arg->u.spec.mem, NULL);
- else if (arg->type == ca_PATHSPEC)
- err = OS_MakePathSpec(NULL, str, arg->u.pathspec.mem);
- else /* if (arg->type == ca_NAMESPEC) */
- err = OS_MakeNameSpec(str, arg->u.namespec.mem);
- }
-
- if (err != OS_NOERR) {
- parse_error("argument '%s': cannot set to '%s' (%s)", arg->name,
- str, OS_GetErrText(err));
- return 0;
- }
-
- if (arg->action)
- if (!arg->action(arg, caa_WRITE))
- return 0;
-
- return 1;
- }
-
- void
- command_arg_read_toggle(command_arg * arg, int *val)
- {
- command_arg_read_num(arg, val);
- *val = (arg->u.toggle.flag & *val) != 0;
- }
-
- int
- command_arg_get_toggle(command_arg * arg, int *val)
- {
- if (!arg) {
- *val = 0L;
- return 0;
- }
- if (!command_arg_get_num(arg, val))
- return 0;
-
- *val = (arg->u.toggle.flag & *val) != 0;
- return 1;
- }
-
- int
- command_arg_set_toggle(command_arg * arg, int val)
- {
- int curval;
-
- if (!arg) {
- return 0;
- }
-
- if (!command_arg_get_num(arg, &curval))
- return 0;
-
- val = val ? (curval | arg->u.toggle.flag) :
- (curval & ~arg->u.toggle.flag);
-
- if (!command_arg_set_num(arg, val))
- return 0;
-
- return 1;
- }
-
- /***************************************/
-
- int
- command_get_val(command_symbol * sym, command_exprval * val)
- {
- command_arg *ret;
-
- if (sym->action)
- if (!sym->action(sym, csa_READ, 0))
- return 0;
-
- ret = sym->ret;
- if (!ret) {
- val->type = ca_VOID;
- return 1;
- } else if (ret->type == ca_NUM) {
- val->type = ca_NUM;
- if (!command_arg_get_num(ret, &val->u.num))
- return 0;
- } else if (ret->type == ca_STRING) {
- char *str;
-
- val->type = ca_STRING;
- if (!command_arg_get_string(ret, &str))
- return 0;
- val->u.str = xstrdup(str);
- } else if (ca_ISSPEC(ret->type)) {
- char *str;
-
- val->type = ca_STRING;
- if (!command_arg_get_spec(ret, &str))
- return 0;
- val->u.str = xstrdup(str);
- } else if (ret->type == ca_TOGGLE) {
- val->type = ca_NUM;
- if (!command_arg_get_toggle(ret, &val->u.num))
- return 0;
- } else {
- logger(_L | LOG_FATAL, "Unhandled ca_XXXX (%s)\n", ca_types[ret->type]);
- }
-
-
- return 1;
- }
-
-
- int
- command_set_args(command_exprval * ret, command_symbol * sym, ...)
- {
- va_list ap;
- command_exprval *val;
- command_arg *arg;
- int argnum = 0;
-
- logger(_L | L_2, "sym->name='%s'\n", sym->name);
-
- // if (!(!(sym->flags & c_SESSION_ONLY) && session_only))
- {
-
- arg = sym->args;
- va_start(ap, sym);
- while ((val = va_arg(ap, command_exprval *)) != NULL) {
- argnum++;
-
- if (arg == NULL) {
- parse_error("%s: unexpected additional %s argument #%d",
- sym->name, ca_types[val->type], argnum);
- return 0;
- }
-
- /* Look for implicit conversions */
- if (val->type == ca_STRING && ca_ISSPEC(arg->type)) {
- if (!command_arg_set_spec(arg, val->u.str))
- return 0;
- xfree(val->u.str);
-
- } else if (val->type == ca_NUM && arg->type == ca_TOGGLE) {
- if (!command_arg_set_toggle(arg, val->u.num))
- return 0;
-
- } else if (val->type == ca_NUM && arg->type == ca_NUM) {
- if (!command_arg_set_num(arg, val->u.num))
- return 0;
- } else if (val->type == ca_STRING && arg->type == ca_STRING) {
- if (!command_arg_set_string(arg, val->u.str))
- return 0;
- xfree(val->u.str);
- } else if (val->type != arg->type) {
- parse_error("%s: type mismatch in argument '%s' (expected %s)",
- sym->name, arg->name, ca_types[arg->type]);
- return 0;
- } else
- logger(_L | LOG_FATAL, "command_set_args: cannot handle %s\n",
- ca_types[val->type]);
-
- arg = arg->next;
- }
-
- if (arg != NULL) {
- parse_error("%s: expected additional parameters", sym->name);
- return 0;
- }
-
- if (sym->action)
- if (!sym->action(sym, csa_WRITE, 0))
- return 0;
-
- }
-
- if (ret) {
- ret->type = ca_VOID;
- if (sym->ret && !command_get_val(sym, ret))
- return 0;
- }
-
- return 1;
- }
-
- /************************/
-
- int
- command_lexer_setup_text(char *name, char *text, int len)
- {
- return lexer_push_text(name, text, len) != NULL;
- }
-
- int
- command_lexer_setup_file(char *filename)
- {
- return lexer_push_file(filename) != NULL;
- }
-
-
- /**********************/
-
- void
- command_init(void)
- {
- universe = command_symbol_table_new("V9t9 Options",
- "This is the complete list of options and commands "
- "you may specify in a configuration file or command prompt.",
- NULL, NULL, NULL);
- session_only = false;
- }
-
-
- int
- command_parse_file(char *name)
- {
- if (!command_lexer_setup_file(name))
- return 0;
- command_parse(universe);
- return 1;
- }
-
- int
- command_parse_text(char *str)
- {
- if (!command_lexer_setup_text("<command_parse_text>", str, strlen(str)))
- return 0;
- command_parse(universe);
- return 1;
- }
-
- bool command_get_session_filter(void)
- {
- return session_only;
- }
-
- void command_set_session_filter(bool allow_session_only)
- {
- session_only = allow_session_only;
- }
-
- /**********************/
-
- #ifdef STANDALONE
-
- int a, b;
- OSPathSpec dir;
- char buf[4], buf2[16];
- int c;
-
- int
- main(int argc, char **argv)
- {
-
- /*
- command_symbol_table *table =
- command_symbol_table_new(NULL,
- command_symbol_new("a", NULL,
- command_arg_new_num(sizeof(a), &a, NULL
- ),
- command_arg_new_num(sizeof(a), &a, NULL
- ),
- command_symbol_new("b", NULL,
- command_arg_new_num(sizeof(b), &b, NULL
- ),
- command_arg_new_num(sizeof(b), &b, NULL
- ),
- command_symbol_new("ni", NULL,
- command_arg_new_num(sizeof(c), &c, NULL
- ),
- command_arg_new_string(sizeof(buf), buf,
- command_arg_new_num(sizeof(c), &c, NULL
- )),
- command_symbol_new("c", NULL,
- command_arg_new_string(sizeof(buf), buf, NULL
- ),
- command_arg_new_string(sizeof(buf), buf, NULL
- ),
- command_symbol_new("d", NULL,
- command_arg_new_string(sizeof(buf2), buf2, NULL
- ),
- command_arg_new_string(sizeof(buf2), buf2, NULL
- ),
- NULL
- )))))
- );
- */
- char *text = "#include \"test.cnf\"";
-
- // xminfo();
-
- command_symbol_table_add(universe,
- command_symbol_new("DelayBetweenInstructions",
- "Sets a constant delay between instructions",
- NULL,
- NULL,
- command_arg_new_num("cycles",
- "number of cycles to count",
- NULL,
- ARG_NUM
- (a),
- NULL),
- command_symbol_new
- ("ModulesPath",
- "Set directory to search for module ROMs",
- NULL, NULL,
- command_arg_new_pathspec
- ("dir", "path to directory",
- NULL, &dir, NULL),
-
- NULL)));
-
- command_help();
-
- if (!command_lexer_setup_text("test", text, strlen(text)))
- return -1;
- command_parse(universe);
-
- printf("a=%d, b=%d, buf=%s, buf2=%s, c=%d\n", a, b, buf, buf2, c);
-
- // xminfo();
- }
- #endif
-