/* Serval DNA command-line functions Copyright (C) 2010-2013 Serval Project Inc. This program 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 2 of the License, or (at your option) any later version. This program 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "cli.h" #include "log.h" #include "serval.h" #include "rhizome.h" #include "strbuf_helpers.h" #include "dataformats.h" int cli_usage(const struct cli_schema *commands, XPRINTF xpf) { return cli_usage_args(0, NULL, commands, xpf); } int cli_usage_parsed(const struct cli_parsed *parsed, XPRINTF xpf) { if (parsed->varargi == -1) return cli_usage(parsed->commands, xpf); return cli_usage_args(parsed->argc - parsed->varargi, &parsed->args[parsed->varargi], parsed->commands, xpf); } int cli_usage_args(const int argc, const char *const *args, const struct cli_schema *commands, XPRINTF xpf) { unsigned cmd; int matched_any = 0; for (cmd = 0; commands[cmd].function; ++cmd) { int opt; const char *word; int matched = 1; for (opt = 0; matched && opt < argc && (word = commands[cmd].words[opt]); ++opt) if (strncmp(word, args[opt], strlen(args[opt])) != 0) matched = 0; if (matched) { matched_any = 1; for (opt = 0; (word = commands[cmd].words[opt]); ++opt) { if (word[0] == '|') ++word; xprintf(xpf, " %s", word); } xputc('\n', xpf); if (commands[cmd].description && commands[cmd].description[0]) xprintf(xpf, " %s\n", commands[cmd].description); } } if (!matched_any && argc) { strbuf b = strbuf_alloca(160); strbuf_append_argv(b, argc, args); xprintf(xpf, " No commands matching %s\n", strbuf_str(b)); } return 0; } /* Returns 0 if a command is matched and parsed, with the results of the parsing in the '*parsed' * structure. * * Returns 1 and logs an error if no command matches the argument list, contents of '*parsed' are * undefined. * * Returns 2 if the argument list is ambiguous, ie, matches more than one command, contents of * '*parsed' are undefined. * * Returns -1 and logs an error if the parsing fails due to an internal error (eg, malformed command * schema), contents of '*parsed' are undefined. * * @author Andrew Bettison */ int cli_parse(const int argc, const char *const *args, const struct cli_schema *commands, struct cli_parsed *parsed) { int ambiguous = 0; int matched_cmd = -1; int cmd; for (cmd = 0; commands[cmd].function; ++cmd) { struct cli_parsed cmdpa; memset(&cmdpa, 0, sizeof cmdpa); cmdpa.commands = commands; cmdpa.cmdi = cmd; cmdpa.args = args; cmdpa.argc = argc; cmdpa.labelc = 0; cmdpa.varargi = -1; const char *pattern = NULL; int arg = 0; unsigned opt = 0; while ((pattern = commands[cmd].words[opt])) { //DEBUGF("cmd=%d opt=%d pattern='%s' args[arg=%d]='%s'", cmd, opt, pattern, arg, arg < argc ? args[arg] : ""); unsigned patlen = strlen(pattern); if (cmdpa.varargi != -1) return WHYF("Internal error: commands[%d].word[%d]=\"%s\" - more words not allowed after \"...\"", cmd, opt, commands[cmd].words[opt]); /* These are the argument matching rules: * * "..." consumes all remaining arguments * * "word" consumes one argument that exactly matches "word", does not label it (this is the * "simple" case in the code below; all other rules label something that matched) * * "word1|word2|...|wordN" consumes one argument that exactly matches "word1" or "word2" etc. * or "wordN", labels it with the matched word (an empty alternative, eg "|word" does not * match an empty argument) * * (as a special case of the above rule, "|word" consumes one argument that exactly matches * "word" and labels it "word", but it appears in the help description as "word") * * "