LCOV - code coverage report
Current view: top level - templating - mustach-jansson.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 53.4 % 148 79
Test Date: 2025-12-28 14:06:02 Functions: 61.5 % 13 8

            Line data    Source code
       1              : /*
       2              :  Author: José Bollo <jobol@nonadev.net>
       3              : 
       4              :  https://gitlab.com/jobol/mustach
       5              : 
       6              :  SPDX-License-Identifier: ISC
       7              : */
       8              : 
       9              : #ifndef _GNU_SOURCE
      10              : #define _GNU_SOURCE
      11              : #endif
      12              : 
      13              : #include <stdio.h>
      14              : #include <string.h>
      15              : 
      16              : #include "mustach.h"
      17              : #include "mustach-wrap.h"
      18              : #include "mustach-jansson.h"
      19              : 
      20              : struct expl {
      21              :         json_t *root;
      22              :         json_t *selection;
      23              :         int depth;
      24              :         struct {
      25              :                 json_t *cont;
      26              :                 json_t *obj;
      27              :                 void *iter;
      28              :                 int is_objiter;
      29              :                 size_t index, count;
      30              :         } stack[MUSTACH_MAX_DEPTH];
      31              : };
      32              : 
      33            6 : static int start(void *closure)
      34              : {
      35            6 :         struct expl *e = closure;
      36            6 :         e->depth = 0;
      37            6 :         e->selection = json_null();
      38            6 :         e->stack[0].cont = NULL;
      39            6 :         e->stack[0].obj = e->root;
      40            6 :         e->stack[0].index = 0;
      41            6 :         e->stack[0].count = 1;
      42            6 :         return MUSTACH_OK;
      43              : }
      44              : 
      45            0 : static int compare(void *closure, const char *value)
      46              : {
      47            0 :         struct expl *e = closure;
      48            0 :         json_t *o = e->selection;
      49              :         double d;
      50              :         json_int_t i;
      51              : 
      52            0 :         switch (json_typeof(o)) {
      53            0 :         case JSON_REAL:
      54            0 :                 d = json_number_value(o) - atof(value);
      55            0 :                 return d < 0 ? -1 : d > 0 ? 1 : 0;
      56            0 :         case JSON_INTEGER:
      57            0 :                 i = (json_int_t)json_integer_value(o) - (json_int_t)atoll(value);
      58            0 :                 return i < 0 ? -1 : i > 0 ? 1 : 0;
      59            0 :         case JSON_STRING:
      60            0 :                 return strcmp(json_string_value(o), value);
      61            0 :         case JSON_TRUE:
      62            0 :                 return strcmp("true", value);
      63            0 :         case JSON_FALSE:
      64            0 :                 return strcmp("false", value);
      65            0 :         case JSON_NULL:
      66            0 :                 return strcmp("null", value);
      67            0 :         default:
      68            0 :                 return 1;
      69              :         }
      70              : }
      71              : 
      72           10 : static int sel(void *closure, const char *name)
      73              : {
      74           10 :         struct expl *e = closure;
      75              :         json_t *o;
      76              :         int i, r;
      77              : 
      78           10 :         if (name == NULL) {
      79            2 :                 o = e->stack[e->depth].obj;
      80            2 :                 r = 1;
      81              :         } else {
      82            8 :                 i = e->depth;
      83           10 :                 while (i >= 0 && !(o = json_object_get(e->stack[i].obj, name)))
      84            2 :                         i--;
      85            8 :                 if (i >= 0)
      86            7 :                         r = 1;
      87              :                 else {
      88            1 :                         o = json_null();
      89            1 :                         r = 0;
      90              :                 }
      91              :         }
      92           10 :         e->selection = o;
      93           10 :         return r;
      94              : }
      95              : 
      96            1 : static int subsel(void *closure, const char *name)
      97              : {
      98            1 :         struct expl *e = closure;
      99            1 :         json_t *o = NULL;
     100            1 :         int r = 0;
     101              : 
     102            1 :         if (json_is_object(e->selection)) {
     103            1 :                 o = json_object_get(e->selection, name);
     104            1 :                 r = o != NULL;
     105              :         }
     106            0 :         else if (json_is_array(e->selection)) {
     107              :                 char *end;
     108            0 :                 size_t idx = (size_t)strtol(name, &end, 10);
     109            0 :                 if (!*end && idx < json_array_size(e->selection)) {
     110            0 :                         o = json_array_get(e->selection, idx);
     111            0 :                         r = 1;
     112              :                 }               
     113              :         }
     114            1 :         if (r)
     115            1 :                 e->selection = o;
     116            1 :         return r;
     117              : }
     118              : 
     119            3 : static int enter(void *closure, int objiter)
     120              : {
     121            3 :         struct expl *e = closure;
     122              :         json_t *o;
     123              : 
     124            3 :         if (++e->depth >= MUSTACH_MAX_DEPTH)
     125            0 :                 return MUSTACH_ERROR_TOO_DEEP;
     126              : 
     127            3 :         o = e->selection;
     128            3 :         e->stack[e->depth].is_objiter = 0;
     129            3 :         if (objiter) {
     130            0 :                 if (!json_is_object(o))
     131            0 :                         goto not_entering;
     132            0 :                 e->stack[e->depth].iter = json_object_iter(o);
     133            0 :                 if (e->stack[e->depth].iter == NULL)
     134            0 :                         goto not_entering;
     135            0 :                 e->stack[e->depth].obj = json_object_iter_value(e->stack[e->depth].iter);
     136            0 :                 e->stack[e->depth].cont = o;
     137            0 :                 e->stack[e->depth].is_objiter = 1;
     138            3 :         } else if (json_is_array(o)) {
     139            2 :                 e->stack[e->depth].count = json_array_size(o);
     140            2 :                 if (e->stack[e->depth].count == 0)
     141            1 :                         goto not_entering;
     142            1 :                 e->stack[e->depth].cont = o;
     143            1 :                 e->stack[e->depth].obj = json_array_get(o, 0);
     144            1 :                 e->stack[e->depth].index = 0;
     145            1 :         } else if ((json_is_object(o) && json_object_size(o))
     146            0 :                 || json_is_true(o)
     147            0 :                 || (json_is_string(o) && json_string_length(o) > 0)
     148            0 :                 || (json_is_integer(o) && json_integer_value(o) != 0)
     149            0 :                 || (json_is_real(o) && json_real_value(o) != 0)) {
     150            1 :                 e->stack[e->depth].count = 1;
     151            1 :                 e->stack[e->depth].cont = NULL;
     152            1 :                 e->stack[e->depth].obj = o;
     153            1 :                 e->stack[e->depth].index = 0;
     154              :         } else
     155            0 :                 goto not_entering;
     156            2 :         return 1;
     157              : 
     158            1 : not_entering:
     159            1 :         e->depth--;
     160            1 :         return 0;
     161              : }
     162              : 
     163            3 : static int next(void *closure)
     164              : {
     165            3 :         struct expl *e = closure;
     166              : 
     167            3 :         if (e->depth <= 0)
     168            0 :                 return MUSTACH_ERROR_CLOSING;
     169              : 
     170            3 :         if (e->stack[e->depth].is_objiter) {
     171            0 :                 e->stack[e->depth].iter = json_object_iter_next(e->stack[e->depth].cont, e->stack[e->depth].iter);
     172            0 :                 if (e->stack[e->depth].iter == NULL)
     173            0 :                         return 0;
     174            0 :                 e->stack[e->depth].obj = json_object_iter_value(e->stack[e->depth].iter);
     175            0 :                 return 1;
     176              :         }
     177              : 
     178            3 :         e->stack[e->depth].index++;
     179            3 :         if (e->stack[e->depth].index >= e->stack[e->depth].count)
     180            2 :                 return 0;
     181              : 
     182            1 :         e->stack[e->depth].obj = json_array_get(e->stack[e->depth].cont, e->stack[e->depth].index);
     183            1 :         return 1;
     184              : }
     185              : 
     186            2 : static int leave(void *closure)
     187              : {
     188            2 :         struct expl *e = closure;
     189              : 
     190            2 :         if (e->depth <= 0)
     191            0 :                 return MUSTACH_ERROR_CLOSING;
     192              : 
     193            2 :         e->depth--;
     194            2 :         return 0;
     195              : }
     196              : 
     197            6 : static int get(void *closure, struct mustach_sbuf *sbuf, int key)
     198              : {
     199            6 :         struct expl *e = closure;
     200              :         const char *s;
     201              :         int d;
     202              : 
     203            6 :         if (key) {
     204            0 :                 s = "";
     205            0 :                 for (d = e->depth ; d >= 0 ; d--)
     206            0 :                         if (e->stack[d].is_objiter) {
     207            0 :                                 s = json_object_iter_key(e->stack[d].iter);
     208            0 :                                 break;
     209              :                         }
     210              :         }
     211            6 :         else if (json_is_string(e->selection))
     212            6 :                 s = json_string_value(e->selection);
     213            0 :         else if (json_is_null(e->selection))
     214            0 :                 s = "";
     215              :         else {
     216            0 :                 s = json_dumps(e->selection, JSON_ENCODE_ANY | JSON_COMPACT);
     217            0 :                 if (s == NULL)
     218            0 :                         return MUSTACH_ERROR_SYSTEM;
     219            0 :                 sbuf->freecb = free;
     220              :         }
     221            6 :         sbuf->value = s;
     222            6 :         return 1;
     223              : }
     224              : 
     225              : const struct mustach_wrap_itf mustach_jansson_wrap_itf = {
     226              :         .start = start,
     227              :         .stop = NULL,
     228              :         .compare = compare,
     229              :         .sel = sel,
     230              :         .subsel = subsel,
     231              :         .enter = enter,
     232              :         .next = next,
     233              :         .leave = leave,
     234              :         .get = get
     235              : };
     236              : 
     237            0 : int mustach_jansson_file(const char *template, size_t length, json_t *root, int flags, FILE *file)
     238              : {
     239              :         struct expl e;
     240            0 :         e.root = root;
     241            0 :         return mustach_wrap_file(template, length, &mustach_jansson_wrap_itf, &e, flags, file);
     242              : }
     243              : 
     244            0 : int mustach_jansson_fd(const char *template, size_t length, json_t *root, int flags, int fd)
     245              : {
     246              :         struct expl e;
     247            0 :         e.root = root;
     248            0 :         return mustach_wrap_fd(template, length, &mustach_jansson_wrap_itf, &e, flags, fd);
     249              : }
     250              : 
     251            6 : int mustach_jansson_mem(const char *template, size_t length, json_t *root, int flags, char **result, size_t *size)
     252              : {
     253              :         struct expl e;
     254            6 :         e.root = root;
     255            6 :         return mustach_wrap_mem(template, length, &mustach_jansson_wrap_itf, &e, flags, result, size);
     256              : }
     257              : 
     258            0 : int mustach_jansson_write(const char *template, size_t length, json_t *root, int flags, mustach_write_cb_t *writecb, void *closure)
     259              : {
     260              :         struct expl e;
     261            0 :         e.root = root;
     262            0 :         return mustach_wrap_write(template, length, &mustach_jansson_wrap_itf, &e, flags, writecb, closure);
     263              : }
     264              : 
     265            0 : int mustach_jansson_emit(const char *template, size_t length, json_t *root, int flags, mustach_emit_cb_t *emitcb, void *closure)
     266              : {
     267              :         struct expl e;
     268            0 :         e.root = root;
     269            0 :         return mustach_wrap_emit(template, length, &mustach_jansson_wrap_itf, &e, flags, emitcb, closure);
     270              : }
     271              : 
        

Generated by: LCOV version 2.0-1