summary refs log tree commit diff
diff options
context:
space:
mode:
authorwrmr2024-11-02 15:10:41 -0500
committerwrmr2024-11-02 15:10:41 -0500
commit58214ec5f982c1b97aadce254c958a5f922c9724 (patch)
treeae64cb697531b0ee619350645e47adf186febfe7
parentdf1b0b23569e5244d5b9398802fec6435a995368 (diff)
split main.c in several places, began work on design doc
-rw-r--r--design.txt4
-rw-r--r--doc.c143
-rw-r--r--doc.h24
-rw-r--r--err.c12
-rw-r--r--err.h7
-rw-r--r--main.c272
-rw-r--r--net.c34
-rw-r--r--net.h26
-rw-r--r--parse.c17
-rw-r--r--parse.h9
10 files changed, 343 insertions, 205 deletions
diff --git a/design.txt b/design.txt
new file mode 100644
index 0000000..84fa2f0
--- /dev/null
+++ b/design.txt
@@ -0,0 +1,4 @@
+=====================
+ WORM'S LINE BROWSER
+=====================
+Design Considerations
diff --git a/doc.c b/doc.c
new file mode 100644
index 0000000..3478f8b
--- /dev/null
+++ b/doc.c
@@ -0,0 +1,143 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "doc.h"
+#include "err.h"
+
+/* text */
+
+static struct {
+	char *buf;
+	size_t len, cap;
+} txt;
+
+void txt_init(void) {
+	txt.buf = malloc(1);
+	if (!txt.buf) efatal("txt_init");
+	txt.buf[0] = 0;
+	txt.len = 0;
+	txt.cap = 1;
+}
+
+void txt_fini(void) {
+	free(txt.buf);
+}
+
+void txt_grow(size_t n) {
+	size_t cap = txt.cap;
+	size_t len = txt.len + n;
+	if (cap < len) {
+		while (cap < len) cap <<= 1;
+		char *s = realloc(txt.buf, cap);
+		if (!s) efatal("txt_grow");
+		txt.cap = cap;
+		txt.buf = s;
+	}
+}
+
+/* docs */
+
+struct doc {
+	size_t ofs, len, idx;
+};
+
+#define DOC_MAX 32
+
+static struct doc docv[DOC_MAX] = {
+	{
+		 
+		.ofs = 0,
+		.len = 0,
+		.idx = 0
+	}
+};
+
+static 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(txt.buf, txt.buf + docv[0].len, txt.len - docv[0].len);
+		memmove(&docv[0], &docv[1], docn * sizeof(struct doc));
+		docv[0].ofs = 0;
+		for (int i = 1; i < docn; i++) {
+			docv[i].idx = docv[i - 1].ofs + (docv[i].idx - docv[i].ofs);
+			docv[i].ofs = docv[i - 1].ofs + docv[i - 1].len;
+		}
+		if (docn > 0 && doci >= docn) doci = docn - 1;
+	}
+}
+
+void doc_new(void) {
+	while (docn >= DOC_MAX) {
+		doc_shift();
+	}
+	if (doci < docn) {
+		txt.len = docv[doci].ofs;
+		docn = doci;
+	}
+	memset(&docv[docn], 0, sizeof(struct doc));
+	docv[docn].ofs = txt.len;
+	docv[docn].idx = txt.len;
+	doci = docn++;
+}
+
+void doc_add(const char *buf, size_t n) {
+	txt_grow(n);
+	memcpy(&txt.buf[txt.len], buf, n);
+	txt.len += n;
+	docv[doci].len += n;
+}
+
+void doc_adds(const char *s) {
+	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->idx;
+	while (i > 0 && txt.buf[d->idx] != '\n') i--;
+	if (i > 0) i--;
+	while (i > 0 && txt.buf[d->idx] != '\n') i--;
+	if (i > 0) i++;
+	d->idx = i;
+}
+
+void doc_print_line(void) {
+	if (doci >= docn) return;
+	struct doc *d = &docv[doci];
+	size_t i = d->idx;
+	size_t n = d->ofs + d->len;
+	while (i < n && txt.buf[d->idx] != '\n') {
+		putchar(txt.buf[i++]);
+	}
+	if (i < n) i++;
+	d->idx = i;
+}
+
+void doc_init(void) {
+	txt_init();
+	doc_new();
+	doc_adds("Type ? for command help.\n");
+}
+
+void doc_fini(void) {
+	txt_fini();
+}
diff --git a/doc.h b/doc.h
new file mode 100644
index 0000000..3c5dfcc
--- /dev/null
+++ b/doc.h
@@ -0,0 +1,24 @@
+#ifndef DOC_H
+#define DOC_H
+
+enum doc_type {
+	TYPE_UNKNOWN,
+	TYPE_GOPHERDOC,
+	TYPE_GEMTEXT,
+	TYPE_PLAIN,
+};
+
+void doc_new(void);
+void doc_prev(void);
+void doc_next(void);
+
+void doc_add(const char *, size_t);
+void doc_adds(const char *);
+
+void doc_back_line(void);
+void doc_print_line(void);
+
+void doc_init(void);
+void doc_fini(void);
+
+#endif
diff --git a/err.c b/err.c
new file mode 100644
index 0000000..0b98a2b
--- /dev/null
+++ b/err.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "err.h"
+
+void perr(const char *s) {
+	fprintf(stderr, "%s\n", s);
+}
+
+void efatal(const char *s) {
+	perror(s);
+	exit(1);
+}
diff --git a/err.h b/err.h
new file mode 100644
index 0000000..312795d
--- /dev/null
+++ b/err.h
@@ -0,0 +1,7 @@
+#ifndef ERR_H
+#define ERR_H
+
+void perr(const char *s);
+void efatal(const char *s);
+
+#endif
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;
 }
