summaryrefslogtreecommitdiffstats
path: root/cli/src/registry.c
diff options
context:
space:
mode:
Diffstat (limited to 'cli/src/registry.c')
-rw-r--r--cli/src/registry.c386
1 files changed, 386 insertions, 0 deletions
diff --git a/cli/src/registry.c b/cli/src/registry.c
new file mode 100644
index 00000000..0ced0078
--- /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;
+}
+