summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c272
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;
}