Blob


1 /*
2 * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include "compat.h"
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <string.h>
23 #include "telescope.h"
24 #include "mcache.h"
25 #include "parser.h"
27 const char *gemtext_prefixes[] = {
28 [LINE_TEXT] = "",
29 [LINE_TITLE_1] = "# ",
30 [LINE_TITLE_2] = "## ",
31 [LINE_TITLE_3] = "### ",
32 [LINE_ITEM] = "* ",
33 [LINE_QUOTE] = "> ",
34 [LINE_PRE_START] = "``` ",
35 [LINE_PRE_CONTENT] = "",
36 [LINE_PRE_END] = "```",
37 };
39 struct mcache {
40 struct ohash h;
41 size_t tot;
42 } mcache;
44 struct mcache_entry {
45 const char *parser_name;
46 int trust;
47 struct evbuffer *evb;
48 char url[];
49 };
51 static void *hash_alloc(size_t, void *);
52 static void *hash_calloc(size_t, size_t, void *);
53 static void hash_free(void *, void *);
55 static void *
56 hash_alloc(size_t len, void *d)
57 {
58 if ((d = malloc(len)) == NULL)
59 abort();
60 return d;
61 }
63 static void *
64 hash_calloc(size_t nmemb, size_t size, void *d)
65 {
66 if ((d = calloc(nmemb, size)) == NULL)
67 abort();
68 return d;
69 }
71 static void
72 hash_free(void *ptr, void *d)
73 {
74 free(ptr);
75 }
77 void
78 mcache_init(void)
79 {
80 struct ohash_info info = {
81 .key_offset = offsetof(struct mcache_entry, url),
82 .calloc = hash_calloc,
83 .free = hash_free,
84 .alloc = hash_alloc,
85 };
87 ohash_init(&mcache.h, 5, &info);
88 }
90 int
91 mcache_tab(struct tab *tab)
92 {
93 struct mcache_entry *e;
94 struct line *line;
95 unsigned int slot;
96 size_t l, len;
97 const char *url;
99 url = tab->hist_cur->h;
100 l = strlen(url);
101 len = sizeof(*e) + l + 1;
103 if ((e = calloc(1, len)) == NULL)
104 return -1;
105 e->parser_name = tab->buffer.page.name;
106 e->trust = tab->trust;
107 memcpy(e->url, url, l);
109 if ((e->evb = evbuffer_new()) == NULL)
110 goto err;
112 TAILQ_FOREACH(line, &tab->buffer.page.head, lines) {
113 const char *text, *alt;
114 int r;
116 if ((text = line->line) == NULL)
117 text = "";
119 if ((alt = line->alt) == NULL)
120 alt = "";
122 switch (line->type) {
123 case LINE_TEXT:
124 case LINE_TITLE_1:
125 case LINE_TITLE_2:
126 case LINE_TITLE_3:
127 case LINE_ITEM:
128 case LINE_QUOTE:
129 case LINE_PRE_START:
130 case LINE_PRE_CONTENT:
131 case LINE_PRE_END:
132 r = evbuffer_add_printf(e->evb, "%s%s\n",
133 gemtext_prefixes[line->type], text);
134 break;
136 case LINE_LINK:
137 r = evbuffer_add_printf(e->evb, "=> %s %s\n",
138 alt, text);
139 break;
141 case LINE_PATCH:
142 case LINE_PATCH_HDR:
143 case LINE_PATCH_HUNK_HDR:
144 case LINE_PATCH_ADD:
145 case LINE_PATCH_DEL:
146 /* TODO */
147 r = -1;
148 break;
150 case LINE_COMPL:
151 case LINE_COMPL_CURRENT:
152 case LINE_HELP:
153 case LINE_DOWNLOAD:
154 case LINE_DOWNLOAD_DONE:
155 case LINE_DOWNLOAD_INFO:
156 case LINE_FRINGE:
157 /* not reached */
158 abort();
161 if (r == -1)
162 goto err;
165 slot = ohash_qlookup(&mcache.h, url);
166 ohash_insert(&mcache.h, slot, e);
167 return 0;
169 err:
170 if (e->evb != NULL)
171 evbuffer_free(e->evb);
172 free(e);
173 return -1;
176 int
177 mcache_lookup(const char *url, struct tab *tab)
179 struct mcache_entry *e;
180 unsigned int slot;
182 slot = ohash_qlookup(&mcache.h, url);
183 if ((e = ohash_find(&mcache.h, slot)) == NULL)
184 return 0;
186 parser_init(tab, gemtext_initparser);
187 if (!parser_parse(tab, EVBUFFER_DATA(e->evb), EVBUFFER_LENGTH(e->evb)))
188 goto err;
189 if (!parser_free(tab))
190 goto err;
192 tab->buffer.page.name = e->parser_name;
193 tab->trust = e->trust;
194 return 1;
196 err:
197 parser_free(tab);
198 erase_buffer(&tab->buffer);
199 return 0;