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

context.c (26682B)


      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:        context.c
      8  * Purpose:     Determine ident/value context
      9  */
     10 
     11 #include "context.h"
     12 #include "tokenizer.h"
     13 #include "api_mode.h"
     14 #include "api_mode_yy.h"
     15 #include "api_grammar.tab.h"
     16 #include "shared/util.h"
     17 #include "sal/appl/sal.h"
     18 #include "cint_interpreter.h"
     19 
     20 typedef struct api_cint_db_s {
     21     api_mode_cint_dt_db_t func; /* CINT function database */
     22     api_mode_cint_dt_db_t tdef; /* CINT typedef database */
     23     api_mode_cint_var_db_t var; /* CINT global variables */
     24     int dt_changed;             /* CINT datatypes changed */
     25     int var_changed;            /* CINT global variables changed */
     26     const char *prefix;         /* API prefix */
     27     const char *prefix_u;       /* API prefix in uppercase */
     28     int prefix_len;             /* API prefix length */
     29 } api_cint_db_t;
     30 
     31 STATIC api_cint_db_t api_cint;
     32 
     33 STATIC api_mode_private_t api_mode_private[] = {
     34     { "print",   PRINT,  api_mode_context_qual_print},
     35     { "create",  CREATE, api_mode_context_qual_create},
     36     { "var",     VAR,    api_mode_context_qual_variable}
     37 };
     38 
     39 #define PRIVATE_CMD(idx) { api_mode_private[idx].name, api_mode_private+idx }
     40 
     41 STATIC api_mode_cint_dt_db_entry_t api_mode_command[COUNTOF(api_mode_private)];
     42 
     43 STATIC void
     44 _api_mode_init_private(void)
     45 {
     46     int i;
     47 
     48     for (i=0; i<COUNTOF(api_mode_private); i++) {
     49         sal_memset(api_mode_command + i, 0, sizeof(api_mode_command[0]));
     50         api_mode_command[i].name = api_mode_private[i].name;
     51         api_mode_command[i].private = api_mode_private + i;
     52     }
     53 }
     54 
     55 /*
     56   Try to match identifier arguments in arg to a CINT function. Return
     57   TRUE if there is a match. 'out' is set to the first non-identfier
     58   argument from 'in', and 'dt' is the CINT function datatype.
     59 
     60   'buffer' contains the matched function name.
     61 
     62   If help, prompt-assignment, or keyword/value arguments, then only the
     63   identifiers are matched.  If positional arguments, then the arity must
     64   either match or be one greater if the first argument name is "unit".
     65 
     66  */
     67 
     68 
     69 
     70 #define OP_PROMPT      1
     71 #define OP_HELP        2
     72 #define OP_KWARG       3
     73 
     74 STATIC int
     75 _pfn(void *item, void *target)
     76 {
     77     const api_mode_cint_dt_db_entry_t *entry = item;
     78     api_mode_context_t *ctx = target;
     79     int match = sal_strcmp(entry->name, ctx->match);
     80 
     81     return match;
     82 }
     83 
     84 
     85 /* join IDENT args from 'tokens' separated by 'c' into ctx->join
     86 
     87    return API_MODE_E_NONE if successful, error if failed
     88 */
     89 STATIC int
     90 join_args(api_mode_context_t *ctx, api_mode_tokens_t *tokens, char c)
     91 {
     92     int i, n, join, rv, len;
     93     char *s;
     94     const char *t;
     95 
     96     s = ctx->join;
     97     len = ctx->jlen;
     98     rv = API_MODE_E_NONE;
     99 
    100     /* sanity check */
    101     if (tokens->len != ctx->len) {
    102         sal_printf("join_args: token/context mismatchn\n");
    103         return API_MODE_E_FAIL;
    104     }
    105 
    106     for (i=0; i<tokens->len; i++) {
    107         if (i == 0 && ctx->info[i].grammar_type == INFO) {
    108             /* INFO */
    109             continue;
    110         }
    111         
    112         if (ctx->info[i].grammar_type != IDENT) {
    113             break;
    114         }
    115 
    116         t = tokens->token[i].str;
    117         n = sal_strlen(t);
    118         if (n < (len+2)) { /* one for joining, one for end-sf-string */
    119             sal_strcpy(s, t);
    120             s += n;
    121             len -= n;
    122             /* join if this is not the last token and the token
    123                following is an IDENT */
    124             join = i < ((tokens->len)-1) &&
    125                 ctx->info[i+1].grammar_type == IDENT;
    126 
    127             if (join) {
    128                 *s++ = c;
    129                 len -= 1;
    130             }
    131         } else {
    132             /* out of room */
    133             rv = API_MODE_E_FAIL;
    134             break;
    135         }
    136     }
    137     *s = 0;
    138 
    139     return rv;
    140 }
    141 
    142 /* Join tokens and search for var
    143 
    144    returns
    145               -error: some error
    146      API_MODE_E_NONE: match found
    147                    1: no match
    148    
    149 */
    150 STATIC int
    151 _match_var_ctx(api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    152 {
    153     return API_MODE_E_NONE; /* STUB */
    154 }
    155 
    156 
    157 /* Join tokens and search for var
    158 
    159    returns
    160               -error: some error
    161      API_MODE_E_NONE: match found
    162                    1: no match
    163    
    164 */
    165 STATIC int
    166 _match_create_ctx(api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    167 {
    168     
    169     if (tokens->len == 3 && ctx->info[2].grammar_type == IDENT) {
    170         ctx->info[2].grammar_type = KEY;
    171     }
    172     return API_MODE_E_NONE; /* STUB */
    173 }
    174 
    175 
    176 
    177 /* Search for a matching function based on ctx
    178 
    179    returns
    180               -error: some error
    181      API_MODE_E_NONE: match found
    182                    1: no match
    183    
    184 */
    185 
    186 /* reverse search horizon. Should be larger then the number of APIs that
    187    are strict substrings of each following API. */
    188 
    189 #define HORIZON 20
    190 
    191 STATIC int
    192 _search_func_ctx(api_mode_context_t *ctx)
    193 {
    194     int idx, rv;
    195     const char *name;
    196 
    197     rv = API_MODE_E_FAIL;
    198     idx = _shr_bsearch(api_cint.func.entry,
    199                        api_cint.func.count,
    200                        sizeof(*api_cint.func.entry),
    201                        ctx,
    202                        _pfn);
    203 
    204     if (idx < 0) {
    205         /* inexact match; see if the match buffer refers to the given
    206            index (if match buffer is shorter or equal) or the next
    207            index (if the match buffer is longer) */
    208 
    209         idx = -idx - 1;
    210         if (idx < api_cint.func.count) {
    211             name = api_cint.func.entry[idx].name;
    212             if (!strncmp(ctx->match, name, sal_strlen(name))) {
    213                 ctx->exact = 1;
    214             } else {
    215                 ctx->partial = !strncmp(ctx->match, name,
    216                                         sal_strlen(ctx->match));
    217             }
    218             rv = API_MODE_E_NONE;
    219         } else {
    220             rv = 1;
    221         }
    222     } else {
    223         ctx->exact = 1;
    224         rv = API_MODE_E_NONE;
    225     }
    226 
    227     if (rv == API_MODE_E_NONE) {
    228         int i;
    229 
    230         if (!ctx->partial && !ctx->exact) {
    231             /*
    232               'Over Matching' an API with identifiers as arguments
    233 
    234               There are five cases that can occur:
    235 
    236               (1) The function being matched is not a substring of a
    237                   subsequent function. The match index will point to the
    238                   function *following* the one corresponding to the
    239                   (ultimately) desired function.
    240 
    241                   Example: field qset t init qset
    242                            ----- ---- - ----
    243 
    244                   Match text:
    245                     field_qset_t_init_qset
    246 
    247                   Matches (*):
    248                     bcm_field_qset_t_init       [5/5]
    249 
    250               (2) The function being matched is a substring of a
    251                   subsequent function, and the desired function
    252                   concatenated with the identifier argument(s) sorts
    253                   *before* subsequent function.
    254 
    255                   Example: mpls info foo bar
    256                            ---- ----
    257 
    258                   Match text:
    259                     bcm_mpls_info_foo_bar
    260 
    261                   Matches (*):
    262                     bcm_mpls_info               [3/3]
    263                     bcm_mpls_info_t_init *      [3/5]
    264                     bcm_mpls_init               [2/3]
    265 
    266               (3) The function being matched is a substring of a
    267                   subsequent function, and the desired function
    268                   concatenated with the identifier argument(s) matches
    269                   exactly.
    270 
    271                   Example: mpls info t init
    272                            ---- ----
    273                   Match text:
    274                     bcm_mpls_info_t_init
    275 
    276                   Matches (*):
    277                     bcm_mpls_info               [3/3]
    278                     bcm_mpls_info_t_init *      [5/5]
    279                     bcm_mpls_init               [2/3]
    280 
    281               (4) The function being matched is a substring of a
    282                   subsequent function, and the desired function
    283                   concatenated with the identifier argument(s)
    284                   overmatches:
    285               
    286                   Example: mpls info test output
    287                            ---- ----
    288               
    289                   Match text:
    290                     bcm_mpls_info_test_output
    291 
    292                   Matches (*):
    293                     bcm_mpls_info               [3/3]
    294                     bcm_mpls_info_t_init        [3/5]
    295                     bcm_mpls_init *             [2/3]
    296 
    297               (5) The function being matched is a substring of a
    298                   subsequent function, and the desired function
    299                   concatenated with the identifier argument(s) sorts
    300                   after:
    301   
    302                   Example: mpls info zzz yyy
    303                            ---- ----
    304               
    305                   Match text:
    306                     bcm_mpls_info_zzz_yyy
    307 
    308                   Matches (*):
    309                     bcm_mpls_info               [3/3]
    310                     bcm_mpls_info_t_init        [3/5]
    311                     bcm_mpls_init *             [2/3]
    312               
    313             If the match is against the immediately following
    314             function, then the string being matched is longer, and a
    315             superset of the functions, i.e., it has arguments to the
    316             function.
    317 
    318             This means that an inexact match will overshoot the target
    319             by at least two entries. However, as in example (5) above,
    320             if the target is the shortest string of a sequence of
    321             larger strings, then the distance to search backwards
    322             increases by the number of 'superstrings', which is a
    323             property of API naming. For example:
    324 
    325               field group create qset
    326               
    327             initially matches against field_group_destroy, so the
    328             reverse search horizon is 4.
    329             
    330                field_group_create *
    331                field_group_create_id
    332                field_group_create_mode
    333                field_group_create_mode_id
    334                field_group_destroy
    335 
    336 
    337             */
    338             for (i=0; i < HORIZON && idx > 1; i++) {
    339                 idx--;
    340                 name = api_cint.func.entry[idx].name;
    341                 ctx->more = !strncmp(ctx->match, name, sal_strlen(name));
    342                 if (ctx->more) {
    343                     rv = 1; /* try again to reduce the overmatch */
    344                     break;
    345                 }
    346             }
    347         }
    348         ctx->dt0 = api_cint.func.entry + idx;
    349         ctx->idx = idx;
    350 
    351     }
    352 
    353     return rv;
    354 }
    355 
    356 /* Join tokens and search for function
    357 
    358    returns
    359               -error: some error
    360      API_MODE_E_NONE: match found
    361                    1: no match
    362    
    363 */
    364 STATIC int
    365 _match_func_ctx(api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    366 {
    367     int rv;
    368 
    369     rv = join_args(ctx, tokens, '_');
    370     if (API_MODE_SUCCESS(rv)) {
    371         rv = _search_func_ctx(ctx);
    372     }
    373 
    374     if (rv == API_MODE_E_NONE && ctx->exact && ctx->dt0->private != NULL) {
    375         /* private command handled by grammar */
    376         ctx->info[0].grammar_type = ctx->dt0->private->grammar_type;
    377         ctx->qual = ctx->dt0->private->qual;
    378     }
    379 
    380     return rv;
    381 }
    382 
    383 /* Initialize search context.
    384 
    385    returns
    386               -error: some error
    387      API_MODE_E_NONE: match found
    388                    1: no match
    389    
    390 */
    391 STATIC int
    392 _search_ctx(api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    393 {
    394     int rv = API_MODE_E_FAIL;
    395 
    396     /* match based on context */
    397     switch (ctx->qual) {
    398     case api_mode_context_qual_variable:
    399     case api_mode_context_qual_print:
    400         rv = _match_var_ctx(tokens, ctx);
    401         break;
    402     case api_mode_context_qual_create:
    403         rv = _match_create_ctx(tokens, ctx);
    404         break;
    405     case api_mode_context_qual_unknown:
    406     case api_mode_context_qual_function:
    407         rv = _match_func_ctx(tokens, ctx);
    408         break;
    409     default:
    410         break;
    411     }
    412 
    413     if ((rv == API_MODE_E_NONE) && (!ctx->more || ctx->exact)) {
    414         if (ctx->len > 0 && ctx->dt0 != NULL && ctx->exact) {
    415             /* info structs are passed through to grammar; the first
    416                grammar token will carry the CINT datatype for the entire
    417                function. */
    418             ctx->info[0].dt = &ctx->dt0->dt;
    419         }
    420     } else if (rv > 0) {
    421         if (ctx->qual == api_mode_context_qual_function &&
    422             ctx->num_ident > 0 && ctx->more) {
    423             /* No match and there are arguments, so mark the last
    424                ident token as VALUE and try again. */
    425             
    426             ctx->info[ctx->num_ident-1].grammar_type = VALUE;
    427         }
    428     }
    429     return rv ;
    430 }
    431 
    432 
    433 
    434 
    435 
    436 STATIC int
    437 _ctx_value(int idx, api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    438 {
    439     /* VALUE+ident nodes only count towards command matching up to the
    440        first non-identifer, after which they count towards
    441        arguments. */
    442     if (tokens->token[idx].ident) {
    443         if (ctx->num_arg == 0) {
    444             ctx->info[idx].grammar_type = IDENT;
    445             ctx->num_ident++;
    446         } else {
    447             ctx->info[idx].grammar_type = VALUE;
    448             ctx->num_arg++;
    449         }
    450     } else {
    451         ctx->info[idx].grammar_type = CONSTANT;
    452         ctx->num_arg++;
    453     }
    454 
    455     return API_MODE_E_NONE;
    456 }
    457 
    458 STATIC int
    459 _ctx_equal(int idx, api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    460 {
    461     /* There is a potential shift/reduce conflict in the grammar when
    462        an '=' character is the last token in a sequence (used for
    463        prompt assignment). Explicitly make the last '=' as a PROMPT
    464        token to help disambiguate.
    465     */
    466     if (idx == tokens->len-1) {
    467         ctx->info[idx].grammar_type = PROMPT;
    468     } else {
    469         ctx->info[idx].grammar_type = tokens->token[idx].str[0];
    470         if (ctx->qual == api_mode_context_qual_function &&
    471             ctx->num_ident > 1 && idx > 0) {
    472             /* For function grammar, the token before '=' is key */
    473             if (ctx->num_arg == 0) {
    474                 /* this is the first argument */
    475                 ctx->num_arg++;
    476                 ctx->num_ident--;
    477             }
    478             /* The token before '=' is a key */
    479             ctx->info[idx-1].grammar_type = KEY;
    480         }
    481     }
    482 
    483     return API_MODE_E_NONE;
    484 }
    485 
    486 STATIC int
    487 _ctx_comma(int idx, api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    488 {
    489     /* tokens surrounding comma are values */
    490     if (ctx->num_arg > 1 &&
    491         idx > 1 &&
    492         idx < tokens->len &&
    493         tokens->token[idx-1].token_type == API_MODE_TOKEN_TYPE_VALUE &&
    494         tokens->token[idx+1].token_type == API_MODE_TOKEN_TYPE_VALUE) {
    495         ctx->info[idx-1].grammar_type = ITEM;
    496         ctx->info[idx].grammar_type = tokens->token[idx].str[0];
    497         ctx->info[idx+1].grammar_type = ITEM;
    498     }
    499     return API_MODE_E_NONE;
    500 }
    501 
    502 STATIC int
    503 _ctx_separator(int idx, api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    504 {
    505     int info = 0;
    506 
    507     if (tokens->token[idx].str[0] == '=') {
    508         _ctx_equal(idx, tokens, ctx);
    509     } else if (tokens->token[idx].str[0] == ',') {
    510         _ctx_comma(idx, tokens, ctx);
    511     } else {
    512         /* all other separators stand as themselves */
    513         ctx->info[idx].grammar_type = tokens->token[idx].str[0];
    514         if (idx == 0 && tokens->token[idx].str[0] == INFO) {
    515             info = 1;
    516         }
    517     }
    518 
    519     if (tokens->token[idx].str[0] == '.') {
    520         ctx->num_ident++;
    521     } else if (!info) {
    522         ctx->num_arg++;
    523     }
    524 
    525     return API_MODE_E_NONE;
    526 }
    527     
    528 STATIC int
    529 _ctx_quote(int idx, api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    530 {
    531     ctx->info[idx].grammar_type = CONSTANT;
    532     ctx->num_arg++;
    533 
    534     return API_MODE_E_NONE;
    535 }
    536 
    537 STATIC void
    538 _api_mode_check(void)
    539 {
    540 #if 0
    541     int i;
    542     const char *p, *q;
    543 
    544     for (i=0; i<api_cint.func.count-1; i++) {
    545         p = api_cint.func.entry[i].dt.desc.basetype;
    546         q = api_cint.func.entry[i+1].dt.desc.basetype;
    547         if (p != NULL && q != NULL && !strncmp(p, q, sal_strlen(p))) {
    548             sal_printf("%s substring of %s\n", p, q);
    549         }
    550     }
    551     for (i=0; i<api_cint.func.count; i++) {
    552         p = api_cint.func.entry[i].dt.desc.basetype;
    553         if (p != NULL) {
    554             sal_printf("::: %s\n", p);
    555         }
    556     }
    557 #endif
    558 }
    559 
    560 STATIC int
    561 _api_mode_local(api_mode_cint_dt_db_t *db)
    562 {
    563     int i;
    564 
    565     for (i=0; i<COUNTOF(api_mode_command); i++) {
    566         sal_memcpy((void *)(db->entry + db->idx),
    567                    api_mode_command + i,
    568                    sizeof(*api_mode_command));
    569         db->idx++;
    570     }
    571 
    572     return i;
    573 }
    574 
    575 STATIC const char *
    576 _api_mode_dt_name(const cint_datatype_t *dt)
    577 {
    578     const char *name;
    579 
    580     if ((dt->flags & CINT_DATATYPE_F_CONSTANT) != 0) {
    581         name = dt->basetype.cp->name;
    582     } else if ((dt->flags & CINT_DATATYPE_F_TYPEDEF) != 0) {
    583         name = dt->desc.name;
    584     } else {
    585         name = dt->desc.basetype;
    586     }
    587 
    588     return name;
    589 }
    590 
    591 STATIC int
    592 _api_mode_cmp_dt(void *a, void *b)
    593 {
    594     const api_mode_cint_dt_db_entry_t *ea, *eb;
    595     int cmp;
    596 
    597     ea = (const api_mode_cint_dt_db_entry_t *)a;
    598     eb = (const api_mode_cint_dt_db_entry_t *)b;
    599 
    600     cmp = sal_strcmp(ea->name, eb->name);
    601 
    602     if (cmp == 0) {
    603         int pa, pb;
    604 
    605         pa = ea->name != _api_mode_dt_name(&ea->dt);
    606         pb = eb->name != _api_mode_dt_name(&eb->dt);
    607 
    608         /* sort full function names before aliases */
    609         cmp = (pa - pb);
    610 
    611         if (cmp == 0) {
    612             cmp = ea->dt.flags - eb->dt.flags;
    613 
    614             if (cmp == 0 && (ea->dt.flags & CINT_DATATYPE_F_TYPEDEF) != 0) {
    615                 
    616                 cmp = sal_strcmp(ea->dt.desc.basetype,
    617                                  eb->dt.desc.basetype);
    618             }
    619         }
    620     }
    621 
    622     return cmp;
    623 }
    624 
    625 /* return TRUE if function is eligible for API mode matching */
    626 STATIC int
    627 _api_mode_eligible_func(const cint_datatype_t* dt)
    628 {
    629     cint_parameter_desc_t *desc = dt->basetype.fp->params;
    630 
    631     /* must have some parameters */
    632     if (desc == NULL) {
    633         return FALSE;
    634     }
    635 
    636     /* must have a return type specified */
    637     if (desc->basetype == NULL) {
    638         return FALSE;
    639     }
    640 
    641     for (desc++; desc->basetype != NULL; desc++) {
    642     /* The flags parameters for all arguments be non-zero.  This is
    643        the case for PAPI generated interfaces, but not necessarily the
    644        case for hand generated interfaces, or interfaces generated by
    645        other tools. */
    646         if (desc->flags == 0) {
    647             return FALSE;
    648         }
    649     }
    650     return TRUE;
    651 }
    652 
    653 /* Add eligible CINT functions to internal database */
    654 STATIC int
    655 _api_mode_scan_dt(void* cookie, const cint_datatype_t* dt)
    656 {
    657     api_mode_cint_dt_db_t *db = cookie;
    658 
    659     
    660     if (db == NULL) {
    661         return api_mode_unexpected();
    662     }
    663 
    664     if (_api_mode_eligible_func(dt)) {
    665         if (db->idx >= db->count) {
    666             return api_mode_unexpected();
    667         }
    668         
    669         sal_memcpy((void *)&db->entry[db->idx].dt, dt, sizeof(*dt));
    670         db->entry[db->idx].name = _api_mode_dt_name(dt);
    671         db->entry[db->idx].private = NULL;
    672         db->idx++;
    673     }
    674 
    675     return API_MODE_E_NONE;
    676 }
    677 
    678 /* Add CINT functions matching prefix to internal database with
    679    prefix stripped off. */
    680 STATIC int
    681 _api_mode_scan_at(void* cookie, const cint_datatype_t* dt)
    682 {
    683     api_mode_cint_dt_db_t *db = cookie;
    684     const char *name;
    685     int t1;
    686     int t2;
    687 
    688     if (db == NULL) {
    689         return api_mode_unexpected();
    690     }
    691 
    692     if (_api_mode_eligible_func(dt)) {
    693 
    694         if (db->idx <  db->count) {
    695             return api_mode_unexpected();
    696         }
    697 
    698         if (db->idx >= (db->count*2)) {
    699             return api_mode_unexpected();
    700         }
    701 
    702         name = _api_mode_dt_name(dt);
    703 
    704         if (api_cint.prefix_len > 0) {
    705             t1 = !strncmp(name, api_cint.prefix,   api_cint.prefix_len);
    706             t2 = !strncmp(name, api_cint.prefix_u, api_cint.prefix_len);
    707         } else {
    708             t1 = 1;
    709             t2 = 0;
    710         }
    711 
    712         if (t2) {
    713             const char *p;
    714             /* Check to see if there are any lower case letters */
    715             for (p=name; *p; p++) {
    716                 if (*p >= 'a' && *p <= 'z') {
    717                     sal_printf("@@@ mixed case: %s\n", name);
    718                     break;
    719                 }
    720             }
    721         }
    722         if (sal_strlen(name) > api_cint.prefix_len && (t1 || t2)) {
    723             sal_memcpy((void *)&db->entry[db->idx].dt, dt,
    724                        sizeof(*dt));
    725             db->entry[db->idx].name =
    726                 dt->desc.basetype + api_cint.prefix_len;
    727             db->entry[db->idx].private = NULL;
    728             db->idx++;
    729         }
    730     }
    731 
    732     return API_MODE_E_NONE;
    733 }
    734 
    735 STATIC int
    736 _api_mode_count_dt(void* cookie, const cint_datatype_t* dt)
    737 {
    738     api_cint_db_t *db = cookie;
    739 
    740     /* only count eligible functions */
    741     if (_api_mode_eligible_func(dt)) {
    742         db->func.count++;
    743     }
    744 
    745     return API_MODE_E_NONE;
    746 }
    747 
    748 STATIC int
    749 _api_mode_function_update(void)
    750 {
    751     int rv;
    752     int flags = CINT_DATATYPE_FLAGS_FUNC;
    753     int n;
    754 
    755     /* Build function list */
    756     api_cint.func.count = 0;
    757     api_cint.func.idx = 0;
    758     rv = cint_datatype_traverse(flags, _api_mode_count_dt, &api_cint);
    759     if (rv == CINT_E_NONE && api_cint.func.count > 0) {
    760         /* double allocation for worst case aliases, plus some local cmds */
    761         n  = api_cint.func.count * 2;
    762         n += COUNTOF(api_mode_command);
    763         if (n > api_cint.func.alloc) {
    764             if (api_cint.func.entry) {
    765                 sal_free(api_cint.func.entry);
    766             }
    767             api_cint.func.entry =
    768                 sal_alloc(n * sizeof(*api_cint.func.entry), "apimode");
    769             if (api_cint.func.entry == NULL) {
    770                 api_cint.func.alloc = 0;
    771                 return API_MODE_E_MEMORY;
    772             }
    773             api_cint.func.alloc = n;
    774         }
    775         rv = cint_datatype_traverse(flags, _api_mode_scan_dt, &api_cint);
    776         if (rv == CINT_E_NONE) {
    777             rv = cint_datatype_traverse(flags, _api_mode_scan_at, &api_cint);
    778         }
    779         if (rv == CINT_E_NONE) {
    780             /* update actual count */
    781             api_cint.func.count = api_cint.func.idx;
    782 
    783             /* add local commands */
    784             api_cint.func.count += _api_mode_local(&api_cint.func);
    785 
    786             _shr_sort(api_cint.func.entry, api_cint.func.count,
    787                       sizeof(*api_cint.func.entry), _api_mode_cmp_dt);
    788         }
    789     }
    790 
    791     return rv;
    792 }
    793 
    794 /* Determine command context
    795 
    796    returns
    797               -error: some error
    798      API_MODE_E_NONE: match found
    799                    1: no match
    800    
    801 */
    802 int
    803 api_mode_contextualizer(api_mode_tokens_t *tokens, api_mode_context_t *ctx)
    804 {
    805     int i;
    806     int rv;
    807     int ctx_len, alloc_len;
    808 
    809     rv = API_MODE_E_FAIL;
    810 
    811     /* update CINT info if changed */
    812     if (api_cint.dt_changed != 0) {
    813         rv = _api_mode_function_update();
    814         if (API_MODE_FAILURE(rv)) {
    815             return rv;
    816         }
    817         api_cint.dt_changed = 0;
    818     }
    819     sal_memset(ctx, 0, sizeof(*ctx));
    820 
    821     ctx->jlen = CONTEXT_MAX_BUFFER;
    822 
    823     ctx_len = tokens->len * sizeof(ctx->info[0]);
    824     alloc_len = ctx_len;
    825     alloc_len += CONTEXT_MAX_PFX;
    826     alloc_len += CONTEXT_MAX_BUFFER;
    827     ctx->alloc = sal_alloc(alloc_len, "api_mode_contextualizer");
    828 
    829     if (ctx->alloc == NULL) {
    830         return API_MODE_E_MEMORY;
    831     }
    832 
    833     sal_memset(ctx->alloc, 0, alloc_len);
    834     ctx->qual = api_mode_context_qual_unknown;
    835     ctx->info = (void *)ctx->alloc;
    836     ctx->len = tokens->len;
    837     ctx->match = ctx->alloc + ctx_len;
    838     ctx->join = ctx->match;
    839     ctx->db = &api_cint.func;
    840     ctx->mlen = alloc_len - ctx_len - 1;
    841 
    842     /* determine grammar qualification if needed */
    843     if (tokens->len > 0 && tokens->token[0].ident) {
    844         const char *token0 = tokens->token[0].str;
    845 
    846         /* assume function */
    847         ctx->qual = api_mode_context_qual_function;
    848         /* There's at least one token ident */
    849         for (i=0; i<COUNTOF(api_mode_private); i++) {
    850             if (!sal_strcmp(token0, api_mode_private[i].name)) {
    851                 ctx->qual = api_mode_private[i].qual;
    852                 ctx->info[0].grammar_type =
    853                     api_mode_private[i].grammar_type;
    854                 break;
    855             }
    856         }
    857     }
    858 
    859     /* set grammar types based on token types and token context */
    860     for (i=0; i<tokens->len; i++) {
    861         /* if grammar_type is already set, don't set it again */
    862         if (ctx->info[i].grammar_type != 0) {
    863             continue;
    864         }
    865         switch (tokens->token[i].token_type) {
    866         case API_MODE_TOKEN_TYPE_VALUE:
    867             _ctx_value(i, tokens, ctx); 
    868             break;
    869         case API_MODE_TOKEN_TYPE_QUOTE:
    870             _ctx_quote(i, tokens, ctx); 
    871             break;
    872         case API_MODE_TOKEN_TYPE_SEPARATOR:
    873             _ctx_separator(i, tokens, ctx); 
    874             break;
    875         case API_MODE_TOKEN_TYPE_COMMENT:
    876             /* skip */
    877             break;
    878         case API_MODE_TOKEN_TYPE_ERROR:
    879         default:
    880             /* game over! */
    881             return API_MODE_E_FAIL;
    882         }
    883     }
    884 
    885     /* Now see if there is a matching function. Allow the "no
    886        identifiers" case so this will work correctly on empty inputs
    887        with a default prefix.
    888     */
    889     for (; ctx->num_ident>=0; ctx->num_ident--, ctx->num_arg++) {
    890         if ((rv=_search_ctx(tokens, ctx)) <= 0) {
    891             break;
    892         }
    893     }
    894 
    895     return rv;
    896 }
    897 
    898 int
    899 api_mode_contextualizer_free(api_mode_context_t *ctx)
    900 {
    901     if (ctx->alloc != NULL) {
    902         sal_free(ctx->alloc);
    903     }
    904     ctx->alloc = NULL;
    905 
    906     return API_MODE_E_NONE;
    907 }
    908 
    909 STATIC int
    910 _api_mode_cint_event(void* cookie, cint_interpreter_event_t event)
    911 {
    912     api_cint_db_t *db = (api_cint_db_t *)cookie;
    913 
    914     switch (event) {
    915     case cintEventReset:
    916         db->dt_changed = 1;
    917         db->var_changed = 1;
    918         break;
    919     case cintEventDatatypeAdded:
    920         db->dt_changed = 1;
    921         break;
    922     case cintEventGlobalVariableAdded:
    923         db->var_changed = 1;
    924         break;
    925     default:
    926         /* ignore */
    927         break;
    928     }
    929 
    930     return API_MODE_E_NONE;
    931 }
    932 
    933 int
    934 api_mode_context_initialize(void)
    935 {
    936     sal_memset(&api_cint, 0, sizeof(api_cint));
    937 
    938     api_cint.prefix   = "bcm_";
    939     api_cint.prefix_u = "BCM_";
    940     api_cint.prefix_len = sal_strlen(api_cint.prefix);
    941     api_cint.dt_changed = 1;
    942     api_cint.var_changed = 1;
    943 
    944     if (sal_strlen(api_cint.prefix_u) != api_cint.prefix_len) {
    945         return api_mode_unexpected();
    946     }
    947 
    948     _api_mode_init_private();
    949 
    950     cint_interpreter_event_register(_api_mode_cint_event, &api_cint);
    951 
    952     _api_mode_check();
    953 
    954     
    955     return API_MODE_E_NONE;
    956 }
    957 
    958 int
    959 api_mode_context_uninitialize(void)
    960 {
    961     cint_interpreter_event_unregister(_api_mode_cint_event);
    962 
    963     /* Destroy data */
    964     if (api_cint.func.entry != NULL) {
    965         sal_free(api_cint.func.entry);
    966     }
    967     sal_memset(&api_cint, 0, sizeof(api_cint));
    968     
    969     return API_MODE_E_NONE;
    970 }
    971