LCOV - code coverage report
Current view: top level - templating - mustach-jansson.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 56.1 % 148 83
Test Date: 2026-05-12 15:34:29 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              : {
      22              :   json_t *root;
      23              :   json_t *selection;
      24              :   int depth;
      25              :   struct
      26              :   {
      27              :     json_t *cont;
      28              :     json_t *obj;
      29              :     void *iter;
      30              :     int is_objiter;
      31              :     size_t index, count;
      32              :   } stack[MUSTACH_MAX_DEPTH];
      33              : };
      34              : 
      35              : static int
      36            9 : start (void *closure)
      37              : {
      38            9 :   struct expl *e = closure;
      39            9 :   e->depth = 0;
      40            9 :   e->selection = json_null ();
      41            9 :   e->stack[0].cont = NULL;
      42            9 :   e->stack[0].obj = e->root;
      43            9 :   e->stack[0].index = 0;
      44            9 :   e->stack[0].count = 1;
      45            9 :   return MUSTACH_OK;
      46              : }
      47              : 
      48              : 
      49              : static int
      50            0 : compare (void *closure, const char *value)
      51              : {
      52            0 :   struct expl *e = closure;
      53            0 :   json_t *o = e->selection;
      54              :   double d;
      55              :   json_int_t i;
      56              : 
      57            0 :   switch (json_typeof (o))
      58              :   {
      59            0 :   case JSON_REAL:
      60            0 :     d = json_number_value (o) - atof (value);
      61            0 :     return d < 0 ? -1 : d > 0 ? 1 : 0;
      62            0 :   case JSON_INTEGER:
      63            0 :     i = (json_int_t) json_integer_value (o) - (json_int_t) atoll (value);
      64            0 :     return i < 0 ? -1 : i > 0 ? 1 : 0;
      65            0 :   case JSON_STRING:
      66            0 :     return strcmp (json_string_value (o), value);
      67            0 :   case JSON_TRUE:
      68            0 :     return strcmp ("true", value);
      69            0 :   case JSON_FALSE:
      70            0 :     return strcmp ("false", value);
      71            0 :   case JSON_NULL:
      72            0 :     return strcmp ("null", value);
      73            0 :   default:
      74            0 :     return 1;
      75              :   }
      76              : }
      77              : 
      78              : 
      79              : static int
      80           17 : sel (void *closure, const char *name)
      81              : {
      82           17 :   struct expl *e = closure;
      83              :   json_t *o;
      84              :   int i, r;
      85              : 
      86           17 :   if (name == NULL)
      87              :   {
      88            2 :     o = e->stack[e->depth].obj;
      89            2 :     r = 1;
      90              :   }
      91              :   else
      92              :   {
      93           15 :     i = e->depth;
      94           18 :     while (i >= 0 && ! (o = json_object_get (e->stack[i].obj, name)))
      95            3 :       i--;
      96           15 :     if (i >= 0)
      97           13 :       r = 1;
      98              :     else
      99              :     {
     100            2 :       o = json_null ();
     101            2 :       r = 0;
     102              :     }
     103              :   }
     104           17 :   e->selection = o;
     105           17 :   return r;
     106              : }
     107              : 
     108              : 
     109              : static int
     110            1 : subsel (void *closure, const char *name)
     111              : {
     112            1 :   struct expl *e = closure;
     113            1 :   json_t *o = NULL;
     114            1 :   int r = 0;
     115              : 
     116            1 :   if (json_is_object (e->selection))
     117              :   {
     118            1 :     o = json_object_get (e->selection, name);
     119            1 :     r = o != NULL;
     120              :   }
     121            0 :   else if (json_is_array (e->selection))
     122              :   {
     123              :     char *end;
     124            0 :     size_t idx = (size_t) strtol (name, &end, 10);
     125            0 :     if (! *end && idx < json_array_size (e->selection))
     126              :     {
     127            0 :       o = json_array_get (e->selection, idx);
     128            0 :       r = 1;
     129              :     }
     130              :   }
     131            1 :   if (r)
     132            1 :     e->selection = o;
     133            1 :   return r;
     134              : }
     135              : 
     136              : 
     137              : static int
     138            3 : enter (void *closure, int objiter)
     139              : {
     140            3 :   struct expl *e = closure;
     141              :   json_t *o;
     142              : 
     143            3 :   if (++e->depth >= MUSTACH_MAX_DEPTH)
     144            0 :     return MUSTACH_ERROR_TOO_DEEP;
     145              : 
     146            3 :   o = e->selection;
     147            3 :   e->stack[e->depth].is_objiter = 0;
     148              :   /* Squash warning for comparing float to 0.0 */
     149              : #pragma GCC diagnostic push
     150              : #pragma GCC diagnostic ignored "-Wfloat-equal"
     151            3 :   if (objiter)
     152              :   {
     153            0 :     if (! json_is_object (o))
     154            0 :       goto not_entering;
     155            0 :     e->stack[e->depth].iter = json_object_iter (o);
     156            0 :     if (e->stack[e->depth].iter == NULL)
     157            0 :       goto not_entering;
     158            0 :     e->stack[e->depth].obj = json_object_iter_value (e->stack[e->depth].iter);
     159            0 :     e->stack[e->depth].cont = o;
     160            0 :     e->stack[e->depth].is_objiter = 1;
     161              :   }
     162            3 :   else if (json_is_array (o))
     163              :   {
     164            2 :     e->stack[e->depth].count = json_array_size (o);
     165            2 :     if (e->stack[e->depth].count == 0)
     166            1 :       goto not_entering;
     167            1 :     e->stack[e->depth].cont = o;
     168            1 :     e->stack[e->depth].obj = json_array_get (o, 0);
     169            1 :     e->stack[e->depth].index = 0;
     170              :   }
     171            1 :   else if ((json_is_object (o) && json_object_size (o))
     172            0 :            || json_is_true (o)
     173            0 :            || (json_is_string (o) && json_string_length (o) > 0)
     174            0 :            || (json_is_integer (o) && json_integer_value (o) != 0)
     175            0 :            || (json_is_real (o) && json_real_value (o) != 0))
     176              :   {
     177            1 :     e->stack[e->depth].count = 1;
     178            1 :     e->stack[e->depth].cont = NULL;
     179            1 :     e->stack[e->depth].obj = o;
     180            1 :     e->stack[e->depth].index = 0;
     181              :   }
     182              :   else
     183            0 :     goto not_entering;
     184              : #pragma GCC diagnostic pop
     185            2 :   return 1;
     186              : 
     187            1 : not_entering:
     188            1 :   e->depth--;
     189            1 :   return 0;
     190              : }
     191              : 
     192              : 
     193              : static int
     194            3 : next (void *closure)
     195              : {
     196            3 :   struct expl *e = closure;
     197              : 
     198            3 :   if (e->depth <= 0)
     199            0 :     return MUSTACH_ERROR_CLOSING;
     200              : 
     201            3 :   if (e->stack[e->depth].is_objiter)
     202              :   {
     203            0 :     e->stack[e->depth].iter = json_object_iter_next (e->stack[e->depth].cont, e->stack[e->depth].
     204              :                                                      iter);
     205            0 :     if (e->stack[e->depth].iter == NULL)
     206            0 :       return 0;
     207            0 :     e->stack[e->depth].obj = json_object_iter_value (e->stack[e->depth].iter);
     208            0 :     return 1;
     209              :   }
     210              : 
     211            3 :   e->stack[e->depth].index++;
     212            3 :   if (e->stack[e->depth].index >= e->stack[e->depth].count)
     213            2 :     return 0;
     214              : 
     215            1 :   e->stack[e->depth].obj = json_array_get (e->stack[e->depth].cont, e->stack[e->depth].index);
     216            1 :   return 1;
     217              : }
     218              : 
     219              : 
     220              : static int
     221            2 : leave (void *closure)
     222              : {
     223            2 :   struct expl *e = closure;
     224              : 
     225            2 :   if (e->depth <= 0)
     226            0 :     return MUSTACH_ERROR_CLOSING;
     227              : 
     228            2 :   e->depth--;
     229            2 :   return 0;
     230              : }
     231              : 
     232              : 
     233              : static int
     234           12 : get (void *closure, struct mustach_sbuf *sbuf, int key)
     235              : {
     236           12 :   struct expl *e = closure;
     237              :   const char *s;
     238              :   int d;
     239              : 
     240           12 :   if (key)
     241              :   {
     242            0 :     s = "";
     243            0 :     for (d = e->depth ; d >= 0 ; d--)
     244            0 :       if (e->stack[d].is_objiter)
     245              :       {
     246            0 :         s = json_object_iter_key (e->stack[d].iter);
     247            0 :         break;
     248              :       }
     249              :   }
     250           12 :   else if (json_is_string (e->selection))
     251           10 :     s = json_string_value (e->selection);
     252            2 :   else if (json_is_null (e->selection))
     253            0 :     s = "";
     254              :   else
     255              :   {
     256            2 :     s = json_dumps (e->selection, JSON_ENCODE_ANY | JSON_COMPACT);
     257            2 :     if (s == NULL)
     258            0 :       return MUSTACH_ERROR_SYSTEM;
     259            2 :     sbuf->freecb = free;
     260              :   }
     261           12 :   sbuf->value = s;
     262           12 :   return 1;
     263              : }
     264              : 
     265              : 
     266              : const struct mustach_wrap_itf mustach_jansson_wrap_itf = {
     267              :   .start = start,
     268              :   .stop = NULL,
     269              :   .compare = compare,
     270              :   .sel = sel,
     271              :   .subsel = subsel,
     272              :   .enter = enter,
     273              :   .next = next,
     274              :   .leave = leave,
     275              :   .get = get
     276              : };
     277              : 
     278              : int
     279            0 : mustach_jansson_file (const char *template, size_t length, json_t *root, int flags, FILE *file)
     280              : {
     281              :   struct expl e;
     282            0 :   e.root = root;
     283            0 :   return mustach_wrap_file (template, length, &mustach_jansson_wrap_itf, &e, flags, file);
     284              : }
     285              : 
     286              : 
     287              : int
     288            0 : mustach_jansson_fd (const char *template, size_t length, json_t *root, int flags, int fd)
     289              : {
     290              :   struct expl e;
     291            0 :   e.root = root;
     292            0 :   return mustach_wrap_fd (template, length, &mustach_jansson_wrap_itf, &e, flags, fd);
     293              : }
     294              : 
     295              : 
     296              : int
     297            9 : mustach_jansson_mem (const char *template, size_t length, json_t *root, int flags, char **result,
     298              :                      size_t *size)
     299              : {
     300              :   struct expl e;
     301            9 :   e.root = root;
     302            9 :   return mustach_wrap_mem (template, length, &mustach_jansson_wrap_itf, &e, flags, result, size);
     303              : }
     304              : 
     305              : 
     306              : int
     307            0 : mustach_jansson_write (const char *template, size_t length, json_t *root, int flags,
     308              :                        mustach_write_cb_t *writecb, void *closure)
     309              : {
     310              :   struct expl e;
     311            0 :   e.root = root;
     312            0 :   return mustach_wrap_write (template, length, &mustach_jansson_wrap_itf, &e, flags, writecb,
     313              :                              closure);
     314              : }
     315              : 
     316              : 
     317              : int
     318            0 : mustach_jansson_emit (const char *template, size_t length, json_t *root, int flags,
     319              :                       mustach_emit_cb_t *emitcb, void *closure)
     320              : {
     321              :   struct expl e;
     322            0 :   e.root = root;
     323            0 :   return mustach_wrap_emit (template, length, &mustach_jansson_wrap_itf, &e, flags, emitcb, closure)
     324              :   ;
     325              : }
        

Generated by: LCOV version 2.0-1