Revert gerrit 16429 to fix a Debian build-break
[vpp.git] / src / plugins / unittest / string_test.c
1 /*
2  * Copyright (c) 2018 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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 #include <vlib/vlib.h>
16 #include <vppinfra/string.h>
17
18 static int
19 test_memset_s (vlib_main_t * vm, unformat_input_t * input)
20 {
21   u8 dst[64];
22   int i;
23   errno_t err;
24
25   vlib_cli_output (vm, "Test memset_s...");
26
27   err = memset_s (dst, ARRAY_LEN (dst), 0xfe, ARRAY_LEN (dst));
28
29   if (err != EOK)
30     return -1;
31
32   for (i = 0; i < ARRAY_LEN (dst); i++)
33     if (dst[i] != 0xFE)
34       return -1;
35
36   err = memset_s (dst, ARRAY_LEN (dst), 0xfa, ARRAY_LEN (dst) + 1);
37
38   if (err == EOK)
39     return -1;
40
41   return 0;
42 }
43
44 static int
45 test_clib_memset (vlib_main_t * vm, unformat_input_t * input)
46 {
47   u8 dst[64];
48   int i;
49   errno_t err;
50
51   vlib_cli_output (vm, "Test clib_memset...");
52
53   err = clib_memset (dst, 0xfe, ARRAY_LEN (dst));
54
55   if (err != EOK)
56     return -1;
57
58   for (i = 0; i < ARRAY_LEN (dst); i++)
59     if (dst[i] != 0xFE)
60       return -1;
61
62   return 0;
63 }
64
65 static int
66 test_memcpy_s (vlib_main_t * vm, unformat_input_t * input)
67 {
68   char src[64], dst[64];
69   int i;
70   errno_t err;
71
72   vlib_cli_output (vm, "Test memcpy_s...");
73
74   for (i = 0; i < ARRAY_LEN (src); i++)
75     src[i] = i + 1;
76
77   /* Typical case */
78   err = memcpy_s (dst, sizeof (dst), src, sizeof (src));
79
80   if (err != EOK)
81     return -1;
82
83   /* This better not fail but check anyhow */
84   for (i = 0; i < ARRAY_LEN (dst); i++)
85     if (src[i] != dst[i])
86       return -1;
87
88   /* Size fail */
89   err = memcpy_s (dst + 1, sizeof (dst) - 1, src, sizeof (src));
90
91   if (err == EOK)
92     return -1;
93
94   /* overlap fail */
95   err = memcpy_s (dst, sizeof (dst), dst + 1, sizeof (dst) - 1);
96
97   if (err == EOK)
98     return -1;
99
100   /* Zero length copy */
101   err = memcpy_s (0, sizeof (dst), src, 0);
102
103   if (err != EOK)
104     return -1;
105
106   /* OK, seems to work */
107   return 0;
108 }
109
110 static int
111 test_clib_memcpy (vlib_main_t * vm, unformat_input_t * input)
112 {
113   char src[64], dst[64];
114   int i;
115   errno_t err;
116
117   vlib_cli_output (vm, "Test clib_memcpy...");
118
119   for (i = 0; i < ARRAY_LEN (src); i++)
120     src[i] = i + 1;
121
122   /* Typical case */
123   err = clib_memcpy (dst, src, sizeof (src));
124
125   if (err != EOK)
126     return -1;
127
128   /* This better not fail but check anyhow */
129   for (i = 0; i < ARRAY_LEN (dst); i++)
130     if (src[i] != dst[i])
131       return -1;
132   /* verify it against memcpy */
133   memcpy (dst, src, sizeof (src));
134
135   /* This better not fail but check anyhow */
136   for (i = 0; i < ARRAY_LEN (dst); i++)
137     if (src[i] != dst[i])
138       return -1;
139
140   /* Zero length copy */
141   err = clib_memcpy (0, src, 0);
142
143   if (err != EOK)
144     return -1;
145
146   /* OK, seems to work */
147   return 0;
148 }
149
150 static int
151 test_memcmp_s (vlib_main_t * vm, unformat_input_t * input)
152 {
153   char src[64], dst[64];
154   errno_t err;
155   int diff = 0;
156
157   vlib_cli_output (vm, "Test memcmp_s...");
158
159   /* Fill array with different values */
160   err = clib_memset (src, 0x1, ARRAY_LEN (src));
161   if (err != EOK)
162     return -1;
163   err = clib_memset (dst, 0x3, ARRAY_LEN (dst));
164   if (err != EOK)
165     return -1;
166
167   /* s1 > s2, > 0 is expected in diff */
168   err = memcmp_s (dst, ARRAY_LEN (dst), src, ARRAY_LEN (src), &diff);
169   if (err != EOK)
170     return -1;
171   if (!(diff > 0))
172     return -1;
173
174   /* s1 < s2, < 0 is expected in diff */
175   err = memcmp_s (src, ARRAY_LEN (src), dst, ARRAY_LEN (dst), &diff);
176   if (err != EOK)
177     return -1;
178   if (!(diff < 0))
179     return -1;
180
181   err = clib_memset (dst, 0x1, ARRAY_LEN (dst));
182   if (err != EOK)
183     return -1;
184
185   /* s1 == s2, 0 is expected in diff */
186   err = memcmp_s (src, ARRAY_LEN (src), dst, ARRAY_LEN (dst), &diff);
187   if (err != EOK)
188     return -1;
189   if (diff != 0)
190     return -1;
191
192   /* Try negative tests */
193   err = memcmp_s (0, 0, 0, 0, 0);
194   if (err != EINVAL)
195     return -1;
196
197   /* Try s2max > s1max */
198   err = memcmp_s (src, ARRAY_LEN (src) - 1, dst, ARRAY_LEN (dst), &diff);
199   if (err != EINVAL)
200     return -1;
201
202   /* OK, seems to work */
203   return 0;
204 }
205
206 static int
207 test_clib_memcmp (vlib_main_t * vm, unformat_input_t * input)
208 {
209   char src[64], dst[64];
210   errno_t err;
211   char *s;
212
213   vlib_cli_output (vm, "Test clib_memcmp...");
214
215   /* Fill array with different values */
216   err = clib_memset (src, 0x1, ARRAY_LEN (src));
217   if (err != EOK)
218     return -1;
219   err = clib_memset (dst, 0x3, ARRAY_LEN (dst));
220   if (err != EOK)
221     return -1;
222
223   /* s1 > s2, > 0 is expected in diff */
224   if (!(clib_memcmp (dst, src, ARRAY_LEN (src)) > 0))
225     return -1;
226   /* verify it against memcmp */
227   if (!(memcmp (dst, src, ARRAY_LEN (src)) > 0))
228     return -1;
229
230   /* s1 < s2, < 0 is expected in diff */
231   if (!(clib_memcmp (src, dst, ARRAY_LEN (dst)) < 0))
232     return -1;
233   /* verify it against memcmp */
234   if (!(memcmp (src, dst, ARRAY_LEN (dst)) < 0))
235     return -1;
236
237   err = clib_memset (dst, 0x1, ARRAY_LEN (dst));
238   if (err != EOK)
239     return -1;
240
241   /* s1 == s2, 0 is expected in diff */
242   if (clib_memcmp (src, dst, ARRAY_LEN (dst)) != 0)
243     return -1;
244   /* verify it against memcmp */
245   if (memcmp (src, dst, ARRAY_LEN (dst)) != 0)
246     return -1;
247
248   /* Try negative tests */
249   s = 0;
250   if (clib_memcmp (s, s, 0) != 0)
251     return -1;
252   /* verify it against memcmp */
253   if (memcmp (s, s, 0) != 0)
254     return -1;
255
256   /* OK, seems to work */
257   return 0;
258 }
259
260 static int
261 test_strcmp_s (vlib_main_t * vm, unformat_input_t * input)
262 {
263   char s1[] = "Simplicity is the ultimate sophistication";
264   uword s1len = sizeof (s1) - 1;        // excluding null
265   errno_t err;
266   int indicator = 0;
267
268   vlib_cli_output (vm, "Test strcmp_s...");
269
270   /* s1 == s2, 0 is expected */
271   err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication",
272                   &indicator);
273   if (err != EOK)
274     return -1;
275   if (indicator != 0)
276     return -1;
277
278   /* s1 > s2, > 0 is expected */
279   err = strcmp_s (s1, s1len, "Simplicity is the ultimate", &indicator);
280   if (err != EOK)
281     return -1;
282   if (!(indicator > 0))
283     return -1;
284
285   /* s1 < s2, < 0 is expected */
286   err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication!",
287                   &indicator);
288   if (err != EOK)
289     return -1;
290   if (!(indicator < 0))
291     return -1;
292
293   /* Try some negative tests */
294
295   /* Null pointers test */
296   err = strcmp_s (0, 0, 0, 0);
297   if (err != EINVAL)
298     return -1;
299
300   /* non-null terminated s1 */
301   s1[s1len] = 0x1;
302   err = strcmp_s (s1, s1len, "Simplicity is the ultimate sophistication",
303                   &indicator);
304   if (err != EINVAL)
305     return -1;
306
307   /* OK, seems to work */
308   return 0;
309 }
310
311 static int
312 test_clib_strcmp (vlib_main_t * vm, unformat_input_t * input)
313 {
314   char s1[] = "Simplicity is the ultimate sophistication";
315   int indicator;
316   char *s;
317
318   vlib_cli_output (vm, "Test clib_strcmp...");
319
320   /* s1 == s2, 0 is expected */
321   indicator = clib_strcmp (s1, "Simplicity is the ultimate sophistication");
322   if (indicator != 0)
323     return -1;
324   /* verify it against strcmp */
325   indicator = strcmp (s1, "Simplicity is the ultimate sophistication");
326   if (indicator != 0)
327     return -1;
328
329   /* s1 > s2, > 0 is expected */
330   indicator = clib_strcmp (s1, "Simplicity is the ultimate");
331   if (!(indicator > 0))
332     return -1;
333   /* verify it against strcmp */
334   indicator = strcmp (s1, "Simplicity is the ultimate");
335   if (!(indicator > 0))
336     return -1;
337
338   /* s1 < s2, < 0 is expected */
339   indicator = clib_strcmp (s1, "Simplicity is the ultimate sophistication!");
340   if (!(indicator < 0))
341     return -1;
342   /* verify it against strcmp */
343   indicator = strcmp (s1, "Simplicity is the ultimate sophistication!");
344   if (!(indicator < 0))
345     return -1;
346
347   /* Try some negative tests */
348
349   /* Null pointers comparison */
350   s = 0;
351   indicator = clib_strcmp (s, s);
352   if (indicator != 0)
353     return -1;
354   /* verify it against strcmp */
355   indicator = strcmp (s, s);
356   if (indicator != 0)
357     return -1;
358
359   /* OK, seems to work */
360   return 0;
361 }
362
363 static int
364 test_strncmp_s (vlib_main_t * vm, unformat_input_t * input)
365 {
366   char s1[] = "Every moment is a fresh beginning";
367   uword s1len = sizeof (s1) - 1;        // excluding null
368   errno_t err;
369   int indicator = 0;
370
371   vlib_cli_output (vm, "Test strncmp_s...");
372
373   /* s1 == s2, 0 is expected */
374   err = strncmp_s (s1, s1len, "Every moment is a fresh beginning", s1len,
375                    &indicator);
376   if (err != EOK)
377     return -1;
378   if (indicator != 0)
379     return -1;
380
381   /* s1 > s2, 0 is expected since comparison is no more than n character */
382   err = strncmp_s (s1, s1len, "Every moment is a fresh begin",
383                    sizeof ("Every moment is a fresh begin") - 1, &indicator);
384   if (err != EOK)
385     return -1;
386   if (indicator != 0)
387     return -1;
388
389   /* s1 < s2, < 0 is expected */
390   err = strncmp_s (s1, s1len, "Every moment is fresh beginning",
391                    sizeof ("Every moment is fresh beginning") - 1,
392                    &indicator);
393   if (err != EOK)
394     return -1;
395   if (!(indicator < 0))
396     return -1;
397
398   /* s1 > s2, > 0 is expected */
399   err = strncmp_s ("Every moment is fresh beginning. ",
400                    sizeof ("Every moment is fresh beginning. ") - 1, s1,
401                    s1len, &indicator);
402   if (err != EOK)
403     return -1;
404   if (!(indicator > 0))
405     return -1;
406
407   /* Try some negative tests */
408
409   /* Null pointers */
410   err = strncmp_s (0, 0, 0, 0, 0);
411   if (err != EINVAL)
412     return -1;
413
414   /* n > s1max */
415   err = strncmp_s (s1, s1len, "Every moment is a fresh beginning", s1len + 1,
416                    &indicator);
417   if (err != EINVAL)
418     return -1;
419
420   /* unterminated s1 */
421   s1[s1len] = 0x1;
422   err = strncmp_s (s1, s1len, "Every moment is a fresh beginning",
423                    sizeof ("Every moment is a fresh beginning") - 1,
424                    &indicator);
425   if (err != EINVAL)
426     return -1;
427
428   /* OK, seems to work */
429   return 0;
430 }
431
432 static int
433 test_clib_strncmp (vlib_main_t * vm, unformat_input_t * input)
434 {
435   char s1[] = "Every moment is a fresh beginning";
436   uword s1len = sizeof (s1) - 1;        // excluding null
437   int indicator, v_indicator;
438
439   vlib_cli_output (vm, "Test clib_strncmp...");
440
441   /* s1 == s2, 0 is expected */
442   indicator = clib_strncmp (s1, "Every moment is a fresh beginning", s1len);
443   if (indicator != 0)
444     return -1;
445   /* verify it against strncmp */
446   v_indicator = strncmp (s1, "Every moment is a fresh beginning", s1len);
447   if (v_indicator != 0)
448     return -1;
449   if (v_indicator != indicator)
450     return -1;
451
452   /* s1 > s2, 0 is expected since comparison is no more than n character */
453   indicator = clib_strncmp (s1, "Every moment is a fresh begin",
454                             sizeof ("Every moment is a fresh begin") - 1);
455   if (indicator != 0)
456     return -1;
457   /* verify it against strncmp */
458   v_indicator = strncmp (s1, "Every moment is a fresh begin",
459                          sizeof ("Every moment is a fresh begin") - 1);
460   if (v_indicator != 0)
461     return -1;
462   if (v_indicator != indicator)
463     return -1;
464
465   /* s1 < s2, < 0 is expected */
466   indicator = clib_strncmp (s1, "Every moment is fresh beginning",
467                             sizeof ("Every moment is fresh beginning") - 1);
468   if (!(indicator < 0))
469     return -1;
470   /* verify it against strncmp */
471   v_indicator = strncmp (s1, "Every moment is fresh beginning",
472                          sizeof ("Every moment is fresh beginning") - 1);
473   if (!(v_indicator < 0))
474     return -1;
475   if (v_indicator != indicator)
476     return -1;
477
478   /* s1 > s2, > 0 is expected */
479   indicator = clib_strncmp ("Every moment is fresh beginning. ", s1, s1len);
480   if (!(indicator > 0))
481     return -1;
482   /* verify it against strncmp */
483   v_indicator = strncmp ("Every moment is fresh beginning. ", s1, s1len);
484   if (!(v_indicator > 0))
485     return -1;
486   if (v_indicator != indicator)
487     return -1;
488
489   /* Try some negative tests */
490
491   /* Null pointers */
492
493   /* make sure we don't crash */
494   indicator = clib_strncmp (0, 0, 0);
495   if (indicator != EOK)
496     return -1;
497
498   /* n > s1 len */
499   indicator =
500     clib_strncmp (s1, "Every moment is a fresh beginning", s1len + 1);
501   if (indicator != 0)
502     return -1;
503   /* verify it against strncmp */
504   v_indicator = strncmp (s1, "Every moment is a fresh beginning", s1len + 1);
505   if (v_indicator != 0)
506     return -1;
507   if (v_indicator != indicator)
508     return -1;
509
510   /* unterminated s1 */
511   s1[s1len] = 0x1;
512   indicator = clib_strncmp (s1, "Every moment is a fresh beginning",
513                             sizeof ("every moment is a fresh beginning") - 1);
514   if (indicator != 0)
515     return -1;
516   /* verify it against strncmp */
517   v_indicator = strncmp (s1, "Every moment is a fresh beginning",
518                          sizeof ("Every moment is a fresh beginning") - 1);
519   if (v_indicator != 0)
520     return -1;
521   if (v_indicator != indicator)
522     return -1;
523
524   /* OK, seems to work */
525   return 0;
526 }
527
528 static int
529 test_strcpy_s (vlib_main_t * vm, unformat_input_t * input)
530 {
531   char src[] = "To err is human.";
532   char dst[64];
533   int indicator;
534   size_t s1size = sizeof (dst); // including null
535   errno_t err;
536
537   vlib_cli_output (vm, "Test strcpy_s...");
538
539   err = strcpy_s (dst, s1size, src);
540   if (err != EOK)
541     return -1;
542
543   /* This better not fail but check anyhow */
544   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
545       EOK)
546     return -1;
547   if (indicator != 0)
548     return -1;
549
550   /* Negative tests */
551
552   err = strcpy_s (0, 0, 0);
553   if (err == EOK)
554     return -1;
555
556   /* Size fail */
557   err = strcpy_s (dst, 10, src);
558   if (err == EOK)
559     return -1;
560
561   /* overlap fail */
562 #if __GNUC__ < 8
563   /* GCC 8 flunks this one at compile time... */
564   err = strcpy_s (dst, s1size, dst);
565   if (err == EOK)
566     return -1;
567 #endif
568
569   /* overlap fail */
570   err = strcpy_s (dst, s1size, dst + 1);
571   if (err == EOK)
572     return -1;
573
574   /* OK, seems to work */
575   return 0;
576 }
577
578 static int
579 test_clib_strcpy (vlib_main_t * vm, unformat_input_t * input)
580 {
581   char src[] = "The journey of a one thousand miles begins with one step.";
582   char dst[100];
583   int indicator;
584   errno_t err;
585
586   vlib_cli_output (vm, "Test clib_strcpy...");
587
588   err = clib_strcpy (dst, src);
589   if (err != EOK)
590     return -1;
591
592   /* This better not fail but check anyhow */
593   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
594       EOK)
595     return -1;
596   if (indicator != 0)
597     return -1;
598
599   /* verify it against strcpy */
600   strcpy (dst, src);
601
602   /* This better not fail but check anyhow */
603   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
604       EOK)
605     return -1;
606   if (indicator != 0)
607     return -1;
608
609   /* Negative tests */
610
611   err = clib_strcpy (0, 0);
612   if (err == EOK)
613     return -1;
614
615   /* overlap fail */
616 #if __GNUC__ < 8
617   /* GCC 8 flunks this one at compile time... */
618   err = clib_strcpy (dst, dst);
619   if (err == EOK)
620     return -1;
621 #endif
622
623   /* overlap fail */
624   err = clib_strcpy (dst, dst + 1);
625   if (err == EOK)
626     return -1;
627
628   /* OK, seems to work */
629   return 0;
630 }
631
632 static int
633 test_strncpy_s (vlib_main_t * vm, unformat_input_t * input)
634 {
635   char src[] = "Those who dare to fail miserably can achieve greatly.";
636   char dst[100], old_dst[100];
637   int indicator;
638   size_t s1size = sizeof (dst); // including null
639   errno_t err;
640
641   vlib_cli_output (vm, "Test strncpy_s...");
642
643   /* dmax includes null, n excludes null */
644
645   /* n == string len of src */
646   err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
647   if (err != EOK)
648     return -1;
649   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
650       EOK)
651     return -1;
652   if (indicator != 0)
653     return -1;
654
655   /* limited copy -- strlen src > n, copy up to n */
656   err = strncpy_s (dst, s1size, "The price of greatness is responsibility.",
657                    10);
658   if (err != EOK)
659     return -1;
660   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
661                 &indicator) != EOK)
662     return -1;
663   if (indicator != 0)
664     return -1;
665
666   /* n > string len of src */
667   err = strncpy_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
668   if (err != EOK)
669     return -1;
670   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
671       EOK)
672     return -1;
673   if (indicator != 0)
674     return -1;
675
676   /* truncation, n >= dmax */
677   err = strncpy_s (dst, clib_strnlen (src, sizeof (src)), src,
678                    clib_strnlen (src, sizeof (src)));
679   if (err != EOVERFLOW)
680     return -1;
681
682   /* Check dst content */
683   if (dst[strlen (dst)] != '\0')
684     return -1;
685   if (strncmp_s (dst, clib_strnlen (dst, sizeof (dst)), src,
686                  clib_strnlen (dst, sizeof (dst)), &indicator) != EOK)
687     return -1;
688   if (indicator != 0)
689     return -1;
690
691   /* zero length copy */
692   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
693   err = strncpy_s (dst, sizeof (dst), src, 0);
694   if (err != EOK)
695     return -1;
696   /* verify dst is untouched */
697   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
698       EOK)
699     return -1;
700   if (indicator != 0)
701     return -1;
702
703   /* Negative tests */
704
705   err = strncpy_s (0, 0, 0, 1);
706   if (err == EOK)
707     return -1;
708
709   /* overlap fail */
710   err = strncpy_s (dst, s1size, dst + 1, s1size - 1);
711   if (err == EOK)
712     return -1;
713
714   /* overlap fail */
715 #if __GNUC__ < 8
716   /* GCC 8 flunks this one at compile time... */
717   err = strncpy_s (dst, s1size, dst, s1size);
718   if (err == EOK)
719     return -1;
720 #endif
721
722   /* OK, seems to work */
723   return 0;
724 }
725
726 static int
727 test_clib_strncpy (vlib_main_t * vm, unformat_input_t * input)
728 {
729   char src[] = "Those who dare to fail miserably can achieve greatly.";
730   char dst[100], old_dst[100];
731   int indicator;
732   size_t s1size = sizeof (dst); // including null
733   errno_t err;
734
735   vlib_cli_output (vm, "Test clib_strncpy...");
736
737   /* n == string len of src */
738   err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)));
739   if (err != EOK)
740     return -1;
741
742   /* This better not fail but check anyhow */
743   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
744       EOK)
745     return -1;
746   if (indicator != 0)
747     return -1;
748
749   /* Verify it against strncpy */
750   strncpy (dst, src, strlen (src));
751
752   /* This better not fail but check anyhow */
753   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
754       EOK)
755     return -1;
756   if (indicator != 0)
757     return -1;
758
759   /* limited copy -- strlen src > n, copy up to n */
760   err = clib_strncpy (dst, "The price of greatness is responsibility.", 10);
761   if (err != EOK)
762     return -1;
763   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
764                 &indicator) != EOK)
765     return -1;
766   if (indicator != 0)
767     return -1;
768   /* verify it against strncpy */
769   memset_s (dst, sizeof (dst), 0, sizeof (dst));
770
771 #if __GNUC__ < 8
772   /* GCC 8 flunks this one at compile time... */
773   strncpy (dst, "The price of greatness is responsibility.", 10);
774   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), "The price ",
775                 &indicator) != EOK)
776     return -1;
777   if (indicator != 0)
778     return -1;
779 #endif
780
781   /* n > string len of src */
782   err = clib_strncpy (dst, src, clib_strnlen (src, sizeof (src)) + 10);
783   if (err != EOK)
784     return -1;
785   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
786       EOK)
787     return -1;
788   if (indicator != 0)
789     return -1;
790   /* Verify it against strncpy */
791   strncpy (dst, src, strlen (src));
792   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), src, &indicator) !=
793       EOK)
794     return -1;
795   if (indicator != 0)
796     return -1;
797
798   /* zero length copy */
799   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
800   err = clib_strncpy (dst, src, 0);
801   if (err != EOK)
802     return -1;
803   /* verify dst is untouched */
804   if (strcmp_s (dst, clib_strnlen (dst, sizeof (dst)), old_dst, &indicator) !=
805       EOK)
806     return -1;
807   if (indicator != 0)
808     return -1;
809
810   /* Negative tests */
811
812   err = clib_strncpy (0, 0, 1);
813   if (err == EOK)
814     return -1;
815
816   /* overlap fail */
817   err = clib_strncpy (dst, dst + 1, s1size);
818   if (err == EOK)
819     return -1;
820
821   /* overlap fail */
822 #if __GNUC__ < 8
823   /* GCC 8 flunks this one at compile time... */
824   err = clib_strncpy (dst, dst, s1size);
825   if (err == EOK)
826     return -1;
827 #endif
828
829   /* OK, seems to work */
830   return 0;
831 }
832
833 static int
834 test_strcat_s (vlib_main_t * vm, unformat_input_t * input)
835 {
836   char src[100], dst[100], old_dst[100];
837   size_t s1size = sizeof (dst); // including null
838   errno_t err;
839   int indicator;
840
841   vlib_cli_output (vm, "Test strcat_s...");
842
843   strcpy_s (dst, sizeof (dst), "Tough time never last ");
844   strcpy_s (src, sizeof (src), "but tough people do");
845   err = strcat_s (dst, s1size, src);
846   if (err != EOK)
847     return -1;
848   if (strcmp_s (dst, s1size - 1,
849                 "Tough time never last but tough people do",
850                 &indicator) != EOK)
851     return -1;
852   if (indicator != 0)
853     return -1;
854
855   /* empty string concatenation */
856   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
857   err = strcat_s (dst, s1size, "");
858   if (err != EOK)
859     return -1;
860   /* verify dst is untouched */
861   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
862     return -1;
863   if (indicator != 0)
864     return -1;
865
866   /* negative stuff */
867   err = strcat_s (0, 0, 0);
868   if (err != EINVAL)
869     return -1;
870
871   /* overlap fail */
872   err = strcat_s (dst, s1size, dst + 1);
873   if (err != EINVAL)
874     return -1;
875
876   /* overlap fail */
877 #if __GNUC__ < 8
878   /* GCC 8 flunks this one at compile time... */
879   err = strcat_s (dst, s1size, dst);
880   if (err != EINVAL)
881     return -1;
882 #endif
883
884   /* not enough space for dst */
885   err = strcat_s (dst, 10, src);
886   if (err != EINVAL)
887     return -1;
888
889   /* OK, seems to work */
890   return 0;
891 }
892
893 static int
894 test_clib_strcat (vlib_main_t * vm, unformat_input_t * input)
895 {
896   char src[100], dst[100], old_dst[100];
897   size_t s1size = sizeof (dst); // including null
898   errno_t err;
899   int indicator;
900
901   vlib_cli_output (vm, "Test clib_strcat...");
902
903   strcpy_s (dst, sizeof (dst), "Tough time never last ");
904   strcpy_s (src, sizeof (src), "but tough people do");
905   err = clib_strcat (dst, src);
906   if (err != EOK)
907     return -1;
908   if (strcmp_s (dst, s1size - 1,
909                 "Tough time never last but tough people do",
910                 &indicator) != EOK)
911     return -1;
912   if (indicator != 0)
913     return -1;
914   /* verify it against strcat */
915   strcpy_s (dst, sizeof (dst), "Tough time never last ");
916   strcpy_s (src, sizeof (src), "but tough people do");
917   strcat (dst, src);
918   if (strcmp_s (dst, s1size - 1,
919                 "Tough time never last but tough people do",
920                 &indicator) != EOK)
921     return -1;
922   if (indicator != 0)
923     return -1;
924
925   /* empty string concatenation */
926   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
927   err = clib_strcat (dst, "");
928   if (err != EOK)
929     return -1;
930   /* verify dst is untouched */
931   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
932     return -1;
933   if (indicator != 0)
934     return -1;
935
936   /* negative stuff */
937   err = clib_strcat (0, 0);
938   if (err != EINVAL)
939     return -1;
940
941   /* overlap fail */
942   err = clib_strcat (dst, dst + 1);
943   if (err != EINVAL)
944     return -1;
945
946   /* overlap fail */
947 #if __GNUC__ < 8
948   /* GCC 8 flunks this one at compile time... */
949   err = clib_strcat (dst, dst);
950   if (err != EINVAL)
951     return -1;
952 #endif
953
954   /* OK, seems to work */
955   return 0;
956 }
957
958 static int
959 test_strncat_s (vlib_main_t * vm, unformat_input_t * input)
960 {
961   char src[100], dst[100], old_dst[100];
962   size_t s1size = sizeof (dst); // including null
963   errno_t err;
964   char s1[] = "Two things are infinite: ";
965   char s2[] = "the universe and human stupidity; ";
966   char s3[] = "I am not sure about the universe.";
967   int indicator;
968
969   vlib_cli_output (vm, "Test strncat_s...");
970
971   strcpy_s (dst, sizeof (dst), s1);
972   strcpy_s (src, sizeof (src), s2);
973   err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)));
974   if (err != EOK)
975     return -1;
976   if (strcmp_s (dst, s1size - 1,
977                 "Two things are infinite: the universe and human stupidity; ",
978                 &indicator) != EOK)
979     return -1;
980   if (indicator != 0)
981     return -1;
982
983   /* truncation, n >= dmax - strnlen_s (dst, dmax) */
984   err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)) +
985                    clib_strnlen (s3, sizeof (s3)), s3,
986                    clib_strnlen (s3, sizeof (s3)));
987   if (err != EOVERFLOW)
988     return -1;
989   /*
990    * resulting string is dst + strlen (s3) - 1 characters + null.
991    * notice the "." is missing at the end of the resulting string because
992    * the space is needed to accommodate the null
993    * Notice strcmp_s will check s1 or dst to make sure it is null terminated
994    */
995   if (strcmp_s (dst, s1size - 1,
996                 "Two things are infinite: the universe and human stupidity; "
997                 "I am not sure about the universe", &indicator) != EOK)
998     return -1;
999   if (indicator != 0)
1000     return -1;
1001
1002   /* n > strlen src */
1003   strcpy_s (dst, sizeof (dst), s1);
1004   err = strncat_s (dst, s1size, src, clib_strnlen (src, sizeof (src)) + 10);
1005   if (err != EOK)
1006     return -1;
1007   if (strcmp_s (dst, s1size - 1,
1008                 "Two things are infinite: the universe and human stupidity; ",
1009                 &indicator) != EOK)
1010     return -1;
1011   if (indicator != 0)
1012     return -1;
1013
1014   /* zero length strncat */
1015   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
1016   err = strncat_s (dst, sizeof (dst), src, 0);
1017   if (err != EOK)
1018     return -1;
1019   /* verify dst is untouched */
1020   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1021     return -1;
1022   if (indicator != 0)
1023     return -1;
1024
1025   /* empty string, wrong n concatenation */
1026   err = strncat_s (dst, sizeof (dst), "", 10);
1027   if (err != EOK)
1028     return -1;
1029   /* verify dst is untouched */
1030   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1031     return -1;
1032   if (indicator != 0)
1033     return -1;
1034
1035   /* limited concatenation, string > n, copy up to n */
1036   strcpy_s (dst, sizeof (dst), s1);
1037   err = strncat_s (dst, s1size, s2, 13);
1038   if (err != EOK)
1039     return -1;
1040   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1041                 &indicator) != EOK)
1042     return -1;
1043   if (indicator != 0)
1044     return -1;
1045   /* verify it against strncat */
1046   strcpy_s (dst, sizeof (dst), s1);
1047   strncat (dst, s2, 13);
1048   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1049                 &indicator) != EOK)
1050     return -1;
1051   if (indicator != 0)
1052     return -1;
1053
1054   /* negative stuff */
1055   err = strncat_s (0, 0, 0, 1);
1056   if (err != EINVAL)
1057     return -1;
1058
1059   /* no room for dst -- dmax - strnlen_s (dst, dmax) == 0 */
1060   err = strncat_s (dst, clib_strnlen (dst, sizeof (dst)), s2,
1061                    clib_strnlen (s2, sizeof (s2)));
1062   if (err != EINVAL)
1063     return -1;
1064
1065   /* overlap fail */
1066   err = strncat_s (dst, s1size, dst + 1, clib_strnlen (dst + 1, s1size - 1));
1067   if (err != EINVAL)
1068     return -1;
1069
1070   /* overlap fail */
1071 #if __GNUC__ < 8
1072   /* GCC 8 flunks this one at compile time... */
1073   err = strncat_s (dst, s1size, dst, clib_strnlen (dst, sizeof (dst)));
1074   if (err != EINVAL)
1075     return -1;
1076 #endif
1077
1078   /* OK, seems to work */
1079   return 0;
1080 }
1081
1082 static int
1083 test_clib_strncat (vlib_main_t * vm, unformat_input_t * input)
1084 {
1085   char src[100], dst[100], old_dst[100];
1086   size_t s1size = sizeof (dst); // including null
1087   errno_t err;
1088   char s1[] = "Two things are infinite: ";
1089   char s2[] = "the universe and human stupidity; ";
1090   int indicator;
1091
1092   vlib_cli_output (vm, "Test clib_strncat...");
1093
1094   /* n == strlen src */
1095   strcpy_s (dst, sizeof (dst), s1);
1096   strcpy_s (src, sizeof (src), s2);
1097   err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)));
1098   if (err != EOK)
1099     return -1;
1100   if (strcmp_s (dst, s1size - 1,
1101                 "Two things are infinite: the universe and human stupidity; ",
1102                 &indicator) != EOK)
1103     return -1;
1104   if (indicator != 0)
1105     return -1;
1106   /* verify it against strncat */
1107   strcpy_s (dst, sizeof (dst), s1);
1108   strncat (dst, src, clib_strnlen (src, sizeof (src)));
1109   if (strcmp_s (dst, s1size - 1,
1110                 "Two things are infinite: the universe and human stupidity; ",
1111                 &indicator) != EOK)
1112     return -1;
1113   if (indicator != 0)
1114     return -1;
1115
1116   /* n > strlen src */
1117   strcpy_s (dst, sizeof (dst), s1);
1118   err = clib_strncat (dst, src, clib_strnlen (src, sizeof (src)) + 10);
1119   if (err != EOK)
1120     return -1;
1121   if (strcmp_s (dst, s1size - 1,
1122                 "Two things are infinite: the universe and human stupidity; ",
1123                 &indicator) != EOK)
1124     return -1;
1125   if (indicator != 0)
1126     return -1;
1127   /* verify it against strncat */
1128   strcpy_s (dst, sizeof (dst), s1);
1129   strncat (dst, src, clib_strnlen (src, sizeof (src)));
1130   if (strcmp_s (dst, s1size - 1,
1131                 "Two things are infinite: the universe and human stupidity; ",
1132                 &indicator) != EOK)
1133     return -1;
1134   if (indicator != 0)
1135     return -1;
1136
1137   /* zero length strncat */
1138   clib_strncpy (old_dst, dst, clib_strnlen (dst, sizeof (dst)));
1139   err = clib_strncat (dst, src, 0);
1140   if (err != EOK)
1141     return -1;
1142   /* verify dst is untouched */
1143   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1144     return -1;
1145   if (indicator != 0)
1146     return -1;
1147
1148   /* empty string, wrong n concatenation */
1149   err = clib_strncat (dst, "", 10);
1150   if (err != EOK)
1151     return -1;
1152   /* verify dst is untouched */
1153   if (strcmp_s (dst, s1size - 1, old_dst, &indicator) != EOK)
1154     return -1;
1155   if (indicator != 0)
1156     return -1;
1157
1158   /* limited concatenation, string > n, copy up to n */
1159   strcpy_s (dst, sizeof (dst), s1);
1160   err = clib_strncat (dst, s2, 13);
1161   if (err != EOK)
1162     return -1;
1163   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1164                 &indicator) != EOK)
1165     return -1;
1166   if (indicator != 0)
1167     return -1;
1168   /* verify it against strncat */
1169   strcpy_s (dst, sizeof (dst), s1);
1170   strncat (dst, s2, 13);
1171   if (strcmp_s (dst, s1size - 1, "Two things are infinite: the universe ",
1172                 &indicator) != EOK)
1173     return -1;
1174   if (indicator != 0)
1175     return -1;
1176
1177   /* negative stuff */
1178   err = clib_strncat (0, 0, 1);
1179   if (err != EINVAL)
1180     return -1;
1181
1182   /* overlap fail */
1183   err = clib_strncat (dst, dst + 1, s1size - 1);
1184   if (err != EINVAL)
1185     return -1;
1186
1187   /* overlap fail */
1188 #if __GNUC__ < 8
1189   /* GCC 8 flunks this one at compile time... */
1190   err = clib_strncat (dst, dst, clib_strnlen (dst, sizeof (dst)));
1191   if (err != EINVAL)
1192     return -1;
1193 #endif
1194
1195   /* OK, seems to work */
1196   return 0;
1197 }
1198
1199 static int
1200 test_strtok_s (vlib_main_t * vm, unformat_input_t * input)
1201 {
1202   int indicator;
1203   char *tok, *ptr;
1204   char str2[20];
1205   char str1[40];
1206   uword len;
1207   char *p2str = 0;
1208   char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
1209
1210   vlib_cli_output (vm, "Test strtok_s...");
1211   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1212   len = strnlen_s (str1, sizeof (str1));
1213   tok1 = strtok_s (str1, &len, " ", &p2str);
1214   tok2 = strtok_s (0, &len, " ", &p2str);
1215   tok3 = strtok_s (0, &len, " ", &p2str);
1216   tok4 = strtok_s (0, &len, " ", &p2str);
1217   tok5 = strtok_s (0, &len, " ", &p2str);
1218   tok6 = strtok_s (0, &len, " ", &p2str);
1219   tok7 = strtok_s (0, &len, " ", &p2str);
1220   if ((tok1 == 0) ||
1221       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1222     return -1;
1223   if (indicator != 0)
1224     return -1;
1225   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1226     return -1;
1227   if (indicator != 0)
1228     return -1;
1229   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1230     return -1;
1231   if (indicator != 0)
1232     return -1;
1233   if ((tok4 == 0)
1234       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1235     return -1;
1236   if (indicator != 0)
1237     return -1;
1238   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1239     return -1;
1240   if (indicator != 0)
1241     return -1;
1242   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1243     return -1;
1244   if (indicator != 0)
1245     return -1;
1246   if (tok7 != 0)
1247     return -1;
1248
1249   /* delimiter not present in the string -- the whole string is returned */
1250   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1251   len = strnlen_s (str1, sizeof (str1) - 1);
1252   p2str = 0;
1253   tok1 = strtok_s (str1, &len, ",", &p2str);
1254   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1255     return -1;
1256   if (indicator != 0)
1257     return -1;
1258
1259   /* negative stuff */
1260   tok = strtok_s (0, 0, 0, 0);
1261   if (tok != 0)
1262     return -1;
1263
1264   /* s1 and ptr contents are null */
1265   ptr = 0;
1266   tok = strtok_s (0, 0, 0, &ptr);
1267   if (tok != 0)
1268     return -1;
1269
1270   /* unterminate s1 */
1271   p2str = 0;
1272   len = strnlen_s (str1, sizeof (str1) - 1);
1273   str1[strlen (str1)] = 0x2;
1274   tok = strtok_s (str1, &len, ",", &p2str);
1275   if (tok != 0)
1276     return -1;
1277
1278   /*
1279    * unterminated s2. This test case in not perfect because there is no
1280    * argument for s2max. But s2 len is limited to 16 characters. If the API
1281    * does not find the null character at s2[15], it declares the string s2
1282    * as unterminated.
1283    */
1284   memset_s (str2, sizeof (str2), 0xfa, sizeof (str2));
1285   tok = strtok_s (str1, &len, str2, &p2str);
1286   if (tok != 0)
1287     return -1;
1288
1289   /* OK, seems to work */
1290   return 0;
1291 }
1292
1293 static int
1294 test_clib_strtok (vlib_main_t * vm, unformat_input_t * input)
1295 {
1296   int indicator;
1297   char *s1 __attribute__ ((unused));
1298   char *tok __attribute__ ((unused));
1299   char *ptr __attribute__ ((unused));
1300   char str1[40];
1301   char *p2str;
1302   char *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7;
1303
1304   vlib_cli_output (vm, "Test clib_strtok...");
1305   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1306   p2str = 0;
1307   tok1 = clib_strtok (str1, " ", &p2str);
1308   tok2 = clib_strtok (0, " ", &p2str);
1309   tok3 = clib_strtok (0, " ", &p2str);
1310   tok4 = clib_strtok (0, " ", &p2str);
1311   tok5 = clib_strtok (0, " ", &p2str);
1312   tok6 = clib_strtok (0, " ", &p2str);
1313   tok7 = clib_strtok (0, " ", &p2str);
1314   if ((tok1 == 0) ||
1315       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1316     return -1;
1317   if (indicator != 0)
1318     return -1;
1319   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1320     return -1;
1321   if (indicator != 0)
1322     return -1;
1323   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1324     return -1;
1325   if (indicator != 0)
1326     return -1;
1327   if ((tok4 == 0)
1328       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1329     return -1;
1330   if (indicator != 0)
1331     return -1;
1332   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1333     return -1;
1334   if (indicator != 0)
1335     return -1;
1336   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1337     return -1;
1338   if (indicator != 0)
1339     return -1;
1340   if (tok7 != 0)
1341     return -1;
1342   /* verify it againest strtok_r */
1343   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1344   p2str = 0;
1345   tok1 = strtok_r (str1, " ", &p2str);
1346   tok2 = strtok_r (0, " ", &p2str);
1347   tok3 = strtok_r (0, " ", &p2str);
1348   tok4 = strtok_r (0, " ", &p2str);
1349   tok5 = strtok_r (0, " ", &p2str);
1350   tok6 = strtok_r (0, " ", &p2str);
1351   tok7 = strtok_r (0, " ", &p2str);
1352   if ((tok1 == 0) ||
1353       strcmp_s (tok1, strlen (tok1), "brevity", &indicator) != EOK)
1354     return -1;
1355   if (indicator != 0)
1356     return -1;
1357   if ((tok2 == 0) || strcmp_s (tok2, strlen (tok2), "is", &indicator) != EOK)
1358     return -1;
1359   if (indicator != 0)
1360     return -1;
1361   if ((tok3 == 0) || strcmp_s (tok3, strlen (tok3), "the", &indicator) != EOK)
1362     return -1;
1363   if (indicator != 0)
1364     return -1;
1365   if ((tok4 == 0)
1366       || strcmp_s (tok4, strlen (tok4), "soul", &indicator) != EOK)
1367     return -1;
1368   if (indicator != 0)
1369     return -1;
1370   if ((tok5 == 0) || strcmp_s (tok5, strlen (tok5), "of", &indicator) != EOK)
1371     return -1;
1372   if (indicator != 0)
1373     return -1;
1374   if ((tok6 == 0) || strcmp_s (tok6, strlen (tok6), "wit", &indicator) != EOK)
1375     return -1;
1376   if (indicator != 0)
1377     return -1;
1378   if (tok7 != 0)
1379     return -1;
1380
1381   /* delimiter not present in the string -- the whole string is returned */
1382   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1383   p2str = 0;
1384   tok1 = clib_strtok (str1, ",", &p2str);
1385   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1386     return -1;
1387   if (indicator != 0)
1388     return -1;
1389   /* verify it against strtok_r */
1390   strcpy_s (str1, sizeof (str1), "brevity is the soul of wit");
1391   p2str = 0;
1392   tok1 = strtok_r (str1, ",", &p2str);
1393   if ((tok1 == 0) || strcmp_s (tok1, strlen (tok1), str1, &indicator) != EOK)
1394     return -1;
1395   if (indicator != 0)
1396     return -1;
1397
1398   /* negative stuff */
1399   s1 = 0;
1400   ptr = 0;
1401 #if __GNUC__ < 8
1402   /* GCC 8 flunks this one at compile time... */
1403   tok = clib_strtok (s1, s1, (char **) 0);
1404   if (tok != 0)
1405     return -1;
1406
1407   /* s1 and ptr contents are null */
1408   tok = clib_strtok (s1, s1, &ptr);
1409   if (tok != 0)
1410     return -1;
1411 #endif
1412
1413   /* verify it against strtok_r */
1414   /* No can do. This causes a crash in strtok_r */
1415   // tok = strtok_r (s1, " ", &ptr);
1416   // if (tok != 0)
1417   //  return -1;
1418
1419   /*
1420    * Can't test unterminated string s1 and s2 becuase clib_strtok does not
1421    * supply s1 and s2 max
1422    */
1423
1424   /* OK, seems to work */
1425   return 0;
1426 }
1427
1428 static int
1429 test_strnlen_s (vlib_main_t * vm, unformat_input_t * input)
1430 {
1431   const char s1[] = "Truth is incontrovertible";
1432   size_t len;
1433
1434   vlib_cli_output (vm, "Test strnlen_s...");
1435
1436   len = strnlen_s (s1, sizeof (s1));
1437   if (len != sizeof (s1) - 1)
1438     return -1;
1439
1440   len = strnlen_s (s1, 5);
1441   if (len != 5)
1442     return -1;
1443
1444   /* negative stuff */
1445   len = strnlen_s (0, 0);
1446   if (len != 0)
1447     return -1;
1448
1449   /* OK, seems to work */
1450   return 0;
1451 }
1452
1453 static int
1454 test_clib_strnlen (vlib_main_t * vm, unformat_input_t * input)
1455 {
1456   const char s1[] = "Truth is incontrovertible";
1457   size_t len;
1458
1459   vlib_cli_output (vm, "Test clib_strnlen...");
1460
1461   len = clib_strnlen (s1, sizeof (s1));
1462   if (len != sizeof (s1) - 1)
1463     return -1;
1464
1465   len = clib_strnlen (s1, 5);
1466   if (len != 5)
1467     return -1;
1468
1469   /* negative stuff */
1470   len = clib_strnlen (0, 0);
1471   if (len != 0)
1472     return -1;
1473
1474   /* OK, seems to work */
1475   return 0;
1476 }
1477
1478 static int
1479 test_strstr_s (vlib_main_t * vm, unformat_input_t * input)
1480 {
1481   errno_t err;
1482   char *sub = 0;
1483   char s1[64];
1484   size_t s1len = sizeof (s1) - 1;       // excluding null
1485   int indicator;
1486
1487   vlib_cli_output (vm, "Test strstr_s...");
1488
1489   /* substring not present */
1490   strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
1491   err = strstr_s (s1, s1len, "failures", sizeof ("failures"), &sub);;
1492   if (err != ESRCH)
1493     return -1;
1494
1495   /* substring present */
1496   err = strstr_s (s1, s1len, "failure", sizeof ("failure"), &sub);
1497   if (err != EOK)
1498     return -1;
1499
1500   if ((sub == 0) ||
1501       strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator)
1502       != EOK)
1503     return -1;
1504   if (indicator != 0)
1505     return -1;
1506
1507   /* negative stuff */
1508
1509   /* Null pointers test */
1510   err = strstr_s (0, 0, 0, 0, 0);
1511   if (err != EINVAL)
1512     return -1;
1513
1514   /* unterminated s1 and s2 */
1515   memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
1516   err = strstr_s (s1, s1len, s1, s1len, &sub);
1517   if (err != EINVAL)
1518     return -1;
1519
1520   /* OK, seems to work */
1521   return 0;
1522 }
1523
1524 static int
1525 test_clib_strstr (vlib_main_t * vm, unformat_input_t * input)
1526 {
1527   char *sub, *s;
1528   char s1[64];
1529   size_t s1len = sizeof (s1) - 1;       // excluding null
1530   int indicator;
1531
1532   vlib_cli_output (vm, "Test clib_strstr...");
1533
1534   /* substring not present */
1535   strcpy_s (s1, s1len, "success is not final, failure is not fatal.");
1536   sub = clib_strstr (s1, "failures");
1537   if (sub != 0)
1538     return -1;
1539   /* verify it against strstr */
1540   sub = strstr (s1, "failures");
1541   if (sub != 0)
1542     return -1;
1543
1544   /* substring present */
1545   sub = clib_strstr (s1, "failure");
1546   if (sub == 0)
1547     return -1;
1548   if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
1549       EOK)
1550     return -1;
1551   if (indicator != 0)
1552     return -1;
1553   /* verify it against strstr */
1554   sub = strstr (s1, "failure");
1555   if (sub == 0)
1556     return -1;
1557   if (strcmp_s (sub, strlen (sub), "failure is not fatal.", &indicator) !=
1558       EOK)
1559     return -1;
1560   if (indicator != 0)
1561     return -1;
1562
1563   /* negative stuff */
1564
1565   /* Null pointers test */
1566   s = 0;
1567   sub = clib_strstr (s, s);
1568   if (sub != 0)
1569     return -1;
1570   /*
1571    * Can't verify it against strstr for this test. Null pointers cause strstr
1572    * to crash. Go figure!
1573    */
1574
1575   /* unterminated s1 and s2 */
1576   memset_s (s1, ARRAY_LEN (s1), 0xfe, ARRAY_LEN (s1));
1577   sub = clib_strstr (s1, s1);
1578   if (sub == 0)
1579     return -1;
1580   /*
1581    * Can't verify it against strstr for this test. Unterminated string causes
1582    * strstr to crash. Go figure!
1583    */
1584
1585   /* OK, seems to work */
1586   return 0;
1587 }
1588
1589 #define foreach_string_test                               \
1590   _ (0, MEMCPY_S, "memcpy_s", memcpy_s)                   \
1591   _ (1, CLIB_MEMCPY, "clib_memcpy", clib_memcpy)          \
1592   _ (2, MEMSET_S , "memset_s", memset_s)                  \
1593   _ (3, CLIB_MEMSET , "clib_memset", clib_memset)         \
1594   _ (4, MEMCMP_S, "memcmp_s", memcmp_s)                   \
1595   _ (5, CLIB_MEMCMP, "clib_memcmp", clib_memcmp)          \
1596   _ (6, STRCMP_S, "strcmp_s", strcmp_s)                   \
1597   _ (7, CLIB_STRCMP, "clib_strcmp", clib_strcmp)          \
1598   _ (8, STRNCMP_S, "strncmp_s", strncmp_s)                \
1599   _ (9, CLIB_STRNCMP, "clib_strncmp", clib_strncmp)       \
1600   _ (10, STRCPY_S, "strcpy_s", strcpy_s)                  \
1601   _ (11, CLIB_STRCPY, "clib_strcpy", clib_strcpy)         \
1602   _ (12, STRNCPY_S, "strncpy_s", strncpy_s)               \
1603   _ (13, CLIB_STRNCPY, "clib_strncpy", clib_strncpy)      \
1604   _ (14, STRCAT_S, "strcat_s", strcat_s)                  \
1605   _ (15, CLIB_STRCAT, "clib_strcat", clib_strcat)         \
1606   _ (16, STRNCAT_S, "strncat_s", strncat_s)               \
1607   _ (17, CLIB_STRNCAT, "clib_strncat", clib_strncat)      \
1608   _ (18, STRTOK_S, "strtok_s", strtok_s)                  \
1609   _ (19, CLIB_STRTOK, "clib_strtok", clib_strtok)         \
1610   _ (20, STRNLEN_S, "strnlen_s", strnlen_s)               \
1611   _ (21, CLIB_STRNLEN, "clib_strnlen", clib_strnlen)      \
1612   _ (22, STRSTR_S, "strstr_s", strstr_s)                  \
1613   _ (23, CLIB_STRSTR, "clib_strstr", clib_strstr)
1614
1615 typedef enum
1616 {
1617 #define _(v,f,s,p) STRING_TEST_##f = v,
1618   foreach_string_test
1619 #undef _
1620 } string_test_t;
1621
1622 static uword
1623 unformat_string_test (unformat_input_t * input, va_list * args)
1624 {
1625   u8 *r = va_arg (*args, u8 *);
1626
1627   if (0)
1628     ;
1629 #define _(v,f,s,p) else if (unformat (input, s)) *r = STRING_TEST_##f;
1630   foreach_string_test
1631 #undef _
1632     else
1633     return 0;
1634
1635   return 1;
1636 }
1637
1638 typedef int (*string_test_func) (vlib_main_t * vm, unformat_input_t * input);
1639
1640 typedef struct
1641 {
1642   string_test_func test;
1643 } string_test_func_t;
1644
1645 static clib_error_t *
1646 string_test_command_fn (vlib_main_t * vm,
1647                         unformat_input_t * input,
1648                         vlib_cli_command_t * cmd_arg)
1649 {
1650   string_test_func_t string_func[] = {
1651 #define _(v,f,s,p) { test_##p },
1652     foreach_string_test
1653 #undef _
1654   };
1655   const char *string_table[] = {
1656 #define _(v,f,s,p) s,
1657     foreach_string_test
1658 #undef _
1659   };
1660   int res = 0, ok;
1661   i8 specific_test = ~0;
1662
1663   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1664     {
1665       if (unformat (input, "%U", unformat_string_test, &specific_test))
1666         break;
1667       else
1668         return clib_error_return (0, "unknown input `%U'",
1669                                   format_unformat_error, input);
1670     }
1671
1672   if (specific_test == ~0)
1673     {
1674       for (specific_test = STRING_TEST_MEMCPY_S;
1675            specific_test <= STRING_TEST_CLIB_STRSTR; specific_test++)
1676         {
1677           ok = (string_func[specific_test]).test (vm, input);
1678           res += ok;
1679           if (ok != 0)
1680             vlib_cli_output (vm, "test_%s failed",
1681                              string_table[specific_test]);
1682         }
1683     }
1684   else
1685     res = (string_func[specific_test]).test (vm, input);
1686   if (res)
1687     vlib_cli_output (vm, "String unit test(s) failed...");
1688   else
1689     vlib_cli_output (vm, "String unit test(s) OK...");
1690   return 0;
1691 }
1692
1693 /* *INDENT-OFF* */
1694 VLIB_CLI_COMMAND (string_test_command, static) =
1695 {
1696   .path = "test string",
1697   .short_help = "test string [memcpy_s | clib_memcpy | memset_s | "
1698   "clib_memset | memcmp_s | clib_memcmp | strcmp_s | clib_strcmp | "
1699   "strncmp_s | clib_strncmp | strcpy_s | clib_strcpy | strncpy_s | "
1700   "clib_strncpy | strcat_s | clib_strcat | strncat_s | clib_strncat | "
1701   "strtok_s |  clib_strtok | strnlen_s | clib_strnlen | strstr_s | "
1702   "clib_strstr]",
1703   .function = string_test_command_fn,
1704 };
1705 /* *INDENT-ON* */
1706
1707 /*
1708  * fd.io coding-style-patch-verification: ON
1709  *
1710  * Local Variables:
1711  * eval: (c-set-style "gnu")
1712  * End:
1713  */