summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c131
1 files changed, 108 insertions, 23 deletions
diff --git a/main.c b/main.c
index f179c1b..38f0359 100644
--- a/main.c
+++ b/main.c
@@ -5,6 +5,7 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
+#include <stdarg.h>
#include <netdb.h>
#define ARENA_IMPL
@@ -14,19 +15,21 @@
#include "arena.h"
#include "str.h"
-/* address cache */
-
-#define ADDR_MAP_MAX 128
-#define ADDR_HOST_MAX 128
+/* utils */
-typedef struct {
- char host[ADDR_HOST_MAX];
- int hostn, port;
- struct addrinfo *ai;
-} AddrMap;
-
-static AddrMap addr_mapv[ADDR_MAP_MAX];
-static int addr_mapc = 0;
+Str
+str_fmt(Arena *a, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int n = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+ va_start(ap, fmt);
+ char *s = new_arr(a, char, n);
+ vsprintf(s, fmt, ap);
+ va_end(ap);
+ return (Str) { s, n };
+}
Str
uint_to_str(unsigned src, Arena *a)
@@ -44,6 +47,20 @@ uint_to_str(unsigned src, Arena *a)
return r;
}
+/* address cache */
+
+#define ADDR_MAP_MAX 128
+#define ADDR_HOST_MAX 128
+
+typedef struct {
+ char host[ADDR_HOST_MAX];
+ int hostn, port;
+ struct addrinfo *ai;
+} AddrMap;
+
+static AddrMap addr_mapv[ADDR_MAP_MAX];
+static int addr_mapc = 0;
+
struct addrinfo *
addr_get(Str host, int port, Arena *scratch)
{
@@ -154,7 +171,7 @@ parse_port(Str s) {
for (int i = 0; i < s.n; i++) {
if (s.s[i] < '0' || s.s[i] > '9') return -1;
if (x >= INT_MAX / 10 - 1) return -1;
- x = (x * 10) + s.s[i] - '0';
+ x = (x * 10) + (s.s[i] - '0');
}
return x;
}
@@ -223,13 +240,17 @@ typedef enum {
typedef struct DocLine {
struct DocLine *next, *prev;
Str s;
+ int link;
} DocLine;
+typedef DYNARR(Str) DocLinks;
+
typedef struct {
Arena arena;
DocType type;
Str src;
DocLine *head, *tail;
+ DocLinks links;
} Doc;
/* document parsing */
@@ -246,27 +267,84 @@ doc_push_line(Doc *d, Str s)
return n;
}
-int
-parse_text(Doc *d)
+void
+doc_link(Doc *d, DocLine *l, Str url)
{
+ DA_APUSH(&d->links, &d->arena, url);
+ l->link = d->links.n;
+}
+
+int
+parse_linewise(Doc *d, int (*fn)(Doc *, Str)) {
Str s = d->src;
while (s.n > 0) {
Cut c = str_cut(s, '\n');
- doc_push_line(d, c.head);
+ if (fn(d, str_trim(c.head)))
+ return -1;
s = c.tail;
}
return 0;
}
int
+parse_text_line(Doc *d, Str s)
+{
+ doc_push_line(d, s);
+ return 0;
+}
+
+int
+parse_gophermap_line(Doc *d, Str s)
+{
+ if (!s.n) {
+ doc_push_line(d, s);
+ return 0;
+ }
+
+ if (str_eql(s, S(".")))
+ return 0;
+
+ char item = s.s[0];
+ s = str_skip(s, 1);
+
+ Cut cdsp = str_cut(s, '\t');
+ Str dsp = cdsp.head;
+ s = cdsp.tail;
+
+ Cut csel = str_cut(s, '\t');
+ Str sel = csel.head;
+ s = csel.tail;
+
+ Cut chost = str_cut(s, '\t');
+ Str host = chost.head;
+ int port = parse_port(chost.tail);
+ if (port == -1) {
+ fprintf(stderr, "bad port '%.*s'\n",
+ (int)chost.tail.n, chost.tail.s);
+ return -1;
+ }
+
+ DocLine *l = doc_push_line(d, dsp);
+ if (item != 'i') {
+ Str url = str_fmt(&d->arena,
+ "=> gopher://%.*s:%d/%.*s",
+ (int)host.n, host.s,
+ port,
+ (int)sel.n, sel.s);
+ doc_link(d, l, url);
+ }
+
+ return 0;
+}
+
+int
parse_doc(Doc *d)
{
switch (d->type) {
case DOC_TEXT:
- return parse_text(d);
+ return parse_linewise(d, parse_text_line);
case DOC_GOPHERMAP:
- doc_push_line(d, S("Gophermaps are unimplemented"));
- return -1;
+ return parse_linewise(d, parse_gophermap_line);
case DOC_ERROR:
doc_push_line(d, S("Error"));
return -1;
@@ -367,7 +445,7 @@ main(void)
Request req = { 0 };
addr_init();
- printf("parse_request() -> %d\n", parse_request(S("gopher://tilde.town"), &req));
+ printf("parse_request() -> %d\n", parse_request(S("gopher://tilde.town/1~wrmr"), &req));
printf("host = %.*s\n", (int)req.host.n, req.host.s);
printf("path = %.*s\n", (int)req.path.n, req.path.s);
printf("prot = %d\n", req.proto);
@@ -380,18 +458,25 @@ main(void)
printf("parse() -> %d\n", parse_doc(&doc));
DocLine *l = doc.head;
- while (l) {
+ for (;;) {
int ln;
term_size(&ln, NULL);
- for (int i = 0; l && i < ln - 1; i++) {
- printf("%.*s\n", (int)l->s.n, l->s.s);
+ for (int i = 0; i < ln - 1; i++) {
+ if (l->link > 0) printf("[%d]", l->link);
+ printf("\t%.*s\n", (int)l->s.n, l->s.s);
+ if (!l->next) break;
l = l->next;
}
char buf[1024] = { 0 };
+ if (l->next) printf("MORE");
printf("* ");
fflush(stdout);
fgets(buf, 1023, stdin);
if (buf[0] == 'q') break;
+ if (buf[0] == 'b') {
+ for (int i = 0; l->prev && i < 2 * (ln - 1); i++)
+ l = l->prev;
+ }
}
puts("Goodbye!");