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