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.
audiod_objs += audiod_cmd.lsg.o
server_objs += server_cmd.lsg.o
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))
# now prefix all objects with object dir
recv_objs := $(addprefix $(object_dir)/, $(recv_objs))
server_command_lists := $(lls_suite_dir)/server_cmd.lsg.man
audiod_command_lists := $(lls_suite_dir)/audiod_cmd.lsg.man
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)
$(man_dir)/para_server.1: $(server_command_lists)
$(man_dir)/para_audiod.1: $(audiod_command_lists)
para_audioc \
para_audiod \
para_audioc \
para_audiod \
para_server \
: LDFLAGS += $(lopsub_ldflags)
para_server \
: LDFLAGS += $(lopsub_ldflags)
PARA_ERROR(BAD_FILTER_OPTIONS, "invalid filter option given"), \
PARA_ERROR(BAD_LL, "invalid loglevel"), \
PARA_ERROR(BAD_PATH, "invalid path"), \
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"), \
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"), \
--- /dev/null
+[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]
+
#include <regex.h>
#include <fnmatch.h>
#include <signal.h>
#include <regex.h>
#include <fnmatch.h>
#include <signal.h>
+#include <inttypes.h>
+#include <lopsub.h>
#include "para.h"
#include "list.h"
#include "play.cmdline.h"
#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"
#include "error.h"
#include "ggo.h"
#include "buffer_tree.h"
+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
/* Activate the afh receiver. */
extern void afh_recv_init(struct receiver *r);
#undef AFH_RECEIVER
static struct pp_command pp_cmds[] = {DEFINE_PLAY_CMD_ARRAY};
#define FOR_EACH_COMMAND(c) for (c = 0; pp_cmds[c].name; c++)
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);
static struct i9e_completer pp_completers[];
I9E_DUMMY_COMPLETER(jmp);
result->matches = i9e_complete_commands(ci->word, pp_completers);
}
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)
{
static void attach_stdout(struct play_task *pt, const char *name)
{
-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, ret;
+ char *buf, *errctx;
+ 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);
}
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);
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);
- 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)
{
static int com_info(struct play_task *pt, int argc, __a_unused char **argv)
{
{
int i, ret, argc;
char **argv = NULL;
{
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);
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;
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));
- 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;
+ if (errctx)
+ PARA_ERROR_LOG("%s\n", errctx);
+ free(errctx);
free_argv(argv);
return ret;
}
free_argv(argv);
return ret;
}
SF: play.c
SN: list of commands
---
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
N: next
D: Load next file.
U: next