commit - 5a21e0eb51554d72c1b6465c2b4afc8cdef5dcf1
commit + 069c9a92f36df9d307d734ffa8903035c7181129
blob - b89e63d8364e6a429b45b91d9389d6f1c3cc8b46
blob + 44bab64a89cb50c8229446662395b7912dc7e7f6
--- parser.c
+++ parser.c
}
int
+parser_serialize(struct tab *tab, struct evbuffer *evb)
+{
+ struct line *line;
+ const char *text;
+ int r;
+
+ if (tab->buffer.page.serialize != NULL)
+ return tab->buffer.page.serialize(&tab->buffer.page, evb);
+
+ /* a default implementation good enough for plain text */
+ TAILQ_FOREACH(line, &tab->buffer.page.head, lines) {
+ if ((text = line->line) == NULL)
+ text = "";
+
+ r = evbuffer_add_printf(evb, "%s\n", text);
+ if (r == -1)
+ return 0;
+ }
+
+ return 1;
+}
+
+int
parser_append(struct parser *p, const char *buf, size_t len)
{
size_t newlen;
blob - 63be7ce5d280b6dd51d837b3fc21ca0132203642
blob + b4cb238fd315805241fb22da61a10bbc6d54b1b7
--- parser.h
+++ parser.h
void parser_init(struct tab *, parserfn);
int parser_parse(struct tab *, const char *, size_t);
int parser_free(struct tab *);
+int parser_serialize(struct tab *, struct evbuffer *);
int parser_append(struct parser*, const char*, size_t);
int parser_set_buf(struct parser*, const char*, size_t);
blob - e772078332f5f233f43f5e6af086619664ed3d8f
blob + e23b368b5089ed079d433d6d5f8803e3f2480373
--- parser_gemtext.c
+++ parser_gemtext.c
/*
- * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2021, 2022 Omar Polo <op@omarpolo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include "parser.h"
#include "utf8.h"
-static int gemtext_parse(struct parser*, const char*, size_t);
-static int gemtext_foreach_line(struct parser*, const char*, size_t);
-static int gemtext_free(struct parser*);
+static int gemtext_parse(struct parser *, const char *, size_t);
+static int gemtext_foreach_line(struct parser *, const char *, size_t);
+static int gemtext_free(struct parser *);
+static int gemtext_serialize(struct parser *, struct evbuffer *);
static int parse_text(struct parser*, enum line_type, const char*, size_t);
static int parse_link(struct parser*, enum line_type, const char*, size_t);
p->name = "text/gemini";
p->parse = &gemtext_parse;
p->free = &gemtext_free;
+ p->serialize = &gemtext_serialize;
TAILQ_INIT(&p->head);
}
if (l->line == NULL)
continue;
strlcpy(p->title, l->line, sizeof(p->title));
+ break;
+ }
+ }
+}
+
+static const char *gemtext_prefixes[] = {
+ [LINE_TEXT] = "",
+ [LINE_TITLE_1] = "# ",
+ [LINE_TITLE_2] = "## ",
+ [LINE_TITLE_3] = "### ",
+ [LINE_ITEM] = "* ",
+ [LINE_QUOTE] = "> ",
+ [LINE_PRE_START] = "``` ",
+ [LINE_PRE_CONTENT] = "",
+ [LINE_PRE_END] = "```",
+};
+
+static int
+gemtext_serialize(struct parser *p, struct evbuffer *evb)
+{
+ struct line *line;
+ const char *text;
+ const char *alt;
+ int r;
+
+ TAILQ_FOREACH(line, &p->head, lines) {
+ if ((text = line->line) == NULL)
+ text = "";
+
+ if ((alt = line->alt) == NULL)
+ alt = "";
+
+ switch (line->type) {
+ case LINE_TEXT:
+ case LINE_TITLE_1:
+ case LINE_TITLE_2:
+ case LINE_TITLE_3:
+ case LINE_ITEM:
+ case LINE_QUOTE:
+ case LINE_PRE_START:
+ case LINE_PRE_CONTENT:
+ case LINE_PRE_END:
+ r = evbuffer_add_printf(evb, "%s%s\n",
+ gemtext_prefixes[line->type], text);
break;
+
+ case LINE_LINK:
+ r = evbuffer_add_printf(evb, "=> %s %s\n",
+ alt, text);
+ break;
+
+ default:
+ /* not reached */
+ abort();
}
+
+ if (r == -1)
+ return 0;
}
+
+ return 1;
}
blob - bc51dcb440974643ff5fa60e8629c61fef3cc857
blob + 27a3142a5eb4ef23844d4074b1022269612c4ffa
--- parser_gophermap.c
+++ parser_gophermap.c
#include "parser.h"
#include "utils.h"
+#define evap evbuffer_add_printf
+
struct gm_selector {
char type;
const char *ds;
static int gm_parse(struct parser *, const char *, size_t);
static int gm_foreach_line(struct parser *, const char *, size_t);
static int gm_free(struct parser *);
+static int gm_serialize(struct parser *, struct evbuffer *);
void
gophermap_initparser(struct parser *p)
p->name = "gophermap";
p->parse = &gm_parse;
p->free = &gm_free;
+ p->serialize = &gm_serialize;
TAILQ_INIT(&p->head);
}
return 1;
}
+
+static inline const char *
+gopher_skip_selector(const char *path, int *ret_type)
+{
+ *ret_type = 0;
+
+ if (!strcmp(path, "/") || *path == '\0') {
+ *ret_type = '1';
+ return path;
+ }
+
+ if (*path != '/')
+ return path;
+ path++;
+
+ switch (*ret_type = *path) {
+ case '0':
+ case '1':
+ case '7':
+ break;
+
+ default:
+ *ret_type = 0;
+ path -= 1;
+ return path;
+ }
+
+ return ++path;
+}
+
+static int
+serialize_link(struct line *line, const char *text, struct evbuffer *evb)
+{
+ size_t portlen = 0;
+ int type;
+ const char *uri, *endhost, *port, *path, *colon;
+
+ if ((uri = line->alt) == NULL)
+ return -1;
+
+ if (!has_prefix(uri, "gopher://"))
+ return evap(evb, "h%s\tURL:%s\terror.host\t1\n",
+ text, line->alt);
+
+ uri += 9; /* skip gopher:// */
+
+ path = strchr(uri, '/');
+ colon = strchr(uri, ':');
+
+ if (path != NULL && colon > path)
+ colon = NULL;
+
+ if ((endhost = colon) == NULL &&
+ (endhost = path) == NULL)
+ endhost = strchr(path, '\0');
+
+ if (colon != NULL) {
+ for (port = colon+1; *port && *port != '/'; ++port)
+ ++portlen;
+ port = colon+1;
+ } else {
+ port = "70";
+ portlen = 2;
+ }
+
+ if (path == NULL) {
+ type = '1';
+ path = "";
+ } else
+ path = gopher_skip_selector(path, &type);
+
+ return evap(evb, "%c%s\t%s\t%.*s\t%.*s\n", type, text,
+ path, (int)(endhost - uri), uri, (int)portlen, port);
+}
+
+static int
+gm_serialize(struct parser *p, struct evbuffer *evb)
+{
+ struct line *line;
+ const char *text;
+ int r;
+
+ TAILQ_FOREACH(line, &p->head, lines) {
+ if ((text = line->line) == NULL)
+ text = "";
+
+ switch (line->type) {
+ case LINE_LINK:
+ r = serialize_link(line, text, evb);
+ break;
+
+ case LINE_TEXT:
+ r = evap(evb, "i%s\t\terror.host\t1\n",
+ text);
+ break;
+
+ case LINE_QUOTE:
+ r = evap(evb, "3%s\t\terror.host\t1\n",
+ text);
+ break;
+
+ default:
+ /* unreachable */
+ abort();
+ }
+
+ if (r == -1)
+ return 0;
+ }
+
+ return 1;
+}
blob - a0c403b048f20cad632c8a14e9a2edd106e24969
blob + 0d382ec23caf170cc4fcefab743e0b2626029bea
--- telescope.h
+++ telescope.h
typedef int (*parsechunkfn)(struct parser*, const char*, size_t);
typedef int (*parserfreefn)(struct parser*);
+typedef int (*parserserial)(struct parser*, struct evbuffer *);
typedef void (imsg_handlerfn)(struct imsg*, size_t);
void (*init)(struct parser *);
parsechunkfn parse;
parserfreefn free;
+ parserserial serialize;
TAILQ_HEAD(, line) head;
};