summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--parse.c61
-rw-r--r--strv.c14
-rw-r--r--strv.h13
3 files changed, 47 insertions, 41 deletions
diff --git a/parse.c b/parse.c
index a57c1b3..b6fedd1 100644
--- a/parse.c
+++ b/parse.c
@@ -2,13 +2,9 @@
 #include <string.h>
 
 #include "parse.h"
+#include "strv.h"
 #include "err.h"
 
-struct str_slice {
-	const char *s;
-	size_t n;
-};
-
 int isurlch(char c) {
 	return isalpha(c) || isdigit(c) || c == '-' || c == '.' || c == '_' || c == '~' || c == '!' || c == '$' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || c == '=' || c == '%' || c == '@' || c == ':' || c == '/';
 }
@@ -47,20 +43,7 @@ int parse_plain(struct doc *d, const buf_t *b) {
 	return 0;
 }
 
-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 scatss(char *buf, size_t i, size_t n, strv_t ss) {
 	size_t si = 0;
 	while (i < n && si < ss.n) {
 		buf[i++] = ss.s[si++];
@@ -68,25 +51,25 @@ size_t scatss(char *buf, size_t i, size_t n, struct str_slice ss) {
 	return i;
 }
 
-int parse_gophermap_line(struct doc *d, const char *s, size_t n) {
+int parse_gophermap_line(struct doc *d, strv_t ln) {
 	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;
+		strv_t dstr;
+		strv_t sel;
+		strv_t host;
+		strv_t 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);
+	bits.item_type = ln.s[i++];
+	bits.dstr = strv_head(ln, '\t', &i); 
+	bits.sel = strv_head(ln, '\t', &i); 
+	bits.host = strv_head(ln, '\t', &i); 
+	bits.port = strv_head(ln, '\t', &i); 
 	switch (bits.item_type) {
 	case '.':
-		if (n == 1) return 1;
+		if (ln.n == 1) return 1;
 	default:
 		urln = scatss(url, urln, sizeof url, bits.host);
 		if (urln < sizeof url) url[urln++] = ':';
@@ -106,17 +89,13 @@ int parse_gophermap_line(struct doc *d, const char *s, size_t n) {
 
 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;
+	size_t i = 0;
+	strv_t bufss = { b->buf, b->sz };
+	while (i < b->sz) {
+		strv_t ln = strv_head(bufss, '\n', &i);
+		if (ln.n > 0 && ln.s[ln.n - 1] == '\r') ln.n--;
+		if (parse_gophermap_line(d, ln)) {
+			break;
 		}
 	}
 	return 0;
diff --git a/strv.c b/strv.c
new file mode 100644
index 0000000..5da11f5
--- /dev/null
+++ b/strv.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+#include "strv.h"
+
+strv_t strv_head(strv_t ss, int chr, size_t *i) {
+	size_t j = i ? *i : 0;
+	char *c = memchr(&ss.s[j], chr, ss.n - j);
+	strv_t r = {
+		&ss.s[j],
+		c ? c - &ss.s[j] : ss.n - j
+	};
+	if (i) *i = j + r.n + !!c;
+	return r;
+}
diff --git a/strv.h b/strv.h
new file mode 100644
index 0000000..553a39c
--- /dev/null
+++ b/strv.h
@@ -0,0 +1,13 @@
+#ifndef STRV_H
+#define STRV_H
+
+#include <stddef.h>
+
+typedef struct {
+	const char *s;
+	size_t n;
+} strv_t;
+
+strv_t strv_head(strv_t ss, int chr, size_t *i);
+
+#endif