summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Albers <thomas@thomaslabs.org>2023-08-06 12:15:56 +0200
committerThomas Albers <thomas@thomaslabs.org>2023-08-06 12:15:56 +0200
commitd0e2b015f25d53498da258d3ee988a101bc597fa (patch)
tree0f0f6a10c89227f61bc28ebdc90cab787a581914
parentfb233ab8c205692915dbca6ca4ea27060db7cdbd (diff)
Add parse_args
-rw-r--r--repl.c119
1 files changed, 106 insertions, 13 deletions
diff --git a/repl.c b/repl.c
index 32f2bee..edac70f 100644
--- a/repl.c
+++ b/repl.c
@@ -69,13 +69,6 @@ syntax_error:
return 1;
}
-/*
-static int
-parse_args(const char *fname, const char *types, int argc, char **args, ...)
-{
-}
-*/
-
static int
repl_write(int fd, const struct param *param, int argc, char **args)
{
@@ -160,12 +153,6 @@ repl_echo(int fd, const struct param *param, int argc, char **args)
}
static int
-repl_io_read(int fd, const struct param *param, int argc, char **args)
-{
- return 0;
-}
-
-static int
repl_io_write(int fd, const struct param *param, int argc, char **args)
{
return 0;
@@ -183,6 +170,112 @@ interrupt_handler(int signal)
}
*/
+enum args_type {
+ A_END,
+ A_BYTE,
+ A_DBYTE,
+ A_QBYTE,
+ A_OBYTE,
+ A_STRING,
+ A_OPTIONAL = 16
+};
+
+struct command;
+
+typedef int (*fptr)(int, const struct command *, struct param *, int, char **);
+
+struct command {
+ char alias;
+ const char *name;
+ int *args_spec;
+ const char *usage;
+ fptr fptr;
+ int quit;
+};
+
+static int
+parse_args(const struct command *cmd, int argc, char **args, ...)
+{
+ int i = 0;
+ int opt = 0;
+ int err = 0;
+ va_list ap;
+ va_start(ap, args);
+
+ void *ptr = NULL;
+ int *p = cmd->args_spec;
+
+ for ( ; *p != A_END; ++p) {
+ // Avoid runaway p
+ assert(i < MAX_ARGS);
+
+ if (*p == A_OPTIONAL) {
+ opt = 1;
+ continue;
+ }
+
+ if (i == argc && !opt)
+ goto syntax_error;
+
+ ptr = va_arg(ap, void *);
+ errno = 0;
+ char *end = NULL;
+
+ switch (*p) {
+ case A_BYTE:
+ *((uint8_t *)ptr) = strtoul(args[i], &end, 16);
+ break;
+
+ case A_DBYTE:
+ *((uint16_t *)ptr) = strtoul(args[i], &end, 16);
+ break;
+
+ case A_STRING:
+ *((const char **)ptr) = args[i];
+ break;
+ }
+
+ if (errno || args[i] == end) {
+ fprintf(stderr, "Invalid argument: %s\n", args[i]);
+ goto syntax_error;
+ }
+
+ ++i;
+ }
+
+ va_end(ap);
+ return i;
+
+syntax_error:
+ va_end(ap);
+ fputs(cmd->usage, stderr);
+ return -1;
+}
+
+#define ARGS(...) (int []){__VA_ARGS__}
+
+static int
+repl_io_read(int fd, const struct param *param, int argc, char **args)
+{
+ uint8_t bank;
+ uint16_t address;
+ const char *filename = NULL;
+
+ struct command cmd = {
+ .alias = 'i',
+ .name = "io_read",
+ .usage = "",
+ .fptr = NULL,
+ .quit = 0,
+ .args_spec = ARGS(A_BYTE, A_DBYTE, A_OPTIONAL, A_STRING, A_END),
+ .usage = "Usage: read <bank> <address> <length> [pathname]\n"
+ };
+
+ parse_args(&cmd, argc, args, &bank, &address, &filename);
+ printf("result: %hhx %hx %s\n", bank, address, filename);
+ return 0;
+}
+
// TODO: Handle signals (CTRL-C)
// TODO: Print errors when in repl and crash if from terminal
void