parse.c (41628B)
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: parse.c 8 * Purpose: Defines routines used to break up a command line. 9 */ 10 11 12 #include <sal/core/libc.h> 13 #include <appl/diag/system.h> 14 #include <appl/diag/parse.h> 15 #include <shared/bsl.h> 16 #include <bcm_int/api_xlate_port.h> 17 18 /* 19 * Allow hook to plug a user-defined variable lookup routine into the 20 * shell. If non-NULL, the routine will be called when a shell variable 21 * lookup fails. 22 */ 23 24 char *(*parse_user_var_get)(char *varname); 25 26 /* 27 * scan routines 28 * 29 * These routines are for scanning an input stream from a string, with 30 * the ability to push things onto the front of the stream at any time. 31 * Used for expanding variables. 32 */ 33 34 #define SCAN_DEPTH 10 35 36 typedef struct scan_s { 37 const char *scan_stack[SCAN_DEPTH]; 38 const char *scan_ptr[SCAN_DEPTH]; 39 int scan_tos; 40 } scan_t; 41 42 #define scan_start(scan) ((scan)->scan_tos = -1) 43 #define scan_ungetc(scan) ((scan)->scan_ptr[(scan)->scan_tos]--) 44 45 static void scan_push(scan_t *scan, const char *s) 46 { 47 if (scan->scan_tos < SCAN_DEPTH - 1) { 48 scan->scan_stack[++scan->scan_tos] = s; 49 scan->scan_ptr[scan->scan_tos] = s; 50 } 51 } 52 53 static int scan_getc(scan_t *scan) 54 { 55 int c; 56 57 for (c = 0; scan->scan_tos >= 0; scan->scan_tos--) 58 if ((c = *scan->scan_ptr[scan->scan_tos]++) != 0) 59 break; 60 61 return c; 62 } 63 64 int 65 parse_cmp(const char *p, const char *s, const char term) 66 /* 67 * Function: parse_cmp 68 * Purpose: Compare a command for a match against a string. 69 * Parameters: p - pointer to string to compare against, upper case 70 * letters indicate letters that MUST be present for a 71 * match; digits must also match 72 * s - pointer to string to compare for match (input). 73 * term - termination character, normally '\0', but may be 74 * '=' for assignment type statements. 75 * Returns: TRUE - compare matched 76 * FALSE - compare failed. 77 * Notes: Initial substrings that consume ALL upper case letters 78 * will match. For example, "abc" will match "ABcd", but not 79 * "ABcD". 80 */ 81 { 82 const char *tp, *ts; /* Temp p/s pointers */ 83 84 /* Check for complete string match */ 85 86 tp = p; 87 ts = s; 88 89 while ((*ts != term) && (*tp) && 90 (sal_toupper((unsigned)*ts) == sal_toupper((unsigned)*tp))) { 91 ts++; 92 tp++; 93 } 94 95 /* We may terminate either on "term" character or end of string */ 96 if (!*tp && ((*ts == term) || !*ts)) { 97 return(TRUE); 98 } 99 100 /* 101 * If we failed above, check if we matched up to a point where 102 * no required characters are required (i.e. "abc" will match "ABcd" 103 * but not "ABcdE". This (so far) appears to always do what is 104 * expected. 105 */ 106 107 if (*ts == term) { /* Ok - check pattern */ 108 while (*tp && !isupper((unsigned)*tp) && !isdigit((unsigned)*tp)) { 109 tp++; 110 } 111 if (!*tp) { /* Matched */ 112 return(TRUE); 113 } 114 } 115 116 /* Check for Upper case match only */ 117 118 tp = p; 119 ts = s; 120 121 while (*tp) { 122 if (isupper((unsigned)*tp) || isdigit((unsigned)*tp)) { 123 if (*tp == sal_toupper((unsigned)*ts)) { 124 ts++; 125 } else { 126 break; 127 } 128 } 129 tp++; 130 } 131 132 return (!*tp && ((*ts == term) || !*ts)); 133 } 134 135 static int 136 parse_cmp_exact(const char *p, const char *s, const char term) 137 /* 138 * Function: parse_cmp_exact 139 * Purpose: Compare a command for an exact match against a string. 140 * Parameters: p - pointer to string to compare against, upper case 141 * letters indicate letters that MUST be present for a 142 * match; digits must also match 143 * s - pointer to string to compare for match (input). 144 * term - termination character, normally '\0', but may be 145 * '=' for assignment type statements. 146 * Returns: TRUE - compare matched 147 * FALSE - compare failed. 148 */ 149 { 150 const char *tp, *ts; /* Temp p/s pointers */ 151 152 /* Handle NULL string */ 153 if (p == NULL || s == NULL) { 154 cli_out("Warning: Comparing NULL string: p=%s, s=%s\n", p, s); 155 return (FALSE); 156 } 157 158 /* Check for complete string match */ 159 tp = p; 160 ts = s; 161 162 while ((*ts != term) && (*tp) && 163 (sal_toupper((unsigned)*ts) == sal_toupper((unsigned)*tp))) { 164 ts++; 165 tp++; 166 } 167 168 /* We may terminate either on "term" character or end of string */ 169 if (!*tp && ((*ts == term) || !*ts)) { 170 return (TRUE); 171 } 172 173 return (FALSE); 174 } 175 176 void 177 parse_args_copy(args_t *dst, args_t *src) 178 /* 179 * Function: parse_args_copy 180 * Purpose: Copy an args structure 181 */ 182 { 183 int i; 184 185 sal_memcpy(dst, src, sizeof (*dst)); 186 187 dst->a_cmd = dst->a_buffer + (src->a_cmd - src->a_buffer); 188 189 for (i = 0; i < src->a_argc; i++) { 190 dst->a_argv[i] = dst->a_buffer + (src->a_argv[i] - src->a_buffer); 191 } 192 } 193 194 static int 195 parse_start_word(args_t *a, char *w) 196 /* 197 * Function: parse_start_word 198 * Purpose: Start a new parsed word, checking for argv overflow. 199 * Parameters: a - pointer to args structure 200 * w - pointer to word to start. 201 * Returns: 0 - OK 202 * -1 - failed (to many parameters). 203 */ 204 { 205 if (a->a_argc >= ARGS_CNT) { 206 return(-1); 207 } else { 208 a->a_argv[a->a_argc++] = w; 209 return(0); 210 } 211 } 212 213 #ifdef BROADCOM_DEBUG 214 void 215 parse_arg_dump(args_t *a) 216 { 217 int i; 218 219 cli_out("parse_arg_dump: a=%p argc=%d next=%d\n", 220 (void *)a, a->a_argc, a->a_arg); 221 222 for (i = 0; i < a->a_argc; i++) 223 cli_out("parse_arg_dump: arg[%d] = <%s>\n", i, a->a_argv[i]); 224 } 225 #endif /* BROADCOM_DEBUG */ 226 227 int 228 diag_parse_args(const char *s, char **s_ret, args_t *a) 229 /* 230 * Function: parse_args 231 * Purpose: Break up a command line into argv/argc format. 232 * Parameters: s - string to break up 233 * s_ret - updated to where processing finished (e.g. semicolon) 234 * a - argument structure to fill in. 235 * Returns: 0 - success 236 * -1 failed (message printed) 237 */ 238 { 239 int inDQ = FALSE; /* True if in double quote */ 240 int inSQ = FALSE; /* True if in single quote */ 241 int inW = FALSE; /* True if in word */ 242 char *d; /* Destination of copy */ 243 char *e; /* End of buffer (last char) */ 244 int c; 245 scan_t scan; 246 d = a->a_buffer; 247 e = a->a_buffer + sizeof (a->a_buffer) - 1; 248 249 a->a_argc = 0; /* Start at 0 please */ 250 a->a_arg = 0; 251 252 if (!s) { /* Handle NULL string */ 253 if (s_ret) { 254 *s_ret = 0; 255 } 256 return 0; 257 } 258 259 scan_start(&scan); 260 scan_push(&scan, s); 261 262 while (1) { 263 c = scan_getc(&scan); 264 if ('\\' == c) { /* Escape char */ 265 c = scan_getc(&scan); 266 if (c == '\0') { 267 cli_out("ERROR: Can't escape EOL\n"); 268 return(-1); 269 } else { 270 if (!inW) { 271 if (parse_start_word(a, d)) { 272 return(-1); 273 } 274 inW = TRUE; 275 } 276 if (d < e) { 277 *d++ = c; 278 } 279 } 280 } else if (!inSQ && (c == PARSE_VARIABLE_PREFIX1 || 281 c == PARSE_VARIABLE_PREFIX2)) { 282 char varname[256], *p = varname; 283 int varq; 284 c = scan_getc(&scan); 285 if (c == '{') { 286 while ((c = scan_getc(&scan)) != '}' && c != 0) { 287 *p++= c; 288 } 289 } else { 290 while (isalnum(c) || c == '_' || c == '?') { 291 *p++ = c; 292 c = scan_getc(&scan); 293 } 294 if (c != 0) { 295 /* COVERITY: Coverity reports negative array index write 296 using scan.scan_tos to scan.scan_ptr, but scan.scan.tos 297 would be set to non-negative in scan_push() call */ 298 299 /* coverity[negative_returns : FALSE] */ 300 scan_ungetc(&scan); 301 } 302 } 303 *p = 0; 304 varq = (varname[0] == '?' && varname[1] != 0); 305 p = var_get(varname + varq); 306 if (p == NULL && parse_user_var_get != NULL) { 307 p = (*parse_user_var_get)(varname + varq); 308 } 309 if (varq) { 310 scan_push(&scan, (p == NULL) ? "0" : "1"); 311 } else if (p != NULL) { 312 scan_push(&scan, p); 313 } 314 } else if (isspace(c) || (';' == c) || (0 == c)) { 315 if (inDQ || inSQ) { /* In quote - copy */ 316 if (c == 0) { 317 cli_out("ERROR: Command line ended " 318 "while in a quoted string\n"); 319 return(-1); 320 } 321 if (d < e) { 322 *d++ = c; 323 } 324 continue; 325 } else if (inW) { /* In word - break */ 326 *d = 0; 327 if (d < e) { 328 d++; 329 } 330 inW = FALSE; 331 } 332 if (';' == c || 0 == c) { 333 /* 334 * If end of line or statement, then update return 335 * pointer and finish up 336 */ 337 break; 338 } 339 } else { 340 /* 341 * Nothing special, if not in a word, then start new arg. 342 */ 343 if (!inW) { 344 if (parse_start_word(a, d)) { 345 return(-1); 346 } 347 inW = TRUE; 348 } 349 if ('"' == c && !inSQ) { 350 inDQ = !inDQ; 351 } else if ('\'' == c && !inDQ) { 352 inSQ = !inSQ; 353 } else { 354 if (d < e) { 355 *d++ = c; 356 } 357 } 358 } 359 } 360 361 if (s_ret) { /* Update s_ret if non-NULL */ 362 *s_ret = ((c != 0 && scan.scan_tos == 0) ? 363 (char *) scan.scan_ptr[scan.scan_tos] : 364 NULL); 365 } 366 367 return(0); 368 } 369 370 int 371 parse_mask(const char *p, const parse_pm_t *pm, uint32 *mask) 372 /* 373 * Function: parse_mask 374 * Purpose: Parse an option of the form [+|-]string into an 375 * AND, OR, and XOR mask. 376 * Parameters: p - string to parse. 377 * pm - plus/minus table, last entry MUST have a string 378 * pointer on NULL. 379 * mask - Mask to or/and/xor into. 380 * Returns: 0 - success 381 * -1 failed. 382 * Notes: If the first character of an entry in pm is '@', the '@' 383 * is ignored (see mask format). 384 */ 385 { 386 char c = '\0'; /* Start NULL */ 387 char *ps; /* String to compare */ 388 389 c = *p; 390 if (('+' == c) || ('-' == c)) { 391 p++; 392 } 393 394 while ((ps = pm->pm_s) != 0) { 395 if ('@' == *ps) { /* Skip alias character */ 396 ps++; 397 } 398 if (parse_cmp(ps, p, '\0')) { 399 break; /* while */ 400 } 401 pm++; 402 } 403 404 if (ps) { /* Found */ 405 switch(c) { 406 case '+': /* OR */ 407 *mask |= pm->pm_value; 408 break; 409 case '-': /* AND */ 410 *mask &= ~pm->pm_value; 411 break; 412 default: /* XOR */ 413 *mask ^= pm->pm_value; 414 break; 415 } 416 return(0); 417 } else { 418 return(-1); 419 } 420 } 421 422 static void * 423 parse_do_lookup(const char *s, void *t, const int size, 424 int c, char term, const int cmd_flag) 425 /* 426 * Function: parse_do_lookup 427 * Purpose: Locate an entry in a table of the form "abc". 428 * Parameters: s - pointer to string to locate 429 * t - pointer to table to lookup in 430 * size - size of each entry. 431 * c - # of valid entries 432 * term - character which denotes end of match string. 433 * cmd_flag - flag which indicates the on-going config cmd 434 * Returns: Pointer to command table entry or NULL. 435 * Notes: If cmd_flag == CMD_ADD, only search for an exact match. 436 * Otherwise, in case of multiple matches, an exact match 437 * will be preferred over any partial matches. 438 */ 439 { 440 void *rv; 441 int len; 442 443 if (s[0] == 0) { 444 return NULL; 445 } 446 447 rv = NULL; 448 while (c--) { 449 if (cmd_flag == CMD_ADD) { 450 /* Only search for an exact match */ 451 if (parse_cmp_exact(*(parse_key_t *)t, s, term)) { 452 rv = t; 453 break; 454 } 455 } else { 456 if (parse_cmp(*(parse_key_t *)t, s, term)) { 457 if (rv == NULL) { 458 rv = t; 459 } 460 len = sal_strlen(*(parse_key_t *)t); 461 if (!sal_strncasecmp(s, *(parse_key_t *)t, len)) { 462 rv = t; 463 break; 464 } 465 } 466 } 467 t = (char *)t + size; 468 } 469 return(rv); 470 } 471 472 int 473 parse_check_eq_arg(parse_eq_t *pq, char *s) 474 /* 475 * Function: parse_check_eq 476 * Purpose: Check if an input parameter matches the pattern specified. 477 * Parameters: pq - pointer to parse_eq entry that matched. 478 * s - pointer to string to match against option. 479 * Returns: 0 - success 480 * -1- failed, no error printed 481 * -2- failed, error printed. 482 * Notes: Fills in value in pq if OK. 483 */ 484 { 485 struct boolean_s { 486 char *b_string; 487 int b_value; 488 }; 489 static struct boolean_s boolean_table[] = { 490 {"Yes", TRUE}, {"OKay", TRUE}, 491 {"YOUBET", TRUE}, {"True", TRUE}, 492 {"1", TRUE}, {"0", FALSE}, 493 {"ON", TRUE}, {"OFF", FALSE}, 494 {"No", FALSE}, {"NOWay",FALSE}, 495 {"False", FALSE}, {"YEAH", TRUE}, 496 {"YEP", TRUE}, {"NOPE", FALSE}, 497 {"NOT", FALSE}, /*{"Maybe",__TIME__[7]&1},*/ 498 }; 499 int boolean_cnt = COUNTOF(boolean_table); 500 const struct boolean_s *bs; 501 sal_mac_addr_t mac_addr; 502 ip_addr_t ip_addr; 503 ip6_addr_t ip6_addr; 504 pbmp_t pbm; 505 void *v = NULL; /* Value */ 506 int vs = 0; /* Value size if type == PTR */ 507 void *fv = NULL; /* Free value */ 508 int rv = 0; 509 char **ms = NULL; 510 uint32 flags = 0; 511 uint64 val64; 512 soc_port_mode_t pm; 513 soc_port_t port; 514 bcm_mod_port_t mod_port; 515 soc_phy_control_longreach_ability_t lr_pa; 516 soc_port_ability_t pa; 517 518 switch (PQ_TYPE(pq->pq_type)) { 519 case PQ_INT64: 520 val64 = parse_uint64(s); 521 v = (void *)&val64; 522 vs = sizeof(uint64); 523 break; 524 case PQ_INT: 525 case PQ_HEX: 526 case PQ_INT8: 527 case PQ_INT16: 528 if (!isint(s)) { 529 return(-1); 530 } 531 v = INT_TO_PTR(parse_integer(s)); 532 if (pq->pq_type & PQ_LAB) { 533 cli_out("WARNING: using deprecated zero based port parsing\n"); 534 } 535 break; 536 case PQ_STRING: 537 fv = *(void **)pq->pq_value; 538 v = sal_strdup(s ? s : ""); 539 flags = PQ_MALLOC; 540 break; 541 case PQ_BOOL: 542 bs = parse_lookup(s, boolean_table, sizeof(boolean_table[0]), 543 boolean_cnt); 544 if (!bs) { 545 return(-1); 546 } 547 v = INT_TO_PTR(bs->b_value); 548 break; 549 case PQ_MAC: 550 if (parse_macaddr(s, mac_addr)) { 551 cli_out("Expected MAC address in the format " 552 "xx:xx:xx:xx:xx:xx or 0x<value>\n"); 553 return(-1); 554 } 555 v = mac_addr; 556 vs = sizeof(mac_addr); 557 break; 558 case PQ_IP: 559 if (parse_ipaddr(s, &ip_addr)) { 560 cli_out("Expecting IP address in the format " 561 "w.x.y.z or 0x<value>\n"); 562 return(-1); 563 } 564 v = INT_TO_PTR(ip_addr); 565 break; 566 case PQ_IP6: 567 if (parse_ip6addr(s, ip6_addr)) { 568 cli_out("Expecting IPV6 address in the format " 569 "AAAA:BBBB:CCCC:DDDD:EEEE:FFFF:GGGG:HHHH\n"); 570 return(-1); 571 } 572 v = (void *)&ip6_addr; 573 vs = sizeof(ip6_addr); 574 break; 575 case PQ_PBMP: 576 /* Check for ? */ 577 if (sal_strcmp(s, "?") == 0 || parse_pbmp(pq->pq_unit, s, &pbm)) { 578 /* AND with pbmp_valid */ 579 if (SOC_IS_RAPTOR(pq->pq_unit) || SOC_IS_RAVEN(pq->pq_unit)) { 580 pbmp_t valid_pbm = soc_property_get_pbmp(pq->pq_unit, spn_PBMP_VALID, 0); 581 (void)parse_pbmp_no_error(pq->pq_unit, s, &pbm); 582 if (!SOC_PBMP_IS_NULL(valid_pbm)) { 583 SOC_PBMP_AND(pbm, valid_pbm); 584 } 585 cli_out("Warning: continuing with invalid bitmap\n"); 586 } else { 587 if (sal_strcmp(s, "?") != 0) { 588 cli_out("Invalid port bitmap \"%s\"\n", s); 589 } 590 cli_out("Examples:\n"); 591 cli_out(" fe ge e fe5 fe8-fe15 fe0-fe46:2 fe:2 fe0,ge1,cpu\n"); 592 cli_out(" 1,25,27 none 0x0 all 0xbffffff\n"); 593 return(-2); 594 } 595 } else if (pq->pq_type & PQ_BCM) { 596 BCM_API_XLATE_PORT_PBMP_P2A(pq->pq_unit, &pbm); 597 } 598 v = (void *)&pbm; 599 vs = sizeof(pbm); 600 break; 601 case PQ_PORTMODE: 602 /* Check for ? */ 603 if (sal_strcmp(s, "?") == 0 || parse_port_mode(s, &pm)) { 604 if (sal_strcmp(s, "?") != 0) { 605 cli_out("Invalid port mode string.\n"); 606 } 607 cli_out("Examples: 1000full,100,10,pause 100,pause_tx,pause_rx\n"); 608 return(-2); 609 } 610 v = INT_TO_PTR(pm); 611 break; 612 case PQ_PORTABIL: 613 /* Check for ? */ 614 if (sal_strcmp(s, "?") == 0 || parse_port_ability(s, &pa)) { 615 if (sal_strcmp(s, "?") != 0) { 616 cli_out("Invalid port mode string.\n"); 617 } 618 cli_out("Examples: 21g,1000full,100,10,pause 100,pause_tx,pause_rx,cl74|cl91|fec_none,short|long\n"); 619 return(-2); 620 } 621 v = (void *)&pa; 622 vs = sizeof(pa); 623 break; 624 625 case PQ_PORT: 626 /* Check for ? */ 627 if (!sal_strcmp(s, "?") || parse_port(pq->pq_unit, s, &port)) { 628 if (sal_strcmp(s, "?")) 629 cli_out("Invalid port \"%s\"\n", s); 630 cli_out("Examples: fe0 ge1 3 cpu0 any\n"); 631 return(-2); 632 } 633 if (pq->pq_type & PQ_BCM) { 634 BCM_API_XLATE_PORT_P2A(pq->pq_unit, &port); 635 } 636 v = INT_TO_PTR(port); 637 break; 638 case PQ_MOD_PORT: /* Parse as <mod.port>; if no '.', parse as port */ 639 /* Check for ? */ 640 if (!sal_strcmp(s, "?") || parse_mod_port(pq->pq_unit, s, &mod_port)) { 641 if (sal_strcmp(s, "?")) 642 cli_out("Invalid module.port \"%s\"\n", s); 643 cli_out("<mod>.<port> or port: 2.4 fe0 cpu0 any\n"); 644 return(-2); 645 } 646 v = (void *)&mod_port; 647 vs = sizeof(mod_port); 648 break; 649 case PQ_MULTI: 650 /* Check for ? */ 651 if (!sal_strcmp(s, "?")) { 652 rv = -2; /* Say error, error msg printed */ 653 } else { 654 for (rv = -1, ms = pq->pq_fm; *ms; ms++) { 655 if (parse_cmp(*ms, s, '\0')) { 656 rv = 0; 657 break; 658 } 659 } 660 } 661 if (!rv) { 662 v = (void *)(ms - pq->pq_fm); /* Return Index */ 663 } else { 664 if (-1 == rv) { 665 cli_out("Invalid selection: %s\n", s); 666 rv = -2; 667 } 668 for (ms = pq->pq_fm; *ms; ms++) { 669 cli_out("\t%s\n", *ms); 670 } 671 return(rv); 672 } 673 break; 674 case PQ_LR_PHYAB: 675 /* Check for ? */ 676 if (sal_strcmp(s, "?") == 0 || 677 parse_phy_control_longreach_ability(s, &lr_pa)) { 678 if (sal_strcmp(s, "?") != 0) { 679 cli_out("Invalid longreach phy ability string.\n"); 680 } 681 cli_out("Examples: 100x4,100x2,100x1,50x2,50x1,33x2,33x1,25x2,25x1,20x2,20x1,10x2,10x1,pause_tx,pause_rx\n"); 682 return(-2); 683 } 684 v = INT_TO_PTR(lr_pa); 685 break; 686 default: 687 /* Defensive default */ 688 cli_out("Unexpected parse qualifier 0x%03x\n", PQ_TYPE(pq->pq_type)); 689 return(-2); 690 } 691 /* 692 * Call side effect function, and if result is OK, make the 693 * assignment. 694 */ 695 if (pq->pq_type & PQ_PTR) { 696 sal_memcpy(pq->pq_value, v, vs); 697 } else { 698 switch (PQ_TYPE(pq->pq_type)) { 699 case PQ_INT: 700 case PQ_HEX: 701 case PQ_BOOL: 702 case PQ_IP: 703 case PQ_PORTMODE: 704 case PQ_PORT: 705 case PQ_MULTI: 706 case PQ_LR_PHYAB: 707 *((int *)pq->pq_value) = PTR_TO_INT(v); /* 64-bit support */ 708 break; 709 case PQ_INT8: 710 *((uint8 *)pq->pq_value) = PTR_TO_INT(v); 711 break; 712 case PQ_INT16: 713 *((uint16 *)pq->pq_value) = PTR_TO_INT(v); 714 break; 715 case PQ_STRING: 716 case PQ_MAC: 717 case PQ_PBMP: 718 case PQ_INT64: 719 *(void **)pq->pq_value = v; 720 break; 721 } 722 } 723 if (fv) { /* Free old string if required */ 724 sal_free(fv); 725 } 726 pq->pq_type |= flags; /* Or in possible flags */ 727 pq->pq_type |= PQ_PARSED; /* Mark as parsed */ 728 729 /* 730 * COVERITY 731 * pq->pq_value origin address has been set to fv and freed, 732 * new address alloc by sal_strdup has been set to v; 733 */ 734 /* coverity[leaked_storage] */ 735 736 return(rv); 737 } 738 739 static int 740 parse_prompt_eq(parse_table_t *pt) 741 /* 742 * Function: parse_prompt_eq 743 * Purpose: Prompt from keyboard for each option. 744 * Parameters: pt - table to prompt from. 745 * pq_cnt - # of entries in table. 746 * Returns: # parameters or -1 for failed. 747 * Notes: 748 * Allows entering - to go back an entry. 749 * Allows pressing ^D to default all the rest of the entries. 750 */ 751 { 752 char is[128], ds[128]; /* input/default strings */ 753 char rds[128]; /* real default string */ 754 int pq_cur; 755 void *defl; /* Pointer to default value */ 756 parse_eq_t *pq; 757 int default_rest = 0; 758 int use_rds; 759 char pfmt[SOC_PBMP_FMT_LEN]; 760 761 pq_cur = 0; 762 while (pq_cur < pt->pt_cnt) { 763 pq = &pt->pt_entries[pq_cur]; 764 if (pq->pq_type & PQ_IGNORE) { 765 pq_cur++; 766 continue; 767 } 768 defl = (pq->pq_type & PQ_DFL) ? 769 ((pq->pq_type & PQ_PTR) ? pq->pq_value : *(void **)pq->pq_value) 770 : (void *)pq->pq_default; 771 use_rds = 0; 772 switch(PQ_TYPE(pq->pq_type)) { 773 case PQ_INT64: 774 COMPILER_64_ZERO(*(uint64*)ds); 775 COMPILER_64_OR(*(uint64*)ds, *(uint64*)defl); 776 break; 777 case PQ_INT: 778 case PQ_INT8: 779 case PQ_INT16: 780 sal_sprintf(ds, "%d", PTR_TO_INT(defl)); 781 break; 782 case PQ_HEX: 783 sal_sprintf(ds, "0x%x", PTR_TO_INT(defl)); 784 break; 785 case PQ_BOOL: 786 sal_strncpy(ds, PTR_TO_INT(defl) ? "True" : "False", 127); 787 break; 788 case PQ_STRING: 789 sal_strncpy(ds, defl ? (char *)defl : "", 127); 790 ds[127] = 0; 791 break; 792 case PQ_MAC: 793 if (defl != NULL) { 794 format_macaddr((void *)ds, (void *)defl); 795 } else { 796 ds[0] = 0; 797 } 798 break; 799 case PQ_IP: 800 format_ipaddr((void *)ds, (ip_addr_t)PTR_TO_INT(defl)); 801 break; 802 case PQ_IP6: 803 if (defl != NULL) { 804 format_ip6addr((void *)ds, (void *)defl); 805 } else { 806 ds[0] = 0; 807 } 808 break; 809 case PQ_PBMP: 810 format_pbmp(pq->pq_unit, is, sizeof(is), *(pbmp_t *)pq->pq_value); 811 if (defl != NULL) { 812 sal_sprintf(rds, "%s", SOC_PBMP_FMT(*(pbmp_t *)defl, pfmt)); 813 sal_sprintf(ds, "%s; %s", 814 SOC_PBMP_FMT(*(pbmp_t *)defl, pfmt), 815 is); 816 } else { 817 rds[0] = 0; 818 ds[0] = 0; 819 } 820 use_rds = 1; 821 break; 822 case PQ_PORTMODE: 823 format_port_mode((void *)ds, sizeof (ds), 824 (soc_port_mode_t)PTR_TO_INT(defl), TRUE); 825 break; 826 case PQ_PORT: 827 sal_sprintf(rds, "%s", SOC_PORT_NAME(pq->pq_unit, PTR_TO_INT(defl))); 828 sal_sprintf(ds, "%d; %s", 829 PTR_TO_INT(defl), 830 SOC_PORT_NAME(pq->pq_unit, PTR_TO_INT(defl))); 831 use_rds = 1; 832 break; 833 case PQ_MOD_PORT: 834 { 835 bcm_mod_port_t *mp = defl; 836 837 if (mp->mod == -1) { /* Parse as port */ 838 sal_sprintf(rds, "%s", SOC_PORT_NAME(pq->pq_unit, mp->port)); 839 sal_sprintf(ds, "%d; %s", 840 mp->port, 841 SOC_PORT_NAME(pq->pq_unit, mp->port)); 842 use_rds = 1; 843 } else { /* Parse as <mod>.<port> */ 844 sal_sprintf(ds, "%d.%d", mp->mod, mp->port); 845 } 846 break; 847 } 848 case PQ_MULTI: 849 sal_strncpy(ds, pq->pq_fm[PTR_TO_INT(defl)], 127); 850 ds[127] = 0; 851 break; 852 } 853 854 if (default_rest) { 855 cli_out("%s[%s]\n", pq->pq_s, ds); 856 sal_strncpy(is, ds, sizeof(is) - 1); 857 is[sizeof(is) - 1] = 0; 858 } else if (sal_readline(pq->pq_s, is, sizeof(is), ds) == NULL) { 859 cli_out("\n"); 860 default_rest = 1; 861 sal_strncpy(is, ds, sizeof(is) - 1); 862 is[sizeof(is) - 1] = 0; 863 } 864 865 /* Allow entering '-' to go back an entry. */ 866 867 if (sal_strcmp(is, "-") == 0 && !default_rest) { 868 while (pq_cur > 0) { 869 pq_cur--; 870 pq--; 871 if (!(pq->pq_type & PQ_IGNORE)) { 872 break; 873 } 874 } 875 continue; 876 } 877 878 /* 879 * if just return was hit, the wrong default string was 880 * copied into the input string, so replace it 881 */ 882 if (use_rds && sal_strcmp(ds, is) == 0) { 883 sal_strncpy(is, rds, sizeof(is) - 1); 884 is[sizeof(is) - 1] = 0; 885 } 886 887 switch (parse_check_eq_arg(pq, is)) { 888 case 0: 889 break; 890 case -1: 891 cli_out("Invalid response\n"); 892 /* Fall through */ 893 case -2: /* NO BREAK */ 894 if (!default_rest) { 895 continue; /* While */ 896 } 897 } 898 /* Mark all as parsed */ 899 pq->pq_type |= PQ_PARSED; 900 pq_cur++; /* On to next */ 901 } 902 903 return(pq_cur); 904 } 905 906 907 int 908 parse_default_fill(parse_table_t *pq_table) 909 /* 910 * Function: parse_default_fill 911 * Purpose: Fill default arguments 912 * Parameters: pq_table - pointer to parse table to lookup in. 913 * Returns: # parameters parsed, or -1 if failed. 914 * Notes: All default values are filled in in the table. 915 * 916 * parse_args_eq_done MUST always be called when the argument 917 * list is no longer needed to free any allocated buffers. 918 */ 919 { 920 int i, rv = 0; 921 parse_eq_t *pq; 922 923 for (i = 0; i < pq_table->pt_cnt; i++) { /* Fill in defaults */ 924 pq = &pq_table->pt_entries[i]; 925 if (pq->pq_type & PQ_DFL) { 926 continue; 927 } 928 if (PQ_TYPE(pq->pq_type) == PQ_STRING) { 929 *(char **)pq->pq_value = 930 sal_strdup(pq->pq_default ? (char *)pq->pq_default : ""); 931 if (!(pq->pq_type & PQ_STATIC)) { 932 pq->pq_type |= PQ_MALLOC; 933 } 934 } else if (pq->pq_type & PQ_PTR) { 935 int vs = 4; 936 switch (PQ_TYPE(pq->pq_type)) { 937 case PQ_MAC: vs = 6; break; 938 case PQ_IP: vs = sizeof (ip_addr_t); break; 939 case PQ_IP6: vs = sizeof (ip6_addr_t); break; 940 case PQ_PBMP: vs = sizeof (pbmp_t); break; 941 case PQ_MOD_PORT: vs = sizeof (bcm_mod_port_t); break; 942 } 943 if (pq->pq_default != NULL) { 944 sal_memcpy(pq->pq_value, pq->pq_default, vs); 945 } else { 946 sal_memset(pq->pq_value, 0, vs); 947 } 948 } else { 949 /* All others must be 4-byte 'int' type */ 950 *(int *)pq->pq_value = PTR_TO_INT(pq->pq_default); 951 } 952 } 953 954 /* AFTER defaults are filled in */ 955 return rv; 956 } 957 958 int 959 parse_arg_eq(args_t *a, parse_table_t *pq_table) 960 /* 961 * Function: parse_arg_eq 962 * Purpose: Decode an argument of the form "abc=def". 963 * Parameters: a - pointer to arguments to parse. 964 * pq_table - pointer to parse table to lookup in. 965 * Returns: # parameters parsed, or -1 if failed. 966 * Notes: All default values are filled in in the table, then 967 * the options are parsed and the pq_value values are 968 * overwritten. 969 * 970 * parse_args_eq_done MUST always be called when the argument 971 * list is no longer needed to free any allocated buffers. 972 */ 973 { 974 int i, rv = 0; 975 char *c, *eq; /* Current/after '=' argument */ 976 parse_eq_t *pq; 977 978 for (i = 0; i < pq_table->pt_cnt; i++) { /* Fill in defaults */ 979 pq = &pq_table->pt_entries[i]; 980 if (pq->pq_type & PQ_DFL) { 981 continue; 982 } 983 if (PQ_TYPE(pq->pq_type) == PQ_STRING) { 984 *(char **)pq->pq_value = 985 sal_strdup(pq->pq_default ? (char *)pq->pq_default : ""); 986 if (!(pq->pq_type & PQ_STATIC)) { 987 pq->pq_type |= PQ_MALLOC; 988 } 989 } else if (pq->pq_type & PQ_PTR) { 990 int vs = 4; 991 switch (PQ_TYPE(pq->pq_type)) { 992 case PQ_MAC: vs = 6; break; 993 case PQ_IP: vs = sizeof (ip_addr_t); break; 994 case PQ_IP6: vs = sizeof (ip6_addr_t); break; 995 case PQ_PBMP: vs = sizeof (pbmp_t); break; 996 case PQ_MOD_PORT: vs = sizeof (bcm_mod_port_t); break; 997 } 998 if (pq->pq_default != NULL) { 999 sal_memcpy(pq->pq_value, pq->pq_default, vs); 1000 } else { 1001 sal_memset(pq->pq_value, 0, vs); 1002 } 1003 } else { 1004 /* All others must be 4-byte 'int' type */ 1005 *(int *)pq->pq_value = PTR_TO_INT(pq->pq_default); 1006 } 1007 } 1008 1009 /* AFTER defaults are filled in */ 1010 1011 if (0 == ARG_CNT(a)) { /* No args, return 0 */ 1012 return(0); 1013 } 1014 1015 /* 1016 * If only 1 argument, and it is '=', then prompt from keyboard for 1017 * each option. 1018 */ 1019 1020 if (!sal_strcmp("=", _ARG_CUR(a))) { 1021 ARG_NEXT(a); /* Consume '=' */ 1022 return(parse_prompt_eq(pq_table)); 1023 } 1024 1025 while ((c = ARG_CUR(a)) != NULL) { 1026 pq = parse_do_lookup(c, pq_table->pt_entries, sizeof(parse_eq_t), 1027 pq_table->pt_cnt, '=', pq_table->cmd_flag); 1028 if (!pq) { /* Not found */ 1029 return(rv); 1030 } 1031 rv++; 1032 eq = sal_strchr(c, '='); 1033 if (!eq) { 1034 if (pq->pq_type & PQ_NO_EQ_OPT) { 1035 pq->pq_type |= PQ_SEEN; /* Mark as seen during parsing */ 1036 if (PQ_TYPE(pq->pq_type) == PQ_BOOL) { 1037 *((int *)pq->pq_value) = 1; 1038 } 1039 } else { 1040 return -1; 1041 } 1042 } else { /* = found */ 1043 eq++; 1044 if (parse_check_eq_arg(pq, eq)) { 1045 return(-1); 1046 } 1047 } 1048 ARG_NEXT(a); /* On to next argument */ 1049 } 1050 return(rv); 1051 } 1052 1053 int 1054 parse_arg_eq_keep_index(args_t *a, parse_table_t *pq_table) 1055 /* 1056 * Same as parse_arg_eq, but does not advance the a_arg parameter 1057 * Allows multiple access to single command 1058 */ 1059 { 1060 int rv = 0; 1061 int arg_index_placeholder = ARG_CUR_INDEX(a); 1062 rv = parse_arg_eq(a, pq_table); 1063 while (arg_index_placeholder < ARG_CUR_INDEX(a)) { 1064 ARG_PREV(a); 1065 } 1066 return (rv); 1067 } 1068 1069 void 1070 parse_arg_eq_done(parse_table_t *pt) 1071 /* 1072 * Function: parse_arg_eq_done 1073 * Purpose: Free memory associated/allocated for parsing a 1074 * EQ table. 1075 * Parameters: pq - pointer to table. 1076 * pq_cnt - # of entries. 1077 * Returns: Nothing 1078 */ 1079 { 1080 parse_eq_t *pq; 1081 1082 if (pt->pt_entries == NULL) { 1083 return; 1084 } 1085 for (pq = pt->pt_entries; pq < &pt->pt_entries[pt->pt_cnt]; pq++) { 1086 if ((pq->pq_type & PQ_MALLOC) && 1087 !(pq->pq_type & PQ_STATIC) && 1088 *((void **)pq->pq_value) != NULL) { 1089 sal_free(*(void **)pq->pq_value); 1090 *(void **)pq->pq_value = NULL; 1091 pq->pq_type &= ~PQ_MALLOC; 1092 } 1093 } 1094 sal_free(pt->pt_entries); 1095 pt->pt_entries = NULL; 1096 pt->pt_alloc = 0; 1097 } 1098 1099 void 1100 parse_eq_format(parse_table_t *pt) 1101 /* 1102 * Function: parse_eq_format 1103 * Purpose: Print out current values from a EQ table, using the 1104 * assigned values, NOT the default values. 1105 * Parameters: pq - pointer to eq table 1106 * Returns: Nothing. 1107 */ 1108 { 1109 char fs[128]; 1110 parse_eq_t *pq; 1111 char pfmt[SOC_PBMP_FMT_LEN]; 1112 1113 for (pq = pt->pt_entries; pq < &pt->pt_entries[pt->pt_cnt]; pq++) { 1114 switch(PQ_TYPE(pq->pq_type)) { 1115 case PQ_INT64: 1116 cli_out("\t%s=0x%x%x\n", pq->pq_s, 1117 COMPILER_64_HI(*(uint64 *)pq->pq_value), 1118 COMPILER_64_LO(*(uint64 *)pq->pq_value)); 1119 break; 1120 case PQ_INT: 1121 cli_out("\t%s=%d\n", pq->pq_s, *(int *)pq->pq_value); 1122 break; 1123 case PQ_INT8: 1124 cli_out("\t%s=%d\n", pq->pq_s, *(uint8 *)pq->pq_value); 1125 break; 1126 case PQ_INT16: 1127 cli_out("\t%s=%d\n", pq->pq_s, *(uint16 *)pq->pq_value); 1128 break; 1129 case PQ_HEX: 1130 cli_out("\t%s=0x%x\n", pq->pq_s, *(int *)pq->pq_value); 1131 break; 1132 case PQ_BOOL: 1133 cli_out("\t%s=%s\n", pq->pq_s, 1134 *(int *)pq->pq_value ? "True" : "False"); 1135 break; 1136 case PQ_STRING: 1137 cli_out("\t%s=%s\n", pq->pq_s, 1138 *(char **)pq->pq_value ? 1139 *(char **)pq->pq_value : "<none>"); 1140 break; 1141 case PQ_MULTI: 1142 cli_out("\t%s=%s\n", pq->pq_s, 1143 pq->pq_fm[*(int *)pq->pq_value]); 1144 break; 1145 case PQ_MAC: 1146 format_macaddr(fs, (uint8 *)(pq->pq_value)); 1147 cli_out("\t%s=%s\n", pq->pq_s, fs); 1148 break; 1149 case PQ_IP: 1150 format_ipaddr(fs, *(ip_addr_t *)(pq->pq_value)); 1151 cli_out("\t%s=%s\n", pq->pq_s, fs); 1152 break; 1153 case PQ_IP6: 1154 format_ip6addr(fs, (uint8 *)(pq->pq_value)); 1155 cli_out("\t%s=%s\n", pq->pq_s, fs); 1156 break; 1157 case PQ_PBMP: 1158 format_pbmp(pq->pq_unit, fs, sizeof(fs), *(pbmp_t *)pq->pq_value); 1159 cli_out("\t%s=%s, %s\n", pq->pq_s, 1160 SOC_PBMP_FMT(*(pbmp_t *)pq->pq_value, pfmt), 1161 fs); 1162 break; 1163 case PQ_PORTMODE: 1164 format_port_mode(fs, sizeof (fs), 1165 (soc_port_mode_t)PTR_TO_INT(pq->pq_value), TRUE); 1166 cli_out("\t%s=%s\n", pq->pq_s, fs); 1167 break; 1168 case PQ_PORT: 1169 { 1170 char *pname; 1171 if (pq->pq_type & PQ_BCM) { 1172 pname = BCM_PORT_NAME(pq->pq_unit, *(int *)pq->pq_value); 1173 } else { 1174 pname = SOC_PORT_NAME(pq->pq_unit, *(int *)pq->pq_value); 1175 } 1176 cli_out("\t%s=%s, %d\n", pq->pq_s, pname, *(int *)pq->pq_value); 1177 break; 1178 } 1179 case PQ_MOD_PORT: 1180 { 1181 bcm_mod_port_t *mp = (bcm_mod_port_t *)pq->pq_value; 1182 if (mp->mod < 0) { /* Display as local port */ 1183 cli_out("\t%s=--.%s (%d)\n", pq->pq_s, 1184 SOC_PORT_NAME(pq->pq_unit, mp->port), mp->port); 1185 } else { 1186 cli_out("\t%s=%d.%d\n", pq->pq_s, mp->mod, mp->port); 1187 } 1188 break; 1189 } 1190 } 1191 } 1192 } 1193 1194 1195 int 1196 parse_table_add(parse_table_t *pq_table, char *key, uint32 type, void *def, 1197 void *value, void *func) 1198 /* 1199 * Function: parse_table_add 1200 * Purpose: Initialize fields for a specific entry in the table 1201 * Parameters: pq_table - pointer to pq table to fill in values for. 1202 * key - keyword to fill in 1203 * def - default value for entry 1204 * value - value to assign to "value". 1205 * func - pointer tp 1206 * Returns: 0 - success 1207 * -1 - failed to find entry. 1208 * 1209 * Notes: This routine is not efficient, but it works easily! 1210 */ 1211 { 1212 parse_eq_t *pq; 1213 parse_eq_t *npe; 1214 int nalloc; 1215 1216 /* pt_entries are allocated in clumps of PT_ALLOC */ 1217 if (pq_table->pt_cnt + 1 >= pq_table->pt_alloc) { 1218 nalloc = pq_table->pt_alloc + PT_ALLOC; 1219 npe = sal_alloc(sizeof(parse_eq_t) * nalloc, "parse_tab"); 1220 if (npe == NULL) { 1221 cli_out("parse_table_add: ERROR: " 1222 "cannot allocate %d entries\n", nalloc); 1223 return -1; 1224 } 1225 sal_memset(npe, 0, sizeof(parse_eq_t) * nalloc); 1226 if (pq_table->pt_alloc != 0) { 1227 int copysize; 1228 /* 1229 * Note: mips64 gcc 2.7.6 and 2.7.12 die with an internal 1230 * compiler error unless the copy size is calculated in a 1231 * local variable. 1232 */ 1233 copysize = sizeof (parse_eq_t) * pq_table->pt_alloc; 1234 sal_memcpy(npe, pq_table->pt_entries, copysize); 1235 sal_free(pq_table->pt_entries); 1236 } 1237 pq_table->pt_alloc = nalloc; 1238 pq_table->pt_entries = npe; 1239 } 1240 pq = &pq_table->pt_entries[pq_table->pt_cnt]; 1241 pq_table->pt_cnt += 1; 1242 1243 pq->pq_unit = pq_table->pt_unit; 1244 pq->pq_s = key; 1245 pq->pq_type = type; 1246 pq->pq_default = def; 1247 pq->pq_value = value; 1248 pq->pq_fm = func; 1249 return 0; 1250 } 1251 1252 void 1253 parse_table_init(int unit, parse_table_t *pt) 1254 /* 1255 * Function: parse_table_init 1256 * Purpose: Initialize parse table fields. 1257 * Parameters: pt - pointer to table to initialize. 1258 * Returns: Nothing 1259 */ 1260 { 1261 pt->pt_unit = unit; 1262 pt->pt_cnt = 0; 1263 pt->pt_alloc = 0; 1264 pt->pt_entries = NULL; 1265 pt->cmd_flag = 0; 1266 } 1267 1268 void 1269 parse_mask_format(const int ll, const parse_pm_t *pm, uint32 mask) 1270 /* 1271 * Function: parse_mask_format 1272 * Purpose: Format mask bits into buffer. 1273 * Parameters: ll - line length 1274 * pm - pointer to pm table 1275 * mask - mask value to format. 1276 * Returns: Nothing. 1277 * Notes: If the first character of an entry in pm is '@', the entry 1278 * is ignored - this allows multiple entries to refer to the 1279 * same bit(s) as an alias. 1280 * For simplicity, we always append a space to the end of each 1281 * entry. 1282 */ 1283 { 1284 int cl = 0; /* Current line length */ 1285 int tl; /* Temp line length */ 1286 int nl = FALSE; /* newline require */ 1287 1288 while (pm->pm_s) { 1289 if ('@' != *pm->pm_s) { /* Ignore alias */ 1290 if (pm->pm_value & mask) { 1291 tl = sal_strlen(pm->pm_s) + 1; 1292 if (cl + tl > ll) { 1293 nl = TRUE; 1294 cl = tl; 1295 } else { 1296 cl += tl; 1297 } 1298 cli_out("%s%s%s", 1299 nl ? "\n" : "", /* Newline required */ 1300 cl == tl ? "" : " ", /* First on line */ 1301 pm->pm_s); 1302 nl = FALSE; 1303 } 1304 } 1305 pm++; 1306 } 1307 cli_out("\n"); 1308 } 1309 1310 const void * 1311 parse_lookup(const char *s, const void *t, int size, int cnt) 1312 /* 1313 * Function: parse_lookup 1314 * Purpose: Locate an entry in a table based on the key. 1315 * Parameters: s - pointer to string to locate 1316 * t - pointer to table to lookup in 1317 * size - size of each entry. 1318 * cnt - # of valid entries 1319 * Returns: Pointer to command table entry or NULL. 1320 */ 1321 { 1322 return (parse_do_lookup(s, (void *)t, size, cnt, '\0', CMD_DC)); 1323 } 1324