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

autocomplete.c (10695B)


      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  * Broadcom autocomplete
      8  */
      9 
     10 
     11 #ifdef INCLUDE_AUTOCOMPLETE
     12 
     13 #include <sal/appl/editline/autocomplete.h>
     14 #include <sal/appl/sal.h>
     15 #include <sal/core/libc.h>
     16 #include <sal/appl/io.h>
     17 #include <sal/core/alloc.h>
     18 #include <soc/drv.h>
     19 #include <sys/ioctl.h>
     20 
     21 char autocomplete_string[SOC_MAX_NUM_DEVICES][AUTOCOMPLETE_MAX_STRING_LEN];
     22 
     23 static autocomplete_node_t autocomplete_root[SOC_MAX_NUM_DEVICES];
     24 
     25 autocomplete_node_t *autocomplete_find_root(int unit, char *keyword) {
     26 
     27     autocomplete_node_t *node = autocomplete_root[unit].first_child;
     28 
     29     while (node != NULL) {
     30         if (sal_strcasecmp(node->keyword, keyword) == 0) {
     31             return node;
     32         }
     33         node = node->next_sibling;
     34     }
     35 
     36     return NULL;
     37 }
     38 
     39 
     40 autocomplete_node_t *autocomplete_find_node(int unit, char **keywords) {
     41     autocomplete_node_t *node = autocomplete_root[unit].first_child;
     42     int i = 0;
     43 
     44     while (keywords[i] != NULL) {
     45         while (node != NULL) {
     46             if (sal_strcasecmp(node->keyword, keywords[i]) == 0) {
     47                 if(keywords[i+1] == NULL) {
     48                     return node;
     49                 }
     50                 node = node->first_child;
     51                 break;
     52             }
     53             node = node->next_sibling;
     54         }
     55         if (node == NULL) return NULL;
     56         i++;
     57     }
     58 
     59     return NULL;
     60 }
     61 
     62 /* for description see the header include/sal/appl/editline/autocomplete.h */
     63 
     64 autocomplete_node_t *autocomplete_node_add(int unit, autocomplete_node_t *parent, char *keyword, char is_option) {
     65 
     66     autocomplete_node_t *node = (autocomplete_node_t*) sal_alloc(sizeof(*node), "autocomplete node");
     67 
     68     node->keyword = sal_strdup(keyword);
     69     node->first_child = NULL;
     70     node->next_sibling = NULL;
     71     node->parent = parent;
     72     node->is_option = is_option;
     73 
     74     /* check if parent is root */
     75     if (parent == NULL) {
     76         parent = &autocomplete_root[unit];
     77         node->parent = parent;
     78     }
     79 
     80     /* check if it should be the first child of parent */
     81     if (parent->first_child == NULL) {
     82         parent->first_child = node;
     83     } else {
     84         autocomplete_node_t* last_child = parent->first_child;
     85         while(last_child->next_sibling != NULL) {
     86             last_child = last_child->next_sibling;
     87         }
     88         last_child->next_sibling = node;
     89     }
     90 
     91     return node;
     92 }
     93 
     94 /* for description see the header include/sal/appl/editline/autocomplete.h */
     95 
     96 void autocomplete_delete_all(int unit) {
     97 
     98     autocomplete_node_t *node = autocomplete_root[unit].first_child;
     99     autocomplete_node_t *next_node;
    100     while (node != NULL) {
    101         next_node = node->next_sibling;
    102         autocomplete_node_delete(unit, node);
    103         node = next_node;
    104     }
    105     autocomplete_root[unit].first_child = NULL;
    106 
    107 }
    108 
    109 /* for description see the header include/sal/appl/editline/autocomplete.h */
    110 
    111 void autocomplete_node_delete(int unit, autocomplete_node_t* node) {
    112 
    113     autocomplete_node_t *parent;
    114     autocomplete_node_t *child;
    115 
    116     if (node == NULL)
    117         return;
    118 
    119     parent = node->parent;
    120     child = node->first_child;
    121 
    122     /* check if the node is the first child of it's parent */
    123     if (parent->first_child == node) {
    124         parent->first_child = node->next_sibling;
    125     } else {
    126         autocomplete_node_t* older_sibling = parent->first_child;
    127         while(older_sibling->next_sibling != node) {
    128             older_sibling = older_sibling->next_sibling;
    129         }
    130         older_sibling->next_sibling = node->next_sibling;
    131     }
    132 
    133     /* delete all of the node's children */
    134     while (child != NULL) {
    135         autocomplete_node_t* next_child = child->next_sibling;
    136         autocomplete_node_delete(unit, child);
    137         child = next_child;
    138     }
    139 
    140     /* delete the node */
    141     sal_free(node->keyword);
    142     sal_free(node);
    143 
    144     return;
    145 }
    146 
    147 /* get a prefix as a parameter and a new word, calcuate the largest common prefix and save it in prefix */
    148 
    149 static void update_common_prefix(int index, char *prefix, char *new_word) {
    150     /* if the new_word is the first word */
    151     if (index == 0) {
    152         sal_strncpy(prefix, new_word, AUTOCOMPLETE_MAX_STRING_LEN-1);
    153     } else {
    154         int i=0;
    155         while (prefix[i] == new_word[i]) {
    156             i++;
    157         }
    158         /* truncate the prefix */
    159         sal_memset(prefix+i, 0, sal_strlen(prefix+i));
    160     }
    161 }
    162 
    163 
    164 static void uncheck_options (autocomplete_node_t *options_node) {
    165     while(options_node != NULL) {
    166         options_node->is_checked = 0;
    167         options_node = options_node->next_sibling;
    168     }
    169     return;
    170 }
    171 
    172 /* for description see the header include/sal/appl/editline/autocomplete.h */
    173 
    174 char* autocomplete_print(int unit, char* input, char* prompt) {
    175    autocomplete_node_t *prev_node = NULL;
    176    autocomplete_node_t *options_node = NULL;
    177    autocomplete_node_t *node = NULL;
    178    char new_line[AUTOCOMPLETE_MAX_STRING_LEN] = {0};
    179    char str_to_print[AUTOCOMPLETE_MAX_STRING_LEN] = {0};
    180    char str_tmp[AUTOCOMPLETE_MAX_STRING_LEN] = {0};
    181    char common_prefix[AUTOCOMPLETE_MAX_STRING_LEN] = {0};
    182    char *prefix;
    183    const char s[2] = " ";
    184    char *token;
    185    int token_idx=0;
    186    int node_depth=0;
    187    int num_of_suggestions = 0;
    188    char str_cpy[AUTOCOMPLETE_MAX_STRING_LEN] = {0};
    189    int max_autocomplete_str_len = 0;
    190    int accumulative_line_len = 0;
    191    struct winsize window_size;
    192    int window_len = 0;
    193    char is_last_token = 0;
    194    char *last_token;
    195    char is_option = 0;
    196    char print_options = 0;
    197 
    198    if (unit == -1) {
    199        sal_printf("\nError: autocomplete failed. No attached unit found.\n");
    200        sal_printf("%s", prompt);
    201        return "";
    202    }
    203 
    204    node = prev_node = autocomplete_root[unit].first_child;
    205 
    206    if (node == NULL) {
    207        return "";
    208    }
    209 
    210    /* autocomplete only in BCM shell */
    211    if (sal_strstr(prompt, "BCM") == NULL) {
    212        return "";
    213    }
    214 
    215    sal_strncpy(str_cpy, input, AUTOCOMPLETE_MAX_STRING_LEN-1);
    216 
    217    /* get the first token */
    218    token = strtok(str_cpy, s);
    219 
    220    /* walk through other tokens */
    221    while( token != NULL )
    222    {
    223       char* assignment = NULL;
    224       token_idx++;
    225       prev_node = node;
    226       is_option = 0;
    227       if (node != NULL && node->is_option) {
    228           print_options = 1;
    229           options_node = node;
    230       }
    231       while(node != NULL && node->keyword != NULL) {
    232           if (sal_strcasecmp(node->keyword, token) == 0) {
    233 
    234               if(node->is_option) {
    235                   node->is_checked = 1;
    236               }
    237 
    238               if (print_options && node->first_child == NULL) {
    239                   node = options_node;
    240               } else {
    241                   node = node->first_child;
    242               }
    243 
    244               node_depth++;
    245               break;
    246           }
    247           assignment = strchr(token, '=');
    248           if (assignment != NULL) {
    249               if (sal_strncasecmp(node->keyword, token, assignment - token + 1) == 0) {
    250                   is_option = 1;
    251 
    252                   node->is_checked = 1;
    253 
    254                   if (node->first_child != NULL) {
    255                       node = node->first_child;
    256                   } else {
    257                       node = options_node;
    258                   }
    259 
    260                   node_depth++;
    261                   break;
    262               }
    263           }
    264           node = node->next_sibling;
    265       }
    266       if (token_idx != node_depth) break;
    267       if(is_option) {
    268           last_token = token;
    269           token = strtok(NULL, s);
    270           /* if last token */
    271           if (token == NULL && node != options_node) {
    272               sal_strncat(new_line, last_token , assignment - last_token + 1);
    273               token = assignment + 1;
    274               is_last_token = 1;
    275           } else {
    276               sal_strncat(new_line, last_token, AUTOCOMPLETE_MAX_STRING_LEN - sal_strlen(new_line) - 1);
    277               node = options_node;
    278           }
    279           continue;
    280       } else {
    281           sal_strncat(new_line,token, AUTOCOMPLETE_MAX_STRING_LEN - sal_strlen(new_line) - 1);
    282       }
    283 
    284       if(token[strlen(token)-1] != '=') {
    285           sal_strncat(new_line," ", AUTOCOMPLETE_MAX_STRING_LEN - sal_strlen(new_line) -1);
    286       }
    287 
    288       if (is_last_token) {
    289           token = NULL;
    290       } else {
    291           token = strtok(NULL, s);
    292       }
    293    }
    294 
    295    /* no suggestions */
    296    if (token_idx != node_depth && strtok(NULL, s)) {
    297        uncheck_options(options_node);
    298        return "";
    299    }
    300    /* show all options */
    301    if (token_idx == node_depth) {
    302        prefix = "";
    303    } else { /* complete by the prefix */
    304        node = prev_node;
    305        prefix = token;
    306    }
    307 
    308    /* walk through the suggestions */
    309    while(node != NULL && node->keyword != NULL) {
    310        if (sal_strncasecmp(node->keyword, prefix, sal_strlen(prefix)) == 0 && !node->is_checked) {
    311            update_common_prefix(num_of_suggestions, common_prefix, node->keyword);
    312            sal_sprintf(str_tmp, "%s ", node->keyword);
    313            if (max_autocomplete_str_len < sal_strlen(str_tmp)) {
    314                max_autocomplete_str_len = sal_strlen(str_tmp);
    315            }
    316            sal_strncat(str_to_print, str_tmp, AUTOCOMPLETE_MAX_STRING_LEN - sal_strlen(str_to_print)-1);
    317            sal_strncat(new_line,str_tmp, AUTOCOMPLETE_MAX_STRING_LEN - sal_strlen(new_line)-1);
    318            num_of_suggestions++;
    319        }
    320        node = node->next_sibling;
    321    }
    322    uncheck_options(options_node);
    323 
    324    sal_strcpy(autocomplete_string[unit],"");
    325 
    326    if (num_of_suggestions > 0 && token_idx == node_depth &&
    327        sal_strlen(input) > 0 && input[sal_strlen(input)-1] != ' ' &&
    328        input[sal_strlen(input)-1] != '=') {
    329            sal_strncat(autocomplete_string[unit]," ", AUTOCOMPLETE_MAX_STRING_LEN - sal_strlen(autocomplete_string[unit]) - 1);
    330    }
    331 
    332    if (num_of_suggestions > 1) {
    333        ioctl(0, TIOCGWINSZ, &window_size);
    334        window_len = window_size.ws_col;
    335        sal_printf("\n");
    336        token = strtok(str_to_print, s);
    337        while( token != NULL )
    338        {
    339            accumulative_line_len += max_autocomplete_str_len;
    340            if (accumulative_line_len >= window_len) {
    341                sal_printf("\n");
    342                accumulative_line_len = max_autocomplete_str_len;
    343            }
    344            sal_printf("%*s", -max_autocomplete_str_len, token);
    345            token = strtok(NULL, s);
    346        }
    347        sal_printf("\n");
    348        sal_printf("%s%s", prompt, input);
    349    }
    350    sal_strncat(autocomplete_string[unit], common_prefix + sal_strlen(prefix), AUTOCOMPLETE_MAX_STRING_LEN - sal_strlen(autocomplete_string[unit]) - 1);
    351 
    352    return autocomplete_string[unit];
    353 }
    354 
    355 #else /* INCLUDE_AUTOCOMPLETE */
    356 int _autocomplete_autocomplete_not_empty;
    357 #endif /* INCLUDE_AUTOCOMPLETE */
    358