gawk

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

commit e9b871ac8026cc918d4c3939212a49d37a49363f
parent ddf2f68743bb0a445bdec3b440d5ac2abcbcb276
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Sat, 19 Dec 2020 01:38:35 -0800

Add dysfunctional and badly written program

It is not yet quite, functional, but is mostly what I want out of
it.

Diffstat:
Mmain.c | 184++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 178 insertions(+), 6 deletions(-)

diff --git a/main.c b/main.c @@ -23,6 +23,12 @@ #include <string.h> #include <err.h> #include <errno.h> +#include <limits.h> +#include <ctype.h> + +#define LEN(X) (sizeof(X) / sizeof(*X)) + +#define PROTO_MAX 16 int resolve(struct addrinfo **ai, const char *host, const char *proto) @@ -49,7 +55,7 @@ connect_to(const char *host, const char *proto) error = resolve(&ai0, host, proto); if (error) { - warnx("Unable to resolve '%s':", gai_strerror(error)); + warnx("Unable to resolve: %s:", gai_strerror(error)); return -1; } @@ -75,14 +81,180 @@ connect_to(const char *host, const char *proto) return s; } +char * +input(char *buf, int size, const char *prompt, FILE *fp) +{ + int len; + char *r; + + fputs(prompt, stdout); + r = fgets(buf, size, fp); + if (r == NULL) + return NULL; + + len = strlen(buf); + if (len >= size && buf[size - 1] != '\n') + warnx("maximum of %d bytes: Input too large.", size); + else if (len > 0) + buf[len - 1] = '\0'; + + return r; +} + +void +update_prompt(char *prompt, size_t size, const char *host, const char *path, int connected) +{ + snprintf(prompt, size, "%s%s %c> ", + host, path, connected ? '+' : '-'); +} + +int +strtoui(const char *s) +{ + int i; + + i = 0; + while (isdigit(*s)) { + i = i * 10 + (*s - '0'); + ++s; + } + if (*s != '\0') + return -1; + return i; +} + +void +newpath(char *path, char *newpath) +{ + size_t len; + + if (*newpath == '/') { + strlcpy(path, newpath, PATH_MAX); + } else { + len = strlen(path); + if (len > 0 && path[len - 1] != '/') + path[len - 1] = '/'; + strncat(path, newpath, PATH_MAX); + } +} + +void +gawkparse(char *cmd, char *host, char *path, char *port) +{ + int i; + char *parts[3]; + char *nhost, *npath, *nport; + + nhost = host; + npath = path; + nport = port; + + for (i = 0; i < 3; ++i) + parts[i] = strsep(&cmd, ":"); + + if (parts[1] == NULL) { + if (parts[0] != NULL) + npath = parts[0]; + } else { + if (parts[2] != NULL) + nport = parts[2]; + nhost = parts[0]; + npath = parts[1]; + } + + strlcpy(host, nhost, HOST_NAME_MAX); + newpath(path, npath); + strlcpy(port, nport, PROTO_MAX); +} + +/* returns `<0` on error, if positive `n - 1` is + * be returned to the caller. */ +int +gawk(int sock, int depth, const char *host, const char *path, const char *port) +{ + int done; + int child; + char cbuf[PATH_MAX + HOST_NAME_MAX + PROTO_MAX]; + char *cmd; + char npath[PATH_MAX]; + char nhost[HOST_NAME_MAX]; + char nport[PROTO_MAX]; + char prompt[64]; + + ++depth; + + child = -1; + done = 0; + update_prompt(prompt, sizeof(prompt), host, path, sock != -1); + while (!done && (cmd = input(cbuf, sizeof(cbuf), prompt, stdin))) { + if (*cmd == '\0') + continue; + + switch (*cmd++) { + case 'g': + if (*cmd == '\0') { + warnx("'g': No arguments."); + break;; + } + + gawkparse(cmd, nhost, npath, nport); + if (strcmp(host, nhost) != 0 && strcmp(port, nport) != 0) { + done = gawk(child, depth, nhost, npath, nport); + } else { + child = connect_to(nhost, nport); + if (child == -1) { + warn("unable to connect '%s' '%s'", nhost, nport); + break; + } + + done = gawk(child, depth, nhost, npath, nport); + + if (close(child) == -1) { + warn("unable to close '%s' '%s'", nhost, npath); + return -1; + } + } + + break; + case 'b': + if (*cmd == '\0') + done = 1; + else { + done = strtoui(cmd); + if (done < 0) { + warnx("invalid argument for 'b', '%s'", cmd); + done = 0; + } + } + break; + case 'c': + if (sock != -1) { + warnx("already connected"); + break; + } + sock = connect_to(host, port); + update_prompt(prompt, sizeof(prompt), host, prompt, sock != -1); + break; + case 'q': + if (*cmd != '\0') + warnx("'q': Takes no arguments."); + done = depth; + break; + default: + warnx("invalid command '%c'", *--cmd); + } + } + if (ferror(stdin)) { + warn("an error ocoured on stdin"); + return -1; + } + return done - 1; +} + int main(int argc, char *argv[]) { - int s; + gawk(-1, 0, "localhost", "/","gopher"); - s = connect_to("localhost", "gopher"); - if (s == -1) - return 1; - close(s); return 0; }