gawk

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

commit 1fa849f6766d2a4db924eaa22f5ba11c534c0526
parent 40fd5d995c059ac0b2c97b6cdf9ac509b3b6da08
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Mon, 21 Dec 2020 21:01:14 -0800

Majorly improve cfetch and helpers

A new function, cselect, will handle all indexing and call a function
on each selected line instead of having a function which returns
at each selected line. This is much cleaner and simpler. It will
also ease creating new functions which use it's functionality.

Diffstat:
Mmain.c | 145+++++++++++++++++++++++++++++++++----------------------------------------------
1 file changed, 60 insertions(+), 85 deletions(-)

diff --git a/main.c b/main.c @@ -199,38 +199,6 @@ putprompt(const char *prompt) warn("isatty %d", STDIN_FILENO); } -/* NOTE: Perhaps I should just store the gopher-text in an array. - * It would make this trivial and simple, simply `gphindex[N]`. - * - * It seems like too much though, it probably wouldn't exceed 1 MiB - * even after 1000 are stacked but it seems wrong. I suppose my - * /tmp is in memory anyway though. */ -char * -getlines(unsigned int *i, unsigned int *indexes, int n, FILE *fp) -{ - char *line; - size_t size; - unsigned int j; - int more; - - line = NULL; - size = 0; - more = 1; - for (; more && getline(&line, &size, fp) != -1; ++*i) { - more = 0; - for (j = 0; j < n; ++j) { - if (*i == indexes[j]) - return line; - else if (*i < indexes[j]) - more = 1; - } - } - - if (line) - free(line); - return NULL; -} - int input(char *buf, int size, const char *delims, const char *prompt, FILE *fp) { @@ -390,6 +358,54 @@ exfmt(int (*putter)(const char *, int, const char **), const char *path, int arg return 0; } +int +cs_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) { + warnx("Not a valid gopher item."); + return 1; + } + return func(argc, argv, (const char **)fields); +} + +int +cselect(int argc, const char **argv, const char *cache, int (*func)(int, const char **, const char **)) +{ + FILE *fp; + char buf[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) { + more = 0; + for (j = 0; j < ids; ++j) + if (i == indexes[j]) + cs_splitrun(argc, argv, buf, func); /* NOTE: errors ignored */ + else if (i < indexes[j]) + more = 1; + } + + 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. @@ -474,71 +490,30 @@ cmatch(const char *path, int argc, const char **argv) return 0; } -int -getfromline(char *line, const char *output) -{ - char *fields[GI_NULL + 1]; - - if (argsplit(fields, LEN(fields), line, "\t\r\n") != LEN(fields) - 1) { - warnx("Not a valid gopher item."); - return 1; - } - - if (output == NULL) - if ((output = basename(fields[GI_PATH])) == NULL) { - warn("unable to get basename '%s'", fields[GI_PATH]); - return 1; - } - if (gph_write(fields[GI_HOST], fields[GI_PORT], fields[GI_PATH], output) != 0) - return 1; - warnx("'%s/%s' written to '%s'", fields[GI_HOST], fields[GI_PATH], output); - return 0; -} - /* 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 *cache, const char *host, const char *port) +cfetch(int argc, const char **argv, const char **request) { - FILE *fp; const char *output; - char *line; - unsigned int i, n; - int status; - - if (argc == 0) { - warn("No index given"); - return 1; - } - wunused(2, argc, argv); - - if (strtorange(&n, 0, INT_MAX, argv[0])) - return 1; - if (argv[1]) - output = argv[1]; - else output = NULL; + wunused(1, argc, argv); - fp = wfopen(cache, "r"); - if (fp == NULL) - return 1; + if (argc > 0) + output = argv[0]; + else if ((output = basename(request[GI_PATH])) == NULL) { + warn("unable to get basename '%s'", request[GI_PATH]); + return 0; + } - i = 0; - line = getlines(&i, &n, 1, fp); - if (line == NULL) { - if (!ferror(fp)) - warnx("%d: Out of range.", n); - wfclose(fp); + if (gph_write(request[GI_HOST], request[GI_PORT], request[GI_PATH], output) != 0) return 1; - } - wfclose(fp); + warnx("'%s/%s' written to '%s'", request[GI_HOST], request[GI_PATH], output); - status = getfromline(line, output); - free(line); - return status; + return 0; } int @@ -557,7 +532,7 @@ execute(int command, int argc, const char **argv, int depth, const char *cache, case 'u': case 'b': /* unwind [n] */ return cback(argc, argv); case 'w': case 'f': /* write to file */ - cfetch(argc, argv, cache, host, port); + cselect(argc, argv, cache, cfetch); return 0; default: warnx("invalid command '%c'", command);