LCOV - code coverage report
Current view: top level - src/plugins/yajl - yajl_gen_close.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 64 64 100.0 %
Date: 2019-09-12 12:28:41 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include "yajl_gen.h"
      10             : 
      11             : /**
      12             :  * @brief fixes elektraGenCloseIterate for the special handling of
      13             :  * arrays at very last position.
      14             :  *
      15             :  * @param g generate array there
      16             :  * @param key the key to look at
      17             :  */
      18         124 : static void elektraGenCloseLast (yajl_gen g, const Key * key)
      19             : {
      20         124 :         keyNameReverseIterator last = elektraKeyNameGetReverseIterator (key);
      21         124 :         elektraKeyNameReverseNext (&last);
      22             : 
      23             :         ELEKTRA_LOG_DEBUG ("last startup entry: \"%.*s\"", (int) last.size, last.current);
      24             : 
      25         124 :         if (last.current[0] == '#' && strcmp (last.current, "###empty_array"))
      26             :         {
      27             :                 ELEKTRA_LOG_DEBUG ("GEN array close last");
      28          27 :                 yajl_gen_array_close (g);
      29             :         }
      30         124 : }
      31             : 
      32             : 
      33             : /**
      34             :  * @brief Close given number of levels of key
      35             :  *
      36             :  * @pre there is some needed special handling at begin at end,
      37             :  * the caller needs to do that
      38             :  *
      39             :  * For the basename of cur nothing needs to be done
      40             :  * (it was either a value or an array entry)
      41             :  *
      42             :  * Then for every level do:
      43             :  *
      44             :  *
      45             :  * (C1)
      46             :  * #/_
      47             :  * (lookahead says it is a map in the array)
      48             :  * -> close the anonymous map and then the array
      49             :  *
      50             :  * (C2)
      51             :  * _/#
      52             :  * _/___empty_map
      53             :  * (lookahead says it is not a map)
      54             :  * -> don't do anything
      55             :  *
      56             :  * (C3)
      57             :  * #
      58             :  * -> close the array
      59             :  *
      60             :  * (C4)
      61             :  * _
      62             :  * -> close the map
      63             :  *
      64             :  *
      65             :  * @param g to yield json information
      66             :  * @param cur the key which name is used for closing
      67             :  * @param levels the number of levels to close
      68             :  */
      69         843 : static void elektraGenCloseIterate (yajl_gen g, const Key * cur, int levels)
      70             : {
      71         843 :         keyNameReverseIterator curIt = elektraKeyNameGetReverseIterator (cur);
      72             : 
      73             :         // jump last element
      74         843 :         elektraKeyNameReverseNext (&curIt);
      75             : 
      76        1017 :         for (int i = 0; i < levels; ++i)
      77             :         {
      78         174 :                 elektraKeyNameReverseNext (&curIt);
      79             : 
      80         174 :                 lookahead_t lookahead = elektraLookahead (curIt.current, curIt.size);
      81             : 
      82         174 :                 if (curIt.current[0] == '#')
      83             :                 {
      84          58 :                         if (lookahead == LOOKAHEAD_MAP)
      85             :                         {
      86             :                                 ELEKTRA_LOG_DEBUG ("GEN (C1) anon map close");
      87          30 :                                 yajl_gen_map_close (g);
      88             :                         }
      89             :                         ELEKTRA_LOG_DEBUG ("GEN (C3) array close");
      90          58 :                         yajl_gen_array_close (g);
      91             :                 }
      92             :                 else
      93             :                 {
      94         116 :                         if (lookahead == LOOKAHEAD_MAP)
      95             :                         {
      96             :                                 ELEKTRA_LOG_DEBUG ("GEN (C4) map close");
      97          73 :                                 yajl_gen_map_close (g);
      98             :                         }
      99             :                         else
     100             :                         {
     101             :                                 ELEKTRA_LOG_DEBUG ("(C2) lookahead not a map: nothing to do");
     102             :                         }
     103             :                 }
     104             :         }
     105         843 : }
     106             : 
     107             : /**
     108             :  * @brief Special handling of cases related to closing in non-final
     109             :  * situation.
     110             :  *
     111             :  * Closes the name in the middle (first unequal), so it must be executed
     112             :  * after iterating. (Because closing is in reverse order)
     113             :  *
     114             :  * Following situations are possible:
     115             :  *
     116             :  * (X1)
     117             :  * cur:  #/#
     118             :  * next: #
     119             :  * -> closing array (only if levels <0, because it might be outside
     120             :  *  array with iterating one level deeper)
     121             :  *
     122             :  * (X2)
     123             :  * cur:  #/_
     124             :  * next: #
     125             :  * -> array iteration, but with anon map
     126             :  *
     127             :  * (X3)
     128             :  * cur:  #
     129             :  * next: #
     130             :  * -> array iteration, so do not close array
     131             :  *
     132             :  * (X4)
     133             :  * cur:  _/#
     134             :  * next: _
     135             :  * -> closing map, but only if levels <= 0 (means iteration did nothing)
     136             :  *    (otherwise iteration already closed it)
     137             :  *
     138             :  * (X5)
     139             :  * cur:  _/_
     140             :  * next: _
     141             :  * -> closing map (only if levels <= 0, because iteration did not do it)
     142             :  *
     143             :  * (X6)
     144             :  * cur:  _
     145             :  * next: _
     146             :  * -> map iteration on same level, doing nothing
     147             :  *
     148             :  * @param g to generate to
     149             :  * @param pcur pointer to current name
     150             :  * @param csize size where cur has next level
     151             :  * @param pnext pointer to next name
     152             :  * @param levels how many levels were handled before (see examples
     153             :  * above)
     154             :  */
     155         777 : static void elektraGenCloseFirst (yajl_gen g, const char * pcur, size_t csize, const char * pnext, int levels)
     156             : {
     157         777 :         lookahead_t lookahead = elektraLookahead (pcur, csize);
     158             :         ELEKTRA_LOG_DEBUG ("%s -> %s, levels: %d, lookahead: %d", pcur, pnext, levels, lookahead);
     159         777 :         if (*pcur == '#' && *pnext == '#')
     160             :         {
     161         330 :                 if (levels <= 0 && lookahead == LOOKAHEAD_ARRAY)
     162             :                 {
     163             :                         ELEKTRA_LOG_DEBUG ("GEN (X1) closing array in array");
     164          10 :                         yajl_gen_array_close (g);
     165             :                 }
     166         320 :                 else if (lookahead == LOOKAHEAD_MAP)
     167             :                 {
     168             :                         ELEKTRA_LOG_DEBUG ("GEN (X2) next anon-map");
     169          26 :                         yajl_gen_map_close (g);
     170             :                 }
     171             :                 else
     172             :                 {
     173             :                         ELEKTRA_LOG_DEBUG ("(X3) array iteration");
     174             :                 }
     175             :         }
     176         447 :         else if (*pcur != '#')
     177             :         {
     178         447 :                 if (levels <= 0 && lookahead == LOOKAHEAD_ARRAY)
     179             :                 {
     180             :                         ELEKTRA_LOG_DEBUG ("GEN (X4) closing array");
     181          16 :                         yajl_gen_array_close (g);
     182             :                 }
     183         431 :                 else if (lookahead == LOOKAHEAD_MAP)
     184             :                 {
     185             :                         ELEKTRA_LOG_DEBUG ("GEN (X5) closing map");
     186          66 :                         yajl_gen_map_close (g);
     187             :                 }
     188             :                 else
     189             :                 {
     190             :                         ELEKTRA_LOG_DEBUG ("(X6) same level iteration");
     191             :                 }
     192             :         }
     193         777 : }
     194             : 
     195             : /**
     196             :  * @brief Close all levels in cur not needed in next
     197             :  *
     198             :  * Closing is much simpler then opening because no names need to be
     199             :  * yield.
     200             :  *
     201             :  * @pre keys are not allowed to be below,
     202             :  *      except: last run where everything below root/parent key is
     203             :  *      closed
     204             :  *
     205             :  * Then all levels are reverse iterated until the level before the equal
     206             :  * level.
     207             :  * @see elektraGenCloseIterate
     208             :  *
     209             :  * In the level before the equal level there is some special handling in
     210             :  * regards to the next level.
     211             :  * @see elektraGenCloseFirst
     212             :  *
     213             :  * @example
     214             :  *
     215             :  * cur:  user/sw/org/deeper
     216             :  * next: user/sw/org/other/deeper/below
     217             :  * -> nothing will be done ("deeper" is value)
     218             :  * [eq: 3, cur: 4, next: 6, gen: 0]
     219             :  *
     220             :  * cur:  user/sw/org/other/deeper/below
     221             :  * next: user/no
     222             :  * -> "deeper", "other", "org" and "sw" maps will be closed ("below" is value)
     223             :  * [eq: 1, cur: 6, next: 2, gen: 4]
     224             :  *
     225             :  * cur:  user/no
     226             :  * next: user/oops/it/is/below
     227             :  * -> nothing will be done ("no" is value)
     228             :  * [eq: 1, cur: 2, next: 5, gen: 0]
     229             :  *
     230             :  * cur:  user/oops/it/is/below
     231             :  * next: user/x/t/s/x
     232             :  * -> close "is", "it", "oops"
     233             :  * [eq: 1, cur: 5, next: 5, gen: 3]
     234             :  *
     235             :  * last iteration (e.g. close down to root)
     236             :  * cur:  user/x/t/s/x
     237             :  * next: user
     238             :  * -> close "s", "t" and "x" maps
     239             :  * [eq: 1, cur: 5, next: 1, gen: 3]
     240             :  *
     241             :  * cur:  user/#0/1/1/1
     242             :  * next: user/#1/1/1/1
     243             :  * -> close "1", "1", "1", but not array
     244             :  * [eq: 1, cur: 5, next: 5, gen: 3]
     245             :  *
     246             :  * @param g
     247             :  * @param cur
     248             :  * @param next
     249             :  */
     250         777 : void elektraGenClose (yajl_gen g, const Key * cur, const Key * next)
     251             : {
     252         777 :         int curLevels = elektraKeyCountLevel (cur);
     253             : #ifdef HAVE_LOGGER
     254             :         int nextLevels = elektraKeyCountLevel (next);
     255             : #endif
     256         777 :         int equalLevels = elektraKeyCountEqualLevel (cur, next);
     257             : 
     258             :         // 1 for last level not to iterate, 1 before 1 after equal
     259         777 :         int levels = curLevels - equalLevels - 2;
     260             : 
     261         777 :         const char * pcur = keyName (cur);
     262         777 :         size_t csize = 0;
     263         777 :         const char * pnext = keyName (next);
     264         777 :         size_t nsize = 0;
     265        6590 :         for (int i = 0; i < equalLevels + 1; ++i)
     266             :         {
     267        5813 :                 pcur = keyNameGetOneLevel (pcur + csize, &csize);
     268        5813 :                 pnext = keyNameGetOneLevel (pnext + nsize, &nsize);
     269             :         }
     270             : 
     271             : 
     272             :         ELEKTRA_LOG_DEBUG ("eq: %d, cur: %s %d, next: %s %d, levels: %d", equalLevels, pcur, curLevels, pnext, nextLevels, levels);
     273             : 
     274         777 :         if (levels > 0)
     275             :         {
     276          58 :                 elektraGenCloseLast (g, cur);
     277             :         }
     278         777 :         elektraGenCloseIterate (g, cur, levels);
     279         777 :         elektraGenCloseFirst (g, pcur, csize, pnext, levels);
     280         777 : }
     281             : 
     282             : /**
     283             :  * @brief Close the last element
     284             :  *
     285             :  * Needs less special handling because cur is fully below next.
     286             :  *
     287             :  * Will fully iterate over all elements.
     288             :  *
     289             :  * @param g handle to yield close events
     290             :  * @param cur current key
     291             :  * @param next the last key (the parentKey)
     292             :  */
     293          66 : void elektraGenCloseFinally (yajl_gen g, const Key * cur, const Key * next)
     294             : {
     295          66 :         int curLevels = elektraKeyCountLevel (cur);
     296             : #ifdef HAVE_LOGGER
     297             :         int nextLevels = elektraKeyCountLevel (next);
     298             : #endif
     299          66 :         int equalLevels = elektraKeyCountEqualLevel (cur, next);
     300             : 
     301             :         // 1 for last level not to iterate, 1 after equal
     302          66 :         int levels = curLevels - equalLevels - 1;
     303             : 
     304          66 :         const char * pcur = keyName (cur);
     305          66 :         size_t csize = 0;
     306          66 :         const char * pnext = keyName (next);
     307          66 :         size_t nsize = 0;
     308         334 :         for (int i = 0; i < equalLevels + 1; ++i)
     309             :         {
     310         268 :                 pcur = keyNameGetOneLevel (pcur + csize, &csize);
     311         268 :                 pnext = keyNameGetOneLevel (pnext + nsize, &nsize);
     312             :         }
     313             : 
     314             :         ELEKTRA_LOG_DEBUG ("eq: %d, cur: %s %d, next: %s %d, levels: %d", equalLevels, pcur, curLevels, pnext, nextLevels, levels);
     315             :         // fixes elektraGenCloseIterate for the special handling of
     316             :         // arrays finally
     317          66 :         elektraGenCloseLast (g, cur);
     318             : 
     319             :         // now we iterate over the middle part
     320          66 :         elektraGenCloseIterate (g, cur, levels);
     321             : 
     322             :         // now we look at the first unequal element
     323             :         // this is the very last element we are about to close
     324          66 :         if (pcur && *pcur == '#')
     325             :         {
     326             :                 ELEKTRA_LOG_DEBUG ("array close FINAL");
     327             :         }
     328             :         else
     329             :         {
     330             :                 ELEKTRA_LOG_DEBUG ("GEN map close FINAL");
     331          60 :                 yajl_gen_map_close (g);
     332             :         }
     333          66 : }

Generated by: LCOV version 1.13