summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc.c5
-rw-r--r--doc.h1
-rw-r--r--parse.c112
3 files changed, 103 insertions, 15 deletions
diff --git a/doc.c b/doc.c
index 3f63ba8..89ff756 100644
--- a/doc.c
+++ b/doc.c
@@ -59,6 +59,11 @@ unsigned short doc_add_link(struct doc *d, const char *url) {
return d->linkc++;
}
+void doc_set_link(struct doc *d, unsigned short lnk) {
+ struct doc_line *l = doc_line_at(d, d->latest);
+ l->link = lnk;
+}
+
/* line navigation */
struct doc_line *doc_line_at(struct doc *d, size_t ofs) {
diff --git a/doc.h b/doc.h
index ea9a521..08af700 100644
--- a/doc.h
+++ b/doc.h
@@ -35,6 +35,7 @@ struct doc_line *doc_line_at(struct doc *d, size_t ofs);
int doc_line_prev(struct doc *d, size_t *ofs);
int doc_line_next(struct doc *d, size_t *ofs);
+void doc_set_link(struct doc *d, unsigned short lnk);
unsigned short doc_add_link(struct doc *d, const char *url);
#endif
diff --git a/parse.c b/parse.c
index 22e7edf..601c6b1 100644
--- a/parse.c
+++ b/parse.c
@@ -1,25 +1,107 @@
#include "parse.h"
#include "err.h"
+int parse_plain(struct doc *d, const buf_t *b) {
+ doc_init(d);
+ for (size_t i = 0; i < b->sz; i++) {
+ char c = b->buf[i];
+ if (c == '\n') {
+ doc_new_line(d);
+ } else {
+ doc_add_textn(d, &c, 1);
+ }
+ }
+ return 0;
+}
+
+struct str_slice {
+ const char *s;
+ size_t n;
+};
+
+static struct str_slice gmbit(size_t *i, const char *s, size_t n) {
+ struct str_slice ss = {
+ &s[*i],
+ 0
+ };
+ while (*i < n && s[*i] != '\t') {
+ *i += 1;
+ ss.n++;
+ }
+ *i += 1;
+ return ss;
+}
+
+size_t scatss(char *buf, size_t i, size_t n, struct str_slice ss) {
+ size_t si = 0;
+ while (i < n && si < ss.n) {
+ buf[i++] = ss.s[si++];
+ }
+ return i;
+}
+
+int parse_gophermap_line(struct doc *d, const char *s, size_t n) {
+ char url[512] = "gopher://";
+ size_t urln = 9;
+ struct {
+ char item_type;
+ struct str_slice dstr;
+ struct str_slice sel;
+ struct str_slice host;
+ struct str_slice port;
+ } bits;
+ size_t i = 0;
+ bits.item_type = s[i++];
+ bits.dstr = gmbit(&i, s, n);
+ bits.sel = gmbit(&i, s, n);
+ bits.host = gmbit(&i, s, n);
+ bits.port = gmbit(&i, s, n);
+ switch (bits.item_type) {
+ case '.':
+ if (n == 1) return 1;
+ default:
+ urln = scatss(url, urln, sizeof url, bits.host);
+ if (urln < sizeof url) url[urln++] = ':';
+ urln = scatss(url, urln, sizeof url, bits.port);
+ if (urln < sizeof url) url[urln++] = '/';
+ if (urln < sizeof url) url[urln++] = bits.item_type;
+ urln = scatss(url, urln, sizeof url, bits.sel);
+ url[urln] = 0;
+ doc_set_link(d, doc_add_link(d, url));
+ case 'i':
+ doc_add_textn(d, bits.dstr.s, bits.dstr.n);
+ doc_new_line(d);
+ break;
+ }
+ return 0;
+}
+
+int parse_gophermap(struct doc *d, const buf_t *b) {
+ doc_init(d);
+ size_t ln_start = 0;
+ for (size_t i = 0; i < b->sz; i++) {
+ if (b->buf[i] == '\r') continue;
+ if (b->buf[i] == '\n') {
+ char *ln_str = &b->buf[ln_start];
+ size_t ln_len = i - ln_start;
+ if (i > 0 && b->buf[i - 1] == '\r') ln_len--;
+ if (parse_gophermap_line(d, ln_str, ln_len)) {
+ break;
+ }
+ ln_start = i + 1;
+ }
+ }
+ return 0;
+}
+
int parse_doc(enum doc_type type, struct doc *d, const buf_t *b) {
switch (type) {
case DOC_PLAIN:
- doc_init(d);
- for (size_t i = 0; i < b->sz; i++) {
- char c = b->buf[i];
- if (c == '\n') {
- doc_new_line(d);
- } else {
- doc_add_textn(d, &c, 1);
- }
- }
- goto ok;
+ return parse_plain(d, b);
+ case DOC_GOPHERMAP:
+ return parse_gophermap(d, b);
default:
perr("unsupported doctype");
- goto err;
+ return -1;
}
-ok:
- return 0;
-err:
- return -1;
}