cli: Add a new CLI wrapper
This new CLI wrapper introduces a command mode, like we are used from
Git for instance. The first argument specifies the command mode, which
is `memory` for the classic flashprog CLI. Alternatively to a first
argument, it can be called as `flashprog-cmd`. This will allow us to
add more CLI features that can be developed independently from the
classic CLI.
For instance, flashprog could then be called like this:
$ flashprog memory -p ch341a_spi
$ flashprog mem -p ch341a_spi
If no command mode is specified, we fall back to the classic CLI for
convenience. So this is also still possible:
$ flashprog -p ch341a_spi
Change-Id: I98cb110b47ebce52daf2e0972fc4565ef9d40242
Signed-off-by: Nico Huber <nico.h@gmx.de>
diff --git a/Makefile b/Makefile
index 79601fc..a75c280 100644
--- a/Makefile
+++ b/Makefile
@@ -401,7 +401,7 @@
###############################################################################
# Frontend related stuff.
-CLI_OBJS = cli_classic.o cli_output.o cli_common.o print.o
+CLI_OBJS = cli.o cli_classic.o cli_output.o cli_common.o print.o
# By default version information will be fetched from Git if available.
# Otherwise, versioninfo.inc stores the metadata required to build a
diff --git a/cli.c b/cli.c
new file mode 100644
index 0000000..82723fd
--- /dev/null
+++ b/cli.c
@@ -0,0 +1,100 @@
+/*
+ * This file is part of the flashprog project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "flash.h"
+#include "cli.h"
+
+static const char *const command_prefix = "flashprog-";
+
+static const struct {
+ const char *name;
+ int (*main)(int argc, char *argv[]);
+} commands[] = {
+ { "mem", flashprog_classic_main },
+ { "memory", flashprog_classic_main },
+};
+
+static void usage(const char *const name)
+{
+ fprintf(stderr, "\nUsage: %s [<command>] [<argument>...]\n", name);
+ fprintf(stderr, "\nWhere <command> can be\n\n"
+ " mem[ory] Standard memory operations\n"
+ " (read/erase/write/verify)\n"
+ "\n"
+ "The default is 'memory'. See `%s <command> --help`\n"
+ "for further instructions.\n\n", name);
+ exit(1);
+}
+
+static int combine_argv01(char *argv[])
+{
+ const size_t len = strlen(argv[0]) + 1 + strlen(argv[1]) + 1;
+ char *const argv0 = malloc(len);
+ if (!argv0) {
+ fprintf(stderr, "Out of memory!\n");
+ return 1;
+ }
+ snprintf(argv0, len, "%s %s", argv[0], argv[1]);
+ argv[1] = argv0;
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *cmd;
+ size_t i;
+
+ print_version();
+ print_banner();
+
+ if (argc < 1)
+ usage("flashprog");
+
+ /* Turn something like `./flashprog-cmd` into `flashprog-cmd`: */
+ const char *const slash = strrchr(argv[0], '/');
+ if (slash)
+ cmd = slash + 1;
+ else
+ cmd = argv[0];
+
+ /* Turn `flashprog-cmd` into `cmd`: */
+ if (!strncmp(cmd, command_prefix, strlen(command_prefix)))
+ cmd += strlen(command_prefix);
+
+ /* Run `cmd` if found: */
+ for (i = 0; i < ARRAY_SIZE(commands); ++i) {
+ if (!strcmp(cmd, commands[i].name))
+ return commands[i].main(argc, argv);
+ }
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ /* Try to find command as first argument in argv[1]: */
+ for (i = 0; i < ARRAY_SIZE(commands); ++i) {
+ if (!strcmp(argv[1], commands[i].name)) {
+ /* Squash argv[0] into argv[1]: */
+ if (combine_argv01(argv))
+ return 1;
+ return commands[i].main(argc - 1, argv + 1);
+ }
+ }
+
+ /* We're still here? Fall back to classic cli: */
+ return flashprog_classic_main(argc, argv);
+}
diff --git a/cli_classic.c b/cli_classic.c
index 2f16ef6..26253dc 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -181,7 +181,7 @@
return true;
}
-int main(int argc, char *argv[])
+int flashprog_classic_main(int argc, char *argv[])
{
const struct flashchip *chip = NULL;
/* Probe for up to eight flash chips. */
diff --git a/include/cli.h b/include/cli.h
index b7a0340..1ba442b 100644
--- a/include/cli.h
+++ b/include/cli.h
@@ -62,4 +62,6 @@
int cli_init(void);
+int flashprog_classic_main(int argc, char *argv[]);
+
#endif
diff --git a/meson.build b/meson.build
index ddb705a..e8dd525 100644
--- a/meson.build
+++ b/meson.build
@@ -605,6 +605,7 @@
executable(
'flashprog',
files(
+ 'cli.c',
'cli_classic.c',
'cli_common.c',
'cli_output.c',