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 }