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:
M | main.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);