gawk

[old] Sed-like interface to the Gopher protocol
Log | Files | Refs | LICENSE

commit baddf547341bd520a0d1396dde56d8cb0f2ce872
parent 1fa849f6766d2a4db924eaa22f5ba11c534c0526
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Mon, 21 Dec 2020 21:48:56 -0800

Remove piping and make a new catagory of functions

It's a shame to remove piping but it takes up much more space than
what it gives now, a very commendable formatter can be made in a
few lines utilizing functions which are already needed.

Create a new function catagory, `s' or "selector" functions and
rename cselect to sindexes.

Tweak and rename the cmatch function to smatch for use as a selector.

Diffstat:
Mmain.c | 163+++++++++++++++++++++++++++++++++----------------------------------------------
1 file changed, 67 insertions(+), 96 deletions(-)

diff --git a/main.c b/main.c @@ -43,7 +43,6 @@ enum gphitem { GI_INFO, GI_PATH, GI_HOST, GI_PORT, GI_NULL }; int gawk(const char *, const char *, const char *); static int timeout = 5 * 1000; -static char *gphfmt[] = { "gophmt", NULL }; static char tmpdir[] = "/tmp/gawk-XXXXXXXXXXX"; FILE * @@ -302,68 +301,13 @@ gph_write(const char *host, const char *port, const char *request, const char *p } int -pipedup(int old, int new, int fildes[2]) -{ - if (dup2(old, new) == -1 || - close(fildes[0]) || close(fildes[1])) { - warn("unable to setup pipe"); - return 1; - } - return 0; -} - -int -exfmt(int (*putter)(const char *, int, const char **), const char *path, int argc, const char **argv) -{ - int fds[2]; - int i; - - if (pipe(fds) == -1) { - warn("unable to setup pipe"); - return 1; - } - - switch (fork()) { - case -1: - warn("unable to fork"); - return 1; - case 0: - if (pipedup(fds[0], STDIN_FILENO, fds) != 0) - _exit(1); - execvp(*gphfmt, gphfmt); - warn("execvp '%s'", *gphfmt); - _exit(1); - } - - switch (fork()) { - case -1: - warn("unable to fork"); - return 1; - case 0: - if (pipedup(fds[1], STDOUT_FILENO, fds) != 0) - _exit(1); - _exit(putter(path, argc, argv)); - } - - if (close(fds[0]) || close(fds[1])) { - warn("%s: unable to close pipe", __func__); - return 1; - } - for (i = 0; i < 2; ++i) - if (wait(0) == -1) { - warn("unable to wait"); - return 1; - } - - return 0; -} - -int -cs_splitrun(int argc, const char **argv, char *request, int (*func)(int, const char **, const char **)) +splitrun(int argc, const char **argv, char *request, int (*func)(int, const char **, const char **)) { char *fields[5]; - if (argsplit(fields, LEN(fields), request, "\t\r\n") != 4) { + if (*request == '.') + return func(argc, argv, NULL); + else if (argsplit(fields, LEN(fields), request, "\t\r\n") != 4) { warnx("Not a valid gopher item."); return 1; } @@ -371,7 +315,7 @@ cs_splitrun(int argc, const char **argv, char *request, int (*func)(int, const c } int -cselect(int argc, const char **argv, const char *cache, int (*func)(int, const char **, const char **)) +sindexes(int argc, const char **argv, const char *cache, int (*func)(int, const char **, const char **)) { FILE *fp; char buf[LINE_MAX]; @@ -398,7 +342,7 @@ cselect(int argc, const char **argv, const char *cache, int (*func)(int, const c more = 0; for (j = 0; j < ids; ++j) if (i == indexes[j]) - cs_splitrun(argc, argv, buf, func); /* NOTE: errors ignored */ + splitrun(argc, argv, buf, func); /* NOTE: errors ignored */ else if (i < indexes[j]) more = 1; } @@ -406,6 +350,31 @@ cselect(int argc, const char **argv, const char *cache, int (*func)(int, const c return wfclose(fp); } +int +sgroup(int argc, const char **argv, const char *cache, int (*func)(int, const char **, const char **)) +{ + FILE *fp; + char buf[LINE_MAX]; + int anytype; + + fp = wfopen(cache, "r"); + if (fp == NULL) + return 1; + + if (!argv[0] || strchr(argv[0], '.')) + anytype = 1; + else anytype = 0; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (anytype || argc < 1 || strchr(argv[0], *buf)) { + if (argc < 2 || strcasestr(buf, argv[1])) + splitrun(argc - 2, argv + 2, buf, func); + } + } + + return wfclose(fp); +} + /* If lacking arguments goes to root (`/'). If one argument is given * it is taken as a path, if multiple are given the first is the host, * the second the path, and the optional third the port. @@ -455,51 +424,46 @@ cback(int argc, const char **argv) return back; } -/* argv[0], if present, restricts item types to one type contained - * in it, `.' is a wildcard. argv[1], if present, restricts by - * matches to strcasecmp. - */ int -cmatch(const char *path, int argc, const char **argv) +cprint(int argc, const char **argv, const char **s) { - FILE *fp; - char *line; - size_t size; - int anytype; + wunused(0, argc, argv); - fp = wfopen(path, "r"); - if (fp == NULL) + if (s == NULL) return 1; + if (**s == 'i') + printf(" %s\n", s[GI_INFO] + 1); + else + printf(" [%c] %s (%s%s)\n", s[GI_INFO][0], s[GI_INFO] + 1, s[GI_HOST], s[GI_PATH]); + return 0; +} - if (!argv[0] || strchr(argv[0], '.')) - anytype = 1; - else anytype = 0; - - line = NULL; - size = 0; - while (getline(&line, &size, fp) != -1) { - if (anytype || argc < 1 || strchr(argv[0], *line)) { - if (argc < 2 || strcasestr(line, argv[1])) - dprintf(STDOUT_FILENO, "%s", line); - } - } - free(line); - - if (wfclose(fp)) +int +cprintn(int argc, const char **argv, const char **s) +{ + /* It's a shame but the counter has no way of knowing what + * item it's on in the gopher index, therefor it's not + * useful when restricting with smatch. + */ + static int n; + + if (s == NULL) { + n = 0; return 1; - return 0; + } + printf("%4d", n++); + return cprint(argc, argv, s); + } -/* argv[0] is the line index (starting from 0) of the file to - * download. If present argv[1] is the location to write the file - * to, otherwise it is written to the basename(3) of it's selector - * string. - */ int cfetch(int argc, const char **argv, const char **request) { const char *output; + /* NOTE: perhaps some message should be printed */ + if (request == NULL) + return 1; wunused(1, argc, argv); if (argc > 0) @@ -520,19 +484,26 @@ int execute(int command, 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 */ - exfmt(cmatch, cache, argc, argv); + 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 */ - cselect(argc, argv, cache, cfetch); + sindexes(argc, argv, cache, cfetch); return 0; default: warnx("invalid command '%c'", command);