gawk

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

commit bca75728dbc017877e7a9312398d449f42fb4c66
parent e9b871ac8026cc918d4c3939212a49d37a49363f
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Sat, 19 Dec 2020 02:49:20 -0800

Cleanup and implement requests

While currently sending a request exits immidiately after printing
the result it works.

Diffstat:
Mmain.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 99 insertions(+), 43 deletions(-)

diff --git a/main.c b/main.c @@ -17,6 +17,7 @@ #include <sys/socket.h> #include <sys/types.h> +#include <sys/wait.h> #include <netdb.h> #include <stdio.h> #include <unistd.h> @@ -27,8 +28,10 @@ #include <ctype.h> #define LEN(X) (sizeof(X) / sizeof(*X)) +#define PROTO_MAX 16 +#define BUFSIZE 4096 -#define PROTO_MAX 16 +static char *format_prog = "gophmt"; /* not released, costom formatter */ int resolve(struct addrinfo **ai, const char *host, const char *proto) @@ -101,13 +104,6 @@ input(char *buf, int size, const char *prompt, FILE *fp) 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) { @@ -167,6 +163,63 @@ gawkparse(char *cmd, char *host, char *path, char *port) strlcpy(port, nport, PROTO_MAX); } +/* NOTE: implement caching */ +int +getgph(int sock, const char *path) +{ + ssize_t bytes; + char buf[BUFSIZE]; + + if (send(sock, path, strlen(path), 0) == -1) { + warn("unable to send request"); + return 1; + } + + while ((bytes = recv(sock, buf, sizeof(buf), 0)) > 0) { + if (fwrite(buf, 1, bytes, stdout) != bytes) + return 1; + } + return 0; +} + +int +gawkat(int sock, const char *path) +{ + int status; + int fds[2]; + char *argv[2]; + + if (pipe(fds) == -1) { + warn("unable to pipe"); + return 1; + } + + switch (fork()) { + case -1: + warn("unable to fork"); + return 1; + case 0: + if (dup2(fds[1], STDIN_FILENO) == -1 || close(fds[0])) + warn("unable to setup pipe"); + argv[0] = format_prog; + argv[1] = NULL; + execvp(*argv, argv); + warn("execvp %s", *argv); + return 1; + default: + if (dup2(fds[0], STDOUT_FILENO) == -1 || close(fds[1])) + warn("unable to setup pipe"); + } + + if ((status = getgph(sock, path)) == 0) { + wait(&status); + if (status) + warnx("child exited %d", status); + } + return status; + +} + /* returns `<0` on error, if positive `n - 1` is * be returned to the caller. */ int @@ -176,22 +229,53 @@ gawk(int sock, int depth, const char *host, const char *path, const char *port) int child; char cbuf[PATH_MAX + HOST_NAME_MAX + PROTO_MAX]; char *cmd; + int closeit; char npath[PATH_MAX]; char nhost[HOST_NAME_MAX]; char nport[PROTO_MAX]; - char prompt[64]; + char prompt[64]; /* you wouldn't want it longer anyway */ ++depth; + if (sock != -1) { + closeit = 0; + } else { + closeit = 1; + sock = connect_to(host, port); + if (sock == -1) + return -1; + } + + snprintf(prompt, sizeof(prompt), "[%s] %s ", host, path); + child = -1; done = 0; - update_prompt(prompt, sizeof(prompt), host, path, sock != -1); while (!done && (cmd = input(cbuf, sizeof(cbuf), prompt, stdin))) { + /* `strcpy(cmd, "p")` works I suppose, but I like + * goto and it's more efficient. */ if (*cmd == '\0') - continue; + goto gawk_at; switch (*cmd++) { - case 'g': + case 'q': /* quit */ + done = depth; + break; + case 'p': /* print */ +gawk_at: + gawkat(sock, path); + break; + case 'b': /* back */ + if (*cmd == '\0') + done = 1; + else { + done = strtoui(cmd); + if (done < 0) { + warnx("invalid argument for 'b', '%s'", cmd); + done = 0; + } + } + break; + case 'g': /* goto or gawk */ if (*cmd == '\0') { warnx("'g': No arguments."); break;; @@ -206,46 +290,18 @@ gawk(int sock, int depth, const char *host, const char *path, const char *port) warn("unable to connect '%s' '%s'", nhost, nport); break; } - done = gawk(child, depth, nhost, npath, nport); - - if (close(child) == -1) { + 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"); + warn("'stdin'"); return -1; } return done - 1;