/* Dispatch actions according to program flags (NOT commands or * command options). */ void flag_dispatch (cli_infos_t *infos, gint in_argc, gchar **in_argv) { command_context_t *ctx; gboolean check; argument_t flagdefs[] = { { "help", 'h', 0, G_OPTION_ARG_NONE, NULL, _("Display this help and exit."), NULL }, { "version", 'v', 0, G_OPTION_ARG_NONE, NULL, _("Output version information and exit."), NULL }, { NULL } }; /* 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 (flagdefs, in_argc + 1, in_argv - 1); if (!ctx) { /* An error message has already been printed, so we just return. */ return; } if (command_flag_boolean_get (ctx, "help", &check) && check) { if (ctx->argc > 1) { help_command (infos, infos->cmdnames, ctx->argv + 1, ctx->argc - 1, CMD_TYPE_COMMAND); } else { /* FIXME: explain -h and -v flags here (reuse help_command code?) */ g_printf (_("usage: xmms2 [<command> [args]]\n\n")); g_printf (_("XMMS2 CLI, the awesome command-line XMMS2 client from the future, " "v" XMMS_VERSION ".\n\n")); g_printf (_("If given a command, runs it inline and exit.\n")); g_printf (_("If not, enters a shell-like interface to execute commands.\n\n")); g_printf (_("Type 'help <command>' for detailed help about a command.\n")); } } else if (command_flag_boolean_get (ctx, "version", &check) && check) { g_printf (_("XMMS2 CLI version " XMMS_VERSION "\n")); g_printf (_("Copyright (C) 2008 XMMS2 Team\n")); g_printf (_("This is free software; see the source for copying conditions.\n")); g_printf (_("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n" "PARTICULAR PURPOSE.\n")); /* FIXME: compiled against? use RL_READLINE_VERSION? */ g_printf (_(" Using readline version %s\n"), rl_library_version); } else { /* Call help to print the "no such command" error */ /* FIXME: Could be a more helpful "invalid flag"?*/ help_command (infos, infos->cmdnames, in_argv, in_argc, CMD_TYPE_COMMAND); } command_context_free (ctx); }
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); } }
/* Parse the argv array with GOptionContext, using the given argument * definitions, and return a command context structure containing * argument values. * Note: The lib doesn't like argv starting with a flag, so keep a * token before that to avoid problems. * * The passed argv should be an array of length argc+1. (So that a terminating * NULL-pointer can be added in argv[argc].) */ static command_context_t * init_context_from_args (argument_t *argdefs, gint argc, gchar **argv) { command_context_t *ctx; GOptionContext *context; GError *error = NULL; gint i; ctx = command_context_init (argc, argv); for (i = 0; argdefs && argdefs[i].long_name; ++i) { command_argument_t *arg = g_new (command_argument_t, 1); switch (argdefs[i].arg) { case G_OPTION_ARG_NONE: arg->type = COMMAND_ARGUMENT_TYPE_BOOLEAN; arg->value.vbool = FALSE; argdefs[i].arg_data = &arg->value.vbool; break; case G_OPTION_ARG_INT: arg->type = COMMAND_ARGUMENT_TYPE_INT; arg->value.vint = -1; argdefs[i].arg_data = &arg->value.vint; break; case G_OPTION_ARG_STRING: arg->type = COMMAND_ARGUMENT_TYPE_STRING; arg->value.vstring = NULL; argdefs[i].arg_data = &arg->value.vstring; break; case G_OPTION_ARG_STRING_ARRAY: arg->type = COMMAND_ARGUMENT_TYPE_STRING_ARRAY; arg->value.vstringv = NULL; argdefs[i].arg_data = &arg->value.vstringv; break; default: g_printf (_("Trying to register a flag '%s' of invalid type!"), argdefs[i].long_name); break; } g_hash_table_insert (ctx->flags, g_strdup (argdefs[i].long_name), arg); } context = g_option_context_new (NULL); g_option_context_set_help_enabled (context, FALSE); /* runs exit(0)! */ g_option_context_set_ignore_unknown_options (context, TRUE); g_option_context_add_main_entries (context, argdefs, NULL); g_option_context_parse (context, &ctx->argc, &ctx->argv, &error); g_option_context_free (context); if (error) { g_printf (_("Error: %s\n"), error->message); g_error_free (error); command_context_free (ctx); return NULL; } /* strip --, check for unknown options before it */ /* FIXME: We do not parse options elsewhere, do we? */ for (i = 0; i < ctx->argc; i++) { if (strcmp (ctx->argv[i], "--") == 0) { break; } if (ctx->argv[i][0] == '-' && ctx->argv[i][1] != '\0' && !(ctx->argv[i][1] >= '0' && ctx->argv[i][1] <= '9')) { g_printf (_("Error: Unknown option '%s'\n"), ctx->argv[i]); command_context_free (ctx); return NULL; } } if (i != ctx->argc) { for (i++; i < ctx->argc; i++) { argv[i-1] = argv[i]; } ctx->argc--; } /* Some functions rely on NULL-termination. */ ctx->argv[ctx->argc] = NULL; return ctx; }