diff options
-rw-r--r-- | main.c | 194 |
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; } |