2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 Optimized string handling code, including c11-compliant
41 "safe C library" variants.
44 #ifndef included_clib_string_h
45 #define included_clib_string_h
47 #include <vppinfra/clib.h> /* for CLIB_LINUX_KERNEL */
48 #include <vppinfra/vector.h>
49 #include <vppinfra/error_bootstrap.h>
51 #include <vppinfra/memcpy_x86_64.h>
54 #ifdef CLIB_LINUX_KERNEL
55 #include <linux/string.h>
62 #ifdef CLIB_STANDALONE
63 #include <vppinfra/standalone_string.h>
67 #include <x86intrin.h>
70 /* Exchanges source and destination. */
71 void clib_memswap (void *_a, void *_b, uword bytes);
74 static_always_inline void *
75 clib_memcpy_fast (void *restrict dst, const void *restrict src, size_t n)
78 "memcpy(src, dst, n) with src == NULL or dst == NULL is undefined "
80 #if defined(__COVERITY__)
81 return memcpy (dst, src, n);
82 #elif defined(__SSE4_2__)
83 clib_memcpy_x86_64 (dst, src, n);
86 return memcpy (dst, src, n);
90 static_always_inline void *
91 clib_memmove (void *dst, const void *src, size_t n)
100 for (uword i = n - 1; (i + 1) > 0; i--)
103 for (uword i = 0; i < n; i++)
109 #include <vppinfra/memcpy.h>
111 /* c-11 string manipulation variants */
127 * In order to provide smooth mapping from unsafe string API to the clib string
128 * macro, we often have to improvise s1max and s2max due to the additional
129 * arguments are required for implementing the safe API. This macro is used
130 * to provide the s1max/s2max. It is not perfect because the actual
131 * s1max/s2max may be greater than 4k and the mapping from the unsafe API to
132 * the macro would cause a regression. However, it is not terribly likely.
133 * So I bet against the odds.
135 #define CLIB_STRING_MACRO_MAX 4096
138 typedef uword rsize_t;
140 void clib_c11_violation (const char *s);
141 errno_t memcpy_s (void *__restrict__ dest, rsize_t dmax,
142 const void *__restrict__ src, rsize_t n);
144 always_inline errno_t
145 memcpy_s_inline (void *__restrict__ dest, rsize_t dmax,
146 const void *__restrict__ src, rsize_t n)
152 * Optimize constant-number-of-bytes calls without asking
153 * "too many questions for someone from New Jersey"
155 if (COMPILE_TIME_CONST (n))
157 clib_memcpy_fast (dest, src, n);
162 * call bogus if: src or dst NULL, trying to copy
163 * more data than we have space in dst, or src == dst.
164 * n == 0 isn't really "bad", so check first in the
165 * "wall-of-shame" department...
167 bad = (dest == 0) + (src == 0) + (n > dmax) + (dest == src) + (n == 0);
168 if (PREDICT_FALSE (bad != 0))
170 /* Not actually trying to copy anything is OK */
174 clib_c11_violation ("dest NULL");
176 clib_c11_violation ("src NULL");
178 clib_c11_violation ("n > dmax");
180 clib_c11_violation ("dest == src");
184 /* Check for src/dst overlap, which is not allowed */
185 low = (uword) (src < dest ? src : dest);
186 hi = (uword) (src < dest ? dest : src);
188 if (PREDICT_FALSE (low + (n - 1) >= hi))
190 clib_c11_violation ("src/dest overlap");
194 clib_memcpy_fast (dest, src, n);
199 * Note: $$$ This macro is a crutch. Folks need to manually
200 * inspect every extant clib_memcpy(...) call and
201 * attempt to provide a real destination buffer size
204 #define clib_memcpy(d,s,n) memcpy_s_inline(d,n,s,n)
206 errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
208 always_inline errno_t
209 memset_s_inline (void *s, rsize_t smax, int c, rsize_t n)
213 bad = (s == 0) + (n > smax);
215 if (PREDICT_FALSE (bad != 0))
218 clib_c11_violation ("s NULL");
220 clib_c11_violation ("n > smax");
228 * This macro is not [so much of] a crutch.
229 * It's super-typical to write:
231 * ep = pool_get (<pool>);
232 * clib_memset(ep, 0, sizeof (*ep));
234 * The compiler should delete the not-so useful
235 * (n > smax) test. TBH the NULL pointer check isn't
236 * so useful in this case, but so be it.
238 #define clib_memset(s,c,n) memset_s_inline(s,n,c,n)
240 static_always_inline void
241 clib_memcpy_le (u8 * dst, u8 * src, u8 len, u8 max_len)
243 #if defined (CLIB_HAVE_VEC256)
244 u8x32 s0, s1, d0, d1;
245 u8x32 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
246 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
248 u8x32 lv = u8x32_splat (len);
249 u8x32 add = u8x32_splat (32);
251 s0 = u8x32_load_unaligned (src);
252 s1 = u8x32_load_unaligned (src + 32);
253 d0 = u8x32_load_unaligned (dst);
254 d1 = u8x32_load_unaligned (dst + 32);
256 d0 = u8x32_blend (d0, s0, lv > mask);
257 u8x32_store_unaligned (d0, dst);
263 d1 = u8x32_blend (d1, s1, lv > mask);
264 u8x32_store_unaligned (d1, dst + 32);
266 #elif defined (CLIB_HAVE_VEC128)
267 u8x16 s0, s1, s2, s3, d0, d1, d2, d3;
268 u8x16 mask = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
269 u8x16 lv = u8x16_splat (len);
270 u8x16 add = u8x16_splat (16);
272 s0 = u8x16_load_unaligned (src);
273 s1 = u8x16_load_unaligned (src + 16);
274 s2 = u8x16_load_unaligned (src + 32);
275 s3 = u8x16_load_unaligned (src + 48);
276 d0 = u8x16_load_unaligned (dst);
277 d1 = u8x16_load_unaligned (dst + 16);
278 d2 = u8x16_load_unaligned (dst + 32);
279 d3 = u8x16_load_unaligned (dst + 48);
281 d0 = u8x16_blend (d0, s0, lv > mask);
282 u8x16_store_unaligned (d0, dst);
288 d1 = u8x16_blend (d1, s1, lv > mask);
289 u8x16_store_unaligned (d1, dst + 16);
295 d2 = u8x16_blend (d2, s2, lv > mask);
296 u8x16_store_unaligned (d2, dst + 32);
299 d3 = u8x16_blend (d3, s3, lv > mask);
300 u8x16_store_unaligned (d3, dst + 48);
302 memmove (dst, src, len);
306 static_always_inline void
307 clib_memcpy_le64 (u8 * dst, u8 * src, u8 len)
309 clib_memcpy_le (dst, src, len, 64);
312 static_always_inline void
313 clib_memcpy_le32 (u8 * dst, u8 * src, u8 len)
315 clib_memcpy_le (dst, src, len, 32);
318 static_always_inline void
319 clib_memset_u64 (void *p, u64 val, uword count)
322 #if defined(CLIB_HAVE_VEC512)
323 u64x8 v512 = u64x8_splat (val);
326 u64x8_store_unaligned (v512, ptr);
333 #if defined(CLIB_HAVE_VEC256)
334 u64x4 v256 = u64x4_splat (val);
337 u64x4_store_unaligned (v256, ptr);
344 #if defined(CLIB_HAVE_VEC128)
345 u64x2 v = u64x2_splat (val);
349 #if defined(CLIB_HAVE_VEC128)
350 u64x2_store_unaligned (v, ptr);
351 u64x2_store_unaligned (v, ptr + 2);
353 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
363 static_always_inline void
364 clib_memset_u32 (void *p, u32 val, uword count)
367 #if defined(CLIB_HAVE_VEC512)
368 u32x16 v512 = u32x16_splat (val);
371 u32x16_store_unaligned (v512, ptr);
378 #if defined(CLIB_HAVE_VEC256)
379 u32x8 v256 = u32x8_splat (val);
382 u32x8_store_unaligned (v256, ptr);
389 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
390 u32x4 v128 = u32x4_splat (val);
393 u32x4_store_unaligned (v128, ptr);
400 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
409 static_always_inline void
410 clib_memset_u16 (void *p, u16 val, uword count)
413 #if defined(CLIB_HAVE_VEC512)
414 u16x32 v512 = u16x32_splat (val);
417 u16x32_store_unaligned (v512, ptr);
424 #if defined(CLIB_HAVE_VEC256)
425 u16x16 v256 = u16x16_splat (val);
428 u16x16_store_unaligned (v256, ptr);
435 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
436 u16x8 v128 = u16x8_splat (val);
439 u16x8_store_unaligned (v128, ptr);
446 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
455 static_always_inline void
456 clib_memset_u8 (void *p, u8 val, uword count)
459 #if defined(CLIB_HAVE_VEC512)
460 u8x64 v512 = u8x64_splat (val);
463 u8x64_store_unaligned (v512, ptr);
470 #if defined(CLIB_HAVE_VEC256)
471 u8x32 v256 = u8x32_splat (val);
474 u8x32_store_unaligned (v256, ptr);
481 #if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
482 u8x16 v128 = u8x16_splat (val);
485 u8x16_store_unaligned (v128, ptr);
492 ptr[0] = ptr[1] = ptr[2] = ptr[3] = val;
503 * This macro is to provide smooth mapping from memcmp to memcmp_s.
504 * memcmp has fewer parameters and fewer returns than memcmp_s.
505 * This macro is somewhat a crutch. When err != EOK is returned from memcmp_s,
506 * we return 0 and spit out a message in the console because there is
507 * no way to return the error code to the memcmp callers.
508 * This condition happens when s1 or s2 is null. Please note
509 * in the extant memcmp calls, if s1, s2, or both are null, memcmp returns 0
510 * anyway. So we are consistent in this case for the comparison return
511 * although we also spit out a C11 violation message in the console to
512 * warn that they pass null pointers for both s1 and s2.
513 * Applications are encouraged to use the cool C11 memcmp_s API to get the
514 * maximum benefit out of it.
516 #define clib_memcmp(s1,s2,m1) \
518 memcmp_s_inline (s1, m1, s2, m1, &__diff); \
522 errno_t memcmp_s (const void *s1, rsize_t s1max, const void *s2,
523 rsize_t s2max, int *diff);
525 always_inline errno_t
526 memcmp_s_inline (const void *s1, rsize_t s1max, const void *s2, rsize_t s2max,
531 bad = (s1 == 0) + (s2 == 0) + (diff == 0) + (s2max > s1max) + (s2max == 0) +
534 if (PREDICT_FALSE (bad != 0))
537 clib_c11_violation ("s1 NULL");
539 clib_c11_violation ("s2 NULL");
541 clib_c11_violation ("diff NULL");
543 clib_c11_violation ("s2max > s1max");
545 clib_c11_violation ("s2max 0");
547 clib_c11_violation ("s1max 0");
551 if (PREDICT_FALSE (s1 == s2))
557 *diff = memcmp (s1, s2, s2max);
562 * This macro is to provide smooth mapping from strnlen to strnlen_s
564 #define clib_strnlen(s,m) strnlen_s_inline(s,m)
566 size_t strnlen_s (const char *s, size_t maxsize);
569 strnlen_s_inline (const char *s, size_t maxsize)
573 bad = (s == 0) + (maxsize == 0);
574 if (PREDICT_FALSE (bad != 0))
577 clib_c11_violation ("s NULL");
579 clib_c11_violation ("maxsize 0");
582 return strnlen (s, maxsize);
586 * This macro is to provide smooth mapping from strcmp to strcmp_s.
587 * strcmp has fewer parameters and fewer returns than strcmp_s.
588 * This macro is somewhat a crutch. When err != EOK is returned from strcmp_s,
589 * we return 0 and spit out a message in the console because
590 * there is no way to return the error to the strcmp callers.
591 * This condition happens when s1 or s2 is null. Please note in the extant
592 * strcmp call, they would end up crashing if one of them is null.
593 * So the new behavior is no crash, but an error is displayed in the
594 * console which I think is more user friendly. If both s1 and s2 are null,
595 * strcmp returns 0. Obviously, strcmp did the pointers comparison prior
596 * to actually accessing the pointer contents. We are still consistent
597 * in this case for the comparison return although we also spit out a
598 * C11 violation message in the console to warn that they pass null pointers
599 * for both s1 and s2. The other problem is strcmp does not provide s1max,
600 * we use CLIB_STRING_MACRO_MAX and hopefully, s1 is null terminated.
601 * If not, we may be accessing memory beyonf what is intended.
602 * Applications are encouraged to use the cool C11 strcmp_s API to get the
603 * maximum benefit out of it.
605 #define clib_strcmp(s1,s2) \
606 ({ int __indicator = 0; \
607 strcmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, &__indicator); \
611 errno_t strcmp_s (const char *s1, rsize_t s1max, const char *s2,
614 always_inline errno_t
615 strcmp_s_inline (const char *s1, rsize_t s1max, const char *s2,
620 bad = (indicator == 0) + (s1 == 0) + (s2 == 0) + (s1max == 0) +
621 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0');
623 if (PREDICT_FALSE (bad != 0))
625 if (indicator == NULL)
626 clib_c11_violation ("indicator NULL");
628 clib_c11_violation ("s1 NULL");
630 clib_c11_violation ("s2 NULL");
632 clib_c11_violation ("s1max 0");
633 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
634 clib_c11_violation ("s1 unterminated");
638 *indicator = strcmp (s1, s2);
643 * This macro is to provide smooth mapping from strncmp to strncmp_s.
644 * strncmp has fewer parameters and fewer returns than strncmp_s. That said,
645 * this macro is somewhat a crutch. When we get err != EOK from strncmp_s,
646 * we return 0 and spit out a message in the console because there is no
647 * means to return the error to the strncmp caller.
648 * This condition happens when s1 or s2 is null. In the extant strncmp call,
649 * they would end up crashing if one of them is null. So the new behavior is
650 * no crash, but error is displayed in the console which is more
651 * user friendly. If s1 and s2 are null, strncmp returns 0. Obviously,
652 * strncmp did the pointers comparison prior to actually accessing the
653 * pointer contents. We are still consistent in this case for the comparison
654 * return although we also spit out a C11 violation message in the console to
655 * warn that they pass null pointers for both s1 and s2.
656 * Applications are encouraged to use the cool C11 strncmp_s API to get the
657 * maximum benefit out of it.
659 #define clib_strncmp(s1,s2,n) \
660 ({ int __indicator = 0; \
661 strncmp_s_inline (s1, CLIB_STRING_MACRO_MAX, s2, n, &__indicator); \
665 errno_t strncmp_s (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
668 always_inline errno_t
669 strncmp_s_inline (const char *s1, rsize_t s1max, const char *s2, rsize_t n,
673 u8 s1_greater_s1max = (s1 && s1max && n > clib_strnlen (s1, s1max));
675 if (PREDICT_FALSE (s1_greater_s1max && indicator))
678 * strcmp allows n > s1max. If indicator is non null, we can still
679 * do the compare without any harm and return EINVAL as well as the
680 * result in indicator.
682 clib_c11_violation ("n exceeds s1 length");
683 *indicator = strncmp (s1, s2, n);
687 bad = (s1 == 0) + (s2 == 0) + (indicator == 0) + (s1max == 0) +
688 (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0') + s1_greater_s1max;
690 if (PREDICT_FALSE (bad != 0))
692 if (indicator == NULL)
693 clib_c11_violation ("indicator NULL");
695 clib_c11_violation ("s1 NULL");
697 clib_c11_violation ("s2 NULL");
699 clib_c11_violation ("s1max 0");
700 if (s1 && s1max && s1[clib_strnlen (s1, s1max)] != '\0')
701 clib_c11_violation ("s1 unterminated");
702 if (s1_greater_s1max)
703 clib_c11_violation ("n exceeds s1 length");
707 *indicator = strncmp (s1, s2, n);
711 errno_t strcpy_s (char *__restrict__ dest, rsize_t dmax,
712 const char *__restrict__ src);
714 always_inline errno_t
715 strcpy_s_inline (char *__restrict__ dest, rsize_t dmax,
716 const char *__restrict__ src)
722 bad = (dest == 0) + (dmax == 0) + (src == 0);
723 if (PREDICT_FALSE (bad != 0))
726 clib_c11_violation ("dest NULL");
728 clib_c11_violation ("src NULL");
730 clib_c11_violation ("dmax 0");
734 n = clib_strnlen (src, dmax);
735 if (PREDICT_FALSE (n >= dmax))
737 clib_c11_violation ("not enough space for dest");
740 /* Not actually trying to copy anything is OK */
741 if (PREDICT_FALSE (n == 0))
744 /* Check for src/dst overlap, which is not allowed */
745 low = (uword) (src < dest ? src : dest);
746 hi = (uword) (src < dest ? dest : src);
748 if (PREDICT_FALSE (low + (n - 1) >= hi))
750 clib_c11_violation ("src/dest overlap");
754 clib_memcpy_fast (dest, src, n);
760 * This macro is provided for smooth migration from strncpy. It is not perfect
761 * because we don't know the size of the destination buffer to pass to
762 * strncpy_s. We improvise dmax with CLIB_STRING_MACRO_MAX.
763 * Applications are encouraged to move to the C11 strncpy_s API and provide
764 * the correct dmax for better error checking.
766 #define clib_strncpy(d,s,n) strncpy_s_inline(d,CLIB_STRING_MACRO_MAX,s,n)
769 strncpy_s (char *__restrict__ dest, rsize_t dmax,
770 const char *__restrict__ src, rsize_t n);
772 always_inline errno_t
773 strncpy_s_inline (char *__restrict__ dest, rsize_t dmax,
774 const char *__restrict__ src, rsize_t n)
779 errno_t status = EOK;
781 bad = (dest == 0) + (dmax == 0) + (src == 0) + (n == 0);
782 if (PREDICT_FALSE (bad != 0))
784 /* Not actually trying to copy anything is OK */
788 clib_c11_violation ("dest NULL");
790 clib_c11_violation ("src NULL");
792 clib_c11_violation ("dmax 0");
796 if (PREDICT_FALSE (n >= dmax))
798 /* Relax and use strnlen of src */
799 clib_c11_violation ("n >= dmax");
800 m = clib_strnlen (src, dmax);
803 /* Truncate, adjust copy length to fit dest */
809 /* cap the copy to strlen(src) in case n > strlen(src) */
810 m = clib_strnlen (src, n);
812 /* Check for src/dst overlap, which is not allowed */
813 low = (uword) (src < dest ? src : dest);
814 hi = (uword) (src < dest ? dest : src);
817 * This check may fail innocently if src + dmax >= dst, but
818 * src + strlen(src) < dst. If it fails, check more carefully before
819 * blowing the whistle.
821 if (PREDICT_FALSE (low + (m - 1) >= hi))
823 m = clib_strnlen (src, m);
825 if (low + (m - 1) >= hi)
827 clib_c11_violation ("src/dest overlap");
832 clib_memcpy_fast (dest, src, m);
837 errno_t strcat_s (char *__restrict__ dest, rsize_t dmax,
838 const char *__restrict__ src);
840 always_inline errno_t
841 strcat_s_inline (char *__restrict__ dest, rsize_t dmax,
842 const char *__restrict__ src)
846 size_t m, n, dest_size;
848 bad = (dest == 0) + (dmax == 0) + (src == 0);
849 if (PREDICT_FALSE (bad != 0))
852 clib_c11_violation ("dest NULL");
854 clib_c11_violation ("src NULL");
856 clib_c11_violation ("dmax 0");
860 dest_size = clib_strnlen (dest, dmax);
861 m = dmax - dest_size;
862 n = clib_strnlen (src, m);
863 if (PREDICT_FALSE (n >= m))
865 clib_c11_violation ("not enough space for dest");
869 /* Not actually trying to concatenate anything is OK */
870 if (PREDICT_FALSE (n == 0))
873 /* Check for src/dst overlap, which is not allowed */
874 low = (uword) (src < dest ? src : dest);
875 hi = (uword) (src < dest ? dest : src);
877 if (PREDICT_FALSE (low + (n - 1) >= hi))
879 clib_c11_violation ("src/dest overlap");
883 clib_memcpy_fast (dest + dest_size, src, n);
884 dest[dest_size + n] = '\0';
888 errno_t strncat_s (char *__restrict__ dest, rsize_t dmax,
889 const char *__restrict__ src, rsize_t n);
891 always_inline errno_t
892 strncat_s_inline (char *__restrict__ dest, rsize_t dmax,
893 const char *__restrict__ src, rsize_t n)
897 size_t m, dest_size, allowed_size;
898 errno_t status = EOK;
900 bad = (dest == 0) + (src == 0) + (dmax == 0) + (n == 0);
901 if (PREDICT_FALSE (bad != 0))
903 /* Not actually trying to concatenate anything is OK */
907 clib_c11_violation ("dest NULL");
909 clib_c11_violation ("src NULL");
911 clib_c11_violation ("dmax 0");
915 /* Check for src/dst overlap, which is not allowed */
916 low = (uword) (src < dest ? src : dest);
917 hi = (uword) (src < dest ? dest : src);
919 if (PREDICT_FALSE (low + (n - 1) >= hi))
921 clib_c11_violation ("src/dest overlap");
925 dest_size = clib_strnlen (dest, dmax);
926 allowed_size = dmax - dest_size;
928 if (PREDICT_FALSE (allowed_size == 0))
930 clib_c11_violation ("no space left in dest");
934 if (PREDICT_FALSE (n >= allowed_size))
937 * unlike strcat_s, strncat_s will do the concatenation anyway when
938 * there is not enough space in dest. But it will do the truncation and
939 * null terminate dest
941 m = clib_strnlen (src, allowed_size);
942 if (m >= allowed_size)
944 m = allowed_size - 1;
949 m = clib_strnlen (src, n);
951 clib_memcpy_fast (dest + dest_size, src, m);
952 dest[dest_size + m] = '\0';
957 * This macro is to provide smooth mapping from strtok_r to strtok_s.
958 * To map strtok to this macro, the caller would have to supply an additional
959 * argument. strtokr_s requires s1max which the unsafe API does not have. So
960 * we have to improvise it with CLIB_STRING_MACRO_MAX. Unlike strtok_s,
961 * this macro cannot catch unterminated s1 and s2.
962 * Applications are encouraged to use the cool C11 strtok_s API to avoid
965 #define clib_strtok(s1,s2,p) \
966 ({ rsize_t __s1max = CLIB_STRING_MACRO_MAX; \
967 strtok_s_inline (s1, &__s1max, s2, p); \
970 char *strtok_s (char *__restrict__ s1, rsize_t * __restrict__ s1max,
971 const char *__restrict__ s2, char **__restrict__ ptr);
974 strtok_s_inline (char *__restrict__ s1, rsize_t * __restrict__ s1max,
975 const char *__restrict__ s2, char **__restrict__ ptr)
977 #define STRTOK_DELIM_MAX_LEN 16
983 bad = (s1max == 0) + (s2 == 0) + (ptr == 0) +
984 ((s1 == 0) && ptr && (*ptr == 0));
985 if (PREDICT_FALSE (bad != 0))
988 clib_c11_violation ("s2 NULL");
990 clib_c11_violation ("s1max is NULL");
992 clib_c11_violation ("ptr is NULL");
993 /* s1 == 0 and *ptr == null is no good */
994 if ((s1 == 0) && ptr && (*ptr == 0))
995 clib_c11_violation ("s1 and ptr contents are NULL");
1003 * scan s1 for a delimiter
1007 while (*s1 != '\0' && !ptoken)
1009 if (PREDICT_FALSE (dlen == 0))
1012 clib_c11_violation ("s1 unterminated");
1017 * must scan the entire delimiter list
1018 * ISO should have included a delimiter string limit!!
1020 slen = STRTOK_DELIM_MAX_LEN;
1024 if (PREDICT_FALSE (slen == 0))
1027 clib_c11_violation ("s2 unterminated");
1047 * if the beginning of a token was not found, then no
1048 * need to continue the scan.
1057 * Now we need to locate the end of the token
1064 clib_c11_violation ("s1 unterminated");
1068 slen = STRTOK_DELIM_MAX_LEN;
1075 clib_c11_violation ("s2 unterminated");
1082 * found a delimiter, set to null
1083 * and return context ptr to next char
1086 *ptr = (s1 + 1); /* return pointer for next scan */
1087 *s1max = dlen - 1; /* account for the nulled delimiter */
1093 * simply scanning through the delimiter string
1107 errno_t strstr_s (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1110 always_inline errno_t
1111 strstr_s_inline (char *s1, rsize_t s1max, const char *s2, rsize_t s2max,
1115 size_t s1_size, s2_size;
1118 (s1 == 0) + (s2 == 0) + (substring == 0) + (s1max == 0) + (s2max == 0) +
1119 (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0')) +
1120 (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'));
1121 if (PREDICT_FALSE (bad != 0))
1124 clib_c11_violation ("s1 NULL");
1126 clib_c11_violation ("s2 NULL");
1128 clib_c11_violation ("s1max 0");
1130 clib_c11_violation ("s2max 0");
1132 clib_c11_violation ("substring NULL");
1133 if (s1 && s1max && (s1[clib_strnlen (s1, s1max)] != '\0'))
1134 clib_c11_violation ("s1 unterminated");
1135 if (s2 && s2max && (s2[clib_strnlen (s2, s2max)] != '\0'))
1136 clib_c11_violation ("s2 unterminated");
1141 * s2 points to a string with zero length, or s2 equals s1, return s1
1143 if (PREDICT_FALSE (*s2 == '\0' || s1 == s2))
1150 * s2_size > s1_size, it won't find match.
1152 s1_size = clib_strnlen (s1, s1max);
1153 s2_size = clib_strnlen (s2, s2max);
1154 if (PREDICT_FALSE (s2_size > s1_size))
1157 *substring = strstr (s1, s2);
1158 if (*substring == 0)
1164 static_always_inline const char *
1165 clib_string_skip_prefix (const char *s, const char *prefix)
1167 uword len = __builtin_strlen (prefix);
1168 return s + (__builtin_strncmp (s, prefix, len) ? 0 : len);
1171 #endif /* included_clib_string_h */
1174 * fd.io coding-style-patch-verification: ON
1177 * eval: (c-set-style "gnu")