summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--main.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/main.c b/main.c
index e8599dc..256e03d 100644
--- a/main.c
+++ b/main.c
@@ -1,2 +1,196 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* errors */
+
+void perr(const char *s) {
+	fprintf(stderr, "%s\n", s);
+}
+
+/* misc */
+
+int running;
+
+int quit(const char *_) {
+	puts("goodbye!");
+	running = 0;
+	return 0;
+}
+
+/* documents */
+
+struct doc {
+	struct doc *prev, *next;
+	struct {
+		char *buf;
+		size_t len, cap;
+	} text;
+	size_t ofs;
+};
+
+struct doc *doc_head, *doc_tail, *doc_cur;
+
+void doc_free(struct doc *d) {
+	free(d->text.buf);
+	free(d);
+}
+
+int doc_new(void) {
+	struct doc *d = calloc(1, sizeof *d);
+	if (!d) {
+		return -1;
+	}
+	d->text.buf = calloc(256, 1);
+	if (!d->text.buf) {
+		free(d);
+		return -1;
+	}
+	d->text.len = 256;
+	d->text.cap = 256;
+	if (doc_cur) {
+		struct doc *p = doc_cur->next;
+		while (p) {
+			struct doc *pp = p;
+			p = p->next;
+			doc_free(pp);
+		}
+		doc_tail = doc_cur;
+	}
+	if (doc_tail) {
+		doc_tail->next = d;
+		d->prev = doc_tail;
+	}
+	if (!doc_head) doc_head = d;
+	doc_tail = d;
+	doc_cur = d;
+	return 0;
+}
+
+int doc_add(char *buf, size_t n) {
+	if (!doc_cur) return -1;
+	size_t c = doc_cur->text.cap;
+	size_t tn = doc_cur->text.len + n + 1;
+	if (c < tn) {
+		while (c < tn) c <<= 1;
+		char *s = realloc(doc_cur->text.buf, c);
+		if (!s) {
+			return -1;
+		}
+		doc_cur->text.buf = s;
+	}
+	memcpy(&doc_cur->text.buf[doc_cur->text.len], buf, n);
+	doc_cur->text.len += 1;
+	doc_cur->text.buf[doc_cur->text.len] = 0;
+	return 0;
+}
+
+void doc_prev(void) {
+	if (doc_cur && doc_cur->prev) {
+		doc_cur = doc_cur->prev;
+	}
+}
+
+void doc_next(void) {
+	if (doc_cur && doc_cur->next) {
+		doc_cur = doc_cur->next;
+	}
+}
+
+void doc_fini(void) {
+	while (doc_tail) {
+		doc_head = doc_tail;
+		doc_tail = doc_tail->prev;;
+		doc_free(doc_head);
+	}
+}
+
+/* pagination */
+
+int pg_down(const char *_) {
+	return 0;
+}
+
+/* navigation */
+
+#define HOST_MAX 255
+#define PATH_MAX 255
+
+enum url_type {
+	TYPE_GOPHERDOC,
+	TYPE_GEMTEXT,
+	TYPE_PLAIN
+};
+
+struct url {
+	char host[HOST_MAX];
+	char path[PATH_MAX];
+	size_t host_len, path_len;
+	enum url_type type;
+};
+
+int nav_to(const char *url) {
+	return 0;
+}
+
+int nav_link_nr(unsigned long link_nr) {
+	return 0;
+}
+
+/* commands */
+
+struct cmd {
+	char ch;
+	int (*fn)(const char *);
+};
+
+struct cmd cmd_tbl[] = {
+	{ 'g', nav_to },
+	{ '\n', pg_down },
+	{ 'q', quit }
+};
+
+/* cmd is mutated when trimming strings */
+void cmd_do(char *cmd) {
+	if (isdigit(*cmd)) {
+		errno = 0;
+		unsigned long n = strtoul(cmd, NULL, 10);
+		if (errno) {
+			perr("invalid link number");
+		} else if (nav_link_nr(n)) {
+			perr("navigation failure");
+		}
+	} else {
+		for (size_t i = 0; i < sizeof cmd_tbl / sizeof(struct cmd); i++) {
+			if (cmd_tbl[i].ch == *cmd) {
+				while (isspace(*++cmd));
+				for (int j = strlen(cmd) - 1; j > 0 && isspace(cmd[j]); j--) {
+					cmd[j] = 0;
+				}
+				if (cmd_tbl[i].fn(cmd)) {
+					perr("failed");
+				}
+				goto found;
+			}
+		}
+		perr("?");
+found:		;
+	}
+}
+
+int cmd_get(char *buf, size_t n) {
+	fputs("* ", stdout);
+	return !!fgets(buf, n, stdin);
+}
+
 int main(void) {
+	char cmd_buf[1024];
+	running = 1;
+	while (running && cmd_get(cmd_buf, sizeof cmd_buf)) {
+		cmd_do(cmd_buf);
+	}
+	doc_fini();
+	return 0;
 }