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

          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 1.16