X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=play.c;h=1ab4010160cac7e22988111d361de5e745dcd75c;hp=108db598a51ebb28f72cb03a10c31ebfcb44ca6e;hb=89633512b2bfe6b903341fb12bfab65510ef0e9d;hpb=efad222b6321fe7964d89c1d28c3b4ff05873eca diff --git a/play.c b/play.c index 108db598..1ab40101 100644 --- a/play.c +++ b/play.c @@ -7,12 +7,14 @@ /** \file play.c Paraslash's standalone player. */ #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" @@ -36,6 +38,9 @@ * Playlist handling is done exclusively in play context. */ +/** Array of error strings. */ +DEFINE_PARA_ERRLIST; + /** * Describes a request to change the state of para_play. * @@ -95,8 +100,15 @@ struct play_task { char *afhi_txt; }; -/** Initialize the array of errors for para_play. */ -INIT_PLAY_ERRLISTS; +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); @@ -653,24 +665,6 @@ static char **get_mapped_keyseqs(void) return result; } -#include "play.command_list.h" - -typedef int play_command_handler_t(struct play_task *, int, char**); -static play_command_handler_t PLAY_COMMAND_HANDLERS; - -/* defines one command of para_play */ -struct pp_command { - const char *name; - play_command_handler_t *handler; - const char *description; - const char *usage; - const char *help; -}; - -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 +687,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) { @@ -709,72 +710,74 @@ static void detach_stdout(struct play_task *pt) btr_remove_node(&pt->btrn); } -static int com_quit(struct play_task *pt, int argc, __a_unused char **argv) +static int com_quit(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { - if (argc != 1) - return -E_PLAY_SYNTAX; pt->rq = CRT_TERM_RQ; return 0; } +EXPORT_PLAY_CMD_HANDLER(quit); -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); - 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); + 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); - 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) +static int com_info(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { char *buf; size_t sz; static char dflt[] = "[no information available]"; - if (argc != 1) - return -E_PLAY_SYNTAX; sz = xasprintf(&buf, "playlist_pos: %u\npath: %s\n", pt->current_file, conf.inputs[pt->current_file]); btr_add_output(buf, sz, pt->btrn); @@ -782,26 +785,25 @@ static int com_info(struct play_task *pt, int argc, __a_unused char **argv) btr_add_output_dont_free(buf, strlen(buf), pt->btrn); return 0; } +EXPORT_PLAY_CMD_HANDLER(info); static void list_file(struct play_task *pt, int num) { char *buf; size_t sz; - sz = xasprintf(&buf, "%s %4u %s\n", num == pt->current_file? + sz = xasprintf(&buf, "%s %4d %s\n", num == pt->current_file? "*" : " ", num, conf.inputs[num]); btr_add_output(buf, sz, pt->btrn); } -static int com_tasks(struct play_task *pt, int argc, __a_unused char **argv) +static int com_tasks(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { static char state; char *buf; size_t sz; - if (argc != 1) - return -E_PLAY_SYNTAX; - buf = get_task_list(&sched); btr_add_output(buf, strlen(buf), pt->btrn); state = get_playback_state(pt); @@ -809,36 +811,34 @@ static int com_tasks(struct play_task *pt, int argc, __a_unused char **argv) btr_add_output(buf, sz, pt->btrn); return 0; } +EXPORT_PLAY_CMD_HANDLER(tasks); -static int com_ls(struct play_task *pt, int argc, char **argv) +static int com_ls(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { - int i, j, ret; + int i; - if (argc == 1) { - FOR_EACH_PLAYLIST_FILE(i) - list_file(pt, i); - return 0; - } - for (j = 1; j < argc; j++) { - FOR_EACH_PLAYLIST_FILE(i) { - ret = fnmatch(argv[j], conf.inputs[i], 0); - if (ret == 0) /* match */ - list_file(pt, i); - } - } + FOR_EACH_PLAYLIST_FILE(i) + list_file(pt, i); return 0; } +EXPORT_PLAY_CMD_HANDLER(ls); -static int com_play(struct play_task *pt, int argc, char **argv) +static int com_play(struct play_task *pt, struct lls_parse_result *lpr) { int32_t x; int ret; - char state; + char state, *errctx; - if (argc > 2) - return -E_PLAY_SYNTAX; + 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; + } state = get_playback_state(pt); - if (argc == 1) { + if (lls_num_inputs(lpr) == 0) { if (state == 'P') return 0; pt->next_file = pt->current_file; @@ -846,7 +846,7 @@ static int com_play(struct play_task *pt, int argc, char **argv) pt->playing = true; return 0; } - ret = para_atoi32(argv[1], &x); + ret = para_atoi32(lls_input(0, lpr), &x); if (ret < 0) return ret; if (x < 0 || x >= conf.inputs_num) @@ -856,14 +856,14 @@ static int com_play(struct play_task *pt, int argc, char **argv) pt->rq = CRT_FILE_CHANGE; return 0; } +EXPORT_PLAY_CMD_HANDLER(play); -static int com_pause(struct play_task *pt, int argc, __a_unused char **argv) +static int com_pause(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { char state; long unsigned seconds, ss; - if (argc != 1) - return -E_PLAY_SYNTAX; state = get_playback_state(pt); pt->playing = false; if (state != 'P') @@ -879,14 +879,13 @@ static int com_pause(struct play_task *pt, int argc, __a_unused char **argv) kill_stream(pt); return 0; } +EXPORT_PLAY_CMD_HANDLER(pause); -static int com_prev(struct play_task *pt, int argc, __a_unused char **argv) - +static int com_prev(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { int ret; - if (argc != 1) - return -E_PLAY_SYNTAX; ret = previous_valid_file(pt); if (ret < 0) return ret; @@ -896,13 +895,13 @@ static int com_prev(struct play_task *pt, int argc, __a_unused char **argv) pt->start_chunk = 0; return 0; } +EXPORT_PLAY_CMD_HANDLER(prev); -static int com_next(struct play_task *pt, int argc, __a_unused char **argv) +static int com_next(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { int ret; - if (argc != 1) - return -E_PLAY_SYNTAX; ret = next_valid_file(pt); if (ret < 0) return ret; @@ -912,37 +911,44 @@ static int com_next(struct play_task *pt, int argc, __a_unused char **argv) pt->start_chunk = 0; return 0; } +EXPORT_PLAY_CMD_HANDLER(next); -static int com_fg(struct play_task *pt, int argc, __a_unused char **argv) +static int com_fg(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { - if (argc != 1) - return -E_PLAY_SYNTAX; pt->background = false; return 0; } +EXPORT_PLAY_CMD_HANDLER(fg); -static int com_bg(struct play_task *pt, int argc, __a_unused char **argv) +static int com_bg(struct play_task *pt, + __a_unused struct lls_parse_result *lpr) { - if (argc != 1) - return -E_PLAY_SYNTAX; pt->background = true; return 0; } +EXPORT_PLAY_CMD_HANDLER(bg); -static int com_jmp(struct play_task *pt, int argc, char **argv) +static int com_jmp(struct play_task *pt, struct lls_parse_result *lpr) { int32_t percent; int ret; + char *errctx; - if (argc != 2) - return -E_PLAY_SYNTAX; - ret = para_atoi32(argv[1], &percent); + ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx)); + if (ret < 0) { + if (errctx) + PARA_ERROR_LOG("%s\n", errctx); + free(errctx); + return ret; + } + ret = para_atoi32(lls_input(0, lpr), &percent); if (ret < 0) return ret; if (percent < 0 || percent > 100) return -ERRNO_TO_PARA_ERROR(EINVAL); if (percent == 100) - return com_next(pt, 1, (char *[]){"next", NULL}); + return com_next(pt, NULL); if (pt->playing && !pt->fn.btrn) return 0; pt->start_chunk = percent * pt->num_chunks / 100; @@ -952,15 +958,22 @@ static int com_jmp(struct play_task *pt, int argc, char **argv) kill_stream(pt); return 0; } +EXPORT_PLAY_CMD_HANDLER(jmp); -static int com_ff(struct play_task *pt, int argc, char **argv) +static int com_ff(struct play_task *pt, struct lls_parse_result *lpr) { int32_t seconds; + char *errctx; int ret; - if (argc != 2) - return -E_PLAY_SYNTAX; - ret = para_atoi32(argv[1], &seconds); + ret = lls(lls_check_arg_count(lpr, 1, 1, &errctx)); + if (ret < 0) { + if (errctx) + PARA_ERROR_LOG("%s\n", errctx); + free(errctx); + return ret; + } + ret = para_atoi32(lls_input(0, lpr), &seconds); if (ret < 0) return ret; if (pt->playing && !pt->fn.btrn) @@ -977,34 +990,38 @@ static int com_ff(struct play_task *pt, int argc, char **argv) kill_stream(pt); return 0; } +EXPORT_PLAY_CMD_HANDLER(ff); static int run_command(char *line, struct play_task *pt) { - int i, ret, argc; + int 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); - if (ret < 0) - PARA_WARNING_LOG("%s: %s\n", pt->background? - "" : argv[0], para_strerror(-ret)); - ret = 1; + ret = lls(lls_lookup_subcmd(argv[0], play_cmd_suite, &errctx)); + if (ret < 0) goto out; - } - PARA_WARNING_LOG("invalid command: %s\n", argv[0]); - ret = 0; + cmd = lls_cmd(ret, play_cmd_suite); + ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx)); + if (ret < 0) + goto out; + pci = lls_user_data(cmd); + ret = pci->handler(pt, lpr); + lls_free_parse_result(lpr, cmd); out: + if (errctx) + PARA_ERROR_LOG("%s\n", errctx); + free(errctx); free_argv(argv); return ret; }