diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 272 |
1 files changed, 67 insertions, 205 deletions
diff --git a/main.c b/main.c index c2c9575..adc488a 100644 --- a/main.c +++ b/main.c @@ -4,126 +4,9 @@ #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 */ - -#define TXT_BUF_SIZE (1024 * 1024) -struct { - char buf[TXT_BUF_SIZE]; - size_t n; -} text; - -struct doc { - struct { - size_t ofs, len, idx; - } txt; -}; - -#define DOC_MAX 32 -struct doc docv[DOC_MAX] = { - { - .txt = { - .ofs = 0, - .len = 0, - .idx = 0 - } - } -}; -size_t docn = 0, doci = 0; - -void doc_pop(void) { - if (docn > 0) { - docn--; - if (doci > 0) doci--; - } -} - -void doc_shift(void) { - if (docn > 0) { - docn--; - memmove(text.buf, text.buf + docv[0].txt.len, text.n - docv[0].txt.len); - memmove(&docv[0], &docv[1], docn * sizeof(struct doc)); - docv[0].txt.ofs = 0; - for (int i = 1; i < docn; i++) { - docv[i].txt.idx = docv[i - 1].txt.ofs + (docv[i].txt.idx - docv[i].txt.ofs); - docv[i].txt.ofs = docv[i - 1].txt.ofs + docv[i - 1].txt.len; - } - if (docn > 0 && doci >= docn) doci = docn - 1; - } -} - -int doc_new(void) { - if (doci < docn) { - text.n = docv[doci].txt.ofs; - docn = doci; - } - if (docn >= DOC_MAX) return -1; - memset(&docv[docn], 0, sizeof(struct doc)); - docv[docn].txt.ofs = text.n; - docv[docn].txt.idx = text.n; - doci = docn++; - return 0; -} - -int doc_add(const char *buf, size_t n) { - if (text.n + n > TXT_BUF_SIZE) { - return -1; - } - memcpy(&text.buf[text.n], buf, n); - docv[doci].txt.len += n; - text.n += n; - return 0; -} - -int doc_adds(const char *s) { - return doc_add(s, strlen(s)); -} - -void doc_prev(void) { - if (doci > 0) doci--; -} - -void doc_next(void) { - if (doci < docn) doci++; -} - -void doc_back_line(void) { - if (doci >= docn) return; - struct doc *d = &docv[doci]; - size_t i = d->txt.idx; - while (i > 0 && text.buf[d->txt.idx] != '\n') i--; - if (i > 0) i--; - while (i > 0 && text.buf[d->txt.idx] != '\n') i--; - if (i > 0) i++; - d->txt.idx = i; -} - -void doc_print_line(void) { - if (doci >= docn) return; - struct doc *d = &docv[doci]; - size_t i = d->txt.idx; - size_t n = d->txt.ofs + d->txt.len; - while (i < n && text.buf[d->txt.idx] != '\n') { - putchar(text.buf[i++]); - } - if (i < n) i++; - d->txt.idx = i; -} +#include "doc.h" +#include "net.h" +#include "err.h" /* pagination */ @@ -131,68 +14,29 @@ size_t pg_lines() { return 24; } -int pg_down(const char *_) { +void pg_down(void) { size_t lines = pg_lines(); while (lines--) doc_print_line(); - return 0; } -int pg_up(const char *_) { +void pg_up(void) { size_t lines = pg_lines() << 1; while (lines--) doc_back_line(); - pg_down(_); - return 0; + pg_down(); } -int pg_redraw(const char *_) { +void pg_redraw(void) { size_t lines = pg_lines(); while (lines--) doc_back_line(); - pg_down(_); - return 0; + pg_down(); } /* navigation */ -#define HOST_MAX 255 -#define PATH_MAX 255 - -enum doc_type { - TYPE_UNKNOWN, - TYPE_GOPHERDOC, - TYPE_GEMTEXT, - TYPE_PLAIN, -}; - -enum protocol { - PROT_UNKNOWN, - PROT_FILE, - PROT_GOPHER, - PROT_GEMINI, -}; - -struct addr { - char host[HOST_MAX]; - char path[PATH_MAX]; - size_t host_len, path_len; - enum protocol prot; - enum doc_type type; -}; - -int url_to_addr(const char *url, struct addr *adr, enum protocol prot_default) { - adr->prot = prot_default; - adr->type = TYPE_PLAIN; - adr->host_len = 0; - size_t n = strlen(url); - if (n > PATH_MAX) return -1; - adr->path_len = n; - memcpy(adr->path, url, n); - return 0; -} - int nav_to(const char *url) { struct addr a; static enum protocol prot_default = PROT_FILE; /* change to gopher later */ - if (url_to_addr(url, &a, prot_default)) { + if (net_addr(url, &a, prot_default)) { return -1; } prot_default = a.prot; @@ -210,44 +54,52 @@ struct cmd { int (*fn)(const char *); }; -int addtxt(const char *s) { - return doc_add(s, strlen(s)) || doc_add("\n", 1); -} - -struct cmd cmd_tbl[] = { - { 'g', nav_to }, - { '\n', pg_down }, - { 'b', pg_up }, - { 'r', pg_redraw }, - { 'a', addtxt }, - { '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; +/* cmd is mutated when trimming strings + * returns whether to quit */ +int cmd_do(char *cmd) { + switch (*cmd) { + case 'q': + puts("goodbye!"); + return 1; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + errno = 0; + unsigned long n = strtoul(cmd, NULL, 10); + if (errno) { + perr("invalid link number"); + } else if (nav_link_nr(n)) { + perr("navigation failure"); } } + break; + case 'b': + pg_up(); + break; + case '\0': + pg_down(); + break; + case 'r': + pg_redraw(); + break; + case 'g': + if (nav_to(cmd + 1)) perr("navigation failure"); + break; + default: perr("?"); -found: ; + break; + } + return 0; +} + + +void cmd_trim(char *buf, size_t max) { + size_t n = strlen(buf); + while (n > 0 && isspace(buf[n - 1])) { + buf[--n] = 0; + } + while (n > 1 && isspace(buf[1])) { + memmove(&buf[0], &buf[1], n--); } } @@ -256,13 +108,23 @@ int cmd_get(char *buf, size_t n) { return !!fgets(buf, n, stdin); } +void init(void) { + doc_init(); +} + +void fini(void) { + doc_fini(); +} + int main(void) { char cmd_buf[1024]; - running = 1; - doc_new(); - doc_adds("Press ? for help.\n"); - while (running && cmd_get(cmd_buf, sizeof cmd_buf)) { - cmd_do(cmd_buf); + init(); + atexit(fini); + while (cmd_get(cmd_buf, sizeof cmd_buf)) { + cmd_trim(cmd_buf, sizeof cmd_buf); + if (cmd_do(cmd_buf)) { + break; + } } return 0; } |