diff options
Diffstat (limited to 'string')
71 files changed, 4818 insertions, 143 deletions
diff --git a/string/Makefile b/string/Makefile index 66469f586e..f087022b3c 100644 --- a/string/Makefile +++ b/string/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1991-1999,2000,2001,2002 Free Software Foundation, Inc. +# Copyright (C) 1991-2002, 2005, 2006, 2007 Free Software Foundation, Inc. # This file is part of the GNU C Library. # The GNU C Library is free software; you can redistribute it and/or @@ -52,8 +52,9 @@ strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ tests := tester inl-tester noinl-tester testcopy test-ffs \ tst-strlen stratcliff tst-svc tst-inlcall \ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \ - tst-strtok tst-strxfrm bug-strcoll1 \ - $(addprefix test-,$(strop-tests)) + tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \ + bug-strtok1 $(addprefix test-,$(strop-tests)) \ + bug-envz1 tst-strxfrm2 distribute := memcopy.h pagecopy.h tst-svc.expect test-string.h @@ -63,11 +64,14 @@ tester-ENV = LANGUAGE=C inl-tester-ENV = LANGUAGE=C noinl-tester-ENV = LANGUAGE=C tst-strxfrm-ENV = LOCPATH=$(common-objpfx)localedata +tst-strxfrm2-ENV = LOCPATH=$(common-objpfx)localedata bug-strcoll1-ENV = LOCPATH=$(common-objpfx)localedata +CFLAGS-inl-tester.c = -fno-builtin CFLAGS-noinl-tester.c = -fno-builtin CFLAGS-tst-strlen.c = -fno-builtin CFLAGS-stratcliff.c = -fno-builtin CFLAGS-test-ffs.c = -fno-builtin +CFLAGS-tst-inlcall.c = -fno-builtin ifeq ($(cross-compiling),no) tests: $(objpfx)tst-svc.out diff --git a/string/_strerror.c b/string/_strerror.c new file mode 100644 index 0000000000..cb5d9e3609 --- /dev/null +++ b/string/_strerror.c @@ -0,0 +1,68 @@ +/* Copyright (C) 1991,93,95,96,97,98,2000,2002,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <libintl.h> +#include <stdio.h> +#include <string.h> +#include <sys/param.h> +#include <stdio-common/_itoa.h> + +/* It is critical here that we always use the `dcgettext' function for + the message translation. Since <libintl.h> only defines the macro + `dgettext' to use `dcgettext' for optimizing programs this is not + always guaranteed. */ +#ifndef dgettext +# include <locale.h> /* We need LC_MESSAGES. */ +# define dgettext(domainname, msgid) dcgettext (domainname, msgid, LC_MESSAGES) +#endif + +/* Return a string describing the errno code in ERRNUM. */ +char * +__strerror_r (int errnum, char *buf, size_t buflen) +{ + if (__builtin_expect (errnum < 0 || errnum >= _sys_nerr_internal + || _sys_errlist_internal[errnum] == NULL, 0)) + { + /* Buffer we use to print the number in. For a maximum size for + `int' of 8 bytes we never need more than 20 digits. */ + char numbuf[21]; + const char *unk = _("Unknown error "); + const size_t unklen = strlen (unk); + char *p, *q; + + numbuf[20] = '\0'; + p = _itoa_word (errnum, &numbuf[20], 10, 0); + + /* Now construct the result while taking care for the destination + buffer size. */ + q = __mempcpy (buf, unk, MIN (unklen, buflen)); + if (unklen < buflen) + memcpy (q, p, MIN ((size_t) (&numbuf[21] - p), buflen - unklen)); + + /* Terminate the string in any case. */ + if (buflen > 0) + buf[buflen - 1] = '\0'; + + return buf; + } + + return (char *) _(_sys_errlist_internal[errnum]); +} +weak_alias (__strerror_r, strerror_r) +libc_hidden_def (__strerror_r) diff --git a/string/argz-replace.c b/string/argz-replace.c index 3c4062488e..1b0eb15fd7 100644 --- a/string/argz-replace.c +++ b/string/argz-replace.c @@ -1,5 +1,5 @@ /* String replacement in an argz vector - Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -121,8 +121,7 @@ __argz_replace (char **argz, size_t *argz_len, const char *str, const char *with if (! delayed_copy) /* We never found any instances of str. */ { - if (src) - free (src); + free (src); *argz = dst; *argz_len = dst_len; } diff --git a/string/bcopy.c b/string/bcopy.c new file mode 100644 index 0000000000..3f16b884ac --- /dev/null +++ b/string/bcopy.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1991, 1992, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> + +#define memmove bcopy +#define rettype void +#define RETURN(s) return +#define a1 src +#define a1const const +#define a2 dest +#define a2const + +#include <memmove.c> diff --git a/string/bits/string3.h b/string/bits/string3.h index 87cbe35bb1..041ac11259 100644 --- a/string/bits/string3.h +++ b/string/bits/string3.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 Free Software Foundation, Inc. +/* Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -44,10 +44,9 @@ ((__bos0 (dest) != (size_t) -1) \ ? __builtin___memcpy_chk (dest, src, len, __bos0 (dest)) \ : __memcpy_ichk (dest, src, len)) -static __inline__ void * -__attribute__ ((__always_inline__)) -__memcpy_ichk (void *__restrict __dest, const void *__restrict __src, - size_t __len) +static __always_inline void * +__NTH (__memcpy_ichk (void *__restrict __dest, __const void *__restrict __src, + size_t __len)) { return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest)); } @@ -57,9 +56,8 @@ __memcpy_ichk (void *__restrict __dest, const void *__restrict __src, ((__bos0 (dest) != (size_t) -1) \ ? __builtin___memmove_chk (dest, src, len, __bos0 (dest)) \ : __memmove_ichk (dest, src, len)) -static __inline__ void * -__attribute__ ((__always_inline__)) -__memmove_ichk (void *__dest, const void *__src, size_t __len) +static __always_inline void * +__NTH (__memmove_ichk (void *__dest, __const void *__src, size_t __len)) { return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest)); } @@ -70,23 +68,30 @@ __memmove_ichk (void *__dest, const void *__src, size_t __len) ((__bos0 (dest) != (size_t) -1) \ ? __builtin___mempcpy_chk (dest, src, len, __bos0 (dest)) \ : __mempcpy_ichk (dest, src, len)) -static __inline__ void * -__attribute__ ((__always_inline__)) -__mempcpy_ichk (void *__restrict __dest, const void *__restrict __src, - size_t __len) +static __always_inline void * +__NTH (__mempcpy_ichk (void *__restrict __dest, + __const void *__restrict __src, size_t __len)) { return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest)); } #endif +/* The first two tests here help to catch a somewhat common problem + where the second and third parameter are transposed. This is + especially problematic if the intended fill value is zero. In this + case no work is done at all. We detect these problems by referring + non-existing functions. */ +__warndecl (__warn_memset_zero_len, + "memset used with constant zero length parameter; this could be due to transposed parameters"); #define memset(dest, ch, len) \ - ((__bos0 (dest) != (size_t) -1) \ - ? __builtin___memset_chk (dest, ch, len, __bos0 (dest)) \ - : __memset_ichk (dest, ch, len)) -static __inline__ void * -__attribute__ ((__always_inline__)) -__memset_ichk (void *__dest, int __ch, size_t __len) + (__builtin_constant_p (len) && (len) == 0 \ + ? (__warn_memset_zero_len (), (void) (ch), (void) (len), (void *) (dest)) \ + : ((__bos0 (dest) != (size_t) -1) \ + ? __builtin___memset_chk (dest, ch, len, __bos0 (dest)) \ + : __memset_ichk (dest, ch, len))) +static __always_inline void * +__NTH (__memset_ichk (void *__dest, int __ch, size_t __len)) { return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest)); } @@ -107,9 +112,8 @@ __memset_ichk (void *__dest, int __ch, size_t __len) ((__bos (dest) != (size_t) -1) \ ? __builtin___strcpy_chk (dest, src, __bos (dest)) \ : __strcpy_ichk (dest, src)) -static __inline__ char * -__attribute__ ((__always_inline__)) -__strcpy_ichk (char *__restrict __dest, const char *__restrict __src) +static __always_inline char * +__NTH (__strcpy_ichk (char *__restrict __dest, __const char *__restrict __src)) { return __builtin___strcpy_chk (__dest, __src, __bos (__dest)); } @@ -120,9 +124,8 @@ __strcpy_ichk (char *__restrict __dest, const char *__restrict __src) ((__bos (dest) != (size_t) -1) \ ? __builtin___stpcpy_chk (dest, src, __bos (dest)) \ : __stpcpy_ichk (dest, src)) -static __inline__ char * -__attribute__ ((__always_inline__)) -__stpcpy_ichk (char *__restrict __dest, const char *__restrict __src) +static __always_inline char * +__NTH (__stpcpy_ichk (char *__restrict __dest, __const char *__restrict __src)) { return __builtin___stpcpy_chk (__dest, __src, __bos (__dest)); } @@ -133,22 +136,37 @@ __stpcpy_ichk (char *__restrict __dest, const char *__restrict __src) ((__bos (dest) != (size_t) -1) \ ? __builtin___strncpy_chk (dest, src, len, __bos (dest)) \ : __strncpy_ichk (dest, src, len)) -static __inline__ char * -__attribute__ ((__always_inline__)) -__strncpy_ichk (char *__restrict __dest, const char *__restrict __src, - size_t __len) +static __always_inline char * +__NTH (__strncpy_ichk (char *__restrict __dest, __const char *__restrict __src, + size_t __len)) { return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest)); } +// XXX We have no corresponding builtin yet. +extern char *__stpncpy_chk (char *__dest, __const char *__src, size_t __n, + size_t __destlen) __THROW; +extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, + __const char *__src, + size_t __n), stpncpy); + +extern __always_inline char * +__NTH (stpncpy (char *__dest, __const char *__src, size_t __n)) +{ + if (__bos (__dest) != (size_t) -1 + && (!__builtin_constant_p (__n) || __n <= __bos (__dest))) + return __stpncpy_chk (__dest, __src, __n, __bos (__dest)); + return __stpncpy_alias (__dest, __src, __n); +} + + #define strcat(dest, src) \ ((__bos (dest) != (size_t) -1) \ ? __builtin___strcat_chk (dest, src, __bos (dest)) \ : __strcat_ichk (dest, src)) -static __inline__ char * -__attribute__ ((__always_inline__)) -__strcat_ichk (char *__restrict __dest, const char *__restrict __src) +static __always_inline char * +__NTH (__strcat_ichk (char *__restrict __dest, __const char *__restrict __src)) { return __builtin___strcat_chk (__dest, __src, __bos (__dest)); } @@ -158,10 +176,9 @@ __strcat_ichk (char *__restrict __dest, const char *__restrict __src) ((__bos (dest) != (size_t) -1) \ ? __builtin___strncat_chk (dest, src, len, __bos (dest)) \ : __strncat_ichk (dest, src, len)) -static __inline__ char * -__attribute__ ((__always_inline__)) -__strncat_ichk (char *__restrict __dest, const char *__restrict __src, - size_t __len) +static __always_inline char * +__NTH (__strncat_ichk (char *__restrict __dest, __const char *__restrict __src, + size_t __len)) { return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest)); } diff --git a/string/bug-envz1.c b/string/bug-envz1.c new file mode 100644 index 0000000000..e8a60972b5 --- /dev/null +++ b/string/bug-envz1.c @@ -0,0 +1,76 @@ +/* Test for bug BZ #2703. */ +#include <stdio.h> +#include <envz.h> +#include <stdlib.h> +#include <string.h> + +static const struct +{ + const char *s; + int in_result; +} strs[] = +{ + { "a=1", 1 }, + { "b=2", 1 }, + { "(*)", 0 }, + { "(*)", 0 }, + { "e=5", 1 }, + { "f=", 1 }, + { "(*)", 0 }, + { "h=8", 1 }, + { "i=9", 1 }, + { "j", 0 } +}; + +#define nstrs (sizeof (strs) / sizeof (strs[0])) + + +static int +do_test (void) +{ + + size_t size = 0; + char *str = malloc (100); + if (str == NULL) + { + puts ("out of memory"); + return 1; + } + + char **argz = &str; + + for (int i = 0; i < nstrs; ++i) + argz_add_sep (argz, &size, strs[i].s, '\0'); + + printf ("calling envz_strip with size=%zu\n", size); + envz_strip (argz, &size); + + int result = 0; + printf ("new size=%zu\n", size); + for (int i = 0; i < nstrs; ++i) + if (strs[i].in_result) + { + char name[2]; + name[0] = strs[i].s[0]; + name[1] = '\0'; + + char *e = envz_entry (*argz, size, name); + if (e == NULL) + { + printf ("entry '%s' not found\n", name); + result = 1; + } + else if (strcmp (e, strs[i].s) != 0) + { + printf ("entry '%s' does not match: is '%s', expected '%s'\n", + name, e, strs[i].s); + result = 1; + } + } + + free (*argz); + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/string/bug-strtok1.c b/string/bug-strtok1.c new file mode 100644 index 0000000000..da30acf2e6 --- /dev/null +++ b/string/bug-strtok1.c @@ -0,0 +1,45 @@ +/* See BZ #2126. */ +#include <string.h> +#include <stdio.h> + +static int +do_test (void) +{ + const char str[] = "axaaba"; + char *token; + char *cp; + char *l; + int result = 0; + + puts ("test strtok"); + cp = strdupa (str); + printf ("cp = %p, len = %zu\n", cp, strlen (cp)); + token = strtok (cp, "ab"); + result |= token == NULL || strcmp (token, "x"); + printf ("token: %s (%d)\n", token ? token : "NULL", result); + token = strtok(0, "ab"); + result |= token != NULL; + printf ("token: %s (%d)\n", token ? token : "NULL", result); + token = strtok(0, "a"); + result |= token != NULL; + printf ("token: %s (%d)\n", token ? token : "NULL", result); + + puts ("test strtok_r"); + cp = strdupa (str); + size_t len = strlen (cp); + printf ("cp = %p, len = %zu\n", cp, len); + token = strtok_r (cp, "ab", &l); + result |= token == NULL || strcmp (token, "x"); + printf ("token: %s, next = %p (%d)\n", token ? token : "NULL", l, result); + token = strtok_r(0, "ab", &l); + result |= token != NULL || l != cp + len; + printf ("token: %s, next = %p (%d)\n", token ? token : "NULL", l, result); + token = strtok_r(0, "a", &l); + result |= token != NULL || l != cp + len; + printf ("token: %s, next = %p (%d)\n", token ? token : "NULL", l, result); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/string/bzero.c b/string/bzero.c new file mode 100644 index 0000000000..c6ede14139 --- /dev/null +++ b/string/bzero.c @@ -0,0 +1,83 @@ +/* Copyright (C) 1991, 1997, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> + +#undef __bzero + +/* Set N bytes of S to 0. */ +void +__bzero (s, len) + void *s; + size_t len; +{ + long int dstp = (long int) s; + const op_t zero = 0; + + if (len >= 8) + { + size_t xlen; + + /* There are at least some bytes to zero. No need to test + for LEN == 0 in this alignment loop. */ + while (dstp % OPSIZ != 0) + { + ((byte *) dstp)[0] = 0; + dstp += 1; + len -= 1; + } + + /* Write 8 op_t per iteration until less than 8 op_t remain. */ + xlen = len / (OPSIZ * 8); + while (xlen != 0) + { + ((op_t *) dstp)[0] = zero; + ((op_t *) dstp)[1] = zero; + ((op_t *) dstp)[2] = zero; + ((op_t *) dstp)[3] = zero; + ((op_t *) dstp)[4] = zero; + ((op_t *) dstp)[5] = zero; + ((op_t *) dstp)[6] = zero; + ((op_t *) dstp)[7] = zero; + dstp += 8 * OPSIZ; + xlen -= 1; + } + len %= OPSIZ * 8; + + /* Write 1 op_t per iteration until less than op_t remain. */ + xlen = len / OPSIZ; + while (xlen != 0) + { + ((op_t *) dstp)[0] = zero; + dstp += OPSIZ; + xlen -= 1; + } + len %= OPSIZ; + } + + /* Write the last few bytes. */ + while (len != 0) + { + ((byte *) dstp)[0] = 0; + dstp += 1; + len -= 1; + } +} +weak_alias (__bzero, bzero) diff --git a/string/envz.c b/string/envz.c index 5c5804c12b..a9d420212f 100644 --- a/string/envz.c +++ b/string/envz.c @@ -1,5 +1,5 @@ /* Routines for dealing with '\0' separated environment vectors - Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc. + Copyright (C) 1995-1998,2001,2002,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Miles Bader <miles@gnu.org> @@ -165,7 +165,7 @@ envz_strip (char **envz, size_t *envz_len) left -= entry_len; if (! strchr (entry, SEP)) /* Null entry. */ - memmove (entry + entry_len, entry, left); + memmove (entry, entry + entry_len, left); else entry += entry_len; } diff --git a/string/ffs.c b/string/ffs.c new file mode 100644 index 0000000000..06a1542bd9 --- /dev/null +++ b/string/ffs.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1991, 1992, 1997, 1998, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#define ffsl __something_else +#include <string.h> + +#undef ffs + +/* Find the first bit set in I. */ +int +__ffs (i) + int i; +{ + static const unsigned char table[] = + { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + unsigned int a; + unsigned int x = i & -i; + + a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24); + + return table[x >> a] + a; +} +weak_alias (__ffs, ffs) +libc_hidden_builtin_def (ffs) + +#if ULONG_MAX == UINT_MAX +#undef ffsl +weak_alias (__ffs, ffsl) +#endif diff --git a/string/ffsll.c b/string/ffsll.c new file mode 100644 index 0000000000..9dd269afb7 --- /dev/null +++ b/string/ffsll.c @@ -0,0 +1,42 @@ +/* Copyright (C) 1991, 1992, 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <limits.h> +#define ffsl __something_else +#include <string.h> + +#undef ffsll + +/* Find the first bit set in I. */ +int +ffsll (i) + long long int i; +{ + unsigned long long int x = i & -i; + + if (x <= 0xffffffff) + return ffs (i); + else + return 32 + ffs (i >> 32); +} + +#if ULONG_MAX != UINT_MAX +#undef ffsl +weak_alias (ffsll, ffsl) +#endif diff --git a/string/memccpy.c b/string/memccpy.c new file mode 100644 index 0000000000..9ffdc335d4 --- /dev/null +++ b/string/memccpy.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1991, 1995, 1997, 1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> + +#undef __memccpy +#undef memccpy + +/* Copy no more than N bytes of SRC to DEST, stopping when C is found. + Return the position in DEST one byte past where C was copied, or + NULL if C was not found in the first N bytes of SRC. */ +void * +__memccpy (dest, src, c, n) + void *dest; + const void *src; + int c; + size_t n; +{ + register const char *s = src; + register char *d = dest; + register const char x = c; + register size_t i = n; + + while (i-- > 0) + if ((*d++ = *s++) == x) + return d; + + return NULL; +} + +weak_alias (__memccpy, memccpy) diff --git a/string/memchr.c b/string/memchr.c new file mode 100644 index 0000000000..f3098c775a --- /dev/null +++ b/string/memchr.c @@ -0,0 +1,215 @@ +/* Copyright (C) 1991,93,96,97,99,2000,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Based on strlen implementation by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se) and + commentary by Jim Blandy (jimb@ai.mit.edu); + adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu), + and implemented by Roland McGrath (roland@ai.mit.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#undef __ptr_t +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +# define __ptr_t void * +#else /* Not C++ or ANSI C. */ +# define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined _LIBC +# include <string.h> +# include <memcopy.h> +#else +# define reg_char char +#endif + +#if HAVE_STDLIB_H || defined _LIBC +# include <stdlib.h> +#endif + +#if HAVE_LIMITS_H || defined _LIBC +# include <limits.h> +#endif + +#define LONG_MAX_32_BITS 2147483647 + +#ifndef LONG_MAX +#define LONG_MAX LONG_MAX_32_BITS +#endif + +#include <sys/types.h> +#if HAVE_BP_SYM_H || defined _LIBC +#include <bp-sym.h> +#else +# define BP_SYM(sym) sym +#endif + +#undef memchr +#undef __memchr + +/* Search no more than N bytes of S for C. */ +__ptr_t +__memchr (s, c_in, n) + const __ptr_t s; + int c_in; + size_t n; +{ + const unsigned char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, charmask; + unsigned reg_char c; + + c = (unsigned char) c_in; + + /* Handle the first few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s; + n > 0 && ((unsigned long int) char_ptr + & (sizeof (longword) - 1)) != 0; + --n, ++char_ptr) + if (*char_ptr == c) + return (__ptr_t) char_ptr; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + + if (sizeof (longword) != 4 && sizeof (longword) != 8) + abort (); + +#if LONG_MAX <= LONG_MAX_32_BITS + magic_bits = 0x7efefeff; +#else + magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff; +#endif + + /* Set up a longword, each of whose bytes is C. */ + charmask = c | (c << 8); + charmask |= charmask << 16; +#if LONG_MAX > LONG_MAX_32_BITS + charmask |= charmask << 32; +#endif + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + while (n >= sizeof (longword)) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. + + 3) But wait! Aren't we looking for C, not zero? + Good point. So what we do is XOR LONGWORD with a longword, + each of whose bytes is C. This turns each byte that is C + into a zero. */ + + longword = *longword_ptr++ ^ charmask; + + /* Add MAGIC_BITS to LONGWORD. */ + if ((((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) != 0) + { + /* Which of the bytes was C? If none of them were, it was + a misfire; continue the search. */ + + const unsigned char *cp = (const unsigned char *) (longword_ptr - 1); + + 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]; +#endif + } + + n -= sizeof (longword); + } + + char_ptr = (const unsigned char *) longword_ptr; + + while (n-- > 0) + { + if (*char_ptr == c) + return (__ptr_t) char_ptr; + else + ++char_ptr; + } + + return 0; +} +#ifdef weak_alias +weak_alias (__memchr, BP_SYM (memchr)) +#endif +libc_hidden_builtin_def (memchr) diff --git a/string/memcmp.c b/string/memcmp.c new file mode 100644 index 0000000000..2f8cf344af --- /dev/null +++ b/string/memcmp.c @@ -0,0 +1,381 @@ +/* Copyright (C) 1991,1993,1995,1997,1998,2003,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#undef __ptr_t +#if defined __cplusplus || (defined __STDC__ && __STDC__) +# define __ptr_t void * +#else /* Not C++ or ANSI C. */ +# undef const +# define const +# define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined HAVE_STRING_H || defined _LIBC +# include <string.h> +#endif + +#undef memcmp + +#ifdef _LIBC + +# include <memcopy.h> +# include <endian.h> + +# if __BYTE_ORDER == __BIG_ENDIAN +# define WORDS_BIGENDIAN +# endif + +#else /* Not in the GNU C library. */ + +# include <sys/types.h> + +/* Type to use for aligned memory operations. + This should normally be the biggest type supported by a single load + and store. Must be an unsigned type. */ +# define op_t unsigned long int +# define OPSIZ (sizeof(op_t)) + +/* Threshold value for when to enter the unrolled loops. */ +# define OP_T_THRES 16 + +/* Type to use for unaligned operations. */ +typedef unsigned char byte; + +# ifndef WORDS_BIGENDIAN +# define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2))) +# else +# define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2))) +# endif + +#endif /* In the GNU C library. */ + +#ifdef WORDS_BIGENDIAN +# define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1) +#else +# define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b)) +#endif + +/* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */ + +/* The strategy of this memcmp is: + + 1. Compare bytes until one of the block pointers is aligned. + + 2. Compare using memcmp_common_alignment or + memcmp_not_common_alignment, regarding the alignment of the other + block after the initial byte operations. The maximum number of + full words (of type op_t) are compared in this way. + + 3. Compare the few remaining bytes. */ + +#ifndef WORDS_BIGENDIAN +/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine. + A and B are known to be different. + This is needed only on little-endian machines. */ + +static int memcmp_bytes (op_t, op_t) __THROW; + +# ifdef __GNUC__ +__inline +# endif +static int +memcmp_bytes (a, b) + op_t a, b; +{ + long int srcp1 = (long int) &a; + long int srcp2 = (long int) &b; + op_t a0, b0; + + do + { + a0 = ((byte *) srcp1)[0]; + b0 = ((byte *) srcp2)[0]; + srcp1 += 1; + srcp2 += 1; + } + while (a0 == b0); + return a0 - b0; +} +#endif + +static int memcmp_common_alignment (long, long, size_t) __THROW; + +/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t' + objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for + memory operations on `op_t's. */ +static int +memcmp_common_alignment (srcp1, srcp2, len) + long int srcp1; + long int srcp2; + size_t len; +{ + op_t a0, a1; + op_t b0, b1; + + switch (len % 4) + { + default: /* Avoid warning about uninitialized local variables. */ + case 2: + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + srcp1 -= 2 * OPSIZ; + srcp2 -= 2 * OPSIZ; + len += 2; + goto do1; + case 3: + a1 = ((op_t *) srcp1)[0]; + b1 = ((op_t *) srcp2)[0]; + srcp1 -= OPSIZ; + srcp2 -= OPSIZ; + len += 1; + goto do2; + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return 0; + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + goto do3; + case 1: + a1 = ((op_t *) srcp1)[0]; + b1 = ((op_t *) srcp2)[0]; + srcp1 += OPSIZ; + srcp2 += OPSIZ; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + /* Fall through. */ + } + + do + { + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + if (a1 != b1) + return CMP_LT_OR_GT (a1, b1); + + do3: + a1 = ((op_t *) srcp1)[1]; + b1 = ((op_t *) srcp2)[1]; + if (a0 != b0) + return CMP_LT_OR_GT (a0, b0); + + do2: + a0 = ((op_t *) srcp1)[2]; + b0 = ((op_t *) srcp2)[2]; + if (a1 != b1) + return CMP_LT_OR_GT (a1, b1); + + do1: + a1 = ((op_t *) srcp1)[3]; + b1 = ((op_t *) srcp2)[3]; + if (a0 != b0) + return CMP_LT_OR_GT (a0, b0); + + srcp1 += 4 * OPSIZ; + srcp2 += 4 * OPSIZ; + len -= 4; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + if (a1 != b1) + return CMP_LT_OR_GT (a1, b1); + return 0; +} + +static int memcmp_not_common_alignment (long, long, size_t) __THROW; + +/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN + `op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory + operations on `op_t', but SRCP1 *should be unaligned*. */ +static int +memcmp_not_common_alignment (srcp1, srcp2, len) + long int srcp1; + long int srcp2; + size_t len; +{ + op_t a0, a1, a2, a3; + op_t b0, b1, b2, b3; + op_t x; + int shl, shr; + + /* Calculate how to shift a word read at the memory operation + aligned srcp1 to make it aligned for comparison. */ + + shl = 8 * (srcp1 % OPSIZ); + shr = 8 * OPSIZ - shl; + + /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t' + it points in the middle of. */ + srcp1 &= -OPSIZ; + + switch (len % 4) + { + default: /* Avoid warning about uninitialized local variables. */ + case 2: + a1 = ((op_t *) srcp1)[0]; + a2 = ((op_t *) srcp1)[1]; + b2 = ((op_t *) srcp2)[0]; + srcp1 -= 1 * OPSIZ; + srcp2 -= 2 * OPSIZ; + len += 2; + goto do1; + case 3: + a0 = ((op_t *) srcp1)[0]; + a1 = ((op_t *) srcp1)[1]; + b1 = ((op_t *) srcp2)[0]; + srcp2 -= 1 * OPSIZ; + len += 1; + goto do2; + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return 0; + a3 = ((op_t *) srcp1)[0]; + a0 = ((op_t *) srcp1)[1]; + b0 = ((op_t *) srcp2)[0]; + srcp1 += 1 * OPSIZ; + goto do3; + case 1: + a2 = ((op_t *) srcp1)[0]; + a3 = ((op_t *) srcp1)[1]; + b3 = ((op_t *) srcp2)[0]; + srcp1 += 2 * OPSIZ; + srcp2 += 1 * OPSIZ; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + /* Fall through. */ + } + + do + { + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + x = MERGE(a2, shl, a3, shr); + if (x != b3) + return CMP_LT_OR_GT (x, b3); + + do3: + a1 = ((op_t *) srcp1)[1]; + b1 = ((op_t *) srcp2)[1]; + x = MERGE(a3, shl, a0, shr); + if (x != b0) + return CMP_LT_OR_GT (x, b0); + + do2: + a2 = ((op_t *) srcp1)[2]; + b2 = ((op_t *) srcp2)[2]; + x = MERGE(a0, shl, a1, shr); + if (x != b1) + return CMP_LT_OR_GT (x, b1); + + do1: + a3 = ((op_t *) srcp1)[3]; + b3 = ((op_t *) srcp2)[3]; + x = MERGE(a1, shl, a2, shr); + if (x != b2) + return CMP_LT_OR_GT (x, b2); + + srcp1 += 4 * OPSIZ; + srcp2 += 4 * OPSIZ; + len -= 4; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + x = MERGE(a2, shl, a3, shr); + if (x != b3) + return CMP_LT_OR_GT (x, b3); + return 0; +} + +int +memcmp (s1, s2, len) + const __ptr_t s1; + const __ptr_t s2; + size_t len; +{ + op_t a0; + op_t b0; + long int srcp1 = (long int) s1; + long int srcp2 = (long int) s2; + op_t res; + + if (len >= OP_T_THRES) + { + /* There are at least some bytes to compare. No need to test + for LEN == 0 in this alignment loop. */ + while (srcp2 % OPSIZ != 0) + { + a0 = ((byte *) srcp1)[0]; + b0 = ((byte *) srcp2)[0]; + srcp1 += 1; + srcp2 += 1; + res = a0 - b0; + if (res != 0) + return res; + len -= 1; + } + + /* SRCP2 is now aligned for memory operations on `op_t'. + SRCP1 alignment determines if we can do a simple, + aligned compare or need to shuffle bits. */ + + if (srcp1 % OPSIZ == 0) + res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ); + else + res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ); + if (res != 0) + return res; + + /* Number of bytes remaining in the interval [0..OPSIZ-1]. */ + srcp1 += len & -OPSIZ; + srcp2 += len & -OPSIZ; + len %= OPSIZ; + } + + /* There are just a few bytes to compare. Use byte memory operations. */ + while (len != 0) + { + a0 = ((byte *) srcp1)[0]; + b0 = ((byte *) srcp2)[0]; + srcp1 += 1; + srcp2 += 1; + res = a0 - b0; + if (res != 0) + return res; + len -= 1; + } + + return 0; +} +libc_hidden_builtin_def(memcmp) +#ifdef weak_alias +# undef bcmp +weak_alias (memcmp, bcmp) +#endif diff --git a/string/memcpy.c b/string/memcpy.c new file mode 100644 index 0000000000..e167e85d7b --- /dev/null +++ b/string/memcpy.c @@ -0,0 +1,65 @@ +/* Copy memory to memory until the specified number of bytes + has been copied. Overlap is NOT handled correctly. + Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> +#include <pagecopy.h> + +#undef memcpy + +void * +memcpy (dstpp, srcpp, len) + void *dstpp; + const void *srcpp; + size_t len; +{ + unsigned long int dstp = (long int) dstpp; + unsigned long int srcp = (long int) srcpp; + + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); + + /* Copy whole pages from SRCP to DSTP by virtual address manipulation, + as much as possible. */ + + PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); + + /* Copy from SRCP to DSTP taking advantage of the known alignment of + DSTP. Number of bytes remaining is put in the third argument, + i.e. in LEN. This number may vary from machine to machine. */ + + WORD_COPY_FWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD (dstp, srcp, len); + + return dstpp; +} +libc_hidden_builtin_def (memcpy) diff --git a/string/memmem.c b/string/memmem.c new file mode 100644 index 0000000000..c40462104a --- /dev/null +++ b/string/memmem.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1991,92,93,94,96,97,98,2000,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <string.h> + +#ifndef _LIBC +# define __builtin_expect(expr, val) (expr) +#endif + +#undef memmem + +/* Return the first occurrence of NEEDLE in HAYSTACK. */ +void * +memmem (haystack, haystack_len, needle, needle_len) + const void *haystack; + size_t haystack_len; + const void *needle; + size_t needle_len; +{ + const char *begin; + const char *const last_possible + = (const char *) haystack + haystack_len - needle_len; + + if (needle_len == 0) + /* The first occurrence of the empty string is deemed to occur at + the beginning of the string. */ + return (void *) haystack; + + /* Sanity check, otherwise the loop might search through the whole + memory. */ + if (__builtin_expect (haystack_len < needle_len, 0)) + return NULL; + + for (begin = (const char *) haystack; begin <= last_possible; ++begin) + if (begin[0] == ((const char *) needle)[0] && + !memcmp ((const void *) &begin[1], + (const void *) ((const char *) needle + 1), + needle_len - 1)) + return (void *) begin; + + return NULL; +} diff --git a/string/memmove.c b/string/memmove.c new file mode 100644 index 0000000000..16671f7bb5 --- /dev/null +++ b/string/memmove.c @@ -0,0 +1,112 @@ +/* Copy memory to memory until the specified number of bytes + has been copied. Overlap is handled correctly. + Copyright (C) 1991, 1995, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> +#include <pagecopy.h> + +/* All this is so that bcopy.c can #include + this file after defining some things. */ +#ifndef a1 +#define a1 dest /* First arg is DEST. */ +#define a1const +#define a2 src /* Second arg is SRC. */ +#define a2const const +#undef memmove +#endif +#if !defined(RETURN) || !defined(rettype) +#define RETURN(s) return (s) /* Return DEST. */ +#define rettype void * +#endif + + +rettype +memmove (a1, a2, len) + a1const void *a1; + a2const void *a2; + size_t len; +{ + unsigned long int dstp = (long int) dest; + unsigned long int srcp = (long int) src; + + /* This test makes the forward copying code be used whenever possible. + Reduces the working set. */ + if (dstp - srcp >= len) /* *Unsigned* compare! */ + { + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); + + /* Copy whole pages from SRCP to DSTP by virtual address + manipulation, as much as possible. */ + + PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); + + /* Copy from SRCP to DSTP taking advantage of the known + alignment of DSTP. Number of bytes remaining is put + in the third argument, i.e. in LEN. This number may + vary from machine to machine. */ + + WORD_COPY_FWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD (dstp, srcp, len); + } + else + { + /* Copy from the end to the beginning. */ + srcp += len; + dstp += len; + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= dstp % OPSIZ; + BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ); + + /* Copy from SRCP to DSTP taking advantage of the known + alignment of DSTP. Number of bytes remaining is put + in the third argument, i.e. in LEN. This number may + vary from machine to machine. */ + + WORD_COPY_BWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_BWD (dstp, srcp, len); + } + + RETURN (dest); +} +#ifndef memmove +libc_hidden_builtin_def (memmove) +#endif diff --git a/string/mempcpy.c b/string/mempcpy.c new file mode 100644 index 0000000000..a72617e86f --- /dev/null +++ b/string/mempcpy.c @@ -0,0 +1,69 @@ +/* Copy memory to memory until the specified number of bytes + has been copied, return pointer to following byte. + Overlap is NOT handled correctly. + Copyright (C) 1991, 1997, 1998, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> +#include <pagecopy.h> + +#undef mempcpy +#undef __mempcpy + +void * +__mempcpy (dstpp, srcpp, len) + void *dstpp; + const void *srcpp; + size_t len; +{ + unsigned long int dstp = (long int) dstpp; + unsigned long int srcp = (long int) srcpp; + + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) + { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ); + + /* Copy whole pages from SRCP to DSTP by virtual address manipulation, + as much as possible. */ + + PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); + + /* Copy from SRCP to DSTP taking advantage of the known alignment of + DSTP. Number of bytes remaining is put in the third argument, + i.e. in LEN. This number may vary from machine to machine. */ + + WORD_COPY_FWD (dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD (dstp, srcp, len); + + return (void *) dstp; +} +libc_hidden_def (__mempcpy) +weak_alias (__mempcpy, mempcpy) +libc_hidden_builtin_def (mempcpy) diff --git a/string/memrchr.c b/string/memrchr.c new file mode 100644 index 0000000000..21662b1bd7 --- /dev/null +++ b/string/memrchr.c @@ -0,0 +1,210 @@ +/* memrchr -- find the last occurrence of a byte in a memory block + Copyright (C) 1991, 93, 96, 97, 99, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Based on strlen implementation by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se) and + commentary by Jim Blandy (jimb@ai.mit.edu); + adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu), + and implemented by Roland McGrath (roland@ai.mit.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef __ptr_t +#if defined __cplusplus || (defined __STDC__ && __STDC__) +# define __ptr_t void * +#else /* Not C++ or ANSI C. */ +# define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined _LIBC +# include <string.h> +# include <memcopy.h> +#else +# define reg_char char +#endif + +#if defined HAVE_LIMITS_H || defined _LIBC +# include <limits.h> +#endif + +#define LONG_MAX_32_BITS 2147483647 + +#ifndef LONG_MAX +# define LONG_MAX LONG_MAX_32_BITS +#endif + +#include <sys/types.h> + +#undef __memrchr +#undef memrchr + +#ifndef weak_alias +# define __memrchr memrchr +#endif + +/* Search no more than N bytes of S for C. */ +__ptr_t +__memrchr (s, c_in, n) + const __ptr_t s; + int c_in; + size_t n; +{ + const unsigned char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, charmask; + unsigned reg_char c; + + c = (unsigned char) c_in; + + /* Handle the last few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s + n; + n > 0 && ((unsigned long int) char_ptr + & (sizeof (longword) - 1)) != 0; + --n) + if (*--char_ptr == c) + return (__ptr_t) char_ptr; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (const unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + + if (sizeof (longword) != 4 && sizeof (longword) != 8) + abort (); + +#if LONG_MAX <= LONG_MAX_32_BITS + magic_bits = 0x7efefeff; +#else + magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff; +#endif + + /* Set up a longword, each of whose bytes is C. */ + charmask = c | (c << 8); + charmask |= charmask << 16; +#if LONG_MAX > LONG_MAX_32_BITS + charmask |= charmask << 32; +#endif + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + while (n >= sizeof (longword)) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. + + 3) But wait! Aren't we looking for C, not zero? + Good point. So what we do is XOR LONGWORD with a longword, + each of whose bytes is C. This turns each byte that is C + into a zero. */ + + longword = *--longword_ptr ^ charmask; + + /* Add MAGIC_BITS to LONGWORD. */ + if ((((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) != 0) + { + /* Which of the bytes was C? If none of them were, it was + a misfire; continue the search. */ + + const unsigned char *cp = (const unsigned char *) longword_ptr; + +#if LONG_MAX > 2147483647 + 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); + } + + char_ptr = (const unsigned char *) longword_ptr; + + while (n-- > 0) + { + if (*--char_ptr == c) + return (__ptr_t) char_ptr; + } + + return 0; +} +#ifdef weak_alias +weak_alias (__memrchr, memrchr) +#endif diff --git a/string/memset.c b/string/memset.c new file mode 100644 index 0000000000..592b11e435 --- /dev/null +++ b/string/memset.c @@ -0,0 +1,91 @@ +/* Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> + +#undef memset + +void * +memset (dstpp, c, len) + void *dstpp; + int c; + size_t len; +{ + long int dstp = (long int) dstpp; + + if (len >= 8) + { + size_t xlen; + op_t cccc; + + cccc = (unsigned char) c; + cccc |= cccc << 8; + cccc |= cccc << 16; + if (OPSIZ > 4) + /* Do the shift in two steps to avoid warning if long has 32 bits. */ + cccc |= (cccc << 16) << 16; + + /* There are at least some bytes to set. + No need to test for LEN == 0 in this alignment loop. */ + while (dstp % OPSIZ != 0) + { + ((byte *) dstp)[0] = c; + dstp += 1; + len -= 1; + } + + /* Write 8 `op_t' per iteration until less than 8 `op_t' remain. */ + xlen = len / (OPSIZ * 8); + while (xlen > 0) + { + ((op_t *) dstp)[0] = cccc; + ((op_t *) dstp)[1] = cccc; + ((op_t *) dstp)[2] = cccc; + ((op_t *) dstp)[3] = cccc; + ((op_t *) dstp)[4] = cccc; + ((op_t *) dstp)[5] = cccc; + ((op_t *) dstp)[6] = cccc; + ((op_t *) dstp)[7] = cccc; + dstp += 8 * OPSIZ; + xlen -= 1; + } + len %= OPSIZ * 8; + + /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain. */ + xlen = len / OPSIZ; + while (xlen > 0) + { + ((op_t *) dstp)[0] = cccc; + dstp += OPSIZ; + xlen -= 1; + } + len %= OPSIZ; + } + + /* Write the last few bytes. */ + while (len > 0) + { + ((byte *) dstp)[0] = c; + dstp += 1; + len -= 1; + } + + return dstpp; +} +libc_hidden_builtin_def (memset) diff --git a/string/rawmemchr.c b/string/rawmemchr.c new file mode 100644 index 0000000000..cb00ad7e90 --- /dev/null +++ b/string/rawmemchr.c @@ -0,0 +1,189 @@ +/* Copyright (C) 1991,93,96,97,99,2000,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Based on strlen implementation by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se) and + commentary by Jim Blandy (jimb@ai.mit.edu); + adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu), + and implemented by Roland McGrath (roland@ai.mit.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#undef __ptr_t +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +# define __ptr_t void * +#else /* Not C++ or ANSI C. */ +# define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined (_LIBC) +# include <string.h> +# include <memcopy.h> +# include <stdlib.h> +#else +# define reg_char char +#endif + +#if defined (HAVE_LIMITS_H) || defined (_LIBC) +# include <limits.h> +#endif + +#define LONG_MAX_32_BITS 2147483647 + +#ifndef LONG_MAX +#define LONG_MAX LONG_MAX_32_BITS +#endif + +#include <sys/types.h> + +#undef memchr + + +/* Find the first occurrence of C in S. */ +__ptr_t +__rawmemchr (s, c_in) + const __ptr_t s; + int c_in; +{ + const unsigned char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, charmask; + unsigned reg_char c; + + c = (unsigned char) c_in; + + /* Handle the first few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s; + ((unsigned long int) char_ptr & (sizeof (longword) - 1)) != 0; + ++char_ptr) + if (*char_ptr == c) + return (__ptr_t) char_ptr; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + + if (sizeof (longword) != 4 && sizeof (longword) != 8) + abort (); + +#if LONG_MAX <= LONG_MAX_32_BITS + magic_bits = 0x7efefeff; +#else + magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff; +#endif + + /* Set up a longword, each of whose bytes is C. */ + charmask = c | (c << 8); + charmask |= charmask << 16; +#if LONG_MAX > LONG_MAX_32_BITS + charmask |= charmask << 32; +#endif + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + while (1) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. + + 3) But wait! Aren't we looking for C, not zero? + Good point. So what we do is XOR LONGWORD with a longword, + each of whose bytes is C. This turns each byte that is C + into a zero. */ + + longword = *longword_ptr++ ^ charmask; + + /* Add MAGIC_BITS to LONGWORD. */ + if ((((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) != 0) + { + /* Which of the bytes was C? If none of them were, it was + a misfire; continue the search. */ + + const unsigned char *cp = (const unsigned char *) (longword_ptr - 1); + + 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]; +#endif + } + } +} +libc_hidden_def (__rawmemchr) +weak_alias (__rawmemchr, rawmemchr) diff --git a/string/stpcpy.c b/string/stpcpy.c new file mode 100644 index 0000000000..6e42911fde --- /dev/null +++ b/string/stpcpy.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1992, 1995, 1997, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#undef __stpcpy +#undef stpcpy + +#ifndef weak_alias +# define __stpcpy stpcpy +#endif + +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +char * +__stpcpy (dest, src) + char *dest; + const char *src; +{ + register char *d = dest; + register const char *s = src; + + do + *d++ = *s; + while (*s++ != '\0'); + + return d - 1; +} +#ifdef libc_hidden_def +libc_hidden_def (__stpcpy) +#endif +#ifdef weak_alias +weak_alias (__stpcpy, stpcpy) +#endif +#ifdef libc_hidden_builtin_def +libc_hidden_builtin_def (stpcpy) +#endif diff --git a/string/stpncpy.c b/string/stpncpy.c new file mode 100644 index 0000000000..164d0f1747 --- /dev/null +++ b/string/stpncpy.c @@ -0,0 +1,100 @@ +/* Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* This is almost copied from strncpy.c, written by Torbjorn Granlund. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef _LIBC +# include <string.h> +#else +# include <sys/types.h> +#endif + +#ifndef weak_alias +# define __stpncpy stpncpy +#endif + +/* Copy no more than N characters of SRC to DEST, returning the address of + the terminating '\0' in DEST, if any, or else DEST + N. */ +char * +__stpncpy (dest, src, n) + char *dest; + const char *src; + size_t n; +{ + char c; + char *s = dest; + + if (n >= 4) + { + size_t n4 = n >> 2; + + for (;;) + { + c = *src++; + *dest++ = c; + if (c == '\0') + break; + c = *src++; + *dest++ = c; + if (c == '\0') + break; + c = *src++; + *dest++ = c; + if (c == '\0') + break; + c = *src++; + *dest++ = c; + if (c == '\0') + break; + if (--n4 == 0) + goto last_chars; + } + n -= dest - s; + goto zero_fill; + } + + last_chars: + n &= 3; + if (n == 0) + return dest; + + for (;;) + { + c = *src++; + --n; + *dest++ = c; + if (c == '\0') + break; + if (n == 0) + return dest; + } + + zero_fill: + while (n-- > 0) + dest[n] = '\0'; + + return dest - 1; +} +#ifdef weak_alias +libc_hidden_def (__stpncpy) +weak_alias (__stpncpy, stpncpy) +#endif diff --git a/string/strcasecmp.c b/string/strcasecmp.c new file mode 100644 index 0000000000..3ae3d67d04 --- /dev/null +++ b/string/strcasecmp.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1991,1992,1995,1996,1997,2001,2002, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> +#include <string.h> + +#ifndef _LIBC +# define __strcasecmp strcasecmp +# define TOLOWER(Ch) tolower (Ch) +#else +# include <locale/localeinfo.h> +# ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define __strcasecmp __strcasecmp_l +# endif +# define TOLOWER(Ch) __tolower_l ((Ch), loc) +#endif + +#ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define LOCALE_PARAM , loc +# define LOCALE_PARAM_DECL __locale_t loc; +#else +# define LOCALE_PARAM +# define LOCALE_PARAM_DECL +#endif + +/* Compare S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexicographically less than, + equal to or greater than S2. */ +int +__strcasecmp (s1, s2 LOCALE_PARAM) + const char *s1; + const char *s2; + LOCALE_PARAM_DECL +{ +#if defined _LIBC && !defined USE_IN_EXTENDED_LOCALE_MODEL + __locale_t loc = _NL_CURRENT_LOCALE; +#endif + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + int result; + + if (p1 == p2) + return 0; + + while ((result = TOLOWER (*p1) - TOLOWER (*p2++)) == 0) + if (*p1++ == '\0') + break; + + return result; +} +#ifndef __strcasecmp +libc_hidden_def (__strcasecmp) +weak_alias (__strcasecmp, strcasecmp) +#endif diff --git a/string/strcasecmp_l.c b/string/strcasecmp_l.c new file mode 100644 index 0000000000..498a27d975 --- /dev/null +++ b/string/strcasecmp_l.c @@ -0,0 +1,23 @@ +/* Copyright (C) 1997, 2002, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define USE_IN_EXTENDED_LOCALE_MODEL 1 +#include "strcasecmp.c" + +libc_hidden_def (__strcasecmp_l) +weak_alias (__strcasecmp_l, strcasecmp_l) diff --git a/string/strcasestr.c b/string/strcasestr.c new file mode 100644 index 0000000000..1dde43c606 --- /dev/null +++ b/string/strcasestr.c @@ -0,0 +1,142 @@ +/* Return the offset of one string within another. + Copyright (C) 1994, 1996-2000, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * My personal strstr() implementation that beats most other algorithms. + * Until someone tells me otherwise, I assume that this is the + * fastest implementation of strstr() in C. + * I deliberately chose not to comment it. You should have at least + * as much fun trying to understand it, as I had to write it :-). + * + * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> + +#if defined _LIBC || defined HAVE_STRING_H +# include <string.h> +#endif + +#ifdef _LIBC +# include <locale/localeinfo.h> +# define TOLOWER(c) __tolower_l ((unsigned char) c, loc) +#else +# define TOLOWER(c) _tolower (c) +#endif + +typedef unsigned chartype; + +#undef strcasestr +#undef __strcasestr + +char * +__strcasestr (phaystack, pneedle) + const char *phaystack; + const char *pneedle; +{ + register const unsigned char *haystack, *needle; + register chartype b, c; +#ifdef _LIBC + __locale_t loc = _NL_CURRENT_LOCALE; +#endif + + haystack = (const unsigned char *) phaystack; + needle = (const unsigned char *) pneedle; + + b = TOLOWER (*needle); + if (b != '\0') + { + haystack--; /* possible ANSI violation */ + do + { + c = *++haystack; + if (c == '\0') + goto ret0; + } + while (TOLOWER (c) != (int) b); + + c = TOLOWER (*++needle); + if (c == '\0') + goto foundneedle; + ++needle; + goto jin; + + for (;;) + { + register chartype a; + register const unsigned char *rhaystack, *rneedle; + + do + { + a = *++haystack; + if (a == '\0') + goto ret0; + if (TOLOWER (a) == (int) b) + break; + a = *++haystack; + if (a == '\0') + goto ret0; +shloop: + ; + } + while (TOLOWER (a) != (int) b); + +jin: a = *++haystack; + if (a == '\0') + goto ret0; + + if (TOLOWER (a) != (int) c) + goto shloop; + + rhaystack = haystack-- + 1; + rneedle = needle; + a = TOLOWER (*rneedle); + + if (TOLOWER (*rhaystack) == (int) a) + do + { + if (a == '\0') + goto foundneedle; + ++rhaystack; + a = TOLOWER (*++needle); + if (TOLOWER (*rhaystack) != (int) a) + break; + if (a == '\0') + goto foundneedle; + ++rhaystack; + a = TOLOWER (*++needle); + } + while (TOLOWER (*rhaystack) == (int) a); + + needle = rneedle; /* took the register-poor approach */ + + if (a == '\0') + break; + } + } +foundneedle: + return (char*) haystack; +ret0: + return 0; +} + +weak_alias (__strcasestr, strcasestr) diff --git a/string/strcat.c b/string/strcat.c new file mode 100644 index 0000000000..eef22add36 --- /dev/null +++ b/string/strcat.c @@ -0,0 +1,52 @@ +/* Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> + +#undef strcat + +/* Append SRC on the end of DEST. */ +char * +strcat (dest, src) + char *dest; + const char *src; +{ + char *s1 = dest; + const char *s2 = src; + reg_char c; + + /* Find the end of the string. */ + do + c = *s1++; + while (c != '\0'); + + /* Make S1 point before the next character, so we can increment + it while memory is read (wins on pipelined cpus). */ + s1 -= 2; + + do + { + c = *s2++; + *++s1 = c; + } + while (c != '\0'); + + return dest; +} +libc_hidden_builtin_def (strcat) diff --git a/string/strchr.c b/string/strchr.c new file mode 100644 index 0000000000..5afd364533 --- /dev/null +++ b/string/strchr.c @@ -0,0 +1,191 @@ +/* Copyright (C) 1991,1993-1997,1999,2000,2003,2006 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Based on strlen implementation by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se) and + bug fix and commentary by Jim Blandy (jimb@ai.mit.edu); + adaptation to strchr suggested by Dick Karpinski (dick@cca.ucsf.edu), + and implemented by Roland McGrath (roland@ai.mit.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> +#include <stdlib.h> + +#undef strchr + +/* Find the first occurrence of C in S. */ +char * +strchr (s, c_in) + const char *s; + int c_in; +{ + const unsigned char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, charmask; + unsigned reg_char c; + + c = (unsigned char) c_in; + + /* Handle the first few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s; + ((unsigned long int) char_ptr & (sizeof (longword) - 1)) != 0; + ++char_ptr) + if (*char_ptr == c) + return (void *) char_ptr; + else if (*char_ptr == '\0') + return NULL; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + switch (sizeof (longword)) + { + case 4: magic_bits = 0x7efefeffL; break; + case 8: magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL; break; + default: + abort (); + } + + /* Set up a longword, each of whose bytes is C. */ + charmask = c | (c << 8); + charmask |= charmask << 16; + if (sizeof (longword) > 4) + /* Do the shift in two steps to avoid a warning if long has 32 bits. */ + charmask |= (charmask << 16) << 16; + if (sizeof (longword) > 8) + abort (); + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + for (;;) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. + + 3) But wait! Aren't we looking for C as well as zero? + Good point. So what we do is XOR LONGWORD with a longword, + each of whose bytes is C. This turns each byte that is C + into a zero. */ + + longword = *longword_ptr++; + + /* Add MAGIC_BITS to LONGWORD. */ + if ((((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) != 0 || + + /* That caught zeroes. Now test for C. */ + ((((longword ^ charmask) + magic_bits) ^ ~(longword ^ charmask)) + & ~magic_bits) != 0) + { + /* Which of the bytes was C or zero? + If none of them were, it was a misfire; continue the search. */ + + const unsigned char *cp = (const unsigned char *) (longword_ptr - 1); + + if (*cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + if (*++cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + if (*++cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + if (*++cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + if (sizeof (longword) > 4) + { + if (*++cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + if (*++cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + if (*++cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + if (*++cp == c) + return (char *) cp; + else if (*cp == '\0') + return NULL; + } + } + } + + return NULL; +} + +#ifdef weak_alias +#undef index +weak_alias (strchr, index) +#endif +libc_hidden_builtin_def (strchr) diff --git a/string/strchrnul.c b/string/strchrnul.c new file mode 100644 index 0000000000..88b96dd126 --- /dev/null +++ b/string/strchrnul.c @@ -0,0 +1,170 @@ +/* Copyright (C) 1991,1993-1997,99,2000,2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Based on strlen implementation by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se) and + bug fix and commentary by Jim Blandy (jimb@ai.mit.edu); + adaptation to strchr suggested by Dick Karpinski (dick@cca.ucsf.edu), + and implemented by Roland McGrath (roland@ai.mit.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> +#include <stdlib.h> + +#undef __strchrnul +#undef strchrnul + +/* Find the first occurrence of C in S or the final NUL byte. */ +char * +__strchrnul (s, c_in) + const char *s; + int c_in; +{ + const unsigned char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, charmask; + unsigned reg_char c; + + c = (unsigned char) c_in; + + /* Handle the first few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s; + ((unsigned long int) char_ptr & (sizeof (longword) - 1)) != 0; + ++char_ptr) + if (*char_ptr == c || *char_ptr == '\0') + return (void *) char_ptr; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + switch (sizeof (longword)) + { + case 4: magic_bits = 0x7efefeffL; break; + case 8: magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL; break; + default: + abort (); + } + + /* Set up a longword, each of whose bytes is C. */ + charmask = c | (c << 8); + charmask |= charmask << 16; + if (sizeof (longword) > 4) + /* Do the shift in two steps to avoid a warning if long has 32 bits. */ + charmask |= (charmask << 16) << 16; + if (sizeof (longword) > 8) + abort (); + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + for (;;) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. + + 3) But wait! Aren't we looking for C as well as zero? + Good point. So what we do is XOR LONGWORD with a longword, + each of whose bytes is C. This turns each byte that is C + into a zero. */ + + longword = *longword_ptr++; + + /* Add MAGIC_BITS to LONGWORD. */ + if ((((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) != 0 || + + /* That caught zeroes. Now test for C. */ + ((((longword ^ charmask) + magic_bits) ^ ~(longword ^ charmask)) + & ~magic_bits) != 0) + { + /* Which of the bytes was C or zero? + If none of them were, it was a misfire; continue the search. */ + + const unsigned char *cp = (const unsigned char *) (longword_ptr - 1); + + if (*cp == c || *cp == '\0') + return (char *) cp; + if (*++cp == c || *cp == '\0') + return (char *) cp; + if (*++cp == c || *cp == '\0') + return (char *) cp; + if (*++cp == c || *cp == '\0') + return (char *) cp; + if (sizeof (longword) > 4) + { + if (*++cp == c || *cp == '\0') + return (char *) cp; + if (*++cp == c || *cp == '\0') + return (char *) cp; + if (*++cp == c || *cp == '\0') + return (char *) cp; + if (*++cp == c || *cp == '\0') + return (char *) cp; + } + } + } + + /* This should never happen. */ + return NULL; +} + +weak_alias (__strchrnul, strchrnul) diff --git a/string/strcmp.c b/string/strcmp.c new file mode 100644 index 0000000000..bd53c05c6e --- /dev/null +++ b/string/strcmp.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1991, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> + +#undef strcmp + +/* Compare S1 and S2, returning less than, equal to or + greater than zero if S1 is lexicographically less than, + equal to or greater than S2. */ +int +strcmp (p1, p2) + const char *p1; + const char *p2; +{ + register const unsigned char *s1 = (const unsigned char *) p1; + register const unsigned char *s2 = (const unsigned char *) p2; + unsigned reg_char c1, c2; + + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } + while (c1 == c2); + + return c1 - c2; +} +libc_hidden_builtin_def (strcmp) diff --git a/string/strcoll.c b/string/strcoll.c index 8a73cae564..8e8fdc7792 100644 --- a/string/strcoll.c +++ b/string/strcoll.c @@ -23,6 +23,7 @@ # define STRING_TYPE char # define STRCOLL strcoll # define STRCOLL_L __strcoll_l +# define USE_HIDDEN_DEF #endif #include "../locale/localeinfo.h" @@ -35,6 +36,7 @@ STRCOLL (s1, s2) { return STRCOLL_L (s1, s2, _NL_CURRENT_LOCALE); } -#if !defined WIDE_CHAR_VERSION -libc_hidden_def (strcoll) + +#ifdef USE_HIDDEN_DEF +libc_hidden_def (STRCOLL) #endif diff --git a/string/strcpy.c b/string/strcpy.c new file mode 100644 index 0000000000..c736a60762 --- /dev/null +++ b/string/strcpy.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1991, 1997, 2000, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stddef.h> +#include <string.h> +#include <memcopy.h> +#include <bp-checks.h> + +#undef strcpy + +/* Copy SRC to DEST. */ +char * +strcpy (dest, src) + char *dest; + const char *src; +{ + reg_char c; + char *__unbounded s = (char *__unbounded) CHECK_BOUNDS_LOW (src); + const ptrdiff_t off = CHECK_BOUNDS_LOW (dest) - s - 1; + size_t n; + + do + { + c = *s++; + s[off] = c; + } + while (c != '\0'); + + n = s - src; + (void) CHECK_BOUNDS_HIGH (src + n); + (void) CHECK_BOUNDS_HIGH (dest + n); + + return dest; +} +libc_hidden_builtin_def (strcpy) diff --git a/string/strcspn.c b/string/strcspn.c new file mode 100644 index 0000000000..f359d578f7 --- /dev/null +++ b/string/strcspn.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1991, 1994, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined _LIBC || HAVE_STRING_H +# include <string.h> +#else +# include <strings.h> +# ifndef strchr +# define strchr index +# endif +#endif + +#undef strcspn + +/* Return the length of the maximum initial segment of S + which contains no characters from REJECT. */ +size_t +strcspn (s, reject) + const char *s; + const char *reject; +{ + size_t count = 0; + + while (*s != '\0') + if (strchr (reject, *s++) == NULL) + ++count; + else + return count; + + return count; +} +libc_hidden_builtin_def (strcspn) diff --git a/string/string-inlines.c b/string/string-inlines.c new file mode 100644 index 0000000000..89a5baab5d --- /dev/null +++ b/string/string-inlines.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* <bits/string.h> and <bits/string2.h> declare some extern inline + functions. These functions are declared additionally here if + inlining is not possible. */ + +#undef __USE_STRING_INLINES +#define __USE_STRING_INLINES +#define _FORCE_INLINES +#define __STRING_INLINE /* empty */ +#define __NO_INLINE__ + +#include <string.h> +#undef index +#undef rindex + +#undef __NO_INLINE__ +#include <bits/string.h> +#include <bits/string2.h> diff --git a/string/strlen.c b/string/strlen.c new file mode 100644 index 0000000000..9bc9db68f7 --- /dev/null +++ b/string/strlen.c @@ -0,0 +1,153 @@ +/* Copyright (C) 1991, 1993, 1997, 2000, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se); + commentary by Jim Blandy (jimb@ai.mit.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <stdlib.h> + +#undef strlen + +/* Return the length of the null-terminated string STR. Scan for + the null terminator quickly by testing four bytes at a time. */ +size_t +strlen (str) + const char *str; +{ + const char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, himagic, lomagic; + + /* Handle the first few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = str; ((unsigned long int) char_ptr + & (sizeof (longword) - 1)) != 0; + ++char_ptr) + if (*char_ptr == '\0') + return char_ptr - str; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + magic_bits = 0x7efefeffL; + himagic = 0x80808080L; + lomagic = 0x01010101L; + if (sizeof (longword) > 4) + { + /* 64-bit version of the magic. */ + /* Do the shift in two steps to avoid a warning if long has 32 bits. */ + magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL; + himagic = ((himagic << 16) << 16) | himagic; + lomagic = ((lomagic << 16) << 16) | lomagic; + } + if (sizeof (longword) > 8) + abort (); + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + for (;;) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. */ + + longword = *longword_ptr++; + + if ( +#if 0 + /* Add MAGIC_BITS to LONGWORD. */ + (((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) +#else + ((longword - lomagic) & himagic) +#endif + != 0) + { + /* Which of the bytes was the zero? If none of them were, it was + a misfire; continue the search. */ + + const char *cp = (const char *) (longword_ptr - 1); + + if (cp[0] == 0) + return cp - str; + if (cp[1] == 0) + return cp - str + 1; + if (cp[2] == 0) + return cp - str + 2; + if (cp[3] == 0) + return cp - str + 3; + if (sizeof (longword) > 4) + { + if (cp[4] == 0) + return cp - str + 4; + if (cp[5] == 0) + return cp - str + 5; + if (cp[6] == 0) + return cp - str + 6; + if (cp[7] == 0) + return cp - str + 7; + } + } + } +} +libc_hidden_builtin_def (strlen) diff --git a/string/strncase.c b/string/strncase.c new file mode 100644 index 0000000000..a55aaf6a3a --- /dev/null +++ b/string/strncase.c @@ -0,0 +1,76 @@ +/* Compare at most N characters of two strings without taking care for + the case. + Copyright (C) 1992, 1996, 1997, 2001, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <ctype.h> + +#ifndef weak_alias +# define __strncasecmp strncasecmp +# define TOLOWER(Ch) tolower (Ch) +#else +# include <locale/localeinfo.h> +# ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define __strncasecmp __strncasecmp_l +# endif +# define TOLOWER(Ch) __tolower_l ((Ch), loc) +#endif + +#ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define LOCALE_PARAM , loc +# define LOCALE_PARAM_DECL __locale_t loc; +#else +# define LOCALE_PARAM +# define LOCALE_PARAM_DECL +#endif + +/* Compare no more than N characters of S1 and S2, + ignoring case, returning less than, equal to or + greater than zero if S1 is lexicographically less + than, equal to or greater than S2. */ +int +__strncasecmp (s1, s2, n LOCALE_PARAM) + const char *s1; + const char *s2; + size_t n; + LOCALE_PARAM_DECL +{ +#if defined _LIBC && !defined USE_IN_EXTENDED_LOCALE_MODEL + __locale_t loc = _NL_CURRENT_LOCALE; +#endif + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + int result; + + if (p1 == p2 || n == 0) + return 0; + + while ((result = TOLOWER (*p1) - TOLOWER (*p2++)) == 0) + if (*p1++ == '\0' || --n == 0) + break; + + return result; +} +#ifndef __strncasecmp +weak_alias (__strncasecmp, strncasecmp) +#endif diff --git a/string/strncase_l.c b/string/strncase_l.c new file mode 100644 index 0000000000..0f22b46de1 --- /dev/null +++ b/string/strncase_l.c @@ -0,0 +1,25 @@ +/* Compare at most N characters of two strings without taking care for + the case using given locale. + Copyright (C) 1997, 2002, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define USE_IN_EXTENDED_LOCALE_MODEL 1 +#include "strncase.c" + +libc_hidden_def (__strncasecmp_l) +weak_alias (__strncasecmp_l, strncasecmp_l) diff --git a/string/strncat.c b/string/strncat.c new file mode 100644 index 0000000000..2e2de11508 --- /dev/null +++ b/string/strncat.c @@ -0,0 +1,85 @@ +/* Copyright (C) 1991, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> + +#ifdef _LIBC +# include <memcopy.h> +#else +typedef char reg_char; +#endif + +#undef strncat + +char * +strncat (s1, s2, n) + char *s1; + const char *s2; + size_t n; +{ + reg_char c; + char *s = s1; + + /* Find the end of S1. */ + do + c = *s1++; + while (c != '\0'); + + /* Make S1 point before next character, so we can increment + it while memory is read (wins on pipelined cpus). */ + s1 -= 2; + + if (n >= 4) + { + size_t n4 = n >> 2; + do + { + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + } while (--n4 > 0); + n &= 3; + } + + while (n > 0) + { + c = *s2++; + *++s1 = c; + if (c == '\0') + return s; + n--; + } + + if (c != '\0') + *++s1 = '\0'; + + return s; +} diff --git a/string/strncmp.c b/string/strncmp.c new file mode 100644 index 0000000000..1adb2c0ebd --- /dev/null +++ b/string/strncmp.c @@ -0,0 +1,73 @@ +/* Copyright (C) 1991, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> + +#undef strncmp + +/* Compare no more than N characters of S1 and S2, + returning less than, equal to or greater than zero + if S1 is lexicographically less than, equal to or + greater than S2. */ +int +strncmp (s1, s2, n) + const char *s1; + const char *s2; + size_t n; +{ + unsigned reg_char c1 = '\0'; + unsigned reg_char c2 = '\0'; + + if (n >= 4) + { + size_t n4 = n >> 2; + do + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + } while (--n4 > 0); + n &= 3; + } + + while (n > 0) + { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0' || c1 != c2) + return c1 - c2; + n--; + } + + return c1 - c2; +} +libc_hidden_builtin_def (strncmp) diff --git a/string/strncpy.c b/string/strncpy.c new file mode 100644 index 0000000000..f32612e1cf --- /dev/null +++ b/string/strncpy.c @@ -0,0 +1,87 @@ +/* Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> +#include <memcopy.h> + +#undef strncpy + +char * +strncpy (s1, s2, n) + char *s1; + const char *s2; + size_t n; +{ + reg_char c; + char *s = s1; + + --s1; + + if (n >= 4) + { + size_t n4 = n >> 2; + + for (;;) + { + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + c = *s2++; + *++s1 = c; + if (c == '\0') + break; + if (--n4 == 0) + goto last_chars; + } + n = n - (s1 - s) - 1; + if (n == 0) + return s; + goto zero_fill; + } + + last_chars: + n &= 3; + if (n == 0) + return s; + + do + { + c = *s2++; + *++s1 = c; + if (--n == 0) + return s; + } + while (c != '\0'); + + zero_fill: + do + *++s1 = '\0'; + while (--n > 0); + + return s; +} +libc_hidden_builtin_def (strncpy) diff --git a/string/strnlen.c b/string/strnlen.c new file mode 100644 index 0000000000..454257b2bc --- /dev/null +++ b/string/strnlen.c @@ -0,0 +1,161 @@ +/* Find the length of STRING, but scan at most MAXLEN characters. + Copyright (C) 1991,1993,1997,2000,2001,2005 Free Software Foundation, Inc. + Contributed by Jakub Jelinek <jakub@redhat.com>. + + Based on strlen written by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se); + commentary by Jim Blandy (jimb@ai.mit.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <string.h> +#include <stdlib.h> + +/* Find the length of S, but scan at most MAXLEN characters. If no + '\0' terminator is found in that many characters, return MAXLEN. */ +size_t +__strnlen (const char *str, size_t maxlen) +{ + const char *char_ptr, *end_ptr = str + maxlen; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, himagic, lomagic; + + if (maxlen == 0) + return 0; + + if (__builtin_expect (end_ptr < str, 0)) + end_ptr = (const char *) ~0UL; + + /* Handle the first few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = str; ((unsigned long int) char_ptr + & (sizeof (longword) - 1)) != 0; + ++char_ptr) + if (*char_ptr == '\0') + { + if (char_ptr > end_ptr) + char_ptr = end_ptr; + return char_ptr - str; + } + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + magic_bits = 0x7efefeffL; + himagic = 0x80808080L; + lomagic = 0x01010101L; + if (sizeof (longword) > 4) + { + /* 64-bit version of the magic. */ + /* Do the shift in two steps to avoid a warning if long has 32 bits. */ + magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL; + himagic = ((himagic << 16) << 16) | himagic; + lomagic = ((lomagic << 16) << 16) | lomagic; + } + if (sizeof (longword) > 8) + abort (); + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + while (longword_ptr < (unsigned long int *) end_ptr) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. */ + + longword = *longword_ptr++; + + if ((longword - lomagic) & himagic) + { + /* Which of the bytes was the zero? If none of them were, it was + a misfire; continue the search. */ + + const char *cp = (const char *) (longword_ptr - 1); + + char_ptr = cp; + if (cp[0] == 0) + break; + char_ptr = cp + 1; + if (cp[1] == 0) + break; + char_ptr = cp + 2; + if (cp[2] == 0) + break; + char_ptr = cp + 3; + if (cp[3] == 0) + break; + if (sizeof (longword) > 4) + { + char_ptr = cp + 4; + if (cp[4] == 0) + break; + char_ptr = cp + 5; + if (cp[5] == 0) + break; + char_ptr = cp + 6; + if (cp[6] == 0) + break; + char_ptr = cp + 7; + if (cp[7] == 0) + break; + } + } + char_ptr = end_ptr; + } + + if (char_ptr > end_ptr) + char_ptr = end_ptr; + return char_ptr - str; +} +weak_alias (__strnlen, strnlen) +libc_hidden_def (strnlen) diff --git a/string/strpbrk.c b/string/strpbrk.c new file mode 100644 index 0000000000..620cfab7f9 --- /dev/null +++ b/string/strpbrk.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1991, 1994, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined _LIBC || defined HAVE_CONFIG_H +# include <string.h> +#endif + +#undef strpbrk + +/* Find the first occurrence in S of any character in ACCEPT. */ +char * +strpbrk (s, accept) + const char *s; + const char *accept; +{ + while (*s != '\0') + { + const char *a = accept; + while (*a != '\0') + if (*a++ == *s) + return (char *) s; + ++s; + } + + return NULL; +} +libc_hidden_builtin_def (strpbrk) diff --git a/string/strrchr.c b/string/strrchr.c new file mode 100644 index 0000000000..64118b87ef --- /dev/null +++ b/string/strrchr.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> + +#undef strrchr + +/* Find the last occurrence of C in S. */ +char * +strrchr (const char *s, int c) +{ + register const char *found, *p; + + c = (unsigned char) c; + + /* Since strchr is fast, we use it rather than the obvious loop. */ + + if (c == '\0') + return strchr (s, '\0'); + + found = NULL; + while ((p = strchr (s, c)) != NULL) + { + found = p; + s = p + 1; + } + + return (char *) found; +} + +#ifdef weak_alias +#undef rindex +weak_alias (strrchr, rindex) +#endif +libc_hidden_builtin_def (strrchr) diff --git a/string/strsep.c b/string/strsep.c new file mode 100644 index 0000000000..e5342f7a22 --- /dev/null +++ b/string/strsep.c @@ -0,0 +1,70 @@ +/* Copyright (C) 1992, 93, 96, 97, 98, 99, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> + +#undef __strsep +#undef strsep + +char * +__strsep (char **stringp, const char *delim) +{ + char *begin, *end; + + begin = *stringp; + if (begin == NULL) + return NULL; + + /* A frequent case is when the delimiter string contains only one + character. Here we don't need to call the expensive `strpbrk' + function and instead work using `strchr'. */ + if (delim[0] == '\0' || delim[1] == '\0') + { + char ch = delim[0]; + + if (ch == '\0') + end = NULL; + else + { + if (*begin == ch) + end = begin; + else if (*begin == '\0') + end = NULL; + else + end = strchr (begin + 1, ch); + } + } + else + /* Find the end of the token. */ + end = strpbrk (begin, delim); + + if (end) + { + /* Terminate the token and set *STRINGP past NUL character. */ + *end++ = '\0'; + *stringp = end; + } + else + /* No more delimiters; this is the last token. */ + *stringp = NULL; + + return begin; +} +weak_alias (__strsep, strsep) +strong_alias (__strsep, __strsep_g) +libc_hidden_def (__strsep_g) diff --git a/string/strsignal.c b/string/strsignal.c index 8ff01a4731..8c5ed1e621 100644 --- a/string/strsignal.c +++ b/string/strsignal.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1994-2000, 2001, 2002 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1994-2002, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -24,10 +24,6 @@ #include <bits/libc-lock.h> -#ifndef HAVE_GNU_LD -#define _sys_siglist sys_siglist -#endif - /* Defined in siglist.c. */ extern const char *const _sys_siglist[]; extern const char *const _sys_siglist_internal[] attribute_hidden; diff --git a/string/strspn.c b/string/strspn.c new file mode 100644 index 0000000000..dc17ea8cbc --- /dev/null +++ b/string/strspn.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> + +#undef strspn + +/* Return the length of the maximum initial segment + of S which contains only characters in ACCEPT. */ +size_t +strspn (s, accept) + const char *s; + const char *accept; +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + else + ++count; + } + + return count; +} +libc_hidden_builtin_def (strspn) diff --git a/string/strstr.c b/string/strstr.c new file mode 100644 index 0000000000..fce1f2a756 --- /dev/null +++ b/string/strstr.c @@ -0,0 +1,123 @@ +/* Return the offset of one string within another. + Copyright (C) 1994,1996,1997,2000,2001,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * My personal strstr() implementation that beats most other algorithms. + * Until someone tells me otherwise, I assume that this is the + * fastest implementation of strstr() in C. + * I deliberately chose not to comment it. You should have at least + * as much fun trying to understand it, as I had to write it :-). + * + * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined _LIBC || defined HAVE_STRING_H +# include <string.h> +#endif + +typedef unsigned chartype; + +#undef strstr + +char * +strstr (phaystack, pneedle) + const char *phaystack; + const char *pneedle; +{ + const unsigned char *haystack, *needle; + chartype b; + const unsigned char *rneedle; + + haystack = (const unsigned char *) phaystack; + + if ((b = *(needle = (const unsigned char *) pneedle))) + { + chartype c; + haystack--; /* possible ANSI violation */ + + { + chartype a; + do + if (!(a = *++haystack)) + goto ret0; + while (a != b); + } + + if (!(c = *++needle)) + goto foundneedle; + ++needle; + goto jin; + + for (;;) + { + { + chartype a; + if (0) + jin:{ + if ((a = *++haystack) == c) + goto crest; + } + else + a = *++haystack; + do + { + for (; a != b; a = *++haystack) + { + if (!a) + goto ret0; + if ((a = *++haystack) == b) + break; + if (!a) + goto ret0; + } + } + while ((a = *++haystack) != c); + } + crest: + { + chartype a; + { + const unsigned char *rhaystack; + if (*(rhaystack = haystack-- + 1) == (a = *(rneedle = needle))) + do + { + if (!a) + goto foundneedle; + if (*++rhaystack != (a = *++needle)) + break; + if (!a) + goto foundneedle; + } + while (*++rhaystack == (a = *++needle)); + needle = rneedle; /* took the register-poor aproach */ + } + if (!a) + break; + } + } + } +foundneedle: + return (char *) haystack; +ret0: + return 0; +} +libc_hidden_builtin_def (strstr) diff --git a/string/strtok.c b/string/strtok.c new file mode 100644 index 0000000000..f45b760f74 --- /dev/null +++ b/string/strtok.c @@ -0,0 +1,66 @@ +/* Copyright (C) 1991,1996,1997,1999,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <string.h> + + +static char *olds; + +#undef strtok + +/* Parse S into tokens separated by characters in DELIM. + If S is NULL, the last string strtok() was called with is + used. For example: + char s[] = "-abc-=-def"; + x = strtok(s, "-"); // x = "abc" + x = strtok(NULL, "-="); // x = "def" + x = strtok(NULL, "="); // x = NULL + // s = "abc\0-def\0" +*/ +char * +strtok (s, delim) + char *s; + const char *delim; +{ + char *token; + + if (s == NULL) + s = olds; + + /* Scan leading delimiters. */ + s += strspn (s, delim); + if (*s == '\0') + { + olds = s; + return NULL; + } + + /* Find the end of the token. */ + token = s; + s = strpbrk (token, delim); + if (s == NULL) + /* This token finishes the string. */ + olds = __rawmemchr (token, '\0'); + else + { + /* Terminate the token and make OLDS point past it. */ + *s = '\0'; + olds = s + 1; + } + return token; +} diff --git a/string/strtok_r.c b/string/strtok_r.c new file mode 100644 index 0000000000..b11cb520f6 --- /dev/null +++ b/string/strtok_r.c @@ -0,0 +1,79 @@ +/* Reentrant string tokenizer. Generic version. + Copyright (C) 1991,1996-1999,2001,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#undef strtok_r +#undef __strtok_r + +#ifndef _LIBC +/* Get specification. */ +# include "strtok_r.h" +# define __strtok_r strtok_r +# define __rawmemchr strchr +#endif + +/* Parse S into tokens separated by characters in DELIM. + If S is NULL, the saved pointer in SAVE_PTR is used as + the next starting point. For example: + char s[] = "-abc-=-def"; + char *sp; + x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def" + x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL + x = strtok_r(NULL, "=", &sp); // x = NULL + // s = "abc\0-def\0" +*/ +char * +__strtok_r (char *s, const char *delim, char **save_ptr) +{ + char *token; + + if (s == NULL) + s = *save_ptr; + + /* Scan leading delimiters. */ + s += strspn (s, delim); + if (*s == '\0') + { + *save_ptr = s; + return NULL; + } + + /* Find the end of the token. */ + token = s; + s = strpbrk (token, delim); + if (s == NULL) + /* This token finishes the string. */ + *save_ptr = __rawmemchr (token, '\0'); + else + { + /* Terminate the token and make *SAVE_PTR point past it. */ + *s = '\0'; + *save_ptr = s + 1; + } + return token; +} +#ifdef weak_alias +libc_hidden_def (__strtok_r) +weak_alias (__strtok_r, strtok_r) +#endif diff --git a/string/strxfrm_l.c b/string/strxfrm_l.c index 44b605168a..20f2f149bd 100644 --- a/string/strxfrm_l.c +++ b/string/strxfrm_l.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1995,96,97,2002, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996, 1997, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Ulrich Drepper <drepper@gnu.org>, 1995. @@ -96,6 +97,7 @@ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l) const int32_t *indirect; uint_fast32_t pass; size_t needed; + size_t last_needed; const USTRING_TYPE *usrc; size_t srclen = STRLEN (src); int32_t *idxarr; @@ -197,6 +199,7 @@ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l) this is true for all of them. */ int position = rule & sort_position; + last_needed = needed; if (position == 0) { for (idxcnt = 0; idxcnt < idxmax; ++idxcnt) @@ -210,8 +213,9 @@ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l) /* Handle the pushed elements now. */ size_t backw; - for (backw = idxcnt - 1; backw >= backw_stop; --backw) + for (backw = idxcnt; backw > backw_stop; ) { + --backw; len = weights[idxarr[backw]++]; if (needed + len < n) @@ -293,8 +297,9 @@ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l) /* Handle the pushed elements now. */ size_t backw; - for (backw = idxcnt - 1; backw >= backw_stop; --backw) + for (backw = idxcnt; backw > backw_stop; ) { + --backw; len = weights[idxarr[backw]++]; if (len != 0) { @@ -424,11 +429,11 @@ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l) a `position' rule at the end and if no non-ignored character is found the last \1 byte is immediately followed by a \0 byte signalling this. We can avoid the \1 byte(s). */ - if (needed <= n && needed > 2 && dest[needed - 2] == L('\1')) + if (needed > 2 && needed == last_needed + 1) { /* Remove the \1 byte. */ - --needed; - dest[needed - 1] = L('\0'); + if (--needed <= n) + dest[needed - 1] = L('\0'); } /* Free the memory if needed. */ diff --git a/string/test-memccpy.c b/string/test-memccpy.c index b581408f37..26532633df 100644 --- a/string/test-memccpy.c +++ b/string/test-memccpy.c @@ -1,5 +1,5 @@ /* Test and measure memccpy functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -109,8 +109,8 @@ do_test (size_t align1, size_t align2, int c, size_t len, size_t n, if (align2 + len >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0; i < len - 1; ++i) { diff --git a/string/test-memchr.c b/string/test-memchr.c index df866fe2d7..c233ead5dd 100644 --- a/string/test-memchr.c +++ b/string/test-memchr.c @@ -1,5 +1,5 @@ /* Test and measure memchr functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -89,7 +89,7 @@ do_test (size_t align, size_t pos, size_t len, int seek_char) { buf1[align + pos] = seek_char; buf1[align + len] = -seek_char; - result = buf1 + align + pos; + result = (char *) (buf1 + align + pos); } else { @@ -101,7 +101,7 @@ do_test (size_t align, size_t pos, size_t len, int seek_char) printf ("Length %4zd, alignment %2zd:", pos, align); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, buf1 + align, seek_char, len, result); + do_one_test (impl, (char *) (buf1 + align), seek_char, len, result); if (HP_TIMING_AVAIL) putchar ('\n'); @@ -144,16 +144,17 @@ do_random_tests (void) } if (pos < len) - result = p + pos + align; + result = (char *) (p + pos + align); else result = NULL; FOR_EACH_IMPL (impl, 1) - if (CALL (impl, p + align, seek_char, len) != result) + if (CALL (impl, (char *) (p + align), seek_char, len) != result) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %d, %zd, %zd) %p != %p, p %p", n, impl->name, align, seek_char, len, pos, - CALL (impl, p + align, seek_char, len), result, p); + CALL (impl, (char *) (p + align), seek_char, len), + result, p); ret = 1; } } diff --git a/string/test-memcmp.c b/string/test-memcmp.c index 89c104386b..af07a5e599 100644 --- a/string/test-memcmp.c +++ b/string/test-memcmp.c @@ -1,5 +1,5 @@ /* Test and measure memcmp functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -88,8 +88,8 @@ do_test (size_t align1, size_t align2, size_t len, int exp_result) if (align2 + len >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0; i < len; i++) s1[i] = s2[i] = 1 + 23 * i % 255; @@ -161,7 +161,7 @@ do_random_tests (void) FOR_EACH_IMPL (impl, 1) { - r = CALL (impl, p1 + align1, p2 + align2, len); + r = CALL (impl, (char *) (p1 + align1), (char *) (p2 + align2), len); /* Test whether on 64-bit architectures where ABI requires callee to promote has the promotion been done. */ asm ("" : "=g" (r) : "0" (r)); diff --git a/string/test-memcpy.c b/string/test-memcpy.c index adc90da767..7b0723a65a 100644 --- a/string/test-memcpy.c +++ b/string/test-memcpy.c @@ -1,5 +1,5 @@ /* Test and measure memcpy functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -102,8 +102,8 @@ do_test (size_t align1, size_t align2, size_t len) if (align2 + len >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0, j = 1; i < len; i++, j += 23) s1[i] = j; @@ -190,7 +190,9 @@ do_random_tests (void) if (j > size2) j = size2; memset (p2, c, j); - res = CALL (impl, p2 + align2, p1 + align1, len); + res = (unsigned char *) CALL (impl, + (char *) (p2 + align2), + (char *) (p1 + align1), len); if (res != MEMCPY_RESULT (p2 + align2, len)) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p", diff --git a/string/test-memmove.c b/string/test-memmove.c index 9531aa82d8..2f3a8f7631 100644 --- a/string/test-memmove.c +++ b/string/test-memmove.c @@ -101,8 +101,8 @@ do_test (size_t align1, size_t align2, size_t len) if (align2 + len >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0, j = 1; i < len; i++, j += 23) s1[i] = j; @@ -111,7 +111,7 @@ do_test (size_t align1, size_t align2, size_t len) printf ("Length %4zd, alignment %2zd/%2zd:", len, align1, align2); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, s2, buf2 + align1, s1, len); + do_one_test (impl, s2, (char *) (buf2 + align1), s1, len); if (HP_TIMING_AVAIL) putchar ('\n'); @@ -179,7 +179,9 @@ do_random_tests (void) { memset (p2 + dststart, c, dstend - dststart); memcpy (p2 + srcstart, p1 + srcstart, srcend - srcstart); - res = CALL (impl, p2 + align2, p2 + align1, len); + res = (unsigned char *) CALL (impl, + (char *) (p2 + align2), + (char *) (p2 + align1), len); if (res != p2 + align2) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p", diff --git a/string/test-memset.c b/string/test-memset.c index 9ae774162f..601ace4195 100644 --- a/string/test-memset.c +++ b/string/test-memset.c @@ -1,5 +1,5 @@ /* Test and measure memset functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -49,10 +49,12 @@ static void do_one_test (impl_t *impl, char *s, int c, size_t n) { char *res = CALL (impl, s, c, n); - if (res != s) + char tstbuf[n]; + if (res != s + || simple_memset (tstbuf, c, n) != tstbuf + || memcmp (s, tstbuf, n) != 0) { - error (0, 0, "Wrong result in function %s %p != %p", impl->name, - res, s); + error (0, 0, "Wrong result in function %s", impl->name); ret = 1; return; } @@ -87,7 +89,7 @@ do_test (size_t align, int c, size_t len) printf ("Length %4zd, alignment %2zd, c %2d:", len, align, c); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, buf1 + align, c, len); + do_one_test (impl, (char *) buf1 + align, c, len); if (HP_TIMING_AVAIL) putchar ('\n'); @@ -143,7 +145,7 @@ do_random_tests (void) if (p[i + align] == c) p[i + align] = o; } - res = CALL (impl, p + align, c, len); + res = (unsigned char *) CALL (impl, (char *) p + align, c, len); if (res != p + align) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %d, %zd) %p != %p", @@ -191,7 +193,7 @@ test_main (void) printf ("\t%s", impl->name); putchar ('\n'); - for (c = 0; c <= 65; c += 65) + for (c = -65; c <= 130; c += 65) { for (i = 0; i < 18; ++i) do_test (0, c, 1 << i); diff --git a/string/test-strcat.c b/string/test-strcat.c index 53c8462839..443752069c 100644 --- a/string/test-strcat.c +++ b/string/test-strcat.c @@ -1,5 +1,5 @@ /* Test and measure strcat functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -91,8 +91,8 @@ do_test (size_t align1, size_t align2, size_t len1, size_t len2, int max_char) if (align2 + len1 + len2 >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0; i < len1; ++i) s1[i] = 32 + 23 * i % (max_char - 32); @@ -175,7 +175,8 @@ do_random_tests (void) memset (p2 - 64, '\1', align2 + 64); memset (p2 + align2 + len2 + 1, '\1', 512 - align2 - len2 - 1); memcpy (p2 + align2, buf1, len2 + 1); - res = CALL (impl, p2 + align2, p1 + align1); + res = (unsigned char *) CALL (impl, (char *) (p2 + align2), + (char *) (p1 + align1)); if (res != p2 + align2) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd %zd) %p != %p", diff --git a/string/test-strchr.c b/string/test-strchr.c index 1333ebc8bc..cf25b449d9 100644 --- a/string/test-strchr.c +++ b/string/test-strchr.c @@ -101,10 +101,10 @@ do_test (size_t align, size_t pos, size_t len, int seek_char, int max_char) if (pos < len) { buf1[align + pos] = seek_char; - result = buf1 + align + pos; + result = (char *) (buf1 + align + pos); } else if (seek_char == 0) - result = buf1 + align + len; + result = (char *) (buf1 + align + len); else result = NULL; @@ -112,7 +112,7 @@ do_test (size_t align, size_t pos, size_t len, int seek_char, int max_char) printf ("Length %4zd, alignment %2zd:", pos, align); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, buf1 + align, seek_char, result); + do_one_test (impl, (char *) (buf1 + align), seek_char, result); if (HP_TIMING_AVAIL) putchar ('\n'); @@ -166,18 +166,18 @@ do_random_tests (void) } if (pos <= len) - result = p + pos + align; + result = (char *) (p + pos + align); else if (seek_char == 0) - result = p + len + align; + result = (char *) (p + len + align); else result = NULL; FOR_EACH_IMPL (impl, 1) - if (CALL (impl, p + align, seek_char) != result) + if (CALL (impl, (char *) (p + align), seek_char) != result) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %d, %zd, %zd) %p != %p, p %p", n, impl->name, align, seek_char, len, pos, - CALL (impl, p + align, seek_char), result, p); + CALL (impl, (char *) (p + align), seek_char), result, p); ret = 1; } } diff --git a/string/test-strcmp.c b/string/test-strcmp.c index af49f14fe1..769e9828fd 100644 --- a/string/test-strcmp.c +++ b/string/test-strcmp.c @@ -1,5 +1,5 @@ /* Test and measure strcmp functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -103,8 +103,8 @@ do_test (size_t align1, size_t align2, size_t len, int max_char, if (align2 + len + 1 >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0; i < len; i++) s1[i] = s2[i] = 1 + 23 * i % max_char; @@ -198,7 +198,7 @@ do_random_tests (void) FOR_EACH_IMPL (impl, 1) { - r = CALL (impl, p1 + align1, p2 + align2); + r = CALL (impl, (char *) (p1 + align1), (char *) (p2 + align2)); /* Test whether on 64-bit architectures where ABI requires callee to promote has the promotion been done. */ asm ("" : "=g" (r) : "0" (r)); diff --git a/string/test-strcpy.c b/string/test-strcpy.c index dbfbb9294d..6a2ea2510e 100644 --- a/string/test-strcpy.c +++ b/string/test-strcpy.c @@ -1,5 +1,5 @@ /* Test and measure strcpy functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -92,8 +92,8 @@ do_test (size_t align1, size_t align2, size_t len, int max_char) if (align2 + len >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0; i < len; i++) s1[i] = 32 + 23 * i % (max_char - 32); @@ -148,7 +148,8 @@ do_random_tests (void) FOR_EACH_IMPL (impl, 1) { memset (p2 - 64, '\1', 512 + 64); - res = CALL (impl, p2 + align2, p1 + align1); + res = (unsigned char *) CALL (impl, (char *) (p2 + align2), + (char *) (p1 + align1)); if (res != STRCPY_RESULT (p2 + align2, len)) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p", diff --git a/string/test-strlen.c b/string/test-strlen.c index 82ad95e5cc..e01befbf46 100644 --- a/string/test-strlen.c +++ b/string/test-strlen.c @@ -1,5 +1,5 @@ /* Test and measure strlen functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -92,7 +92,7 @@ do_test (size_t align, size_t len, int max_char) printf ("Length %4zd, alignment %2zd:", len, align); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, buf1 + align, len); + do_one_test (impl, (char *) (buf1 + align), len); if (HP_TIMING_AVAIL) putchar ('\n'); @@ -127,10 +127,11 @@ do_random_tests (void) } FOR_EACH_IMPL (impl, 1) - if (CALL (impl, p + align) != len) + if (CALL (impl, (char *) (p + align)) != len) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd) %zd != %zd, p %p", - n, impl->name, align, CALL (impl, p + align), len, p); + n, impl->name, align, CALL (impl, (char *) (p + align)), + len, p); ret = 1; } } diff --git a/string/test-strncmp.c b/string/test-strncmp.c index 431b64d6af..5adf0eb311 100644 --- a/string/test-strncmp.c +++ b/string/test-strncmp.c @@ -86,6 +86,65 @@ do_one_test (impl_t *impl, const char *s1, const char *s2, size_t n, } static void +do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char, + int exp_result) +{ + size_t i, align_n; + char *s1, *s2; + + if (n == 0) + { + s1 = (char*)(buf1 + page_size); + s2 = (char*)(buf2 + page_size); + if (HP_TIMING_AVAIL) + printf ("Length %4zd/%4zd:", len, n); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, n, 0); + + if (HP_TIMING_AVAIL) + putchar ('\n'); + + return; + } + + align1 &= 15; + align2 &= 15; + align_n = (page_size - n) & 15; + + s1 = (char*)(buf1 + page_size - n); + s2 = (char*)(buf2 + page_size - n); + + if (align1 < align_n) + s1 -= (align_n - align1); + + if (align2 < align_n) + s2 -= (align_n - align2); + + for (i = 0; i < n; i++) + s1[i] = s2[i] = 1 + 23 * i % max_char; + + if (len < n) + { + s1[len] = 0; + s2[len] = 0; + if (exp_result < 0) + s2[len] = 32; + else if (exp_result > 0) + s1[len] = 64; + } + + if (HP_TIMING_AVAIL) + printf ("Length %4zd/%4zd, alignment %2zd/%2zd:", len, n, align1, align2); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, n, exp_result); + + if (HP_TIMING_AVAIL) + putchar ('\n'); +} + +static void do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char, int exp_result) { @@ -103,8 +162,8 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char, if (align2 + n + 1 >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char*)(buf1 + align1); + s2 = (char*)(buf2 + align2); for (i = 0; i < n; i++) s1[i] = s2[i] = 1 + 23 * i % max_char; @@ -124,7 +183,7 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char, printf ("Length %4zd/%4zd, alignment %2zd/%2zd:", len, n, align1, align2); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, s1, s2, n, exp_result); + do_one_test (impl, (char*)s1, (char*)s2, n, exp_result); if (HP_TIMING_AVAIL) putchar ('\n'); @@ -208,7 +267,7 @@ do_random_tests (void) FOR_EACH_IMPL (impl, 1) { - r = CALL (impl, p1 + align1, p2 + align2, size); + r = CALL (impl, (char*)(p1 + align1), (char*)(p2 + align2), size); /* Test whether on 64-bit architectures where ABI requires callee to promote has the promotion been done. */ asm ("" : "=g" (r) : "0" (r)); @@ -271,6 +330,24 @@ test_main (void) do_test (2 * i, i, 8 << i, 16 << i, 255, 0); do_test (2 * i, i, 8 << i, 16 << i, 255, 1); } + + do_test_limit (0, 0, 0, 0, 127, 0); + do_test_limit (4, 0, 21, 20, 127, 0); + do_test_limit (0, 4, 21, 20, 127, 0); + do_test_limit (8, 0, 25, 24, 127, 0); + do_test_limit (0, 8, 25, 24, 127, 0); + + for (i = 0; i < 8; ++i) + { + do_test_limit (0, 0, 17 - i, 16 - i, 127, 0); + do_test_limit (0, 0, 17 - i, 16 - i, 255, 0); + do_test_limit (0, 0, 15 - i, 16 - i, 127, 0); + do_test_limit (0, 0, 15 - i, 16 - i, 127, 1); + do_test_limit (0, 0, 15 - i, 16 - i, 127, -1); + do_test_limit (0, 0, 15 - i, 16 - i, 255, 0); + do_test_limit (0, 0, 15 - i, 16 - i, 255, 1); + do_test_limit (0, 0, 15 - i, 16 - i, 255, -1); + } do_random_tests (); return ret; diff --git a/string/test-strncpy.c b/string/test-strncpy.c index 62b83166a3..d7a714cef1 100644 --- a/string/test-strncpy.c +++ b/string/test-strncpy.c @@ -1,5 +1,5 @@ /* Test and measure strncpy functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -124,8 +124,8 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char) if (align2 + len >= page_size) return; - s1 = buf1 + align1; - s2 = buf2 + align2; + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); for (i = 0; i < len; ++i) s1[i] = 32 + 23 * i % (max_char - 32); @@ -215,7 +215,9 @@ do_random_tests (void) FOR_EACH_IMPL (impl, 1) { memset (p2 - 64, '\1', 512 + 64); - res = CALL (impl, p2 + align2, p1 + align1, size); + res = (unsigned char *) CALL (impl, + (char *) (p2 + align2), + (char *) (p1 + align1), size); if (res != STRNCPY_RESULT (p2 + align2, len, size)) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p", diff --git a/string/test-strpbrk.c b/string/test-strpbrk.c index 2ec52fd286..f3ed2080bc 100644 --- a/string/test-strpbrk.c +++ b/string/test-strpbrk.c @@ -1,5 +1,5 @@ /* Test and measure strpbrk functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -102,8 +102,8 @@ do_test (size_t align, size_t pos, size_t len) if (align + pos + 10 >= page_size || len > 240) return; - rej = buf2 + (random () & 255); - s = buf1 + align; + rej = (char *) (buf2 + (random () & 255)); + s = (char *) (buf1 + align); for (i = 0; i < len; ++i) { @@ -182,7 +182,7 @@ do_random_tests (void) } rej[i] = '\0'; for (c = 1; c <= 255; ++c) - if (strchr (rej, c) == NULL) + if (strchr ((char *) rej, c) == NULL) break; j = (pos > len ? pos : len) + align + 64; if (j > 512) @@ -199,23 +199,24 @@ do_random_tests (void) else { p[i] = random () & 255; - if (strchr (rej, p[i])) + if (strchr ((char *) rej, p[i])) { p[i] = random () & 255; - if (strchr (rej, p[i])) + if (strchr ((char *) rej, p[i])) p[i] = c; } } } - result = STRPBRK_RESULT (p + align, pos < len ? pos : len); + result = STRPBRK_RESULT ((char *) (p + align), pos < len ? pos : len); FOR_EACH_IMPL (impl, 1) - if (CALL (impl, p + align, rej) != result) + if (CALL (impl, (char *) (p + align), (char *) rej) != result) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %p, %zd, %zd, %zd) %p != %p", n, impl->name, align, rej, rlen, pos, len, - (void *) CALL (impl, p + align, rej), (void *) result); + (void *) CALL (impl, (char *) (p + align), (char *) rej), + (void *) result); ret = 1; } } diff --git a/string/test-strrchr.c b/string/test-strrchr.c index 5aff75aeba..92e8ab1bb1 100644 --- a/string/test-strrchr.c +++ b/string/test-strrchr.c @@ -1,5 +1,5 @@ /* Test and measure strrchr functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -95,10 +95,10 @@ do_test (size_t align, size_t pos, size_t len, int seek_char, int max_char) if (pos < len) { buf1[align + pos] = seek_char; - result = buf1 + align + pos; + result = (char *) (buf1 + align + pos); } else if (seek_char == 0) - result = buf1 + align + len; + result = (char *) (buf1 + align + len); else result = NULL; @@ -106,7 +106,7 @@ do_test (size_t align, size_t pos, size_t len, int seek_char, int max_char) printf ("Length %4zd, alignment %2zd:", pos, align); FOR_EACH_IMPL (impl, 0) - do_one_test (impl, buf1 + align, seek_char, result); + do_one_test (impl, (char *) (buf1 + align), seek_char, result); if (HP_TIMING_AVAIL) putchar ('\n'); @@ -165,18 +165,18 @@ do_random_tests (void) } if (pos <= len) - result = p + pos + align; + result = (char *) (p + pos + align); else if (seek_char == 0) - result = p + len + align; + result = (char *) (p + len + align); else result = NULL; FOR_EACH_IMPL (impl, 1) - if (CALL (impl, p + align, seek_char) != result) + if (CALL (impl, (char *) (p + align), seek_char) != result) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %d, %zd, %zd) %p != %p, p %p", n, impl->name, align, seek_char, len, pos, - CALL (impl, p + align, seek_char), result, p); + CALL (impl, (char *) (p + align), seek_char), result, p); ret = 1; } } diff --git a/string/test-strspn.c b/string/test-strspn.c index de7351fe8c..15cf4923f0 100644 --- a/string/test-strspn.c +++ b/string/test-strspn.c @@ -1,5 +1,5 @@ /* Test and measure strspn functions. - Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999,2002,2003,2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek <jakub@redhat.com>, 1999. @@ -104,8 +104,8 @@ do_test (size_t align, size_t pos, size_t len) if (align + pos + 10 >= page_size || len > 240 || ! len) return; - acc = buf2 + (random () & 255); - s = buf1 + align; + acc = (char *) (buf2 + (random () & 255)); + s = (char *) (buf1 + align); for (i = 0; i < len; ++i) { @@ -183,7 +183,7 @@ do_random_tests (void) else if (i == pos + align) { p[i] = random () & 255; - if (strchr (acc, p[i])) + if (strchr ((char *) acc, p[i])) p[i] = '\0'; } else if (i < align || i > pos + align) @@ -193,11 +193,13 @@ do_random_tests (void) } FOR_EACH_IMPL (impl, 1) - if (CALL (impl, p + align, acc) != (pos < len ? pos : len)) + if (CALL (impl, (char *) (p + align), + (char *) acc) != (pos < len ? pos : len)) { error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %p, %zd, %zd, %zd) %zd != %zd", n, impl->name, align, acc, alen, pos, len, - CALL (impl, p + align, acc), (pos < len ? pos : len)); + CALL (impl, (char *) (p + align), (char *) acc), + (pos < len ? pos : len)); ret = 1; } } diff --git a/string/tester.c b/string/tester.c index 5f0a851104..cccef3ad9d 100644 --- a/string/tester.c +++ b/string/tester.c @@ -1,5 +1,5 @@ /* Tester for string functions. - Copyright (C) 1995-2000, 2001, 2003 Free Software Foundation, Inc. + Copyright (C) 1995-2001, 2003, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -34,10 +34,6 @@ #include <strings.h> #include <fcntl.h> -#ifndef HAVE_GNU_LD -#define _sys_nerr sys_nerr -#define _sys_errlist sys_errlist -#endif #define STREQ(a, b) (strcmp((a), (b)) == 0) @@ -348,6 +344,9 @@ test_strncat (void) (void) strncat (one, "gh", 2); equal (one, "abcdgh", 12); /* Count and length equal. */ + + (void) strncat (one, "ij", (size_t)-1); /* set sign bit in count */ + equal (one, "abcdghij", 13); } static void @@ -368,6 +367,8 @@ test_strncmp (void) check (strncmp ("abce", "abc", 3) == 0, 11); /* Count == length. */ check (strncmp ("abcd", "abce", 4) < 0, 12); /* Nudging limit. */ check (strncmp ("abc", "def", 0) == 0, 13); /* Zero count. */ + check (strncmp ("abc", "", (size_t)-1) > 0, 14); /* set sign bit in count */ + check (strncmp ("abc", "abc", (size_t)-2) == 0, 15); } static void @@ -434,6 +435,29 @@ test_strlen (void) } static void +test_strnlen (void) +{ + it = "strnlen"; + check (strnlen ("", 10) == 0, 1); /* Empty. */ + check (strnlen ("a", 10) == 1, 2); /* Single char. */ + check (strnlen ("abcd", 10) == 4, 3); /* Multiple chars. */ + check (strnlen ("foo", (size_t)-1) == 3, 4); /* limits of n. */ + + { + char buf[4096]; + int i; + char *p; + for (i=0; i < 0x100; i++) + { + p = (char *) ((unsigned long int)(buf + 0xff) & ~0xff) + i; + strcpy (p, "OK"); + strcpy (p+3, "BAD/WRONG"); + check (strnlen (p, 100) == 2, 5+i); + } + } +} + +static void test_strchr (void) { it = "strchr"; @@ -1386,6 +1410,9 @@ main (void) /* strlen. */ test_strlen (); + /* strnlen. */ + test_strnlen (); + /* strchr. */ test_strchr (); diff --git a/string/tst-strfry.c b/string/tst-strfry.c new file mode 100644 index 0000000000..2b40a39b13 --- /dev/null +++ b/string/tst-strfry.c @@ -0,0 +1,15 @@ +#include <stdio.h> +#include <string.h> + +static int +do_test (void) +{ + char str[] = "this is a test"; + + strfry (str); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/string/tst-strxfrm2.c b/string/tst-strxfrm2.c new file mode 100644 index 0000000000..d5a1115338 --- /dev/null +++ b/string/tst-strxfrm2.c @@ -0,0 +1,83 @@ +#include <locale.h> +#include <stdio.h> +#include <string.h> + +static int +do_test (void) +{ + int res = 0; + + char buf[20]; + size_t l1 = strxfrm (NULL, "ab", 0); + size_t l2 = strxfrm (buf, "ab", 1); + size_t l3 = strxfrm (buf, "ab", sizeof (buf)); + if (l3 < sizeof (buf) && strlen (buf) != l3) + { + puts ("C locale l3 test failed"); + res = 1; + } + + size_t l4 = strxfrm (buf, "ab", l1 + 1); + if (l4 < l1 + 1 && strlen (buf) != l4) + { + puts ("C locale l4 test failed"); + res = 1; + } + + buf[l1] = 'Z'; + size_t l5 = strxfrm (buf, "ab", l1); + if (buf[l1] != 'Z') + { + puts ("C locale l5 test failed"); + res = 1; + } + + if (l1 != l2 || l1 != l3 || l1 != l4 || l1 != l5) + { + puts ("C locale retval test failed"); + res = 1; + } + + if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL) + { + puts ("setlocale failed"); + res = 1; + } + else + { + l1 = strxfrm (NULL, "ab", 0); + l2 = strxfrm (buf, "ab", 1); + l3 = strxfrm (buf, "ab", sizeof (buf)); + if (l3 < sizeof (buf) && strlen (buf) != l3) + { + puts ("UTF-8 locale l3 test failed"); + res = 1; + } + + l4 = strxfrm (buf, "ab", l1 + 1); + if (l4 < l1 + 1 && strlen (buf) != l4) + { + puts ("UTF-8 locale l4 test failed"); + res = 1; + } + + buf[l1] = 'Z'; + l5 = strxfrm (buf, "ab", l1); + if (buf[l1] != 'Z') + { + puts ("UTF-8 locale l5 test failed"); + res = 1; + } + + if (l1 != l2 || l1 != l3 || l1 != l4 || l1 != l5) + { + puts ("UTF-8 locale retval test failed"); + res = 1; + } + } + + return res; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/string/wordcopy.c b/string/wordcopy.c new file mode 100644 index 0000000000..0c9a4be4f6 --- /dev/null +++ b/string/wordcopy.c @@ -0,0 +1,413 @@ +/* _memcopy.c -- subroutines for memory copy functions. + Copyright (C) 1991, 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* BE VERY CAREFUL IF YOU CHANGE THIS CODE...! */ + +#include <stddef.h> +#include <memcopy.h> + +/* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to + block beginning at DSTP with LEN `op_t' words (not LEN bytes!). + Both SRCP and DSTP should be aligned for memory operations on `op_t's. */ + +void +_wordcopy_fwd_aligned (dstp, srcp, len) + long int dstp; + long int srcp; + size_t len; +{ + op_t a0, a1; + + switch (len % 8) + { + case 2: + a0 = ((op_t *) srcp)[0]; + srcp -= 6 * OPSIZ; + dstp -= 7 * OPSIZ; + len += 6; + goto do1; + case 3: + a1 = ((op_t *) srcp)[0]; + srcp -= 5 * OPSIZ; + dstp -= 6 * OPSIZ; + len += 5; + goto do2; + case 4: + a0 = ((op_t *) srcp)[0]; + srcp -= 4 * OPSIZ; + dstp -= 5 * OPSIZ; + len += 4; + goto do3; + case 5: + a1 = ((op_t *) srcp)[0]; + srcp -= 3 * OPSIZ; + dstp -= 4 * OPSIZ; + len += 3; + goto do4; + case 6: + a0 = ((op_t *) srcp)[0]; + srcp -= 2 * OPSIZ; + dstp -= 3 * OPSIZ; + len += 2; + goto do5; + case 7: + a1 = ((op_t *) srcp)[0]; + srcp -= 1 * OPSIZ; + dstp -= 2 * OPSIZ; + len += 1; + goto do6; + + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return; + a0 = ((op_t *) srcp)[0]; + srcp -= 0 * OPSIZ; + dstp -= 1 * OPSIZ; + goto do7; + case 1: + a1 = ((op_t *) srcp)[0]; + srcp -=-1 * OPSIZ; + dstp -= 0 * OPSIZ; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + goto do8; /* No-op. */ + } + + do + { + do8: + a0 = ((op_t *) srcp)[0]; + ((op_t *) dstp)[0] = a1; + do7: + a1 = ((op_t *) srcp)[1]; + ((op_t *) dstp)[1] = a0; + do6: + a0 = ((op_t *) srcp)[2]; + ((op_t *) dstp)[2] = a1; + do5: + a1 = ((op_t *) srcp)[3]; + ((op_t *) dstp)[3] = a0; + do4: + a0 = ((op_t *) srcp)[4]; + ((op_t *) dstp)[4] = a1; + do3: + a1 = ((op_t *) srcp)[5]; + ((op_t *) dstp)[5] = a0; + do2: + a0 = ((op_t *) srcp)[6]; + ((op_t *) dstp)[6] = a1; + do1: + a1 = ((op_t *) srcp)[7]; + ((op_t *) dstp)[7] = a0; + + srcp += 8 * OPSIZ; + dstp += 8 * OPSIZ; + len -= 8; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + ((op_t *) dstp)[0] = a1; +} + +/* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to + block beginning at DSTP with LEN `op_t' words (not LEN bytes!). + DSTP should be aligned for memory operations on `op_t's, but SRCP must + *not* be aligned. */ + +void +_wordcopy_fwd_dest_aligned (dstp, srcp, len) + long int dstp; + long int srcp; + size_t len; +{ + op_t a0, a1, a2, a3; + int sh_1, sh_2; + + /* Calculate how to shift a word read at the memory operation + aligned srcp to make it aligned for copy. */ + + sh_1 = 8 * (srcp % OPSIZ); + sh_2 = 8 * OPSIZ - sh_1; + + /* Make SRCP aligned by rounding it down to the beginning of the `op_t' + it points in the middle of. */ + srcp &= -OPSIZ; + + switch (len % 4) + { + case 2: + a1 = ((op_t *) srcp)[0]; + a2 = ((op_t *) srcp)[1]; + srcp -= 1 * OPSIZ; + dstp -= 3 * OPSIZ; + len += 2; + goto do1; + case 3: + a0 = ((op_t *) srcp)[0]; + a1 = ((op_t *) srcp)[1]; + srcp -= 0 * OPSIZ; + dstp -= 2 * OPSIZ; + len += 1; + goto do2; + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return; + a3 = ((op_t *) srcp)[0]; + a0 = ((op_t *) srcp)[1]; + srcp -=-1 * OPSIZ; + dstp -= 1 * OPSIZ; + len += 0; + goto do3; + case 1: + a2 = ((op_t *) srcp)[0]; + a3 = ((op_t *) srcp)[1]; + srcp -=-2 * OPSIZ; + dstp -= 0 * OPSIZ; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + goto do4; /* No-op. */ + } + + do + { + do4: + a0 = ((op_t *) srcp)[0]; + ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2); + do3: + a1 = ((op_t *) srcp)[1]; + ((op_t *) dstp)[1] = MERGE (a3, sh_1, a0, sh_2); + do2: + a2 = ((op_t *) srcp)[2]; + ((op_t *) dstp)[2] = MERGE (a0, sh_1, a1, sh_2); + do1: + a3 = ((op_t *) srcp)[3]; + ((op_t *) dstp)[3] = MERGE (a1, sh_1, a2, sh_2); + + srcp += 4 * OPSIZ; + dstp += 4 * OPSIZ; + len -= 4; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2); +} + +/* _wordcopy_bwd_aligned -- Copy block finishing right before + SRCP to block finishing right before DSTP with LEN `op_t' words + (not LEN bytes!). Both SRCP and DSTP should be aligned for memory + operations on `op_t's. */ + +void +_wordcopy_bwd_aligned (dstp, srcp, len) + long int dstp; + long int srcp; + size_t len; +{ + op_t a0, a1; + + switch (len % 8) + { + case 2: + srcp -= 2 * OPSIZ; + dstp -= 1 * OPSIZ; + a0 = ((op_t *) srcp)[1]; + len += 6; + goto do1; + case 3: + srcp -= 3 * OPSIZ; + dstp -= 2 * OPSIZ; + a1 = ((op_t *) srcp)[2]; + len += 5; + goto do2; + case 4: + srcp -= 4 * OPSIZ; + dstp -= 3 * OPSIZ; + a0 = ((op_t *) srcp)[3]; + len += 4; + goto do3; + case 5: + srcp -= 5 * OPSIZ; + dstp -= 4 * OPSIZ; + a1 = ((op_t *) srcp)[4]; + len += 3; + goto do4; + case 6: + srcp -= 6 * OPSIZ; + dstp -= 5 * OPSIZ; + a0 = ((op_t *) srcp)[5]; + len += 2; + goto do5; + case 7: + srcp -= 7 * OPSIZ; + dstp -= 6 * OPSIZ; + a1 = ((op_t *) srcp)[6]; + len += 1; + goto do6; + + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return; + srcp -= 8 * OPSIZ; + dstp -= 7 * OPSIZ; + a0 = ((op_t *) srcp)[7]; + goto do7; + case 1: + srcp -= 9 * OPSIZ; + dstp -= 8 * OPSIZ; + a1 = ((op_t *) srcp)[8]; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + goto do8; /* No-op. */ + } + + do + { + do8: + a0 = ((op_t *) srcp)[7]; + ((op_t *) dstp)[7] = a1; + do7: + a1 = ((op_t *) srcp)[6]; + ((op_t *) dstp)[6] = a0; + do6: + a0 = ((op_t *) srcp)[5]; + ((op_t *) dstp)[5] = a1; + do5: + a1 = ((op_t *) srcp)[4]; + ((op_t *) dstp)[4] = a0; + do4: + a0 = ((op_t *) srcp)[3]; + ((op_t *) dstp)[3] = a1; + do3: + a1 = ((op_t *) srcp)[2]; + ((op_t *) dstp)[2] = a0; + do2: + a0 = ((op_t *) srcp)[1]; + ((op_t *) dstp)[1] = a1; + do1: + a1 = ((op_t *) srcp)[0]; + ((op_t *) dstp)[0] = a0; + + srcp -= 8 * OPSIZ; + dstp -= 8 * OPSIZ; + len -= 8; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + ((op_t *) dstp)[7] = a1; +} + +/* _wordcopy_bwd_dest_aligned -- Copy block finishing right + before SRCP to block finishing right before DSTP with LEN `op_t' + words (not LEN bytes!). DSTP should be aligned for memory + operations on `op_t', but SRCP must *not* be aligned. */ + +void +_wordcopy_bwd_dest_aligned (dstp, srcp, len) + long int dstp; + long int srcp; + size_t len; +{ + op_t a0, a1, a2, a3; + int sh_1, sh_2; + + /* Calculate how to shift a word read at the memory operation + aligned srcp to make it aligned for copy. */ + + sh_1 = 8 * (srcp % OPSIZ); + sh_2 = 8 * OPSIZ - sh_1; + + /* Make srcp aligned by rounding it down to the beginning of the op_t + it points in the middle of. */ + srcp &= -OPSIZ; + srcp += OPSIZ; + + switch (len % 4) + { + case 2: + srcp -= 3 * OPSIZ; + dstp -= 1 * OPSIZ; + a2 = ((op_t *) srcp)[2]; + a1 = ((op_t *) srcp)[1]; + len += 2; + goto do1; + case 3: + srcp -= 4 * OPSIZ; + dstp -= 2 * OPSIZ; + a3 = ((op_t *) srcp)[3]; + a2 = ((op_t *) srcp)[2]; + len += 1; + goto do2; + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return; + srcp -= 5 * OPSIZ; + dstp -= 3 * OPSIZ; + a0 = ((op_t *) srcp)[4]; + a3 = ((op_t *) srcp)[3]; + goto do3; + case 1: + srcp -= 6 * OPSIZ; + dstp -= 4 * OPSIZ; + a1 = ((op_t *) srcp)[5]; + a0 = ((op_t *) srcp)[4]; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + goto do4; /* No-op. */ + } + + do + { + do4: + a3 = ((op_t *) srcp)[3]; + ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2); + do3: + a2 = ((op_t *) srcp)[2]; + ((op_t *) dstp)[2] = MERGE (a3, sh_1, a0, sh_2); + do2: + a1 = ((op_t *) srcp)[1]; + ((op_t *) dstp)[1] = MERGE (a2, sh_1, a3, sh_2); + do1: + a0 = ((op_t *) srcp)[0]; + ((op_t *) dstp)[0] = MERGE (a1, sh_1, a2, sh_2); + + srcp -= 4 * OPSIZ; + dstp -= 4 * OPSIZ; + len -= 4; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2); +} diff --git a/string/xpg-strerror.c b/string/xpg-strerror.c new file mode 100644 index 0000000000..5cb56cdfb8 --- /dev/null +++ b/string/xpg-strerror.c @@ -0,0 +1,57 @@ +/* Copyright (C) 1991, 1993, 1995, 1996, 1997, 1998, 2000, 2002, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <libintl.h> +#include <stdio.h> +#include <string.h> +#include <sys/param.h> +#include <stdio-common/_itoa.h> + +/* It is critical here that we always use the `dcgettext' function for + the message translation. Since <libintl.h> only defines the macro + `dgettext' to use `dcgettext' for optimizing programs this is not + always guaranteed. */ +#ifndef dgettext +# include <locale.h> /* We need LC_MESSAGES. */ +# define dgettext(domainname, msgid) dcgettext (domainname, msgid, LC_MESSAGES) +#endif + +/* Fill buf with a string describing the errno code in ERRNUM. */ +int +__xpg_strerror_r (int errnum, char *buf, size_t buflen) +{ + if (errnum < 0 || errnum >= _sys_nerr_internal + || _sys_errlist_internal[errnum] == NULL) + { + __set_errno (EINVAL); + return -1; + } + const char *estr = (const char *) _(_sys_errlist_internal[errnum]); + size_t estrlen = strlen (estr) + 1; + + if (buflen < estrlen) + { + __set_errno (ERANGE); + return -1; + } + + memcpy (buf, estr, estrlen); + return 0; +} |