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 : }
|