diff --git a/ChangeLog b/ChangeLog index a1a27fbf56..bd320a2fb9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +1999-10-04 Ulrich Drepper + + * include/string.h: Add __memrchr declaration. + + * string/string.h: Moce __memrchr declaration to include/string.h. + +1999-10-03 Ulrich Drepper + + * string/Makefile (routines): Add memrchr. + + * sysdeps/generic/memrchr.c: Don't undef memchr, undef memrchr. + Correct order of tests for matching bytes. + + * string/tester.c: Add tests for memrchr. + + * sysdeps/i386/i486/bits/string.h (__memrchr): Correct implementation. + Start from the last character and take decrement not increment + into account for correction in return line. Add memrchr alias. + * sysdeps/i386/bits/string.h: Likewise. + 1999-10-04 Roland McGrath * stdlib/stdlib.h [__USE_BSD]: Declare getloadavg. diff --git a/include/string.h b/include/string.h index 4d610bab62..4cd64fb226 100644 --- a/include/string.h +++ b/include/string.h @@ -20,4 +20,6 @@ extern __ptr_t __rawmemchr __P ((__const __ptr_t __s, int __c)); extern char *__strchrnul __P ((__const char *__s, int __c)); +extern __ptr_t __memrchr __P ((__const __ptr_t __s, int __c, size_t __n)); + #endif diff --git a/string/string.h b/string/string.h index 03cf103ad6..a09d42a207 100644 --- a/string/string.h +++ b/string/string.h @@ -66,7 +66,6 @@ extern __ptr_t memchr __P ((__const __ptr_t __s, int __c, size_t __n)); extern __ptr_t rawmemchr __P ((__const __ptr_t __s, int __c)); /* Search N bytes of S for the final occurrence of C. */ -extern __ptr_t __memrchr __P ((__const __ptr_t __s, int __c, size_t __n)); extern __ptr_t memrchr __P ((__const __ptr_t __s, int __c, size_t __n)); #endif diff --git a/string/tester.c b/string/tester.c index 5105e4eea4..4fed10e4b4 100644 --- a/string/tester.c +++ b/string/tester.c @@ -563,6 +563,52 @@ test_strrchr (void) } } +void +test_memrchr (void) +{ + size_t l; + it = "memrchr"; + check (memrchr ("abcd", 'z', 5) == NULL, 1); /* Not found. */ + (void) strcpy (one, "abcd"); + l = strlen (one) + 1; + check (memrchr (one, 'c', l) == one+2, 2); /* Basic test. */ + check (memrchr (one, 'd', l) == one+3, 3); /* End of string. */ + check (memrchr (one, 'a', l) == one, 4); /* Beginning. */ + check (memrchr (one, '\0', l) == one+4, 5); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + l = strlen (one) + 1; + check (memrchr (one, 'b', l) == one+3, 6); /* Finding last. */ + (void) strcpy (one, ""); + l = strlen (one) + 1; + check (memrchr (one, 'b', l) == NULL, 7); /* Empty string. */ + check (memrchr (one, '\0', l) == one, 8); /* NUL in empty string. */ + + /* now test all possible alignment and length combinations to catch + bugs due to unrolled loops (assuming unrolling is limited to no + more than 128 byte chunks: */ + { + char buf[128 + sizeof(long)]; + long align, len, i, pos; + + for (align = 0; align < (long) sizeof(long); ++align) { + for (len = 0; len < (long) (sizeof(buf) - align); ++len) { + for (i = 0; i < len; ++i) + buf[align + i] = 'x'; /* don't depend on memset... */ + + for (pos = len - 1; pos >= 0; --pos) { +#if 0 + printf("align %d, len %d, pos %d\n", align, len, pos); +#endif + check(memrchr(buf + align, 'x', len) == buf + align + pos, 9); + check(memrchr(buf + align + pos + 1, 'x', len - (pos + 1)) == NULL, + 10); + buf[align + pos] = '-'; + } + } + } + } +} + void test_rindex (void) { @@ -1183,6 +1229,9 @@ main (void) /* strrchr. */ test_strrchr (); + /* memrchr. */ + test_memrchr (); + /* rindex - just like strrchr. */ test_rindex (); diff --git a/sysdeps/generic/memrchr.c b/sysdeps/generic/memrchr.c index c86625755b..874caf1072 100644 --- a/sysdeps/generic/memrchr.c +++ b/sysdeps/generic/memrchr.c @@ -51,6 +51,8 @@ #include +#undef memrchr + /* Search no more than N bytes of S for C. */ __ptr_t @@ -163,24 +165,24 @@ __memrchr (s, c_in, n) const unsigned char *cp = (const unsigned char *) longword_ptr; - if (cp[0] == c) - return (__ptr_t) cp; - if (cp[1] == c) - return (__ptr_t) &cp[1]; - if (cp[2] == c) - return (__ptr_t) &cp[2]; - if (cp[3] == c) - return (__ptr_t) &cp[3]; #if LONG_MAX > 2147483647 - if (cp[4] == c) - return (__ptr_t) &cp[4]; - if (cp[5] == c) - return (__ptr_t) &cp[5]; - if (cp[6] == c) - return (__ptr_t) &cp[6]; if (cp[7] == c) return (__ptr_t) &cp[7]; + if (cp[6] == c) + return (__ptr_t) &cp[6]; + if (cp[5] == c) + return (__ptr_t) &cp[5]; + if (cp[4] == c) + return (__ptr_t) &cp[4]; #endif + if (cp[3] == c) + return (__ptr_t) &cp[3]; + if (cp[2] == c) + return (__ptr_t) &cp[2]; + if (cp[1] == c) + return (__ptr_t) &cp[1]; + if (cp[0] == c) + return (__ptr_t) cp; } n -= sizeof (longword); diff --git a/sysdeps/i386/bits/string.h b/sysdeps/i386/bits/string.h index 01c17db68d..b727e2bc17 100644 --- a/sysdeps/i386/bits/string.h +++ b/sysdeps/i386/bits/string.h @@ -319,13 +319,16 @@ __memrchr (__const void *__s, int __c, size_t __n) ("std\n\t" "repne; scasb\n\t" "je 1f\n\t" - "movl $1,%0\n" + "orl $-1,%0\n" "1:\tcld" : "=D" (__res), "=&c" (__d0) - : "a" (__c), "0" (__s), "1" (__n) + : "a" (__c), "0" (__s + __n - 1), "1" (__n) : "cc"); - return __res - 1; + return __res + 1; } +# ifdef __USE_GNU +# define memrchr(s, c, n) __memrchr (s, c, n) +# endif #endif /* Return the length of S. */ diff --git a/sysdeps/i386/i486/bits/string.h b/sysdeps/i386/i486/bits/string.h index 9b37f5898e..54e5ac4620 100644 --- a/sysdeps/i386/i486/bits/string.h +++ b/sysdeps/i386/i486/bits/string.h @@ -452,34 +452,37 @@ __STRING_INLINE void * __memrchr (__const void *__s, int __c, size_t __n) { register unsigned long int __d0; -#ifdef __i686__ +# ifdef __i686__ register unsigned long int __d1; -#endif +# endif register void *__res; if (__n == 0) return NULL; -#ifdef __i686__ +# ifdef __i686__ __asm__ __volatile__ ("std\n\t" "repne; scasb\n\t" "cmovne %2,%0\n\t" "cld" : "=D" (__res), "=&c" (__d0), "=&r" (__d1) - : "a" (__c), "0" (__s), "1" (__n), "2" (1) + : "a" (__c), "0" (__s + __n - 1), "1" (__n), "2" (-1) : "cc"); -#else +# else __asm__ __volatile__ ("std\n\t" "repne; scasb\n\t" "je 1f\n\t" - "movl $1,%0\n" + "orl $-1,%0\n" "1:\tcld" : "=D" (__res), "=&c" (__d0) - : "a" (__c), "0" (__s), "1" (__n) + : "a" (__c), "0" (__s + __n - 1), "1" (__n) : "cc"); -#endif - return __res - 1; +# endif + return __res + 1; } +# ifdef __USE_GNU +# define memrchr(s, c, n) __memrchr (s, c, n) +# endif #endif /* Return pointer to C in S. */