LCOV - code coverage report
Current view: top level - templating - mustach.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.1 % 322 184
Test Date: 2026-09-09 15:11:34 Functions: 58.8 % 17 10

            Line data    Source code
       1              : /*
       2              :  Author: José Bollo <jobol@nonadev.net>
       3              : 
       4              :  https://gitlab.com/jobol/mustach
       5              : 
       6              :  SPDX-License-Identifier: 0BSD
       7              : */
       8              : 
       9              : #ifndef _GNU_SOURCE
      10              : #define _GNU_SOURCE
      11              : #endif
      12              : 
      13              : #include "mustach.h"
      14              : 
      15              : #include <stdlib.h>
      16              : #include <stdio.h>
      17              : #include <string.h>
      18              : #include <errno.h>
      19              : #include <ctype.h>
      20              : #ifdef _WIN32
      21              : #include <malloc.h>
      22              : #endif
      23              : 
      24              : struct iwrap {
      25              :         int (*emit)(void *closure, const char *buffer, size_t size, int escape, FILE *file);
      26              :         void *closure; /* closure for: enter, next, leave, emit, get */
      27              :         int (*put)(void *closure, const char *name, int escape, FILE *file);
      28              :         void *closure_put; /* closure for put */
      29              :         int (*enter)(void *closure, const char *name);
      30              :         int (*next)(void *closure);
      31              :         int (*leave)(void *closure);
      32              :         int (*get)(void *closure, const char *name, struct mustach_sbuf *sbuf);
      33              :         int (*partial)(void *closure, const char *name, struct mustach_sbuf *sbuf);
      34              :         void *closure_partial; /* closure for partial */
      35              :         FILE *file;
      36              :         int flags;
      37              :         int nesting;
      38              : };
      39              : 
      40              : struct prefix {
      41              :         size_t len;
      42              :         const char *start;
      43              :         struct prefix *prefix;
      44              : };
      45              : 
      46              : /*********************************************************
      47              : * This section wraps implementation details of memory files.
      48              : * It also takes care of adding a terminating zero to the
      49              : * produced text.
      50              : * When the function open_memstream exists, use it.
      51              : * Otherwise emulate it using a temporary file.
      52              : **********************************************************/
      53              : #if !defined(NO_OPEN_MEMSTREAM)
      54           36 : static FILE *memfile_open(char **buffer, size_t *size)
      55              : {
      56           36 :         return open_memstream(buffer, size);
      57              : }
      58            0 : static void memfile_abort(FILE *file, char **buffer, size_t *size)
      59              : {
      60            0 :         fclose(file);
      61            0 :         free(*buffer);
      62            0 :         *buffer = NULL;
      63            0 :         *size = 0;
      64            0 : }
      65           36 : static int memfile_close(FILE *file, char **buffer, size_t *size)
      66              : {
      67              :         int rc;
      68              : 
      69              :         /* adds terminating null */
      70           36 :         rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
      71           36 :         fclose(file);
      72           36 :         if (rc == 0)
      73              :                 /* removes terminating null of the length */
      74           36 :                 (*size)--;
      75              :         else {
      76            0 :                 free(*buffer);
      77            0 :                 *buffer = NULL;
      78            0 :                 *size = 0;
      79              :         }
      80           36 :         return rc;
      81              : }
      82              : #else
      83              : static FILE *memfile_open(char **buffer, size_t *size)
      84              : {
      85              :         /*
      86              :          * We can't provide *buffer and *size as open_memstream does but
      87              :          * at least clear them so the caller won't get bad data.
      88              :          */
      89              :         *buffer = NULL;
      90              :         *size = 0;
      91              : 
      92              :         return tmpfile();
      93              : }
      94              : static void memfile_abort(FILE *file, char **buffer, size_t *size)
      95              : {
      96              :         fclose(file);
      97              :         *buffer = NULL;
      98              :         *size = 0;
      99              : }
     100              : static int memfile_close(FILE *file, char **buffer, size_t *size)
     101              : {
     102              :         int rc;
     103              :         size_t s;
     104              :         char *b;
     105              : 
     106              :         s = (size_t)ftell(file);
     107              :         b = malloc(s + 1);
     108              :         if (b == NULL) {
     109              :                 rc = MUSTACH_ERROR_SYSTEM;
     110              :                 errno = ENOMEM;
     111              :                 s = 0;
     112              :         } else {
     113              :                 rewind(file);
     114              :                 if (1 == fread(b, s, 1, file)) {
     115              :                         rc = 0;
     116              :                         b[s] = 0;
     117              :                 } else {
     118              :                         rc = MUSTACH_ERROR_SYSTEM;
     119              :                         free(b);
     120              :                         b = NULL;
     121              :                         s = 0;
     122              :                 }
     123              :         }
     124              :         *buffer = b;
     125              :         *size = s;
     126              :         return rc;
     127              : }
     128              : #endif
     129              : 
     130              : /*********************************************************
     131              : * This section has functions for managing instances of
     132              : * struct mustach_sbuf.
     133              : *********************************************************/
     134           32 : static inline void sbuf_reset(struct mustach_sbuf *sbuf)
     135              : {
     136           32 :         sbuf->value = NULL;
     137           32 :         sbuf->freecb = NULL;
     138           32 :         sbuf->closure = NULL;
     139           32 :         sbuf->length = 0;
     140           32 : }
     141              : 
     142           32 : static inline void sbuf_release(struct mustach_sbuf *sbuf)
     143              : {
     144           32 :         if (sbuf->releasecb)
     145            4 :                 sbuf->releasecb(sbuf->value, sbuf->closure);
     146           32 : }
     147              : 
     148           32 : static inline size_t sbuf_length(struct mustach_sbuf *sbuf)
     149              : {
     150           32 :         size_t length = sbuf->length;
     151           32 :         if (length == 0 && sbuf->value != NULL)
     152           32 :                 length = strlen(sbuf->value);
     153           32 :         return length;
     154              : }
     155              : 
     156              : /*********************************************************
     157              : * This section is for default implementations of
     158              : * optional callbacks that are although required
     159              : *********************************************************/
     160            0 : static int iwrap_emit(void *closure, const char *buffer, size_t size, int escape, FILE *file)
     161              : {
     162              :         size_t i, j, r;
     163              : 
     164              :         (void)closure; /* unused */
     165              : 
     166            0 :         if (!escape)
     167            0 :                 return fwrite(buffer, 1, size, file) != size ? MUSTACH_ERROR_SYSTEM : MUSTACH_OK;
     168              : 
     169            0 :         r = i = 0;
     170            0 :         while (i < size) {
     171            0 :                 j = i;
     172            0 :                 while (j < size && buffer[j] != '<' && buffer[j] != '>' && buffer[j] != '&' && buffer[j] != '"')
     173            0 :                         j++;
     174            0 :                 if (j != i && fwrite(&buffer[i], j - i, 1, file) != 1)
     175            0 :                         return MUSTACH_ERROR_SYSTEM;
     176            0 :                 if (j < size) {
     177            0 :                         switch(buffer[j++]) {
     178            0 :                         case '<':
     179            0 :                                 r = fwrite("&lt;", 4, 1, file);
     180            0 :                                 break;
     181            0 :                         case '>':
     182            0 :                                 r = fwrite("&gt;", 4, 1, file);
     183            0 :                                 break;
     184            0 :                         case '&':
     185            0 :                                 r = fwrite("&amp;", 5, 1, file);
     186            0 :                                 break;
     187            0 :                         case '"':
     188            0 :                                 r = fwrite("&quot;", 6, 1, file);
     189            0 :                                 break;
     190              :                         }
     191            0 :                         if (r != 1)
     192            0 :                                 return MUSTACH_ERROR_SYSTEM;
     193              :                 }
     194            0 :                 i = j;
     195              :         }
     196            0 :         return MUSTACH_OK;
     197              : }
     198              : 
     199           32 : static int iwrap_put(void *closure, const char *name, int escape, FILE *file)
     200              : {
     201           32 :         struct iwrap *iwrap = closure;
     202              :         int rc;
     203              :         struct mustach_sbuf sbuf;
     204              :         size_t length;
     205              : 
     206           32 :         sbuf_reset(&sbuf);
     207           32 :         rc = iwrap->get(iwrap->closure, name, &sbuf);
     208           32 :         if (rc >= 0) {
     209           32 :                 length = sbuf_length(&sbuf);
     210           32 :                 if (length)
     211           28 :                         rc = iwrap->emit(iwrap->closure, sbuf.value, length, escape, file);
     212           32 :                 sbuf_release(&sbuf);
     213              :         }
     214           32 :         return rc;
     215              : }
     216              : 
     217            0 : static int iwrap_partial(void *closure, const char *name, struct mustach_sbuf *sbuf)
     218              : {
     219            0 :         struct iwrap *iwrap = closure;
     220              :         int rc;
     221              :         FILE *file;
     222              :         size_t size;
     223              :         char *result;
     224              : 
     225            0 :         result = NULL;
     226            0 :         file = memfile_open(&result, &size);
     227            0 :         if (file == NULL)
     228            0 :                 rc = MUSTACH_ERROR_SYSTEM;
     229              :         else {
     230            0 :                 rc = iwrap->put(iwrap->closure_put, name, 0, file);
     231            0 :                 if (rc < 0)
     232            0 :                         memfile_abort(file, &result, &size);
     233              :                 else {
     234            0 :                         rc = memfile_close(file, &result, &size);
     235            0 :                         if (rc == 0) {
     236            0 :                                 sbuf->value = result;
     237            0 :                                 sbuf->freecb = free;
     238            0 :                                 sbuf->length = size;
     239              :                         }
     240              :                 }
     241              :         }
     242            0 :         return rc;
     243              : }
     244              : 
     245              : /*********************************************************
     246              : * Function for writing the indentation prefix
     247              : *********************************************************/
     248          105 : static int emitprefix(struct iwrap *iwrap, struct prefix *prefix)
     249              : {
     250          105 :         if (prefix->prefix) {
     251            0 :                 int rc = emitprefix(iwrap, prefix->prefix);
     252            0 :                 if (rc < 0)
     253            0 :                         return rc;
     254              :         }
     255          105 :         return prefix->len ? iwrap->emit(iwrap->closure, prefix->start, prefix->len, 0, iwrap->file) : 0;
     256              : }
     257              : 
     258              : /*********************************************************
     259              : * This section is for default implementations of
     260              : * optional callbacks that are although required
     261              : *********************************************************/
     262           36 : static int process(const char *template, size_t length, struct iwrap *iwrap, struct prefix *prefix)
     263              : {
     264              :         struct mustach_sbuf sbuf;
     265              :         char opstr[MUSTACH_MAX_DELIM_LENGTH], clstr[MUSTACH_MAX_DELIM_LENGTH];
     266              :         char name[MUSTACH_MAX_LENGTH + 1], c;
     267              :         const char *beg, *term, *end;
     268              :         struct { const char *name, *again; size_t length; unsigned enabled: 1, entered: 1; } stack[MUSTACH_MAX_DEPTH];
     269              :         size_t oplen, cllen, len, l;
     270              :         int depth, rc, enabled, stdalone;
     271              :         struct prefix pref;
     272              : 
     273           36 :         pref.prefix = prefix;
     274           36 :         end = template + (length ? length : strlen(template));
     275           36 :         opstr[0] = opstr[1] = '{';
     276           36 :         clstr[0] = clstr[1] = '}';
     277           36 :         oplen = cllen = 2;
     278           36 :         stdalone = enabled = 1;
     279           36 :         depth = pref.len = 0;
     280              :         for (;;) {
     281              :                 /* search next openning delimiter */
     282         1139 :                 for (beg = template ; ; beg++) {
     283         1139 :                         if (beg == end)
     284           36 :                                 c = '\n';
     285              :                         else {
     286         1103 :                                 c = *beg;
     287         1103 :                                 if (c == '\r') {
     288            0 :                                         if ((beg + 1) != end && beg[1] == '\n')
     289            0 :                                                 beg++;
     290            0 :                                         c = '\n';
     291              :                                 }
     292              :                         }
     293         1139 :                         if (c == '\n') {
     294           77 :                                 l = (beg != end) + (size_t)(beg - template);
     295           77 :                                 if (stdalone != 2 && enabled) {
     296           77 :                                         if (beg != template /* don't prefix empty lines */) {
     297           42 :                                                 rc = emitprefix(iwrap, &pref);
     298           42 :                                                 if (rc < 0)
     299            0 :                                                         return rc;
     300              :                                         }
     301           77 :                                         rc = iwrap->emit(iwrap->closure, template, l, 0, iwrap->file);
     302           77 :                                         if (rc < 0)
     303            0 :                                                 return rc;
     304              :                                 }
     305           77 :                                 if (beg == end) /* no more mustach */
     306           36 :                                         return depth ? MUSTACH_ERROR_UNEXPECTED_END : MUSTACH_OK;
     307           41 :                                 template += l;
     308           41 :                                 stdalone = 1;
     309           41 :                                 pref.len = 0;
     310           41 :                                 pref.prefix = prefix;
     311              :                         }
     312         1062 :                         else if (!isspace(c)) {
     313          953 :                                 if (stdalone == 2 && enabled) {
     314           10 :                                         rc = emitprefix(iwrap, &pref);
     315           10 :                                         if (rc < 0)
     316            0 :                                                 return rc;
     317           10 :                                         pref.len = 0;
     318           10 :                                         stdalone = 0;
     319           10 :                                         pref.prefix = NULL;
     320              :                                 }
     321          953 :                                 if (c == *opstr && end - beg >= (ssize_t)oplen) {
     322          142 :                                         for (l = 1 ; l < oplen && beg[l] == opstr[l] ; l++);
     323           71 :                                         if (l == oplen)
     324           71 :                                                 break;
     325              :                                 }
     326          882 :                                 stdalone = 0;
     327              :                         }
     328              :                 }
     329              : 
     330           71 :                 pref.start = template;
     331           71 :                 pref.len = enabled ? (size_t)(beg - template) : 0;
     332           71 :                 beg += oplen;
     333              : 
     334              :                 /* search next closing delimiter */
     335          398 :                 for (term = beg ; ; term++) {
     336          398 :                         if (term == end)
     337            0 :                                 return MUSTACH_ERROR_UNEXPECTED_END;
     338          398 :                         if (*term == *clstr && end - term >= (ssize_t)cllen) {
     339          142 :                                 for (l = 1 ; l < cllen && term[l] == clstr[l] ; l++);
     340           71 :                                 if (l == cllen)
     341           71 :                                         break;
     342              :                         }
     343              :                 }
     344           71 :                 template = term + cllen;
     345           71 :                 len = (size_t)(term - beg);
     346           71 :                 c = *beg;
     347           71 :                 switch(c) {
     348            0 :                 case ':':
     349            0 :                         stdalone = 0;
     350            0 :                         if (iwrap->flags & Mustach_With_Colon)
     351            0 :                                 goto exclude_first;
     352            0 :                         goto get_name;
     353            1 :                 case '!':
     354              :                 case '=':
     355            1 :                         break;
     356            1 :                 case '{':
     357            3 :                         for (l = 0 ; l < cllen && clstr[l] == '}' ; l++);
     358            1 :                         if (l < cllen) {
     359            0 :                                 if (!len || beg[len-1] != '}')
     360            0 :                                         return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
     361            0 :                                 len--;
     362              :                         } else {
     363            1 :                                 if (term[l] != '}')
     364            0 :                                         return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
     365            1 :                                 template++;
     366              :                         }
     367            1 :                         c = '&';
     368              :                         /*@fallthrough@*/
     369            2 :                 case '&':
     370            2 :                         stdalone = 0;
     371              :                         /*@fallthrough@*/
     372              :                 case '^':
     373              :                 case '#':
     374              :                 case '/':
     375              :                 case '>':
     376           40 : exclude_first:
     377           40 :                         beg++;
     378           40 :                         len--;
     379           40 :                         goto get_name;
     380           30 :                 default:
     381           30 :                         stdalone = 0;
     382           70 : get_name:
     383           92 :                         while (len && isspace(beg[0])) { beg++; len--; }
     384           92 :                         while (len && isspace(beg[len-1])) len--;
     385           70 :                         if (len == 0 && !(iwrap->flags & Mustach_With_EmptyTag))
     386            0 :                                 return MUSTACH_ERROR_EMPTY_TAG;
     387           70 :                         if (len > MUSTACH_MAX_LENGTH)
     388            0 :                                 return MUSTACH_ERROR_TAG_TOO_LONG;
     389           70 :                         memcpy(name, beg, len);
     390           70 :                         name[len] = 0;
     391           70 :                         break;
     392              :                 }
     393           71 :                 if (stdalone)
     394           14 :                         stdalone = 2;
     395           57 :                 else if (enabled) {
     396           53 :                         rc = emitprefix(iwrap, &pref);
     397           53 :                         if (rc < 0)
     398            0 :                                 return rc;
     399           53 :                         pref.len = 0;
     400           53 :                         pref.prefix = NULL;
     401              :                 }
     402           71 :                 switch(c) {
     403            1 :                 case '!':
     404              :                         /* comment */
     405              :                         /* nothing to do */
     406            1 :                         break;
     407            0 :                 case '=':
     408              :                         /* defines delimiters */
     409            0 :                         if (len < 5 || beg[len - 1] != '=')
     410            0 :                                 return MUSTACH_ERROR_BAD_SEPARATORS;
     411            0 :                         beg++;
     412            0 :                         len -= 2;
     413            0 :                         while (len && isspace(*beg))
     414            0 :                                 beg++, len--;
     415            0 :                         while (len && isspace(beg[len - 1]))
     416            0 :                                 len--;
     417            0 :                         for (l = 0; l < len && !isspace(beg[l]) ; l++);
     418            0 :                         if (l == len || l > MUSTACH_MAX_DELIM_LENGTH)
     419            0 :                                 return MUSTACH_ERROR_BAD_SEPARATORS;
     420            0 :                         oplen = l;
     421            0 :                         memcpy(opstr, beg, l);
     422            0 :                         while (l < len && isspace(beg[l])) l++;
     423            0 :                         if (l == len || len - l > MUSTACH_MAX_DELIM_LENGTH)
     424            0 :                                 return MUSTACH_ERROR_BAD_SEPARATORS;
     425            0 :                         cllen = len - l;
     426            0 :                         memcpy(clstr, beg + l, cllen);
     427            0 :                         break;
     428           17 :                 case '^':
     429              :                 case '#':
     430              :                         /* begin section */
     431           17 :                         if (depth == MUSTACH_MAX_DEPTH)
     432            0 :                                 return MUSTACH_ERROR_TOO_DEEP;
     433           17 :                         rc = enabled;
     434           17 :                         if (rc) {
     435           17 :                                 rc = iwrap->enter(iwrap->closure, name);
     436           17 :                                 if (rc < 0)
     437            0 :                                         return rc;
     438              :                         }
     439           17 :                         stack[depth].name = beg;
     440           17 :                         stack[depth].again = template;
     441           17 :                         stack[depth].length = len;
     442           17 :                         stack[depth].enabled = enabled != 0;
     443           17 :                         stack[depth].entered = rc != 0;
     444           17 :                         if ((c == '#') == (rc == 0))
     445            4 :                                 enabled = 0;
     446           17 :                         depth++;
     447           17 :                         break;
     448           21 :                 case '/':
     449              :                         /* end section */
     450           21 :                         if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len))
     451            0 :                                 return MUSTACH_ERROR_CLOSING;
     452           21 :                         rc = enabled && stack[depth].entered ? iwrap->next(iwrap->closure) : 0;
     453           21 :                         if (rc < 0)
     454            0 :                                 return rc;
     455           21 :                         if (rc) {
     456            4 :                                 template = stack[depth++].again;
     457              :                         } else {
     458           17 :                                 enabled = stack[depth].enabled;
     459           17 :                                 if (enabled && stack[depth].entered)
     460            9 :                                         iwrap->leave(iwrap->closure);
     461              :                         }
     462           21 :                         break;
     463            0 :                 case '>':
     464              :                         /* partials */
     465            0 :                         if (enabled) {
     466            0 :                                 if (iwrap->nesting >= MUSTACH_MAX_NESTING)
     467            0 :                                         rc = MUSTACH_ERROR_TOO_MUCH_NESTING;
     468              :                                 else {
     469            0 :                                         sbuf_reset(&sbuf);
     470            0 :                                         rc = iwrap->partial(iwrap->closure_partial, name, &sbuf);
     471            0 :                                         if (rc >= 0) {
     472            0 :                                                 iwrap->nesting++;
     473            0 :                                                 rc = process(sbuf.value, sbuf_length(&sbuf), iwrap, &pref);
     474            0 :                                                 sbuf_release(&sbuf);
     475            0 :                                                 iwrap->nesting--;
     476              :                                         }
     477              :                                 }
     478            0 :                                 if (rc < 0)
     479            0 :                                         return rc;
     480              :                         }
     481            0 :                         break;
     482           32 :                 default:
     483              :                         /* replacement */
     484           32 :                         if (enabled) {
     485           32 :                                 rc = iwrap->put(iwrap->closure_put, name, c != '&', iwrap->file);
     486           32 :                                 if (rc < 0)
     487            0 :                                         return rc;
     488              :                         }
     489           32 :                         break;
     490              :                 }
     491              :         }
     492              : }
     493              : 
     494              : /*********************************************************
     495              : * This section is for the public interface functions
     496              : *********************************************************/
     497           36 : int mustach_file(const char *template, size_t length, const struct mustach_itf *itf, void *closure, int flags, FILE *file)
     498              : {
     499              :         int rc;
     500              :         struct iwrap iwrap;
     501              : 
     502              :         /* check validity */
     503           36 :         if (!itf->enter || !itf->next || !itf->leave || (!itf->put && !itf->get))
     504            0 :                 return MUSTACH_ERROR_INVALID_ITF;
     505              : 
     506              :         /* init wrap structure */
     507           36 :         iwrap.closure = closure;
     508           36 :         if (itf->put) {
     509            0 :                 iwrap.put = itf->put;
     510            0 :                 iwrap.closure_put = closure;
     511              :         } else {
     512           36 :                 iwrap.put = iwrap_put;
     513           36 :                 iwrap.closure_put = &iwrap;
     514              :         }
     515           36 :         if (itf->partial) {
     516           36 :                 iwrap.partial = itf->partial;
     517           36 :                 iwrap.closure_partial = closure;
     518            0 :         } else if (itf->get) {
     519            0 :                 iwrap.partial = itf->get;
     520            0 :                 iwrap.closure_partial = closure;
     521              :         } else {
     522            0 :                 iwrap.partial = iwrap_partial;
     523            0 :                 iwrap.closure_partial = &iwrap;
     524              :         }
     525           36 :         iwrap.emit = itf->emit ? itf->emit : iwrap_emit;
     526           36 :         iwrap.enter = itf->enter;
     527           36 :         iwrap.next = itf->next;
     528           36 :         iwrap.leave = itf->leave;
     529           36 :         iwrap.get = itf->get;
     530           36 :         iwrap.file = file;
     531           36 :         iwrap.flags = flags;
     532           36 :         iwrap.nesting = 0;
     533              : 
     534              :         /* process */
     535           36 :         rc = itf->start ? itf->start(closure) : 0;
     536           36 :         if (rc == 0)
     537           36 :                 rc = process(template, length, &iwrap, NULL);
     538           36 :         if (itf->stop)
     539           36 :                 itf->stop(closure, rc);
     540           36 :         return rc;
     541              : }
     542              : 
     543            0 : int mustach_fd(const char *template, size_t length, const struct mustach_itf *itf, void *closure, int flags, int fd)
     544              : {
     545              :         int rc;
     546              :         FILE *file;
     547              : 
     548            0 :         file = fdopen(fd, "w");
     549            0 :         if (file == NULL) {
     550            0 :                 rc = MUSTACH_ERROR_SYSTEM;
     551            0 :                 errno = ENOMEM;
     552              :         } else {
     553            0 :                 rc = mustach_file(template, length, itf, closure, flags, file);
     554            0 :                 fclose(file);
     555              :         }
     556            0 :         return rc;
     557              : }
     558              : 
     559           36 : int mustach_mem(const char *template, size_t length, const struct mustach_itf *itf, void *closure, int flags, char **result, size_t *size)
     560              : {
     561              :         int rc;
     562              :         FILE *file;
     563              :         size_t s;
     564              : 
     565           36 :         *result = NULL;
     566           36 :         if (size == NULL)
     567            0 :                 size = &s;
     568           36 :         file = memfile_open(result, size);
     569           36 :         if (file == NULL)
     570            0 :                 rc = MUSTACH_ERROR_SYSTEM;
     571              :         else {
     572           36 :                 rc = mustach_file(template, length, itf, closure, flags, file);
     573           36 :                 if (rc < 0)
     574            0 :                         memfile_abort(file, result, size);
     575              :                 else
     576           36 :                         rc = memfile_close(file, result, size);
     577              :         }
     578           36 :         return rc;
     579              : }
     580              : 
     581            0 : int fmustach(const char *template, const struct mustach_itf *itf, void *closure, FILE *file)
     582              : {
     583            0 :         return mustach_file(template, 0, itf, closure, Mustach_With_AllExtensions, file);
     584              : }
     585              : 
     586            0 : int fdmustach(const char *template, const struct mustach_itf *itf, void *closure, int fd)
     587              : {
     588            0 :         return mustach_fd(template, 0, itf, closure, Mustach_With_AllExtensions, fd);
     589              : }
     590              : 
     591            0 : int mustach(const char *template, const struct mustach_itf *itf, void *closure, char **result, size_t *size)
     592              : {
     593            0 :         return mustach_mem(template, 0, itf, closure, Mustach_With_AllExtensions, result, size);
     594              : }
     595              : 
        

Generated by: LCOV version 2.0-1