LCOV - code coverage report
Current view: top level - src/libs/elektra - internal.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 248 255 97.3 %
Date: 2019-09-12 12:28:41 Functions: 23 23 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Internal methods for Elektra.
       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             : #ifdef HAVE_STDIO_H
      14             : #include <stdio.h>
      15             : #endif
      16             : 
      17             : #ifdef HAVE_STDARG_H
      18             : #include <stdarg.h>
      19             : #endif
      20             : 
      21             : #ifdef HAVE_STRING_H
      22             : #include <string.h>
      23             : #endif
      24             : 
      25             : #ifdef HAVE_STDLIB_H
      26             : #include <stdlib.h>
      27             : #endif
      28             : 
      29             : #ifdef HAVE_ERRNO_H
      30             : #include <errno.h>
      31             : #endif
      32             : 
      33             : #ifdef HAVE_STRING_H
      34             : #include <string.h>
      35             : #endif
      36             : 
      37             : #ifdef HAVE_CTYPE_H
      38             : #include <ctype.h>
      39             : #endif
      40             : 
      41             : #include "kdbinternal.h"
      42             : #include <kdbassert.h>
      43             : 
      44             : /**
      45             :  * @brief Internal Methods for Elektra
      46             :  *
      47             :  * To use them:
      48             :  * @code
      49             :  * #include <kdbinternal.h>
      50             :  * @endcode
      51             :  *
      52             :  * There are some areas where libraries have to reimplement
      53             :  * some basic functions to archive support for non-standard
      54             :  * systems, for testing purposes or to provide a little more
      55             :  * convenience.
      56             :  *
      57             :  */
      58             : 
      59             : /**
      60             :  * Copies the key array2 into where array1 points.
      61             :  * It copies size elements.
      62             :  *
      63             :  * Overlapping is prohibited, use elektraMemmove() instead.
      64             :  *
      65             :  * @param array1 the destination
      66             :  * @param array2 the source
      67             :  * @param size how many pointer to Keys to copy
      68             :  * @retval -1 on null pointers
      69             :  * @retval 0 if nothing was done
      70             :  * @return size how many keys were copied
      71             :  */
      72      334890 : ssize_t elektraMemcpy (Key ** array1, Key ** array2, size_t size)
      73             : {
      74      334890 :         if (!array1) return -1;
      75      334890 :         if (!array2) return -1;
      76      334890 :         if (size > SSIZE_MAX) return -1;
      77      334890 :         if (size == 0) return 0;
      78             : #if DEBUG
      79             :         char * a = (char *) array1;
      80             :         char * b = (char *) array2;
      81     1136009 :         for (size_t i = 0; i < size; i++)
      82             :         {
      83     1136009 :                 ELEKTRA_ASSERT (a + i != b && b + i != a, "memcpy overlap: %p and %p with size %zu", (void *) a, (void *) b, size);
      84             :         }
      85             : #endif
      86      224110 :         memcpy (array1, array2, size * sizeof (Key *));
      87      224110 :         return size;
      88             : }
      89             : 
      90             : /**
      91             :  * Copies the key array2 into where array1 points.
      92             :  * It copies size elements.
      93             :  *
      94             :  * Overlapping is ok. If they do not overlap consider
      95             :  * elektraMemcpy() instead.
      96             :  *
      97             :  * @param array1 the destination
      98             :  * @param array2 the source
      99             :  * @param size how many pointer to Keys to copy
     100             :  * @retval -1 on null pointers
     101             :  * @retval 0 if nothing was done
     102             :  * @return size how many keys were copied
     103             :  */
     104      249300 : ssize_t elektraMemmove (Key ** array1, Key ** array2, size_t size)
     105             : {
     106      249300 :         if (!array1) return -1;
     107      249300 :         if (!array2) return -1;
     108      249300 :         if (size > SSIZE_MAX) return -1;
     109      249300 :         if (size == 0) return 0;
     110      249300 :         memmove (array1, array2, size * sizeof (Key *));
     111      249300 :         return size;
     112             : }
     113             : 
     114             : /**@brief Compare Strings.
     115             :  *
     116             :  * @param s1 The first string to be compared
     117             :  * @param s2 The second string to be compared
     118             :  *
     119             :  * @ingroup internal
     120             :  * @return a negative number if s1 is less than s2
     121             :  * @retval 0 if s1 matches s2
     122             :  * @return a positive number if s1 is greater than s2
     123             :  **/
     124       58460 : int elektraStrCmp (const char * s1, const char * s2)
     125             : {
     126       58460 :         ELEKTRA_ASSERT (s1 != NULL && s2 != NULL, "Got null pointer s1: %p s2: %p", (void *) s1, (void *) s2);
     127             : 
     128       58460 :         return strcmp (s1, s2);
     129             : }
     130             : 
     131             : /**@brief Compare Strings up to a maximum length.
     132             :  *
     133             :  * @param s1 The first string to be compared
     134             :  * @param s2 The second string to be compared
     135             :  * @param n The maximum length to be compared
     136             :  *
     137             :  * @ingroup internal
     138             :  * @return a negative number if s1 is less than s2
     139             :  * @retval 0 if s1 matches s2
     140             :  * @return a positive number if s1 is greater than s2
     141             :  **/
     142         342 : int elektraStrNCmp (const char * s1, const char * s2, size_t n)
     143             : {
     144         342 :         ELEKTRA_ASSERT (s1 != NULL && s2 != NULL, "Got null pointer s1: %p s2: %p", (void *) s1, (void *) s2);
     145             : 
     146         342 :         return strncmp (s1, s2, n);
     147             : }
     148             : 
     149             : /**@brief Compare Strings ignoring case.
     150             :  *
     151             :  * @param s1 The first string to be compared
     152             :  * @param s2 The second string to be compared
     153             :  *
     154             :  * @ingroup internal
     155             :  * @return a negative number if s1 is less than s2
     156             :  * @retval 0 if s1 matches s2
     157             :  * @return a positive number if s1 is greater than s2
     158             :  **/
     159     2269548 : int elektraStrCaseCmp (const char * s1, const char * s2)
     160             : {
     161     2269548 :         ELEKTRA_ASSERT (s1 != NULL && s2 != NULL, "Got null pointer s1: %p s2: %p", (void *) s1, (void *) s2);
     162     2269548 :         return strcasecmp (s1, s2);
     163             : }
     164             : 
     165             : /**@brief Compare Strings ignoring case up to a maximum length.
     166             :  *
     167             :  * @param s1 The first string to be compared
     168             :  * @param s2 The second string to be compared
     169             :  * @param n The maximum length to be compared
     170             :  *
     171             :  * @ingroup internal
     172             :  * @return a negative number if s1 is less than s2
     173             :  * @retval 0 if s1 matches s2
     174             :  * @return a positive number if s1 is greater than s2
     175             :  **/
     176          66 : int elektraStrNCaseCmp (const char * s1, const char * s2, size_t n)
     177             : {
     178          66 :         ELEKTRA_ASSERT (s1 != NULL && s2 != NULL, "Got null pointer s1: %p s2: %p", (void *) s1, (void *) s2);
     179          66 :         return strncasecmp (s1, s2, n);
     180             : }
     181             : 
     182             : /**
     183             :  * @brief Compare two memory regions but make cmp chars uppercase before
     184             :  * comparison.
     185             :  *
     186             :  * @param s1 The first string to be compared
     187             :  * @param s2 The second string to be compared
     188             :  * @param size to be compared
     189             :  *
     190             :  * @ingroup internal
     191             :  * @return a negative number if s1 is less than s2
     192             :  * @retval 0 if s1 matches s2
     193             :  * @return a positive number if s1 is greater than s2
     194             :  */
     195        8238 : int elektraMemCaseCmp (const char * s1, const char * s2, size_t size)
     196             : {
     197             :         size_t i;
     198        8238 :         ELEKTRA_ASSERT (s1 != NULL && s2 != NULL, "Got null pointer s1: %p s2: %p", (void *) s1, (void *) s2);
     199       91182 :         for (i = 0; i < size; i++)
     200             :         {
     201       96578 :                 const unsigned char cmp1 = s1[i];
     202       96578 :                 const unsigned char cmp2 = s2[i];
     203       96578 :                 const int CMP1 = toupper (cmp1);
     204       96578 :                 const int CMP2 = toupper (cmp2);
     205       96578 :                 const int diff = CMP1 - CMP2;
     206       96578 :                 if (diff) return diff;
     207             :         }
     208             :         return 0;
     209             : }
     210             : 
     211             : /**Reallocate Storage in a save way.
     212             :  *
     213             :  *@code
     214             : if (elektraRealloc ((void **) & buffer, new_length) < 0) {
     215             :         // here comes the failure handler
     216             :         // you can still use the old buffer
     217             : #if DEBUG
     218             :         fprintf (stderr, "Reallocation error\n");
     219             : #endif
     220             :         elektraFree (buffer);
     221             :         buffer = 0;
     222             :         // return with error
     223             : }
     224             :  *@endcode
     225             :  *
     226             :  * @param buffer is a pointer to a elektraMalloc
     227             :  * @param size is the new size for the memory
     228             :  * @retval -1 on failure
     229             :  * @retval 0 on success
     230             :  * @ingroup internal
     231             :  */
     232     9259154 : int elektraRealloc (void ** buffer, size_t size)
     233             : {
     234     9259154 :         ELEKTRA_ASSERT (size, "Size to allocate is zero (implementation defined behavior)");
     235             :         void * ptr;
     236     9259154 :         void * svr = *buffer;
     237             : 
     238     9259154 :         ptr = realloc (*buffer, size);
     239     9259154 :         ELEKTRA_ASSERT (ptr, "Memory (re)allocation failed with size %zu", size);
     240             :         if (ptr == NULL)
     241             :         {
     242             :                 *buffer = svr; /* restore old buffer*/
     243             :                 return -1;
     244             :         }
     245             :         else
     246             :         {
     247     9259154 :                 *buffer = ptr;
     248             :                 return 0;
     249             :         }
     250             : }
     251             : 
     252             : /**
     253             :  * Allocate memory for Elektra.
     254             :  *
     255             :  * @code
     256             : if ((buffer = elektraMalloc (length)) == 0) {
     257             :         // here comes the failure handler
     258             :         // no allocation happened here, so don't use buffer
     259             : #if DEBUG
     260             :         fprintf (stderr, "Allocation error");
     261             : #endif
     262             :         // return with error
     263             : }
     264             :  * @endcode
     265             :  *
     266             :  * @param size the requested size
     267             :  *
     268             :  * This function is compatible to ANSI-C malloc
     269             :  * @see elektraFree
     270             :  * @see elektraCalloc
     271             :  */
     272    34388052 : void * elektraMalloc (size_t size)
     273             : {
     274    34388052 :         ELEKTRA_ASSERT (size, "Size to allocate is zero (implementation defined behavior)");
     275    34388052 :         void * ret = malloc (size);
     276    34388052 :         ELEKTRA_ASSERT (ret, "Memory allocation failed with size %zu", size);
     277    34388052 :         return ret;
     278             : }
     279             : 
     280             : /**Allocate memory for Elektra.
     281             :  *
     282             :  * Memory will be set to 0.
     283             :  *
     284             :  * @param size the requested size
     285             :  * @see elektraMalloc
     286             :  */
     287     1139647 : void * elektraCalloc (size_t size)
     288             : {
     289     1139647 :         ELEKTRA_ASSERT (size, "Size to allocate is zero (implementation defined behavior)");
     290     1139647 :         void * ret = calloc (1, size);
     291     1139647 :         ELEKTRA_ASSERT (ret, "Memory allocation failed with size %zu", size);
     292     1139647 :         return ret;
     293             : }
     294             : 
     295             : /**Free memory of Elektra or its backends.
     296             :  *
     297             :  * @param ptr the pointer to free
     298             :  *
     299             :  * If ptr is NULL, no operation is performed.
     300             :  *
     301             :  * @ingroup internal
     302             :  * @see elektraMalloc
     303             :  */
     304    37548853 : void elektraFree (void * ptr)
     305             : {
     306    37548853 :         free (ptr);
     307    37548853 : }
     308             : 
     309             : 
     310             : /**Copy string into new allocated memory.
     311             :  *
     312             :  * You need to free the memory yourself.
     313             :  *
     314             :  * @note that size is determined at runtime.
     315             :  *       So if you have a size information, don't use
     316             :  *       that function.
     317             :  *
     318             :  * @param s the null-terminated string to duplicate
     319             :  *
     320             :  * @ingroup internal
     321             :  * @return 0 if out of memory, a pointer otherwise
     322             :  * @pre s must be a c-string.
     323             :  * @see elektraFree
     324             :  * @see elektraStrLen
     325             :  * @see elektraStrNDup
     326             :  */
     327     1627662 : char * elektraStrDup (const char * s)
     328             : {
     329     1627662 :         void * tmp = 0;
     330     1627662 :         size_t l = 0;
     331     1627662 :         ELEKTRA_ASSERT (s, "Tried to duplicate null pointer");
     332             : 
     333     1627662 :         l = elektraStrLen (s);
     334     1627662 :         ELEKTRA_ASSERT (l, "Size of string to duplicate is zero");
     335     1627662 :         tmp = elektraMalloc (l);
     336     1627662 :         if (tmp) memcpy (tmp, s, l);
     337             : 
     338     1627662 :         return tmp;
     339             : }
     340             : 
     341             : /**Copy buffer into new allocated memory.
     342             :  *
     343             :  * You need to free the memory yourself.
     344             :  *
     345             :  * This function also works with \\0 characters
     346             :  * in the buffer. The length is taken as given,
     347             :  * it must be correct.
     348             :  *
     349             :  * @return 0 if out of memory, a pointer otherwise
     350             :  * @param s must be an allocated buffer
     351             :  * @param l the length of s
     352             :  * @ingroup internal
     353             :  */
     354     3306975 : char * elektraStrNDup (const char * s, size_t l)
     355             : {
     356     3306975 :         void * tmp = 0;
     357     3306975 :         ELEKTRA_ASSERT (l, "Size for string duplicate is zero");
     358             : 
     359     3306975 :         tmp = elektraMalloc (l);
     360     3306975 :         if (tmp) memcpy (tmp, s, l);
     361             : 
     362     3306975 :         return tmp;
     363             : }
     364             : 
     365             : 
     366             : /**
     367             :  * Calculates the length in bytes of a string.
     368             :  *
     369             :  * This function differs from strlen() because it is Unicode and multibyte
     370             :  * chars safe. While strlen() counts characters and ignores the final NULL,
     371             :  * elektraStrLen() count bytes including the ending NULL.
     372             :  *
     373             :  * It must not be used to search for / in the name, because it does not
     374             :  * consider escaping. Instead use the unescaped name.
     375             :  *
     376             :  * @see keyUnescapedName()
     377             :  *
     378             :  * @ingroup internal
     379             :  * @param s the string to get the length from
     380             :  * @return number of bytes used by the string, including the final NULL.
     381             :  * @ingroup internal
     382             :  */
     383    29297138 : size_t elektraStrLen (const char * s)
     384             : {
     385    29297138 :         ELEKTRA_ASSERT (s, "Got null pointer");
     386             : 
     387    29297138 :         char * found = strchr (s, 0);
     388    29297138 :         if (found) return found - s + 1;
     389             :         return 0;
     390             : }
     391             : 
     392             : /**
     393             :  * @brief Does string formatting in fresh allocated memory
     394             :  *
     395             :  * @param format as in printf()
     396             :  * @param ... as in printf()
     397             :  *
     398             :  * @return new allocated memory (free with elektraFree)
     399             :  */
     400      296860 : char * elektraFormat (const char * format, ...)
     401             : {
     402      296860 :         ELEKTRA_ASSERT (format, "Got null pointer");
     403             : 
     404             :         va_list va;
     405      296860 :         va_start (va, format);
     406      296860 :         char * ret = elektraVFormat (format, va);
     407      296860 :         va_end (va);
     408      296860 :         return ret;
     409             : }
     410             : 
     411             : /**
     412             :  * @brief Does string formatting in fresh allocated memory
     413             :  *
     414             :  * @param format as in vprintf()
     415             :  * @param arg_list as in vprintf()
     416             :  *
     417             :  * @return new allocated memory (free with elektraFree)
     418             :  */
     419      318477 : char * elektraVFormat (const char * format, va_list arg_list)
     420             : {
     421      318477 :         ELEKTRA_ASSERT (format, "Got null pointer");
     422             : 
     423             :         static int const default_size = 512;
     424      318477 :         char * buffer = elektraMalloc (default_size);
     425      318477 :         if (!buffer) return 0;
     426             : 
     427             :         va_list arg_list_adj;
     428      318477 :         va_copy (arg_list_adj, arg_list);
     429             : 
     430      318477 :         int const calculated_length = vsnprintf (buffer, default_size, format, arg_list);
     431             : 
     432      318477 :         if (calculated_length == -1)
     433             :         {
     434           0 :                 va_end (arg_list_adj);
     435           0 :                 elektraFree (buffer);
     436             :                 // before Glibc 2.0.6, always -1 is returned
     437             :                 // we won't do Glibc job, please upgrade
     438           0 :                 return 0;
     439             :         }
     440             : 
     441      318477 :         if (calculated_length < default_size)
     442             :         {
     443      318471 :                 va_end (arg_list_adj);
     444             :                 // content was written successfully into
     445             :                 // default sized buffer
     446      318471 :                 return buffer;
     447             :         }
     448             : 
     449             :         // String is longer than default_size.
     450             :         // Allocate an intermediate buffer
     451             :         // according to the calculated length from our last try
     452           6 :         size_t const adjusted_buffer_size = calculated_length + 1;
     453           6 :         elektraRealloc ((void **) &buffer, adjusted_buffer_size);
     454           6 :         if (!buffer)
     455             :         {
     456           0 :                 va_end (arg_list_adj);
     457           0 :                 return 0;
     458             :         }
     459             : 
     460           6 :         int const ret = vsnprintf (buffer, adjusted_buffer_size, format, arg_list_adj);
     461             : 
     462           6 :         va_end (arg_list_adj);
     463             : 
     464           6 :         if (ret == -1)
     465             :         {
     466           0 :                 elektraFree (buffer);
     467           0 :                 return 0;
     468             :         }
     469           6 :         return buffer;
     470             : }
     471             : 
     472             : 
     473             : /**
     474             :  * Validates whether the supplied keyname is valid.
     475             :  *
     476             :  * The function looks for tangling escape characters in the end
     477             :  * and for a minimum length.
     478             :  *
     479             :  * Does not check for valid namespaces
     480             :  *
     481             :  * @pre size must be at least 2
     482             :  *
     483             :  * @param name the key name that is to be checked
     484             :  * @param size a elektraStrLen of the key name
     485             :  * @retval true if the supplied keyname part is valid
     486             :  * @retval false if its invalid
     487             :  */
     488     7320426 : int elektraValidateKeyName (const char * name, size_t size)
     489             : {
     490     7320426 :         ELEKTRA_ASSERT (name, "Got null pointer");
     491     7320426 :         ELEKTRA_ASSERT (size >= 2, "size too small %zu", size);
     492             : 
     493     7320426 :         size_t escapeCount = 0;
     494             : 
     495     7320426 :         size -= 2; // forward null character to last character
     496             : 
     497             :         // now do backwards iteration
     498    14640926 :         while (size && name[size] == '\\')
     499             :         {
     500          74 :                 ++escapeCount;
     501          74 :                 --size;
     502             :         }
     503             : 
     504     7320426 :         return (escapeCount % 2) == 0; // only allow equal number of escapes in the end
     505             : }
     506             : 
     507             : /**
     508             :  * @internal
     509             :  *
     510             :  * @brief Write number backslashes to dest
     511             :  *
     512             :  * @param dest where to write to, will be updated to position after
     513             :  *        the written backslashes
     514             :  * @param number of backslashes to write
     515             :  */
     516         948 : static void elektraWriteBackslashes (char ** dest, size_t number)
     517             : {
     518         948 :         ELEKTRA_ASSERT (dest, "Got null pointer");
     519         948 :         ELEKTRA_ASSERT (*dest, "Got null pointer (*dest)");
     520             : 
     521             :         char * dp = *dest;
     522        2060 :         while (number)
     523             :         {
     524        1112 :                 *dp = '\\';
     525        1112 :                 ++dp;
     526        1112 :                 --number;
     527             :         }
     528         948 :         *dest = dp;
     529         948 : }
     530             : 
     531             : /**
     532             :  * @internal
     533             :  *
     534             :  * @brief Unescapes the beginning of the key name part
     535             :  *
     536             :  * If there was something to escape in the begin, then it is guaranteed
     537             :  * that nothing more needs to be escaped.
     538             :  *
     539             :  * Otherwise this method does not change anything
     540             :  *
     541             :  * @param source the source to read from
     542             :  * @param size the number of bytes to process from source
     543             :  * @param [in] dest the destination to write to
     544             :  * @param [out] dest pointer after writing to it (w/o null, 1 after the
     545             :  *        last character)
     546             :  *
     547             :  * @retval 0 if nothing was done (dest unmodified) and escaping of
     548             :  *         string needs to be done
     549             :  * @retval 1 if key name part was handled correctly (dest might be
     550             :  *         updated if it was needed)
     551             :  */
     552     3470149 : int elektraUnescapeKeyNamePartBegin (const char * source, size_t size, char ** dest)
     553             : {
     554     3470149 :         const char * sp = source;
     555     3470149 :         char * dp = *dest;
     556             : 
     557     3470149 :         ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);
     558             : 
     559     3470149 :         if (!strncmp ("%", sp, size))
     560             :         {
     561             :                 // nothing to do, but part is finished
     562             :                 return 1;
     563             :         }
     564             : 
     565             :         size_t skippedBackslashes = 0;
     566             :         // skip all backslashes, but one, at start of a name
     567     3712916 :         while (*sp == '\\')
     568             :         {
     569      296031 :                 ++sp;
     570      296031 :                 ++skippedBackslashes;
     571             :         }
     572     3416885 :         size -= skippedBackslashes;
     573             : 
     574     3416885 :         if (skippedBackslashes > 0)
     575             :         {
     576             :                 // correct by one (avoid lookahead in loop)
     577      293113 :                 --sp;
     578      293113 :                 ++size;
     579      293113 :                 --skippedBackslashes;
     580             :         }
     581             : 
     582     3416885 :         if (size <= 1)
     583             :         {
     584             :                 // matches below would be wrong
     585             :                 return 0;
     586             :         }
     587             : 
     588     3413069 :         if (!strncmp ("\\%", sp, size))
     589             :         {
     590         748 :                 elektraWriteBackslashes (&dp, skippedBackslashes);
     591         748 :                 strcpy (dp, "%");
     592         748 :                 *dest = dp + 1;
     593         748 :                 return 1;
     594             :         }
     595             : 
     596     3412321 :         if (!strncmp ("\\.", sp, size))
     597             :         {
     598          20 :                 elektraWriteBackslashes (&dp, skippedBackslashes);
     599          20 :                 strcpy (dp, ".");
     600          20 :                 *dest = dp + 1;
     601          20 :                 return 1;
     602             :         }
     603             : 
     604     3412301 :         if (size <= 2)
     605             :         {
     606             :                 // matches below would be wrong
     607             :                 return 0;
     608             :         }
     609             : 
     610     3315492 :         if (!strncmp ("\\..", sp, size))
     611             :         {
     612          18 :                 elektraWriteBackslashes (&dp, skippedBackslashes);
     613          18 :                 strcpy (dp, "..");
     614          18 :                 *dest = dp + 2;
     615          18 :                 return 1;
     616             :         }
     617             : 
     618             :         return 0;
     619             : }
     620             : 
     621             : 
     622             : /**
     623             :  * @internal
     624             :  *
     625             :  * @brief Unescapes (a part of) a key name.
     626             :  *
     627             :  * As described in Syntax for Key Names, slashes are
     628             :  * prefixed with a \\ (or uneven number thereof). This method removes all \\ that are such
     629             :  * escape characters.
     630             :  *
     631             :  * The new string will be written to dest.
     632             :  * May only need half the storage than the source string.
     633             :  * It is not safe to use the same string for source and dest.
     634             :  *
     635             :  * @param source the source to read from
     636             :  * @param size the number of bytes to process from source
     637             :  * @param dest the destination to write to
     638             :  *
     639             :  * @return the destination pointer how far it was written to
     640             :  */
     641     3416107 : char * elektraUnescapeKeyNamePart (const char * source, size_t size, char * dest)
     642             : {
     643     3416107 :         const char * sp = source;
     644     3416107 :         char * dp = dest;
     645     3416107 :         size_t count = 0;
     646             : 
     647     3416107 :         ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);
     648             : 
     649    39775037 :         while (size)
     650             :         {
     651    36358930 :                 if (*sp == '\\')
     652             :                 {
     653     1746767 :                         ++count;
     654             :                 }
     655    34612163 :                 else if (*sp == '/')
     656             :                 {
     657             :                         // we escape a part, so there had to be a backslash
     658     1736772 :                         ELEKTRA_ASSERT (count > 0, "no backslash found, count is %zu", count);
     659     1736772 :                         ELEKTRA_ASSERT ((count % 2) == 1, "counted uneven number of backslashes: %zu", count);
     660             : 
     661     1736772 :                         count /= 2;
     662     3475610 :                         while (count)
     663             :                         {
     664        2066 :                                 *dp = '\\';
     665        2066 :                                 ++dp;
     666        2066 :                                 --count;
     667             :                         }
     668             : 
     669     1736772 :                         *dp = *sp;
     670     1736772 :                         ++dp;
     671             :                 }
     672             :                 else
     673             :                 {
     674             :                         // output delayed backslashes
     675    32876462 :                         while (count)
     676             :                         {
     677        1071 :                                 *dp = '\\';
     678        1071 :                                 ++dp;
     679        1071 :                                 --count;
     680             :                         }
     681             : 
     682    32875391 :                         *dp = *sp;
     683    32875391 :                         ++dp;
     684             :                 }
     685    36358930 :                 ++sp;
     686    36358930 :                 --size;
     687             :         }
     688             : 
     689     3416107 :         ELEKTRA_ASSERT ((count % 2) == 0, "uneven number of backslashes: %zu", count);
     690     3416107 :         count /= 2;
     691     6834610 :         while (count)
     692             :         {
     693        2396 :                 *dp = '\\';
     694        2396 :                 ++dp;
     695        2396 :                 --count;
     696             :         }
     697     3416107 :         return dp;
     698             : }
     699             : 
     700             : /**
     701             :  * @internal
     702             :  *
     703             :  * @brief Unescapes a key name.
     704             :  *
     705             :  * Writes a null terminated sequence of key name parts to dest.
     706             :  *
     707             :  * May only need half the storage than the source string.
     708             :  * It is not safe to use the same string for source and dest.
     709             :  **/
     710    14552497 : size_t elektraUnescapeKeyName (const char * source, char * dest)
     711             : {
     712    14552497 :         const char * sp = source;
     713    14552497 :         char * dp = dest;
     714    14552497 :         size_t size = 0;
     715             : 
     716    14552497 :         ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);
     717             : 
     718             :         // if there is nothing to unescape, just make a copy and replace / with \0
     719    14552497 :         if (strpbrk (sp, "\\%") == NULL)
     720             :         {
     721    13846283 :                 strcpy (dest, sp);
     722    13846283 :                 char * last = dp;
     723    50221875 :                 while ((dp = strchr (dp, '/')) != NULL)
     724             :                 {
     725    22529309 :                         *dp = '\0';
     726    22529309 :                         ++dp;
     727    22529309 :                         last = dp;
     728             :                 }
     729             :                 // add 1, if we didn't end with \0 already
     730    13846283 :                 return last - dest + strlen (last) + (*last != '\0');
     731             :         }
     732             : 
     733      706214 :         if (*sp == '/')
     734             :         {
     735             :                 // handling for cascading names
     736       15725 :                 *dp = 0;
     737       15725 :                 ++dp;
     738             :         }
     739     4176363 :         while (*(sp = keyNameGetOneLevel (sp + size, &size)))
     740             :         {
     741     3470149 :                 if (!elektraUnescapeKeyNamePartBegin (sp, size, &dp))
     742             :                 {
     743     3416099 :                         dp = elektraUnescapeKeyNamePart (sp, size, dp);
     744             :                 }
     745     3470149 :                 *dp = 0;
     746     3470149 :                 ++dp;
     747             :         }
     748      706214 :         return dp - dest;
     749             : }
     750             : 
     751             : /**
     752             :  * @internal
     753             :  *
     754             :  * Escapes (a part of) a key name.
     755             :  */
     756     1330599 : int elektraEscapeKeyNamePartBegin (const char * source, char * dest)
     757             : {
     758     1330599 :         const char * sp = source;
     759     1330599 :         char * dp = dest;
     760             : 
     761     1330599 :         ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);
     762             : 
     763     1330599 :         if (!strcmp ("", sp))
     764             :         {
     765        1077 :                 strcpy (dp, "%");
     766        1077 :                 return 1;
     767             :         }
     768             : 
     769             :         size_t skippedBackslashes = 0;
     770             :         // skip all backslashes at start of a name
     771     1331166 :         while (*sp == '\\')
     772             :         {
     773        1644 :                 ++sp;
     774        1644 :                 ++skippedBackslashes;
     775             :         }
     776             : 
     777     1329522 :         if (!strcmp ("%", sp))
     778             :         {
     779         124 :                 elektraWriteBackslashes (&dp, skippedBackslashes);
     780         124 :                 strcpy (dp, "\\%");
     781         124 :                 return 1;
     782             :         }
     783             : 
     784     1329398 :         if (!strcmp (".", sp))
     785             :         {
     786          20 :                 elektraWriteBackslashes (&dp, skippedBackslashes);
     787          20 :                 strcpy (dp, "\\.");
     788          20 :                 return 1;
     789             :         }
     790             : 
     791     1329378 :         if (!strcmp ("..", sp))
     792             :         {
     793          18 :                 elektraWriteBackslashes (&dp, skippedBackslashes);
     794          18 :                 strcpy (dp, "\\..");
     795          18 :                 return 1;
     796             :         }
     797             : 
     798             :         return 0;
     799             : }
     800             : 
     801             : 
     802             : /**
     803             :  * @internal
     804             :  *
     805             :  * @brief Escapes character in the part of a key name.
     806             :  *
     807             :  * As described in Syntax for Key Names, special characters will be
     808             :  * prefixed with a \\. No existing escaping is assumed. That means
     809             :  * that even sequences that look like escapings will be escaped again.
     810             :  * For example, \\/ will be escaped (or quoted) to \\\\\\/.
     811             :  *
     812             :  * The string will be written to dest.
     813             :  *
     814             :  * @note May need twice the storage than the source string.
     815             :  *       Do not use the source string as destination string.
     816             :  *
     817             :  * @param source the source pointer where escaping should start
     818             :  * @param dest the destination to write to (twice the size as sp)
     819             :  *
     820             :  * @return pointer to destination
     821             :  */
     822     1330599 : char * elektraEscapeKeyNamePart (const char * source, char * dest)
     823             : {
     824     1330599 :         if (elektraEscapeKeyNamePartBegin (source, dest))
     825             :         {
     826             :                 return dest;
     827             :         }
     828             : 
     829     1329360 :         size_t count = 0;
     830             : 
     831     1329360 :         const char * sp = source;
     832     1329360 :         char * dp = dest;
     833             : 
     834     1329360 :         ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);
     835             : 
     836     8447567 :         while (*sp)
     837             :         {
     838     7118207 :                 if (*sp == '\\')
     839             :                 {
     840        2881 :                         ++count;
     841             :                 }
     842     7115326 :                 else if (*sp == '/')
     843             :                 {
     844             :                         // escape every slash
     845        9944 :                         *dp = '\\';
     846        9944 :                         ++dp;
     847             :                         // and print escaped slashes
     848       20232 :                         while (count)
     849             :                         {
     850         344 :                                 *dp = '\\';
     851         344 :                                 ++dp;
     852         344 :                                 --count;
     853             :                         }
     854             :                 }
     855             :                 else
     856             :                 {
     857             :                         count = 0;
     858             :                 }
     859     7118207 :                 *dp = *sp;
     860     7118207 :                 ++dp;
     861     7118207 :                 ++sp;
     862             :         }
     863             :         // print other escaped backslashes at end of part
     864     1330886 :         while (count)
     865             :         {
     866        1526 :                 *dp = '\\';
     867        1526 :                 ++dp;
     868        1526 :                 --count;
     869             :         }
     870     1329360 :         *dp = 0;
     871     1329360 :         return dest;
     872             : }

Generated by: LCOV version 1.13