LCOV - code coverage report
Current view: top level - src/libs/elektra - trie.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 75 76 98.7 %
Date: 2019-09-12 12:28:41 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Interna of trie functionality.
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #ifdef HAVE_KDBCONFIG_H
      10             : #include "kdbconfig.h"
      11             : #endif
      12             : 
      13             : #if VERBOSE && defined(HAVE_STDIO_H)
      14             : #include <stdio.h>
      15             : #endif
      16             : 
      17             : #ifdef HAVE_LOCALE_H
      18             : #include <locale.h>
      19             : #endif
      20             : 
      21             : #ifdef HAVE_STDLIB_H
      22             : #include <stdlib.h>
      23             : #endif
      24             : 
      25             : #ifdef HAVE_STRING_H
      26             : #include <string.h>
      27             : #endif
      28             : 
      29             : #ifdef HAVE_STDIO_H
      30             : #include <stdio.h>
      31             : #endif
      32             : 
      33             : #include "kdbinternal.h"
      34             : 
      35             : static char * elektraTrieStartsWith (const char * str, const char * substr);
      36             : static Backend * elektraTriePrefixLookup (Trie * trie, const char * name);
      37             : 
      38             : /**
      39             :  * @brief The Trie structure
      40             :  */
      41             : 
      42             : /**
      43             :  * Lookups a backend inside the trie.
      44             :  *
      45             :  * @return the backend if found
      46             :  * @return 0 otherwise
      47             :  * @param trie the trie object to work with
      48             :  * @param key the name of this key will be looked up
      49             :  * @ingroup trie
      50             :  */
      51      496171 : Backend * trieLookup (Trie * trie, const Key * key)
      52             : {
      53      496171 :         char * where = 0;
      54      496171 :         Backend * ret = 0;
      55      496171 :         size_t len = 0;
      56             : 
      57      496171 :         if (!key) return 0;
      58      496171 :         if (!trie) return 0;
      59             : 
      60      316317 :         len = keyGetNameSize (key) + 1;
      61      316317 :         if (len <= 1) return 0; // would crash otherwise
      62      316317 :         where = elektraMalloc (len);
      63      316317 :         strncpy (where, keyName (key), len);
      64      316317 :         where[len - 2] = '/';
      65             : 
      66      316317 :         ret = elektraTriePrefixLookup (trie, where);
      67      316317 :         elektraFree (where);
      68             : 
      69      316317 :         return ret;
      70             : }
      71             : 
      72             : /**
      73             :  * Closes the trie and all opened backends within.
      74             :  *
      75             :  * @param trie the trie to close
      76             :  * @param errorKey the key used to report warnings
      77             :  * @ingroup trie
      78             :  * @retval 0 on success
      79             :  */
      80      103489 : int trieClose (Trie * trie, Key * errorKey)
      81             : {
      82             :         size_t i;
      83      103489 :         if (trie == NULL) return 0;
      84    10150400 :         for (i = 0; i < KDB_MAX_UCHAR; ++i)
      85             :         {
      86    10150400 :                 if (trie->text[i] != NULL)
      87             :                 {
      88       92842 :                         trieClose (trie->children[i], errorKey);
      89       92842 :                         if (trie->value[i]) backendClose (trie->value[i], errorKey);
      90       92842 :                         elektraFree (trie->text[i]);
      91             :                 }
      92             :         }
      93       39650 :         if (trie->empty_value)
      94             :         {
      95         250 :                 backendClose (trie->empty_value, errorKey);
      96             :         }
      97       39650 :         elektraFree (trie);
      98       39650 :         return 0;
      99             : }
     100             : 
     101             : /**
     102             :  * @brief Insert into trie
     103             :  *
     104             :  * @ingroup trie
     105             :  *
     106             :  * @param trie the trie to insert to (0 to create a new trie)
     107             :  * @param name the key's name to insert
     108             :  * @param value the value to insert
     109             :  *
     110             :  * @retval trie on success
     111             :  */
     112      198254 : Trie * trieInsert (Trie * trie, const char * name, Backend * value)
     113             : {
     114             :         unsigned char idx;
     115             : 
     116      198254 :         if (name == 0)
     117             :         {
     118           0 :                 name = "";
     119             :         }
     120      198254 :         idx = (unsigned char) name[0];
     121             : 
     122      198254 :         if (trie == NULL)
     123             :         {
     124       39650 :                 trie = elektraCalloc (sizeof (Trie));
     125             : 
     126       39650 :                 if (!strcmp ("", name))
     127             :                 {
     128         244 :                         trie->empty_value = value;
     129         244 :                         return trie;
     130             :                 }
     131             : 
     132       39406 :                 trie->textlen[idx] = strlen (name);
     133             : 
     134       39406 :                 trie->text[idx] = elektraStrDup (name);
     135             : 
     136       39406 :                 trie->value[idx] = value;
     137       39406 :                 return trie;
     138             :         }
     139             : 
     140      158604 :         if (!strcmp ("", name))
     141             :         {
     142           6 :                 trie->empty_value = value;
     143           6 :                 return trie;
     144             :         }
     145             : 
     146      158598 :         if (trie->text[idx])
     147             :         {
     148             :                 char * p;
     149             :                 /* there exists an entry with the same first character */
     150      120782 :                 if ((p = elektraTrieStartsWith (name, trie->text[idx])) == 0)
     151             :                 {
     152             :                         /* the name in the trie is part of the searched name --> continue search */
     153      105162 :                         trie->children[idx] = trieInsert (trie->children[idx], name + trie->textlen[idx], value);
     154             :                 }
     155             :                 else
     156             :                 {
     157             :                         /* name in trie doesn't match name --> split trie */
     158             :                         char * newname;
     159             :                         Trie * child;
     160             :                         unsigned char idx2;
     161             : 
     162       15620 :                         newname = elektraStrDup (p);
     163       15620 :                         *p = 0; /* shorten the old name in the trie */
     164       15620 :                         trie->textlen[idx] = strlen (trie->text[idx]);
     165             : 
     166       15620 :                         child = trie->children[idx];
     167             : 
     168             :                         /* insert the name given as a parameter into the new trie entry */
     169       15620 :                         trie->children[idx] = trieInsert (NULL, name + (p - trie->text[idx]), value);
     170             : 
     171             :                         /* insert the split try into the new trie entry */
     172             : 
     173       15620 :                         idx2 = (unsigned char) newname[0];
     174       15620 :                         trie->children[idx]->text[idx2] = newname;
     175       15620 :                         trie->children[idx]->textlen[idx2] = strlen (newname);
     176       15620 :                         trie->children[idx]->value[idx2] = trie->value[idx];
     177       15620 :                         trie->children[idx]->children[idx2] = child;
     178             : 
     179       15620 :                         trie->value[idx] = 0;
     180             :                 }
     181             :         }
     182             :         else
     183             :         {
     184             :                 /* there doesn't exist an entry with the same first character */
     185       37816 :                 trie->text[idx] = elektraStrDup (name);
     186       37816 :                 trie->value[idx] = (void *) value;
     187       37816 :                 trie->textlen[idx] = strlen (name);
     188             :         }
     189             : 
     190             :         return trie;
     191             : }
     192             : 
     193             : 
     194             : #if 0
     195             : 
     196             : static Trie *delete_trie(Trie *trie, char *name, CloseMapper closemapper)
     197             : {
     198             :         Trie *tr;
     199             :         unsigned char idx;
     200             :         if (trie==NULL) {
     201             :                 return NULL;
     202             :         }
     203             : 
     204             :         idx=(unsigned char) name[0];
     205             : 
     206             :         if (trie->text[idx]==NULL) {
     207             :                 return NULL;
     208             :         }
     209             : 
     210             :         if (elektraTrieStartsWith(name,trie->text[idx])==0) {
     211             : 
     212             :                 tr=delete_trie(trie->children[idx],name+trie->textlen[idx],closemapper);
     213             : 
     214             :                 if (tr==NULL) {
     215             :                         /* child trie has been deleted */
     216             :                         trie->children[idx]=NULL;
     217             :                         elektraFree (trie->text[idx]);
     218             :                         closemapper(trie->value[idx]);
     219             :                         trie->text[idx]=NULL;
     220             :                 }
     221             : 
     222             :                 return trie;
     223             :         }
     224             :         return NULL;
     225             : }
     226             : 
     227             : #endif
     228             : 
     229             : /**
     230             :  * return NULL if string starts with substring, except for the terminating '\0',
     231             :  * otherwise return a pointer to the first mismatch in substr.
     232             :  *
     233             :  * Takes const char* arguments but return char* pointer to it.
     234             :  * (like e.g. strchr)
     235             :  */
     236      506048 : static char * elektraTrieStartsWith (const char * str, const char * substr)
     237             : {
     238      506048 :         size_t i = 0;
     239      506048 :         size_t sublen = strlen (substr);
     240             : 
     241     6384142 :         for (i = 0; i < sublen; i++)
     242             :         {
     243     5979992 :                 if (substr[i] != str[i]) return (char *) substr + i;
     244             :         }
     245             :         return 0;
     246             : }
     247             : 
     248      615305 : static Backend * elektraTriePrefixLookup (Trie * trie, const char * name)
     249             : {
     250      615305 :         if (trie == NULL) return NULL;
     251             : 
     252      446683 :         unsigned char idx = (unsigned char) name[0];
     253      446683 :         const char * trieText = trie->text[idx];
     254             : 
     255      446683 :         if (trieText == NULL)
     256             :         {
     257       61417 :                 return trie->empty_value;
     258             :         }
     259             : 
     260      385266 :         void * ret = NULL;
     261      385266 :         if (elektraTrieStartsWith (name, trieText) == 0)
     262             :         {
     263      298988 :                 ret = elektraTriePrefixLookup (trie->children[idx], name + trie->textlen[idx]);
     264             :         }
     265             :         else
     266             :         {
     267       86278 :                 return trie->empty_value;
     268             :         }
     269             : 
     270      522911 :         if (ret == NULL && trie->value[idx] == NULL)
     271             :         {
     272       12087 :                 return trie->empty_value;
     273             :         }
     274      286901 :         if (ret == NULL) return trie->value[idx];
     275             : 
     276             :         return ret;
     277             : }

Generated by: LCOV version 1.13