commit 2a85db865534232ed9f453b71d3be564abd06a3e
parent baddf547341bd520a0d1396dde56d8cb0f2ce872
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date: Mon, 21 Dec 2020 23:39:06 -0800
Center command execution heavily on function pointers
Selectors renamed to filters and add stack commands. Stack commands
act on the stack and have parameters given accordingly, whereas
regular commands are given an gopher item. Three character to
function pointer functions are added to end up making a pretty
flexible system.
Unfortuneately since statements are now variable length there must
be a separater between them and their arguments.
Diffstat:
M | main.c | | | 151 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- |
1 file changed, 103 insertions(+), 48 deletions(-)
diff --git a/main.c b/main.c
@@ -38,6 +38,10 @@
#define ARG_SEP ":\t "
#define CMD_SEP ";\n"
+typedef int (command)(int, const char **, const char **);
+typedef int (filter)(const char *, int, const char **, command);
+typedef int (stack_command)(int, const char **, int, const char *, const char *, const char *);
+
enum gphitem { GI_INFO, GI_PATH, GI_HOST, GI_PORT, GI_NULL };
int gawk(const char *, const char *, const char *);
@@ -301,7 +305,7 @@ gph_write(const char *host, const char *port, const char *request, const char *p
}
int
-splitrun(int argc, const char **argv, char *request, int (*func)(int, const char **, const char **))
+splitrun(int argc, const char **argv, char *request, command *func)
{
char *fields[5];
@@ -315,7 +319,7 @@ splitrun(int argc, const char **argv, char *request, int (*func)(int, const char
}
int
-sindexes(int argc, const char **argv, const char *cache, int (*func)(int, const char **, const char **))
+findex(const char *cache, int argc, const char **argv, command *func)
{
FILE *fp;
char buf[LINE_MAX];
@@ -351,7 +355,7 @@ sindexes(int argc, const char **argv, const char *cache, int (*func)(int, const
}
int
-sgroup(int argc, const char **argv, const char *cache, int (*func)(int, const char **, const char **))
+fgroup(const char *cache, int argc, const char **argv, command *func)
{
FILE *fp;
char buf[LINE_MAX];
@@ -380,8 +384,8 @@ sgroup(int argc, const char **argv, const char *cache, int (*func)(int, const ch
* the second the path, and the optional third the port.
*/
int
-cgoto(int argc, const char **argv, const char *host, const char *path,
- const char *port)
+sgoto(int argc, const char **argv, int depth, const char *host,
+ const char *port, const char *path)
{
char npath[PATH_MAX];
const char *nhost, *nport;
@@ -406,22 +410,27 @@ cgoto(int argc, const char **argv, const char *host, const char *path,
return gawk(nhost, npath, nport);
}
-/* argv[0], if present, is the number of backtracks to make which
- * is by default 1.
- */
int
-cback(int argc, const char **argv)
+sunwind(int argc, const char **argv, int depth, const char *host,
+ const char *port, const char *path)
{
- unsigned int back;
+ unsigned int n;
wunused(1, argc, argv);
if (argc == 0)
- return 1; /* back `1`, not an error */
-
- if (strtorange(&back, 1, INT_MAX, argv[0]))
+ return 1;
+ if (strtorange(&n, 1, INT_MAX, argv[0]))
return 0;
- return back;
+ return n;
+}
+
+int
+sexit(int argc, const char **argv, int depth, const char *host,
+ const char *port, const char *path)
+{
+ wunused(0, argc, argv);
+ return depth;
}
int
@@ -480,35 +489,86 @@ cfetch(int argc, const char **argv, const char **request)
return 0;
}
+command *
+getcommand(int c)
+{
+ switch (c) {
+ case 'p':
+ return cprint;
+ case 'n':
+ return cprintn;
+ case 'f':
+ return cfetch;
+ default:
+ return NULL;
+ }
+}
+
+filter *
+getfilter(int c)
+{
+ switch (c) {
+ case 'g':
+ return fgroup;
+ case 'i':
+ return findex;
+ default:
+ return NULL;
+ }
+}
+
+stack_command *
+getstackc(int c)
+{
+ switch (c) {
+ case 'u':
+ return sunwind;
+ case 'g':
+ return sgoto;
+ case 'q':
+ return sexit;
+ default:
+ return NULL;
+ }
+}
+
int
-execute(int command, int argc, const char **argv, int depth, const char *cache,
+execute(int argc, const char **argv, int depth, const char *cache,
const char *host, const char *path, const char *port)
{
- /* NOTE: have another prefix command which decides which
- * selector to use, currently either sindexes or sgroup.
- */
- switch (command) {
- case 'U': case 'q': /* unwind the whole stack */
- wunused(0, argc, argv);
- return depth;
- case 'p': /* print gopher-text */
- sgroup(argc, argv, cache, cprint);
- return 0;
- case 'i':
- sgroup(argc, argv, cache, cprintn);
- cprintn(0, NULL, NULL); /* reset counter, kinda messy */
- return 0;
- case 's': case 'g': /* goto new location */
- return cgoto(argc, argv, host, path, port);
- case 'u': case 'b': /* unwind [n] */
- return cback(argc, argv);
- case 'w': case 'f': /* write to file */
- sindexes(argc, argv, cache, cfetch);
+ command *c;
+ filter *f;
+ stack_command *sc;
+
+ if (argc == 0)
return 0;
+
+ sc = NULL;
+ switch (strlen(argv[0])) {
+ case 0:
+ return 0; /* ignore empty */
+ case 1:
+ f = fgroup;
+ c = getcommand(argv[0][0]);
+ if (c == NULL)
+ sc = getstackc(argv[0][0]);
+ break;
+ case 2:
+ f = getfilter(argv[0][0]);
+ c = getcommand(argv[0][1]);
+ break;
default:
- warnx("invalid command '%c'", command);
+invalid_statement:
+ warnx("invalid statement '%s'", *argv);
return 0;
}
+
+ if (sc != NULL)
+ return sc(argc + 1, argv - 1, depth, host, port, path);
+ if (f == NULL || c == NULL)
+ goto invalid_statement;
+ f(cache, argc - 1, argv + 1, c);
+ return 0;
}
void
@@ -526,7 +586,6 @@ gawk(const char *host, const char *path, const char *port)
{
static int depth;
char *argv[ARGV_MAX];
- char *start;
char cache[PATH_MAX];
char inbuf[ARG_MAX];
char prompt[64];
@@ -549,16 +608,12 @@ gawk(const char *host, const char *path, const char *port)
done = 0;
snprintf(prompt, sizeof(prompt), "[%s] %s ", host, path);
while (!done && input(inbuf, sizeof(inbuf), CMD_SEP, prompt, stdin) == 0) {
- start = inbuf + strspn(inbuf, " \t");
- if (*start != '\0') {
- argc = argsplit(argv, LEN(argv), start + 1, ARG_SEP);
- if (argc < 0) {
- warnc(E2BIG, "'%c'", *start);
- } else {
- done = execute(*start, argc,
- (const char **)argv, depth, cache, host,
- path, port);
- }
+ argc = argsplit(argv, LEN(argv), inbuf, ARG_SEP);
+ if (argc < 0) {
+ warnx("Too many arguments.");
+ } else if (argc > 0) {
+ done = execute(argc, (const char **)argv, depth, cache,
+ host, path, port);
}
}
@@ -584,7 +639,7 @@ main(int argc, char *argv[])
if (mkdtemp(tmpdir) == NULL)
err(1, "mkdtemp '%s'", tmpdir);
- status = cgoto(argc - 1, (const char **)argv + 1, "localhost", "/", "70");
+ status = sgoto(argc - 1, (const char **)argv + 1, 0, "localhost", "70", "/");
if (status)
fprintf(stderr, "usage: %s [path] | [host] [path] [port]\n",
getprogname());