summaryrefslogtreecommitdiff
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;
}