diff options
Diffstat (limited to 'cli/src/registry.c')
-rw-r--r-- | cli/src/registry.c | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/cli/src/registry.c b/cli/src/registry.c new file mode 100644 index 00000000000..0ced00787c8 --- /dev/null +++ b/cli/src/registry.c @@ -0,0 +1,386 @@ +/* + Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "cli.h" +#include "cli-cmd.h" + + +static int +__is_spc (int ch) +{ + if (ch == ' ') + return 1; + return 0; +} + + +static int +__is_div (int ch) +{ + switch (ch) { + case '(': + case ')': + case '<': + case '>': + case '[': + case ']': + case '{': + case '}': + case '|': + return 1; + } + + return 0; +} + + +static int +__is_word (const char *word) +{ + return (!__is_div (*word) && !__is_spc (*word)); +} + + +int +counter_char (int ch) +{ + switch (ch) { + case '(': + return ')'; + case '<': + return '>'; + case '[': + return ']'; + case '{': + return '}'; + } + + return -1; +} + + +const char * +__is_template_balanced (const char *template) +{ + const char *trav = NULL; + int ch = 0; + + trav = template; + + while (*trav) { + ch = *trav; + + switch (ch) { + case '<': + case '(': + case '[': + trav = __is_template_balanced (trav+1); + if (!trav) + return NULL; + if (*trav != counter_char (ch)) + return NULL; + break; + case '>': + case ')': + case ']': + return trav; + } + + trav++; + } + + return trav; +} + + +int +is_template_balanced (const char *template) +{ + const char *trav = NULL; + + trav = __is_template_balanced (template); + if (!trav || *trav) + return -1; + + return 0; +} + + +int +cli_cmd_token_count (const char *template) +{ + int count = 0; + const char *trav = NULL; + int is_alnum = 0; + + for (trav = template; *trav; trav++) { + switch (*trav) { + case '<': + case '>': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '|': + count++; + /* fall through */ + case ' ': + is_alnum = 0; + break; + default: + if (!is_alnum) { + is_alnum = 1; + count++; + } + } + } + + return count + 1; +} + + +void +cli_cmd_tokens_destroy (char **tokens) +{ + char **tokenp = NULL; + + if (!tokens) + return; + + tokenp = tokens; + while (*tokenp) { + free (*tokenp); + tokenp++; + } + + free (tokens); +} + + +int +cli_cmd_tokens_fill (char **tokens, const char *template) +{ + const char *trav = NULL; + char **tokenp = NULL; + char *token = NULL; + int ret = 0; + int ch = 0; + + tokenp = tokens; + + for (trav = template; *trav; trav++) { + ch = *trav; + + if (__is_spc (ch)) + continue; + + if (__is_div (ch)) { + token = calloc (2, 1); + if (!token) + return -1; + token[0] = ch; + + *tokenp = token; + tokenp++; + + continue; + } + + token = strdup (trav); + *tokenp = token; + tokenp++; + + for (token++; *token; token++) { + if (__is_spc (*token) || __is_div (*token)) { + *token = 0; + break; + } + trav++; + } + } + + return ret; +} + + +char ** +cli_cmd_tokenize (const char *template) +{ + char **tokens = NULL; + int ret = 0; + int count = 0; + + ret = is_template_balanced (template); + if (ret) + return NULL; + + count = cli_cmd_token_count (template); + if (count <= 0) + return NULL; + + tokens = calloc (count + 1, sizeof (char *)); + if (!tokens) + return NULL; + + ret = cli_cmd_tokens_fill (tokens, template); + if (ret) + goto err; + + return tokens; +err: + cli_cmd_tokens_destroy (tokens); + return NULL; +} + + +struct cli_cmd_word * +cli_cmd_nextword (struct cli_cmd_word *word, const char *token) +{ + struct cli_cmd_word *next = NULL; + struct cli_cmd_word **trav = NULL; + int ret = 0; + + if (!word->nextwords) + return NULL; + + for (trav = word->nextwords; (next = *trav); trav++) { + if (next->match) { +// ret = next->match (); + } else { + ret = strcmp (next->word, token); + } + + if (ret == 0) + break; + } + + return next; +} + + +struct cli_cmd_word * +cli_cmd_newword (struct cli_cmd_word *word, const char *token) +{ + struct cli_cmd_word **nextwords = NULL; + struct cli_cmd_word *nextword = NULL; + + nextwords = realloc (word->nextwords, + (word->nextwords_cnt + 2) * sizeof (*nextwords)); + if (!nextwords) + return NULL; + + word->nextwords = nextwords; + + nextword = calloc (1, sizeof (*nextword)); + if (!nextword) + return NULL; + + nextword->word = strdup (token); + if (!nextword->word) { + free (nextword); + return NULL; + } + + nextword->tree = word->tree; + nextwords[word->nextwords_cnt++] = nextword; + nextwords[word->nextwords_cnt] = NULL; + + return nextword; +} + + +int +cli_cmd_ingest (struct cli_cmd_tree *tree, char **tokens, cli_cmd_cbk_t *cbkfn) +{ + int ret = 0; + char **tokenp = NULL; + char *token = NULL; + struct cli_cmd_word *word = NULL; + struct cli_cmd_word *next = NULL; + + word = &tree->root; + + for (tokenp = tokens; (token = *tokenp); tokenp++) { + if (!__is_word (token)) + break; + + next = cli_cmd_nextword (word, token); + if (!next) + next = cli_cmd_newword (word, token); + + word = next; + if (!word) + break; + } + + if (!word) + return -1; + + if (word->cbkfn) { + /* warning - command already registered */ + } + + word->cbkfn = cbkfn; + + /* end of static strings in command template */ + + /* TODO: autocompletion beyond this point is just "nice to have" */ + + return ret; +} + + +int +cli_cmd_register (struct cli_cmd_tree *tree, const char *template, + cli_cmd_cbk_t cbk) +{ + char **tokens = NULL; + int ret = 0; + + if (!template) + return -1; + + tokens = cli_cmd_tokenize (template); + if (!tokens) + return -1; + + ret = cli_cmd_ingest (tree, tokens, cbk); + if (ret) + goto err; + + return 0; +err: + if (tokens) + cli_cmd_tokens_destroy (tokens); + + return ret; +} + |