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