LCOV - code coverage report
Current view: top level - src/plugins/xmltool - kscompare.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 39 43 90.7 %
Date: 2022-05-21 16:19:22 Functions: 2 2 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 "xmltool.h"
      10             : 
      11             : #include <stdlib.h>
      12             : #include <string.h>
      13             : 
      14          14 : static Key * commonParent (Key * firstKey, Key * secondKey, size_t maxSize)
      15             : {
      16             :         // First we find the common prefix of the first two keys.
      17             :         // NOTE: a common prefix is not necessarily a common parent
      18             :         //   e.g. system:/abc/d is a common prefix of system:/abc/de and system:/abc/df,
      19             :         //   but the common parent would be system:/abc
      20             : 
      21          14 :         const char * firstName = keyName (firstKey);
      22          14 :         const char * secondName = keyName (secondKey);
      23             : 
      24          14 :         size_t commonLength = 0;
      25         208 :         for (size_t i = 0; i < maxSize; ++i)
      26             :         {
      27         208 :                 if (firstName[i] == '\0' || secondName[i] == '\0')
      28             :                 {
      29             :                         break;
      30             :                 }
      31             : 
      32         208 :                 if (firstName[i] != secondName[i])
      33             :                 {
      34             :                         break;
      35             :                 }
      36             : 
      37         194 :                 commonLength = i + 1;
      38             :         }
      39             : 
      40          14 :         if (commonLength == 0)
      41             :         {
      42             :                 return NULL;
      43             :         }
      44             : 
      45             :         // We now extract the common prefix ...
      46          10 :         char * commonPrefix = strndup (firstName, commonLength);
      47             : 
      48             :         // ... and adjust it to a common parent.
      49          10 :         Key * common = keyNew (commonPrefix, KEY_END);
      50          10 :         if (commonPrefix[commonLength - 1] != '/')
      51             :         {
      52           2 :                 keySetBaseName (common, NULL);
      53             :         }
      54             : 
      55          10 :         free (commonPrefix);
      56             : 
      57          10 :         if ((size_t) keyGetNameSize (common) > maxSize)
      58             :         {
      59           0 :                 keyDel (common);
      60           0 :                 return NULL;
      61             :         }
      62             : 
      63             :         return common;
      64             : }
      65             : 
      66             : 
      67             : /**
      68             :  * @internal
      69             :  *
      70             :  * Calculates the common parent to all keys in @p ks.
      71             :  *
      72             :  * This is a c-helper function, you need not implement it in bindings.
      73             :  *
      74             :  * Given the @p ks KeySet, calculates the parent name for all the keys.
      75             :  * So if @p ks contains these keys:
      76             :  *
      77             :  * @code
      78             :  *   system:/sw/xorg/Monitors/Monitor1/vrefresh
      79             :  *   system:/sw/xorg/Monitors/Monitor1/hrefresh
      80             :  *   system:/sw/xorg/Devices/Device1/driver
      81             :  *   system:/sw/xorg/Devices/Device1/mode
      82             :  * @endcode
      83             :  *
      84             :  * The common parent is @p system:/sw/xorg .
      85             :  *
      86             :  * On the other hand, if we have this KeySet:
      87             :  *
      88             :  * @code
      89             :  *   system:/some/thing
      90             :  *   system:/other/thing
      91             :  *   user:/unique/thing
      92             :  * @endcode
      93             :  *
      94             :  * No common parent is possible, so @p returnedCommonParent will contain nothing.
      95             :  *
      96             :  * @param working the Keyset to work with
      97             :  * @param returnedCommonParent a pre-allocated buffer that will receive the
      98             :  *        common parent, if found
      99             :  * @param maxSize size of the pre-allocated @p returnedCommonParent buffer
     100             :  * @return size in bytes of the parent name, or 0 if there is no common parent (with length <= maxSize)
     101             :  */
     102          14 : size_t ksGetCommonParentName (KeySet * working, char * returnedCommonParent, size_t maxSize)
     103             : {
     104          14 :         if (maxSize > SSIZE_MAX) return 0;
     105          14 :         if (ksGetSize (working) < 1) return 0;
     106             : 
     107          14 :         if (ksGetSize (working) == 1)
     108             :         {
     109           2 :                 return keyGetName (ksAtCursor (working, 0), returnedCommonParent, maxSize);
     110             :         }
     111             : 
     112             :         // Get common parent of first two keys in the KeySet.
     113             : 
     114          12 :         Key * common = commonParent (ksAtCursor (working, 0), ksAtCursor (working, 1), maxSize);
     115             : 
     116          12 :         if (common == NULL)
     117             :         {
     118           4 :                 *returnedCommonParent = '\0';
     119           4 :                 return 0;
     120             :         }
     121             : 
     122             :         // We then check if all keys in the KeySet are below the parent we found.
     123           8 :         KeySet * cut = ksCut (working, common);
     124             : 
     125          10 :         while (ksGetSize (working) != 0)
     126             :         {
     127             :                 // If not all keys match, we find the common prefix of common and the first non-matching key.
     128           2 :                 Key * nextKey = ksAtCursor (working, 0);
     129             : 
     130           2 :                 ksAppend (working, cut);
     131           2 :                 ksDel (cut);
     132             : 
     133           2 :                 Key * newCommon = commonParent (common, nextKey, maxSize);
     134             : 
     135           2 :                 keyDel (common);
     136           2 :                 common = newCommon;
     137             : 
     138           2 :                 if (common == NULL)
     139             :                 {
     140           0 :                         *returnedCommonParent = '\0';
     141           0 :                         return 0;
     142             :                 }
     143             : 
     144           2 :                 cut = ksCut (working, common);
     145             :         }
     146             : 
     147           8 :         ksAppend (working, cut);
     148           8 :         ksDel (cut);
     149             : 
     150           8 :         ssize_t ret = keyGetName (common, returnedCommonParent, maxSize);
     151           8 :         keyDel (common);
     152           8 :         return ret;
     153             : }

Generated by: LCOV version 1.13