Line data Source code
1 : /*
2 : * lwan - web server
3 : * Copyright (c) 2012 L. A. F. Pereira <l@tia.mat.br>
4 : *
5 : * This program is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU General Public License
7 : * as published by the Free Software Foundation; either version 2
8 : * of the License, or any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 : * USA.
19 : */
20 : /*
21 : * Ideas from Mustache logic-less templates: http://mustache.github.com/
22 : * Lexer+parser implemented using ideas from Rob Pike's talk "Lexical Scanning
23 : * in Go" (https://www.youtube.com/watch?v=HxaD_trXwRE).
24 : */
25 :
26 : #define _GNU_SOURCE
27 : #include <ctype.h>
28 : #include <errno.h>
29 : #include <fcntl.h>
30 : #include <limits.h>
31 : #include <math.h>
32 : #include <stdarg.h>
33 : #include <stdbool.h>
34 : #include <stdint.h>
35 : #include <stdio.h>
36 : #include <stdlib.h>
37 : #include <string.h>
38 : #include <sys/mman.h>
39 : #include <sys/stat.h>
40 : #include <unistd.h>
41 :
42 : #include "lwan-private.h"
43 :
44 : #include "hash.h"
45 : #include "int-to-str.h"
46 : #include "list.h"
47 : #include "ringbuffer.h"
48 : #include "lwan-array.h"
49 : #include "lwan-strbuf.h"
50 : #include "lwan-template.h"
51 :
52 : /* Define this and build a debug version to have the template
53 : * chunks printed out after compilation. */
54 : #undef TEMPLATE_DEBUG
55 :
56 : #define LEXEME_MAX_LEN 64
57 :
58 : enum action {
59 : ACTION_APPEND,
60 : ACTION_APPEND_SMALL,
61 : ACTION_VARIABLE,
62 : ACTION_VARIABLE_STR,
63 : ACTION_VARIABLE_STR_ESCAPE,
64 : ACTION_START_ITER,
65 : ACTION_END_ITER,
66 : ACTION_IF_VARIABLE_NOT_EMPTY,
67 : ACTION_END_IF_VARIABLE_NOT_EMPTY,
68 : ACTION_APPLY_TPL,
69 : ACTION_LAST
70 : };
71 :
72 : enum flags {
73 : FLAGS_ALL = -1,
74 : FLAGS_NEGATE = 1 << 0,
75 : FLAGS_QUOTE = 1 << 1,
76 : FLAGS_NO_FREE = 1 << 2,
77 : };
78 :
79 : #define FOR_EACH_LEXEME(X) \
80 : X(ERROR) X(EOF) X(IDENTIFIER) X(LEFT_META) X(HASH) X(RIGHT_META) X(TEXT) \
81 : X(SLASH) X(QUESTION_MARK) X(HAT) X(GREATER_THAN) X(OPEN_CURLY_BRACE) \
82 : X(CLOSE_CURLY_BRACE)
83 :
84 : #define GENERATE_ENUM(id) LEXEME_##id,
85 : #define GENERATE_ARRAY_ITEM(id) [LEXEME_##id] = #id,
86 :
87 : enum lexeme_type {
88 : FOR_EACH_LEXEME(GENERATE_ENUM)
89 : TOTAL_LEXEMES
90 : };
91 :
92 : static const char *lexeme_type_str[TOTAL_LEXEMES] = {
93 : FOR_EACH_LEXEME(GENERATE_ARRAY_ITEM)
94 : };
95 :
96 : #undef GENERATE_ENUM
97 : #undef GENERATE_ARRAY_ITEM
98 :
99 : struct chunk {
100 : const void *instruction;
101 : void *data;
102 : enum flags flags;
103 : enum action action;
104 : };
105 :
106 5954 : DEFINE_ARRAY_TYPE(chunk_array, struct chunk)
107 :
108 : struct lwan_tpl {
109 : struct chunk_array chunks;
110 : size_t minimum_size;
111 : bool dispatch_table_direct;
112 : };
113 :
114 : struct symtab {
115 : struct hash *hash;
116 : struct symtab *next;
117 : };
118 :
119 : struct lexeme {
120 : enum lexeme_type type;
121 : struct {
122 : const char *value;
123 : size_t len;
124 : } value;
125 : };
126 :
127 118475 : DEFINE_RING_BUFFER_TYPE(lexeme_ring_buffer, struct lexeme, 4)
128 :
129 : struct lexer {
130 : void *(*state)(struct lexer *);
131 : const char *start, *pos, *end;
132 :
133 : struct lexeme_ring_buffer ring_buffer;
134 : };
135 :
136 : struct parser {
137 : struct lwan_tpl *tpl;
138 : const struct lwan_var_descriptor *descriptor;
139 : struct symtab *symtab;
140 : struct lexer lexer;
141 : enum flags flags;
142 : struct list_head stack;
143 : struct chunk_array chunks;
144 : enum lwan_tpl_flag template_flags;
145 : };
146 :
147 : struct stacked_lexeme {
148 : struct list_node stack;
149 : struct lexeme lexeme;
150 : };
151 :
152 : struct chunk_descriptor {
153 : struct chunk *chunk;
154 : struct lwan_var_descriptor *descriptor;
155 : };
156 :
157 : static const char left_meta[] = "{{";
158 : static const char right_meta[] = "}}";
159 : static_assert(sizeof(left_meta) == sizeof(right_meta),
160 : "right_meta and left_meta are the same length");
161 :
162 : static void *lex_inside_action(struct lexer *lexer);
163 : static void *lex_identifier(struct lexer *lexer);
164 : static void *lex_left_meta(struct lexer *lexer);
165 : static void *lex_right_meta(struct lexer *lexer);
166 : static void *lex_text(struct lexer *lexer);
167 :
168 : static void *parser_end_iter(struct parser *parser, struct lexeme *lexeme);
169 : static void *parser_end_var_not_empty(struct parser *parser,
170 : struct lexeme *lexeme);
171 : static void *parser_iter(struct parser *parser, struct lexeme *lexeme);
172 : static void *parser_meta(struct parser *parser, struct lexeme *lexeme);
173 : static void *parser_negate(struct parser *parser, struct lexeme *lexeme);
174 : static void *parser_identifier(struct parser *parser, struct lexeme *lexeme);
175 : static void *parser_slash(struct parser *parser, struct lexeme *lexeme);
176 : static void *parser_text(struct parser *parser, struct lexeme *lexeme);
177 :
178 : static void error_vlexeme(struct lexeme *lexeme, const char *msg, va_list ap)
179 : __attribute__((format(printf, 2, 0)));
180 : static void *error_lexeme(struct lexeme *lexeme, const char *msg, ...)
181 : __attribute__((format(printf, 2, 3)));
182 : static void *lex_error(struct lexer *lexer, const char *msg, ...)
183 : __attribute__((format(printf, 2, 3)));
184 :
185 2466 : static struct lwan_var_descriptor *symtab_lookup(struct parser *parser,
186 : const char *var_name)
187 : {
188 2645 : for (struct symtab *tab = parser->symtab; tab; tab = tab->next) {
189 2645 : struct lwan_var_descriptor *var = hash_find(tab->hash, var_name);
190 2645 : if (var)
191 2466 : return var;
192 : }
193 :
194 0 : return NULL;
195 : }
196 :
197 : static __attribute__((noinline)) struct lwan_var_descriptor *
198 2466 : symtab_lookup_lexeme(struct parser *parser, struct lexeme *lexeme)
199 : {
200 2466 : if (lexeme->value.len > LEXEME_MAX_LEN) {
201 0 : lwan_status_error("Lexeme exceeds %d characters", LEXEME_MAX_LEN);
202 0 : return NULL;
203 : }
204 :
205 2466 : return symtab_lookup(parser,
206 2466 : strndupa(lexeme->value.value, lexeme->value.len));
207 : }
208 :
209 363 : static int symtab_push(struct parser *parser,
210 : const struct lwan_var_descriptor *descriptor)
211 : {
212 : struct symtab *tab;
213 : int r;
214 :
215 363 : if (!descriptor)
216 0 : return -ENODEV;
217 :
218 363 : tab = malloc(sizeof(*tab));
219 363 : if (!tab)
220 0 : return -errno;
221 :
222 363 : tab->hash = hash_str_new(NULL, NULL);
223 363 : if (!tab->hash) {
224 0 : r = -ENOMEM;
225 0 : goto hash_new_err;
226 : }
227 :
228 363 : tab->next = parser->symtab;
229 363 : parser->symtab = tab;
230 :
231 2302 : for (; descriptor->name; descriptor++) {
232 1939 : r = hash_add(parser->symtab->hash, descriptor->name, descriptor);
233 :
234 1939 : if (r < 0)
235 0 : goto hash_add_err;
236 : }
237 :
238 363 : return 0;
239 :
240 0 : hash_add_err:
241 0 : hash_free(tab->hash);
242 0 : hash_new_err:
243 0 : free(tab);
244 :
245 0 : return r;
246 : }
247 :
248 363 : static void symtab_pop(struct parser *parser)
249 : {
250 363 : struct symtab *tab = parser->symtab;
251 :
252 363 : assert(tab);
253 :
254 363 : hash_free(tab->hash);
255 363 : parser->symtab = tab->next;
256 363 : free(tab);
257 363 : }
258 :
259 12069 : static void emit_lexeme(struct lexer *lexer, struct lexeme *lexeme)
260 : {
261 12069 : lexeme_ring_buffer_put(&lexer->ring_buffer, lexeme);
262 12069 : lexer->start = lexer->pos;
263 12069 : }
264 :
265 12069 : static void emit(struct lexer *lexer, enum lexeme_type lexeme_type)
266 : {
267 12069 : struct lexeme lexeme = {
268 : .type = lexeme_type,
269 : .value = {
270 12069 : .value = lexer->start,
271 12069 : .len = (size_t)(lexer->pos - lexer->start)
272 : }
273 : };
274 12069 : emit_lexeme(lexer, &lexeme);
275 12069 : }
276 :
277 199757 : static int next(struct lexer *lexer)
278 : {
279 199757 : if (lexer->pos >= lexer->end)
280 184 : return EOF;
281 199573 : int r = *lexer->pos;
282 199573 : lexer->pos++;
283 199573 : return r;
284 : }
285 :
286 336428 : static size_t remaining(struct lexer *lexer)
287 : {
288 336428 : return (size_t)(lexer->end - lexer->pos);
289 : }
290 :
291 336428 : static bool lex_streq(struct lexer *lexer, const char *str, size_t s)
292 : {
293 336428 : if (remaining(lexer) < s)
294 736 : return false;
295 :
296 335692 : return !strncmp(lexer->pos, str, s);
297 : }
298 :
299 0 : static void ignore(struct lexer *lexer) { lexer->start = lexer->pos; }
300 :
301 7224 : static void backup(struct lexer *lexer) { lexer->pos--; }
302 :
303 0 : static void error_vlexeme(struct lexeme *lexeme, const char *msg, va_list ap)
304 : {
305 : char *formatted;
306 : size_t formatted_len;
307 : int r;
308 :
309 0 : *lexeme = (struct lexeme){.type = LEXEME_ERROR};
310 :
311 0 : r = vasprintf(&formatted, msg, ap);
312 0 : if (r < 0) {
313 0 : lexeme->value.value = strdup(strerror(errno));
314 0 : if (!lexeme->value.value)
315 0 : return;
316 :
317 0 : formatted_len = strlen(lexeme->value.value);
318 : } else {
319 0 : formatted_len = (size_t)r;
320 : }
321 :
322 0 : lwan_status_error("Error while parsing template: %.*s", (int)formatted_len, formatted);
323 0 : free(formatted);
324 : }
325 :
326 0 : static void *error_lexeme(struct lexeme *lexeme, const char *msg, ...)
327 : {
328 : va_list ap;
329 :
330 0 : va_start(ap, msg);
331 0 : error_vlexeme(lexeme, msg, ap);
332 0 : va_end(ap);
333 :
334 0 : return NULL;
335 : }
336 :
337 0 : static void *lex_error(struct lexer *lexer, const char *msg, ...)
338 : {
339 : struct lexeme lexeme;
340 : va_list ap;
341 :
342 0 : va_start(ap, msg);
343 0 : error_vlexeme(&lexeme, msg, ap);
344 0 : va_end(ap);
345 :
346 0 : emit_lexeme(lexer, &lexeme);
347 0 : return NULL;
348 : }
349 :
350 31466 : static bool is_ident(int ch)
351 : {
352 31466 : return isalnum(ch) || ch == '_' || ch == '.' || ch == '/';
353 : }
354 :
355 2466 : static void *lex_identifier(struct lexer *lexer)
356 : {
357 29174 : while (is_ident(next(lexer)))
358 : ;
359 2466 : backup(lexer);
360 2466 : emit(lexer, LEXEME_IDENTIFIER);
361 2466 : return lex_inside_action;
362 : }
363 :
364 0 : static void *lex_partial(struct lexer *lexer)
365 : {
366 0 : while (true) {
367 0 : int r = next(lexer);
368 :
369 0 : if (r == EOF)
370 0 : return lex_error(lexer, "unexpected EOF while scanning action");
371 0 : if (r == '\n')
372 0 : return lex_error(lexer, "actions cannot span multiple lines");
373 0 : if (isspace(r)) {
374 0 : ignore(lexer);
375 0 : continue;
376 : }
377 0 : if (is_ident(r)) {
378 0 : backup(lexer);
379 0 : return lex_identifier;
380 : }
381 0 : return lex_error(lexer, "unexpected character: %c", r);
382 : }
383 : }
384 :
385 174 : static void *lex_quoted_identifier(struct lexer *lexer)
386 : {
387 : int r;
388 :
389 174 : emit(lexer, LEXEME_OPEN_CURLY_BRACE);
390 174 : lex_identifier(lexer);
391 :
392 174 : r = next(lexer);
393 174 : if (r != '}')
394 0 : return lex_error(lexer, "expecting `}', found `%c'", r);
395 :
396 174 : emit(lexer, LEXEME_CLOSE_CURLY_BRACE);
397 174 : return lex_inside_action;
398 : }
399 :
400 0 : static void *lex_comment(struct lexer *lexer)
401 : {
402 0 : size_t brackets = strlen(left_meta);
403 :
404 : do {
405 0 : int r = next(lexer);
406 0 : if (r == '{')
407 0 : brackets++;
408 0 : else if (r == '}')
409 0 : brackets--;
410 0 : else if (r == EOF)
411 0 : return lex_error(lexer,
412 : "unexpected EOF while scanning comment end");
413 0 : } while (brackets);
414 :
415 0 : ignore(lexer);
416 0 : return lex_text;
417 : }
418 :
419 6856 : static void *lex_inside_action(struct lexer *lexer)
420 : {
421 0 : while (true) {
422 : int r;
423 :
424 6856 : if (lex_streq(lexer, right_meta, strlen(right_meta)))
425 2466 : return lex_right_meta;
426 :
427 4390 : r = next(lexer);
428 4390 : switch (r) {
429 0 : case EOF:
430 0 : return lex_error(lexer, "unexpected EOF while scanning action");
431 0 : case '\n':
432 0 : return lex_error(lexer, "actions cannot span multiple lines");
433 179 : case '#':
434 179 : emit(lexer, LEXEME_HASH);
435 179 : break;
436 870 : case '?':
437 870 : emit(lexer, LEXEME_QUESTION_MARK);
438 870 : break;
439 261 : case '^':
440 261 : emit(lexer, LEXEME_HAT);
441 261 : break;
442 0 : case '>':
443 0 : emit(lexer, LEXEME_GREATER_THAN);
444 0 : return lex_partial;
445 174 : case '{':
446 174 : return lex_quoted_identifier;
447 614 : case '/':
448 614 : emit(lexer, LEXEME_SLASH);
449 614 : break;
450 2292 : default:
451 2292 : if (isspace(r)) {
452 0 : ignore(lexer);
453 0 : continue;
454 : }
455 2292 : if (is_ident(r)) {
456 2292 : backup(lexer);
457 2292 : return lex_identifier;
458 : }
459 :
460 0 : return lex_error(lexer, "unexpected character: %c", r);
461 : }
462 :
463 1924 : return lex_inside_action;
464 : }
465 : }
466 :
467 2466 : static void *lex_left_meta(struct lexer *lexer)
468 : {
469 2466 : lexer->pos += strlen(left_meta);
470 2466 : int r = next(lexer);
471 2466 : if (r == '!')
472 0 : return lex_comment;
473 2466 : backup(lexer);
474 :
475 2466 : emit(lexer, LEXEME_LEFT_META);
476 2466 : return lex_inside_action;
477 : }
478 :
479 2466 : static void *lex_right_meta(struct lexer *lexer)
480 : {
481 2466 : lexer->pos += strlen(right_meta);
482 2466 : emit(lexer, LEXEME_RIGHT_META);
483 2466 : return lex_text;
484 : }
485 :
486 2650 : static void *lex_text(struct lexer *lexer)
487 : {
488 : do {
489 166019 : if (lex_streq(lexer, left_meta, strlen(left_meta))) {
490 2466 : if (lexer->pos > lexer->start)
491 2031 : emit(lexer, LEXEME_TEXT);
492 2466 : return lex_left_meta;
493 : }
494 :
495 163553 : if (lex_streq(lexer, right_meta, strlen(right_meta)))
496 0 : return lex_error(lexer, "unexpected action close sequence");
497 163553 : } while (next(lexer) != EOF);
498 184 : if (lexer->pos > lexer->start)
499 184 : emit(lexer, LEXEME_TEXT);
500 184 : emit(lexer, LEXEME_EOF);
501 184 : return NULL;
502 : }
503 :
504 12069 : static struct lexeme *lex_next_fsm_loop(struct lexer *lexer)
505 : {
506 : struct lexeme *lexeme;
507 :
508 28973 : while (lexer->state) {
509 28605 : if ((lexeme = lexeme_ring_buffer_get_ptr_or_null(&lexer->ring_buffer)))
510 11701 : return lexeme;
511 :
512 16904 : lexer->state = lexer->state(lexer);
513 : }
514 :
515 368 : return lexeme_ring_buffer_get_ptr_or_null(&lexer->ring_buffer);
516 : }
517 :
518 12069 : static struct lexeme *lex_next(struct lexer *lexer)
519 : {
520 12069 : struct lexeme *lexeme = lex_next_fsm_loop(lexer);
521 :
522 12069 : if (lexeme && lexeme->type == LEXEME_ERROR)
523 0 : return NULL;
524 :
525 12069 : return lexeme;
526 : }
527 :
528 184 : static void lex_init(struct lexer *lexer, const char *input)
529 : {
530 184 : lexer->state = lex_text;
531 184 : lexer->pos = lexer->start = input;
532 184 : lexer->end = input + strlen(input);
533 184 : lexeme_ring_buffer_init(&lexer->ring_buffer);
534 184 : }
535 :
536 0 : static void *unexpected_lexeme(struct lexeme *lexeme)
537 : {
538 0 : if (lexeme->type == LEXEME_ERROR)
539 0 : return NULL;
540 :
541 0 : return error_lexeme(lexeme, "unexpected lexeme: %s [%.*s]",
542 0 : lexeme_type_str[lexeme->type], (int)lexeme->value.len,
543 : lexeme->value.value);
544 : }
545 :
546 614 : static void parser_push_lexeme(struct parser *parser, struct lexeme *lexeme)
547 : {
548 614 : struct stacked_lexeme *stacked_lexeme = malloc(sizeof(*stacked_lexeme));
549 614 : if (!stacked_lexeme)
550 0 : lwan_status_critical_perror("Could not push parser lexeme");
551 :
552 614 : stacked_lexeme->lexeme = *lexeme;
553 614 : list_add(&parser->stack, &stacked_lexeme->stack);
554 614 : }
555 :
556 4865 : static void emit_chunk(struct parser *parser,
557 : enum action action,
558 : enum flags flags,
559 : void *data)
560 : {
561 : struct chunk *chunk;
562 :
563 4865 : chunk = chunk_array_append(&parser->chunks);
564 4865 : if (!chunk)
565 0 : lwan_status_critical_perror("Could not emit template chunk");
566 :
567 4865 : chunk->action = action;
568 4865 : chunk->flags = flags;
569 4865 : chunk->data = data;
570 4865 : }
571 :
572 614 : static bool parser_stack_top_matches(struct parser *parser,
573 : struct lexeme *lexeme,
574 : enum lexeme_type type)
575 : {
576 614 : if (list_empty(&parser->stack)) {
577 0 : error_lexeme(lexeme, "unexpected {{/%.*s}}", (int)lexeme->value.len,
578 : lexeme->value.value);
579 0 : return false;
580 : }
581 :
582 614 : struct stacked_lexeme *stacked_lexeme =
583 : (struct stacked_lexeme *)parser->stack.n.next;
584 1842 : bool matches = (stacked_lexeme->lexeme.type == type &&
585 1228 : lexeme->value.len == stacked_lexeme->lexeme.value.len &&
586 614 : !memcmp(stacked_lexeme->lexeme.value.value,
587 614 : lexeme->value.value, lexeme->value.len));
588 614 : if (matches) {
589 614 : list_del(&stacked_lexeme->stack);
590 614 : free(stacked_lexeme);
591 614 : return true;
592 : }
593 :
594 0 : error_lexeme(lexeme, "expecting %s `%.*s' but found `%.*s'",
595 0 : lexeme_type_str[stacked_lexeme->lexeme.type],
596 0 : (int)stacked_lexeme->lexeme.value.len,
597 0 : stacked_lexeme->lexeme.value.value, (int)lexeme->value.len,
598 : lexeme->value.value);
599 0 : return false;
600 : }
601 :
602 1049 : static void *parser_right_meta(struct parser *parser __attribute__((unused)),
603 : struct lexeme *lexeme)
604 : {
605 1049 : if (lexeme->type != LEXEME_RIGHT_META)
606 0 : return unexpected_lexeme(lexeme);
607 1049 : return parser_text;
608 : }
609 :
610 179 : static void *parser_end_iter(struct parser *parser, struct lexeme *lexeme)
611 : {
612 : struct chunk *iter;
613 : struct lwan_var_descriptor *symbol;
614 :
615 179 : if (!parser_stack_top_matches(parser, lexeme, LEXEME_IDENTIFIER))
616 0 : return NULL;
617 :
618 179 : symbol = symtab_lookup_lexeme(parser, lexeme);
619 179 : if (!symbol) {
620 0 : return error_lexeme(lexeme, "Unknown variable: %.*s",
621 0 : (int)lexeme->value.len, lexeme->value.value);
622 : }
623 :
624 1770 : LWAN_ARRAY_FOREACH_REVERSE(&parser->chunks, iter) {
625 1770 : if (iter->action != ACTION_START_ITER)
626 1591 : continue;
627 179 : if (iter->data == symbol) {
628 179 : size_t index = chunk_array_get_elem_index(&parser->chunks, iter);
629 :
630 179 : emit_chunk(parser, ACTION_END_ITER, 0, (void *)index);
631 179 : symtab_pop(parser);
632 :
633 179 : return parser_text;
634 : }
635 : }
636 :
637 0 : return error_lexeme(lexeme, "Could not find {{#%.*s}}",
638 0 : (int)lexeme->value.len, lexeme->value.value);
639 : }
640 :
641 435 : static void *parser_end_var_not_empty(struct parser *parser,
642 : struct lexeme *lexeme)
643 : {
644 : struct chunk *iter;
645 : struct lwan_var_descriptor *symbol;
646 :
647 435 : if (!parser_stack_top_matches(parser, lexeme, LEXEME_IDENTIFIER))
648 0 : return NULL;
649 :
650 435 : symbol = symtab_lookup_lexeme(parser, lexeme);
651 435 : if (!symbol) {
652 0 : return error_lexeme(lexeme, "Unknown variable: %.*s",
653 0 : (int)lexeme->value.len, lexeme->value.value);
654 : }
655 :
656 435 : if (!parser->chunks.base.elements)
657 0 : return error_lexeme(
658 : lexeme,
659 : "No chunks were emitted but parsing end variable not empty");
660 :
661 1392 : LWAN_ARRAY_FOREACH_REVERSE(&parser->chunks, iter) {
662 1392 : if (iter->action != ACTION_IF_VARIABLE_NOT_EMPTY)
663 957 : continue;
664 435 : if (iter->data == symbol) {
665 435 : emit_chunk(parser, ACTION_END_IF_VARIABLE_NOT_EMPTY, 0, symbol);
666 435 : return parser_right_meta;
667 : }
668 : }
669 :
670 0 : return error_lexeme(lexeme, "Could not find {{%.*s?}}",
671 0 : (int)lexeme->value.len, lexeme->value.value);
672 : }
673 :
674 614 : static void *parser_slash(struct parser *parser, struct lexeme *lexeme)
675 : {
676 614 : if (lexeme->type == LEXEME_IDENTIFIER) {
677 : struct lexeme *next;
678 :
679 614 : if ((next = lex_next(&parser->lexer))) {
680 614 : if (next->type == LEXEME_RIGHT_META)
681 179 : return parser_end_iter(parser, lexeme);
682 :
683 435 : if (next->type == LEXEME_QUESTION_MARK)
684 435 : return parser_end_var_not_empty(parser, lexeme);
685 :
686 0 : return unexpected_lexeme(next);
687 : }
688 : }
689 :
690 0 : return unexpected_lexeme(lexeme);
691 : }
692 :
693 179 : static void *parser_iter(struct parser *parser, struct lexeme *lexeme)
694 : {
695 179 : if (lexeme->type == LEXEME_IDENTIFIER) {
696 179 : enum flags negate = parser->flags & FLAGS_NEGATE;
697 : struct lwan_var_descriptor *symbol =
698 179 : symtab_lookup_lexeme(parser, lexeme);
699 179 : if (!symbol) {
700 0 : return error_lexeme(lexeme, "Unknown variable: %.*s",
701 0 : (int)lexeme->value.len, lexeme->value.value);
702 : }
703 :
704 179 : int r = symtab_push(parser, symbol->list_desc);
705 179 : if (r < 0) {
706 0 : if (r == -ENODEV) {
707 0 : return error_lexeme(
708 : lexeme, "Couldn't find descriptor for variable `%.*s'",
709 0 : (int)lexeme->value.len, lexeme->value.value);
710 : }
711 0 : return error_lexeme(lexeme,
712 : "Could not push symbol table (out of memory)");
713 : }
714 :
715 179 : emit_chunk(parser, ACTION_START_ITER, negate | FLAGS_NO_FREE, symbol);
716 :
717 179 : parser_push_lexeme(parser, lexeme);
718 179 : parser->flags &= ~FLAGS_NEGATE;
719 179 : return parser_right_meta;
720 : }
721 :
722 0 : return unexpected_lexeme(lexeme);
723 : }
724 :
725 261 : static void *parser_negate(struct parser *parser, struct lexeme *lexeme)
726 : {
727 261 : switch (lexeme->type) {
728 0 : default:
729 0 : return unexpected_lexeme(lexeme);
730 :
731 87 : case LEXEME_HASH:
732 87 : parser->flags ^= FLAGS_NEGATE;
733 87 : return parser_iter;
734 :
735 174 : case LEXEME_IDENTIFIER:
736 174 : parser->flags ^= FLAGS_NEGATE;
737 174 : return parser_identifier(parser, lexeme);
738 : }
739 : }
740 :
741 1673 : static void *parser_identifier(struct parser *parser, struct lexeme *lexeme)
742 : {
743 : struct lexeme *next;
744 :
745 1673 : if (!(next = lex_next(&parser->lexer)))
746 0 : return NULL;
747 :
748 1673 : if (parser->flags & FLAGS_QUOTE) {
749 174 : if (next->type != LEXEME_CLOSE_CURLY_BRACE)
750 0 : return error_lexeme(lexeme, "Expecting closing brace");
751 174 : if (!(next = lex_next(&parser->lexer)))
752 0 : return unexpected_lexeme(lexeme);
753 : }
754 :
755 1673 : if (next->type == LEXEME_RIGHT_META) {
756 : struct lwan_var_descriptor *symbol =
757 1238 : symtab_lookup_lexeme(parser, lexeme);
758 1238 : if (!symbol) {
759 0 : return error_lexeme(lexeme, "Unknown variable: %.*s",
760 0 : (int)lexeme->value.len, lexeme->value.value);
761 : }
762 :
763 1238 : emit_chunk(parser, ACTION_VARIABLE, parser->flags, symbol);
764 :
765 1238 : parser->flags &= ~FLAGS_QUOTE;
766 1238 : parser->tpl->minimum_size += lexeme->value.len + 1;
767 :
768 1238 : return parser_text;
769 : }
770 :
771 435 : if (next->type == LEXEME_QUESTION_MARK) {
772 : struct lwan_var_descriptor *symbol =
773 435 : symtab_lookup_lexeme(parser, lexeme);
774 435 : if (!symbol) {
775 0 : return error_lexeme(lexeme, "Unknown variable: %.*s",
776 0 : (int)lexeme->value.len, lexeme->value.value);
777 : }
778 :
779 435 : enum flags flags = FLAGS_NO_FREE | (parser->flags & FLAGS_NEGATE);
780 435 : emit_chunk(parser, ACTION_IF_VARIABLE_NOT_EMPTY, flags, symbol);
781 435 : parser_push_lexeme(parser, lexeme);
782 :
783 435 : parser->flags &= ~FLAGS_NEGATE;
784 :
785 435 : return parser_right_meta;
786 : }
787 :
788 0 : return unexpected_lexeme(next);
789 : }
790 :
791 0 : static void *parser_partial(struct parser *parser, struct lexeme *lexeme)
792 : {
793 : struct lwan_tpl *tpl;
794 0 : char *filename = strndupa(lexeme->value.value, lexeme->value.len);
795 :
796 0 : if (lexeme->type != LEXEME_IDENTIFIER)
797 0 : return unexpected_lexeme(lexeme);
798 :
799 0 : tpl = lwan_tpl_compile_file(filename, parser->descriptor);
800 0 : if (tpl) {
801 0 : emit_chunk(parser, ACTION_APPLY_TPL, 0, tpl);
802 0 : return parser_right_meta;
803 : }
804 :
805 0 : return error_lexeme(lexeme, "Could not compile template ``%s''", filename);
806 : }
807 :
808 2640 : static void *parser_meta(struct parser *parser, struct lexeme *lexeme)
809 : {
810 2640 : switch (lexeme->type) {
811 0 : default:
812 0 : return unexpected_lexeme(lexeme);
813 :
814 174 : case LEXEME_OPEN_CURLY_BRACE:
815 174 : if (parser->flags & FLAGS_QUOTE)
816 0 : return unexpected_lexeme(lexeme);
817 :
818 174 : parser->flags |= FLAGS_QUOTE;
819 174 : return parser_meta;
820 :
821 1499 : case LEXEME_IDENTIFIER:
822 1499 : return parser_identifier(parser, lexeme);
823 :
824 0 : case LEXEME_GREATER_THAN:
825 0 : return parser_partial;
826 :
827 92 : case LEXEME_HASH:
828 92 : return parser_iter;
829 :
830 261 : case LEXEME_HAT:
831 261 : return parser_negate;
832 :
833 614 : case LEXEME_SLASH:
834 614 : return parser_slash;
835 : }
836 : }
837 :
838 1601 : static struct lwan_strbuf *lwan_strbuf_from_lexeme(struct parser *parser,
839 : struct lexeme *lexeme)
840 : {
841 1601 : if (parser->template_flags & LWAN_TPL_FLAG_CONST_TEMPLATE)
842 1601 : return lwan_strbuf_new_static(lexeme->value.value, lexeme->value.len);
843 :
844 0 : struct lwan_strbuf *buf = lwan_strbuf_new_with_size(lexeme->value.len);
845 0 : if (buf)
846 0 : lwan_strbuf_set(buf, lexeme->value.value, lexeme->value.len);
847 :
848 0 : return buf;
849 : }
850 :
851 4865 : static void *parser_text(struct parser *parser, struct lexeme *lexeme)
852 : {
853 4865 : if (lexeme->type == LEXEME_LEFT_META)
854 2466 : return parser_meta;
855 :
856 2399 : if (lexeme->type == LEXEME_TEXT) {
857 2215 : if (lexeme->value.len <= sizeof(void *)) {
858 614 : uintptr_t tmp = 0;
859 :
860 614 : memcpy(&tmp, lexeme->value.value, lexeme->value.len);
861 614 : emit_chunk(parser, ACTION_APPEND_SMALL, 0, (void*)tmp);
862 : } else {
863 1601 : struct lwan_strbuf *buf = lwan_strbuf_from_lexeme(parser, lexeme);
864 1601 : if (!buf)
865 0 : return error_lexeme(lexeme, "Out of memory");
866 :
867 1601 : emit_chunk(parser, ACTION_APPEND, 0, buf);
868 : }
869 2215 : parser->tpl->minimum_size += lexeme->value.len;
870 2215 : return parser_text;
871 : }
872 :
873 184 : if (lexeme->type == LEXEME_EOF) {
874 184 : emit_chunk(parser, ACTION_LAST, 0, NULL);
875 184 : return NULL;
876 : }
877 :
878 0 : return unexpected_lexeme(lexeme);
879 : }
880 :
881 21 : void lwan_append_int_to_strbuf(struct lwan_strbuf *buf, void *ptr)
882 : {
883 : char convertbuf[INT_TO_STR_BUFFER_SIZE];
884 : size_t len;
885 : char *converted;
886 :
887 21 : converted = int_to_string(*(int *)ptr, convertbuf, &len);
888 21 : lwan_strbuf_append_str(buf, converted, len);
889 21 : }
890 :
891 0 : bool lwan_tpl_int_is_empty(void *ptr) { return (*(int *)ptr) == 0; }
892 :
893 0 : void lwan_append_double_to_strbuf(struct lwan_strbuf *buf, void *ptr)
894 : {
895 0 : lwan_strbuf_append_printf(buf, "%f", *(double *)ptr);
896 0 : }
897 :
898 0 : bool lwan_tpl_double_is_empty(void *ptr)
899 : {
900 : #if defined(LWAN_HAVE_BUILTIN_FPCLASSIFY)
901 0 : return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL,
902 0 : FP_ZERO, *(double *)ptr);
903 : #else
904 : return fpclassify(*(double *)ptr) == FP_ZERO;
905 : #endif
906 : }
907 :
908 130 : void lwan_append_str_to_strbuf(struct lwan_strbuf *buf, void *ptr)
909 : {
910 130 : const char *str = *(char **)ptr;
911 :
912 130 : if (LIKELY(str))
913 130 : lwan_strbuf_append_strz(buf, str);
914 130 : }
915 :
916 : #if __x86_64__
917 : #include <emmintrin.h>
918 : #endif
919 :
920 : static ALWAYS_INLINE int escaped_index(char ch)
921 : {
922 : #if __x86_64__
923 : /* FIXME: instead of calling escaped_index() for each byte that needs to be
924 : * escaped, use SIMD to leap through input string until an escapable character
925 : * is found. */
926 2241 : const __m128i ch_mask = _mm_set1_epi8(ch);
927 : const __m128i escapable =
928 2241 : _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '<', '>', '&', '"', '\'', '/');
929 :
930 4482 : return __builtin_ffs(_mm_movemask_epi8(_mm_cmpeq_epi8(ch_mask, escapable)));
931 : #else
932 : switch (ch) {
933 : default:
934 : return 0;
935 : case '/':
936 : return 1;
937 : case '\'':
938 : return 2;
939 : case '"':
940 : return 3;
941 : case '&':
942 : return 4;
943 : case '>':
944 : return 5;
945 : case '<':
946 : return 6;
947 : }
948 : #endif
949 : }
950 :
951 35 : void lwan_append_str_escaped_to_strbuf(struct lwan_strbuf *buf, void *ptr)
952 : {
953 : static const struct lwan_value escaped[] = {
954 : {},
955 : { /* / */ "/", 6 },
956 : { /* ' */ "'", 6 },
957 : { /* " */ """, 6 },
958 : { /* & */ "&", 5 },
959 : { /* > */ ">", 4 },
960 : { /* < */ "<", 4 },
961 : };
962 :
963 35 : if (UNLIKELY(!ptr))
964 0 : return;
965 :
966 35 : const char *str = *(char **)ptr;
967 35 : if (UNLIKELY(!str))
968 0 : return;
969 :
970 : const char *last, *p;
971 2276 : for (last = p = str; *p; p++) {
972 2241 : int index = escaped_index(*p);
973 :
974 2241 : if (index) {
975 22 : lwan_strbuf_append_str(buf, last, (size_t)(p - last));
976 22 : last = p + 1;
977 :
978 22 : lwan_strbuf_append_str(buf, escaped[index].value, escaped[index].len);
979 : }
980 : }
981 :
982 35 : if (last != p)
983 34 : lwan_strbuf_append_str(buf, last, (size_t)(p - last));
984 : }
985 :
986 10 : bool lwan_tpl_str_is_empty(void *ptr)
987 : {
988 10 : if (UNLIKELY(!ptr))
989 0 : return true;
990 :
991 10 : const char *str = *(const char **)ptr;
992 10 : return !str || *str == '\0';
993 : }
994 :
995 0 : static void free_chunk(struct chunk *chunk)
996 : {
997 0 : if (!chunk)
998 0 : return;
999 0 : if (chunk->flags & FLAGS_NO_FREE)
1000 0 : return;
1001 :
1002 0 : switch (chunk->action) {
1003 0 : case ACTION_LAST:
1004 : case ACTION_APPEND_SMALL:
1005 : case ACTION_VARIABLE:
1006 : case ACTION_VARIABLE_STR:
1007 : case ACTION_VARIABLE_STR_ESCAPE:
1008 : case ACTION_END_IF_VARIABLE_NOT_EMPTY:
1009 : case ACTION_END_ITER:
1010 : /* do nothing */
1011 0 : break;
1012 0 : case ACTION_IF_VARIABLE_NOT_EMPTY:
1013 : case ACTION_START_ITER:
1014 0 : free(chunk->data);
1015 0 : break;
1016 0 : case ACTION_APPEND:
1017 0 : lwan_strbuf_free(chunk->data);
1018 0 : break;
1019 0 : case ACTION_APPLY_TPL:
1020 0 : lwan_tpl_free(chunk->data);
1021 0 : break;
1022 : }
1023 : }
1024 :
1025 0 : static void free_chunk_array(struct chunk_array *array)
1026 : {
1027 : struct chunk *iter;
1028 :
1029 0 : LWAN_ARRAY_FOREACH(array, iter)
1030 0 : free_chunk(iter);
1031 0 : chunk_array_reset(array);
1032 0 : }
1033 :
1034 0 : void lwan_tpl_free(struct lwan_tpl *tpl)
1035 : {
1036 0 : if (tpl) {
1037 0 : free_chunk_array(&tpl->chunks);
1038 0 : free(tpl);
1039 : }
1040 0 : }
1041 :
1042 184 : static bool post_process_template(struct parser *parser)
1043 : {
1044 : struct chunk *last_chunk =
1045 184 : chunk_array_get_elem(&parser->chunks, chunk_array_len(&parser->chunks));
1046 : struct chunk *prev_chunk;
1047 : struct chunk *chunk;
1048 :
1049 4251 : LWAN_ARRAY_FOREACH (&parser->chunks, chunk) {
1050 4251 : if (chunk->action == ACTION_IF_VARIABLE_NOT_EMPTY) {
1051 1827 : for (prev_chunk = chunk;; chunk++) {
1052 1827 : if (chunk == last_chunk)
1053 0 : goto error;
1054 1827 : if (chunk->action == ACTION_LAST) {
1055 0 : lwan_status_error("Internal error: Could not find the end "
1056 : "var not empty chunk");
1057 0 : return false;
1058 : }
1059 1827 : if (chunk->action == ACTION_END_IF_VARIABLE_NOT_EMPTY &&
1060 435 : chunk->data == prev_chunk->data)
1061 435 : break;
1062 : }
1063 :
1064 435 : struct chunk_descriptor *cd = malloc(sizeof(*cd));
1065 435 : if (!cd)
1066 0 : lwan_status_critical_perror("malloc");
1067 :
1068 435 : cd->descriptor = prev_chunk->data;
1069 435 : cd->chunk = chunk;
1070 435 : prev_chunk->data = cd;
1071 435 : prev_chunk->flags &= ~FLAGS_NO_FREE;
1072 :
1073 435 : chunk = prev_chunk + 1;
1074 3816 : } else if (chunk->action == ACTION_START_ITER) {
1075 179 : enum flags flags = chunk->flags;
1076 :
1077 1949 : for (prev_chunk = chunk;; chunk++) {
1078 1949 : if (chunk == last_chunk)
1079 0 : goto error;
1080 1949 : if (chunk->action == ACTION_LAST) {
1081 0 : lwan_status_error(
1082 : "Internal error: Could not find the end iter chunk");
1083 0 : return false;
1084 : }
1085 1949 : if (chunk->action == ACTION_END_ITER) {
1086 179 : size_t start_index = (size_t)chunk->data;
1087 : size_t prev_index =
1088 179 : chunk_array_get_elem_index(&parser->chunks, prev_chunk);
1089 :
1090 179 : if (prev_index == start_index) {
1091 179 : chunk->flags |= flags;
1092 179 : chunk->data =
1093 179 : chunk_array_get_elem(&parser->chunks, start_index);
1094 179 : break;
1095 : }
1096 : }
1097 : }
1098 :
1099 179 : struct chunk_descriptor *cd = malloc(sizeof(*cd));
1100 179 : if (!cd)
1101 0 : lwan_status_critical_perror("malloc");
1102 :
1103 179 : cd->descriptor = prev_chunk->data;
1104 179 : prev_chunk->data = cd;
1105 179 : prev_chunk->flags &= ~FLAGS_NO_FREE;
1106 :
1107 179 : if (chunk->action == ACTION_LAST)
1108 0 : cd->chunk = chunk;
1109 : else
1110 179 : cd->chunk = chunk + 1;
1111 :
1112 179 : chunk = prev_chunk + 1;
1113 3637 : } else if (chunk->action == ACTION_VARIABLE) {
1114 1238 : struct lwan_var_descriptor *descriptor = chunk->data;
1115 1238 : bool escape = chunk->flags & FLAGS_QUOTE;
1116 :
1117 1238 : if (descriptor->append_to_strbuf == lwan_append_str_to_strbuf) {
1118 880 : if (escape)
1119 174 : chunk->action = ACTION_VARIABLE_STR_ESCAPE;
1120 : else
1121 706 : chunk->action = ACTION_VARIABLE_STR;
1122 880 : chunk->data = (void *)(uintptr_t)descriptor->offset;
1123 358 : } else if (escape) {
1124 0 : lwan_status_error("Variable must be string to be escaped");
1125 0 : return false;
1126 358 : } else if (!descriptor->append_to_strbuf) {
1127 0 : lwan_status_error("Invalid variable descriptor");
1128 0 : return false;
1129 : }
1130 2399 : } else if (chunk->action == ACTION_LAST) {
1131 184 : break;
1132 : }
1133 : }
1134 :
1135 184 : parser->tpl->chunks = parser->chunks;
1136 :
1137 184 : return true;
1138 :
1139 0 : error:
1140 0 : lwan_status_error("Unknown error while parsing template; bug?");
1141 0 : return false;
1142 : }
1143 :
1144 184 : static bool parser_init(struct parser *parser,
1145 : const struct lwan_var_descriptor *descriptor,
1146 : const char *string)
1147 : {
1148 184 : if (symtab_push(parser, descriptor) < 0)
1149 0 : return false;
1150 :
1151 184 : chunk_array_init(&parser->chunks);
1152 184 : parser->tpl->chunks = parser->chunks;
1153 :
1154 184 : lex_init(&parser->lexer, string);
1155 184 : list_head_init(&parser->stack);
1156 :
1157 184 : return true;
1158 : }
1159 :
1160 184 : static bool parser_shutdown(struct parser *parser, struct lexeme *lexeme)
1161 : {
1162 184 : bool success = true;
1163 :
1164 184 : if (lexeme && lexeme->type == LEXEME_ERROR && lexeme->value.value) {
1165 0 : lwan_status_error("Parser error: %.*s", (int)lexeme->value.len,
1166 : lexeme->value.value);
1167 0 : free((char *)lexeme->value.value);
1168 :
1169 0 : success = false;
1170 : }
1171 :
1172 184 : if (!list_empty(&parser->stack)) {
1173 : struct stacked_lexeme *stacked, *stacked_next;
1174 :
1175 0 : list_for_each_safe (&parser->stack, stacked, stacked_next, stack) {
1176 0 : lwan_status_error(
1177 : "Parser error: EOF while looking for matching {{/%.*s}}",
1178 : (int)stacked->lexeme.value.len, stacked->lexeme.value.value);
1179 0 : list_del(&stacked->stack);
1180 0 : free(stacked);
1181 : }
1182 :
1183 0 : success = false;
1184 : }
1185 :
1186 184 : if (!parser->symtab) {
1187 0 : lwan_status_error(
1188 : "Parser error: No symbol table was found when finishing the parser");
1189 0 : success = false;
1190 : } else {
1191 184 : symtab_pop(parser);
1192 184 : if (parser->symtab) {
1193 0 : lwan_status_error(
1194 : "Parser error: Symbol table not empty when finishing parser");
1195 :
1196 0 : while (parser->symtab)
1197 0 : symtab_pop(parser);
1198 :
1199 0 : success = false;
1200 : }
1201 : }
1202 :
1203 184 : if (parser->flags & FLAGS_NEGATE) {
1204 0 : lwan_status_error("Parser error: unmatched negation");
1205 0 : success = false;
1206 : }
1207 184 : if (parser->flags & FLAGS_QUOTE) {
1208 0 : lwan_status_error("Parser error: unmatched quote");
1209 0 : success = false;
1210 : }
1211 :
1212 184 : success = success && post_process_template(parser);
1213 :
1214 184 : if (!success)
1215 0 : free_chunk_array(&parser->chunks);
1216 :
1217 184 : return success;
1218 : }
1219 :
1220 184 : static bool parse_string(struct lwan_tpl *tpl,
1221 : const char *string,
1222 : const struct lwan_var_descriptor *descriptor,
1223 : enum lwan_tpl_flag flags)
1224 : {
1225 184 : struct parser parser = {
1226 : .tpl = tpl,
1227 : .symtab = NULL,
1228 : .descriptor = descriptor,
1229 : .template_flags = flags
1230 : };
1231 184 : void *(*state)(struct parser *parser, struct lexeme *lexeme) = parser_text;
1232 : struct lexeme *lexeme;
1233 :
1234 184 : if (!parser_init(&parser, descriptor, string))
1235 0 : return false;
1236 :
1237 9792 : while (state) {
1238 9608 : if (!(lexeme = lex_next(&parser.lexer)))
1239 0 : break;
1240 :
1241 9608 : state = state(&parser, lexeme);
1242 : }
1243 :
1244 184 : return parser_shutdown(&parser, lexeme);
1245 : }
1246 :
1247 : #if !defined(NDEBUG) && defined(TEMPLATE_DEBUG)
1248 : static const char *instr(const char *name, char buf[static 32])
1249 : {
1250 : int ret = snprintf(buf, 32, "\033[33m%s\033[0m", name);
1251 :
1252 : if (ret < 0 || ret >= 32)
1253 : return "?";
1254 :
1255 : return buf;
1256 : }
1257 :
1258 : static void dump_program(const struct lwan_tpl *tpl)
1259 : {
1260 : struct chunk *iter;
1261 : int indent = 0;
1262 :
1263 : if (!tpl->chunks.base.elements)
1264 : return;
1265 :
1266 : LWAN_ARRAY_FOREACH(&tpl->chunks, iter) {
1267 : char instr_buf[32];
1268 :
1269 : printf("%8zu ", iter - (struct chunk *)tpl->chunks.base.base);
1270 :
1271 : switch (iter->action) {
1272 : default:
1273 : for (int i = 0; i < indent; i++) {
1274 : printf(" ");
1275 : }
1276 : break;
1277 : case ACTION_END_ITER:
1278 : case ACTION_END_IF_VARIABLE_NOT_EMPTY:
1279 : break;
1280 : }
1281 :
1282 : switch (iter->action) {
1283 : case ACTION_APPEND:
1284 : printf("%s [%.*s]", instr("APPEND", instr_buf),
1285 : (int)lwan_strbuf_get_length(iter->data),
1286 : lwan_strbuf_get_buffer(iter->data));
1287 : break;
1288 : case ACTION_APPEND_SMALL: {
1289 : uintptr_t val = (uintptr_t)iter->data;
1290 : size_t len = strnlen((char *)&val, sizeof(val));
1291 :
1292 : printf("%s (%zu) [%.*s]", instr("APPEND_SMALL", instr_buf), len, (int)len, (char *)&val);
1293 : break;
1294 : }
1295 : case ACTION_VARIABLE: {
1296 : struct lwan_var_descriptor *descriptor = iter->data;
1297 :
1298 : printf("%s [%s]", instr("APPEND_VAR", instr_buf), descriptor->name);
1299 : break;
1300 : }
1301 : case ACTION_VARIABLE_STR:
1302 : printf("%s", instr("APPEND_VAR_STR", instr_buf));
1303 : break;
1304 : case ACTION_VARIABLE_STR_ESCAPE:
1305 : printf("%s", instr("APPEND_VAR_STR_ESCAPE", instr_buf));
1306 : break;
1307 : case ACTION_START_ITER: {
1308 : struct chunk_descriptor *descriptor = iter->data;
1309 :
1310 : printf("%s [%s]", instr("START_ITER", instr_buf),
1311 : descriptor->descriptor->name);
1312 : indent++;
1313 : break;
1314 : }
1315 : case ACTION_END_ITER:
1316 : printf("%s [%zu]", instr("END_ITER", instr_buf),
1317 : (size_t)iter->data);
1318 : indent--;
1319 : break;
1320 : case ACTION_IF_VARIABLE_NOT_EMPTY: {
1321 : struct chunk_descriptor *cd = iter->data;
1322 :
1323 : printf("%s [%s]", instr("IF_VAR_NOT_EMPTY", instr_buf),
1324 : cd->descriptor->name);
1325 : indent++;
1326 : break;
1327 : }
1328 : case ACTION_END_IF_VARIABLE_NOT_EMPTY:
1329 : printf("%s", instr("END_VAR_NOT_EMPTY", instr_buf));
1330 : indent--;
1331 : break;
1332 : case ACTION_APPLY_TPL:
1333 : printf("%s", instr("APPLY_TEMPLATE", instr_buf));
1334 : break;
1335 : case ACTION_LAST:
1336 : printf("%s", instr("LAST", instr_buf));
1337 : }
1338 :
1339 : printf("\033[34m");
1340 : if (iter->flags & FLAGS_NEGATE)
1341 : printf(" NEG");
1342 : if (iter->flags & FLAGS_QUOTE)
1343 : printf(" QUOTE");
1344 : if (iter->flags & FLAGS_NO_FREE)
1345 : printf(" NO_FREE");
1346 : printf("\033[0m\n");
1347 : }
1348 : }
1349 : #endif
1350 :
1351 : struct lwan_tpl *
1352 184 : lwan_tpl_compile_string_full(const char *string,
1353 : const struct lwan_var_descriptor *descriptor,
1354 : enum lwan_tpl_flag flags)
1355 : {
1356 : struct lwan_tpl *tpl;
1357 :
1358 184 : tpl = calloc(1, sizeof(*tpl));
1359 184 : if (tpl) {
1360 184 : if (parse_string(tpl, string, descriptor, flags)) {
1361 : #if !defined(NDEBUG) && defined(TEMPLATE_DEBUG)
1362 : dump_program(tpl);
1363 : #endif
1364 :
1365 184 : return tpl;
1366 : }
1367 :
1368 0 : lwan_tpl_free(tpl);
1369 : }
1370 :
1371 0 : return NULL;
1372 : }
1373 :
1374 : struct lwan_tpl *
1375 0 : lwan_tpl_compile_string(const char *string,
1376 : const struct lwan_var_descriptor *descriptor)
1377 : {
1378 0 : return lwan_tpl_compile_string_full(string, descriptor, 0);
1379 : }
1380 :
1381 : struct lwan_tpl *
1382 0 : lwan_tpl_compile_file(const char *filename,
1383 : const struct lwan_var_descriptor *descriptor)
1384 : {
1385 : int fd;
1386 : struct stat st;
1387 : char *mapped;
1388 0 : struct lwan_tpl *tpl = NULL;
1389 :
1390 0 : fd = open(filename, O_RDONLY | O_CLOEXEC);
1391 0 : if (fd < 0)
1392 0 : goto end;
1393 :
1394 0 : if (fstat(fd, &st) < 0)
1395 0 : goto close_file;
1396 :
1397 0 : mapped = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1398 0 : if (mapped == MAP_FAILED)
1399 0 : goto close_file;
1400 :
1401 0 : tpl = lwan_tpl_compile_string(mapped, descriptor);
1402 :
1403 0 : if (munmap(mapped, (size_t)st.st_size) < 0)
1404 0 : lwan_status_perror("munmap");
1405 :
1406 0 : close_file:
1407 0 : close(fd);
1408 0 : end:
1409 0 : return tpl;
1410 : }
1411 :
1412 : static void
1413 36 : bake_direct_addresses(struct lwan_tpl *tpl,
1414 : const void *const dispatch_table[static ACTION_LAST])
1415 : {
1416 : struct chunk *iter;
1417 :
1418 342 : LWAN_ARRAY_FOREACH (&tpl->chunks, iter) {
1419 306 : if (iter->action == ACTION_APPLY_TPL)
1420 0 : bake_direct_addresses(iter->data, dispatch_table);
1421 :
1422 306 : iter->instruction = dispatch_table[iter->action];
1423 : }
1424 :
1425 36 : tpl->dispatch_table_direct = true;
1426 36 : }
1427 :
1428 71 : static const struct chunk *apply(struct lwan_tpl *tpl,
1429 : const struct chunk *chunks,
1430 : struct lwan_strbuf *buf,
1431 : void *variables,
1432 : const void *data)
1433 : {
1434 : struct coro_switcher switcher;
1435 71 : struct coro *coro = NULL;
1436 71 : const struct chunk *chunk = chunks;
1437 :
1438 71 : if (UNLIKELY(!chunk))
1439 0 : return NULL;
1440 :
1441 71 : if (!tpl->dispatch_table_direct) {
1442 : static const void *const dispatch_table[] = {
1443 : [ACTION_APPEND] = &&action_append,
1444 : [ACTION_APPEND_SMALL] = &&action_append_small,
1445 : [ACTION_VARIABLE] = &&action_variable,
1446 : [ACTION_VARIABLE_STR] = &&action_variable_str,
1447 : [ACTION_VARIABLE_STR_ESCAPE] = &&action_variable_str_escape,
1448 : [ACTION_IF_VARIABLE_NOT_EMPTY] = &&action_if_variable_not_empty,
1449 : [ACTION_END_IF_VARIABLE_NOT_EMPTY] = &&action_end_if_variable_not_empty,
1450 : [ACTION_APPLY_TPL] = &&action_apply_tpl,
1451 : [ACTION_START_ITER] = &&action_start_iter,
1452 : [ACTION_END_ITER] = &&action_end_iter,
1453 : [ACTION_LAST] = &&finalize,
1454 : };
1455 :
1456 36 : bake_direct_addresses(tpl, dispatch_table);
1457 : }
1458 :
1459 : #define RETURN_IF_NO_CHUNK(force_) \
1460 : do { \
1461 : if (force_ UNLIKELY(!chunk)) { \
1462 : lwan_status_error("Chunk is NULL while dispatching"); \
1463 : return NULL; \
1464 : } \
1465 : } while (false)
1466 :
1467 : #define DISPATCH_ACTION(force_check_) \
1468 : do { \
1469 : RETURN_IF_NO_CHUNK(force_check_); \
1470 : goto *chunk->instruction; \
1471 : } while (false)
1472 :
1473 : #define DISPATCH_NEXT_ACTION(force_check_) \
1474 : do { \
1475 : RETURN_IF_NO_CHUNK(force_check_); \
1476 : \
1477 : chunk++; \
1478 : goto *chunk->instruction; \
1479 : } while (false)
1480 :
1481 : #define DISPATCH_ACTION_FAST() DISPATCH_ACTION(0 &&)
1482 : #define DISPATCH_ACTION_CHECK() DISPATCH_ACTION(1 &&)
1483 : #define DISPATCH_NEXT_ACTION_FAST() DISPATCH_NEXT_ACTION(0 &&)
1484 : #define DISPATCH_NEXT_ACTION_CHECK() DISPATCH_NEXT_ACTION(1 &&)
1485 :
1486 71 : DISPATCH_ACTION_FAST();
1487 :
1488 211 : action_append:
1489 211 : lwan_strbuf_append_str(buf, lwan_strbuf_get_buffer(chunk->data),
1490 211 : lwan_strbuf_get_length(chunk->data));
1491 211 : DISPATCH_NEXT_ACTION_FAST();
1492 :
1493 39 : action_append_small: {
1494 39 : uintptr_t val = (uintptr_t)chunk->data;
1495 39 : size_t len = strnlen((char *)&val, sizeof(val));
1496 :
1497 39 : lwan_strbuf_append_str(buf, (char*)&val, len);
1498 :
1499 39 : DISPATCH_NEXT_ACTION_FAST();
1500 : }
1501 :
1502 40 : action_variable: {
1503 40 : struct lwan_var_descriptor *descriptor = chunk->data;
1504 40 : descriptor->append_to_strbuf(buf, (char *)variables + descriptor->offset);
1505 40 : DISPATCH_NEXT_ACTION_FAST();
1506 : }
1507 :
1508 130 : action_variable_str:
1509 130 : lwan_append_str_to_strbuf(buf, (char *)variables + (uintptr_t)chunk->data);
1510 130 : DISPATCH_NEXT_ACTION_FAST();
1511 :
1512 16 : action_variable_str_escape:
1513 16 : lwan_append_str_escaped_to_strbuf(buf, (char *)variables +
1514 16 : (uintptr_t)chunk->data);
1515 16 : DISPATCH_NEXT_ACTION_FAST();
1516 :
1517 10 : action_if_variable_not_empty: {
1518 10 : struct chunk_descriptor *cd = chunk->data;
1519 10 : bool empty = cd->descriptor->get_is_empty((char *)variables +
1520 10 : cd->descriptor->offset);
1521 10 : if (chunk->flags & FLAGS_NEGATE)
1522 4 : empty = !empty;
1523 10 : if (empty) {
1524 4 : chunk = cd->chunk;
1525 4 : DISPATCH_NEXT_ACTION_FAST();
1526 : } else {
1527 6 : chunk = apply(tpl, chunk + 1, buf, variables, cd->chunk);
1528 6 : DISPATCH_NEXT_ACTION_CHECK();
1529 : }
1530 : }
1531 :
1532 6 : action_end_if_variable_not_empty:
1533 6 : if (LIKELY(data == chunk))
1534 6 : goto finalize;
1535 0 : DISPATCH_NEXT_ACTION_FAST();
1536 :
1537 0 : action_apply_tpl: {
1538 0 : struct lwan_tpl *inner_tpl = chunk->data;
1539 :
1540 0 : if (LIKELY(lwan_strbuf_grow_by(buf, inner_tpl->minimum_size))) {
1541 0 : if (!apply(inner_tpl, chunk_array_get_array(&inner_tpl->chunks),
1542 : buf, variables, NULL)) {
1543 0 : lwan_status_warning("Could not apply subtemplate");
1544 0 : return NULL;
1545 : }
1546 : } else {
1547 0 : lwan_status_warning("Could not grow template by %zu bytes",
1548 : inner_tpl->minimum_size);
1549 0 : return NULL;
1550 : }
1551 :
1552 0 : DISPATCH_NEXT_ACTION_FAST();
1553 : }
1554 :
1555 5 : action_start_iter:
1556 5 : if (UNLIKELY(coro != NULL)) {
1557 0 : lwan_status_warning("Coroutine is not NULL when starting iteration");
1558 0 : return NULL;
1559 : }
1560 :
1561 5 : struct chunk_descriptor *cd = chunk->data;
1562 5 : coro = coro_new(&switcher, cd->descriptor->generator, variables);
1563 :
1564 5 : bool resumed = coro_resume_value(coro, 0);
1565 5 : bool negate = chunk->flags & FLAGS_NEGATE;
1566 5 : if (negate)
1567 2 : resumed = !resumed;
1568 5 : if (!resumed) {
1569 2 : chunk = cd->chunk;
1570 :
1571 2 : if (negate)
1572 2 : coro_resume_value(coro, 1);
1573 :
1574 2 : coro_free(coro);
1575 2 : coro = NULL;
1576 :
1577 2 : if (negate)
1578 2 : DISPATCH_ACTION_FAST();
1579 :
1580 0 : DISPATCH_NEXT_ACTION_FAST();
1581 : }
1582 :
1583 3 : chunk = apply(tpl, chunk + 1, buf, variables, chunk);
1584 3 : DISPATCH_ACTION_CHECK();
1585 :
1586 42 : action_end_iter:
1587 42 : if (data == chunk->data)
1588 21 : goto finalize;
1589 :
1590 21 : if (UNLIKELY(!coro)) {
1591 0 : if (!chunk->flags) {
1592 0 : lwan_status_warning("Coroutine is NULL when finishing iteration");
1593 0 : return NULL;
1594 : }
1595 0 : DISPATCH_NEXT_ACTION_FAST();
1596 : }
1597 :
1598 21 : if (!coro_resume_value(coro, 0)) {
1599 3 : coro_free(coro);
1600 3 : coro = NULL;
1601 3 : DISPATCH_NEXT_ACTION_FAST();
1602 : }
1603 :
1604 18 : chunk = apply(tpl, ((struct chunk *)chunk->data) + 1, buf, variables,
1605 18 : chunk->data);
1606 18 : DISPATCH_ACTION_CHECK();
1607 :
1608 71 : finalize:
1609 71 : return chunk;
1610 : #undef DISPATCH_ACTION
1611 : #undef DISPATCH_NEXT_ACTION
1612 : #undef DISPATCH_ACTION_CHECK
1613 : #undef DISPATCH_NEXT_ACTION_CHECK
1614 : #undef DISPATCH_ACTION_FAST
1615 : #undef DISPATCH_NEXT_ACTION_FAST
1616 : #undef RETURN_IF_NO_CHUNK
1617 : }
1618 :
1619 44 : bool lwan_tpl_apply_with_buffer(struct lwan_tpl *tpl,
1620 : struct lwan_strbuf *buf,
1621 : void *variables)
1622 : {
1623 44 : lwan_strbuf_reset(buf);
1624 :
1625 44 : if (UNLIKELY(!lwan_strbuf_grow_to(buf, tpl->minimum_size)))
1626 0 : return false;
1627 :
1628 44 : if (!apply(tpl, tpl->chunks.base.base, buf, variables, NULL))
1629 0 : return false;
1630 :
1631 44 : return true;
1632 : }
1633 :
1634 0 : struct lwan_strbuf *lwan_tpl_apply(struct lwan_tpl *tpl, void *variables)
1635 : {
1636 0 : struct lwan_strbuf *buf = lwan_strbuf_new_with_size(tpl->minimum_size);
1637 :
1638 0 : if (UNLIKELY(!buf))
1639 0 : return NULL;
1640 :
1641 0 : if (LIKELY(lwan_tpl_apply_with_buffer(tpl, buf, variables)))
1642 0 : return buf;
1643 :
1644 0 : lwan_strbuf_free(buf);
1645 0 : return NULL;
1646 : }
1647 :
1648 : #ifdef TEMPLATE_TEST
1649 :
1650 : struct test_struct {
1651 : int some_int;
1652 : char *a_string;
1653 : };
1654 :
1655 : int main(int argc, char *argv[])
1656 : {
1657 : if (argc < 2) {
1658 : printf("Usage: %s file.tpl\n", argv[0]);
1659 : return 1;
1660 : }
1661 :
1662 : printf("*** Compiling template...\n");
1663 : struct lwan_var_descriptor desc[] = {
1664 : TPL_VAR_INT(struct test_struct, some_int),
1665 : TPL_VAR_STR(struct test_struct, a_string),
1666 : TPL_VAR_SENTINEL
1667 : };
1668 : struct lwan_tpl *tpl = lwan_tpl_compile_file(argv[1], desc);
1669 : if (!tpl)
1670 : return 1;
1671 :
1672 : printf("*** Applying template 100000 times...\n");
1673 : for (size_t i = 0; i < 100000; i++) {
1674 : struct lwan_strbuf *applied = lwan_tpl_apply(tpl, &(struct test_struct) {
1675 : .some_int = 42,
1676 : .a_string = "some string"
1677 : });
1678 : lwan_strbuf_free(applied);
1679 : }
1680 :
1681 : lwan_tpl_free(tpl);
1682 : return 0;
1683 : }
1684 :
1685 : #endif /* TEMPLATE_TEST */
|