openbcm

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

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