From: Andre Noll Date: Sun, 10 Apr 2016 20:02:10 +0000 (+0200) Subject: play: Link against lopsub and convert com_help() to lopsub. X-Git-Tag: v0.6.0~2^2~51 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=dbb31185345c74b0fb1f475d17594e94ec30db5c play: Link against lopsub and convert com_help() to lopsub. This introduces the play_cmd suite for the subcommands of para_play, like play, pause, fg, bg, etc. The new suite contains only the "help" subcommand so far. Other commands will be converted one by one in subsequent patches. We make use of the lopsub user_data feature to store a pointer to the command handler in the lls_command structure generated by lopsubgen. This pointer is initialized by the new EXPORT_PLAY_CMD_HANDLER macro in play.c. The suite has no supercommand, therefore lopsubgen adds a special "unavailable" identifier to play.lsg.h. We must therefore provide a dummy completer for the fake supercommand. Until all subcommands are converted, the run_command() and com_help() subcommand need to iterate over two command lists. Afterwards, this compatibility code can be removed. --- diff --git a/Makefile.real b/Makefile.real index 8aa10a6e..53fa22fe 100644 --- a/Makefile.real +++ b/Makefile.real @@ -47,6 +47,7 @@ m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(executables))) audiod_objs += audiod_cmd.lsg.o server_objs += server_cmd.lsg.o +play_objs += play_cmd.lsg.o # now prefix all objects with object dir recv_objs := $(addprefix $(object_dir)/, $(recv_objs)) @@ -176,7 +177,7 @@ $(cmdlist_dir)/audiod.completion.h \ server_command_lists := $(lls_suite_dir)/server_cmd.lsg.man audiod_command_lists := $(lls_suite_dir)/audiod_cmd.lsg.man -play_command_lists := $(cmdlist_dir)/play.command_list.man +play_command_lists := $(lls_suite_dir)/play_cmd.lsg.man $(man_dir)/para_server.1: $(server_command_lists) $(man_dir)/para_audiod.1: $(audiod_command_lists) @@ -320,6 +321,7 @@ para_fade \ para_audioc \ para_audiod \ +para_play \ para_server \ : LDFLAGS += $(lopsub_ldflags) diff --git a/error.h b/error.h index 346ef50f..a4038d5c 100644 --- a/error.h +++ b/error.h @@ -63,7 +63,6 @@ PARA_ERROR(BAD_FILTER_OPTIONS, "invalid filter option given"), \ PARA_ERROR(BAD_LL, "invalid loglevel"), \ PARA_ERROR(BAD_PATH, "invalid path"), \ - PARA_ERROR(BAD_PLAY_CMD, "invalid command"), \ PARA_ERROR(BAD_PRIVATE_KEY, "invalid private key"), \ PARA_ERROR(BAD_SAMPLE_FORMAT, "sample format not supported"), \ PARA_ERROR(BAD_SAMPLERATE, "sample rate not supported"), \ diff --git a/m4/lls/play_cmd.suite.m4 b/m4/lls/play_cmd.suite.m4 new file mode 100644 index 00000000..50727c94 --- /dev/null +++ b/m4/lls/play_cmd.suite.m4 @@ -0,0 +1,16 @@ +[suite play_cmd] +caption = list of commands +[subcommand help] + purpose = list commands or keybindings, or print command-specific help + non-opts-name = [command] + [description] + + This command acts differently depending on whether it is executed in + command mode or in insert mode. + + In command mode, the help command prints the list of defined + keybindings. In insert mode, if no argument is given, it prints the + list of available commands. When called with the name of a command + as first argument, it prints the description of this command. + [/description] + diff --git a/play.c b/play.c index fac551aa..6fe66678 100644 --- a/play.c +++ b/play.c @@ -9,10 +9,13 @@ #include #include #include +#include +#include #include "para.h" #include "list.h" #include "play.cmdline.h" +#include "play_cmd.lsg.h" #include "error.h" #include "ggo.h" #include "buffer_tree.h" @@ -98,6 +101,16 @@ struct play_task { char *afhi_txt; }; +typedef int (*play_cmd_handler_t)(struct play_task *pt, + struct lls_parse_result *lpr); +struct play_command_info { + play_cmd_handler_t handler; +}; +#define EXPORT_PLAY_CMD_HANDLER(_cmd) \ + const struct play_command_info lsg_play_cmd_com_ ## _cmd ## _user_data = { \ + .handler = com_ ## _cmd \ + }; + /* Activate the afh receiver. */ extern void afh_recv_init(struct receiver *r); #undef AFH_RECEIVER @@ -670,7 +683,6 @@ struct pp_command { static struct pp_command pp_cmds[] = {DEFINE_PLAY_CMD_ARRAY}; #define FOR_EACH_COMMAND(c) for (c = 0; pp_cmds[c].name; c++) -#include "play.completion.h" static struct i9e_completer pp_completers[]; I9E_DUMMY_COMPLETER(jmp); @@ -693,7 +705,14 @@ static void help_completer(struct i9e_completion_info *ci, result->matches = i9e_complete_commands(ci->word, pp_completers); } -static struct i9e_completer pp_completers[] = {PLAY_COMPLETERS {.name = NULL}}; +I9E_DUMMY_COMPLETER(SUPERCOMMAND_UNAVAILABLE); +static struct i9e_completer pp_completers[] = { +#define LSG_PLAY_CMD_CMD(_name) {.name = #_name, \ + .completer = _name ## _completer} + LSG_PLAY_CMD_SUBCOMMANDS +#undef LSG_PLAY_CMD_CMD + {.name = NULL} +}; static void attach_stdout(struct play_task *pt, const char *name) { @@ -717,55 +736,63 @@ static int com_quit(struct play_task *pt, int argc, __a_unused char **argv) return 0; } -static int com_help(struct play_task *pt, int argc, char **argv) +static int com_help(struct play_task *pt, struct lls_parse_result *lpr) { - int i; - char *buf; + int i, ret; + char *buf, *errctx; size_t sz; + const struct lls_command *cmd; - if (argc > 2) - return -E_PLAY_SYNTAX; - if (argc < 2) { - if (pt->background) - FOR_EACH_COMMAND(i) { - sz = xasprintf(&buf, "%s\t%s\n", pp_cmds[i].name, - pp_cmds[i].description); + ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx)); + if (ret < 0) { + if (errctx) + PARA_ERROR_LOG("%s\n", errctx); + free(errctx); + return ret; + } + if (lls_num_inputs(lpr) == 0) { + if (pt->background) { + for (i = 1; (cmd = lls_cmd(i, play_cmd_suite)); i++) { + sz = xasprintf(&buf, "%s\t%s\n", + lls_command_name(cmd), lls_purpose(cmd)); btr_add_output(buf, sz, pt->btrn); } - else { - FOR_EACH_MAPPED_KEY(i) { - bool internal = is_internal_key(i); - int idx = get_key_map_idx(i); - char *seq = get_key_map_seq_safe(i); - char *cmd = get_key_map_cmd(i); - sz = xasprintf(&buf, - "%s key #%d: %s -> %s\n", - internal? "internal" : "user-defined", - idx, seq, cmd); + FOR_EACH_COMMAND(i) { + sz = xasprintf(&buf, "%s\t%s\n", pp_cmds[i].name, + pp_cmds[i].description); btr_add_output(buf, sz, pt->btrn); - free(seq); - free(cmd); } + return 0; + } + FOR_EACH_MAPPED_KEY(i) { + bool internal = is_internal_key(i); + int idx = get_key_map_idx(i); + char *seq = get_key_map_seq_safe(i); + char *kmc = get_key_map_cmd(i); + sz = xasprintf(&buf, "%s key #%d: %s -> %s\n", + internal? "internal" : "user-defined", + idx, seq, kmc); + btr_add_output(buf, sz, pt->btrn); + free(seq); + free(kmc); } return 0; } - FOR_EACH_COMMAND(i) { - if (strcmp(pp_cmds[i].name, argv[1])) - continue; - sz = xasprintf(&buf, - "NAME\n\t%s -- %s\n" - "SYNOPSIS\n\t%s\n" - "DESCRIPTION\n%s\n", - argv[1], - pp_cmds[i].description, - pp_cmds[i].usage, - pp_cmds[i].help - ); - btr_add_output(buf, sz, pt->btrn); - return 0; + ret = lls(lls_lookup_subcmd(lls_input(0, lpr), play_cmd_suite, + &errctx)); + if (ret < 0) { + if (errctx) + PARA_ERROR_LOG("%s\n", errctx); + free(errctx); + return ret; } - return -E_BAD_PLAY_CMD; + cmd = lls_cmd(ret, play_cmd_suite); + buf = lls_long_help(cmd); + assert(buf); + btr_add_output(buf, strlen(buf), pt->btrn); + return 0; } +EXPORT_PLAY_CMD_HANDLER(help); static int com_info(struct play_task *pt, int argc, __a_unused char **argv) { @@ -982,29 +1009,42 @@ static int run_command(char *line, struct play_task *pt) { int i, ret, argc; char **argv = NULL; + char *errctx = NULL; + const struct play_command_info *pci; + struct lls_parse_result *lpr; + const struct lls_command *cmd; attach_stdout(pt, __FUNCTION__); ret = create_argv(line, " ", &argv); - if (ret < 0) { - PARA_ERROR_LOG("parse error: %s\n", para_strerror(-ret)); - return 0; - } + if (ret < 0) + goto out; if (ret == 0) goto out; argc = ret; - FOR_EACH_COMMAND(i) { - if (strcmp(pp_cmds[i].name, argv[0])) - continue; - ret = pp_cmds[i].handler(pt, argc, argv); + + ret = lls(lls_lookup_subcmd(argv[0], play_cmd_suite, &errctx)); + if (ret >= 0) { + cmd = lls_cmd(ret, play_cmd_suite); + ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx)); if (ret < 0) - PARA_WARNING_LOG("%s: %s\n", pt->background? - "" : argv[0], para_strerror(-ret)); - ret = 1; - goto out; + goto out; + pci = lls_user_data(cmd); + ret = pci->handler(pt, lpr); + lls_free_parse_result(lpr, cmd); + } else { + FOR_EACH_COMMAND(i) { + if (strcmp(pp_cmds[i].name, argv[0])) + continue; + free(errctx); + errctx = NULL; + ret = pp_cmds[i].handler(pt, argc, argv); + break; + } } - PARA_WARNING_LOG("invalid command: %s\n", argv[0]); - ret = 0; out: + if (errctx) + PARA_ERROR_LOG("%s\n", errctx); + free(errctx); free_argv(argv); return ret; } diff --git a/play.cmd b/play.cmd index 459ad8cf..85b14211 100644 --- a/play.cmd +++ b/play.cmd @@ -2,14 +2,6 @@ BN: play SF: play.c SN: list of commands --- -N: help -D: Display command list or help for given command. -U: help [command] -H: This command acts differently depending on whether it is executed in command -H: mode or in insert mode. In command mode, the list of keybindings is printed. -H: In insert mode, if no command is given, the list of commands is shown. -H: Otherwise, the help for the given command is printed. ---- N: next D: Load next file. U: next