LCOV - code coverage report
Current view: top level - lib - lwan-template.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 454 721 63.0 %
Date: 2023-04-18 16:19:03 Functions: 57 76 75.0 %

          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             :         { /* / */ "&#x2f;", 6 },
     956             :         { /* ' */ "&#x27;", 6 },
     957             :         { /* " */ "&quot;", 6 },
     958             :         { /* & */ "&amp;", 5 },
     959             :         { /* > */ "&gt;", 4 },
     960             :         { /* < */ "&lt;", 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 */

Generated by: LCOV version 1.15-2-gb9d6727