4343#endif
4444
4545/* pass NULL into functions without triggering -Wnonnull */
46- extern void * NULL_ptr ;
46+ extern void * NULL_ptr ;
4747
4848//------------------------------------------------------------------------------
4949// Debug routines
@@ -177,6 +177,9 @@ char *T_strrchr(const char *s, int c)
177177char * T_strrstr (const char * haystack , const char * needle )
178178 __attribute__((nonnull (1 , 2 )));
179179
180+ char * T_strsep (char * * __restrict s , const char * __restrict delim )
181+ __attribute__((nonnull (1 , 2 )));
182+
180183char * T_strstr (const char * haystack , const char * needle )
181184 __attribute__((nonnull (1 , 2 )));
182185
@@ -217,6 +220,7 @@ char *T_strtok_r(char *__restrict s, const char *__restrict delim, char **__rest
217220#define T_strnlen strnlen
218221#define T_strrchr strrchr
219222#define T_strrstr strrstr
223+ #define T_strsep strsep
220224#define T_strstr strstr
221225#define T_strtok strtok
222226#define T_strtok_r strtok_r
@@ -529,11 +533,10 @@ int memccpy_tests(void) {
529533 char dest [sizeof src ];
530534 const char alt = '@' ;
531535
532- for (size_t i = 0 ; i != sizeof terminal ; ++ i )
533- {
536+ for (size_t i = 0 ; i != sizeof terminal ; ++ i ) {
534537 void * to = T_memccpy (dest , src , terminal [i ], sizeof dest );
535538
536- fprintf (file ,"Terminal '%c' (%s):\t\"" , terminal [i ], to ? "found" : "absent" );
539+ fprintf (file , "Terminal '%c' (%s):\t\"" , terminal [i ], to ? "found" : "absent" );
537540
538541 // if `terminal` character was not found - print the whole `dest`
539542 to = to ? to : dest + sizeof dest ;
@@ -545,7 +548,6 @@ int memccpy_tests(void) {
545548 fputs ("\"\n" , file );
546549 }
547550
548-
549551 fprintf (file , "%c%s" , '\n' , "Separate star names from distances (ly):\n" );
550552 const char * star_distance [] = {
551553 "Arcturus : 37" , "Vega : 25" , "Capella : 43" , "Rigel : 860" , "Procyon : 11"
@@ -554,8 +556,7 @@ int memccpy_tests(void) {
554556 char * first = names_only ;
555557 char * last = names_only + sizeof names_only ;
556558
557- for (size_t t = 0 ; t != (sizeof star_distance ) / (sizeof star_distance [0 ]); ++ t )
558- {
559+ for (size_t t = 0 ; t != (sizeof star_distance ) / (sizeof star_distance [0 ]); ++ t ) {
559560 if (first ) {
560561 first = T_memccpy (first , star_distance [t ], ' ' , last - first );
561562 } else {
@@ -1474,6 +1475,106 @@ int strtok_test(void) {
14741475 return 0 ;
14751476}
14761477
1478+ static char * truth_strsep (char * * __restrict stringp , const char * __restrict delim ) {
1479+ char * const begin_str = * stringp ;
1480+ if (begin_str == NULL ) {
1481+ return NULL ;
1482+ }
1483+ size_t length = strcspn (begin_str , delim );
1484+ char * end_str = begin_str + length ;
1485+ if (* end_str != '\0' ) {
1486+ * end_str ++ = '\0' ;
1487+ * stringp = end_str ;
1488+ } else {
1489+ * stringp = NULL ;
1490+ }
1491+ return begin_str ;
1492+ }
1493+
1494+ static int strsep_loop_test (char * str_1 , char * str_2 ) {
1495+ for (;;) {
1496+ char * __restrict prev_1 = T_strsep (& str_1 , ", ." );
1497+ char * __restrict prev_2 = truth_strsep (& str_2 , ", ." );
1498+ if (str_1 == NULL || str_2 == NULL ) {
1499+ break ;
1500+ }
1501+ ptrdiff_t diff_1 = (str_1 - prev_1 );
1502+ ptrdiff_t diff_2 = (str_2 - prev_2 );
1503+ if (diff_1 != diff_2 ) {
1504+ test_printf ("%td != %td\n%p %p\n1: %.20s\n2: %.20s\n" , diff_1 , diff_2 , prev_1 , prev_2 , str_1 , str_2 );
1505+ return __LINE__ ;
1506+ }
1507+ C (diff_1 == diff_2 );
1508+ }
1509+ C (str_1 == NULL && str_2 == NULL );
1510+ return 0 ;
1511+ }
1512+
1513+ int strsep_test (char * * dup_1 , char * * dup_2 ) {
1514+ {
1515+ char * ptr = NULL_ptr ;
1516+ C (T_strsep (& ptr , SINK ) == NULL );
1517+ C (T_strsep (& ptr , NULL_ptr ) == NULL );
1518+ C (T_strsep ((char * * )SINK , SINK ) == NULL );
1519+ C (T_strsep ((char * * )SINK , NULL_ptr ) == NULL );
1520+ }
1521+ {
1522+ // example taken straight from the man page
1523+ char * argv [] = {
1524+ NULL ,
1525+ "a/bbb///cc;xxx:yyy:" ,
1526+ ":;" ,
1527+ "/"
1528+ };
1529+ char * token , * subtoken ;
1530+
1531+ token = T_strsep ((char * * )& argv [1 ], argv [2 ]); C (strcmp_exact (token , "a/bbb///cc" ));
1532+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "a" ));
1533+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "bbb" ));
1534+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "" ));
1535+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "" ));
1536+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "cc" ));
1537+ subtoken = T_strsep (& token , argv [3 ]); C (subtoken == NULL );
1538+
1539+ token = T_strsep ((char * * )& argv [1 ], argv [2 ]); C (strcmp_exact (token , "xxx" ));
1540+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "xxx" ));
1541+ subtoken = T_strsep (& token , argv [3 ]); C (subtoken == NULL );
1542+
1543+ token = T_strsep ((char * * )& argv [1 ], argv [2 ]); C (strcmp_exact (token , "yyy" ));
1544+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "yyy" ));
1545+ subtoken = T_strsep (& token , argv [3 ]); C (subtoken == NULL );
1546+
1547+ token = T_strsep ((char * * )& argv [1 ], argv [2 ]); C (strcmp_exact (token , "" ));
1548+ subtoken = T_strsep (& token , argv [3 ]); C (strcmp_exact (subtoken , "" ));
1549+ subtoken = T_strsep (& token , argv [3 ]); C (subtoken == NULL );
1550+ }
1551+
1552+ const size_t len = strlen (gnu_copypasta );
1553+ const size_t size = len + 1 ;
1554+ * dup_1 = strdup (gnu_copypasta );
1555+ * dup_2 = strndup (gnu_copypasta , len );
1556+ C (* dup_1 != NULL && * dup_2 != NULL );
1557+ C (strcmp (* dup_1 , * dup_2 ) == 0 );
1558+ {
1559+ char * ptr , * prev ;
1560+ ptr = * dup_2 ;
1561+ prev = T_strsep (& ptr , "" );
1562+ C (ptr == NULL );
1563+ C (prev == * dup_2 );
1564+ ptr = * dup_2 ;
1565+ prev = T_strsep (& ptr , "zZ" );
1566+ C (ptr == NULL );
1567+ C (prev == * dup_2 );
1568+ C (memcmp (* dup_1 , * dup_2 , size ) == 0 );
1569+ }
1570+ {
1571+ int ret ;
1572+ TEST (strsep_loop_test (* dup_1 , * dup_2 ));
1573+ C (memcmp (* dup_1 , * dup_2 , size ) == 0 );
1574+ }
1575+ return 0 ;
1576+ }
1577+
14771578int mem65536_test (void ) {
14781579 void fill_mem32 (void * dst , size_t bytes , uint32_t pattern );
14791580
@@ -1592,6 +1693,17 @@ int run_tests(void) {
15921693 }
15931694 if (ret != 0 ) { return ret ; }
15941695
1696+ /* strsep */ {
1697+ char * dup_1 = SINK , * dup_2 = SINK ;
1698+ ret = strsep_test (& dup_1 , & dup_2 );
1699+ if (dup_1 == NULL || dup_2 == NULL ) {
1700+ perror ("str(n)dup returned NULL" );
1701+ }
1702+ free (dup_1 ); dup_1 = NULL ;
1703+ free (dup_2 ); dup_2 = NULL ;
1704+ if (ret != 0 ) { return ret ; }
1705+ }
1706+
15951707 TEST (mempcpy_test ());
15961708 TEST (bzero_test ());
15971709 TEST (strncmp_test ());
0 commit comments