commit 30229cba3c91d512f1190c770268f2d7e07cbd57
parent 2aa849677382af4d00a99adaefa84eeecdcbb21d
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date: Tue, 22 Dec 2020 18:43:25 -0800
Allow chaining filteres
Multiple filters are now allowed and only one funtion does the I/O
cutting down on duplicate code.
Diffstat:
M | main.c | | | 213 | +++++++++++++++++++++++++++++++++++++------------------------------------------ |
1 file changed, 101 insertions(+), 112 deletions(-)
diff --git a/main.c b/main.c
@@ -41,13 +41,14 @@
#define MY_LINE_MAX 128
#define MY_PATH_MAX 128 /* NOTE: PATH_MAX should be used with realpath(1), etc. */
#define MY_URL_MAX 72
+#define MY_FILTER_MAX 4
enum gphitem { GI_INFO, GI_PATH, GI_HOST, GI_PORT, GI_NULL };
/* NOTE: before changing see reqtoaddr() */
enum address { AR_PATH, AR_HOST, AR_PORT, AR_NULL };
typedef int (command)(int, const char **, int, const char **);
-typedef int (filter)(const char *, int, const char **, command);
+typedef int (filter)(int, const char **, int, const char **, command);
typedef int (stack_command)(int, const char **, int, const char **);
int gawk(const char **);
@@ -87,11 +88,17 @@ wfclose(FILE *fp)
return 0;
}
-void
-wunused(int max, int argc, const char **ap)
+int
+badargs(int min, int max, int argc, const char **ap)
{
- if (argc > max)
+ if (max > 0 && argc > max) {
warnx("warning: '%s' and %d more arguments unused.", ap[max], argc - (max + 1));
+ } else if (argc < min) {
+ warnx("error: Not enough arguments.");
+ return 1;
+ }
+
+ return 0;
}
int
@@ -318,108 +325,83 @@ gph_write(const char **addr, const char *path)
return close(sock);
}
+/* Returns -1 on fatal error, 0 on no match, and 1 on match. */
int
-splitrun(int argc, const char **argv, int index, char *request, command *func)
+splitrun(filter **filters, int argc, const char **argv, int index, char *s, command *func)
{
- char *fields[6];
+ int i, n;
+ char *item[6];
/* NOTE: argsplit ignores multiple terminators. */
- if (argsplit(fields, LEN(fields), request, "\t\r\n") != 4)
- if (fields[4] != NULL && strcmp(fields[4], "+") != 0) {
+ if (argsplit(item, LEN(item), s, "\t\r\n") != 4)
+ /* NOTE: not foolproof */
+ if (item[4] != NULL && strcmp(item[4], "+") != 0) {
warnx("%d: Not a valid gopher item.", index);
return 1;
}
- return func(argc, argv, index, (const char **)fields);
-}
-int
-findex(const char *cache, int argc, const char **argv, command *func)
-{
- FILE *fp;
- char buf[MY_LINE_MAX];
- int more;
- unsigned int i, j;
- unsigned int indexes[argc];
- int ids;
-
- fp = fopen(cache, "r");
- if (fp == NULL)
- return 1;
-
- /* NOTE: One could optomize by sorting these indexes. */
- for (ids = 0; ids < argc && isdigit(*argv[ids]); ++ids) {
- if (strtorange(&indexes[ids], 0, UINT_MAX, argv[ids]) != 0)
- return 1;
-
- }
- argc -= ids;
- argv += ids;
-
- more = 1;
- for (i = 0; more && fgets(buf, sizeof(buf), fp) != NULL; ++i) {
- if (*buf == '.')
- break;
- more = 0;
- for (j = 0; j < ids; ++j)
- if (i == indexes[j])
- splitrun(argc, argv, i, buf, func); /* NOTE: errors ignored */
- else if (i < indexes[j])
- more = 1;
+ for (i = 0; filters[i] != NULL; ++i) {
+ n = filters[i](argc, argv, index, (const char **)item, func);
+ if (n <= 0)
+ return n;
+ argc -= n;
+ argv += n;
}
- return wfclose(fp);
+ func(argc, argv, index, (const char **)item);
+ return 0;
}
int
-fstrmatch(const char *cache, int argc, const char **argv, command *func)
+run_filters(const char *cache, filter **filters, int argc, const char **argv, command *func)
{
FILE *fp;
- char buf[MY_LINE_MAX];
- int anystr;
+ char item[MY_LINE_MAX];
int i;
fp = wfopen(cache, "r");
if (fp == NULL)
return 1;
- if (!argv[0])
- anystr = 1;
- else anystr = 0;
-
- for (i = 0; fgets(buf, sizeof(buf), fp) != NULL; ++i) {
- if (*buf == '.')
- break;
- if (anystr || strcasestr(buf, argv[0]))
- splitrun(argc - 1, argv + 1, i, buf, func);
+ for (i = 0; fgets(item, sizeof(item), fp) != NULL && *item != '.'; ++i) {
+ if (splitrun(filters, argc, argv, i, item, func) < 0)
+ return -1;
}
-
return wfclose(fp);
}
int
-fgroup(const char *cache, int argc, const char **argv, command *func)
+findex(int argc, const char **argv, int index, const char **item, command *func)
{
- FILE *fp;
- char buf[MY_LINE_MAX];
- int anytype;
- int i;
+ unsigned int n;
- fp = wfopen(cache, "r");
- if (fp == NULL)
+ if (badargs(1, -1, argc, argv))
+ return -1;
+ if (strtorange(&n, 0, UINT_MAX, argv[0]))
+ return -1;
+ if (index == n)
return 1;
+ return 0;
+}
- if (!argv[0] || strchr(argv[0], '.'))
- anytype = 1;
- else anytype = 0;
-
- for (i = 0; fgets(buf, sizeof(buf), fp) != NULL; ++i) {
- if (*buf == '.')
- break;
- if (anytype || strchr(argv[0], *buf))
- splitrun(argc - 1, argv + 1, i, buf, func);
- }
+int
+fstring(int argc, const char **argv, int index, const char **item, command *func)
+{
+ if (badargs(1, -1, argc, argv))
+ return -1;
+ if (strcasestr(item[GI_INFO], argv[0]) != NULL)
+ return 1;
+ return 0;
+}
- return wfclose(fp);
+int
+ftype(int argc, const char **argv, int index, const char **item, command *func)
+{
+ if (badargs(1, -1, argc, argv))
+ return -1;
+ if (strchr(argv[0], *item[GI_INFO]) != NULL)
+ return 1;
+ return 0;
}
/* If lacking arguments goes to root (`/'). If one argument is given
@@ -432,7 +414,8 @@ sgoto(int argc, const char **argv, int depth, const char **addr)
char tmp[MY_PATH_MAX];
const char *newaddr[AR_NULL];
- wunused(3, argc, argv);
+ if (badargs(0, 3, argc, argv))
+ return 1;
strcpy(tmp, addr[AR_PATH]);
newaddr[AR_HOST] = addr[AR_HOST];
@@ -458,9 +441,7 @@ sunwind(int argc, const char **argv, int depth, const char **addr)
{
unsigned int n;
- wunused(1, argc, argv);
-
- if (argc == 0)
+ if (badargs(1, 1, argc, argv))
return 1;
if (strtorange(&n, 1, INT_MAX, argv[0]))
return 0;
@@ -470,14 +451,14 @@ sunwind(int argc, const char **argv, int depth, const char **addr)
int
sexit(int argc, const char **argv, int depth, const char **addr)
{
- wunused(0, argc, argv);
+ badargs(0, 0, argc, argv);
return depth;
}
int
cprint(int argc, const char **argv, int i, const char **s)
{
- wunused(0, argc, argv);
+ badargs(0, 0, argc, argv);
if (**s == 'i')
printf(" %s\n", s[GI_INFO] + 1);
@@ -498,7 +479,8 @@ cfetch(int argc, const char **argv, int i, const char **request)
{
const char *output;
- wunused(1, argc, argv);
+ if (badargs(0, 1, argc, argv))
+ return 1;
if (argc > 0)
output = argv[0];
@@ -564,12 +546,12 @@ filter *
getfilter(int c)
{
switch (c) {
- case 'g':
- return fgroup;
+ case 't':
+ return ftype;
case 'i':
return findex;
case 's':
- return fstrmatch;
+ return fstring;
default:
return NULL;
}
@@ -594,38 +576,45 @@ int
execute(int argc, const char **argv, int depth, const char *cache,
const char **addr)
{
- command *c;
- filter *f;
- stack_command *sc;
+ int i;
+ filter *filters[MY_FILTER_MAX];
+ command *command;
+ stack_command *stackc;
- if (argc == 0)
+ if (argc == 0 && argv[0][0] == '\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:
-invalid_statement:
- warnx("invalid statement '%s'", *argv);
- return 0;
+ filters[0] = NULL;
+ stackc = 0;
+
+ for (i = 0; argv[0][i + 1] != '\0'; ++i) {
+ if (i >= LEN(filters)) {
+ warnx("Too many filters");
+ return 0;
+ }
+ filters[i] = getfilter(argv[0][i]);
+ if (filters[i] == NULL) {
+ warnx("'%c': Not a filter.", argv[0][i]);
+ return 0;
+ }
+ }
+ filters[i] = NULL;
+ command = getcommand(argv[0][i]);
+ if (command == NULL) {
+ stackc = getstackc(argv[0][i]);
+ if (stackc == NULL) {
+ warnx("'%c': Not a command.", argv[0][i]);
+ return 0;
+ }
}
- if (sc != NULL)
- return sc(argc - 1, argv + 1, depth, addr);
- if (f == NULL || c == NULL)
- goto invalid_statement;
- f(cache, argc - 1, argv + 1, c);
+ /* TODO: combine stack commands and regular commands */
+ --argc;
+ ++argv;
+ if (stackc != NULL)
+ return stackc(argc, argv, depth, addr);
+ else
+ run_filters(cache, filters, argc, argv, command);
return 0;
}