Blob


1 /*
2 * Copyright (c) 2021 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 <string.h>
22 #include "hist.h"
23 #include "parser.h"
24 #include "telescope.h"
25 #include "xwrapper.h"
27 static int parser_foreach_line(struct buffer *, const char *, size_t);
29 void
30 parser_init(struct buffer *buffer, const struct parser *p)
31 {
32 erase_buffer(buffer);
34 memset(buffer->title, 0, sizeof(buffer->title));
35 buffer->parser = p;
36 buffer->mode = p->name;
37 buffer->parser_flags = p->initflags;
38 }
40 int
41 parser_parse(struct buffer *buffer, const char *chunk, size_t len)
42 {
43 const struct parser *p = buffer->parser;
45 if (p->parse)
46 return p->parse(buffer, chunk, len);
47 return parser_foreach_line(buffer, chunk, len);
48 }
50 int
51 parser_parsef(struct buffer *buffer, const char *fmt, ...)
52 {
53 char *s;
54 va_list ap;
55 int r;
57 va_start(ap, fmt);
58 r = vasprintf(&s, fmt, ap);
59 va_end(ap);
61 if (r == -1)
62 return 0;
64 r = parser_parse(buffer, s, strlen(s));
65 free(s);
66 return r;
67 }
69 int
70 parser_free(struct tab *tab)
71 {
72 struct buffer *buffer = &tab->buffer;
73 const struct parser *p = buffer->parser;
74 int r = 1;
75 char *tilde, *slash;
77 if (p->free) {
78 r = p->free(buffer);
79 } else if (buffer->len != 0) {
80 if (p->parse)
81 r = p->parse(buffer, buffer->buf, buffer->len);
82 else
83 r = parser_foreach_line(buffer, buffer->buf,
84 buffer->len);
85 }
87 free(buffer->buf);
88 buffer->buf = NULL;
89 buffer->len = 0;
91 if (*buffer->title != '\0')
92 return r;
94 /*
95 * heuristic: see if there is a "tilde user" and use that as
96 * page title, using the full domain name as fallback.
97 */
98 if ((tilde = strstr(hist_cur(tab->hist), "/~")) != NULL) {
99 strlcpy(buffer->title, tilde+1, sizeof(buffer->title));
101 if ((slash = strchr(buffer->title, '/')) != NULL)
102 *slash = '\0';
103 } else
104 strlcpy(buffer->title, tab->iri.iri_host,
105 sizeof(buffer->title));
107 return r;
110 int
111 parser_serialize(struct buffer *b, FILE *fp)
113 const struct parser *p = b->parser;
114 struct line *line;
115 const char *text;
116 int r;
118 if (p->serialize != NULL)
119 return p->serialize(b, fp);
121 /* a default implementation good enough for plain text */
122 TAILQ_FOREACH(line, &b->head, lines) {
123 if ((text = line->line) == NULL)
124 text = "";
126 r = fprintf(fp, "%s\n", text);
127 if (r == -1)
128 return 0;
131 return 1;
134 static int
135 parser_append(struct buffer *b, const char *buf, size_t len)
137 size_t newlen;
138 char *t;
140 if (len == 0)
141 return (1);
143 newlen = len + b->len;
144 t = xcalloc(1, newlen);
145 memcpy(t, b->buf, b->len);
146 memcpy(t + b->len, buf, len);
147 free(b->buf);
148 b->buf = t;
149 b->len = newlen;
150 return 1;
153 static int
154 parser_set_buf(struct buffer *b, const char *buf, size_t len)
156 char *tmp;
158 if (len == 0) {
159 b->len = 0;
160 free(b->buf);
161 b->buf = NULL;
162 return 1;
165 /*
166 * p->buf and buf can (and probably almost always will)
167 * overlap!
168 */
170 tmp = xcalloc(1, len);
171 memcpy(tmp, buf, len);
172 free(b->buf);
173 b->buf = tmp;
174 b->len = len;
175 return 1;
178 static int
179 parser_foreach_line(struct buffer *b, const char *buf, size_t size)
181 const struct parser *p = b->parser;
182 char *beg, *end;
183 unsigned int ch;
184 size_t i, l, len;
186 if (!parser_append(b, buf, size))
187 return 0;
188 beg = b->buf;
189 len = b->len;
191 if (!(b->parser_flags & PARSER_IN_BODY) && len < 3)
192 return 1;
194 if (!(b->parser_flags & PARSER_IN_BODY)) {
195 b->parser_flags |= PARSER_IN_BODY;
197 /*
198 * drop the BOM: only UTF-8 is supported, and there
199 * it's useless; some editors may still add one
200 * though.
201 */
202 if (memmem(beg, len, "\xEF\xBB\xBF", 3) == beg) {
203 b += 3;
204 len -= 3;
208 /* drop every "funny" ASCII character */
209 for (i = 0; i < len; ) {
210 ch = beg[i];
211 if ((ch >= ' ' || ch == '\n' || ch == '\t')
212 && ch != 127) { /* del */
213 ++i;
214 continue;
216 memmove(&beg[i], &beg[i+1], len - i - 1);
217 len--;
220 while (len > 0) {
221 if ((end = memmem((char*)beg, len, "\n", 1)) == NULL)
222 break;
223 l = end - beg;
225 if (!p->parseline(b, beg, l))
226 return 0;
228 len -= l;
229 beg += l;
231 if (len > 0) {
232 /* skip \n */
233 len--;
234 beg++;
238 return parser_set_buf(b, beg, len);