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