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