diff options
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 131 |
1 files changed, 108 insertions, 23 deletions
@@ -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!"); |
