"Fossies" - the Fresh Open Source Software Archive

Member "glusterfs-8.2/cli/src/registry.c" (16 Sep 2020, 7423 Bytes) of package /linux/misc/glusterfs-8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "registry.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2    Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com>
    3    This file is part of GlusterFS.
    4 
    5    This file is licensed to you under your choice of the GNU Lesser
    6    General Public License, version 3 or any later version (LGPLv3 or
    7    later), or the GNU General Public License, version 2 (GPLv2), in all
    8    cases as published by the Free Software Foundation.
    9 */
   10 
   11 #include <stdio.h>
   12 #include <string.h>
   13 #include <stdlib.h>
   14 
   15 #include "cli.h"
   16 #include "cli-cmd.h"
   17 
   18 static int
   19 __is_spc(int ch)
   20 {
   21     if (ch == ' ')
   22         return 1;
   23     return 0;
   24 }
   25 
   26 static int
   27 __is_div(int ch)
   28 {
   29     switch (ch) {
   30         case '(':
   31         case ')':
   32         case '<':
   33         case '>':
   34         case '[':
   35         case ']':
   36         case '{':
   37         case '}':
   38         case '|':
   39             return 1;
   40     }
   41 
   42     return 0;
   43 }
   44 
   45 static int
   46 __is_word(const char *word)
   47 {
   48     return (!__is_div(*word) && !__is_spc(*word));
   49 }
   50 
   51 int
   52 counter_char(int ch)
   53 {
   54     switch (ch) {
   55         case '(':
   56             return ')';
   57         case '<':
   58             return '>';
   59         case '[':
   60             return ']';
   61         case '{':
   62             return '}';
   63     }
   64 
   65     return -1;
   66 }
   67 
   68 const char *
   69 __is_template_balanced(const char *template)
   70 {
   71     const char *trav = NULL;
   72     int ch = 0;
   73 
   74     trav = template;
   75 
   76     while (*trav) {
   77         ch = *trav;
   78 
   79         switch (ch) {
   80             case '<':
   81             case '(':
   82             case '[':
   83                 trav = __is_template_balanced(trav + 1);
   84                 if (!trav)
   85                     return NULL;
   86                 if (*trav != counter_char(ch))
   87                     return NULL;
   88                 break;
   89             case '>':
   90             case ')':
   91             case ']':
   92                 return trav;
   93         }
   94 
   95         trav++;
   96     }
   97 
   98     return trav;
   99 }
  100 
  101 int
  102 is_template_balanced(const char *template)
  103 {
  104     const char *trav = NULL;
  105 
  106     trav = __is_template_balanced(template);
  107     if (!trav || *trav)
  108         return -1;
  109 
  110     return 0;
  111 }
  112 
  113 int
  114 cli_cmd_token_count(const char *template)
  115 {
  116     int count = 0;
  117     const char *trav = NULL;
  118     int is_alnum = 0;
  119 
  120     for (trav = template; *trav; trav++) {
  121         switch (*trav) {
  122             case '<':
  123             case '>':
  124             case '(':
  125             case ')':
  126             case '[':
  127             case ']':
  128             case '{':
  129             case '}':
  130             case '|':
  131                 count++;
  132                 /* fall through */
  133             case ' ':
  134                 is_alnum = 0;
  135                 break;
  136             default:
  137                 if (!is_alnum) {
  138                     is_alnum = 1;
  139                     count++;
  140                 }
  141         }
  142     }
  143 
  144     return count + 1;
  145 }
  146 
  147 void
  148 cli_cmd_tokens_destroy(char **tokens)
  149 {
  150     char **tokenp = NULL;
  151 
  152     if (!tokens)
  153         return;
  154 
  155     tokenp = tokens;
  156     while (*tokenp) {
  157         free(*tokenp);
  158         tokenp++;
  159     }
  160 
  161     free(tokens);
  162 }
  163 
  164 int
  165 cli_cmd_tokens_fill(char **tokens, const char *template)
  166 {
  167     const char *trav = NULL;
  168     char **tokenp = NULL;
  169     char *token = NULL;
  170     int ret = 0;
  171     int ch = 0;
  172 
  173     tokenp = tokens;
  174 
  175     for (trav = template; *trav; trav++) {
  176         ch = *trav;
  177 
  178         if (__is_spc(ch))
  179             continue;
  180 
  181         if (__is_div(ch)) {
  182             token = calloc(2, 1);
  183             if (!token)
  184                 return -1;
  185             token[0] = ch;
  186 
  187             *tokenp = token;
  188             tokenp++;
  189 
  190             continue;
  191         }
  192 
  193         token = strdup(trav);
  194         *tokenp = token;
  195         tokenp++;
  196 
  197         for (token++; *token; token++) {
  198             if (__is_spc(*token) || __is_div(*token)) {
  199                 *token = 0;
  200                 break;
  201             }
  202             trav++;
  203         }
  204     }
  205 
  206     return ret;
  207 }
  208 
  209 char **
  210 cli_cmd_tokenize(const char *template)
  211 {
  212     char **tokens = NULL;
  213     int ret = 0;
  214     int count = 0;
  215 
  216     ret = is_template_balanced(template);
  217     if (ret)
  218         return NULL;
  219 
  220     count = cli_cmd_token_count(template);
  221     if (count <= 0)
  222         return NULL;
  223 
  224     tokens = calloc(count + 1, sizeof(char *));
  225     if (!tokens)
  226         return NULL;
  227 
  228     ret = cli_cmd_tokens_fill(tokens, template);
  229     if (ret)
  230         goto err;
  231 
  232     return tokens;
  233 err:
  234     cli_cmd_tokens_destroy(tokens);
  235     return NULL;
  236 }
  237 
  238 void *
  239 cli_getunamb(const char *tok, void **choices, cli_selector_t sel)
  240 {
  241     void **wcon = NULL;
  242     char *w = NULL;
  243     unsigned mn = 0;
  244     void *ret = NULL;
  245 
  246     if (!choices || !tok || !*tok)
  247         return NULL;
  248 
  249     for (wcon = choices; *wcon; wcon++) {
  250         w = strtail((char *)sel(*wcon), tok);
  251         if (!w)
  252             /* no match */
  253             continue;
  254         if (!*w)
  255             /* exact match */
  256             return *wcon;
  257 
  258         ret = *wcon;
  259         mn++;
  260     }
  261 
  262 #ifdef FORCE_MATCH_EXACT
  263     return NULL;
  264 #else
  265     return (mn == 1) ? ret : NULL;
  266 #endif
  267 }
  268 
  269 static const char *
  270 sel_cmd_word(void *wcon)
  271 {
  272     return ((struct cli_cmd_word *)wcon)->word;
  273 }
  274 
  275 struct cli_cmd_word *
  276 cli_cmd_nextword(struct cli_cmd_word *word, const char *token)
  277 {
  278     return (struct cli_cmd_word *)cli_getunamb(token, (void **)word->nextwords,
  279                                                sel_cmd_word);
  280 }
  281 
  282 struct cli_cmd_word *
  283 cli_cmd_newword(struct cli_cmd_word *word, const char *token)
  284 {
  285     struct cli_cmd_word **nextwords = NULL;
  286     struct cli_cmd_word *nextword = NULL;
  287 
  288     nextwords = realloc(word->nextwords,
  289                         (word->nextwords_cnt + 2) * sizeof(*nextwords));
  290     if (!nextwords)
  291         return NULL;
  292 
  293     word->nextwords = nextwords;
  294 
  295     nextword = calloc(1, sizeof(*nextword));
  296     if (!nextword)
  297         return NULL;
  298 
  299     nextword->word = strdup(token);
  300     if (!nextword->word) {
  301         free(nextword);
  302         return NULL;
  303     }
  304 
  305     nextword->tree = word->tree;
  306     nextwords[word->nextwords_cnt++] = nextword;
  307     nextwords[word->nextwords_cnt] = NULL;
  308 
  309     return nextword;
  310 }
  311 
  312 int
  313 cli_cmd_ingest(struct cli_cmd_tree *tree, char **tokens, cli_cmd_cbk_t *cbkfn,
  314                const char *desc, const char *pattern)
  315 {
  316     int ret = 0;
  317     char **tokenp = NULL;
  318     char *token = NULL;
  319     struct cli_cmd_word *word = NULL;
  320     struct cli_cmd_word *next = NULL;
  321 
  322     word = &tree->root;
  323 
  324     for (tokenp = tokens; (token = *tokenp); tokenp++) {
  325         if (!__is_word(token))
  326             break;
  327 
  328         next = cli_cmd_nextword(word, token);
  329         if (!next)
  330             next = cli_cmd_newword(word, token);
  331 
  332         word = next;
  333         if (!word)
  334             break;
  335     }
  336 
  337     if (!word)
  338         return -1;
  339 
  340     if (word->cbkfn) {
  341         /* warning - command already registered */
  342     }
  343 
  344     word->cbkfn = cbkfn;
  345     word->desc = desc;
  346     word->pattern = pattern;
  347 
  348     /* end of static strings in command template */
  349 
  350     /* TODO: autocompletion beyond this point is just "nice to have" */
  351 
  352     return ret;
  353 }
  354 
  355 int
  356 cli_cmd_register(struct cli_cmd_tree *tree, struct cli_cmd *cmd)
  357 {
  358     char **tokens = NULL;
  359     int ret = 0;
  360 
  361     GF_ASSERT(cmd);
  362 
  363     if (cmd->reg_cbk)
  364         cmd->reg_cbk(cmd);
  365 
  366     if (cmd->disable) {
  367         ret = 0;
  368         goto out;
  369     }
  370 
  371     tokens = cli_cmd_tokenize(cmd->pattern);
  372     if (!tokens) {
  373         ret = -1;
  374         goto out;
  375     }
  376 
  377     ret = cli_cmd_ingest(tree, tokens, cmd->cbk, cmd->desc, cmd->pattern);
  378     if (ret) {
  379         ret = -1;
  380         goto out;
  381     }
  382 
  383     ret = 0;
  384 
  385 out:
  386     if (tokens)
  387         cli_cmd_tokens_destroy(tokens);
  388 
  389     gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
  390     return ret;
  391 }