diff --git a/net.c b/net.c
new file mode 100644
index 0000000..73f50d4
--- /dev/null
+++ b/net.c
@@ -0,0 +1,34 @@
+#include <string.h>
+#include "net.h"
+
+int net_addr(const char *url, struct addr *adr, enum protocol prot_default) {
+	char *prot_mark;
+	if ((prot_mark = strstr(url, "://"))) {
+		static struct {
+			const char *str;
+			enum protocol prot;
+		} prot_str_tbl[] = {
+			{ "gopher", PROT_GOPHER },
+			{ "gemini", PROT_GEMINI },
+			{ "file", PROT_FILE },
+		};
+		size_t n = prot_mark - url;
+		adr->prot = PROT_UNKNOWN;
+		for (size_t i = 0; i < sizeof prot_str_tbl / sizeof *prot_str_tbl; i++) {
+			if (!strncmp(prot_str_tbl[i].str, url, n)) {
+				adr->prot = prot_str_tbl[i].prot;
+				break;
+			}
+		}
+		url = prot_mark + 3;
+	} else {
+		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;
+}
diff --git a/net.h b/net.h
new file mode 100644
index 0000000..0b4422f
--- /dev/null
+++ b/net.h
@@ -0,0 +1,26 @@
+#ifndef NET_H
+#define NET_H
+
+#include "doc.h"
+
+#define HOST_MAX 255
+#define PATH_MAX 255
+
+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 net_addr(const char *url, struct addr *adr, enum protocol prot_default);
+
+#endif
diff --git a/parse.c b/parse.c
new file mode 100644
index 0000000..8061257
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,17 @@
+#include "parse.h"
+
+int parse_doc(enum doc_type doct, int (*line_get)(char **, size_t *)) {
+	char *s;
+	size_t n;
+	switch (doct) {
+	case TYPE_PLAIN:
+		doc_new();
+		while (line_get(&s, &n)) {
+			doc_add(s, n);
+			doc_add("\n", 1);
+		}
+		return 0;
+	default:
+		return -1;
+	}
+}
diff --git a/parse.h b/parse.h
new file mode 100644
index 0000000..1267b3c
--- /dev/null
+++ b/parse.h
@@ -0,0 +1,9 @@
+#ifndef PARSE_H
+#define PARSE_H
+
+#include <stddef.h>
+#include "doc.h"
+
+int parse_doc(enum doc_type doct, int (*line_get)(char **, size_t *));
+
+#endif