home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / command.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  17.0 KB  |  823 lines

  1.  
  2. /*    This module handles dynamic changes to V9t9's state through the use
  3.     of a generalized text parser.  The configuration file is the most
  4.     obvious use of this parser.  */
  5.  
  6. #include <stdarg.h>
  7. #include <stdlib.h>
  8. #include "v9t9_common.h"
  9. #include "log.h"
  10. #define _L     LOG_COMMANDS | LOG_INFO
  11. #include "command.h"
  12. #include "command_lexer.h"
  13. #include "command_parser.h"
  14.  
  15. char       *ca_types[] = { 
  16.     "void", "symbol", "number", "string",
  17.     "filepath", "directory", "filename",
  18.     "boolean"
  19. };
  20.  
  21. command_symbol_table *universe;
  22.  
  23. static bool session_only;
  24.  
  25. /***********************************/
  26.  
  27. /*    We consider a symbol to match if 'name' is a prefix
  28.     of an item in 'list'.  'list' can use '|' to separate
  29.     distinct spellings.  We are only allowed to use a prefix
  30.     if it is at least five characters.
  31.     
  32.     Returns 0 if no match, 1 if a definite match, and
  33.     -1 if a prefix match. */
  34. static int  
  35. symbol_match(const char *list, const char *name, int need_prefix)
  36. {
  37.     const char    *nptr = name;
  38.     int         match = 0;
  39.  
  40.     while (*list) {
  41.         if (*list == '|') {        /* aaa|bbb , aaabadab */
  42.             if (!*nptr)
  43.                 match = 1;
  44.             nptr = name;
  45.             list++;
  46.             if (*list == '|')
  47.                 list++;
  48.         } else if (!*nptr) {    /* aaa|bbb , a */
  49.             if (!match && (!need_prefix || (nptr - name >= 5)))
  50.                 match = -1;
  51.             nptr = name;
  52.         } else if (tolower(*list) == tolower(*nptr)) {
  53.             *list++;
  54.             *nptr++;
  55.         } else {
  56.             while (*list && *list != '|')
  57.                 list++;
  58.             if (*list)
  59.                 list++;
  60.             nptr = name;
  61.         }
  62.     }
  63.     if (!*nptr)
  64.         match = 1;
  65.     return match;
  66. }
  67.  
  68. /*    Returns 0 for no match, 1 for a definite match, and -1 for a prefix match */
  69. int
  70. command_match_symbol(const command_symbol_table * table,
  71.                      const char *name, command_symbol ** sym)
  72. {
  73.     command_symbol *match = NULL;
  74.     int         ret = 0;
  75.  
  76.     while (table != NULL) {
  77.         command_symbol *lst = table->list;
  78.         int         subret;
  79.  
  80.         // note:  comment out "ret != 1" to debug options
  81.         while (lst != NULL && ret != 1) {
  82.             subret = symbol_match(lst->name, name, 1);
  83.             if (subret) {
  84.                 if (match) {
  85.                     // only report this if we don't already have a good idea
  86.                     if (subret < 0 && ret <= 0)
  87.                         parse_error
  88.                             ("%s:  ambiguous identifier (collides with '%s')",
  89.                              name, lst->name);
  90.                 } else {
  91.                     match = lst;
  92.                     ret = subret;
  93.                 }
  94.             }
  95.             lst = lst->next;
  96.         }
  97.  
  98.         // note:  comment out "ret != 1" to debug options
  99.         if (table->sub && ret != 1) {
  100.             subret = command_match_symbol(table->sub, name, &lst);
  101.             if (subret) {
  102.                 if (!match) {
  103.                     match = lst;
  104.                     ret = subret;
  105.                 }
  106.             }
  107.         }
  108.  
  109.         table = table->next;
  110.     }
  111.  
  112.     if (match)
  113.         logger(LOG_COMMANDS | L_1, "for '%s', matched '%s' (%d)\n", name,
  114.                match->name, ret);
  115.  
  116.     *sym = match;
  117.  
  118.     return ret;
  119. }
  120.  
  121. /*    Return list of matching symbols. */
  122.  
  123. #define ADD_DELTA 16
  124. static void
  125. add_match(command_symbol *** matches, int *nmatches, command_symbol * match)
  126. {
  127.     if (*nmatches % ADD_DELTA == 0) {
  128.         *matches = (command_symbol **) xrealloc(*matches,
  129.                                                 sizeof(command_symbol *) *
  130.                                                 (*nmatches + ADD_DELTA));
  131.     }
  132.     (*matches)[(*nmatches)++] = match;
  133. }
  134.  
  135. void
  136. command_match_symbols(const command_symbol_table * table,
  137.                       const char *name,
  138.                       command_symbol *** matches, int *nmatches)
  139. {
  140.     while (table != NULL) {
  141.         command_symbol *lst = table->list;
  142.         int         subret;
  143.  
  144.         while (lst != NULL) {
  145.             subret = symbol_match(lst->name, name, 0);
  146.             if (subret)
  147.                 add_match(matches, nmatches, lst);
  148.             lst = lst->next;
  149.         }
  150.  
  151.         if (table->sub)
  152.             command_match_symbols(table->sub, name, matches, nmatches);
  153.  
  154.         table = table->next;
  155.     }
  156. }
  157.  
  158. command_symbol_table *
  159. command_symbol_table_new(char *name, char *help,
  160.                          command_symbol * list, command_symbol_table * sub,
  161.                          command_symbol_table * next)
  162. {
  163.     command_symbol_table *tbl =
  164.         (command_symbol_table *) xmalloc(sizeof(command_symbol_table));
  165.     tbl->name = name;
  166.     tbl->help = help;
  167.     tbl->list = list;
  168.     tbl->sub = sub;
  169.     tbl->next = next;
  170.     return tbl;
  171. }
  172.  
  173. command_symbol_table *
  174. command_symbol_table_add_subtable(command_symbol_table * parent,
  175.                                   command_symbol_table * table)
  176. {
  177.     command_symbol_table **ptr = &parent->sub;
  178.  
  179.     while (*ptr)
  180.         ptr = &(*ptr)->next;
  181.     *ptr = table;
  182.     return parent;
  183. }
  184.  
  185. command_symbol_table *
  186. command_symbol_table_add(command_symbol_table * parent, command_symbol * list)
  187. {
  188.     command_symbol **ptr = &parent->list;
  189.  
  190.     while (*ptr)
  191.         ptr = &(*ptr)->next;
  192.     *ptr = list;
  193.     return parent;
  194. }
  195.  
  196. command_symbol *
  197. command_symbol_new(char *name, char *help, command_symbol_flags flags,
  198.                    command_symbol_action action, command_arg * ret, 
  199.                    command_arg * args, command_symbol * next)
  200. {
  201.     command_symbol *sym = (command_symbol *) xmalloc(sizeof(command_symbol));
  202.  
  203.     sym->name = name ? name : "<unnamed>";
  204.     sym->help = help;            // ? help : "<no help>";
  205.     sym->flags = flags;
  206.     sym->action = action;
  207.     sym->ret = ret == RET_FIRST_ARG ? args : ret;
  208.     sym->args = args;
  209.     sym->next = next;
  210.     return sym;
  211. }
  212.  
  213. command_arg *
  214. command_arg_new_num(char *name, char *help, command_arg_action action,
  215.                     int sz, void *mem, command_arg * next)
  216. {
  217.     command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
  218.  
  219.     sym->name = name ? name : "<unnamed>";
  220.     sym->help = help ? help : "a number";
  221.     sym->action = action;
  222.     sym->type = ca_NUM;
  223.     sym->u.num.sz = sz;
  224.     sym->u.num.mem = mem;
  225.     sym->next = next;
  226.     return sym;
  227. }
  228.  
  229. command_arg *
  230. command_arg_new_string(char *name, char *help, command_arg_action action,
  231.                        int maxlen, void *mem, command_arg * next)
  232. {
  233.     command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
  234.  
  235.     sym->name = name ? name : "<unnamed>";
  236.     sym->help = help ? help : "a string";
  237.     sym->action = action;
  238.     sym->type = ca_STRING;
  239.     sym->u.string.maxlen = maxlen;
  240.     if (maxlen >= 0)
  241.         sym->u.string.m.mem = (char *) mem;
  242.     else
  243.         sym->u.string.m.ptr = (char **) mem;
  244.  
  245.     sym->next = next;
  246.     return sym;
  247. }
  248.  
  249. command_arg *
  250. command_arg_new_spec(char *name, char *help, command_arg_action action,
  251.                      OSSpec * spec, command_arg * next)
  252. {
  253.     command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
  254.  
  255.     sym->name = name ? name : "<unnamed>";
  256.     sym->help = help ? help : "a filespec";
  257.     sym->action = action;
  258.     sym->type = ca_SPEC;
  259.     sym->u.spec.mem = spec;
  260.     sym->next = next;
  261.     return sym;
  262. }
  263.  
  264. command_arg *
  265. command_arg_new_pathspec(char *name, char *help, command_arg_action action,
  266.                          OSPathSpec * pathspec, command_arg * next)
  267. {
  268.     command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
  269.  
  270.     sym->name = name ? name : "<unnamed>";
  271.     sym->help = help ? help : "a pathspec";
  272.     sym->action = action;
  273.     sym->type = ca_PATHSPEC;
  274.     sym->u.pathspec.mem = pathspec;
  275.     sym->next = next;
  276.     return sym;
  277. }
  278.  
  279. command_arg *
  280. command_arg_new_namespec(char *name, char *help, command_arg_action action,
  281.                          OSNameSpec * namespec, command_arg * next)
  282. {
  283.     command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
  284.  
  285.     sym->name = name ? name : "<unnamed>";
  286.     sym->help = help ? help : "a filename";
  287.     sym->action = action;
  288.     sym->type = ca_NAMESPEC;
  289.     sym->u.namespec.mem = namespec;
  290.     sym->next = next;
  291.     return sym;
  292. }
  293.  
  294. command_arg *
  295. command_arg_new_toggle(char *name, char *help, command_arg_action action,
  296.                        int sz, void *mem, int val, command_arg * next)
  297. {
  298.     command_arg *sym = (command_arg *) xmalloc(sizeof(command_arg));
  299.  
  300.     sym->name = name ? name : "<unnamed>";
  301.     sym->help = help ? help : "a number";
  302.     sym->action = action;
  303.     sym->type = ca_TOGGLE;
  304.     sym->u.toggle.sz = sz;
  305.     sym->u.toggle.mem = mem;
  306.     sym->u.toggle.flag = val;
  307.     sym->next = next;
  308.     return sym;
  309. }
  310.  
  311. /*************************************************/
  312.  
  313. void
  314. command_arg_read_num(command_arg *arg, int *val)
  315. {
  316.     switch (arg->u.num.sz) {
  317.     case 1:
  318.     {
  319.         u8          u8val;
  320.  
  321.         u8val = *(u8 *) arg->u.num.mem;
  322.         *val = u8val;
  323.         break;
  324.     }
  325.     case 2:
  326.     {
  327.         u16         u16val;
  328.  
  329.         u16val = *(u16 *) arg->u.num.mem;
  330.         *val = u16val;
  331.         break;
  332.     }
  333.     case 4:
  334.     {
  335.         u32         u32val;
  336.  
  337.         u32val = *(u32 *) arg->u.num.mem;
  338.         *val = u32val;
  339.         break;
  340.     }
  341.     default:
  342.         logger(_L | LOG_FATAL, "Unhandled size in command_arg_read_num (%d)\n",
  343.              arg->u.num.sz);
  344.         break;
  345.     }
  346. }
  347.  
  348. int
  349. command_arg_get_num(command_arg * arg, int *val)
  350. {
  351.     if (!arg) {
  352.         *val = 0;
  353.         return 0;
  354.     }
  355.     my_assert(arg->type == ca_NUM || arg->type == ca_TOGGLE);
  356.  
  357.     if (arg->action)
  358.         if (!arg->action(arg, caa_READ))
  359.             return 0;
  360.  
  361.     command_arg_read_num(arg, val);
  362.     return 1;
  363. }
  364.  
  365. int
  366. command_arg_set_num(command_arg * arg, int val)
  367. {
  368.     if (!arg) {
  369.         return 0;
  370.     }
  371.     my_assert(arg->type == ca_NUM || arg->type == ca_TOGGLE);
  372.     switch (arg->u.num.sz) {
  373.     case 1:
  374.     {
  375.         u8          u8val = val;
  376.  
  377.         *(u8 *) arg->u.num.mem = u8val;
  378.         break;
  379.     }
  380.     case 2:
  381.     {
  382.         u16         u16val = val;
  383.  
  384.         *(u16 *) arg->u.num.mem = u16val;
  385.         break;
  386.     }
  387.     case 4:
  388.     {
  389.         u32         u32val = val;
  390.  
  391.         *(u32 *) arg->u.num.mem = u32val;
  392.         break;
  393.     }
  394.     default:
  395.         logger(_L | LOG_FATAL, "Unhandled size in command_arg_set_num (%d)\n",
  396.              arg->u.num.sz);
  397.         break;
  398.     }
  399.  
  400.     if (arg->action)
  401.         if (!arg->action(arg, caa_WRITE))
  402.             return 0;
  403.  
  404.     return 1;
  405. }
  406.  
  407. void
  408. command_arg_read_string(command_arg * arg, char **str)
  409. {
  410.     if (arg->u.string.maxlen >= 0)
  411.         *str = arg->u.string.m.mem;
  412.     else
  413.         *str = *arg->u.string.m.ptr;
  414. }
  415.  
  416. int
  417. command_arg_get_string(command_arg * arg, char **str)
  418. {
  419.     if (!arg) {
  420.         *str = 0L;
  421.         return 0;
  422.     }
  423.     my_assert(arg->type == ca_STRING);
  424.     if (arg->action)
  425.         if (!arg->action(arg, caa_READ))
  426.             return 0;
  427.     command_arg_read_string(arg, str);
  428.     return 1;
  429. }
  430.  
  431. int
  432. command_arg_set_string(command_arg * arg, const char *str)
  433. {
  434.     if (!arg) {
  435.         return 0;
  436.     }
  437.     my_assert(arg->type == ca_STRING);
  438.  
  439.     if (arg->u.string.maxlen >= 0) {
  440.         if (str) {
  441.             strncpy(arg->u.string.m.mem, str, arg->u.string.maxlen);
  442.             arg->u.string.m.mem[arg->u.string.maxlen - 1] = 0;
  443.         } else {
  444.             *arg->u.string.m.mem = 0;
  445.         }
  446.     } else {
  447.         if (str) {
  448.             *arg->u.string.m.ptr = (char *) xrealloc(*arg->u.string.m.ptr,
  449.                                                      strlen(str) + 1);
  450.             strcpy(*arg->u.string.m.ptr, str);
  451.         } else {
  452.             if (*arg->u.string.m.ptr) {
  453.                 xfree(arg->u.string.m.ptr);
  454.             }
  455.             *arg->u.string.m.ptr = 0L;
  456.         }
  457.     }
  458.  
  459.     if (arg->action)
  460.         if (!arg->action(arg, caa_WRITE))
  461.             return 0;
  462.  
  463.     return 1;
  464. }
  465.  
  466. void
  467. command_arg_read_spec(command_arg * arg, char **str)
  468. {
  469.     if (arg->type == ca_SPEC)
  470.         *str = OS_SpecToString1(arg->u.spec.mem);
  471.     else if (arg->type == ca_PATHSPEC)
  472.         *str = OS_PathSpecToString1(arg->u.pathspec.mem);
  473.     else                        /* if (arg->type == ca_NAMESPEC) */
  474.         *str = OS_NameSpecToString1(arg->u.namespec.mem);
  475. }
  476.  
  477. int
  478. command_arg_get_spec(command_arg * arg, char **str)
  479. {
  480.     if (!arg) {
  481.         *str = 0L;
  482.         return 0;
  483.     }
  484.     my_assert(ca_ISSPEC(arg->type));
  485.     if (arg->action)
  486.         if (!arg->action(arg, caa_READ))
  487.             return 0;
  488.     command_arg_read_spec(arg, str);
  489.     return 1;
  490. }
  491.  
  492. int
  493. command_arg_set_spec(command_arg * arg, const char *str)
  494. {
  495.     OSError     err = OS_FNFERR;
  496.  
  497.     if (!arg) {
  498.         return 0;
  499.     }
  500.  
  501.     my_assert(ca_ISSPEC(arg->type));
  502.  
  503.     if (str) {
  504.         if (arg->type == ca_SPEC)
  505.             err = OS_MakeSpec(str, arg->u.spec.mem, NULL);
  506.         else if (arg->type == ca_PATHSPEC)
  507.             err = OS_MakePathSpec(NULL, str, arg->u.pathspec.mem);
  508.         else                        /* if (arg->type == ca_NAMESPEC) */
  509.             err = OS_MakeNameSpec(str, arg->u.namespec.mem);
  510.     }
  511.  
  512.     if (err != OS_NOERR) {
  513.         parse_error("argument '%s': cannot set to '%s' (%s)", arg->name,
  514.                     str, OS_GetErrText(err));
  515.         return 0;
  516.     }
  517.  
  518.     if (arg->action)
  519.         if (!arg->action(arg, caa_WRITE))
  520.             return 0;
  521.  
  522.     return 1;
  523. }
  524.  
  525. void
  526. command_arg_read_toggle(command_arg * arg, int *val)
  527. {
  528.     command_arg_read_num(arg, val);
  529.     *val = (arg->u.toggle.flag & *val) != 0;
  530. }
  531.  
  532. int
  533. command_arg_get_toggle(command_arg * arg, int *val)
  534. {
  535.     if (!arg) {
  536.         *val = 0L;
  537.         return 0;
  538.     }
  539.     if (!command_arg_get_num(arg, val))
  540.         return 0;
  541.  
  542.     *val = (arg->u.toggle.flag & *val) != 0;
  543.     return 1;
  544. }
  545.  
  546. int
  547. command_arg_set_toggle(command_arg * arg, int val)
  548. {
  549.     int         curval;
  550.  
  551.     if (!arg) {
  552.         return 0;
  553.     }
  554.  
  555.     if (!command_arg_get_num(arg, &curval))
  556.         return 0;
  557.  
  558.     val = val ? (curval | arg->u.toggle.flag) :
  559.         (curval & ~arg->u.toggle.flag);
  560.  
  561.     if (!command_arg_set_num(arg, val))
  562.         return 0;
  563.  
  564.     return 1;
  565. }
  566.  
  567. /***************************************/
  568.  
  569. int
  570. command_get_val(command_symbol * sym, command_exprval * val)
  571. {
  572.     command_arg *ret;
  573.  
  574.     if (sym->action)
  575.         if (!sym->action(sym, csa_READ, 0))
  576.             return 0;
  577.  
  578.     ret = sym->ret;
  579.     if (!ret) {
  580.         val->type = ca_VOID;
  581.         return 1;
  582.     } else if (ret->type == ca_NUM) {
  583.         val->type = ca_NUM;
  584.         if (!command_arg_get_num(ret, &val->u.num))
  585.             return 0;
  586.     } else if (ret->type == ca_STRING) {
  587.         char       *str;
  588.  
  589.         val->type = ca_STRING;
  590.         if (!command_arg_get_string(ret, &str))
  591.             return 0;
  592.         val->u.str = xstrdup(str);
  593.     } else if (ca_ISSPEC(ret->type)) {
  594.         char       *str;
  595.  
  596.         val->type = ca_STRING;
  597.         if (!command_arg_get_spec(ret, &str))
  598.             return 0;
  599.         val->u.str = xstrdup(str);
  600.     } else if (ret->type == ca_TOGGLE) {
  601.         val->type = ca_NUM;
  602.         if (!command_arg_get_toggle(ret, &val->u.num))
  603.             return 0;
  604.     } else {
  605.         logger(_L | LOG_FATAL, "Unhandled ca_XXXX (%s)\n", ca_types[ret->type]);
  606.     }
  607.  
  608.  
  609.     return 1;
  610. }
  611.  
  612.  
  613. int
  614. command_set_args(command_exprval * ret, command_symbol * sym, ...)
  615. {
  616.     va_list     ap;
  617.     command_exprval *val;
  618.     command_arg *arg;
  619.     int         argnum = 0;
  620.  
  621.     logger(_L | L_2, "sym->name='%s'\n", sym->name);
  622.  
  623. //    if (!(!(sym->flags & c_SESSION_ONLY) && session_only)) 
  624.     {
  625.  
  626.     arg = sym->args;
  627.     va_start(ap, sym);
  628.     while ((val = va_arg(ap, command_exprval *)) != NULL) {
  629.         argnum++;
  630.  
  631.         if (arg == NULL) {
  632.             parse_error("%s:  unexpected additional %s argument #%d",
  633.                         sym->name, ca_types[val->type], argnum);
  634.             return 0;
  635.         }
  636.  
  637.         /*  Look for implicit conversions */
  638.         if (val->type == ca_STRING && ca_ISSPEC(arg->type)) {
  639.             if (!command_arg_set_spec(arg, val->u.str))
  640.                 return 0;
  641.             xfree(val->u.str);
  642.  
  643.         } else if (val->type == ca_NUM && arg->type == ca_TOGGLE) {
  644.             if (!command_arg_set_toggle(arg, val->u.num))
  645.                 return 0;
  646.  
  647.         } else if (val->type == ca_NUM && arg->type == ca_NUM) {
  648.             if (!command_arg_set_num(arg, val->u.num))
  649.                 return 0;
  650.         } else if (val->type == ca_STRING && arg->type == ca_STRING) {
  651.             if (!command_arg_set_string(arg, val->u.str))
  652.                 return 0;
  653.             xfree(val->u.str);
  654.         } else if (val->type != arg->type) {
  655.             parse_error("%s:  type mismatch in argument '%s' (expected %s)",
  656.                         sym->name, arg->name, ca_types[arg->type]);
  657.             return 0;
  658.         } else
  659.             logger(_L | LOG_FATAL, "command_set_args:  cannot handle %s\n",
  660.                  ca_types[val->type]);
  661.  
  662.         arg = arg->next;
  663.     }
  664.  
  665.     if (arg != NULL) {
  666.         parse_error("%s:  expected additional parameters", sym->name);
  667.         return 0;
  668.     }
  669.  
  670.     if (sym->action)
  671.         if (!sym->action(sym, csa_WRITE, 0))
  672.             return 0;
  673.  
  674.     }
  675.  
  676.     if (ret) {
  677.         ret->type = ca_VOID;
  678.         if (sym->ret && !command_get_val(sym, ret))
  679.             return 0;
  680.     }
  681.  
  682.     return 1;
  683. }
  684.  
  685. /************************/
  686.  
  687. int
  688. command_lexer_setup_text(char *name, char *text, int len)
  689. {
  690.     return lexer_push_text(name, text, len) != NULL;
  691. }
  692.  
  693. int
  694. command_lexer_setup_file(char *filename)
  695. {
  696.     return lexer_push_file(filename) != NULL;
  697. }
  698.  
  699.  
  700. /**********************/
  701.  
  702. void
  703. command_init(void)
  704. {
  705.     universe = command_symbol_table_new("V9t9 Options",
  706.                                         "This is the complete list of options and commands "
  707.                                         "you may specify in a configuration file or command prompt.",
  708.                                         NULL, NULL, NULL);
  709.     session_only = false;
  710. }
  711.  
  712.  
  713. int
  714. command_parse_file(char *name)
  715. {
  716.     if (!command_lexer_setup_file(name))
  717.         return 0;
  718.     command_parse(universe);
  719.     return 1;
  720. }
  721.  
  722. int
  723. command_parse_text(char *str)
  724. {
  725.     if (!command_lexer_setup_text("<command_parse_text>", str, strlen(str)))
  726.         return 0;
  727.     command_parse(universe);
  728.     return 1;
  729. }
  730.  
  731. bool    command_get_session_filter(void)
  732. {
  733.     return session_only;
  734. }
  735.  
  736. void    command_set_session_filter(bool allow_session_only)
  737. {
  738.     session_only = allow_session_only;
  739. }
  740.  
  741. /**********************/
  742.  
  743. #ifdef STANDALONE
  744.  
  745. int         a, b;
  746. OSPathSpec  dir;
  747. char        buf[4], buf2[16];
  748. int         c;
  749.  
  750. int
  751. main(int argc, char **argv)
  752. {
  753.  
  754. /*
  755.     command_symbol_table *table = 
  756.         command_symbol_table_new(NULL, 
  757.             command_symbol_new("a", NULL,
  758.                 command_arg_new_num(sizeof(a), &a, NULL
  759.                 ),
  760.                 command_arg_new_num(sizeof(a), &a, NULL
  761.                 ),
  762.             command_symbol_new("b", NULL,
  763.                 command_arg_new_num(sizeof(b), &b, NULL
  764.                 ),
  765.                 command_arg_new_num(sizeof(b), &b, NULL
  766.                 ),
  767.             command_symbol_new("ni", NULL,
  768.                 command_arg_new_num(sizeof(c), &c, NULL
  769.                 ),
  770.                 command_arg_new_string(sizeof(buf), buf,
  771.                 command_arg_new_num(sizeof(c), &c, NULL
  772.                 )), 
  773.             command_symbol_new("c", NULL,
  774.                 command_arg_new_string(sizeof(buf), buf, NULL
  775.                 ),
  776.                 command_arg_new_string(sizeof(buf), buf, NULL
  777.                 ), 
  778.             command_symbol_new("d", NULL,
  779.                 command_arg_new_string(sizeof(buf2), buf2, NULL
  780.                 ),
  781.                 command_arg_new_string(sizeof(buf2), buf2, NULL
  782.                 ),
  783.             NULL
  784.             )))))
  785.         );
  786. */
  787.     char       *text = "#include \"test.cnf\"";
  788.  
  789. //  xminfo();
  790.  
  791.     command_symbol_table_add(universe,
  792.                              command_symbol_new("DelayBetweenInstructions",
  793.                                                 "Sets a constant delay between instructions",
  794.                                                 NULL,
  795.                                                 NULL,
  796.                                                 command_arg_new_num("cycles",
  797.                                                                     "number of cycles to count",
  798.                                                                     NULL,
  799.                                                                     ARG_NUM
  800.                                                                     (a),
  801.                                                                     NULL),
  802.                             command_symbol_new
  803.                                                 ("ModulesPath",
  804.                                                  "Set directory to search for module ROMs",
  805.                                                  NULL, NULL,
  806.                                                  command_arg_new_pathspec
  807.                                                  ("dir", "path to directory",
  808.                                                   NULL, &dir, NULL), 
  809.  
  810.                                                  NULL)));
  811.  
  812.     command_help();
  813.  
  814.     if (!command_lexer_setup_text("test", text, strlen(text)))
  815.         return -1;
  816.     command_parse(universe);
  817.  
  818.     printf("a=%d, b=%d, buf=%s, buf2=%s, c=%d\n", a, b, buf, buf2, c);
  819.  
  820. //  xminfo();
  821. }
  822. #endif
  823.