Ignore -Wrestrict for one strncat test.
[glibc.git] / string / tester.c
blob601eb01b55bdd3ed052a25331c68a400bf8d43ec
1 /* Tester for string functions.
2 Copyright (C) 1995-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
23 /* Make sure we don't test the optimized inline functions if we want to
24 test the real implementation. */
25 #if !defined DO_STRING_INLINES
26 #undef __USE_STRING_INLINES
27 #endif
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <fcntl.h>
35 #include <libc-diag.h>
38 #define STREQ(a, b) (strcmp((a), (b)) == 0)
40 const char *it = "<UNSET>"; /* Routine name for message routines. */
41 size_t errors = 0;
43 /* Complain if condition is not true. */
44 static void
45 check (int thing, int number)
47 if (!thing)
49 printf ("%s flunked test %d\n", it, number);
50 ++errors;
54 /* Complain if first two args don't strcmp as equal. */
55 static void
56 equal (const char *a, const char *b, int number)
58 check (a != NULL && b != NULL && STREQ (a, b), number);
61 char one[50];
62 char two[50];
63 char *cp;
65 static void
66 test_strcmp (void)
68 it = "strcmp";
69 check (strcmp ("", "") == 0, 1); /* Trivial case. */
70 check (strcmp ("a", "a") == 0, 2); /* Identity. */
71 check (strcmp ("abc", "abc") == 0, 3); /* Multicharacter. */
72 check (strcmp ("abc", "abcd") < 0, 4); /* Length mismatches. */
73 check (strcmp ("abcd", "abc") > 0, 5);
74 check (strcmp ("abcd", "abce") < 0, 6); /* Honest miscompares. */
75 check (strcmp ("abce", "abcd") > 0, 7);
76 check (strcmp ("a\203", "a") > 0, 8); /* Tricky if char signed. */
77 check (strcmp ("a\203", "a\003") > 0, 9);
80 char buf1[0x40], buf2[0x40];
81 int i, j;
82 for (i=0; i < 0x10; i++)
83 for (j = 0; j < 0x10; j++)
85 int k;
86 for (k = 0; k < 0x3f; k++)
88 buf1[k] = '0' ^ (k & 4);
89 buf2[k] = '4' ^ (k & 4);
91 buf1[i] = buf1[0x3f] = 0;
92 buf2[j] = buf2[0x3f] = 0;
93 for (k = 0; k < 0xf; k++)
95 int cnum = 0x10+0x10*k+0x100*j+0x1000*i;
96 check (strcmp (buf1+i,buf2+j) == 0, cnum);
97 buf1[i+k] = 'A' + i + k;
98 buf1[i+k+1] = 0;
99 check (strcmp (buf1+i,buf2+j) > 0, cnum+1);
100 check (strcmp (buf2+j,buf1+i) < 0, cnum+2);
101 buf2[j+k] = 'B' + i + k;
102 buf2[j+k+1] = 0;
103 check (strcmp (buf1+i,buf2+j) < 0, cnum+3);
104 check (strcmp (buf2+j,buf1+i) > 0, cnum+4);
105 buf2[j+k] = 'A' + i + k;
106 buf1[i] = 'A' + i + 0x80;
107 check (strcmp (buf1+i,buf2+j) > 0, cnum+5);
108 check (strcmp (buf2+j,buf1+i) < 0, cnum+6);
109 buf1[i] = 'A' + i;
115 #define SIMPLE_COPY(fn, n, str, ntest) \
116 do { \
117 int __n; \
118 char *cp; \
119 for (__n = 0; __n < (int) sizeof (one); ++__n) \
120 one[__n] = 'Z'; \
121 fn (one, str); \
122 for (cp = one, __n = 0; __n < n; ++__n, ++cp) \
123 check (*cp == '0' + (n % 10), ntest); \
124 check (*cp == '\0', ntest); \
125 } while (0)
127 static void
128 test_strcpy (void)
130 int i;
131 it = "strcpy";
132 check (strcpy (one, "abcd") == one, 1); /* Returned value. */
133 equal (one, "abcd", 2); /* Basic test. */
135 (void) strcpy (one, "x");
136 equal (one, "x", 3); /* Writeover. */
137 equal (one+2, "cd", 4); /* Wrote too much? */
139 (void) strcpy (two, "hi there");
140 (void) strcpy (one, two);
141 equal (one, "hi there", 5); /* Basic test encore. */
142 equal (two, "hi there", 6); /* Stomped on source? */
144 (void) strcpy (one, "");
145 equal (one, "", 7); /* Boundary condition. */
147 for (i = 0; i < 16; i++)
149 (void) strcpy (one + i, "hi there"); /* Unaligned destination. */
150 equal (one + i, "hi there", 8 + (i * 2));
151 (void) strcpy (two, one + i); /* Unaligned source. */
152 equal (two, "hi there", 9 + (i * 2));
155 SIMPLE_COPY(strcpy, 0, "", 41);
156 SIMPLE_COPY(strcpy, 1, "1", 42);
157 SIMPLE_COPY(strcpy, 2, "22", 43);
158 SIMPLE_COPY(strcpy, 3, "333", 44);
159 SIMPLE_COPY(strcpy, 4, "4444", 45);
160 SIMPLE_COPY(strcpy, 5, "55555", 46);
161 SIMPLE_COPY(strcpy, 6, "666666", 47);
162 SIMPLE_COPY(strcpy, 7, "7777777", 48);
163 SIMPLE_COPY(strcpy, 8, "88888888", 49);
164 SIMPLE_COPY(strcpy, 9, "999999999", 50);
165 SIMPLE_COPY(strcpy, 10, "0000000000", 51);
166 SIMPLE_COPY(strcpy, 11, "11111111111", 52);
167 SIMPLE_COPY(strcpy, 12, "222222222222", 53);
168 SIMPLE_COPY(strcpy, 13, "3333333333333", 54);
169 SIMPLE_COPY(strcpy, 14, "44444444444444", 55);
170 SIMPLE_COPY(strcpy, 15, "555555555555555", 56);
171 SIMPLE_COPY(strcpy, 16, "6666666666666666", 57);
173 /* Simple test using implicitly coerced `void *' arguments. */
174 const void *src = "frobozz";
175 void *dst = one;
176 check (strcpy (dst, src) == dst, 1);
177 equal (dst, "frobozz", 2);
180 static void
181 test_stpcpy (void)
183 it = "stpcpy";
184 check ((stpcpy (one, "a") - one) == 1, 1);
185 equal (one, "a", 2);
187 check ((stpcpy (one, "ab") - one) == 2, 3);
188 equal (one, "ab", 4);
190 check ((stpcpy (one, "abc") - one) == 3, 5);
191 equal (one, "abc", 6);
193 check ((stpcpy (one, "abcd") - one) == 4, 7);
194 equal (one, "abcd", 8);
196 check ((stpcpy (one, "abcde") - one) == 5, 9);
197 equal (one, "abcde", 10);
199 check ((stpcpy (one, "abcdef") - one) == 6, 11);
200 equal (one, "abcdef", 12);
202 check ((stpcpy (one, "abcdefg") - one) == 7, 13);
203 equal (one, "abcdefg", 14);
205 check ((stpcpy (one, "abcdefgh") - one) == 8, 15);
206 equal (one, "abcdefgh", 16);
208 check ((stpcpy (one, "abcdefghi") - one) == 9, 17);
209 equal (one, "abcdefghi", 18);
211 check ((stpcpy (one, "x") - one) == 1, 19);
212 equal (one, "x", 20); /* Writeover. */
213 equal (one+2, "cdefghi", 21); /* Wrote too much? */
215 check ((stpcpy (one, "xx") - one) == 2, 22);
216 equal (one, "xx", 23); /* Writeover. */
217 equal (one+3, "defghi", 24); /* Wrote too much? */
219 check ((stpcpy (one, "xxx") - one) == 3, 25);
220 equal (one, "xxx", 26); /* Writeover. */
221 equal (one+4, "efghi", 27); /* Wrote too much? */
223 check ((stpcpy (one, "xxxx") - one) == 4, 28);
224 equal (one, "xxxx", 29); /* Writeover. */
225 equal (one+5, "fghi", 30); /* Wrote too much? */
227 check ((stpcpy (one, "xxxxx") - one) == 5, 31);
228 equal (one, "xxxxx", 32); /* Writeover. */
229 equal (one+6, "ghi", 33); /* Wrote too much? */
231 check ((stpcpy (one, "xxxxxx") - one) == 6, 34);
232 equal (one, "xxxxxx", 35); /* Writeover. */
233 equal (one+7, "hi", 36); /* Wrote too much? */
235 check ((stpcpy (one, "xxxxxxx") - one) == 7, 37);
236 equal (one, "xxxxxxx", 38); /* Writeover. */
237 equal (one+8, "i", 39); /* Wrote too much? */
239 check ((stpcpy (stpcpy (stpcpy (one, "a"), "b"), "c") - one) == 3, 40);
240 equal (one, "abc", 41);
241 equal (one + 4, "xxx", 42);
243 SIMPLE_COPY(stpcpy, 0, "", 43);
244 SIMPLE_COPY(stpcpy, 1, "1", 44);
245 SIMPLE_COPY(stpcpy, 2, "22", 45);
246 SIMPLE_COPY(stpcpy, 3, "333", 46);
247 SIMPLE_COPY(stpcpy, 4, "4444", 47);
248 SIMPLE_COPY(stpcpy, 5, "55555", 48);
249 SIMPLE_COPY(stpcpy, 6, "666666", 49);
250 SIMPLE_COPY(stpcpy, 7, "7777777", 50);
251 SIMPLE_COPY(stpcpy, 8, "88888888", 51);
252 SIMPLE_COPY(stpcpy, 9, "999999999", 52);
253 SIMPLE_COPY(stpcpy, 10, "0000000000", 53);
254 SIMPLE_COPY(stpcpy, 11, "11111111111", 54);
255 SIMPLE_COPY(stpcpy, 12, "222222222222", 55);
256 SIMPLE_COPY(stpcpy, 13, "3333333333333", 56);
257 SIMPLE_COPY(stpcpy, 14, "44444444444444", 57);
258 SIMPLE_COPY(stpcpy, 15, "555555555555555", 58);
259 SIMPLE_COPY(stpcpy, 16, "6666666666666666", 59);
262 static void
263 test_stpncpy (void)
265 it = "stpncpy";
266 memset (one, 'x', sizeof (one));
267 DIAG_PUSH_NEEDS_COMMENT;
268 #if __GNUC_PREREQ (8, 0)
269 /* GCC 8 warns about stpncpy truncating output; this is deliberately
270 tested here. */
271 DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation");
272 #endif
273 check (stpncpy (one, "abc", 2) == one + 2, 1);
274 check (stpncpy (one, "abc", 3) == one + 3, 2);
275 DIAG_POP_NEEDS_COMMENT;
276 check (stpncpy (one, "abc", 4) == one + 3, 3);
277 check (one[3] == '\0' && one[4] == 'x', 4);
278 check (stpncpy (one, "abcd", 5) == one + 4, 5);
279 check (one[4] == '\0' && one[5] == 'x', 6);
280 check (stpncpy (one, "abcd", 6) == one + 4, 7);
281 check (one[4] == '\0' && one[5] == '\0' && one[6] == 'x', 8);
284 static void
285 test_strcat (void)
287 it = "strcat";
288 (void) strcpy (one, "ijk");
289 check (strcat (one, "lmn") == one, 1); /* Returned value. */
290 equal (one, "ijklmn", 2); /* Basic test. */
292 (void) strcpy (one, "x");
293 (void) strcat (one, "yz");
294 equal (one, "xyz", 3); /* Writeover. */
295 equal (one+4, "mn", 4); /* Wrote too much? */
297 (void) strcpy (one, "gh");
298 (void) strcpy (two, "ef");
299 (void) strcat (one, two);
300 equal (one, "ghef", 5); /* Basic test encore. */
301 equal (two, "ef", 6); /* Stomped on source? */
303 (void) strcpy (one, "");
304 (void) strcat (one, "");
305 equal (one, "", 7); /* Boundary conditions. */
306 (void) strcpy (one, "ab");
307 (void) strcat (one, "");
308 equal (one, "ab", 8);
309 (void) strcpy (one, "");
310 (void) strcat (one, "cd");
311 equal (one, "cd", 9);
313 int ntest = 10;
314 char buf1[80] __attribute__ ((aligned (16)));
315 char buf2[32] __attribute__ ((aligned (16)));
316 for (size_t n1 = 0; n1 < 16; ++n1)
317 for (size_t n2 = 0; n2 < 16; ++n2)
318 for (size_t n3 = 0; n3 < 32; ++n3)
320 size_t olderrors = errors;
322 memset (buf1, 'b', sizeof (buf1));
324 memset (buf1 + n2, 'a', n3);
325 buf1[n2 + n3] = '\0';
326 strcpy (buf2 + n1, "123");
328 check (strcat (buf1 + n2, buf2 + n1) == buf1 + n2, ntest);
329 if (errors == olderrors)
330 for (size_t i = 0; i < sizeof (buf1); ++i)
332 if (i < n2)
333 check (buf1[i] == 'b', ntest);
334 else if (i < n2 + n3)
335 check (buf1[i] == 'a', ntest);
336 else if (i < n2 + n3 + 3)
337 check (buf1[i] == "123"[i - (n2 + n3)], ntest);
338 else if (i == n2 + n3 + 3)
339 check (buf1[i] == '\0', ntest);
340 else
341 check (buf1[i] == 'b', ntest);
343 if (errors != olderrors)
345 printf ("n1=%zu, n2=%zu, n3=%zu, buf1=%02hhx",
346 n1, n2, n3, buf1[0]);
347 for (size_t j = 1; j < sizeof (buf1); ++j)
348 printf (",%02hhx", buf1[j]);
349 putchar_unlocked ('\n');
350 break;
356 static void
357 test_strncat (void)
359 /* First test it as strcat, with big counts, then test the count
360 mechanism. */
361 it = "strncat";
362 (void) strcpy (one, "ijk");
363 DIAG_PUSH_NEEDS_COMMENT;
364 #if __GNUC_PREREQ (7, 0)
365 /* GCC 7 warns about the size passed to strncat being larger than
366 the size of the buffer; this is deliberately tested here.. */
367 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
368 #endif
369 check (strncat (one, "lmn", 99) == one, 1); /* Returned value. */
370 DIAG_POP_NEEDS_COMMENT;
371 equal (one, "ijklmn", 2); /* Basic test. */
373 (void) strcpy (one, "x");
374 DIAG_PUSH_NEEDS_COMMENT;
375 #if __GNUC_PREREQ (7, 0)
376 /* GCC 7 warns about the size passed to strncat being larger than
377 the size of the buffer; this is deliberately tested here.. */
378 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
379 #endif
380 (void) strncat (one, "yz", 99);
381 DIAG_POP_NEEDS_COMMENT;
382 equal (one, "xyz", 3); /* Writeover. */
383 equal (one+4, "mn", 4); /* Wrote too much? */
385 (void) strcpy (one, "gh");
386 (void) strcpy (two, "ef");
387 DIAG_PUSH_NEEDS_COMMENT;
388 #if __GNUC_PREREQ (7, 0)
389 /* GCC 7 warns about the size passed to strncat being larger than
390 the size of the buffer; this is deliberately tested here; GCC 8
391 gives a -Warray-bounds warning about this. */
392 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
393 #endif
394 DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds");
395 (void) strncat (one, two, 99);
396 DIAG_POP_NEEDS_COMMENT;
397 equal (one, "ghef", 5); /* Basic test encore. */
398 equal (two, "ef", 6); /* Stomped on source? */
400 (void) strcpy (one, "");
401 DIAG_PUSH_NEEDS_COMMENT;
402 #if __GNUC_PREREQ (7, 0)
403 /* GCC 7 warns about the size passed to strncat being larger than
404 the size of the buffer; this is deliberately tested here.. */
405 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
406 #endif
407 (void) strncat (one, "", 99);
408 DIAG_POP_NEEDS_COMMENT;
409 equal (one, "", 7); /* Boundary conditions. */
410 (void) strcpy (one, "ab");
411 DIAG_PUSH_NEEDS_COMMENT;
412 #if __GNUC_PREREQ (7, 0)
413 /* GCC 7 warns about the size passed to strncat being larger than
414 the size of the buffer; this is deliberately tested here.. */
415 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
416 #endif
417 (void) strncat (one, "", 99);
418 DIAG_POP_NEEDS_COMMENT;
419 equal (one, "ab", 8);
420 (void) strcpy (one, "");
421 DIAG_PUSH_NEEDS_COMMENT;
422 #if __GNUC_PREREQ (7, 0)
423 /* GCC 7 warns about the size passed to strncat being larger than
424 the size of the buffer; this is deliberately tested here.. */
425 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
426 #endif
427 (void) strncat (one, "cd", 99);
428 DIAG_POP_NEEDS_COMMENT;
429 equal (one, "cd", 9);
431 (void) strcpy (one, "ab");
432 DIAG_PUSH_NEEDS_COMMENT;
433 #if __GNUC_PREREQ (8, 0)
434 /* GCC 8 warns about strncat truncating output; this is deliberately
435 tested here. */
436 DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation");
437 #endif
438 (void) strncat (one, "cdef", 2);
439 DIAG_POP_NEEDS_COMMENT;
440 equal (one, "abcd", 10); /* Count-limited. */
442 (void) strncat (one, "gh", 0);
443 equal (one, "abcd", 11); /* Zero count. */
445 DIAG_PUSH_NEEDS_COMMENT;
446 #if __GNUC_PREREQ (7, 0)
447 /* GCC 8 warns about strncat bound equal to source length; this is
448 deliberately tested here. */
449 DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow=");
450 #endif
451 (void) strncat (one, "gh", 2);
452 DIAG_POP_NEEDS_COMMENT;
453 equal (one, "abcdgh", 12); /* Count and length equal. */
455 DIAG_PUSH_NEEDS_COMMENT;
456 #if __GNUC_PREREQ (7, 0)
457 /* GCC 7 warns about the size passed to strncat being larger than
458 the size of the buffer; this is deliberately tested here.. */
459 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
460 #endif
461 (void) strncat (one, "ij", (size_t)-1); /* set sign bit in count */
462 DIAG_POP_NEEDS_COMMENT;
463 equal (one, "abcdghij", 13);
465 int ntest = 14;
466 char buf1[80] __attribute__ ((aligned (16)));
467 char buf2[32] __attribute__ ((aligned (16)));
468 for (size_t n1 = 0; n1 < 16; ++n1)
469 for (size_t n2 = 0; n2 < 16; ++n2)
470 for (size_t n3 = 0; n3 < 32; ++n3)
471 for (size_t n4 = 0; n4 < 16; ++n4)
473 size_t olderrors = errors;
475 memset (buf1, 'b', sizeof (buf1));
477 memset (buf1 + n2, 'a', n3);
478 buf1[n2 + n3] = '\0';
479 strcpy (buf2 + n1, "123");
481 DIAG_PUSH_NEEDS_COMMENT;
482 #if __GNUC_PREREQ (7, 0)
483 /* GCC 7 warns about the size passed to strncat being
484 larger than the size of the buffer; this is
485 deliberately tested here; GCC 8 gives a -Warray-bounds
486 warning about this. */
487 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=");
488 /* GCC 9 as of 2018-06-14 warns that the size passed is
489 large enough that, if it were the actual object size,
490 the objects would have to overlap. */
491 DIAG_IGNORE_NEEDS_COMMENT (9, "-Wrestrict");
492 #endif
493 DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds");
494 check (strncat (buf1 + n2, buf2 + n1, ~((size_t) 0) - n4)
495 == buf1 + n2, ntest);
496 DIAG_POP_NEEDS_COMMENT;
497 if (errors == olderrors)
498 for (size_t i = 0; i < sizeof (buf1); ++i)
500 if (i < n2)
501 check (buf1[i] == 'b', ntest);
502 else if (i < n2 + n3)
503 check (buf1[i] == 'a', ntest);
504 else if (i < n2 + n3 + 3)
505 check (buf1[i] == "123"[i - (n2 + n3)], ntest);
506 else if (i == n2 + n3 + 3)
507 check (buf1[i] == '\0', ntest);
508 else
509 check (buf1[i] == 'b', ntest);
511 if (errors != olderrors)
513 printf ("n1=%zu, n2=%zu, n3=%zu, n4=%zu, buf1=%02hhx",
514 n1, n2, n3, n4, buf1[0]);
515 for (size_t j = 1; j < sizeof (buf1); ++j)
516 printf (",%02hhx", buf1[j]);
517 putchar_unlocked ('\n');
518 break;
524 static void
525 test_strncmp (void)
527 /* First test as strcmp with big counts, then test count code. */
528 it = "strncmp";
529 check (strncmp ("", "", 99) == 0, 1); /* Trivial case. */
530 check (strncmp ("a", "a", 99) == 0, 2); /* Identity. */
531 check (strncmp ("abc", "abc", 99) == 0, 3); /* Multicharacter. */
532 check (strncmp ("abc", "abcd", 99) < 0, 4); /* Length unequal. */
533 check (strncmp ("abcd", "abc", 99) > 0, 5);
534 check (strncmp ("abcd", "abce", 99) < 0, 6); /* Honestly unequal. */
535 check (strncmp ("abce", "abcd", 99) > 0, 7);
536 check (strncmp ("a\203", "a", 2) > 0, 8); /* Tricky if '\203' < 0 */
537 check (strncmp ("a\203", "a\003", 2) > 0, 9);
538 check (strncmp ("abce", "abcd", 3) == 0, 10); /* Count limited. */
539 check (strncmp ("abce", "abc", 3) == 0, 11); /* Count == length. */
540 check (strncmp ("abcd", "abce", 4) < 0, 12); /* Nudging limit. */
541 check (strncmp ("abc", "def", 0) == 0, 13); /* Zero count. */
542 check (strncmp ("abc", "", (size_t)-1) > 0, 14); /* set sign bit in count */
543 check (strncmp ("abc", "abc", (size_t)-2) == 0, 15);
546 static void
547 test_strncpy (void)
549 /* Testing is a bit different because of odd semantics. */
550 it = "strncpy";
551 check (strncpy (one, "abc", 4) == one, 1); /* Returned value. */
552 equal (one, "abc", 2); /* Did the copy go right? */
554 (void) strcpy (one, "abcdefgh");
555 DIAG_PUSH_NEEDS_COMMENT;
556 #if __GNUC_PREREQ (8, 0)
557 /* GCC 8 warns about strncpy truncating output; this is deliberately
558 tested here. */
559 DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation");
560 #endif
561 (void) strncpy (one, "xyz", 2);
562 DIAG_POP_NEEDS_COMMENT;
563 equal (one, "xycdefgh", 3); /* Copy cut by count. */
565 (void) strcpy (one, "abcdefgh");
566 DIAG_PUSH_NEEDS_COMMENT;
567 #if __GNUC_PREREQ (8, 0)
568 /* GCC 8 warns about strncpy truncating output; this is deliberately
569 tested here. */
570 DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation");
571 #endif
572 (void) strncpy (one, "xyz", 3); /* Copy cut just before NUL. */
573 DIAG_POP_NEEDS_COMMENT;
574 equal (one, "xyzdefgh", 4);
576 (void) strcpy (one, "abcdefgh");
577 (void) strncpy (one, "xyz", 4); /* Copy just includes NUL. */
578 equal (one, "xyz", 5);
579 equal (one+4, "efgh", 6); /* Wrote too much? */
581 (void) strcpy (one, "abcdefgh");
582 (void) strncpy (one, "xyz", 5); /* Copy includes padding. */
583 equal (one, "xyz", 7);
584 equal (one+4, "", 8);
585 equal (one+5, "fgh", 9);
587 (void) strcpy (one, "abc");
588 DIAG_PUSH_NEEDS_COMMENT;
589 #if __GNUC_PREREQ (8, 0)
590 /* GCC 8 warns about strncpy truncating output; this is deliberately
591 tested here. */
592 DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation");
593 #endif
594 (void) strncpy (one, "xyz", 0); /* Zero-length copy. */
595 DIAG_POP_NEEDS_COMMENT;
596 equal (one, "abc", 10);
598 (void) strncpy (one, "", 2); /* Zero-length source. */
599 equal (one, "", 11);
600 equal (one+1, "", 12);
601 equal (one+2, "c", 13);
603 (void) strcpy (one, "hi there");
604 (void) strncpy (two, one, 9);
605 equal (two, "hi there", 14); /* Just paranoia. */
606 equal (one, "hi there", 15); /* Stomped on source? */
609 static void
610 test_strlen (void)
612 it = "strlen";
613 check (strlen ("") == 0, 1); /* Empty. */
614 check (strlen ("a") == 1, 2); /* Single char. */
615 check (strlen ("abcd") == 4, 3); /* Multiple chars. */
617 char buf[4096];
618 int i;
619 char *p;
620 for (i=0; i < 0x100; i++)
622 p = (char *) ((unsigned long int)(buf + 0xff) & ~0xff) + i;
623 strcpy (p, "OK");
624 strcpy (p+3, "BAD/WRONG");
625 check (strlen (p) == 2, 4+i);
630 static void
631 test_strnlen (void)
633 it = "strnlen";
634 check (strnlen ("", 10) == 0, 1); /* Empty. */
635 check (strnlen ("a", 10) == 1, 2); /* Single char. */
636 check (strnlen ("abcd", 10) == 4, 3); /* Multiple chars. */
637 check (strnlen ("foo", (size_t) -1) == 3, 4); /* limits of n. */
638 check (strnlen ("abcd", 0) == 0, 5); /* Restricted. */
639 check (strnlen ("abcd", 1) == 1, 6); /* Restricted. */
640 check (strnlen ("abcd", 2) == 2, 7); /* Restricted. */
641 check (strnlen ("abcd", 3) == 3, 8); /* Restricted. */
642 check (strnlen ("abcd", 4) == 4, 9); /* Restricted. */
644 char buf[4096];
645 for (int i = 0; i < 0x100; ++i)
647 char *p = (char *) ((unsigned long int)(buf + 0xff) & ~0xff) + i;
648 strcpy (p, "OK");
649 strcpy (p + 3, "BAD/WRONG");
650 check (strnlen (p, 100) == 2, 10 + i);
654 static void
655 test_strchr (void)
657 it = "strchr";
658 check (strchr ("abcd", 'z') == NULL, 1); /* Not found. */
659 (void) strcpy (one, "abcd");
660 check (strchr (one, 'c') == one+2, 2); /* Basic test. */
661 check (strchr (one, 'd') == one+3, 3); /* End of string. */
662 check (strchr (one, 'a') == one, 4); /* Beginning. */
663 check (strchr (one, '\0') == one+4, 5); /* Finding NUL. */
664 (void) strcpy (one, "ababa");
665 check (strchr (one, 'b') == one+1, 6); /* Finding first. */
666 (void) strcpy (one, "");
667 check (strchr (one, 'b') == NULL, 7); /* Empty string. */
668 check (strchr (one, '\0') == one, 8); /* NUL in empty string. */
670 char buf[4096];
671 int i;
672 char *p;
673 for (i=0; i < 0x100; i++)
675 p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
676 strcpy (p, "OK");
677 strcpy (p+3, "BAD/WRONG");
678 check (strchr (p, '/') == NULL, 9+i);
683 static void
684 test_strchrnul (void)
686 const char *os;
687 it = "strchrnul";
688 cp = strchrnul ((os = "abcd"), 'z');
689 check (*cp == '\0', 1); /* Not found. */
690 check (cp == os + 4, 2);
691 (void) strcpy (one, "abcd");
692 check (strchrnul (one, 'c') == one+2, 3); /* Basic test. */
693 check (strchrnul (one, 'd') == one+3, 4); /* End of string. */
694 check (strchrnul (one, 'a') == one, 5); /* Beginning. */
695 check (strchrnul (one, '\0') == one+4, 6); /* Finding NUL. */
696 (void) strcpy (one, "ababa");
697 check (strchrnul (one, 'b') == one+1, 7); /* Finding first. */
698 (void) strcpy (one, "");
699 check (strchrnul (one, 'b') == one, 8); /* Empty string. */
700 check (strchrnul (one, '\0') == one, 9); /* NUL in empty string. */
702 char buf[4096];
703 int i;
704 char *p;
705 for (i=0; i < 0x100; i++)
707 p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
708 strcpy (p, "OK");
709 strcpy (p+3, "BAD/WRONG");
710 cp = strchrnul (p, '/');
711 check (*cp == '\0', 9+2*i);
712 check (cp == p+2, 10+2*i);
717 static void
718 test_rawmemchr (void)
720 it = "rawmemchr";
721 (void) strcpy (one, "abcd");
722 check (rawmemchr (one, 'c') == one+2, 1); /* Basic test. */
723 check (rawmemchr (one, 'd') == one+3, 2); /* End of string. */
724 check (rawmemchr (one, 'a') == one, 3); /* Beginning. */
725 check (rawmemchr (one, '\0') == one+4, 4); /* Finding NUL. */
726 (void) strcpy (one, "ababa");
727 check (rawmemchr (one, 'b') == one+1, 5); /* Finding first. */
728 (void) strcpy (one, "");
729 check (rawmemchr (one, '\0') == one, 6); /* NUL in empty string. */
731 char buf[4096];
732 int i;
733 char *p;
734 for (i=0; i < 0x100; i++)
736 p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
737 strcpy (p, "OK");
738 strcpy (p+3, "BAD/WRONG");
739 check (rawmemchr (p, 'R') == p+8, 6+i);
744 static void
745 test_index (void)
747 it = "index";
748 check (index ("abcd", 'z') == NULL, 1); /* Not found. */
749 (void) strcpy (one, "abcd");
750 check (index (one, 'c') == one+2, 2); /* Basic test. */
751 check (index (one, 'd') == one+3, 3); /* End of string. */
752 check (index (one, 'a') == one, 4); /* Beginning. */
753 check (index (one, '\0') == one+4, 5); /* Finding NUL. */
754 (void) strcpy (one, "ababa");
755 check (index (one, 'b') == one+1, 6); /* Finding first. */
756 (void) strcpy (one, "");
757 check (index (one, 'b') == NULL, 7); /* Empty string. */
758 check (index (one, '\0') == one, 8); /* NUL in empty string. */
761 static void
762 test_strrchr (void)
764 it = "strrchr";
765 check (strrchr ("abcd", 'z') == NULL, 1); /* Not found. */
766 (void) strcpy (one, "abcd");
767 check (strrchr (one, 'c') == one+2, 2); /* Basic test. */
768 check (strrchr (one, 'd') == one+3, 3); /* End of string. */
769 check (strrchr (one, 'a') == one, 4); /* Beginning. */
770 check (strrchr (one, '\0') == one+4, 5); /* Finding NUL. */
771 (void) strcpy (one, "ababa");
772 check (strrchr (one, 'b') == one+3, 6); /* Finding last. */
773 (void) strcpy (one, "");
774 check (strrchr (one, 'b') == NULL, 7); /* Empty string. */
775 check (strrchr (one, '\0') == one, 8); /* NUL in empty string. */
777 char buf[4096];
778 int i;
779 char *p;
780 for (i=0; i < 0x100; i++)
782 p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
783 strcpy (p, "OK");
784 strcpy (p+3, "BAD/WRONG");
785 check (strrchr (p, '/') == NULL, 9+i);
790 static void
791 test_memrchr (void)
793 size_t l;
794 it = "memrchr";
795 check (memrchr ("abcd", 'z', 5) == NULL, 1); /* Not found. */
796 (void) strcpy (one, "abcd");
797 l = strlen (one) + 1;
798 check (memrchr (one, 'c', l) == one+2, 2); /* Basic test. */
799 check (memrchr (one, 'd', l) == one+3, 3); /* End of string. */
800 check (memrchr (one, 'a', l) == one, 4); /* Beginning. */
801 check (memrchr (one, '\0', l) == one+4, 5); /* Finding NUL. */
802 (void) strcpy (one, "ababa");
803 l = strlen (one) + 1;
804 check (memrchr (one, 'b', l) == one+3, 6); /* Finding last. */
805 (void) strcpy (one, "");
806 l = strlen (one) + 1;
807 check (memrchr (one, 'b', l) == NULL, 7); /* Empty string. */
808 check (memrchr (one, '\0', l) == one, 8); /* NUL in empty string. */
810 /* now test all possible alignment and length combinations to catch
811 bugs due to unrolled loops (assuming unrolling is limited to no
812 more than 128 byte chunks: */
814 char buf[128 + sizeof(long)];
815 long align, len, i, pos, n = 9;
817 for (align = 0; align < (long) sizeof(long); ++align) {
818 for (len = 0; len < (long) (sizeof(buf) - align); ++len) {
819 for (i = 0; i < len; ++i)
820 buf[align + i] = 'x'; /* don't depend on memset... */
822 for (pos = len - 1; pos >= 0; --pos) {
823 #if 0
824 printf("align %d, len %d, pos %d\n", align, len, pos);
825 #endif
826 check(memrchr(buf + align, 'x', len) == buf + align + pos, n++);
827 check(memrchr(buf + align + pos + 1, 'x', len - (pos + 1)) == NULL,
828 n++);
829 buf[align + pos] = '-';
836 static void
837 test_rindex (void)
839 it = "rindex";
840 check (rindex ("abcd", 'z') == NULL, 1); /* Not found. */
841 (void) strcpy (one, "abcd");
842 check (rindex (one, 'c') == one+2, 2); /* Basic test. */
843 check (rindex (one, 'd') == one+3, 3); /* End of string. */
844 check (rindex (one, 'a') == one, 4); /* Beginning. */
845 check (rindex (one, '\0') == one+4, 5); /* Finding NUL. */
846 (void) strcpy (one, "ababa");
847 check (rindex (one, 'b') == one+3, 6); /* Finding last. */
848 (void) strcpy (one, "");
849 check (rindex (one, 'b') == NULL, 7); /* Empty string. */
850 check (rindex (one, '\0') == one, 8); /* NUL in empty string. */
853 static void
854 test_strpbrk (void)
856 it = "strpbrk";
857 check(strpbrk("abcd", "z") == NULL, 1); /* Not found. */
858 (void) strcpy(one, "abcd");
859 check(strpbrk(one, "c") == one+2, 2); /* Basic test. */
860 check(strpbrk(one, "d") == one+3, 3); /* End of string. */
861 check(strpbrk(one, "a") == one, 4); /* Beginning. */
862 check(strpbrk(one, "") == NULL, 5); /* Empty search list. */
863 check(strpbrk(one, "cb") == one+1, 6); /* Multiple search. */
864 (void) strcpy(one, "abcabdea");
865 check(strpbrk(one, "b") == one+1, 7); /* Finding first. */
866 check(strpbrk(one, "cb") == one+1, 8); /* With multiple search. */
867 check(strpbrk(one, "db") == one+1, 9); /* Another variant. */
868 (void) strcpy(one, "");
869 check(strpbrk(one, "bc") == NULL, 10); /* Empty string. */
870 (void) strcpy(one, "");
871 check(strpbrk(one, "bcd") == NULL, 11); /* Empty string. */
872 (void) strcpy(one, "");
873 check(strpbrk(one, "bcde") == NULL, 12); /* Empty string. */
874 check(strpbrk(one, "") == NULL, 13); /* Both strings empty. */
875 (void) strcpy(one, "abcabdea");
876 check(strpbrk(one, "befg") == one+1, 14); /* Finding first. */
877 check(strpbrk(one, "cbr") == one+1, 15); /* With multiple search. */
878 check(strpbrk(one, "db") == one+1, 16); /* Another variant. */
879 check(strpbrk(one, "efgh") == one+6, 17); /* And yet another. */
882 static void
883 test_strstr (void)
885 it = "strstr";
886 check(strstr("abcd", "z") == NULL, 1); /* Not found. */
887 check(strstr("abcd", "abx") == NULL, 2); /* Dead end. */
888 (void) strcpy(one, "abcd");
889 check(strstr(one, "c") == one+2, 3); /* Basic test. */
890 check(strstr(one, "bc") == one+1, 4); /* Multichar. */
891 check(strstr(one, "d") == one+3, 5); /* End of string. */
892 check(strstr(one, "cd") == one+2, 6); /* Tail of string. */
893 check(strstr(one, "abc") == one, 7); /* Beginning. */
894 check(strstr(one, "abcd") == one, 8); /* Exact match. */
895 check(strstr(one, "abcde") == NULL, 9); /* Too long. */
896 check(strstr(one, "de") == NULL, 10); /* Past end. */
897 check(strstr(one, "") == one, 11); /* Finding empty. */
898 (void) strcpy(one, "ababa");
899 check(strstr(one, "ba") == one+1, 12); /* Finding first. */
900 (void) strcpy(one, "");
901 check(strstr(one, "b") == NULL, 13); /* Empty string. */
902 check(strstr(one, "") == one, 14); /* Empty in empty string. */
903 (void) strcpy(one, "bcbca");
904 check(strstr(one, "bca") == one+2, 15); /* False start. */
905 (void) strcpy(one, "bbbcabbca");
906 check(strstr(one, "bbca") == one+1, 16); /* With overlap. */
909 static void
910 test_strspn (void)
912 it = "strspn";
913 check(strspn("abcba", "abc") == 5, 1); /* Whole string. */
914 check(strspn("abcba", "ab") == 2, 2); /* Partial. */
915 check(strspn("abc", "qx") == 0, 3); /* None. */
916 check(strspn("", "ab") == 0, 4); /* Null string. */
917 check(strspn("abc", "") == 0, 5); /* Null search list. */
920 static void
921 test_strcspn (void)
923 it = "strcspn";
924 check(strcspn("abcba", "qx") == 5, 1); /* Whole string. */
925 check(strcspn("abcba", "cx") == 2, 2); /* Partial. */
926 check(strcspn("abc", "abc") == 0, 3); /* None. */
927 check(strcspn("", "ab") == 0, 4); /* Null string. */
928 check(strcspn("abc", "") == 3, 5); /* Null search list. */
931 static void
932 test_strtok (void)
934 it = "strtok";
935 (void) strcpy(one, "first, second, third");
936 equal(strtok(one, ", "), "first", 1); /* Basic test. */
937 equal(one, "first", 2);
938 equal(strtok((char *)NULL, ", "), "second", 3);
939 equal(strtok((char *)NULL, ", "), "third", 4);
940 check(strtok((char *)NULL, ", ") == NULL, 5);
941 (void) strcpy(one, ", first, ");
942 equal(strtok(one, ", "), "first", 6); /* Extra delims, 1 tok. */
943 check(strtok((char *)NULL, ", ") == NULL, 7);
944 (void) strcpy(one, "1a, 1b; 2a, 2b");
945 equal(strtok(one, ", "), "1a", 8); /* Changing delim lists. */
946 equal(strtok((char *)NULL, "; "), "1b", 9);
947 equal(strtok((char *)NULL, ", "), "2a", 10);
948 (void) strcpy(two, "x-y");
949 equal(strtok(two, "-"), "x", 11); /* New string before done. */
950 equal(strtok((char *)NULL, "-"), "y", 12);
951 check(strtok((char *)NULL, "-") == NULL, 13);
952 (void) strcpy(one, "a,b, c,, ,d");
953 equal(strtok(one, ", "), "a", 14); /* Different separators. */
954 equal(strtok((char *)NULL, ", "), "b", 15);
955 equal(strtok((char *)NULL, " ,"), "c", 16); /* Permute list too. */
956 equal(strtok((char *)NULL, " ,"), "d", 17);
957 check(strtok((char *)NULL, ", ") == NULL, 18);
958 check(strtok((char *)NULL, ", ") == NULL, 19); /* Persistence. */
959 (void) strcpy(one, ", ");
960 check(strtok(one, ", ") == NULL, 20); /* No tokens. */
961 (void) strcpy(one, "");
962 check(strtok(one, ", ") == NULL, 21); /* Empty string. */
963 (void) strcpy(one, "abc");
964 equal(strtok(one, ", "), "abc", 22); /* No delimiters. */
965 check(strtok((char *)NULL, ", ") == NULL, 23);
966 (void) strcpy(one, "abc");
967 equal(strtok(one, ""), "abc", 24); /* Empty delimiter list. */
968 check(strtok((char *)NULL, "") == NULL, 25);
969 (void) strcpy(one, "abcdefgh");
970 (void) strcpy(one, "a,b,c");
971 equal(strtok(one, ","), "a", 26); /* Basics again... */
972 equal(strtok((char *)NULL, ","), "b", 27);
973 equal(strtok((char *)NULL, ","), "c", 28);
974 check(strtok((char *)NULL, ",") == NULL, 29);
975 equal(one+6, "gh", 30); /* Stomped past end? */
976 equal(one, "a", 31); /* Stomped old tokens? */
977 equal(one+2, "b", 32);
978 equal(one+4, "c", 33);
981 static void
982 test_strtok_r (void)
984 it = "strtok_r";
985 (void) strcpy(one, "first, second, third");
986 cp = NULL; /* Always initialize cp to make sure it doesn't point to some old data. */
987 equal(strtok_r(one, ", ", &cp), "first", 1); /* Basic test. */
988 equal(one, "first", 2);
989 equal(strtok_r((char *)NULL, ", ", &cp), "second", 3);
990 equal(strtok_r((char *)NULL, ", ", &cp), "third", 4);
991 check(strtok_r((char *)NULL, ", ", &cp) == NULL, 5);
992 (void) strcpy(one, ", first, ");
993 cp = NULL;
994 equal(strtok_r(one, ", ", &cp), "first", 6); /* Extra delims, 1 tok. */
995 check(strtok_r((char *)NULL, ", ", &cp) == NULL, 7);
996 (void) strcpy(one, "1a, 1b; 2a, 2b");
997 cp = NULL;
998 equal(strtok_r(one, ", ", &cp), "1a", 8); /* Changing delim lists. */
999 equal(strtok_r((char *)NULL, "; ", &cp), "1b", 9);
1000 equal(strtok_r((char *)NULL, ", ", &cp), "2a", 10);
1001 (void) strcpy(two, "x-y");
1002 cp = NULL;
1003 equal(strtok_r(two, "-", &cp), "x", 11); /* New string before done. */
1004 equal(strtok_r((char *)NULL, "-", &cp), "y", 12);
1005 check(strtok_r((char *)NULL, "-", &cp) == NULL, 13);
1006 (void) strcpy(one, "a,b, c,, ,d");
1007 cp = NULL;
1008 equal(strtok_r(one, ", ", &cp), "a", 14); /* Different separators. */
1009 equal(strtok_r((char *)NULL, ", ", &cp), "b", 15);
1010 equal(strtok_r((char *)NULL, " ,", &cp), "c", 16); /* Permute list too. */
1011 equal(strtok_r((char *)NULL, " ,", &cp), "d", 17);
1012 check(strtok_r((char *)NULL, ", ", &cp) == NULL, 18);
1013 check(strtok_r((char *)NULL, ", ", &cp) == NULL, 19); /* Persistence. */
1014 (void) strcpy(one, ", ");
1015 cp = NULL;
1016 check(strtok_r(one, ", ", &cp) == NULL, 20); /* No tokens. */
1017 (void) strcpy(one, "");
1018 cp = NULL;
1019 check(strtok_r(one, ", ", &cp) == NULL, 21); /* Empty string. */
1020 check(strtok_r((char *)NULL, ", ", &cp) == NULL, 22); /* Persistence. */
1021 (void) strcpy(one, "abc");
1022 cp = NULL;
1023 equal(strtok_r(one, ", ", &cp), "abc", 23); /* No delimiters. */
1024 check(strtok_r((char *)NULL, ", ", &cp) == NULL, 24);
1025 (void) strcpy(one, "abc");
1026 cp = NULL;
1027 equal(strtok_r(one, "", &cp), "abc", 25); /* Empty delimiter list. */
1028 check(strtok_r((char *)NULL, "", &cp) == NULL, 26);
1029 (void) strcpy(one, "abcdefgh");
1030 (void) strcpy(one, "a,b,c");
1031 cp = NULL;
1032 equal(strtok_r(one, ",", &cp), "a", 27); /* Basics again... */
1033 equal(strtok_r((char *)NULL, ",", &cp), "b", 28);
1034 equal(strtok_r((char *)NULL, ",", &cp), "c", 29);
1035 check(strtok_r((char *)NULL, ",", &cp) == NULL, 30);
1036 equal(one+6, "gh", 31); /* Stomped past end? */
1037 equal(one, "a", 32); /* Stomped old tokens? */
1038 equal(one+2, "b", 33);
1039 equal(one+4, "c", 34);
1040 strcpy (one, ":::");
1041 cp = NULL;
1042 check (strtok_r (one, ":", &cp) == NULL, 35); /* Must store pointer in cp. */
1043 check (strtok_r (NULL, ":", &cp) == NULL, 36);
1046 static void
1047 test_strsep (void)
1049 char *ptr;
1050 it = "strsep";
1051 cp = strcpy(one, "first, second, third");
1052 equal(strsep(&cp, ", "), "first", 1); /* Basic test. */
1053 equal(one, "first", 2);
1054 equal(strsep(&cp, ", "), "", 3);
1055 equal(strsep(&cp, ", "), "second", 4);
1056 equal(strsep(&cp, ", "), "", 5);
1057 equal(strsep(&cp, ", "), "third", 6);
1058 check(strsep(&cp, ", ") == NULL, 7);
1059 cp = strcpy(one, ", first, ");
1060 equal(strsep(&cp, ", "), "", 8);
1061 equal(strsep(&cp, ", "), "", 9);
1062 equal(strsep(&cp, ", "), "first", 10); /* Extra delims, 1 tok. */
1063 equal(strsep(&cp, ", "), "", 11);
1064 equal(strsep(&cp, ", "), "", 12);
1065 check(strsep(&cp, ", ") == NULL, 13);
1066 cp = strcpy(one, "1a, 1b; 2a, 2b");
1067 equal(strsep(&cp, ", "), "1a", 14); /* Changing delim lists. */
1068 equal(strsep(&cp, ", "), "", 15);
1069 equal(strsep(&cp, "; "), "1b", 16);
1070 equal(strsep(&cp, ", "), "", 17);
1071 equal(strsep(&cp, ", "), "2a", 18);
1072 cp = strcpy(two, "x-y");
1073 equal(strsep(&cp, "-"), "x", 19); /* New string before done. */
1074 equal(strsep(&cp, "-"), "y", 20);
1075 check(strsep(&cp, "-") == NULL, 21);
1076 cp = strcpy(one, "a,b, c,, ,d ");
1077 equal(strsep(&cp, ", "), "a", 22); /* Different separators. */
1078 equal(strsep(&cp, ", "), "b", 23);
1079 equal(strsep(&cp, " ,"), "", 24);
1080 equal(strsep(&cp, " ,"), "c", 25); /* Permute list too. */
1081 equal(strsep(&cp, " ,"), "", 26);
1082 equal(strsep(&cp, " ,"), "", 27);
1083 equal(strsep(&cp, " ,"), "", 28);
1084 equal(strsep(&cp, " ,"), "d", 29);
1085 equal(strsep(&cp, " ,"), "", 30);
1086 check(strsep(&cp, ", ") == NULL, 31);
1087 check(strsep(&cp, ", ") == NULL, 32); /* Persistence. */
1088 cp = strcpy(one, ", ");
1089 equal(strsep(&cp, ", "), "", 33);
1090 equal(strsep(&cp, ", "), "", 34);
1091 equal(strsep(&cp, ", "), "", 35);
1092 check(strsep(&cp, ", ") == NULL, 36); /* No tokens. */
1093 cp = strcpy(one, "");
1094 equal(strsep(&cp, ", "), "", 37);
1095 check(strsep(&cp, ", ") == NULL, 38); /* Empty string. */
1096 cp = strcpy(one, "abc");
1097 equal(strsep(&cp, ", "), "abc", 39); /* No delimiters. */
1098 check(strsep(&cp, ", ") == NULL, 40);
1099 cp = strcpy(one, "abc");
1100 equal(strsep(&cp, ""), "abc", 41); /* Empty delimiter list. */
1101 check(strsep(&cp, "") == NULL, 42);
1102 (void) strcpy(one, "abcdefgh");
1103 cp = strcpy(one, "a,b,c");
1104 equal(strsep(&cp, ","), "a", 43); /* Basics again... */
1105 equal(strsep(&cp, ","), "b", 44);
1106 equal(strsep(&cp, ","), "c", 45);
1107 check(strsep(&cp, ",") == NULL, 46);
1108 equal(one+6, "gh", 47); /* Stomped past end? */
1109 equal(one, "a", 48); /* Stomped old tokens? */
1110 equal(one+2, "b", 49);
1111 equal(one+4, "c", 50);
1114 char text[] = "This,is,a,test";
1115 char *list = strdupa (text);
1116 equal (strsep (&list, ","), "This", 51);
1117 equal (strsep (&list, ","), "is", 52);
1118 equal (strsep (&list, ","), "a", 53);
1119 equal (strsep (&list, ","), "test", 54);
1120 check (strsep (&list, ",") == NULL, 55);
1123 cp = strcpy(one, "a,b, c,, ,d,");
1124 equal(strsep(&cp, ","), "a", 56); /* Different separators. */
1125 equal(strsep(&cp, ","), "b", 57);
1126 equal(strsep(&cp, ","), " c", 58); /* Permute list too. */
1127 equal(strsep(&cp, ","), "", 59);
1128 equal(strsep(&cp, ","), " ", 60);
1129 equal(strsep(&cp, ","), "d", 61);
1130 equal(strsep(&cp, ","), "", 62);
1131 check(strsep(&cp, ",") == NULL, 63);
1132 check(strsep(&cp, ",") == NULL, 64); /* Persistence. */
1134 cp = strcpy(one, "a,b, c,, ,d,");
1135 equal(strsep(&cp, "xy,"), "a", 65); /* Different separators. */
1136 equal(strsep(&cp, "x,y"), "b", 66);
1137 equal(strsep(&cp, ",xy"), " c", 67); /* Permute list too. */
1138 equal(strsep(&cp, "xy,"), "", 68);
1139 equal(strsep(&cp, "x,y"), " ", 69);
1140 equal(strsep(&cp, ",xy"), "d", 70);
1141 equal(strsep(&cp, "xy,"), "", 71);
1142 check(strsep(&cp, "x,y") == NULL, 72);
1143 check(strsep(&cp, ",xy") == NULL, 73); /* Persistence. */
1145 cp = strcpy(one, "ABC");
1146 one[4] = ':';
1147 equal(strsep(&cp, "C"), "AB", 74); /* Access beyond NUL. */
1148 ptr = strsep(&cp, ":");
1149 equal(ptr, "", 75);
1150 check(ptr == one + 3, 76);
1151 check(cp == NULL, 77);
1153 cp = strcpy(one, "ABC");
1154 one[4] = ':';
1155 equal(strsep(&cp, "CD"), "AB", 78); /* Access beyond NUL. */
1156 ptr = strsep(&cp, ":.");
1157 equal(ptr, "", 79);
1158 check(ptr == one + 3, 80);
1160 cp = strcpy(one, "ABC"); /* No token in string. */
1161 equal(strsep(&cp, ","), "ABC", 81);
1162 check(cp == NULL, 82);
1164 *one = '\0'; /* Empty string. */
1165 cp = one;
1166 ptr = strsep(&cp, ",");
1167 equal(ptr, "", 83);
1168 check(ptr == one, 84);
1169 check(cp == NULL, 85);
1171 *one = '\0'; /* Empty string and no token. */
1172 cp = one;
1173 ptr = strsep(&cp, "");
1174 equal(ptr, "", 86);
1175 check(ptr == one , 87);
1176 check(cp == NULL, 88);
1179 static void
1180 test_memcmp (void)
1182 int cnt = 1;
1183 char one[21];
1184 char two[21];
1186 it = "memcmp";
1187 check(memcmp("a", "a", 1) == 0, cnt++); /* Identity. */
1188 check(memcmp("abc", "abc", 3) == 0, cnt++); /* Multicharacter. */
1189 check(memcmp("abcd", "abcf", 4) < 0, cnt++); /* Honestly unequal. */
1190 check(memcmp("abcf", "abcd", 4) > 0, cnt++);
1191 check(memcmp("alph", "cold", 4) < 0, cnt++);
1192 check(memcmp("a\203", "a\003", 2) > 0, cnt++);
1193 check(memcmp("a\003", "a\203", 2) < 0, cnt++);
1194 check(memcmp("a\003bc", "a\203bc", 2) < 0, cnt++);
1195 check(memcmp("abc\203", "abc\003", 4) > 0, cnt++);
1196 check(memcmp("abc\003", "abc\203", 4) < 0, cnt++);
1197 check(memcmp("abcf", "abcd", 3) == 0, cnt++); /* Count limited. */
1198 check(memcmp("abc", "def", 0) == 0, cnt++); /* Zero count. */
1199 /* Comparisons with shifting 4-byte boundaries. */
1200 for (int i = 0; i < 4; ++i)
1202 char *a = one + i;
1203 char *b = two + i;
1204 memcpy(a, "--------11112222", 16);
1205 memcpy(b, "--------33334444", 16);
1206 check(memcmp(b, a, 16) > 0, cnt++);
1207 check(memcmp(a, b, 16) < 0, cnt++);
1211 static void
1212 test_memchr (void)
1214 it = "memchr";
1215 check(memchr("abcd", 'z', 4) == NULL, 1); /* Not found. */
1216 (void) strcpy(one, "abcd");
1217 check(memchr(one, 'c', 4) == one+2, 2); /* Basic test. */
1218 check(memchr(one, ~0xff|'c', 4) == one+2, 2); /* ignore highorder bits. */
1219 check(memchr(one, 'd', 4) == one+3, 3); /* End of string. */
1220 check(memchr(one, 'a', 4) == one, 4); /* Beginning. */
1221 check(memchr(one, '\0', 5) == one+4, 5); /* Finding NUL. */
1222 (void) strcpy(one, "ababa");
1223 check(memchr(one, 'b', 5) == one+1, 6); /* Finding first. */
1224 check(memchr(one, 'b', 0) == NULL, 7); /* Zero count. */
1225 check(memchr(one, 'a', 1) == one, 8); /* Singleton case. */
1226 (void) strcpy(one, "a\203b");
1227 check(memchr(one, 0203, 3) == one+1, 9); /* Unsignedness. */
1229 /* now test all possible alignment and length combinations to catch
1230 bugs due to unrolled loops (assuming unrolling is limited to no
1231 more than 128 byte chunks: */
1233 char buf[128 + sizeof(long)];
1234 long align, len, i, pos;
1236 for (align = 0; align < (long) sizeof(long); ++align) {
1237 for (len = 0; len < (long) (sizeof(buf) - align); ++len) {
1238 for (i = 0; i < len; ++i) {
1239 buf[align + i] = 'x'; /* don't depend on memset... */
1241 for (pos = 0; pos < len; ++pos) {
1242 #if 0
1243 printf("align %d, len %d, pos %d\n", align, len, pos);
1244 #endif
1245 check(memchr(buf + align, 'x', len) == buf + align + pos, 10);
1246 check(memchr(buf + align, 'x', pos) == NULL, 11);
1247 buf[align + pos] = '-';
1254 static void
1255 test_memcpy (void)
1257 int i;
1258 it = "memcpy";
1259 check(memcpy(one, "abc", 4) == one, 1); /* Returned value. */
1260 equal(one, "abc", 2); /* Did the copy go right? */
1262 (void) strcpy(one, "abcdefgh");
1263 (void) memcpy(one+1, "xyz", 2);
1264 equal(one, "axydefgh", 3); /* Basic test. */
1266 (void) strcpy(one, "abc");
1267 (void) memcpy(one, "xyz", 0);
1268 equal(one, "abc", 4); /* Zero-length copy. */
1270 (void) strcpy(one, "hi there");
1271 (void) strcpy(two, "foo");
1272 (void) memcpy(two, one, 9);
1273 equal(two, "hi there", 5); /* Just paranoia. */
1274 equal(one, "hi there", 6); /* Stomped on source? */
1276 for (i = 0; i < 16; i++)
1278 const char *x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
1279 strcpy (one, x);
1280 check (memcpy (one + i, "hi there", 9) == one + i,
1281 7 + (i * 6)); /* Unaligned destination. */
1282 check (memcmp (one, x, i) == 0, 8 + (i * 6)); /* Wrote under? */
1283 equal (one + i, "hi there", 9 + (i * 6));
1284 check (one[i + 9] == 'x', 10 + (i * 6)); /* Wrote over? */
1285 check (memcpy (two, one + i, 9) == two,
1286 11 + (i * 6)); /* Unaligned source. */
1287 equal (two, "hi there", 12 + (i * 6));
1291 static void
1292 test_mempcpy (void)
1294 int i;
1295 it = "mempcpy";
1296 check(mempcpy(one, "abc", 4) == one + 4, 1); /* Returned value. */
1297 equal(one, "abc", 2); /* Did the copy go right? */
1299 (void) strcpy(one, "abcdefgh");
1300 (void) mempcpy(one+1, "xyz", 2);
1301 equal(one, "axydefgh", 3); /* Basic test. */
1303 (void) strcpy(one, "abc");
1304 (void) mempcpy(one, "xyz", 0);
1305 equal(one, "abc", 4); /* Zero-length copy. */
1307 (void) strcpy(one, "hi there");
1308 (void) strcpy(two, "foo");
1309 (void) mempcpy(two, one, 9);
1310 equal(two, "hi there", 5); /* Just paranoia. */
1311 equal(one, "hi there", 6); /* Stomped on source? */
1313 for (i = 0; i < 16; i++)
1315 const char *x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
1316 strcpy (one, x);
1317 check (mempcpy (one + i, "hi there", 9) == one + i + 9,
1318 7 + (i * 6)); /* Unaligned destination. */
1319 check (memcmp (one, x, i) == 0, 8 + (i * 6)); /* Wrote under? */
1320 equal (one + i, "hi there", 9 + (i * 6));
1321 check (one[i + 9] == 'x', 10 + (i * 6)); /* Wrote over? */
1322 check (mempcpy (two, one + i, 9) == two + 9,
1323 11 + (i * 6)); /* Unaligned source. */
1324 equal (two, "hi there", 12 + (i * 6));
1328 static void
1329 test_memmove (void)
1331 it = "memmove";
1332 check(memmove(one, "abc", 4) == one, 1); /* Returned value. */
1333 equal(one, "abc", 2); /* Did the copy go right? */
1335 (void) strcpy(one, "abcdefgh");
1336 (void) memmove(one+1, "xyz", 2);
1337 equal(one, "axydefgh", 3); /* Basic test. */
1339 (void) strcpy(one, "abc");
1340 (void) memmove(one, "xyz", 0);
1341 equal(one, "abc", 4); /* Zero-length copy. */
1343 (void) strcpy(one, "hi there");
1344 (void) strcpy(two, "foo");
1345 (void) memmove(two, one, 9);
1346 equal(two, "hi there", 5); /* Just paranoia. */
1347 equal(one, "hi there", 6); /* Stomped on source? */
1349 (void) strcpy(one, "abcdefgh");
1350 (void) memmove(one+1, one, 9);
1351 equal(one, "aabcdefgh", 7); /* Overlap, right-to-left. */
1353 (void) strcpy(one, "abcdefgh");
1354 (void) memmove(one+1, one+2, 7);
1355 equal(one, "acdefgh", 8); /* Overlap, left-to-right. */
1357 (void) strcpy(one, "abcdefgh");
1358 (void) memmove(one, one, 9);
1359 equal(one, "abcdefgh", 9); /* 100% overlap. */
1362 static void
1363 test_memccpy (void)
1365 /* First test like memcpy, then the search part The SVID, the only
1366 place where memccpy is mentioned, says overlap might fail, so we
1367 don't try it. Besides, it's hard to see the rationale for a
1368 non-left-to-right memccpy. */
1369 it = "memccpy";
1370 check(memccpy(one, "abc", 'q', 4) == NULL, 1); /* Returned value. */
1371 equal(one, "abc", 2); /* Did the copy go right? */
1373 (void) strcpy(one, "abcdefgh");
1374 (void) memccpy(one+1, "xyz", 'q', 2);
1375 equal(one, "axydefgh", 3); /* Basic test. */
1377 (void) strcpy(one, "abc");
1378 (void) memccpy(one, "xyz", 'q', 0);
1379 equal(one, "abc", 4); /* Zero-length copy. */
1381 (void) strcpy(one, "hi there");
1382 (void) strcpy(two, "foo");
1383 (void) memccpy(two, one, 'q', 9);
1384 equal(two, "hi there", 5); /* Just paranoia. */
1385 equal(one, "hi there", 6); /* Stomped on source? */
1387 (void) strcpy(one, "abcdefgh");
1388 (void) strcpy(two, "horsefeathers");
1389 check(memccpy(two, one, 'f', 9) == two+6, 7); /* Returned value. */
1390 equal(one, "abcdefgh", 8); /* Source intact? */
1391 equal(two, "abcdefeathers", 9); /* Copy correct? */
1393 (void) strcpy(one, "abcd");
1394 (void) strcpy(two, "bumblebee");
1395 check(memccpy(two, one, 'a', 4) == two+1, 10); /* First char. */
1396 equal(two, "aumblebee", 11);
1397 check(memccpy(two, one, 'd', 4) == two+4, 12); /* Last char. */
1398 equal(two, "abcdlebee", 13);
1399 (void) strcpy(one, "xyz");
1400 check(memccpy(two, one, 'x', 1) == two+1, 14); /* Singleton. */
1401 equal(two, "xbcdlebee", 15);
1404 static void
1405 test_memset (void)
1407 int i;
1409 it = "memset";
1410 (void) strcpy(one, "abcdefgh");
1411 check(memset(one+1, 'x', 3) == one+1, 1); /* Return value. */
1412 equal(one, "axxxefgh", 2); /* Basic test. */
1414 DIAG_PUSH_NEEDS_COMMENT;
1415 #if __GNUC_PREREQ (5, 0)
1416 /* GCC 5.0 warns about a zero-length memset because the arguments to memset
1417 may be in the wrong order. But we really want to test this. */
1418 DIAG_IGNORE_NEEDS_COMMENT (5.0, "-Wmemset-transposed-args")
1419 #endif
1420 (void) memset(one+2, 'y', 0);
1421 equal(one, "axxxefgh", 3); /* Zero-length set. */
1422 DIAG_POP_NEEDS_COMMENT;
1424 (void) memset(one+5, 0, 1);
1425 equal(one, "axxxe", 4); /* Zero fill. */
1426 equal(one+6, "gh", 5); /* And the leftover. */
1428 (void) memset(one+2, 010045, 1);
1429 equal(one, "ax\045xe", 6); /* Unsigned char convert. */
1431 /* Non-8bit fill character. */
1432 memset (one, 0x101, sizeof (one));
1433 for (i = 0; i < (int) sizeof (one); ++i)
1434 check (one[i] == '\01', 7);
1436 /* Test for more complex versions of memset, for all alignments and
1437 lengths up to 256. This test takes a little while, perhaps it should
1438 be made weaker? */
1440 char data[512];
1441 int j;
1442 int k;
1443 int c;
1445 for (i = 0; i < 512; i++)
1446 data[i] = 'x';
1447 for (c = 0; c <= 'y'; c += 'y') /* check for memset(,0,) and
1448 memset(,'y',) */
1449 for (j = 0; j < 256; j++)
1450 for (i = 0; i < 256; i++)
1452 memset (data + i, c, j);
1453 for (k = 0; k < i; k++)
1454 if (data[k] != 'x')
1455 goto fail;
1456 for (k = i; k < i+j; k++)
1458 if (data[k] != c)
1459 goto fail;
1460 data[k] = 'x';
1462 for (k = i+j; k < 512; k++)
1463 if (data[k] != 'x')
1464 goto fail;
1465 continue;
1467 fail:
1468 check (0, 8 + i + j * 256 + (c != 0) * 256 * 256);
1473 static void
1474 test_bcopy (void)
1476 /* Much like memcpy. Berklix manual is silent about overlap, so
1477 don't test it. */
1478 it = "bcopy";
1479 (void) bcopy("abc", one, 4);
1480 equal(one, "abc", 1); /* Simple copy. */
1482 (void) strcpy(one, "abcdefgh");
1483 (void) bcopy("xyz", one+1, 2);
1484 equal(one, "axydefgh", 2); /* Basic test. */
1486 (void) strcpy(one, "abc");
1487 (void) bcopy("xyz", one, 0);
1488 equal(one, "abc", 3); /* Zero-length copy. */
1490 (void) strcpy(one, "hi there");
1491 (void) strcpy(two, "foo");
1492 (void) bcopy(one, two, 9);
1493 equal(two, "hi there", 4); /* Just paranoia. */
1494 equal(one, "hi there", 5); /* Stomped on source? */
1497 static void
1498 test_bzero (void)
1500 it = "bzero";
1501 (void) strcpy(one, "abcdef");
1502 bzero(one+2, 2);
1503 equal(one, "ab", 1); /* Basic test. */
1504 equal(one+3, "", 2);
1505 equal(one+4, "ef", 3);
1507 (void) strcpy(one, "abcdef");
1508 bzero(one+2, 0);
1509 equal(one, "abcdef", 4); /* Zero-length copy. */
1512 static void
1513 test_strndup (void)
1515 char *p, *q;
1516 it = "strndup";
1517 p = strndup("abcdef", 12);
1518 check(p != NULL, 1);
1519 if (p != NULL)
1521 equal(p, "abcdef", 2);
1522 q = strndup(p + 1, 2);
1523 check(q != NULL, 3);
1524 if (q != NULL)
1525 equal(q, "bc", 4);
1526 free (q);
1528 free (p);
1529 p = strndup("abc def", 3);
1530 check(p != NULL, 5);
1531 if (p != NULL)
1532 equal(p, "abc", 6);
1533 free (p);
1536 static void
1537 test_bcmp (void)
1539 it = "bcmp";
1540 check(bcmp("a", "a", 1) == 0, 1); /* Identity. */
1541 check(bcmp("abc", "abc", 3) == 0, 2); /* Multicharacter. */
1542 check(bcmp("abcd", "abce", 4) != 0, 3); /* Honestly unequal. */
1543 check(bcmp("abce", "abcd", 4) != 0, 4);
1544 check(bcmp("alph", "beta", 4) != 0, 5);
1545 check(bcmp("abce", "abcd", 3) == 0, 6); /* Count limited. */
1546 check(bcmp("abc", "def", 0) == 0, 8); /* Zero count. */
1549 static void
1550 test_strerror (void)
1552 it = "strerror";
1553 check(strerror(EDOM) != 0, 1);
1554 check(strerror(ERANGE) != 0, 2);
1555 check(strerror(ENOENT) != 0, 3);
1558 static void
1559 test_strcasecmp (void)
1561 it = "strcasecmp";
1562 /* Note that the locale is "C". */
1563 check(strcasecmp("a", "a") == 0, 1);
1564 check(strcasecmp("a", "A") == 0, 2);
1565 check(strcasecmp("A", "a") == 0, 3);
1566 check(strcasecmp("a", "b") < 0, 4);
1567 check(strcasecmp("c", "b") > 0, 5);
1568 check(strcasecmp("abc", "AbC") == 0, 6);
1569 check(strcasecmp("0123456789", "0123456789") == 0, 7);
1570 check(strcasecmp("", "0123456789") < 0, 8);
1571 check(strcasecmp("AbC", "") > 0, 9);
1572 check(strcasecmp("AbC", "A") > 0, 10);
1573 check(strcasecmp("AbC", "Ab") > 0, 11);
1574 check(strcasecmp("AbC", "ab") > 0, 12);
1577 static void
1578 test_strncasecmp (void)
1580 it = "strncasecmp";
1581 /* Note that the locale is "C". */
1582 check(strncasecmp("a", "a", 5) == 0, 1);
1583 check(strncasecmp("a", "A", 5) == 0, 2);
1584 check(strncasecmp("A", "a", 5) == 0, 3);
1585 check(strncasecmp("a", "b", 5) < 0, 4);
1586 check(strncasecmp("c", "b", 5) > 0, 5);
1587 check(strncasecmp("abc", "AbC", 5) == 0, 6);
1588 check(strncasecmp("0123456789", "0123456789", 10) == 0, 7);
1589 check(strncasecmp("", "0123456789", 10) < 0, 8);
1590 check(strncasecmp("AbC", "", 5) > 0, 9);
1591 check(strncasecmp("AbC", "A", 5) > 0, 10);
1592 check(strncasecmp("AbC", "Ab", 5) > 0, 11);
1593 check(strncasecmp("AbC", "ab", 5) > 0, 12);
1594 check(strncasecmp("0123456789", "AbC", 0) == 0, 13);
1595 check(strncasecmp("AbC", "abc", 1) == 0, 14);
1596 check(strncasecmp("AbC", "abc", 2) == 0, 15);
1597 check(strncasecmp("AbC", "abc", 3) == 0, 16);
1598 check(strncasecmp("AbC", "abcd", 3) == 0, 17);
1599 check(strncasecmp("AbC", "abcd", 4) < 0, 18);
1600 check(strncasecmp("ADC", "abcd", 1) == 0, 19);
1601 check(strncasecmp("ADC", "abcd", 2) > 0, 20);
1605 main (void)
1607 int status;
1609 /* Test strcmp first because we use it to test other things. */
1610 test_strcmp ();
1612 /* Test strcpy next because we need it to set up other tests. */
1613 test_strcpy ();
1615 /* A closely related function is stpcpy. */
1616 test_stpcpy ();
1618 /* stpncpy. */
1619 test_stpncpy ();
1621 /* strcat. */
1622 test_strcat ();
1624 /* strncat. */
1625 test_strncat ();
1627 /* strncmp. */
1628 test_strncmp ();
1630 /* strncpy. */
1631 test_strncpy ();
1633 /* strlen. */
1634 test_strlen ();
1636 /* strnlen. */
1637 test_strnlen ();
1639 /* strchr. */
1640 test_strchr ();
1642 /* strchrnul. */
1643 test_strchrnul ();
1645 /* rawmemchr. */
1646 test_rawmemchr ();
1648 /* index - just like strchr. */
1649 test_index ();
1651 /* strrchr. */
1652 test_strrchr ();
1654 /* memrchr. */
1655 test_memrchr ();
1657 /* rindex - just like strrchr. */
1658 test_rindex ();
1660 /* strpbrk - somewhat like strchr. */
1661 test_strpbrk ();
1663 /* strstr - somewhat like strchr. */
1664 test_strstr ();
1666 /* strspn. */
1667 test_strspn ();
1669 /* strcspn. */
1670 test_strcspn ();
1672 /* strtok - the hard one. */
1673 test_strtok ();
1675 /* strtok_r. */
1676 test_strtok_r ();
1678 /* strsep. */
1679 test_strsep ();
1681 /* memcmp. */
1682 test_memcmp ();
1684 /* memchr. */
1685 test_memchr ();
1687 /* memcpy - need not work for overlap. */
1688 test_memcpy ();
1690 /* memmove - must work on overlap. */
1691 test_memmove ();
1693 /* mempcpy */
1694 test_mempcpy ();
1696 /* memccpy. */
1697 test_memccpy ();
1699 /* memset. */
1700 test_memset ();
1702 /* bcopy. */
1703 test_bcopy ();
1705 /* bzero. */
1706 test_bzero ();
1708 /* bcmp - somewhat like memcmp. */
1709 test_bcmp ();
1711 /* strndup. */
1712 test_strndup ();
1714 /* strerror - VERY system-dependent. */
1715 test_strerror ();
1717 /* strcasecmp. Without locale dependencies. */
1718 test_strcasecmp ();
1720 /* strncasecmp. Without locale dependencies. */
1721 test_strncasecmp ();
1723 if (errors == 0)
1725 status = EXIT_SUCCESS;
1726 puts("No errors.");
1728 else
1730 status = EXIT_FAILURE;
1731 printf("%Zd errors.\n", errors);
1734 return status;