command_trie_match_type_t cli_context_complete_command (cli_context_t *ctx, gchar ***argv, gint *argc, command_action_t **action, GList **suffixes) { gboolean auto_complete = configuration_get_boolean (ctx->config, "AUTO_UNIQUE_COMPLETE"); return command_trie_find (ctx->commands, argv, argc, auto_complete, action, suffixes); }
/* Given a command trie, look up the action that matches the input * passed as an array of input strings (typically argv). The input * array and number of items in the array (num) are passed as * pointers, such that they are updated to the position of the * matched action. * The matching action (if any) is stored in the action pointer, and * the state of the matching is returned by the function: * NONE - command mismatch * ACTION - matched an action, arguments might remain in input * SUBTRIE - matched a "parent command", with available subcommands * * If auto_complete is TRUE, unambiguous prefixes of commands are * automatically matched. * * If completions is not NULL, a list of possible completions is * stored in it. */ command_trie_match_type_t command_trie_find (command_trie_t *trie, gchar ***input, gint *num, gboolean auto_complete, command_action_t **action, GList **completions) { command_trie_t *node; command_trie_match_type_t retval = COMMAND_TRIE_MATCH_NONE; if ((node = command_trie_find_node (trie, **input, auto_complete, completions))) { (*input) ++; (*num) --; if (node->match.type == COMMAND_TRIE_MATCH_ACTION) { *action = node->match.action; retval = COMMAND_TRIE_MATCH_ACTION; } else if (node->match.type == COMMAND_TRIE_MATCH_SUBTRIE) { if (*num == 0) { *action = node->match.action; retval = COMMAND_TRIE_MATCH_SUBTRIE; } else { retval = command_trie_find (node->match.subtrie, input, num, auto_complete, action, completions); } } } return retval; }
void command_dispatch (cli_infos_t *infos, gint in_argc, gchar **in_argv) { command_action_t *action; command_trie_match_type_t match; gint argc; gchar **argv; gboolean auto_complete; /* The arguments will be updated by command_trie_find. */ argc = in_argc; argv = in_argv; auto_complete = configuration_get_boolean (infos->config, "AUTO_UNIQUE_COMPLETE"); match = command_trie_find (infos->commands, &argv, &argc, auto_complete, &action); if (match == COMMAND_TRIE_MATCH_ACTION) { gboolean help; gboolean need_io; command_context_t *ctx; /* Include one command token as a workaround for the bug that * the option parser does not parse commands starting with a * flag properly (e.g. "-p foo arg1"). Will be skipped by the * command utils. */ ctx = init_context_from_args (action->argdefs, argc + 1, argv - 1); ctx->name = g_strdup (action->name); if (command_flag_boolean_get (ctx, "help", &help) && help) { /* Help flag passed, bypass action and show help */ /* FIXME(g): select aliasnames list if it's an alias */ help_command (infos, infos->cmdnames, in_argv, in_argc, CMD_TYPE_COMMAND); } else if (command_runnable (infos, action)) { /* All fine, run the command */ cli_infos_loop_suspend (infos); need_io = action->callback (infos, ctx); if (!need_io) { cli_infos_loop_resume (infos); } } command_context_free (ctx); } else { /* Call help to print the "no such command" error */ help_command (infos, infos->cmdnames, in_argv, in_argc, CMD_TYPE_COMMAND); } }