diff --git a/doc/vitunes.1 b/doc/vitunes.1 index 7495bef..ca45c0b 100644 --- a/doc/vitunes.1 +++ b/doc/vitunes.1 @@ -235,6 +235,14 @@ section for a complete listing. More detailed usage information and examples for each e-command can be obtained by issuing: .Dl $ vitunes -e help command-name +.Pp +Note that abbreviations are also supported. +That is, entering any non-ambiguous abbreviation of an e-command will also +execute the e-command. +.Bd -literal -offset indent +$ vitunes -e a ~/music +vitunes: Ambiguous e-command 'a'. Matches: add addurl +.Ed .Sh RUN-TIME COMMANDS Below is a listing of all run-time commands supported by .Nm . @@ -243,9 +251,7 @@ All commands are entered by typing ':' followed by the command name and any parameters (just like in .Xr vi 1 ). .Pp -Note that abbreviations are also supported. -That is, entering any non-ambiguous abbreviation of a command name will also -execute the command. +As with e-commands, abbreviations are also supported. .Bl -tag -width Ds .It Pf : Ic bind Ar action Ar keycode This will bind the action specified by diff --git a/ecmd.c b/ecmd.c index eb0fbdb..8c3e614 100644 --- a/ecmd.c +++ b/ecmd.c @@ -17,6 +17,20 @@ #include "ecmd.h" +/* set of e-commands */ +static const struct ecmd *ecmdtab[] = { + &ecmd_add, + &ecmd_addurl, + &ecmd_check, + &ecmd_flush, + &ecmd_help, + &ecmd_init, + &ecmd_rmfile, + &ecmd_tag, + &ecmd_update, +}; +static const int ecmdtab_size = sizeof ecmdtab / sizeof ecmdtab[0]; + static int ecmd_parse(const struct ecmd *ecmd, int argc, char ***argv) { @@ -45,49 +59,79 @@ ecmd_parse(const struct ecmd *ecmd, int argc, char ***argv) if (ecmd->args_upper >= 0 && argc > ecmd->args_upper) return -1; - /* return updated (no name) number of arguments */ + /* return updated number of arguments */ return argc; } +static void +ecmd_print_ambiguous(const char *ecmd) +{ + int i; + + fprintf(stderr, "%s: Ambiguous e-command '%s'. Matches: ", progname, ecmd); + for (i = 0; i < ecmdtab_size; i++) { + if (strncmp(ecmd, ecmdtab[i]->name, strlen(ecmd)) != 0) + continue; + fprintf(stderr, "%s ", ecmdtab[i]->name); + } + fputs("\n", stderr); +} + +const char * +ecmd_get_names(void) +{ + static int i = 0; + const struct ecmd *ecmdp; + + if (i == ecmdtab_size) + return (NULL); + + ecmdp = ecmdtab[i++]; + return (ecmdp->name); +} + int ecmd_exec(const char *ecmd, int argc, char **argv) { - /* set of e-commands */ - static const struct ecmd *ecmdtab[] = { - &ecmd_add, - &ecmd_addurl, - &ecmd_check, - &ecmd_flush, - &ecmd_help, - &ecmd_init, - &ecmd_rmfile, - &ecmd_tag, - &ecmd_update, - }; - static const int ecmdtab_size = sizeof ecmdtab / sizeof ecmdtab[0]; - int i; + bool ambiguous = false; + int i; + const struct ecmd *ecmdp = NULL; - /* search for e-command (first by name and then by alias) */ + /* search for e-command (first by name and then by abbreviation) */ for (i = 0; i < ecmdtab_size; i++) { - if (strcmp(ecmd, ecmdtab[i]->name) == 0) + /* exact match */ + if (strcmp(ecmd, ecmdtab[i]->name) == 0) { + ecmdp = ecmdtab[i]; break; - if (ecmdtab[i]->alias != NULL && strcmp(ecmd, ecmdtab[i]->alias) == 0) + } + /* abbreviation match */ + if (strncmp(ecmd, ecmdtab[i]->name, strlen(ecmd)) != 0) + continue; + if (ecmdp != NULL) { + ambiguous = true; break; + } + ecmdp = ecmdtab[i]; } /* not found; bail out */ - if (i == ecmdtab_size) { + if (ecmdp == NULL) { warnx("Unknown e-command '%s'. See 'vitunes -e help' for list.", ecmd); return -1; } + /* ambiguous e-command */ + if (ambiguous) { + ecmd_print_ambiguous(ecmd); + return -1; + } /* parse e-command arguments */ - if ((argc = ecmd_parse(ecmdtab[i], argc, &argv)) == -1) { - fprintf(stderr, "usage: %s -e %s %s\n", progname, ecmdtab[i]->name, - ecmdtab[i]->usage != NULL ? ecmdtab[i]->usage : ""); + if ((argc = ecmd_parse(ecmdp, argc, &argv)) == -1) { + fprintf(stderr, "usage: %s -e %s %s\n", progname, ecmdp->name, + ecmdp->usage != NULL ? ecmdp->usage : ""); return 1; } /* finally execute it */ - ecmdtab[i]->exec(argc, argv); + ecmdp->exec(argc, argv); return 0; } diff --git a/ecmd.h b/ecmd.h index 95c4a31..df2eea6 100644 --- a/ecmd.h +++ b/ecmd.h @@ -19,6 +19,7 @@ #define ECMD_H #include +#include #include #include #include @@ -27,7 +28,6 @@ struct ecmd { const char *name; - const char *alias; /* may be NULL */ const char *usage; /* may be NULL */ int args_lower; /* minimum number of arguments */ int args_upper; /* negative number means no limit */ @@ -46,6 +46,7 @@ extern const struct ecmd ecmd_rmfile; extern const struct ecmd ecmd_tag; extern const struct ecmd ecmd_update; -int ecmd_exec(const char *ecmd, int argc, char **argv); +const char *ecmd_get_names(void); +int ecmd_exec(const char *ecmd, int argc, char **argv); #endif diff --git a/ecmd_add.c b/ecmd_add.c index 882d3d2..284567f 100644 --- a/ecmd_add.c +++ b/ecmd_add.c @@ -34,7 +34,7 @@ ecmd_add_exec(UNUSED int argc, char **argv) } const struct ecmd ecmd_add = { - "add", NULL, + "add", "path [...]", 1, -1, NULL, diff --git a/ecmd_addurl.c b/ecmd_addurl.c index bb58717..f886c95 100644 --- a/ecmd_addurl.c +++ b/ecmd_addurl.c @@ -94,7 +94,7 @@ ecmd_addurl_exec(UNUSED int argc, char **argv) } const struct ecmd ecmd_addurl = { - "addurl", NULL, + "addurl", "URL|path", 1, 1, NULL, diff --git a/ecmd_check.c b/ecmd_check.c index dabfb49..39c7854 100644 --- a/ecmd_check.c +++ b/ecmd_check.c @@ -151,7 +151,7 @@ ecmd_check_exec(int argc, char **argv) } const struct ecmd ecmd_check = { - "check", NULL, + "check", "-d | -r | -s path [...]", 1, -1, ecmd_check_parse, diff --git a/ecmd_flush.c b/ecmd_flush.c index 6eeb158..fe7a0f2 100644 --- a/ecmd_flush.c +++ b/ecmd_flush.c @@ -55,7 +55,7 @@ ecmd_flush_exec(UNUSED int argc, UNUSED char **argv) } const struct ecmd ecmd_flush = { - "flush", NULL, + "flush", "[-t format]", 0, 0, ecmd_flush_parse, diff --git a/ecmd_help.c b/ecmd_help.c index ad85528..66e687a 100644 --- a/ecmd_help.c +++ b/ecmd_help.c @@ -26,30 +26,19 @@ static void ecmd_help_exec(UNUSED int argc, char **argv) { - char *man_args[3]; + char *man_args[3]; + const char *name; /* no help requested for a specific command, give a list of all e-cmds */ if (argc == 0) { - printf("\ -The following is a list of e-commands supported by vitunes.\n\ -Each command is executed by doing:\n\ - $ vitunes -e COMMAND [args ...]\n\ -The complete manual for each can be obtained by doing:\n\ - $ vitunes -e help COMMAND\n\ -The list of available commands are:\n\n\ - Command Description\n\ - ------- ------------------------------------------------------------\n\ - add Add files to the database.\n\ - addurl Add URL (or non-file playable item) to the database.\n\ - check Check files for meta-information.\n\ - flush Output the contents of the database to stdout.\n\ - help This command.\n\ - init Initialize the media database.\n\ - rm Remove a file or a URL from the database.\n\ - rmfile Alias for \"rm\".\n\ - tag Set the meta-information tags in media files.\n\ - update Update all files in the database.\n\ -"); + printf("Available e-commands: "); + while ((name = ecmd_get_names()) != NULL) + printf("%s ", name); + puts("\n"); + printf("Each is executed by doing:\n" + "$ vitunes -e e-command [...]\n" + "The complete manual for each can be obtained by doing:\n" + "$ vitunes -e help e-command\n"); return; } @@ -69,7 +58,7 @@ The list of available commands are:\n\n\ } const struct ecmd ecmd_help = { - "help", NULL, + "help", "[command]", 0, 1, NULL, diff --git a/ecmd_init.c b/ecmd_init.c index b0857dc..921dd71 100644 --- a/ecmd_init.c +++ b/ecmd_init.c @@ -31,7 +31,7 @@ ecmd_init_exec(UNUSED int argc, UNUSED char **argv) } const struct ecmd ecmd_init = { - "init", NULL, + "init", NULL, 0, 0, NULL, diff --git a/ecmd_rmfile.c b/ecmd_rmfile.c index 39af3cf..f897194 100644 --- a/ecmd_rmfile.c +++ b/ecmd_rmfile.c @@ -86,7 +86,7 @@ ecmd_rmfile_exec(UNUSED int argc, char **argv) } const struct ecmd ecmd_rmfile = { - "rmfile", "rm", + "rmfile", "[-f] URL|path", 1, 1, ecmd_rmfile_parse, diff --git a/ecmd_tag.c b/ecmd_tag.c index d17c7cd..068801d 100644 --- a/ecmd_tag.c +++ b/ecmd_tag.c @@ -144,7 +144,7 @@ ecmd_tag_exec(int argc, char **argv) } const struct ecmd ecmd_tag = { - "tag", NULL, + "tag", "[-A album] [-T track] [-a artist] [-c comment] [-g genre] [-t title]\n\ \t[-y year] path [...]", 1, -1, diff --git a/ecmd_update.c b/ecmd_update.c index 877b1e6..06a7293 100644 --- a/ecmd_update.c +++ b/ecmd_update.c @@ -62,7 +62,7 @@ ecmd_update_exec(UNUSED int argc, UNUSED char **argv) } const struct ecmd ecmd_update = { - "update", NULL, + "update", "[-fs]", 0, 0, ecmd_update_parse,