openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

cint_exec.c (57000B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        cint_exec.c
      8  * Purpose:     API mode CINT execution interface
      9  */
     10 
     11 #include "bcm/port.h"
     12 #include "sal/types.h"
     13 #include "sal/core/alloc.h"
     14 #include "sal/core/libc.h"
     15 #include "sal/appl/io.h"
     16 #include "shared/util.h"
     17 #include "appl/diag/system.h"
     18 #include "appl/diag/shell.h"
     19 #include "cint_porting.h"
     20 
     21 /* The following declarations allows only the %token identifiers to be
     22    included, and not any of the other Bison types. This facilitates
     23    including multiple Bison interpreter headers, provided that the
     24    individual token types don't conflict. */
     25 #define YYSTYPE_IS_DECLARED
     26 #define YYLTYPE_IS_DECLARED
     27 #define YYPUSH_DECLS
     28 
     29 #include "cint_interpreter.h"
     30 #include "cint_porting.h"
     31 #include "cint_internal.h"
     32 
     33 #include "context.h"
     34 #include "api_grammar.tab.h"
     35 #include "api_mode.h"
     36 
     37 typedef enum prompt_assign_e {
     38     prompt_assign_none,
     39     prompt_assign_error,
     40     prompt_assign_create_tmp,
     41     prompt_assign_output_var,
     42     prompt_assign_output_var_c,
     43     prompt_assign_output_var_r,
     44     prompt_assign_output_tmp,
     45     prompt_assign_bidir_var_c,
     46     prompt_assign_bidir_tmp,
     47     prompt_assign_input_constant,
     48     prompt_assign_input_var,
     49     prompt_assign_input_tmp
     50 } prompt_assign_t;
     51 
     52 /* Note that the cint_parameter_desc_t have to be structures,
     53    not references because of how CINT typedef resolution works */
     54 
     55 /* prompt_arg_t flags */
     56 #define PA_LAST       0x00000001
     57 #define PA_EXPAND     0x00000002
     58 
     59 /*
     60   CINT function arguments are fully and recursively expanded to
     61   facilitate prompt assignment. This becomes the assignment structure
     62   used to create the resulting CINT program. The function arguments
     63   are represented as 'level 0' structures, and any aggregrate
     64   (structure and array) arguments are expanded as level 1 and
     65   higher. Aggregates inherit the directionality of the parent
     66   arguments.
     67  */
     68 typedef struct prompt_arg_s {
     69     prompt_assign_t assign_op;          /* assignment operation */
     70     cint_parameter_desc_t desc;         /* CINT parameter desc */
     71     cint_datatype_t dt;                 /* CINT datatype */
     72     const char *path;                   /* variable components */
     73     const char *value;                  /* assigned value */
     74     int idx;                            /* array index if array member */
     75     int level;                          /* arg level;0=toplevel */
     76     int pos;                            /* positional index */
     77     uint32 p_flags;                     /* PA flags */
     78     uint32 c_flags;                     /* CINT flags */
     79     struct prompt_arg_s *next;          /* next in list */
     80     struct prompt_arg_s *prev;          /* prev in list */
     81 } prompt_arg_t;
     82 
     83 /* subset of prompt_arg_t used for construction */
     84 typedef struct desc_data_s {
     85     uint32 p_flags;                       /* PA flags */
     86     uint32 c_flags;                       /* CINT flags */
     87     int idx;
     88     int level;
     89     int pos;
     90 } desc_data_t;
     91 
     92 /* track assignment context */
     93 typedef enum prompt_ctx_e {
     94     prompt_ctx_unknown, /* unknown assignment context */
     95     prompt_ctx_outer,   /* outermost level */
     96     prompt_ctx_kv,      /* keyword - value */
     97     prompt_ctx_pos      /* positional */
     98 } prompt_ctx_t;
     99 
    100 /* root prompt arg struct */
    101 typedef struct {
    102     prompt_arg_t *head;         /* head of API argument list */
    103     prompt_arg_t *tail;         /* tail of API argument list */
    104     prompt_arg_t *search;       /* current search pointer */
    105     prompt_arg_t *assign;       /* current assign pointer */
    106     prompt_ctx_t context;       /* current assignment context */
    107 } prompt_t;
    108 
    109 /* temporary staging buffer size */
    110 #ifndef API_MODE_STAGE_SIZE
    111 #define API_MODE_STAGE_SIZE 256
    112 #endif
    113 
    114 /* prompt mode prompt string buffer */
    115 #ifndef API_MODE_PROMPT_SIZE
    116 #define API_MODE_PROMPT_SIZE 256
    117 #endif
    118 
    119 /* buffer to construct CINT program */
    120 #ifndef API_MODE_PROGRAM_SIZE
    121 #define API_MODE_PROGRAM_SIZE 16*1024
    122 #endif
    123 
    124 /* CINT program indent level */
    125 #ifndef API_MODE_INDENT
    126 #define API_MODE_INDENT "  "
    127 #endif
    128 
    129 /* global data used for program construction */
    130 typedef struct {
    131     int unit;                   /* default unit */
    132     int debug;                  /* true if tracing requested */
    133     int rv;                     /* internal return value */
    134     char *prompt;               /* program construction buffers */
    135     char *stage;
    136     char *program;
    137 } api_mode_data_t;
    138 
    139 typedef int (*pfunc_t)(api_mode_data_t *data, prompt_arg_t *p_arg);
    140 typedef int (*pfunc_s_t)(api_mode_data_t *data, prompt_arg_t *p_arg,
    141                           const char *s);
    142 typedef int (*paf)(api_mode_data_t *data, prompt_arg_t *dst);
    143 
    144 typedef struct prompt_arg_helper_s {
    145     const char *key;
    146     pfunc_t help;
    147     pfunc_s_t convert;
    148     pfunc_t format;
    149 } prompt_arg_helper_t;
    150 
    151 typedef struct prompt_arg_type_inference_s {
    152     const char *basetype_out;
    153     const char *basetype_in;
    154     const char *name;
    155 } prompt_arg_type_inference_t;
    156 
    157 typedef enum match_op_e {
    158     OP_NONE,
    159     OP_FPROMPT,
    160     OP_VPROMPT,
    161     OP_HELP,
    162     OP_KWARG,
    163     OP_PRINT,
    164     OP_VAR,
    165     OP_CREATE
    166 } match_op_t;
    167 
    168 
    169 /* run a CINT program */
    170 STATIC int
    171 cmd_api_run(api_mode_data_t *data)
    172 {
    173     cint_ast_t* ast;
    174     int rv = API_MODE_E_NONE;
    175 
    176     if (data->program) {
    177         if (data->debug) {
    178             sal_printf("Program: \n%s\n", data->program);
    179             sal_printf("Result:\n");
    180         }
    181         ast = cint_interpreter_parse_string(data->program);
    182         if (ast) {
    183             rv = cint_interpreter_evaluate(ast);
    184         }
    185     }
    186 
    187     return rv;
    188 }
    189 
    190 /* Return a string indicating parameter direction */
    191 STATIC char *
    192 param_dir_str(uint32 flags)
    193 {
    194     char *s = "?";
    195     if ((flags & CINT_PARAM_INOUT) == CINT_PARAM_INOUT) {
    196         s = "IO";
    197     } else if (flags & CINT_PARAM_IN) {
    198         s = "I";
    199     } else if (flags & CINT_PARAM_OUT) {
    200         s = "O";
    201     } else if (flags == 0) {
    202         s = "";
    203     } else {
    204         s = "!";
    205     }
    206     return s;
    207 }
    208 
    209 
    210 /*
    211   Try to match identifier arguments in arg to a CINT function. Return
    212   TRUE if there is a match. 'out' is set to the first non-identfier
    213   argument from 'in', and 'dt' is the CINT function datatype.
    214 
    215   'buffer' contains the matched function name.
    216 
    217   If help, prompt-assignment, or keyword/value arguments, then only the
    218   identifiers are matched.  If positional arguments, then the arity must
    219   either match or be one greater if the first argument name is "unit".
    220 
    221  */
    222 
    223 
    224 
    225 STATIC int
    226 match_command(api_mode_arg_t *in, api_mode_arg_t **out,
    227               const cint_datatype_t **dt, int *op_p)
    228 {
    229     api_mode_arg_t *a, *argp;
    230     match_op_t op = OP_NONE;
    231     int rv = API_MODE_E_FAIL;
    232     int has_arg = 0;
    233     argp = NULL;
    234 
    235     for (a=in; a; a=a->next) {
    236         switch (a->kind) {
    237         case IDENT:
    238             break;
    239         case HELP:
    240             op = OP_HELP;
    241             break;
    242         case PRINT:
    243             op = OP_PRINT;
    244             has_arg = 1;
    245             break;
    246         case VAR:
    247             op = OP_VAR;
    248             has_arg = 1;
    249             break;
    250         case CREATE:
    251             op = OP_CREATE;
    252             has_arg = 1;
    253             break;
    254         case PROMPT:
    255             op = (op == OP_VAR) ? OP_VPROMPT : OP_FPROMPT;
    256             break;
    257         case KEY_VALUE:
    258             op = OP_KWARG;
    259             has_arg = 1;
    260             break;
    261         default:
    262             has_arg = 1;
    263             break;
    264         }
    265         if (has_arg && !argp) {
    266             argp = a;
    267         }
    268 
    269     }
    270 
    271     switch (op) {
    272     case OP_NONE:
    273     case OP_HELP:
    274     case OP_FPROMPT:
    275     case OP_KWARG:
    276         if (in->dt) {
    277             *dt = in->dt;
    278             rv = API_MODE_E_NONE;
    279         } else {
    280             rv = API_MODE_E_NOT_FOUND;
    281         }
    282         break;
    283     case OP_PRINT:
    284     case OP_VAR:
    285     case OP_CREATE:
    286     case OP_VPROMPT:
    287         rv = has_arg ? API_MODE_E_NONE : API_MODE_E_FAIL;
    288         break;
    289     default:
    290         rv = API_MODE_E_NOT_FOUND; /* or fail? */
    291         break;
    292     }
    293     
    294     *out = argp;
    295     *op_p = op;
    296 
    297     return rv;
    298 }
    299 
    300 /* show partial help for a CINT datatype */
    301 STATIC int
    302 _partial_help(void* cookie, const cint_datatype_t* dt)
    303 {
    304     char *str = (char *)cookie;
    305     int len = sal_strlen(str);
    306     if (!strncmp(str, dt->desc.basetype, len)) {
    307         sal_printf("%s\n", dt->desc.basetype);
    308     }
    309 
    310     return API_MODE_E_NONE;
    311 }
    312 
    313 /* partial help for a set of functions */
    314 STATIC int
    315 api_mode_partial_help(api_mode_arg_t *in)
    316 {
    317     if (in->dt) {
    318         const char *name = in->dt->desc.basetype;
    319         sal_printf("Functions beginning with %s:\n", name);
    320         cint_datatype_traverse(CINT_DATATYPE_FLAGS_FUNC,
    321                                _partial_help, (void *)name);
    322     } else {
    323         return API_MODE_E_UNAVAIL;
    324     }
    325     return API_MODE_E_NONE;
    326 }
    327 
    328 
    329 
    330 typedef int (*_ccb_d_t_f)(const cint_parameter_desc_t *desc,
    331                           const cint_parameter_desc_t *parent,
    332                           const cint_datatype_t *dt,
    333                           int level,
    334                           void *data);
    335 
    336 /* CINT parameter desc traversal */
    337 int
    338 _ccb_desc_traverse(const cint_parameter_desc_t *desc,
    339                    const cint_parameter_desc_t *parent,
    340                    _ccb_d_t_f func,
    341                    int level,
    342                    void *data)
    343 {
    344     int rv;
    345     cint_datatype_t dt;
    346 
    347     if (!desc->basetype) {
    348         return API_MODE_E_NONE;
    349     }
    350 
    351     rv = cint_datatype_find(desc->basetype, &dt);
    352     rv = func(desc, parent, (rv == CINT_E_NONE) ? &dt : NULL, level, data);
    353     if (API_MODE_SUCCESS(rv)) {
    354         if (dt.flags & CINT_DATATYPE_F_STRUCT) {
    355             const cint_parameter_desc_t *m;
    356             for (m=dt.basetype.sp->struct_members; m->basetype; m++) {
    357                 if (_ccb_desc_traverse(m, desc, func, level+1, data) < 0) {
    358                     break;
    359                 }
    360             }
    361         }
    362         if (dt.flags & CINT_DATATYPE_F_TYPEDEF) {
    363             if ((desc->name != NULL)) {
    364                 _ccb_desc_traverse(&dt.desc, desc, func, level+1, data);
    365             }
    366         }
    367     }
    368 
    369     return rv;
    370 }
    371 
    372 /* show datatype information */
    373 STATIC int
    374 _ccb_show_callback(const cint_parameter_desc_t *desc,
    375                    const cint_parameter_desc_t *parent,
    376                    const cint_datatype_t *dt,
    377                    int level,
    378                    void *user_data)
    379 {
    380     int i;
    381     int indent = level*2;
    382 
    383     for (i=0; i<indent; i++) {
    384         sal_printf("  ");
    385     }
    386     if (indent > 5) {
    387         sal_printf("?depth\n");
    388         return API_MODE_E_FAIL;
    389     }
    390     if (dt->flags & CINT_DATATYPE_F_TYPEDEF) {
    391         sal_printf("typedef ");
    392     }
    393     if (dt->flags & CINT_DATATYPE_F_STRUCT) {
    394         sal_printf("struct ");
    395     }
    396     if (dt->flags & CINT_DATATYPE_F_ENUM) {
    397         sal_printf("enum ");
    398     }
    399     if (dt->flags & CINT_DATATYPE_F_FUNC) {
    400         sal_printf("function ");
    401     }
    402     if (dt->flags & CINT_DATATYPE_F_CONSTANT) {
    403         sal_printf("constant ");
    404     }
    405     if (dt->flags & CINT_DATATYPE_F_FUNC_DYNAMIC) {
    406         sal_printf("dynamic function ");
    407     }
    408     if (dt->flags & CINT_DATATYPE_F_FUNC_POINTER) {
    409         sal_printf("function pointer ");
    410     }
    411     if (dt->flags & CINT_DATATYPE_F_ITERATOR) {
    412         sal_printf("iterator ");
    413     }
    414     if (dt->flags & CINT_DATATYPE_F_MACRO) {
    415         sal_printf("macro ");
    416     }
    417     if (dt->flags & CINT_DATATYPE_F_FUNC_VARARG) {
    418         sal_printf("variadic function ");
    419     }
    420     sal_printf("%s ", desc->basetype);
    421     for (i=0; i<desc->pcount; i++) {
    422         sal_printf("*");
    423     }
    424 
    425     sal_printf("%s", desc->name ? desc->name : "");
    426 
    427     if (desc->array > 0) {
    428         sal_printf("[%d]", desc->array);
    429     }
    430     sal_printf(";");
    431 
    432     sal_printf("\n");
    433     return API_MODE_E_NONE;
    434 }
    435 
    436 /* CINT parameter desc traversal */
    437 STATIC void
    438 _ccb_show_desc(const cint_parameter_desc_t *desc)
    439 {
    440     _ccb_desc_traverse(desc, NULL, _ccb_show_callback, 0, NULL);
    441 }
    442 
    443 /* help string for CINT parameter desc */
    444 STATIC void
    445 _help_arg(const cint_parameter_desc_t *desc)
    446 {
    447     int i;
    448 
    449     sal_printf("{%s} ", param_dir_str(desc->flags));
    450     sal_printf("%s ", desc->basetype);
    451     for (i=0; i<desc->pcount; i++) {
    452         sal_printf("*");
    453     }
    454 
    455     sal_printf("%s", desc->name ? desc->name : "");
    456 
    457     if (desc->array > 0) {
    458         sal_printf("[%d]", desc->array);
    459     }
    460 }
    461 
    462 /* function and structure help */
    463 STATIC int
    464 api_mode_help(const cint_datatype_t *dt)
    465 {
    466     if (dt->flags & CINT_DATATYPE_FLAGS_FUNC) {
    467         const cint_parameter_desc_t *param;
    468 
    469         param = dt->basetype.fp->params;
    470         sal_printf("%s %s(", param->basetype, dt->desc.basetype);
    471         param++;
    472         while (param->basetype != NULL) {
    473             _help_arg(param);
    474             if (param[1].basetype) {
    475                 sal_printf(", ");
    476             }
    477             param++;
    478         }
    479         sal_printf(")");
    480     } else if (dt->flags & CINT_DATATYPE_F_STRUCT) {
    481         const cint_parameter_desc_t *m;
    482         sal_printf("typedef struct %s {\n", dt->desc.basetype);
    483         for (m=dt->basetype.sp->struct_members; m->basetype; m++) {
    484             sal_printf("  %s %s;\n", m->basetype, m->name);
    485         }
    486         sal_printf("}\n");
    487     } else {
    488         _ccb_show_desc(&dt->desc);
    489     }
    490 
    491     sal_printf("\n");
    492     return API_MODE_E_NONE;
    493 }
    494 
    495 /*
    496   prompt_assign operators control how the CINT program is constructed based
    497   on the API mode function argument assignments.
    498 
    499   Note that the global and bidir variables are created as a convenience. It
    500   is normally expected that bidir variables already exist.
    501   
    502   An API mode command is translated to a CINT program with the
    503   following structure:
    504 
    505   // Create output and bidir global variables
    506   {
    507     // Create needed input, output, and bidir temporary variables
    508     // Assign input constants
    509     // Call CINT function
    510     // Display return value
    511     // Display output variables
    512   }
    513 
    514   prompt_assign_none
    515 
    516     Assignments were not made to this argument. If this a top level
    517     function parameter, create a temporary variable.  If the function
    518     argument is treated as an input and if a constructor exists, call
    519     the constructor. The temporary variable is passed to the function,
    520     and, if it is an output, schedule for printing. op changed to
    521     prompt_assign_*_tmp where * is input, output, or bidir. If this is
    522     not a top level argument, i.e., a structure or array member, then
    523     ignore.
    524   
    525   prompt_assign_error
    526 
    527     Terminate program construction and return an error.
    528   
    529   prompt_assign_output_var
    530 
    531     Output variable exists - pass directly to function and schedule
    532     for printing. Not applicable to non-top level arguments.
    533   
    534   prompt_assign_output_var_c
    535 
    536     Output variable does not exist - create as global, pass directly
    537     to function, and schedule for printing. Output variable values are
    538     constructed by the function being called, so do not need to have a
    539     constructor called. Not applicable to non-top level arguments.
    540   
    541   prompt_assign_output_var_r
    542 
    543     Output variable exists but the type is incompatible - delete the
    544     global variable first and then process as with
    545     prompt_assign_output_var_c. Not applicable to non-top level
    546     arguments.
    547   
    548   prompt_assign_bidir_var_c
    549 
    550     Bidir variable does not exist - create as global, construct if
    551     necessary, pass directly to function, and schedule for
    552     printing. Not applicable to non-top level arguments.
    553   
    554   prompt_assign_input_constant
    555 
    556     The input is a constant. For a top level argument, create a
    557     temporary input variable, assign the constant to the variable, and
    558     pass the temporary variable to the function. For non-top-level arguments,
    559     assign to input component.
    560   
    561   prompt_assign_input_var
    562   
    563     The input is an existing variable - pass the input variable to the
    564     function. Not applicable to non-top level arguments.
    565   
    566  */
    567 
    568 /* value assignment */
    569 STATIC int
    570 pa_value(prompt_arg_t *p_arg, const char *value)
    571 {
    572     int rv = API_MODE_E_FAIL;
    573 
    574     if (p_arg->value) {
    575         sal_free((void *)p_arg->value);
    576     }
    577     
    578     p_arg->value = sal_strdup(value);
    579     if (p_arg->value != NULL) {
    580         rv = API_MODE_E_NONE;
    581     }
    582 
    583     return rv;
    584 }
    585 
    586 /* port converter help */
    587 STATIC int
    588 pa_bcm_port_t_help(api_mode_data_t *data, prompt_arg_t *p_arg)
    589 {
    590     sal_printf("Physical port, gport, diag shell port\n");
    591     return API_MODE_E_NONE;
    592 }
    593 
    594 /* port converter */
    595 STATIC int
    596 pa_bcm_port_t_convert(api_mode_data_t *data, prompt_arg_t *p_arg, const char *s)
    597 {
    598     bcm_port_t port;
    599     char buf[16];
    600     int rv = 0;
    601     
    602     rv = parse_bcm_port(data->unit, (char *)s, &port);
    603     if (API_MODE_SUCCESS(rv)) {
    604         sal_printf("convert: %s=%d\n", s, port);
    605         sal_sprintf(buf, "%d", port);
    606         rv = pa_value(p_arg, buf);
    607     } else {
    608         sal_printf("convert %s failed:%d\n", s, rv);
    609     }
    610     return rv;
    611 }
    612 
    613 /* MAC converter help */
    614 STATIC int
    615 pa_bcm_mac_t_help(api_mode_data_t *data, prompt_arg_t *p_arg)
    616 {
    617     sal_printf("MAC address in the form of xx:xx:xx:xx:xx:xx\n");
    618     return API_MODE_E_NONE;
    619 }
    620 
    621 /* MAC converter */
    622 STATIC int
    623 pa_bcm_mac_t_convert(api_mode_data_t *data, prompt_arg_t *p_arg, const char *s)
    624 {
    625     sal_mac_addr_t mac;
    626     char buf[32];
    627     int rv = API_MODE_E_NONE;
    628     
    629     sal_printf("convert %s\n", s);
    630     rv = parse_macaddr((char *)s, mac);
    631     if (API_MODE_SUCCESS(rv)) {
    632         sal_sprintf(buf, "\"%x:%x:%x:%x:%x:%x\"",
    633                     mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    634         rv = pa_value(p_arg, buf);
    635     }
    636     return rv;
    637 }
    638 
    639 /* MAC printer */
    640 STATIC int
    641 pa_bcm_mac_t_format(api_mode_data_t *data, prompt_arg_t *p_arg)
    642 {
    643     CINT_STRCAT(data->program, "\"");
    644     CINT_STRCAT(data->program, p_arg->value);
    645     CINT_STRCAT(data->program, "\"");
    646     return API_MODE_E_NONE;
    647 }
    648 
    649 /* converter and type inference interfaces */
    650 STATIC prompt_arg_helper_t pa_helper[] = {
    651     {
    652         "bcm_port_t",
    653         pa_bcm_port_t_help,
    654         pa_bcm_port_t_convert,
    655         NULL,
    656     },
    657     {
    658         "bcm_mac_t",
    659         pa_bcm_mac_t_help,
    660         pa_bcm_mac_t_convert,
    661         pa_bcm_mac_t_format
    662     }
    663 };
    664 
    665 STATIC prompt_arg_type_inference_t pa_tinf[] = {
    666     { "bcm_port_t",     "int",          "port" }
    667 };
    668 
    669 /* search for a type inferrer */
    670 STATIC const char *
    671 pa_infer(const cint_parameter_desc_t *desc)
    672 {
    673     int i;
    674     
    675     for (i=0; i<COUNTOF(pa_tinf); i++) {
    676         if (!strcmp(pa_tinf[i].basetype_in, desc->basetype) &&
    677             !strcmp(pa_tinf[i].name, desc->name)) {
    678             return (pa_tinf[i].basetype_out);
    679         }
    680     }
    681 
    682     return desc->basetype;
    683 }
    684 
    685 /* search for a conversion helper */
    686 STATIC prompt_arg_helper_t *
    687 pa_helper_find(const cint_parameter_desc_t *desc)
    688 {
    689     int i;
    690     const char *basetype = pa_infer(desc);
    691     
    692     for (i=0; i<COUNTOF(pa_helper); i++) {
    693         if (!strcmp(pa_helper[i].key, basetype)) {
    694             return (pa_helper+i);
    695         }
    696     }
    697 
    698     return NULL;
    699 }
    700 
    701 /* arg help */
    702 STATIC int
    703 pa_help(api_mode_data_t *data, prompt_arg_t *p_arg)
    704 {
    705     prompt_arg_helper_t *helper;
    706     int rv = API_MODE_E_NONE;
    707 
    708     helper = pa_helper_find(&p_arg->desc);
    709     if (helper && helper->help) {
    710         rv = helper->help(data, p_arg);
    711     }
    712     return rv;
    713 }
    714 
    715 /* arg format */
    716 STATIC int
    717 pa_format(api_mode_data_t *data, prompt_arg_t *p_arg)
    718 {
    719     prompt_arg_helper_t *helper;
    720     int rv = API_MODE_E_NONE;
    721 
    722     helper = pa_helper_find(&p_arg->desc);
    723     if (helper && helper->format) {
    724         rv = helper->format(data, p_arg);
    725     } else {
    726         CINT_STRCAT(data->program, p_arg->value);
    727     }
    728     return rv;
    729 }
    730 
    731 /* convert 's' */
    732 STATIC int
    733 pa_convert(api_mode_data_t *data, prompt_arg_t *p_arg, const char *s)
    734 {
    735     prompt_arg_helper_t *helper;
    736     int rv = API_MODE_E_NONE;
    737 
    738     helper = pa_helper_find(&p_arg->desc);
    739     if (helper && helper->convert) {
    740         rv = helper->convert(data, p_arg, s);
    741     } else {
    742         rv = pa_value(p_arg, s);
    743     }
    744     return rv;
    745 }
    746 
    747 /* add prompt_arg to list */
    748 STATIC void
    749 add_arg(prompt_t *prompt, prompt_arg_t *arg)
    750 {
    751     if (!prompt->head) {
    752         prompt->head = prompt->tail = arg;
    753     } else {
    754         prompt->tail->next = arg;
    755         arg->prev = prompt->tail;
    756         prompt->tail = arg;
    757     }
    758 }
    759 
    760 /* alloc a prompt_arg node */
    761 STATIC prompt_arg_t *
    762 alloc_arg(void)
    763 {
    764     prompt_arg_t *arg;
    765 
    766     arg = sal_alloc(sizeof(*arg), "apimode");
    767     if (!arg) {
    768         return NULL;
    769     }
    770     sal_memset(arg, 0, sizeof(*arg));
    771 
    772     return arg;
    773 }
    774 
    775 /* display 'unsupported' */
    776 STATIC void
    777 _unsupported(void)
    778 {
    779     sal_printf("unsupported\n");
    780 }
    781 
    782 #define MAXVARPATH 128
    783 
    784 /* append a parameter desc as a prompt_arg node to the prompt list */
    785 STATIC int
    786 append_desc(prompt_t *prompt, const cint_parameter_desc_t *desc,
    787             const char *path, desc_data_t *data)
    788 {
    789     prompt_arg_t *arg;
    790     cint_datatype_t dt;
    791     int rv;
    792     int expand = 0;
    793     char newpath[MAXVARPATH];
    794     const char *basetype;
    795     int array;
    796     int expand_struct;
    797     int expand_array;
    798     int path_len;
    799     cint_parameter_desc_t adesc;
    800 
    801     if (desc == NULL) {
    802         return api_mode_unexpected();
    803     }
    804     
    805     if (desc->basetype == NULL) {
    806         return api_mode_unexpected();
    807     }
    808 
    809     sal_memset(newpath, 0, sizeof(newpath));
    810     path_len = sal_strlen(desc->name);
    811     path_len += 1; /* NUL */
    812     if (path) {
    813         path_len += sal_strlen(path);
    814         path_len += 1; /* '.' */
    815         if (path_len < MAXVARPATH) {
    816             sal_strncpy(newpath, path, MAXVARPATH-1);
    817             CINT_STRCAT(newpath, ".");
    818         } else {
    819             /* too long */
    820             sal_printf("buffer overflow\n");
    821             return API_MODE_E_FAIL;
    822         }
    823     } else if (data->level != 0) {
    824         _unsupported();
    825         return API_MODE_E_FAIL;
    826     }
    827 
    828     if (path_len < MAXVARPATH) {
    829         CINT_STRCAT(newpath, desc->name);
    830     } else {
    831         sal_printf("buffer overflow\n");
    832         return API_MODE_E_FAIL;
    833     }
    834 
    835     basetype = desc->basetype;
    836     array = desc->array;
    837     adesc = *desc;
    838 
    839     for (;;) {
    840         rv = cint_datatype_find(basetype, &dt);
    841         if (rv != CINT_E_NONE) {
    842             sal_printf("Could not find datatype '%s'\n", basetype);
    843             return API_MODE_E_FAIL;
    844         }
    845         
    846         /* If this is a typedef, resolve typedef */
    847         if (dt.flags & CINT_DATATYPE_F_TYPEDEF) {
    848             basetype = dt.desc.basetype;
    849             if (dt.desc.array > 0) {
    850                 array = (array == 0) ? dt.desc.array : array * dt.desc.array;
    851                 adesc = dt.desc;
    852                 adesc.name = desc->name;
    853             }
    854             if (dt.desc.pcount != 0) {
    855                 api_mode_unexpected();
    856             }
    857         } else {
    858             break;
    859         }
    860     }
    861 
    862     expand = (data->c_flags & CINT_PARAM_IN) &&
    863         desc->pcount < ((path == NULL) ? 2 : 1) &&
    864         desc->array == 0 && (pa_helper_find(desc) == NULL);
    865     expand_struct = (dt.flags & CINT_DATATYPE_F_STRUCT) != 0 && expand;
    866     expand_array = array > 0;
    867     
    868     
    869 
    870     arg = alloc_arg();
    871     if (!arg) {
    872         return API_MODE_E_MEMORY;
    873     }
    874 
    875     arg->desc = *desc;
    876     arg->dt = dt;
    877     arg->path = sal_strdup(newpath);
    878     arg->idx = data->idx;
    879     arg->c_flags = data->c_flags;
    880     arg->level = data->level;
    881     arg->pos = data->pos;
    882     arg->p_flags = data->p_flags;
    883     if (expand_struct || expand_array) {
    884         arg->p_flags |= PA_EXPAND;
    885     }
    886     add_arg(prompt, arg);
    887 
    888     /* add any expanded arguments */
    889     if (expand_array) {
    890         desc_data_t adata;
    891 
    892         adata = *data;
    893         adata.level++;
    894         adesc.array = 0;
    895         for (adata.idx=0; adata.idx<array; adata.idx++) {
    896             rv = append_desc(prompt, &adesc, path, &adata);
    897             if (API_MODE_FAILURE(rv)) {
    898                 return rv;
    899             }
    900         }
    901     } else if (desc->flags & CINT_PARAM_VP) {
    902         _unsupported();
    903         return API_MODE_E_UNAVAIL;
    904     } else if (desc->flags & CINT_PARAM_VL) {
    905         _unsupported();
    906         return API_MODE_E_UNAVAIL;
    907     } else if (expand_struct) {
    908         const cint_parameter_desc_t *m;
    909         desc_data_t sdata;
    910 
    911         sdata = *data;
    912         sdata.level++;
    913         sdata.idx = -1;
    914         for (m=dt.basetype.sp->struct_members; m->basetype; m++) {
    915             rv = append_desc(prompt, m, newpath, &sdata);
    916             if (API_MODE_FAILURE(rv)) {
    917                 return rv;
    918             }
    919             
    920         }
    921     }
    922 
    923     return API_MODE_E_NONE;
    924 }
    925 
    926 /* free a prompt list */
    927 STATIC void
    928 prompt_free(prompt_t *prompt)
    929 {
    930     prompt_arg_t *arg, *next;
    931 
    932     arg = prompt->head;
    933     while (arg != NULL) {
    934         if (arg->value) {
    935             sal_free((void *)arg->value);
    936             arg->value = NULL;
    937         }
    938         if (arg->path) {
    939             sal_free((void *)arg->path);
    940             arg->path = NULL;
    941         }
    942         next = arg->next;
    943         sal_free(arg);
    944         arg = next;
    945     }
    946 }
    947 
    948 /* display assignment operations */
    949 STATIC void
    950 _annotate_assignments(prompt_arg_t *prg)
    951 {
    952     for (;prg; prg=prg->next) {
    953         switch (prg->assign_op) {
    954         case prompt_assign_none:
    955             sal_printf("%s n/a\n", prg->path);
    956             break;
    957 
    958         case prompt_assign_error:
    959             sal_printf("%s err\n", prg->path);
    960             break;
    961 
    962         case prompt_assign_output_var:
    963             sal_printf("%s=%s output_var\n", prg->path, prg->value);
    964             break;
    965 
    966         case prompt_assign_output_var_c:
    967             sal_printf("%s=%s output_var_c\n", prg->path, prg->value);
    968             break;
    969 
    970         case prompt_assign_output_var_r:
    971             sal_printf("%s=%s output_var_r\n", prg->path, prg->value);
    972             break;
    973 
    974         case prompt_assign_bidir_var_c:
    975             sal_printf("%s=%s bidir_var_c\n", prg->path, prg->value);
    976             break;
    977 
    978         case prompt_assign_input_constant:
    979             sal_printf("%s=%s input_constant\n", prg->path, prg->value);
    980             break;
    981 
    982         case prompt_assign_input_var:
    983             sal_printf("%s=%s input_var\n", prg->path, prg->value);
    984             break;
    985             
    986         default:
    987             break;
    988         }
    989     }
    990 }
    991 
    992 /* create a CINT variable corresponding to 'arg' */
    993 STATIC int
    994 _create_var(api_mode_data_t *data, prompt_arg_t *arg,
    995             const char *prefix, const char *assignment)
    996 {
    997     if (prefix) {
    998         CINT_STRCAT(data->program, prefix);
    999     }
   1000     CINT_STRCAT(data->program, arg->desc.basetype);
   1001     CINT_STRCAT(data->program, " ");
   1002     CINT_STRCAT(data->program, arg->value);
   1003     if (assignment) {
   1004         CINT_STRCAT(data->program, " = ");
   1005         CINT_STRCAT(data->program, assignment);
   1006     }
   1007     CINT_STRCAT(data->program, ";\n");
   1008 
   1009     return API_MODE_E_NONE;
   1010 }
   1011 
   1012 /* call an initializer for CINT variable corresponding to 'arg' if an
   1013    initializer exists. */
   1014 STATIC int
   1015 _init_var(api_mode_data_t *data, prompt_arg_t *arg)
   1016 {
   1017     int rv;
   1018     cint_datatype_t dt;
   1019 
   1020     /* locate a constructor */
   1021     sal_strcpy(data->stage, arg->desc.basetype);
   1022     CINT_STRCAT(data->stage, "_init");
   1023     
   1024     rv = cint_datatype_find(data->stage, &dt);
   1025 
   1026     if (rv == CINT_E_NONE &&
   1027         (dt.flags & CINT_DATATYPE_FLAGS_FUNC) != 0 &&
   1028         dt.basetype.fp->params[0].basetype != NULL &&
   1029         dt.basetype.fp->params[1].basetype != NULL &&
   1030         dt.basetype.fp->params[2].basetype == NULL &&
   1031         !sal_strcmp(arg->desc.basetype, dt.basetype.fp->params[1].basetype) &&
   1032         arg->desc.pcount == dt.basetype.fp->params[1].pcount &&
   1033         arg->desc.array == dt.basetype.fp->params[1].array) {
   1034         /* Function was found and accepts a single parameter of a
   1035            given argument's datatype. Rely on CINT auto-pointer,
   1036            so don't bother to take address of argument. */
   1037         CINT_STRCAT(data->program, data->stage);
   1038         CINT_STRCAT(data->program, "(");
   1039         CINT_STRCAT(data->program, arg->value);
   1040         CINT_STRCAT(data->program, ");\n");
   1041     }
   1042 
   1043     /* it is not a problem if an initializer does not exist */
   1044     return API_MODE_E_NONE;
   1045 }
   1046 
   1047 /* create a CINT temporary variable corresponding to 'arg' */
   1048 STATIC int
   1049 _temp_var(api_mode_data_t *data, prompt_arg_t *arg)
   1050 {
   1051     int rv = API_MODE_E_FAIL;
   1052 
   1053     if (arg->value == NULL) {
   1054         data->stage[0] = 0;
   1055         CINT_STRCAT(data->stage, "__");
   1056         CINT_STRCAT(data->stage, arg->desc.name);
   1057         arg->value = sal_strdup(data->stage);
   1058         rv = (arg->value) ? API_MODE_E_NONE : API_MODE_E_FAIL;
   1059     }
   1060 
   1061     return rv;
   1062 }
   1063 
   1064 /* call 'func' for every element in the prompt list */
   1065 STATIC int
   1066 _prompt_apply(api_mode_data_t *data, prompt_t *prompt, paf func)
   1067 {
   1068     prompt_arg_t *arg;
   1069     int rv = API_MODE_E_NONE;
   1070 
   1071     for (arg=prompt->head; arg; arg=arg->next) {
   1072         rv = func(data, arg);
   1073         if (API_MODE_FAILURE(rv)) {
   1074             break;
   1075         }
   1076     }
   1077 
   1078     return rv;
   1079 }
   1080 
   1081 /* return an error code if an assign error was found */
   1082 STATIC int
   1083 _paf_error(api_mode_data_t *data, prompt_arg_t *dst)
   1084 {
   1085     return (dst->assign_op == prompt_assign_error) ?
   1086         API_MODE_E_FAIL : API_MODE_E_NONE;
   1087 }
   1088 
   1089 /* delete any existing variables for toplevel prompt_assign_output_var_r */
   1090 STATIC int
   1091 _paf_delete_existing(api_mode_data_t *data, prompt_arg_t *dst)
   1092 {
   1093     if (dst->level == 0 && dst->assign_op == prompt_assign_output_var_r) {
   1094         if (data->debug) {
   1095             sal_printf("// deleting variable '%s'\n", dst->value);
   1096         }
   1097         cint_variable_delete(dst->value);
   1098     }
   1099 
   1100     return API_MODE_E_NONE;
   1101 }
   1102 
   1103 /* create needed toplevel global variables */
   1104 STATIC int
   1105 _paf_create_global(api_mode_data_t *data, prompt_arg_t *dst)
   1106 {
   1107     int rv = API_MODE_E_NONE;
   1108 
   1109     if (dst->level == 0) {
   1110         switch (dst->assign_op) {
   1111         case prompt_assign_output_var_c:
   1112         case prompt_assign_output_var_r:
   1113         case prompt_assign_bidir_var_c:
   1114             rv = _create_var(data, dst, NULL, NULL);
   1115             break;
   1116         default:
   1117             break;
   1118         }
   1119     }
   1120 
   1121     return rv;
   1122 }
   1123 
   1124 /* create needed local variables */
   1125 STATIC int
   1126 _paf_create_local(api_mode_data_t *data, prompt_arg_t *dst)
   1127 {
   1128     int rv = API_MODE_E_NONE;
   1129 
   1130     if (dst->level == 0) {
   1131         switch (dst->assign_op) {
   1132         case prompt_assign_none:
   1133 
   1134             if (dst->desc.pcount > 1) {
   1135                 /* unsupported - ignore for now */
   1136             } else {
   1137                 rv = _temp_var(data, dst);
   1138                 if (API_MODE_SUCCESS(rv)) {
   1139                     rv = _create_var(data, dst, API_MODE_INDENT, NULL);
   1140                     if (API_MODE_SUCCESS(rv)) {
   1141                         dst->assign_op = prompt_assign_create_tmp;
   1142                     }
   1143                 }
   1144             }
   1145             break;
   1146         default:
   1147             break;
   1148         }
   1149     }
   1150 
   1151     return rv;
   1152 }
   1153 
   1154 /* initialize local variables */
   1155 STATIC int
   1156 _paf_init_local(api_mode_data_t *data, prompt_arg_t *dst)
   1157 {
   1158     int rv = API_MODE_E_NONE;
   1159 
   1160     if (dst->level == 0) {
   1161         switch (dst->assign_op) {
   1162         case prompt_assign_create_tmp:
   1163 
   1164             if (dst->c_flags & CINT_PARAM_IN) {
   1165                 CINT_STRCAT(data->program, API_MODE_INDENT);
   1166                 rv = _init_var(data, dst);
   1167                 if (API_MODE_SUCCESS(rv)) {
   1168                     dst->assign_op = prompt_assign_input_tmp;
   1169                 }
   1170             }
   1171             if (dst->c_flags & CINT_PARAM_OUT) {
   1172                 dst->assign_op = (dst->assign_op == prompt_assign_input_tmp) ?
   1173                     prompt_assign_bidir_tmp : prompt_assign_output_tmp;
   1174             }
   1175             break;
   1176         default:
   1177             break;
   1178         }
   1179     }
   1180 
   1181     return rv;
   1182 }
   1183 
   1184 /* assign input constants - must be called after _paf_create_local */
   1185 STATIC int
   1186 _paf_init_input_const(api_mode_data_t *data, prompt_arg_t *dst)
   1187 {
   1188     int rv = API_MODE_E_NONE;
   1189 
   1190     switch (dst->assign_op) {
   1191     case prompt_assign_input_constant:
   1192         /* top level (function) arguments that are assigned a constant
   1193            will have that constant passed directly, as it would be, by
   1194            definition, a scalar constant. Anything deeper than that,
   1195            i.e., composite arguments will have such constants assigned
   1196            to a termporary variable. */
   1197         if (dst->level > 0) {
   1198             CINT_STRCAT(data->program, API_MODE_INDENT "__");
   1199             CINT_STRCAT(data->program, dst->path);
   1200             if (dst->idx >= 0) {
   1201                 sal_sprintf(data->stage, "[%d]", dst->idx);
   1202                 CINT_STRCAT(data->program, data->stage);
   1203             }
   1204             CINT_STRCAT(data->program, "=");
   1205             pa_format(data, dst);
   1206             CINT_STRCAT(data->program, ";\n");
   1207         }
   1208         break;
   1209         
   1210     case prompt_assign_input_tmp:
   1211         break;
   1212         
   1213     default:
   1214         break;
   1215     }
   1216 
   1217     return rv;
   1218 }
   1219 
   1220 /* print outputs */
   1221 STATIC int
   1222 _paf_print_output(api_mode_data_t *data, prompt_arg_t *dst)
   1223 {
   1224     switch (dst->assign_op) {
   1225     case prompt_assign_output_var_c:
   1226     case prompt_assign_output_var_r:
   1227     case prompt_assign_bidir_var_c:
   1228     case prompt_assign_bidir_tmp:
   1229     case prompt_assign_output_tmp:
   1230         CINT_STRCAT(data->program, API_MODE_INDENT "print ");
   1231         CINT_STRCAT(data->program, dst->value);
   1232         CINT_STRCAT(data->program, ";\n");
   1233         break;
   1234     default:
   1235         break;
   1236     }
   1237 
   1238     return API_MODE_E_NONE;
   1239 }
   1240 
   1241 /* emit function call arguments */
   1242 STATIC int
   1243 _paf_call_arg(api_mode_data_t *data, prompt_arg_t *dst)
   1244 {
   1245     if (dst->level == 0) {
   1246         CINT_STRCAT(data->program, dst->value);
   1247         if ((dst->p_flags & PA_LAST) == 0) {
   1248             CINT_STRCAT(data->program, ", ");
   1249         }
   1250     }
   1251 
   1252     return API_MODE_E_NONE;
   1253 }
   1254 
   1255 #define RV "__rv"
   1256 
   1257 
   1258 /* function return type initialization */
   1259 STATIC int   
   1260 _init_func(api_mode_data_t *data, prompt_t *prompt,
   1261            const cint_datatype_t *dt, int *vret)
   1262 {
   1263     const cint_parameter_desc_t *desc;
   1264     int void_return = 0;
   1265 
   1266     /* create return type */
   1267     desc = dt->basetype.fp->params;
   1268     void_return = !strcmp(desc->basetype, "void");
   1269 
   1270     if (!void_return) {
   1271         CINT_STRCAT(data->program, API_MODE_INDENT);
   1272         CINT_STRCAT(data->program, desc->basetype);
   1273         CINT_STRCAT(data->program, " " RV ";\n");
   1274     }
   1275 
   1276     *vret = void_return;
   1277 
   1278     return API_MODE_E_NONE;
   1279 }
   1280 
   1281 
   1282 /* call CINT function */    
   1283 STATIC int   
   1284 _call_func(api_mode_data_t *data, prompt_t *prompt,
   1285            const cint_datatype_t *dt, int void_return)
   1286 {
   1287     int rv;
   1288 
   1289     /* function call */
   1290     CINT_STRCAT(data->program, API_MODE_INDENT);
   1291     if (!void_return) {
   1292         CINT_STRCAT(data->program, RV " = ");
   1293     }
   1294     CINT_STRCAT(data->program, dt->desc.basetype);
   1295     CINT_STRCAT(data->program, "(");
   1296     rv = _prompt_apply(data, prompt, _paf_call_arg);
   1297     if (API_MODE_SUCCESS(rv)) {
   1298         CINT_STRCAT(data->program, ");\n");
   1299 
   1300         /* print return value */
   1301         if (!void_return && sh_rcload_depth == 0) {
   1302             CINT_STRCAT(data->program, API_MODE_INDENT "print " RV ";\n");
   1303             CINT_STRCAT(data->program,
   1304                         API_MODE_INDENT
   1305                         "printf(\"%s\\n\", "
   1306                         "bcm_errmsg(" RV "));\n");
   1307         }
   1308     }
   1309     return rv;
   1310 }
   1311     
   1312 /* execute an argument list as a CINT program */
   1313 STATIC int
   1314 _api_mode_exec(api_mode_data_t *data, prompt_t *prompt,
   1315                const cint_datatype_t *dt)
   1316 {
   1317     int void_return;
   1318     int rv;
   1319     
   1320     if (data->debug) {
   1321         _annotate_assignments(prompt->head);
   1322     }
   1323     rv = _prompt_apply(data, prompt, _paf_error);
   1324     API_MODE_IF_ERROR_RETURN(rv);
   1325     rv = _prompt_apply(data, prompt, _paf_delete_existing);
   1326     API_MODE_IF_ERROR_RETURN(rv);
   1327     rv = _prompt_apply(data, prompt, _paf_create_global);
   1328     API_MODE_IF_ERROR_RETURN(rv);
   1329     /* open new scope */
   1330     {
   1331         CINT_STRCAT(data->program, "{\n");
   1332         rv = _init_func(data, prompt, dt, &void_return);
   1333         API_MODE_IF_ERROR_RETURN(rv);
   1334         /* set up input */
   1335         rv = _prompt_apply(data, prompt, _paf_create_local);
   1336         API_MODE_IF_ERROR_RETURN(rv);
   1337         rv = _prompt_apply(data, prompt, _paf_init_local);
   1338         API_MODE_IF_ERROR_RETURN(rv);
   1339         rv = _prompt_apply(data, prompt, _paf_init_input_const);
   1340         API_MODE_IF_ERROR_RETURN(rv);
   1341         /* call API */
   1342         rv = _call_func(data, prompt, dt, void_return);
   1343         API_MODE_IF_ERROR_RETURN(rv);
   1344         /* print output */
   1345         if (sh_rcload_depth == 0) {
   1346             rv = _prompt_apply(data, prompt, _paf_print_output);
   1347             API_MODE_IF_ERROR_RETURN(rv);
   1348         }
   1349         /* close scope */
   1350         CINT_STRCAT(data->program, "}\n");
   1351     }
   1352     rv = cmd_api_run(data);
   1353 
   1354     return rv;
   1355 }
   1356 
   1357 /* prompt mode handler */
   1358 STATIC prompt_arg_t *
   1359 api_mode_prompt_arg(api_mode_data_t *data, prompt_arg_t *arg)
   1360 {
   1361     prompt_arg_t *nextarg = arg;
   1362     char *s;
   1363 
   1364     sal_strncpy(data->prompt, param_dir_str(arg->c_flags),
   1365                 API_MODE_PROMPT_SIZE-1);
   1366     while (sal_strlen(data->prompt) < 3) {
   1367         CINT_STRCAT(data->prompt, " ");
   1368     }
   1369     CINT_STRCAT(data->prompt, arg->dt.desc.basetype);
   1370     CINT_STRCAT(data->prompt, " ");
   1371     CINT_STRCAT(data->prompt, arg->path);
   1372     if (arg->idx >= 0) {
   1373         sal_sprintf(data->stage, "[%d]", arg->idx);
   1374         CINT_STRCAT(data->prompt, data->stage);
   1375     }
   1376     CINT_STRCAT(data->prompt, "{");
   1377     if (arg->value) {
   1378         CINT_STRCAT(data->prompt, arg->value);
   1379     }
   1380     CINT_STRCAT(data->prompt, "}");
   1381     CINT_STRCAT(data->prompt, ": ");
   1382     s = sal_readline(data->prompt, data->stage, API_MODE_STAGE_SIZE, NULL);
   1383     if (s == NULL) {
   1384         nextarg = NULL;
   1385     } else if (!strncmp(data->stage, "-", 1)) {
   1386         /* don't go back if at first arg */
   1387         if (arg->prev) {
   1388             nextarg = arg->prev;
   1389             if ((nextarg->p_flags & PA_EXPAND)) {
   1390                 nextarg = nextarg->prev;
   1391             }
   1392         }
   1393     } else if (*data->stage == 0) {
   1394         nextarg = arg->next;
   1395     } else if (!strncmp(data->stage, "?", 1)) {
   1396         pa_help(data, arg);
   1397     } else {
   1398         if (!pa_convert(data, arg, data->stage)) {
   1399             arg->assign_op = prompt_assign_input_constant;
   1400             nextarg = arg->next;
   1401         }
   1402     }
   1403     return nextarg;
   1404 }
   1405 
   1406 #if 0
   1407 STATIC void
   1408 api_mode_prompt_show(prompt_arg_t *arg)
   1409 {
   1410     if (arg->idx < 0) {
   1411         sal_printf("%s %s", arg->dt.desc.basetype, arg->path);
   1412     } else {
   1413         sal_printf("%s %s[%d]", arg->dt.desc.basetype, arg->path, arg->idx);
   1414     }
   1415     if (arg->value) {
   1416         sal_printf("=%s", arg->value);
   1417     }
   1418     sal_printf("\n");
   1419 }
   1420 #endif
   1421 
   1422 /* set the default unit */
   1423 STATIC int
   1424 set_default_unit(api_mode_data_t *data, prompt_t *dst)
   1425 {
   1426     char ubuf[16];
   1427     int rv = API_MODE_E_NONE;
   1428     prompt_arg_t *arg = dst->assign;
   1429 
   1430     if (arg &&
   1431         !arg->value &&
   1432         !strcmp(arg->desc.basetype, "int") &&
   1433         !strcmp(arg->desc.name, "unit")) {
   1434         sal_sprintf(ubuf, "%d", data->unit);
   1435         rv = pa_value(arg, ubuf);
   1436         dst->assign->assign_op = prompt_assign_input_constant;
   1437     }
   1438 
   1439     return rv;
   1440 }
   1441 
   1442 /* initialize prompt list */
   1443 STATIC int
   1444 init_prompt(api_mode_data_t *data, prompt_t *prompt,
   1445             api_mode_arg_t *arg,
   1446             const cint_datatype_t *dt)
   1447 {
   1448     const cint_parameter_desc_t *desc;
   1449     api_mode_arg_t *argctr;
   1450     desc_data_t ddata;
   1451     int pos;
   1452     int rv;
   1453 
   1454     desc = dt->basetype.fp->params;
   1455 
   1456     if (desc == NULL) {
   1457         /* vararg func slipped through */
   1458         return API_MODE_E_INTERNAL;
   1459     }
   1460 
   1461     sal_memset(prompt, 0, sizeof(*prompt));
   1462     desc++; /* skip return */
   1463 
   1464     /* iterate across function parameters to create prompt list */
   1465     sal_memset(&ddata, 0, sizeof(ddata));
   1466     ddata.idx = -1;
   1467     pos = 0;
   1468     while (desc->basetype != NULL) {
   1469         ddata.c_flags = desc->flags;
   1470         if (desc[1].basetype == NULL) {
   1471             ddata.p_flags |= PA_LAST;
   1472         }
   1473         rv = append_desc(prompt, desc, NULL, &ddata);
   1474         if (API_MODE_FAILURE(rv)) {
   1475             return rv;
   1476         }
   1477         desc++;
   1478         pos++;
   1479     }
   1480 
   1481     for (argctr=arg; argctr != NULL; argctr=argctr->next) {
   1482         pos--;
   1483     }
   1484 
   1485     /* set search and assignment pointers */
   1486     prompt->search = prompt->head;
   1487     prompt->assign = prompt->head;
   1488     prompt->context = prompt_ctx_outer;
   1489 
   1490     /* set default value for unit */
   1491     rv = set_default_unit(data, prompt);
   1492 
   1493     if (prompt->assign &&
   1494         prompt->assign->assign_op == prompt_assign_input_constant &&
   1495         pos > 0 && arg && arg->kind != KEY_VALUE && prompt->assign->next) {
   1496         /* special case: if the number of supplied arguments is less
   1497            than the number of required arguments, the unit has a
   1498            default value (which also means it is the first argument),
   1499            the first supplied argument is not key/value, and there
   1500            actually *is* another argument, then assume the default
   1501            unit assignment and advance the search and assignment
   1502            position */
   1503         prompt->assign = prompt->assign->next;
   1504         prompt->search = prompt->search->next;
   1505     }
   1506     return rv;
   1507 }
   1508 
   1509 #define CINT_INPUT(f) (((f) & CINT_PARAM_INOUT) == CINT_PARAM_IN)
   1510 #define CINT_OUTPUT(f) (((f) & CINT_PARAM_INOUT) == CINT_PARAM_OUT)
   1511 #define CINT_BIDIR(f) (((f) & CINT_PARAM_INOUT) == CINT_PARAM_INOUT)
   1512 
   1513 /* Special assignments - currently unimplemented */
   1514 STATIC int
   1515 _assign_special(api_mode_data_t *data, prompt_arg_t *prg, api_mode_arg_t *arg)
   1516 {
   1517     return API_MODE_E_UNAVAIL;
   1518 }
   1519 
   1520 /* Display ident error */
   1521 STATIC void
   1522 _ident_error(api_mode_arg_t *arg)
   1523 {
   1524     /* error - must exist */
   1525     sal_printf("Identifier '%s' must exist "
   1526                "for assignment to an input parameter.\n",
   1527                arg->value);
   1528 }
   1529 
   1530 /* Display type incompatible error */
   1531 STATIC void
   1532 _compat_error(api_mode_arg_t *arg)
   1533 {
   1534     /* error - type incompatible */
   1535     sal_printf("Identifier '%s' type incompatible.\n",
   1536                arg->value);
   1537 }
   1538 
   1539 /* assignment forward references */
   1540 STATIC int
   1541 _agg_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src);
   1542 
   1543 STATIC int
   1544 _generic_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src);
   1545 
   1546 
   1547 /* skip over expanded destinations */
   1548 STATIC void
   1549 _advance_expanded(prompt_t *dst)
   1550 {
   1551     int level = dst->assign->level;
   1552 
   1553     do {
   1554         dst->assign = dst->assign->next;
   1555         if (!dst->assign) {
   1556             /* no more */
   1557             break;
   1558         }
   1559     } while (dst->assign->level != level);
   1560 }
   1561 
   1562 /* assign a value */
   1563 STATIC int
   1564 _value_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src)
   1565 {
   1566     int rv = API_MODE_E_FAIL;
   1567     cint_variable_t *v;
   1568     const char *name = (const char *)src->value;
   1569     cint_datatype_t dt;
   1570 
   1571     if (dst->assign->c_flags & CINT_PARAM_OUT) { /* out or bidir */
   1572         /* outputs *must* be identifiers corresponding to variables */
   1573         if (src->token->ident) {
   1574             /* look it up */
   1575             v = cint_variable_find(name, TRUE);
   1576             if (dst->assign->c_flags & CINT_PARAM_IN) { /* bidir */
   1577                 if (v != NULL) { /* exists */
   1578                     if (cint_type_check(&dst->assign->dt, &v->dt)) {
   1579                         /* compatible - use directly */
   1580                         dst->assign->assign_op = prompt_assign_output_var;
   1581                         rv = API_MODE_E_NONE;
   1582                     } else {
   1583                         _compat_error(src);
   1584                         /* incompatible - error */
   1585                         dst->assign->assign_op = prompt_assign_error;
   1586                         rv = API_MODE_E_FAIL;
   1587                     }
   1588                 } else {
   1589                     /* as a convenience, treat bidir idents as
   1590                        outputs; the input will be whatever the default
   1591                        initializer provides, if it exists. */
   1592                     dst->assign->assign_op = prompt_assign_bidir_var_c;
   1593                     rv = API_MODE_E_NONE;
   1594                 }
   1595             } else { /* out */
   1596                 if (v != NULL) { /* exists */
   1597                     if (cint_type_check(&dst->assign->dt, &v->dt)) {
   1598                         /* compatible - use directly */
   1599                         dst->assign->assign_op = prompt_assign_output_var;
   1600                     } else {
   1601                         /* incompatible - recreate */
   1602                         dst->assign->assign_op = prompt_assign_output_var_r;
   1603                     }
   1604                 } else {
   1605                     /* doesn't exists - create */
   1606                     dst->assign->assign_op = prompt_assign_output_var_c;
   1607                 }
   1608                 rv = API_MODE_E_NONE;
   1609             }
   1610         } else {
   1611             /* error */
   1612             sal_printf("Expected an identifier "
   1613                        "for assignment to an output parameter.\n");
   1614         }
   1615     } else if (dst->assign->c_flags & CINT_PARAM_IN) {
   1616         if (src->token->ident) {
   1617             v = cint_variable_find(name, TRUE);
   1618             /* inputs *may* be identifiers corresponding to variables,
   1619                manifest constants, or enums */
   1620             if (v != NULL) {
   1621                 if (cint_type_check(&dst->assign->dt, &v->dt)) {
   1622                     dst->assign->assign_op = prompt_assign_input_var;
   1623                     rv = API_MODE_E_NONE;
   1624                 } else {
   1625                     _compat_error(src);
   1626                     dst->assign->assign_op = prompt_assign_error;
   1627                     rv = API_MODE_E_FAIL;
   1628                 }
   1629             } else if (cint_datatype_enum_find(name, &dt, NULL)==CINT_E_NONE) {
   1630                 dst->assign->assign_op = prompt_assign_input_var;
   1631                 rv = API_MODE_E_NONE;
   1632             } else if (cint_datatype_find(name, &dt) == CINT_E_NONE) {
   1633                 dst->assign->assign_op = prompt_assign_input_var;
   1634                 rv = API_MODE_E_NONE;
   1635             } else {
   1636                 _ident_error(src);
   1637             }
   1638         } else {
   1639             /* must be assigning a scalar, which is never assigned
   1640                directly to a composite value. */
   1641             while (dst->assign && (dst->assign->p_flags & PA_EXPAND)) {
   1642                 dst->assign = dst->assign->next;
   1643             }
   1644             if (dst->assign) {
   1645                 if (!_assign_special(data, dst->assign, src)) {
   1646                     dst->assign->assign_op = prompt_assign_input_constant;
   1647                     rv = 1; /* value already assigned */
   1648                 } else if (dst->assign->c_flags & CINT_DATATYPE_FLAGS_FUNC) {
   1649                     _unsupported();
   1650                     rv = API_MODE_E_FAIL;
   1651                 } else {
   1652                     dst->assign->assign_op = prompt_assign_input_constant;
   1653                     rv = API_MODE_E_NONE;
   1654                     /* scalar */
   1655                 }
   1656             }
   1657         }
   1658     } else {
   1659         sal_printf("Parameter %s is neither in or out.\n", dst->assign->path);
   1660     }
   1661 
   1662     if (rv == API_MODE_E_NONE) {
   1663         rv = pa_value(dst->assign, src->value);
   1664     }
   1665     
   1666     return rv;
   1667 }
   1668 
   1669 /* display missing key error */
   1670 STATIC void
   1671 _no_key(api_mode_arg_t *arg)
   1672 {
   1673     sal_printf("Could not match key '%s'\n", arg->value);
   1674 }
   1675 
   1676 /* keyword/value assignment */
   1677 STATIC int
   1678 _kw_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src)
   1679 {
   1680     int level;
   1681     int len;
   1682     const char *key;
   1683     int found = 0;
   1684     int rv = API_MODE_E_NONE;
   1685     prompt_arg_t *dict;
   1686     prompt_arg_t *search;
   1687     prompt_arg_t *assign;
   1688     
   1689     dst->context = prompt_ctx_kv;
   1690     key = src->value;
   1691     len = sal_strlen(key);
   1692 
   1693     if ((dst->search->p_flags & PA_EXPAND) && dst->search->next) {
   1694         dst->search = dst->search->next;
   1695     }
   1696 
   1697     level = dst->search->level;
   1698 
   1699     for (dict = dst->search; dict; dict=dict->next) {
   1700         int short_name, long_name;
   1701 
   1702         /* skip anything deeper than our current level */
   1703         if (dict->level > level) {
   1704             continue;
   1705         }
   1706 
   1707         /* stop if anything shallower than our current level */
   1708         if (dict->level < level) {
   1709             break;
   1710         }
   1711 
   1712         long_name  = strncmp(dict->path, key, len);
   1713         short_name = strcmp(dict->desc.name, key);
   1714 
   1715         if (!long_name || !short_name) {
   1716             if (src->kind != KEY_VALUE) {
   1717                 return api_mode_unexpected();
   1718             }
   1719             /* save assign, search point */
   1720             search = dst->search;
   1721             assign = dst->assign;
   1722             dst->search = dict;
   1723             dst->assign = dict;
   1724             rv = _generic_assign(data, dst, src->sub ? src->sub : src);
   1725             /* restore assign, search point */
   1726             dst->search = search;
   1727             dst->assign = assign;
   1728             found = 1;
   1729             break;
   1730         }
   1731     }
   1732 
   1733     if (!found) {
   1734         _no_key(src);
   1735     }
   1736 
   1737     return rv;
   1738 }
   1739 
   1740 /* display no more arguments error */
   1741 STATIC void
   1742 _no_arg(void)
   1743 {
   1744     sal_printf("Ran out of arguments to set\n");
   1745 }
   1746 
   1747 /* positional assignment */
   1748 STATIC int
   1749 _pos_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src)
   1750 {
   1751     int rv = API_MODE_E_FAIL;
   1752 
   1753     if (dst->assign) {
   1754         dst->context = prompt_ctx_pos;
   1755         rv = _value_assign(data, dst, src);
   1756 
   1757         if (API_MODE_SUCCESS(rv)) {
   1758             if ((dst->assign->p_flags & PA_EXPAND) &&
   1759                 dst->assign->assign_op == prompt_assign_input_var) {
   1760                 /* skip over expansion */
   1761                 _advance_expanded(dst);
   1762             } else {
   1763                 dst->assign = dst->assign->next;
   1764             }
   1765             dst->search = dst->assign;
   1766         }
   1767     } else {
   1768         _no_arg();
   1769     }
   1770 
   1771     return rv;
   1772 
   1773 }
   1774 
   1775 /* subvalue prompt assignment */
   1776 STATIC int
   1777 _prompt_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src)
   1778 {
   1779     return API_MODE_E_UNAVAIL;
   1780 }
   1781 
   1782 /* generic assignment based on src */
   1783 STATIC int
   1784 _generic_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src)
   1785 {
   1786     int rv = API_MODE_E_NONE;
   1787     prompt_ctx_t current = dst->context;
   1788 
   1789     switch (src->kind) {
   1790     case AGGREGATE:
   1791         rv = _agg_assign(data, dst, src->sub);
   1792         break;
   1793     case KEY_VALUE:
   1794         {
   1795             prompt_arg_t *search = dst->search; /* save */
   1796             rv = _kw_assign(data, dst, src);
   1797             dst->search = search;               /* restore */
   1798         }
   1799         break;
   1800     case PROMPT:
   1801         rv = _prompt_assign(data, dst, src);
   1802         break;
   1803     default:
   1804         rv = _pos_assign(data, dst, src);
   1805         break;
   1806     }
   1807 
   1808     dst->context = current;
   1809     return rv;
   1810 }
   1811 
   1812 /* aggregate assignment */
   1813 STATIC int
   1814 _agg_assign(api_mode_data_t *data, prompt_t *dst, api_mode_arg_t *src)
   1815 {
   1816     api_mode_arg_t *arg;
   1817     int rv = API_MODE_E_NONE;
   1818 
   1819     for (arg=src; arg; arg=arg->next) {
   1820         rv = _generic_assign(data, dst, arg);
   1821         if (API_MODE_FAILURE(rv)) {
   1822             break;
   1823         }
   1824     }
   1825 
   1826     return rv;
   1827 }
   1828 
   1829 /* variable prompt mode */
   1830 STATIC int
   1831 api_mode_var_prompt(api_mode_data_t *data, const cint_datatype_t *dt)
   1832 {
   1833     _unsupported();
   1834     return API_MODE_E_NONE;
   1835 }
   1836 
   1837 /* function prompt mode */
   1838 STATIC int
   1839 api_mode_func_prompt(api_mode_data_t *data, const cint_datatype_t *dt)
   1840 {
   1841     prompt_t prompt;
   1842     prompt_arg_t *arg;
   1843     int rv;
   1844 
   1845     rv = init_prompt(data, &prompt, NULL, dt);
   1846 
   1847     if (API_MODE_SUCCESS(rv)) {
   1848         /* prompt parameters */
   1849         for (arg=prompt.head; arg; ) {
   1850             if ((arg->p_flags & PA_EXPAND)) {
   1851                 if (arg->next == NULL) {
   1852                     /* Should not happen */
   1853                     return api_mode_unexpected();
   1854                 }
   1855                 arg = arg->next;
   1856             }
   1857             arg = api_mode_prompt_arg(data, arg);
   1858         }
   1859         _api_mode_exec(data, &prompt, dt);
   1860 
   1861         prompt_free(&prompt);
   1862     }
   1863 
   1864     return rv;
   1865 }
   1866 
   1867 /* call an API */
   1868 STATIC int
   1869 api_mode_call(api_mode_data_t *data,
   1870               api_mode_arg_t *arg_in, const cint_datatype_t *dt)
   1871 {
   1872     prompt_t prompt;
   1873     int rv;
   1874 
   1875     rv = init_prompt(data, &prompt, arg_in, dt);
   1876 
   1877     if (API_MODE_SUCCESS(rv)) {
   1878         rv = _agg_assign(data, &prompt, arg_in);
   1879     }
   1880 
   1881     if (API_MODE_SUCCESS(rv)) {
   1882         _api_mode_exec(data, &prompt, dt);
   1883     }
   1884 
   1885     return rv;
   1886 }
   1887 
   1888 /* print a variable */
   1889 STATIC int
   1890 api_mode_print(api_mode_data_t *data, api_mode_arg_t *arg)
   1891 {
   1892     api_mode_arg_t *mbr;
   1893     int rv;
   1894 
   1895     /* Force prints to be in a new scope. */
   1896     
   1897     CINT_STRCAT(data->program, "{\n");
   1898     while (arg) {
   1899         CINT_STRCAT(data->program, "print ");
   1900         CINT_STRCAT(data->program, arg->value);
   1901         for (mbr=arg->sub; mbr; mbr=mbr->next) {
   1902             CINT_STRCAT(data->program, ".");
   1903             CINT_STRCAT(data->program, mbr->value);
   1904         }
   1905         CINT_STRCAT(data->program, ";\n");
   1906         arg = api_mode_arg_next(arg);
   1907     }
   1908     CINT_STRCAT(data->program, "}\n");
   1909     rv = cmd_api_run(data);
   1910 
   1911     return rv;
   1912 }
   1913 
   1914 /* set a variable */
   1915 STATIC int
   1916 api_mode_var(api_mode_data_t *data, api_mode_arg_t *arg)
   1917 {
   1918     api_mode_arg_t *mbr;
   1919     int rv;
   1920 
   1921     while (arg) {
   1922         CINT_STRCAT(data->program, arg->value);
   1923         for (mbr=arg->sub; mbr; mbr=mbr->next) {
   1924             CINT_STRCAT(data->program, ".");
   1925             CINT_STRCAT(data->program, mbr->value);
   1926         }
   1927         if (arg->next) {
   1928             CINT_STRCAT(data->program, "=");
   1929         }
   1930         arg = api_mode_arg_next(arg);
   1931     }
   1932     CINT_STRCAT(data->program, ";\n");
   1933     rv = cmd_api_run(data);
   1934 
   1935     return rv;
   1936 }
   1937 
   1938 /* create a variable */
   1939 STATIC int
   1940 api_mode_create(api_mode_data_t *data, api_mode_arg_t *arg)
   1941 {
   1942     int rv = API_MODE_E_FAIL;
   1943     prompt_arg_t pa; /* just need desc and value */
   1944 
   1945     sal_memset(&pa, 0, sizeof(pa));
   1946     if (arg) {
   1947         pa.path = arg->value;
   1948         rv = cint_datatype_find(pa.path, &pa.dt);
   1949         if (rv == CINT_E_NONE) {
   1950             arg = arg->next;
   1951             pa.desc = pa.dt.desc;
   1952             pa.desc.pcount++;
   1953             if (arg == NULL) {
   1954                 sal_printf("Missing variable name\n");
   1955                 rv = API_MODE_E_PARAM;
   1956             }
   1957         } else {
   1958             sal_printf("Could not find type '%s'\n", pa.path);
   1959         }
   1960     }
   1961             
   1962     if (API_MODE_SUCCESS(rv)) {
   1963         while (arg) {
   1964             pa.value = arg->value;
   1965             CINT_STRCAT(data->program, pa.path);
   1966             CINT_STRCAT(data->program, " ");
   1967             CINT_STRCAT(data->program, pa.value);
   1968             CINT_STRCAT(data->program, ";\n");
   1969             rv = _init_var(data, &pa);
   1970             if (API_MODE_FAILURE(rv)) {
   1971                 break;
   1972             }
   1973             arg = arg->next;
   1974         }
   1975     }
   1976 
   1977     if (API_MODE_SUCCESS(rv)) {
   1978         rv = cmd_api_run(data);
   1979     }
   1980 
   1981     return rv;
   1982 }
   1983 
   1984 /* handle an API mode command */
   1985 STATIC int
   1986 handle_command(api_mode_data_t *data, api_mode_arg_t *cmd)
   1987 {
   1988     int rv;
   1989     const cint_datatype_t *dt;
   1990     api_mode_arg_t *arg;
   1991     int op;
   1992 
   1993     dt = NULL;
   1994     arg = NULL;
   1995     rv = match_command(cmd, &arg, &dt, &op);
   1996     if (API_MODE_SUCCESS(rv)) {
   1997         switch (op) {
   1998         case OP_FPROMPT:
   1999             rv = api_mode_func_prompt(data, dt);
   2000             break;
   2001         case OP_VPROMPT:
   2002             rv = api_mode_var_prompt(data, dt);
   2003             break;
   2004         case OP_HELP:
   2005             rv = api_mode_help(dt);
   2006             break;
   2007         case OP_PRINT:
   2008             rv = api_mode_print(data, arg->next);
   2009             break;
   2010         case OP_VAR:
   2011             rv = api_mode_var(data, arg->next);
   2012             break;
   2013         case OP_CREATE:
   2014             rv = api_mode_create(data, arg->next);
   2015             break;
   2016         case OP_KWARG:
   2017         default:
   2018             rv = api_mode_call(data, arg, dt);
   2019             break;
   2020         }
   2021     } else if (op == OP_HELP) {
   2022         rv = api_mode_partial_help(cmd);
   2023     }
   2024     return rv;
   2025 }
   2026 
   2027 /* execute an API mode command */
   2028 STATIC int
   2029 exec_command(api_mode_arg_t *cmd, void *user_data)
   2030 {
   2031     api_mode_data_t *data = (api_mode_data_t *)user_data;
   2032     int rv = API_MODE_E_NONE;
   2033     int debug = 0;
   2034 
   2035     if (cmd->kind != EMPTY) {
   2036         if (cmd->kind == INFO) {
   2037             cmd = cmd->next;
   2038             debug = 1;
   2039         }
   2040         if (cmd) {
   2041             int old_debug = 0;
   2042             if (debug) {
   2043                 old_debug = data->debug;
   2044                 data->debug = !data->debug;
   2045             }
   2046 
   2047             rv = handle_command(data, cmd);
   2048 
   2049             if (debug) {
   2050                 data->debug = old_debug;
   2051             }
   2052         } else if (debug) {
   2053             data->debug = !data->debug;
   2054             sal_printf("API mode debug is %s\n", data->debug?"on":"off");
   2055         }
   2056     }
   2057 
   2058     /* if rv indicates an error, then the original command string will
   2059        be passed to the subsequent shell, so 'error' really means "the
   2060        string means nothing to me". All other errors should return
   2061        API_MODE_E_NONE so the string stays within the API mode realm.
   2062     */
   2063 #if 0
   2064     data->rv = ((rv == API_MODE_E_FAIL) ? API_MODE_E_NONE : rv);
   2065 #else
   2066     data->rv = ((rv == API_MODE_E_NOT_FOUND) ? rv : API_MODE_E_NONE);
   2067 #endif
   2068     return rv;
   2069 }
   2070 
   2071 #define SIZE (API_MODE_STAGE_SIZE+API_MODE_PROMPT_SIZE+API_MODE_PROGRAM_SIZE)
   2072 
   2073 STATIC api_mode_data_t api_data;
   2074 
   2075 /* process an API mode command from the CLI */
   2076 int
   2077 api_mode_process_command(int u, char *s)
   2078 {
   2079     int rv;
   2080 
   2081     api_data.unit = u;
   2082     if (!api_data.stage) {
   2083         api_data.stage = sal_alloc(SIZE, "apimode");
   2084         if (!api_data.stage) {
   2085             return CMD_FAIL;
   2086         }
   2087         api_data.prompt = api_data.stage + API_MODE_STAGE_SIZE;
   2088         api_data.program = api_data.prompt + API_MODE_PROMPT_SIZE;
   2089     }
   2090     sal_memset(api_data.stage, 0, SIZE);
   2091     rv = api_mode_parse_string(s, PARSE_VERBOSE, exec_command, &api_data);
   2092     if (API_MODE_SUCCESS(rv)) {
   2093         rv = api_data.rv;
   2094     }
   2095     return rv;
   2096 }