diff options
Diffstat (limited to 'REORG.TODO/string')
148 files changed, 20537 insertions, 0 deletions
diff --git a/REORG.TODO/string/Depend b/REORG.TODO/string/Depend new file mode 100644 index 0000000000..f3e1156a4e --- /dev/null +++ b/REORG.TODO/string/Depend @@ -0,0 +1 @@ +localedata diff --git a/REORG.TODO/string/Makefile b/REORG.TODO/string/Makefile new file mode 100644 index 0000000000..f317d02a8c --- /dev/null +++ b/REORG.TODO/string/Makefile @@ -0,0 +1,109 @@ +# Copyright (C) 1991-2017 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, see +# <http://www.gnu.org/licenses/>. + +# +# Sub-makefile for string portion of library. +# +subdir := string + +include ../Makeconfig + +headers := string.h strings.h memory.h endian.h bits/endian.h \ + argz.h envz.h byteswap.h bits/byteswap.h bits/byteswap-16.h \ + bits/string.h bits/string2.h bits/string3.h \ + bits/strings_fortified.h bits/uintn-identity.h + +routines := strcat strchr strcmp strcoll strcpy strcspn \ + strverscmp strdup strndup \ + strerror _strerror strlen strnlen \ + strncat strncmp strncpy \ + strrchr strpbrk strsignal strspn strstr strtok \ + strtok_r strxfrm memchr memcmp memmove memset \ + mempcpy bcopy bzero ffs ffsll stpcpy stpncpy \ + strcasecmp strncase strcasecmp_l strncase_l \ + memccpy memcpy wordcopy strsep strcasestr \ + swab strfry memfrob memmem rawmemchr strchrnul \ + $(addprefix argz-,append count create ctsep next \ + delete extract insert stringify \ + addsep replace) \ + envz basename \ + strcoll_l strxfrm_l string-inlines memrchr \ + xpg-strerror strerror_l explicit_bzero + +strop-tests := memchr memcmp memcpy memmove mempcpy memset memccpy \ + stpcpy stpncpy strcat strchr strcmp strcpy strcspn \ + strlen strncmp strncpy strpbrk strrchr strspn memmem \ + strstr strcasestr strnlen strcasecmp strncasecmp \ + strncat rawmemchr strchrnul bcopy bzero memrchr \ + explicit_bzero +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 tst-strfry \ + bug-strtok1 $(addprefix test-,$(strop-tests)) \ + bug-envz1 tst-strxfrm2 tst-endian tst-svc2 \ + tst-strtok_r bug-strcoll2 tst-cmp tst-xbzero-opt \ + test-endian-types + +# This test allocates a lot of memory and can run for a long time. +xtests = tst-strcoll-overflow + +ifeq ($(run-built-tests),yes) +tests-special += $(objpfx)tst-svc-cmp.out +endif + +include ../Rules + +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 +CFLAGS-tst-xbzero-opt.c = -O3 +# BZ 21006: Resolve all functions but at least explicit_bzero at startup. +# Otherwise the test fails on s390x as the memcpy in prepare_test_buffer is +# done by loading r4 / r5 with the test_pattern and using store multiple +# instruction to store r4 / r5 to buf. If explicit_bzero would be resolved in +# setup_explicit_clear, r4 / r5 would be stored to stack by _dl_runtime_resolve +# and the call to memmem in count_test_patterns will find a hit of the +# test_pattern on the stack. +LDFLAGS-tst-xbzero-opt = -z now + +# Called during TLS initialization. +CFLAGS-memcpy.c = $(no-stack-protector) +CFLAGS-wordcopy.c = $(no-stack-protector) + +ifeq ($(run-built-tests),yes) +$(objpfx)tst-svc-cmp.out: tst-svc.expect $(objpfx)tst-svc.out + cmp $^ > $@; \ + $(evaluate-test) + +LOCALES := de_DE.UTF-8 en_US.ISO-8859-1 en_US.UTF-8 \ + tr_TR.ISO-8859-9 tr_TR.UTF-8 cs_CZ.UTF-8 \ + da_DK.ISO-8859-1 en_GB.UTF-8 +include ../gen-locales.mk + +$(objpfx)test-strcasecmp.out: $(gen-locales) +$(objpfx)test-strncasecmp.out: $(gen-locales) +$(objpfx)tst-strxfrm.out: $(gen-locales) +$(objpfx)tst-strxfrm2.out: $(gen-locales) +# bug-strcoll2 needs cs_CZ.UTF-8 and da_DK.ISO-8859-1. +$(objpfx)bug-strcoll2.out: $(gen-locales) +$(objpfx)tst-strcoll-overflow.out: $(gen-locales) + +endif diff --git a/REORG.TODO/string/Versions b/REORG.TODO/string/Versions new file mode 100644 index 0000000000..9b709d12a9 --- /dev/null +++ b/REORG.TODO/string/Versions @@ -0,0 +1,88 @@ +libc { + GLIBC_2.0 { + # functions with required interface outside normal name space + __argz_count; __argz_stringify; __argz_next; + + # functions used in inline functions or macros + __bzero; __strtok_r; + + # functions used in other libraries + __ffs; __mempcpy; __stpncpy; __stpcpy; __strcasecmp; __strdup; + __strerror_r; + + # a* + argz_add; argz_add_sep; argz_append; argz_count; argz_create; + argz_create_sep; argz_delete; argz_extract; argz_insert; argz_next; + argz_replace; argz_stringify; + + # b* + basename; bcmp; bcopy; bzero; + + # e* + envz_add; envz_entry; envz_get; envz_merge; envz_remove; + envz_strip; + + # f* + ffs; + + # i* + index; + + # m* + memccpy; memchr; memcmp; memcpy; memfrob; memmem; memmove; memset; + + # r* + rindex; + + # s* + stpcpy; stpncpy; strcasecmp; strcat; strchr; strcmp; strcoll; strcpy; + strcspn; strdup; strerror; strerror_r; strfry; strlen; strncasecmp; + strncat; strncmp; strncpy; strndup; strnlen; strpbrk; strrchr; strsep; + strsignal; strspn; strstr; strtok; strtok_r; strxfrm; swab; + } + GLIBC_2.1 { + # functions used in macros and other libraries + __rawmemchr; __strcasestr; + + # f* + ffsl; ffsll; + + # m* + mempcpy; + + # r* + rawmemchr; + + # s* + strcasestr; strverscmp; + } + GLIBC_2.1.1 { + # extern inline functions used by <bits/string2.h> + __mempcpy_small; __stpcpy_small; __strcspn_c1; __strcspn_c2; __strcspn_c3; + __strcpy_small; __strspn_c1; __strspn_c2; __strspn_c3; __strpbrk_c2; + __strpbrk_c3; __strsep_1c; __strsep_2c; __strsep_3c; __strsep_g; + __strtok_r_1c; + + # s* + strchrnul; __strverscmp; + } + GLIBC_2.2 { + # functions used in macros. + __strndup; + + # m* + memrchr; + } + GLIBC_2.3.4 { + # x* + __xpg_strerror_r; + } + GLIBC_2.6 { + strerror_l; + } + GLIBC_2.24 { + } + GLIBC_2.25 { + explicit_bzero; + } +} diff --git a/REORG.TODO/string/_strerror.c b/REORG.TODO/string/_strerror.c new file mode 100644 index 0000000000..4d3a52d906 --- /dev/null +++ b/REORG.TODO/string/_strerror.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <libintl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <_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 "); + size_t unklen = strlen (unk); + char *p, *q; + bool negative = errnum < 0; + + numbuf[20] = '\0'; + p = _itoa_word (abs (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 (negative && unklen < buflen) + { + *q++ = '-'; + ++unklen; + } + 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/REORG.TODO/string/argz-addsep.c b/REORG.TODO/string/argz-addsep.c new file mode 100644 index 0000000000..eab6d3ef17 --- /dev/null +++ b/REORG.TODO/string/argz-addsep.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + + +error_t +__argz_add_sep (char **argz, size_t *argz_len, const char *string, int delim) +{ + size_t nlen = strlen (string) + 1; + + if (nlen > 1) + { + const char *rp; + char *wp; + + *argz = (char *) realloc (*argz, *argz_len + nlen); + if (*argz == NULL) + return ENOMEM; + + wp = *argz + *argz_len; + rp = string; + do + if (*rp == delim) + { + if (wp > *argz && wp[-1] != '\0') + *wp++ = '\0'; + else + --nlen; + } + else + *wp++ = *rp; + while (*rp++ != '\0'); + + *argz_len += nlen; + } + + return 0; +} +weak_alias (__argz_add_sep, argz_add_sep) diff --git a/REORG.TODO/string/argz-append.c b/REORG.TODO/string/argz-append.c new file mode 100644 index 0000000000..09015016e6 --- /dev/null +++ b/REORG.TODO/string/argz-append.c @@ -0,0 +1,49 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <string.h> +#include <stdlib.h> + +/* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */ +error_t +__argz_append (char **argz, size_t *argz_len, const char *buf, size_t buf_len) +{ + size_t new_argz_len = *argz_len + buf_len; + char *new_argz = realloc (*argz, new_argz_len); + if (new_argz) + { + memcpy (new_argz + *argz_len, buf, buf_len); + *argz = new_argz; + *argz_len = new_argz_len; + return 0; + } + else + return ENOMEM; +} +weak_alias (__argz_append, argz_append) + +/* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into + argz.c in libshouldbelibc. */ +error_t +__argz_add (char **argz, size_t *argz_len, const char *str) +{ + return __argz_append (argz, argz_len, str, strlen (str) + 1); +} +weak_alias (__argz_add, argz_add) diff --git a/REORG.TODO/string/argz-count.c b/REORG.TODO/string/argz-count.c new file mode 100644 index 0000000000..64e2e69b12 --- /dev/null +++ b/REORG.TODO/string/argz-count.c @@ -0,0 +1,38 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <string.h> + +/* Returns the number of strings in ARGZ. */ +size_t +__argz_count (const char *argz, size_t len) +{ + size_t count = 0; + while (len > 0) + { + size_t part_len = strlen(argz); + argz += part_len + 1; + len -= part_len + 1; + count++; + } + return count; +} +libc_hidden_def (__argz_count) +weak_alias (__argz_count, argz_count) diff --git a/REORG.TODO/string/argz-create.c b/REORG.TODO/string/argz-create.c new file mode 100644 index 0000000000..f7d429b5b6 --- /dev/null +++ b/REORG.TODO/string/argz-create.c @@ -0,0 +1,53 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <stdlib.h> +#include <string.h> + +/* Make a '\0' separated arg vector from a unix argv vector, returning it in + ARGZ, and the total length in LEN. If a memory allocation error occurs, + ENOMEM is returned, otherwise 0. */ +error_t +__argz_create (char *const argv[], char **argz, size_t *len) +{ + int argc; + size_t tlen = 0; + char *const *ap; + char *p; + + for (argc = 0; argv[argc] != NULL; ++argc) + tlen += strlen (argv[argc]) + 1; + + if (tlen == 0) + *argz = NULL; + else + { + *argz = malloc (tlen); + if (*argz == NULL) + return ENOMEM; + + for (p = *argz, ap = argv; *ap; ++ap, ++p) + p = __stpcpy (p, *ap); + } + *len = tlen; + + return 0; +} +weak_alias (__argz_create, argz_create) diff --git a/REORG.TODO/string/argz-ctsep.c b/REORG.TODO/string/argz-ctsep.c new file mode 100644 index 0000000000..7fc1511a4b --- /dev/null +++ b/REORG.TODO/string/argz-ctsep.c @@ -0,0 +1,70 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + + +error_t +__argz_create_sep (const char *string, int delim, char **argz, size_t *len) +{ + size_t nlen = strlen (string) + 1; + + if (nlen > 1) + { + const char *rp; + char *wp; + + *argz = (char *) malloc (nlen); + if (*argz == NULL) + return ENOMEM; + + rp = string; + wp = *argz; + do + if (*rp == delim) + { + if (wp > *argz && wp[-1] != '\0') + *wp++ = '\0'; + else + --nlen; + } + else + *wp++ = *rp; + while (*rp++ != '\0'); + + if (nlen == 0) + { + free (*argz); + *argz = NULL; + *len = 0; + } + + *len = nlen; + } + else + { + *argz = NULL; + *len = 0; + } + + return 0; +} +weak_alias (__argz_create_sep, argz_create_sep) diff --git a/REORG.TODO/string/argz-delete.c b/REORG.TODO/string/argz-delete.c new file mode 100644 index 0000000000..183ac0d43c --- /dev/null +++ b/REORG.TODO/string/argz-delete.c @@ -0,0 +1,41 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.org> + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <string.h> +#include <stdlib.h> + +/* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */ +void +argz_delete (char **argz, size_t *argz_len, char *entry) +{ + if (entry) + /* Get rid of the old value for NAME. */ + { + size_t entry_len = strlen (entry) + 1; + *argz_len -= entry_len; + memmove (entry, entry + entry_len, *argz_len - (entry - *argz)); + if (*argz_len == 0) + { + free (*argz); + *argz = 0; + } + } +} +libc_hidden_def (argz_delete) diff --git a/REORG.TODO/string/argz-extract.c b/REORG.TODO/string/argz-extract.c new file mode 100644 index 0000000000..13345e894f --- /dev/null +++ b/REORG.TODO/string/argz-extract.c @@ -0,0 +1,36 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.org> + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> + +/* Puts pointers to each string in ARGZ, plus a terminating 0 element, into + ARGV, which must be large enough to hold them all. */ +void +__argz_extract (const char *argz, size_t len, char **argv) +{ + while (len > 0) + { + size_t part_len = strlen (argz); + *argv++ = (char *) argz; + argz += part_len + 1; + len -= part_len + 1; + } + *argv = 0; +} +weak_alias (__argz_extract, argz_extract) diff --git a/REORG.TODO/string/argz-insert.c b/REORG.TODO/string/argz-insert.c new file mode 100644 index 0000000000..e4c78407ff --- /dev/null +++ b/REORG.TODO/string/argz-insert.c @@ -0,0 +1,63 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <string.h> +#include <stdlib.h> + +/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an + existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end. + Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN, + ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not + in ARGZ, EINVAL is returned, else if memory can't be allocated for the new + ARGZ, ENOMEM is returned, else 0. */ +error_t +__argz_insert (char **argz, size_t *argz_len, char *before, const char *entry) +{ + if (! before) + return __argz_add (argz, argz_len, entry); + + if (before < *argz || before >= *argz + *argz_len) + return EINVAL; + + if (before > *argz) + /* Make sure before is actually the beginning of an entry. */ + while (before[-1]) + before--; + + { + size_t after_before = *argz_len - (before - *argz); + size_t entry_len = strlen (entry) + 1; + size_t new_argz_len = *argz_len + entry_len; + char *new_argz = realloc (*argz, new_argz_len); + + if (new_argz) + { + before = new_argz + (before - *argz); + memmove (before + entry_len, before, after_before); + memmove (before, entry, entry_len); + *argz = new_argz; + *argz_len = new_argz_len; + return 0; + } + else + return ENOMEM; + } +} +weak_alias (__argz_insert, argz_insert) diff --git a/REORG.TODO/string/argz-next.c b/REORG.TODO/string/argz-next.c new file mode 100644 index 0000000000..9c2fa33cc2 --- /dev/null +++ b/REORG.TODO/string/argz-next.c @@ -0,0 +1,39 @@ +/* Iterate through the elements of an argz block. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.org> + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <string.h> + +char * +__argz_next (const char *argz, size_t argz_len, const char *entry) +{ + if (entry) + { + if (entry < argz + argz_len) + entry = strchr (entry, '\0') + 1; + + return entry >= argz + argz_len ? NULL : (char *) entry; + } + else + if (argz_len > 0) + return (char *) argz; + else + return NULL; +} +weak_alias (__argz_next, argz_next) diff --git a/REORG.TODO/string/argz-replace.c b/REORG.TODO/string/argz-replace.c new file mode 100644 index 0000000000..6464e9bdbb --- /dev/null +++ b/REORG.TODO/string/argz-replace.c @@ -0,0 +1,134 @@ +/* String replacement in an argz vector + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <string.h> +#include <argz.h> + +/* Append BUF, of length BUF_LEN to *TO, of length *TO_LEN, reallocating and + updating *TO & *TO_LEN appropriately. If an allocation error occurs, + *TO's old value is freed, and *TO is set to 0. */ +static void +str_append (char **to, size_t *to_len, const char *buf, const size_t buf_len) +{ + size_t new_len = *to_len + buf_len; + char *new_to = realloc (*to, new_len + 1); + + if (new_to) + { + *((char *) __mempcpy (new_to + *to_len, buf, buf_len)) = '\0'; + *to = new_to; + *to_len = new_len; + } + else + { + free (*to); + *to = 0; + } +} + +/* Replace any occurrences of the string STR in ARGZ with WITH, reallocating + ARGZ as necessary. If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be + incremented by number of replacements performed. */ +error_t +__argz_replace (char **argz, size_t *argz_len, const char *str, const char *with, + unsigned *replace_count) +{ + error_t err = 0; + + if (str && *str) + { + char *arg = 0; + char *src = *argz; + size_t src_len = *argz_len; + char *dst = 0; + size_t dst_len = 0; + int delayed_copy = 1; /* True while we've avoided copying anything. */ + size_t str_len = strlen (str), with_len = strlen (with); + + while (!err && (arg = argz_next (src, src_len, arg))) + { + char *match = strstr (arg, str); + if (match) + { + char *from = match + str_len; + size_t to_len = match - arg; + char *to = __strndup (arg, to_len); + + while (to && from) + { + str_append (&to, &to_len, with, with_len); + if (to) + { + match = strstr (from, str); + if (match) + { + str_append (&to, &to_len, from, match - from); + from = match + str_len; + } + else + { + str_append (&to, &to_len, from, strlen (from)); + from = 0; + } + } + } + + if (to) + { + if (delayed_copy) + /* We avoided copying SRC to DST until we found a match; + now that we've done so, copy everything from the start + of SRC. */ + { + if (arg > src) + err = __argz_append (&dst, &dst_len, src, (arg - src)); + delayed_copy = 0; + } + if (! err) + err = __argz_add (&dst, &dst_len, to); + free (to); + } + else + err = ENOMEM; + + if (replace_count) + (*replace_count)++; + } + else if (! delayed_copy) + err = __argz_add (&dst, &dst_len, arg); + } + + if (! err) + { + if (! delayed_copy) + /* We never found any instances of str. */ + { + free (src); + *argz = dst; + *argz_len = dst_len; + } + } + else if (dst_len > 0) + free (dst); + } + + return err; +} +weak_alias (__argz_replace, argz_replace) diff --git a/REORG.TODO/string/argz-stringify.c b/REORG.TODO/string/argz-stringify.c new file mode 100644 index 0000000000..5499264d38 --- /dev/null +++ b/REORG.TODO/string/argz-stringify.c @@ -0,0 +1,40 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.org> + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <argz.h> +#include <string.h> + +/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's + except the last into the character SEP. */ +void +__argz_stringify (char *argz, size_t len, int sep) +{ + if (len > 0) + while (1) + { + size_t part_len = __strnlen (argz, len); + argz += part_len; + len -= part_len; + if (len-- <= 1) /* includes final '\0' we want to stop at */ + break; + *argz++ = sep; + } +} +libc_hidden_def (__argz_stringify) +weak_alias (__argz_stringify, argz_stringify) diff --git a/REORG.TODO/string/argz.h b/REORG.TODO/string/argz.h new file mode 100644 index 0000000000..f9d0ac9950 --- /dev/null +++ b/REORG.TODO/string/argz.h @@ -0,0 +1,182 @@ +/* Routines for dealing with '\0' separated arg vectors. + Copyright (C) 1995-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _ARGZ_H +#define _ARGZ_H 1 + +#include <features.h> + +#define __need_error_t +#include <errno.h> +#include <string.h> /* Need size_t, and strchr is called below. */ + +#ifndef __error_t_defined +typedef int error_t; +#endif + + +__BEGIN_DECLS + +/* Make a '\0' separated arg vector from a unix argv vector, returning it in + ARGZ, and the total length in LEN. If a memory allocation error occurs, + ENOMEM is returned, otherwise 0. The result can be destroyed using free. */ +extern error_t __argz_create (char *const __argv[], char **__restrict __argz, + size_t *__restrict __len) __THROW; +extern error_t argz_create (char *const __argv[], char **__restrict __argz, + size_t *__restrict __len) __THROW; + +/* Make a '\0' separated arg vector from a SEP separated list in + STRING, returning it in ARGZ, and the total length in LEN. If a + memory allocation error occurs, ENOMEM is returned, otherwise 0. + The result can be destroyed using free. */ +extern error_t __argz_create_sep (const char *__restrict __string, + int __sep, char **__restrict __argz, + size_t *__restrict __len) __THROW; +extern error_t argz_create_sep (const char *__restrict __string, + int __sep, char **__restrict __argz, + size_t *__restrict __len) __THROW; + +/* Returns the number of strings in ARGZ. */ +extern size_t __argz_count (const char *__argz, size_t __len) + __THROW __attribute_pure__; +extern size_t argz_count (const char *__argz, size_t __len) + __THROW __attribute_pure__; + +/* Puts pointers to each string in ARGZ into ARGV, which must be large enough + to hold them all. */ +extern void __argz_extract (const char *__restrict __argz, size_t __len, + char **__restrict __argv) __THROW; +extern void argz_extract (const char *__restrict __argz, size_t __len, + char **__restrict __argv) __THROW; + +/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's + except the last into the character SEP. */ +extern void __argz_stringify (char *__argz, size_t __len, int __sep) __THROW; +extern void argz_stringify (char *__argz, size_t __len, int __sep) __THROW; + +/* Append BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */ +extern error_t __argz_append (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __buf, size_t __buf_len) + __THROW; +extern error_t argz_append (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __buf, size_t __buf_len) + __THROW; + +/* Append STR to the argz vector in ARGZ & ARGZ_LEN. */ +extern error_t __argz_add (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __str) __THROW; +extern error_t argz_add (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __str) __THROW; + +/* Append SEP separated list in STRING to the argz vector in ARGZ & + ARGZ_LEN. */ +extern error_t __argz_add_sep (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __string, int __delim) + __THROW; +extern error_t argz_add_sep (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __string, int __delim) + __THROW; + +/* Delete ENTRY from ARGZ & ARGZ_LEN, if it appears there. */ +extern void __argz_delete (char **__restrict __argz, + size_t *__restrict __argz_len, + char *__restrict __entry) __THROW; +extern void argz_delete (char **__restrict __argz, + size_t *__restrict __argz_len, + char *__restrict __entry) __THROW; + +/* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an + existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end. + Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN, + ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not + in ARGZ, EINVAL is returned, else if memory can't be allocated for the new + ARGZ, ENOMEM is returned, else 0. */ +extern error_t __argz_insert (char **__restrict __argz, + size_t *__restrict __argz_len, + char *__restrict __before, + const char *__restrict __entry) __THROW; +extern error_t argz_insert (char **__restrict __argz, + size_t *__restrict __argz_len, + char *__restrict __before, + const char *__restrict __entry) __THROW; + +/* Replace any occurrences of the string STR in ARGZ with WITH, reallocating + ARGZ as necessary. If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be + incremented by number of replacements performed. */ +extern error_t __argz_replace (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __str, + const char *__restrict __with, + unsigned int *__restrict __replace_count); +extern error_t argz_replace (char **__restrict __argz, + size_t *__restrict __argz_len, + const char *__restrict __str, + const char *__restrict __with, + unsigned int *__restrict __replace_count); + +/* Returns the next entry in ARGZ & ARGZ_LEN after ENTRY, or NULL if there + are no more. If entry is NULL, then the first entry is returned. This + behavior allows two convenient iteration styles: + + char *entry = 0; + while ((entry = argz_next (argz, argz_len, entry))) + ...; + + or + + char *entry; + for (entry = argz; entry; entry = argz_next (argz, argz_len, entry)) + ...; +*/ +extern char *__argz_next (const char *__restrict __argz, size_t __argz_len, + const char *__restrict __entry) __THROW; +extern char *argz_next (const char *__restrict __argz, size_t __argz_len, + const char *__restrict __entry) __THROW; + +#ifdef __USE_EXTERN_INLINES +__extern_inline char * +__NTH (__argz_next (const char *__argz, size_t __argz_len, + const char *__entry)) +{ + if (__entry) + { + if (__entry < __argz + __argz_len) + __entry = strchr (__entry, '\0') + 1; + + return __entry >= __argz + __argz_len ? (char *) NULL : (char *) __entry; + } + else + return __argz_len > 0 ? (char *) __argz : 0; +} +__extern_inline char * +__NTH (argz_next (const char *__argz, size_t __argz_len, + const char *__entry)) +{ + return __argz_next (__argz, __argz_len, __entry); +} +#endif /* Use extern inlines. */ + +__END_DECLS + +#endif /* argz.h */ diff --git a/REORG.TODO/string/basename.c b/REORG.TODO/string/basename.c new file mode 100644 index 0000000000..0f379680b7 --- /dev/null +++ b/REORG.TODO/string/basename.c @@ -0,0 +1,29 @@ +/* Return the name-within-directory of a file name. + Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +char * +__basename (const char *filename) +{ + char *p = strrchr (filename, '/'); + return p ? p + 1 : (char *) filename; +} +libc_hidden_def (__basename) +weak_alias (__basename, basename) +libc_hidden_weak (basename) diff --git a/REORG.TODO/string/bcopy.c b/REORG.TODO/string/bcopy.c new file mode 100644 index 0000000000..24fe494fec --- /dev/null +++ b/REORG.TODO/string/bcopy.c @@ -0,0 +1,24 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +void +bcopy (const void *src, void *dest, size_t len) +{ + memmove (dest, src, len); +} diff --git a/REORG.TODO/string/bits/string2.h b/REORG.TODO/string/bits/string2.h new file mode 100644 index 0000000000..6a26e2bc68 --- /dev/null +++ b/REORG.TODO/string/bits/string2.h @@ -0,0 +1,119 @@ +/* Machine-independant string function optimizations. + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _STRING_H +# error "Never use <bits/string2.h> directly; include <string.h> instead." +#endif + +#ifndef __NO_STRING_INLINES + +/* Unlike the definitions in the header <bits/string.h> the + definitions contained here are not optimized down to assembler + level. Those optimizations are not always a good idea since this + means the code size increases a lot. Instead the definitions here + optimize some functions in a way which do not dramatically + increase the code size and which do not use assembler. The main + trick is to use GCC's `__builtin_constant_p' function. + + Every function XXX which has a defined version in + <bits/string.h> must be accompanied by a symbol _HAVE_STRING_ARCH_XXX + to make sure we don't get redefinitions. + + We must use here macros instead of inline functions since the + trick won't work with the latter. */ + +#ifndef __STRING_INLINE +# ifdef __cplusplus +# define __STRING_INLINE inline +# else +# define __STRING_INLINE __extern_inline +# endif +#endif + +/* Dereferencing a pointer arg to run sizeof on it fails for the void + pointer case, so we use this instead. + Note that __x is evaluated twice. */ +#define __string2_1bptr_p(__x) \ + ((size_t)(const void *)((__x) + 1) - (size_t)(const void *)(__x) == 1) + +/* Set N bytes of S to 0. */ +#if !defined _HAVE_STRING_ARCH_memset +# define __bzero(s, n) __builtin_memset (s, '\0', n) +#endif + + +/* Copy SRC to DEST, returning pointer to final NUL byte. */ +#ifdef __USE_GNU +# ifndef _HAVE_STRING_ARCH_stpcpy +# define __stpcpy(dest, src) __builtin_stpcpy (dest, src) +/* In glibc we use this function frequently but for namespace reasons + we have to use the name `__stpcpy'. */ +# define stpcpy(dest, src) __stpcpy (dest, src) +# endif +#endif + + +/* Copy no more than N characters of SRC to DEST. */ +#ifndef _HAVE_STRING_ARCH_strncpy +# define strncpy(dest, src, n) __builtin_strncpy (dest, src, n) +#endif + + +/* Append no more than N characters from SRC onto DEST. */ +#ifndef _HAVE_STRING_ARCH_strncat +# ifdef _USE_STRING_ARCH_strchr +# define strncat(dest, src, n) \ + (__extension__ ({ char *__dest = (dest); \ + __builtin_constant_p (src) && __builtin_constant_p (n) \ + ? (strlen (src) < ((size_t) (n)) \ + ? strcat (__dest, src) \ + : (*((char *) __mempcpy (strchr (__dest, '\0'), \ + src, n)) = '\0', __dest)) \ + : strncat (dest, src, n); })) +# else +# define strncat(dest, src, n) __builtin_strncat (dest, src, n) +# endif +#endif + + +/* Return the length of the initial segment of S which + consists entirely of characters not in REJECT. */ +#ifndef _HAVE_STRING_ARCH_strcspn +# define strcspn(s, reject) __builtin_strcspn (s, reject) +#endif + + +/* Return the length of the initial segment of S which + consists entirely of characters in ACCEPT. */ +#ifndef _HAVE_STRING_ARCH_strspn +# define strspn(s, accept) __builtin_strspn (s, accept) +#endif + + +/* Find the first occurrence in S of any character in ACCEPT. */ +#ifndef _HAVE_STRING_ARCH_strpbrk +# define strpbrk(s, accept) __builtin_strpbrk (s, accept) +#endif + + +#ifndef _FORCE_INLINES +# undef __STRING_INLINE +#endif + +#endif /* No string inlines. */ diff --git a/REORG.TODO/string/bits/string3.h b/REORG.TODO/string/bits/string3.h new file mode 100644 index 0000000000..738226d49b --- /dev/null +++ b/REORG.TODO/string/bits/string3.h @@ -0,0 +1,156 @@ +/* Copyright (C) 2004-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _STRING_H +# error "Never use <bits/string3.h> directly; include <string.h> instead." +#endif + +#if !__GNUC_PREREQ (5,0) +__warndecl (__warn_memset_zero_len, + "memset used with constant zero length parameter; this could be due to transposed parameters"); +#endif + +#ifndef __cplusplus +/* XXX This is temporarily. We should not redefine any of the symbols + and instead integrate the error checking into the original + definitions. */ +# undef memcpy +# undef memmove +# undef memset +# undef strcat +# undef strcpy +# undef strncat +# undef strncpy +# ifdef __USE_GNU +# undef mempcpy +# undef stpcpy +# endif +# ifdef __USE_MISC +# undef bcopy +# undef bzero +# endif +#endif + + +__fortify_function void * +__NTH (memcpy (void *__restrict __dest, const void *__restrict __src, + size_t __len)) +{ + return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest)); +} + +__fortify_function void * +__NTH (memmove (void *__dest, const void *__src, size_t __len)) +{ + return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest)); +} + +#ifdef __USE_GNU +__fortify_function void * +__NTH (mempcpy (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. */ +__fortify_function void * +__NTH (memset (void *__dest, int __ch, size_t __len)) +{ + /* GCC-5.0 and newer implements these checks in the compiler, so we don't + need them here. */ +#if !__GNUC_PREREQ (5,0) + if (__builtin_constant_p (__len) && __len == 0 + && (!__builtin_constant_p (__ch) || __ch != 0)) + { + __warn_memset_zero_len (); + return __dest; + } +#endif + return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest)); +} + +#ifdef __USE_MISC +# include <bits/strings_fortified.h> + +void __explicit_bzero_chk (void *__dest, size_t __len, size_t __destlen) + __THROW __nonnull ((1)); + +__fortify_function void +__NTH (explicit_bzero (void *__dest, size_t __len)) +{ + __explicit_bzero_chk (__dest, __len, __bos0 (__dest)); +} +#endif + +__fortify_function char * +__NTH (strcpy (char *__restrict __dest, const char *__restrict __src)) +{ + return __builtin___strcpy_chk (__dest, __src, __bos (__dest)); +} + +#ifdef __USE_GNU +__fortify_function char * +__NTH (stpcpy (char *__restrict __dest, const char *__restrict __src)) +{ + return __builtin___stpcpy_chk (__dest, __src, __bos (__dest)); +} +#endif + + +__fortify_function char * +__NTH (strncpy (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); + +__fortify_function 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); +} + + +__fortify_function char * +__NTH (strcat (char *__restrict __dest, const char *__restrict __src)) +{ + return __builtin___strcat_chk (__dest, __src, __bos (__dest)); +} + + +__fortify_function char * +__NTH (strncat (char *__restrict __dest, const char *__restrict __src, + size_t __len)) +{ + return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest)); +} diff --git a/REORG.TODO/string/bits/strings_fortified.h b/REORG.TODO/string/bits/strings_fortified.h new file mode 100644 index 0000000000..411e7863d6 --- /dev/null +++ b/REORG.TODO/string/bits/strings_fortified.h @@ -0,0 +1,34 @@ +/* Fortify macros for strings.h functions. + Copyright (C) 2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef __STRINGS_FORTIFIED +# define __STRINGS_FORTIFIED 1 + +__fortify_function void +__NTH (bcopy (const void *__src, void *__dest, size_t __len)) +{ + (void) __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest)); +} + +__fortify_function void +__NTH (bzero (void *__dest, size_t __len)) +{ + (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest)); +} + +#endif diff --git a/REORG.TODO/string/bug-envz1.c b/REORG.TODO/string/bug-envz1.c new file mode 100644 index 0000000000..931a0559fe --- /dev/null +++ b/REORG.TODO/string/bug-envz1.c @@ -0,0 +1,75 @@ +/* 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])) + + +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; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/bug-strcoll1.c b/REORG.TODO/string/bug-strcoll1.c new file mode 100644 index 0000000000..b6510d926f --- /dev/null +++ b/REORG.TODO/string/bug-strcoll1.c @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <string.h> +#include <locale.h> + +int +main (void) +{ + const char t1[] = "0-0-0-0-0-0-0-0-0-0.COM"; + const char t2[] = "00000-00000.COM"; + int res1; + int res2; + + setlocale (LC_ALL, "en_US.ISO-8859-1"); + + res1 = strcoll (t1, t2); + printf ("strcoll (\"%s\", \"%s\") = %d\n", t1, t2, res1); + res2 = strcoll (t2, t1); + printf ("strcoll (\"%s\", \"%s\") = %d\n", t2, t1, res2); + + return ((res1 == 0 && res2 != 0) + || (res1 != 0 && res2 == 0) + || (res1 < 0 && res2 < 0) + || (res1 > 0 && res2 > 0)); +} diff --git a/REORG.TODO/string/bug-strcoll2.c b/REORG.TODO/string/bug-strcoll2.c new file mode 100644 index 0000000000..ff33007df6 --- /dev/null +++ b/REORG.TODO/string/bug-strcoll2.c @@ -0,0 +1,91 @@ +/* Bug 18589: sort-test.sh fails at random. + Copyright (C) 2015-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <string.h> +#include <locale.h> + +/* An incorrect strcoll optimization resulted in incorrect + results from strcoll for cs_CZ and da_DK. */ + +int +test_cs_CZ (void) +{ + const char t1[] = "config"; + const char t2[] = "choose"; + if (setlocale (LC_ALL, "cs_CZ.UTF-8") == NULL) + { + perror ("setlocale"); + return 1; + } + /* In Czech the digraph ch sorts after c, therefore we expect + config to sort before choose. */ + int a = strcoll (t1, t2); + int b = strcoll (t2, t1); + printf ("strcoll (\"%s\", \"%s\") = %d\n", t1, t2, a); + printf ("strcoll (\"%s\", \"%s\") = %d\n", t2, t1, b); + if (a < 0 && b > 0) + { + puts ("PASS: config < choose"); + return 0; + } + else + { + puts ("FAIL: Wrong sorting in cs_CZ.UTF-8."); + return 1; + } +} + +int +test_da_DK (void) +{ + const char t1[] = "AS"; + const char t2[] = "AA"; + if (setlocale (LC_ALL, "da_DK.ISO-8859-1") == NULL) + { + perror ("setlocale"); + return 1; + } + /* AA should be treated as the last letter of the Danish alphabet, + hence sorting after AS. */ + int a = strcoll (t1, t2); + int b = strcoll (t2, t1); + printf ("strcoll (\"%s\", \"%s\") = %d\n", t1, t2, a); + printf ("strcoll (\"%s\", \"%s\") = %d\n", t2, t1, b); + if (a < 0 && b > 0) + { + puts ("PASS: AS < AA"); + return 0; + } + else + { + puts ("FAIL: Wrong sorting in da_DK.ISO-8859-1"); + return 1; + } +} + +int +do_test (void) +{ + int err = 0; + err |= test_cs_CZ (); + err |= test_da_DK (); + return err; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/bug-strncat1.c b/REORG.TODO/string/bug-strncat1.c new file mode 100644 index 0000000000..f1b5c37c5c --- /dev/null +++ b/REORG.TODO/string/bug-strncat1.c @@ -0,0 +1,31 @@ +/* Test case by Joseph S. Myers <jsm28@cam.ac.uk>. */ +#undef __USE_STRING_INLINES +#define __USE_STRING_INLINES +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +char d[3] = "\0\1\2"; + +int +main (void) +{ + strncat (d, "\5\6", 1); + if (d[0] != '\5') + { + puts ("d[0] != '\\5'"); + exit (1); + } + if (d[1] != '\0') + { + puts ("d[1] != '\\0'"); + exit (1); + } + if (d[2] != '\2') + { + puts ("d[2] != '\\2'"); + exit (1); + } + + return 0; +} diff --git a/REORG.TODO/string/bug-strpbrk1.c b/REORG.TODO/string/bug-strpbrk1.c new file mode 100644 index 0000000000..28238b0f50 --- /dev/null +++ b/REORG.TODO/string/bug-strpbrk1.c @@ -0,0 +1,19 @@ +/* Test case by Joseph S. Myers <jsm28@cam.ac.uk>. */ +#undef __USE_STRING_INLINES +#define __USE_STRING_INLINES +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +int +main (void) +{ + const char *a = "abc"; + const char *b = a; + + strpbrk (b++, ""); + if (b != a + 1) + return 1; + + return 0; +} diff --git a/REORG.TODO/string/bug-strspn1.c b/REORG.TODO/string/bug-strspn1.c new file mode 100644 index 0000000000..a657bafc43 --- /dev/null +++ b/REORG.TODO/string/bug-strspn1.c @@ -0,0 +1,19 @@ +/* Test case by Joseph S. Myers <jsm28@cam.ac.uk>. */ +#undef __USE_STRING_INLINES +#define __USE_STRING_INLINES +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +int +main (void) +{ + const char *a = "abc"; + const char *b = a; + + strspn (b++, ""); + if (b != a + 1) + return 1; + + return 0; +} diff --git a/REORG.TODO/string/bug-strtok1.c b/REORG.TODO/string/bug-strtok1.c new file mode 100644 index 0000000000..a47b2f3531 --- /dev/null +++ b/REORG.TODO/string/bug-strtok1.c @@ -0,0 +1,44 @@ +/* See BZ #2126. */ +#include <string.h> +#include <stdio.h> + +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; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/byteswap.h b/REORG.TODO/string/byteswap.h new file mode 100644 index 0000000000..4ec8ac7713 --- /dev/null +++ b/REORG.TODO/string/byteswap.h @@ -0,0 +1,39 @@ +/* Copyright (C) 1997-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _BYTESWAP_H +#define _BYTESWAP_H 1 + +#include <features.h> + +/* Get the machine specific, optimized definitions. */ +#include <bits/byteswap.h> + + +/* The following definitions must all be macros since otherwise some + of the possible optimizations are not possible. */ + +/* Return a value with all bytes in the 16 bit argument swapped. */ +#define bswap_16(x) __bswap_16 (x) + +/* Return a value with all bytes in the 32 bit argument swapped. */ +#define bswap_32(x) __bswap_32 (x) + +/* Return a value with all bytes in the 64 bit argument swapped. */ +#define bswap_64(x) __bswap_64 (x) + +#endif /* byteswap.h */ diff --git a/REORG.TODO/string/bzero.c b/REORG.TODO/string/bzero.c new file mode 100644 index 0000000000..9de1f89d10 --- /dev/null +++ b/REORG.TODO/string/bzero.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef __bzero + +/* Set N bytes of S to 0. */ +void +__bzero (void *s, size_t len) +{ + memset (s, '\0', len); +} +weak_alias (__bzero, bzero) diff --git a/REORG.TODO/string/endian.h b/REORG.TODO/string/endian.h new file mode 100644 index 0000000000..dcc9a65df7 --- /dev/null +++ b/REORG.TODO/string/endian.h @@ -0,0 +1,97 @@ +/* Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _ENDIAN_H +#define _ENDIAN_H 1 + +#include <features.h> + +/* Definitions for byte order, according to significance of bytes, + from low addresses to high addresses. The value is what you get by + putting '4' in the most significant byte, '3' in the second most + significant byte, '2' in the second least significant byte, and '1' + in the least significant byte, and then writing down one digit for + each byte, starting with the byte at the lowest address at the left, + and proceeding to the byte with the highest address at the right. */ + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __PDP_ENDIAN 3412 + +/* This file defines `__BYTE_ORDER' for the particular machine. */ +#include <bits/endian.h> + +/* Some machines may need to use a different endianness for floating point + values. */ +#ifndef __FLOAT_WORD_ORDER +# define __FLOAT_WORD_ORDER __BYTE_ORDER +#endif + +#ifdef __USE_MISC +# define LITTLE_ENDIAN __LITTLE_ENDIAN +# define BIG_ENDIAN __BIG_ENDIAN +# define PDP_ENDIAN __PDP_ENDIAN +# define BYTE_ORDER __BYTE_ORDER +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define __LONG_LONG_PAIR(HI, LO) LO, HI +#elif __BYTE_ORDER == __BIG_ENDIAN +# define __LONG_LONG_PAIR(HI, LO) HI, LO +#endif + + +#if defined __USE_MISC && !defined __ASSEMBLER__ +/* Conversion interfaces. */ +# include <bits/byteswap.h> +# include <bits/uintn-identity.h> + +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define htobe16(x) __bswap_16 (x) +# define htole16(x) __uint16_identity (x) +# define be16toh(x) __bswap_16 (x) +# define le16toh(x) __uint16_identity (x) + +# define htobe32(x) __bswap_32 (x) +# define htole32(x) __uint32_identity (x) +# define be32toh(x) __bswap_32 (x) +# define le32toh(x) __uint32_identity (x) + +# define htobe64(x) __bswap_64 (x) +# define htole64(x) __uint64_identity (x) +# define be64toh(x) __bswap_64 (x) +# define le64toh(x) __uint64_identity (x) + +# else +# define htobe16(x) __uint16_identity (x) +# define htole16(x) __bswap_16 (x) +# define be16toh(x) __uint16_identity (x) +# define le16toh(x) __bswap_16 (x) + +# define htobe32(x) __uint32_identity (x) +# define htole32(x) __bswap_32 (x) +# define be32toh(x) __uint32_identity (x) +# define le32toh(x) __bswap_32 (x) + +# define htobe64(x) __uint64_identity (x) +# define htole64(x) __bswap_64 (x) +# define be64toh(x) __uint64_identity (x) +# define le64toh(x) __bswap_64 (x) +# endif +#endif + +#endif /* endian.h */ diff --git a/REORG.TODO/string/envz.c b/REORG.TODO/string/envz.c new file mode 100644 index 0000000000..02fb5cc28a --- /dev/null +++ b/REORG.TODO/string/envz.c @@ -0,0 +1,172 @@ +/* Routines for dealing with '\0' separated environment vectors + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Miles Bader <miles@gnu.org> + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <malloc.h> +#include <string.h> + +#include <envz.h> + +/* The character separating names from values in an envz. */ +#define SEP '=' + +/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none. + If NAME contains the separator character, only the portion before it is + used in the comparison. */ +char * +envz_entry (const char *envz, size_t envz_len, const char *name) +{ + while (envz_len) + { + const char *p = name; + const char *entry = envz; /* Start of this entry. */ + + /* See how far NAME and ENTRY match. */ + while (envz_len && *p == *envz && *p && *p != SEP) + p++, envz++, envz_len--; + + if ((*envz == '\0' || *envz == SEP) && (*p == '\0' || *p == SEP)) + /* Bingo! */ + return (char *) entry; + + /* No match, skip to the next entry. */ + while (envz_len && *envz) + envz++, envz_len--; + if (envz_len) + envz++, envz_len--; /* skip '\0' */ + } + + return 0; +} +libc_hidden_def (envz_entry) + +/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0 + if there is none. */ +char * +envz_get (const char *envz, size_t envz_len, const char *name) +{ + char *entry = envz_entry (envz, envz_len, name); + if (entry) + { + while (*entry && *entry != SEP) + entry++; + if (*entry) + entry++; + else + entry = 0; /* A null entry. */ + } + return entry; +} + +/* Remove the entry for NAME from ENVZ & ENVZ_LEN, if any. */ +void +envz_remove (char **envz, size_t *envz_len, const char *name) +{ + char *entry = envz_entry (*envz, *envz_len, name); + if (entry) + argz_delete (envz, envz_len, entry); +} +libc_hidden_def (envz_remove) + +/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN. If an entry + with the same name already exists in ENVZ, it is removed. If VALUE is + NULL, then the new entry will a special null one, for which envz_get will + return NULL, although envz_entry will still return an entry; this is handy + because when merging with another envz, the null entry can override an + entry in the other one. Null entries can be removed with envz_strip (). */ +error_t +envz_add (char **envz, size_t *envz_len, const char *name, const char *value) +{ + envz_remove (envz, envz_len, name); + + if (value) + /* Add the new value, if there is one. */ + { + size_t name_len = strlen (name); + size_t value_len = strlen (value); + size_t old_envz_len = *envz_len; + size_t new_envz_len = old_envz_len + name_len + 1 + value_len + 1; + char *new_envz = realloc (*envz, new_envz_len); + + if (new_envz) + { + memcpy (new_envz + old_envz_len, name, name_len); + new_envz[old_envz_len + name_len] = SEP; + memcpy (new_envz + old_envz_len + name_len + 1, value, value_len); + new_envz[new_envz_len - 1] = 0; + + *envz = new_envz; + *envz_len = new_envz_len; + + return 0; + } + else + return ENOMEM; + } + else + /* Add a null entry. */ + return __argz_add (envz, envz_len, name); +} + +/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add(). If + OVERRIDE is true, then values in ENVZ2 will supersede those with the same + name in ENV, otherwise not. */ +error_t +envz_merge (char **envz, size_t *envz_len, const char *envz2, + size_t envz2_len, int override) +{ + error_t err = 0; + + while (envz2_len && ! err) + { + char *old = envz_entry (*envz, *envz_len, envz2); + size_t new_len = strlen (envz2) + 1; + + if (! old) + err = __argz_append (envz, envz_len, envz2, new_len); + else if (override) + { + argz_delete (envz, envz_len, old); + err = __argz_append (envz, envz_len, envz2, new_len); + } + + envz2 += new_len; + envz2_len -= new_len; + } + + return err; +} + +/* Remove null entries. */ +void +envz_strip (char **envz, size_t *envz_len) +{ + char *entry = *envz; + size_t left = *envz_len; + while (left) + { + size_t entry_len = strlen (entry) + 1; + left -= entry_len; + if (! strchr (entry, SEP)) + /* Null entry. */ + memmove (entry, entry + entry_len, left); + else + entry += entry_len; + } + *envz_len = entry - *envz; +} diff --git a/REORG.TODO/string/envz.h b/REORG.TODO/string/envz.h new file mode 100644 index 0000000000..330cdd3d8a --- /dev/null +++ b/REORG.TODO/string/envz.h @@ -0,0 +1,73 @@ +/* Routines for dealing with '\0' separated environment vectors + Copyright (C) 1995-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _ENVZ_H +#define _ENVZ_H 1 + +#include <features.h> + +#include <errno.h> + +/* Envz's are argz's too, and should be created etc., using the same + routines. */ +#include <argz.h> + +__BEGIN_DECLS + +/* Returns a pointer to the entry in ENVZ for NAME, or 0 if there is none. */ +extern char *envz_entry (const char *__restrict __envz, size_t __envz_len, + const char *__restrict __name) + __THROW __attribute_pure__; + +/* Returns a pointer to the value portion of the entry in ENVZ for NAME, or 0 + if there is none. */ +extern char *envz_get (const char *__restrict __envz, size_t __envz_len, + const char *__restrict __name) + __THROW __attribute_pure__; + +/* Adds an entry for NAME with value VALUE to ENVZ & ENVZ_LEN. If an entry + with the same name already exists in ENVZ, it is removed. If VALUE is + NULL, then the new entry will a special null one, for which envz_get will + return NULL, although envz_entry will still return an entry; this is handy + because when merging with another envz, the null entry can override an + entry in the other one. Null entries can be removed with envz_strip (). */ +extern error_t envz_add (char **__restrict __envz, + size_t *__restrict __envz_len, + const char *__restrict __name, + const char *__restrict __value) __THROW; + +/* Adds each entry in ENVZ2 to ENVZ & ENVZ_LEN, as if with envz_add(). If + OVERRIDE is true, then values in ENVZ2 will supersede those with the same + name in ENV, otherwise not. */ +extern error_t envz_merge (char **__restrict __envz, + size_t *__restrict __envz_len, + const char *__restrict __envz2, + size_t __envz2_len, int __override) __THROW; + +/* Remove the entry for NAME from ENVZ & ENVZ_LEN, if any. */ +extern void envz_remove (char **__restrict __envz, + size_t *__restrict __envz_len, + const char *__restrict __name) __THROW; + +/* Remove null entries. */ +extern void envz_strip (char **__restrict __envz, + size_t *__restrict __envz_len) __THROW; + +__END_DECLS + +#endif /* envz.h */ diff --git a/REORG.TODO/string/explicit_bzero.c b/REORG.TODO/string/explicit_bzero.c new file mode 100644 index 0000000000..8dadf45ea8 --- /dev/null +++ b/REORG.TODO/string/explicit_bzero.c @@ -0,0 +1,38 @@ +/* Erasure of sensitive data, generic implementation. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* An assembler implementation of explicit_bzero can be created as an + assembler alias of an optimized bzero implementation. + Architecture-specific implementations also need to define + __explicit_bzero_chk. */ + +#include <string.h> + +/* glibc-internal users use __explicit_bzero_chk, and explicit_bzero + redirects to that. */ +#undef explicit_bzero + +/* Set LEN bytes of S to 0. The compiler will not delete a call to + this function, even if S is dead after the call. */ +void +explicit_bzero (void *s, size_t len) +{ + memset (s, '\0', len); + /* Compiler barrier. */ + asm volatile ("" ::: "memory"); +} diff --git a/REORG.TODO/string/ffs.c b/REORG.TODO/string/ffs.c new file mode 100644 index 0000000000..367cbbfb84 --- /dev/null +++ b/REORG.TODO/string/ffs.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <limits.h> +#define ffsl __something_else +#include <string.h> + +#undef ffs + +/* Find the first bit set in I. */ +int +__ffs (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_def (__ffs) +libc_hidden_builtin_def (ffs) + +#if ULONG_MAX == UINT_MAX +#undef ffsl +weak_alias (__ffs, ffsl) +#endif diff --git a/REORG.TODO/string/ffsll.c b/REORG.TODO/string/ffsll.c new file mode 100644 index 0000000000..5e403ef938 --- /dev/null +++ b/REORG.TODO/string/ffsll.c @@ -0,0 +1,40 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <limits.h> +#define ffsl __something_else +#include <string.h> + +#undef ffsll + +/* Find the first bit set in I. */ +int +ffsll (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/REORG.TODO/string/inl-tester.c b/REORG.TODO/string/inl-tester.c new file mode 100644 index 0000000000..88528e5ed8 --- /dev/null +++ b/REORG.TODO/string/inl-tester.c @@ -0,0 +1,6 @@ +/* We want to test the inline functions here. */ + +#define DO_STRING_INLINES +#undef __USE_STRING_INLINES +#define __USE_STRING_INLINES 1 +#include "tester.c" diff --git a/REORG.TODO/string/memccpy.c b/REORG.TODO/string/memccpy.c new file mode 100644 index 0000000000..605a453a69 --- /dev/null +++ b/REORG.TODO/string/memccpy.c @@ -0,0 +1,42 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef __memccpy +#undef memccpy + +#ifdef MEMCCPY +# define __memccpy MEMCCPY +#endif + +/* 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 (void *dest, const void *src, int c, size_t n) +{ + void *p = memchr (src, c, n); + + if (p != NULL) + return __mempcpy (dest, src, p - src + 1); + + memcpy (dest, src, n); + return NULL; +} + +weak_alias (__memccpy, memccpy) diff --git a/REORG.TODO/string/memchr.c b/REORG.TODO/string/memchr.c new file mode 100644 index 0000000000..f6708fd917 --- /dev/null +++ b/REORG.TODO/string/memchr.c @@ -0,0 +1,162 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBC +# include <config.h> +#endif + +#include <string.h> + +#include <stddef.h> + +#include <limits.h> + +#undef __memchr +#ifdef _LIBC +# undef memchr +#endif + +#ifndef weak_alias +# define __memchr memchr +#endif + +#ifndef MEMCHR +# define MEMCHR __memchr +#endif + +/* Search no more than N bytes of S for C. */ +void * +MEMCHR (void const *s, int c_in, size_t n) +{ + /* On 32-bit hardware, choosing longword to be a 32-bit unsigned + long instead of a 64-bit uintmax_t tends to give better + performance. On 64-bit hardware, unsigned long is generally 64 + bits already. Change this typedef to experiment with + performance. */ + typedef unsigned long int longword; + + const unsigned char *char_ptr; + const longword *longword_ptr; + longword repeated_one; + longword repeated_c; + unsigned char c; + + c = (unsigned char) c_in; + + /* Handle the first few bytes by reading one byte at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s; + n > 0 && (size_t) char_ptr % sizeof (longword) != 0; + --n, ++char_ptr) + if (*char_ptr == c) + return (void *) char_ptr; + + longword_ptr = (const longword *) char_ptr; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to any size longwords. */ + + /* Compute auxiliary longword values: + repeated_one is a value which has a 1 in every byte. + repeated_c has c in every byte. */ + repeated_one = 0x01010101; + repeated_c = c | (c << 8); + repeated_c |= repeated_c << 16; + if (0xffffffffU < (longword) -1) + { + repeated_one |= repeated_one << 31 << 1; + repeated_c |= repeated_c << 31 << 1; + if (8 < sizeof (longword)) + { + size_t i; + + for (i = 64; i < sizeof (longword) * 8; i *= 2) + { + repeated_one |= repeated_one << i; + repeated_c |= repeated_c << i; + } + } + } + + /* Instead of the traditional loop which tests each byte, 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 equal to c. We first use an xor + with repeated_c. This reduces the task to testing whether *any of the + four* bytes in longword1 is zero. + + We compute tmp = + ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7). + That is, we perform the following operations: + 1. Subtract repeated_one. + 2. & ~longword1. + 3. & a mask consisting of 0x80 in every byte. + Consider what happens in each byte: + - If a byte of longword1 is zero, step 1 and 2 transform it into 0xff, + and step 3 transforms it into 0x80. A carry can also be propagated + to more significant bytes. + - If a byte of longword1 is nonzero, let its lowest 1 bit be at + position k (0 <= k <= 7); so the lowest k bits are 0. After step 1, + the byte ends in a single bit of value 0 and k bits of value 1. + After step 2, the result is just k bits of value 1: 2^k - 1. After + step 3, the result is 0. And no carry is produced. + So, if longword1 has only non-zero bytes, tmp is zero. + Whereas if longword1 has a zero byte, call j the position of the least + significant zero byte. Then the result has a zero at positions 0, ..., + j-1 and a 0x80 at position j. We cannot predict the result at the more + significant bytes (positions j+1..3), but it does not matter since we + already have a non-zero bit at position 8*j+7. + + So, the test whether any byte in longword1 is zero is equivalent to + testing whether tmp is nonzero. */ + + while (n >= sizeof (longword)) + { + longword longword1 = *longword_ptr ^ repeated_c; + + if ((((longword1 - repeated_one) & ~longword1) + & (repeated_one << 7)) != 0) + break; + longword_ptr++; + n -= sizeof (longword); + } + + char_ptr = (const unsigned char *) longword_ptr; + + /* At this point, we know that either n < sizeof (longword), or one of the + sizeof (longword) bytes starting at char_ptr is == c. On little-endian + machines, we could determine the first such byte without any further + memory accesses, just by looking at the tmp result from the last loop + iteration. But this does not work on big-endian machines. Choose code + that works in both cases. */ + + for (; n > 0; --n, ++char_ptr) + { + if (*char_ptr == c) + return (void *) char_ptr; + } + + return NULL; +} +#ifdef weak_alias +weak_alias (__memchr, memchr) +#endif +libc_hidden_builtin_def (memchr) diff --git a/REORG.TODO/string/memcmp.c b/REORG.TODO/string/memcmp.c new file mode 100644 index 0000000000..c53ab3185d --- /dev/null +++ b/REORG.TODO/string/memcmp.c @@ -0,0 +1,364 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#undef __ptr_t +#define __ptr_t void * + +#if defined HAVE_STRING_H || defined _LIBC +# include <string.h> +#endif + +#undef memcmp + +#ifndef MEMCMP +# define MEMCMP memcmp +#endif + +#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; + +static int +memcmp_bytes (op_t a, op_t 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 (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 (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 (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/REORG.TODO/string/memcpy.c b/REORG.TODO/string/memcpy.c new file mode 100644 index 0000000000..974f65ef94 --- /dev/null +++ b/REORG.TODO/string/memcpy.c @@ -0,0 +1,60 @@ +/* Copy memory to memory until the specified number of bytes + has been copied. Overlap is NOT handled correctly. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <memcopy.h> + +#undef memcpy + +void * +memcpy (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/REORG.TODO/string/memfrob.c b/REORG.TODO/string/memfrob.c new file mode 100644 index 0000000000..91e162e28f --- /dev/null +++ b/REORG.TODO/string/memfrob.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +void * +memfrob (void *s, size_t n) +{ + char *p = (char *) s; + + while (n-- > 0) + *p++ ^= 42; + + return s; +} diff --git a/REORG.TODO/string/memmem.c b/REORG.TODO/string/memmem.c new file mode 100644 index 0000000000..54fca4966d --- /dev/null +++ b/REORG.TODO/string/memmem.c @@ -0,0 +1,81 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* This particular implementation was written by Eric Blake, 2008. */ + +#ifndef _LIBC +# include <config.h> +#endif + +/* Specification of memmem. */ +#include <string.h> + +#ifndef _LIBC +# define __builtin_expect(expr, val) (expr) +# define __memmem memmem +#endif + +#define RETURN_TYPE void * +#define AVAILABLE(h, h_l, j, n_l) ((j) <= (h_l) - (n_l)) +#include "str-two-way.h" + +#undef memmem + +/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK + if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in + HAYSTACK. */ +void * +__memmem (const void *haystack_start, size_t haystack_len, + const void *needle_start, size_t needle_len) +{ + /* Abstract memory is considered to be an array of 'unsigned char' values, + not an array of 'char' values. See ISO C 99 section 6.2.6.1. */ + const unsigned char *haystack = (const unsigned char *) haystack_start; + const unsigned char *needle = (const unsigned char *) needle_start; + + 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 (__glibc_unlikely (haystack_len < needle_len)) + return NULL; + + /* Use optimizations in memchr when possible, to reduce the search + size of haystack using a linear algorithm with a smaller + coefficient. However, avoid memchr for long needles, since we + can often achieve sublinear performance. */ + if (needle_len < LONG_NEEDLE_THRESHOLD) + { + haystack = memchr (haystack, *needle, haystack_len); + if (!haystack || __builtin_expect (needle_len == 1, 0)) + return (void *) haystack; + haystack_len -= haystack - (const unsigned char *) haystack_start; + if (haystack_len < needle_len) + return NULL; + return two_way_short_needle (haystack, haystack_len, needle, needle_len); + } + else + return two_way_long_needle (haystack, haystack_len, needle, needle_len); +} +libc_hidden_def (__memmem) +weak_alias (__memmem, memmem) +libc_hidden_weak (memmem) + +#undef LONG_NEEDLE_THRESHOLD diff --git a/REORG.TODO/string/memmove.c b/REORG.TODO/string/memmove.c new file mode 100644 index 0000000000..d8c2116b01 --- /dev/null +++ b/REORG.TODO/string/memmove.c @@ -0,0 +1,115 @@ +/* Copy memory to memory until the specified number of bytes + has been copied. Overlap is handled correctly. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <memcopy.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 + +#ifndef MEMMOVE +#define MEMMOVE memmove +#endif + +rettype +inhibit_loop_to_libcall +MEMMOVE (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 MEMCPY_OK_FOR_FWD_MEMMOVE + dest = memcpy (dest, src, len); +#else + /* 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); +#endif /* MEMCPY_OK_FOR_FWD_MEMMOVE */ + } + 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/REORG.TODO/string/memory.h b/REORG.TODO/string/memory.h new file mode 100644 index 0000000000..36ad3808f8 --- /dev/null +++ b/REORG.TODO/string/memory.h @@ -0,0 +1,33 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * SVID + */ + +#ifndef _MEMORY_H +#define _MEMORY_H 1 + +#include <features.h> + + +#ifndef _STRING_H +# include <string.h> +#endif /* string.h */ + + +#endif /* memory.h */ diff --git a/REORG.TODO/string/mempcpy.c b/REORG.TODO/string/mempcpy.c new file mode 100644 index 0000000000..7a8718e79f --- /dev/null +++ b/REORG.TODO/string/mempcpy.c @@ -0,0 +1,39 @@ +/* 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-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define NO_MEMPCPY_STPCPY_REDIRECT +#include <string.h> + +#undef mempcpy +#undef __mempcpy + +#ifndef MEMPCPY +# define MEMPCPY __mempcpy +#endif + +void * +MEMPCPY (void *dest, const void *src, size_t len) +{ + return memcpy (dest, src, len) + len; +} +libc_hidden_def (__mempcpy) +weak_alias (__mempcpy, mempcpy) +libc_hidden_builtin_def (mempcpy) diff --git a/REORG.TODO/string/memrchr.c b/REORG.TODO/string/memrchr.c new file mode 100644 index 0000000000..0ecfe08842 --- /dev/null +++ b/REORG.TODO/string/memrchr.c @@ -0,0 +1,200 @@ +/* memrchr -- find the last occurrence of a byte in a memory block + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef __ptr_t +#define __ptr_t void * + +#if defined _LIBC +# include <string.h> +# include <memcopy.h> +#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 +#ifndef MEMRCHR +__memrchr +#else +MEMRCHR +#endif + (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 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. */ + magic_bits = -1; + magic_bits = magic_bits / 0xff * 0xfe << 1 >> 1 | 1; + + /* 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; +} +#ifndef MEMRCHR +# ifdef weak_alias +weak_alias (__memrchr, memrchr) +# endif +#endif diff --git a/REORG.TODO/string/memset.c b/REORG.TODO/string/memset.c new file mode 100644 index 0000000000..549790c356 --- /dev/null +++ b/REORG.TODO/string/memset.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <memcopy.h> + +#undef memset + +void * +inhibit_loop_to_libcall +memset (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/REORG.TODO/string/noinl-tester.c b/REORG.TODO/string/noinl-tester.c new file mode 100644 index 0000000000..2e994f73f9 --- /dev/null +++ b/REORG.TODO/string/noinl-tester.c @@ -0,0 +1,4 @@ +/* We don't want to test any of the inline functions here. */ + +#define __NO_STRING_INLINES 1 +#include "tester.c" diff --git a/REORG.TODO/string/rawmemchr.c b/REORG.TODO/string/rawmemchr.c new file mode 100644 index 0000000000..42a3f8aaba --- /dev/null +++ b/REORG.TODO/string/rawmemchr.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <libc-diag.h> + +#ifndef RAWMEMCHR +# define RAWMEMCHR __rawmemchr +#endif + +/* Find the first occurrence of C in S. */ +void * +RAWMEMCHR (const void *s, int c) +{ + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 8 warns about the size passed to memchr being larger than + PTRDIFF_MAX; the use of SIZE_MAX is deliberate here. */ + DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-overflow="); +#endif + if (c != '\0') + return memchr (s, c, (size_t)-1); + DIAG_POP_NEEDS_COMMENT; + return (char *)s + strlen (s); +} +libc_hidden_def (__rawmemchr) +weak_alias (__rawmemchr, rawmemchr) diff --git a/REORG.TODO/string/stpcpy.c b/REORG.TODO/string/stpcpy.c new file mode 100644 index 0000000000..1603fb319b --- /dev/null +++ b/REORG.TODO/string/stpcpy.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define NO_MEMPCPY_STPCPY_REDIRECT +#include <string.h> + +#undef __stpcpy +#undef stpcpy + +#ifndef STPCPY +# define STPCPY __stpcpy +#endif + +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +char * +STPCPY (char *dest, const char *src) +{ + size_t len = strlen (src); + return memcpy (dest, src, len + 1) + len; +} +weak_alias (__stpcpy, stpcpy) +libc_hidden_def (__stpcpy) +libc_hidden_builtin_def (stpcpy) diff --git a/REORG.TODO/string/stpncpy.c b/REORG.TODO/string/stpncpy.c new file mode 100644 index 0000000000..9b8ef348e5 --- /dev/null +++ b/REORG.TODO/string/stpncpy.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1993-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef _LIBC +# include <string.h> +#else +# include <sys/types.h> +#endif + +#ifndef STPNCPY +# ifdef weak_alias +# define STPNCPY __stpncpy +weak_alias (__stpncpy, stpncpy) +# else +# define STPNCPY stpncpy +# endif +#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 (char *dest, const char *src, size_t n) +{ + size_t size = __strnlen (src, n); + memcpy (dest, src, size); + dest += size; + if (size == n) + return dest; + return memset (dest, '\0', n - size); +} +#ifdef weak_alias +libc_hidden_def (__stpncpy) +#endif diff --git a/REORG.TODO/string/str-two-way.h b/REORG.TODO/string/str-two-way.h new file mode 100644 index 0000000000..599c867ffd --- /dev/null +++ b/REORG.TODO/string/str-two-way.h @@ -0,0 +1,527 @@ +/* Byte-wise substring search, using the Two-Way algorithm. + Copyright (C) 2008-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Eric Blake <ebb9@byu.net>, 2008. + + 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, see + <http://www.gnu.org/licenses/>. */ + +/* Before including this file, you need to include <string.h> (and + <config.h> before that, if not part of libc), and define: + RETURN_TYPE A macro that expands to the return type. + AVAILABLE(h, h_l, j, n_l) + A macro that returns nonzero if there are + at least N_L bytes left starting at H[J]. + H is 'unsigned char *', H_L, J, and N_L + are 'size_t'; H_L is an lvalue. For + NUL-terminated searches, H_L can be + modified each iteration to avoid having + to compute the end of H up front. + + For case-insensitivity, you may optionally define: + CMP_FUNC(p1, p2, l) A macro that returns 0 iff the first L + characters of P1 and P2 are equal. + CANON_ELEMENT(c) A macro that canonicalizes an element right after + it has been fetched from one of the two strings. + The argument is an 'unsigned char'; the result + must be an 'unsigned char' as well. + + Other macros you may optionally define: + RET0_IF_0(a) Documented below at default definition. + CHECK_EOL Same. + + This file undefines the macros listed above, and defines + LONG_NEEDLE_THRESHOLD. +*/ + +#include <limits.h> +#include <stdint.h> +#include <sys/param.h> /* Defines MAX. */ + +/* We use the Two-Way string matching algorithm, which guarantees + linear complexity with constant space. Additionally, for long + needles, we also use a bad character shift table similar to the + Boyer-Moore algorithm to achieve improved (potentially sub-linear) + performance. + + See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260 + and http://en.wikipedia.org/wiki/Boyer-Moore_string_search_algorithm +*/ + +/* Point at which computing a bad-byte shift table is likely to be + worthwhile. Small needles should not compute a table, since it + adds (1 << CHAR_BIT) + NEEDLE_LEN computations of preparation for a + speedup no greater than a factor of NEEDLE_LEN. The larger the + needle, the better the potential performance gain. On the other + hand, on non-POSIX systems with CHAR_BIT larger than eight, the + memory required for the table is prohibitive. */ +#if CHAR_BIT < 10 +# define LONG_NEEDLE_THRESHOLD 32U +#else +# define LONG_NEEDLE_THRESHOLD SIZE_MAX +#endif + +#ifndef CANON_ELEMENT +# define CANON_ELEMENT(c) c +#endif +#ifndef CMP_FUNC +# define CMP_FUNC memcmp +#endif + +/* Check for end-of-line in strstr and strcasestr routines. + We piggy-back matching procedure for detecting EOL where possible, + and use AVAILABLE macro otherwise. */ +#ifndef CHECK_EOL +# define CHECK_EOL (0) +#endif + +/* Return NULL if argument is '\0'. */ +#ifndef RET0_IF_0 +# define RET0_IF_0(a) /* nothing */ +#endif + +/* Perform a critical factorization of NEEDLE, of length NEEDLE_LEN. + Return the index of the first byte in the right half, and set + *PERIOD to the global period of the right half. + + The global period of a string is the smallest index (possibly its + length) at which all remaining bytes in the string are repetitions + of the prefix (the last repetition may be a subset of the prefix). + + When NEEDLE is factored into two halves, a local period is the + length of the smallest word that shares a suffix with the left half + and shares a prefix with the right half. All factorizations of a + non-empty NEEDLE have a local period of at least 1 and no greater + than NEEDLE_LEN. + + A critical factorization has the property that the local period + equals the global period. All strings have at least one critical + factorization with the left half smaller than the global period. + + Given an ordered alphabet, a critical factorization can be computed + in linear time, with 2 * NEEDLE_LEN comparisons, by computing the + larger of two ordered maximal suffixes. The ordered maximal + suffixes are determined by lexicographic comparison of + periodicity. */ +static size_t +critical_factorization (const unsigned char *needle, size_t needle_len, + size_t *period) +{ + /* Index of last byte of left half, or SIZE_MAX. */ + size_t max_suffix, max_suffix_rev; + size_t j; /* Index into NEEDLE for current candidate suffix. */ + size_t k; /* Offset into current period. */ + size_t p; /* Intermediate period. */ + unsigned char a, b; /* Current comparison bytes. */ + + /* Invariants: + 0 <= j < NEEDLE_LEN - 1 + -1 <= max_suffix{,_rev} < j (treating SIZE_MAX as if it were signed) + min(max_suffix, max_suffix_rev) < global period of NEEDLE + 1 <= p <= global period of NEEDLE + p == global period of the substring NEEDLE[max_suffix{,_rev}+1...j] + 1 <= k <= p + */ + + /* Perform lexicographic search. */ + max_suffix = SIZE_MAX; + j = 0; + k = p = 1; + while (j + k < needle_len) + { + a = CANON_ELEMENT (needle[j + k]); + b = CANON_ELEMENT (needle[max_suffix + k]); + if (a < b) + { + /* Suffix is smaller, period is entire prefix so far. */ + j += k; + k = 1; + p = j - max_suffix; + } + else if (a == b) + { + /* Advance through repetition of the current period. */ + if (k != p) + ++k; + else + { + j += p; + k = 1; + } + } + else /* b < a */ + { + /* Suffix is larger, start over from current location. */ + max_suffix = j++; + k = p = 1; + } + } + *period = p; + + /* Perform reverse lexicographic search. */ + max_suffix_rev = SIZE_MAX; + j = 0; + k = p = 1; + while (j + k < needle_len) + { + a = CANON_ELEMENT (needle[j + k]); + b = CANON_ELEMENT (needle[max_suffix_rev + k]); + if (b < a) + { + /* Suffix is smaller, period is entire prefix so far. */ + j += k; + k = 1; + p = j - max_suffix_rev; + } + else if (a == b) + { + /* Advance through repetition of the current period. */ + if (k != p) + ++k; + else + { + j += p; + k = 1; + } + } + else /* a < b */ + { + /* Suffix is larger, start over from current location. */ + max_suffix_rev = j++; + k = p = 1; + } + } + + /* Choose the longer suffix. Return the first byte of the right + half, rather than the last byte of the left half. */ + if (max_suffix_rev + 1 < max_suffix + 1) + return max_suffix + 1; + *period = p; + return max_suffix_rev + 1; +} + +/* Return the first location of non-empty NEEDLE within HAYSTACK, or + NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This + method is optimized for NEEDLE_LEN < LONG_NEEDLE_THRESHOLD. + Performance is guaranteed to be linear, with an initialization cost + of 2 * NEEDLE_LEN comparisons. + + If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */ +static RETURN_TYPE +two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) +{ + size_t i; /* Index into current byte of NEEDLE. */ + size_t j; /* Index into current window of HAYSTACK. */ + size_t period; /* The period of the right half of needle. */ + size_t suffix; /* The index of the right half of needle. */ + + /* Factor the needle into two halves, such that the left half is + smaller than the global period, and the right half is + periodic (with a period as large as NEEDLE_LEN - suffix). */ + suffix = critical_factorization (needle, needle_len, &period); + + /* Perform the search. Each iteration compares the right half + first. */ + if (CMP_FUNC (needle, needle + period, suffix) == 0) + { + /* Entire needle is periodic; a mismatch can only advance by the + period, so use memory to avoid rescanning known occurrences + of the period. */ + size_t memory = 0; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + const unsigned char *pneedle; + const unsigned char *phaystack; + + /* Scan for matches in right half. */ + i = MAX (suffix, memory); + pneedle = &needle[i]; + phaystack = &haystack[i + j]; + while (i < needle_len && (CANON_ELEMENT (*pneedle++) + == CANON_ELEMENT (*phaystack++))) + ++i; + if (needle_len <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + pneedle = &needle[i]; + phaystack = &haystack[i + j]; + while (memory < i + 1 && (CANON_ELEMENT (*pneedle--) + == CANON_ELEMENT (*phaystack--))) + --i; + if (i + 1 < memory + 1) + return (RETURN_TYPE) (haystack + j); + /* No match, so remember how many repetitions of period + on the right half were scanned. */ + j += period; + memory = needle_len - period; + } + else + { + j += i - suffix + 1; + memory = 0; + } + } + } + else + { + const unsigned char *phaystack = &haystack[suffix]; + /* The comparison always starts from needle[suffix], so cache it + and use an optimized first-character loop. */ + unsigned char needle_suffix = CANON_ELEMENT (needle[suffix]); + +#if CHECK_EOL + /* We start matching from the SUFFIX'th element, so make sure we + don't hit '\0' before that. */ + if (haystack_len < suffix + 1 + && !AVAILABLE (haystack, haystack_len, 0, suffix + 1)) + return NULL; +#endif + + /* The two halves of needle are distinct; no extra memory is + required, and any mismatch results in a maximal shift. */ + period = MAX (suffix, needle_len - suffix) + 1; + j = 0; + while (1 +#if !CHECK_EOL + && AVAILABLE (haystack, haystack_len, j, needle_len) +#endif + ) + { + unsigned char haystack_char; + const unsigned char *pneedle; + + /* TODO: The first-character loop can be sped up by adapting + longword-at-a-time implementation of memchr/strchr. */ + if (needle_suffix + != (haystack_char = CANON_ELEMENT (*phaystack++))) + { + RET0_IF_0 (haystack_char); +#if !CHECK_EOL + ++j; +#endif + continue; + } + +#if CHECK_EOL + /* Calculate J if it wasn't kept up-to-date in the first-character + loop. */ + j = phaystack - &haystack[suffix] - 1; +#endif + + /* Scan for matches in right half. */ + i = suffix + 1; + pneedle = &needle[i]; + while (i < needle_len) + { + if (CANON_ELEMENT (*pneedle++) + != (haystack_char = CANON_ELEMENT (*phaystack++))) + { + RET0_IF_0 (haystack_char); + break; + } + ++i; + } + if (needle_len <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + pneedle = &needle[i]; + phaystack = &haystack[i + j]; + while (i != SIZE_MAX) + { + if (CANON_ELEMENT (*pneedle--) + != (haystack_char = CANON_ELEMENT (*phaystack--))) + { + RET0_IF_0 (haystack_char); + break; + } + --i; + } + if (i == SIZE_MAX) + return (RETURN_TYPE) (haystack + j); + j += period; + } + else + j += i - suffix + 1; + +#if CHECK_EOL + if (!AVAILABLE (haystack, haystack_len, j, needle_len)) + break; +#endif + + phaystack = &haystack[suffix + j]; + } + } + ret0: __attribute__ ((unused)) + return NULL; +} + +/* Return the first location of non-empty NEEDLE within HAYSTACK, or + NULL. HAYSTACK_LEN is the minimum known length of HAYSTACK. This + method is optimized for LONG_NEEDLE_THRESHOLD <= NEEDLE_LEN. + Performance is guaranteed to be linear, with an initialization cost + of 3 * NEEDLE_LEN + (1 << CHAR_BIT) operations. + + If AVAILABLE does not modify HAYSTACK_LEN (as in memmem), then at + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, + and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and + sublinear performance is not possible. */ +static RETURN_TYPE +two_way_long_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) +{ + size_t i; /* Index into current byte of NEEDLE. */ + size_t j; /* Index into current window of HAYSTACK. */ + size_t period; /* The period of the right half of needle. */ + size_t suffix; /* The index of the right half of needle. */ + size_t shift_table[1U << CHAR_BIT]; /* See below. */ + + /* Factor the needle into two halves, such that the left half is + smaller than the global period, and the right half is + periodic (with a period as large as NEEDLE_LEN - suffix). */ + suffix = critical_factorization (needle, needle_len, &period); + + /* Populate shift_table. For each possible byte value c, + shift_table[c] is the distance from the last occurrence of c to + the end of NEEDLE, or NEEDLE_LEN if c is absent from the NEEDLE. + shift_table[NEEDLE[NEEDLE_LEN - 1]] contains the only 0. */ + for (i = 0; i < 1U << CHAR_BIT; i++) + shift_table[i] = needle_len; + for (i = 0; i < needle_len; i++) + shift_table[CANON_ELEMENT (needle[i])] = needle_len - i - 1; + + /* Perform the search. Each iteration compares the right half + first. */ + if (CMP_FUNC (needle, needle + period, suffix) == 0) + { + /* Entire needle is periodic; a mismatch can only advance by the + period, so use memory to avoid rescanning known occurrences + of the period. */ + size_t memory = 0; + size_t shift; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + const unsigned char *pneedle; + const unsigned char *phaystack; + + /* Check the last byte first; if it does not match, then + shift to the next possible match location. */ + shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; + if (0 < shift) + { + if (memory && shift < period) + { + /* Since needle is periodic, but the last period has + a byte out of place, there can be no match until + after the mismatch. */ + shift = needle_len - period; + } + memory = 0; + j += shift; + continue; + } + /* Scan for matches in right half. The last byte has + already been matched, by virtue of the shift table. */ + i = MAX (suffix, memory); + pneedle = &needle[i]; + phaystack = &haystack[i + j]; + while (i < needle_len - 1 && (CANON_ELEMENT (*pneedle++) + == CANON_ELEMENT (*phaystack++))) + ++i; + if (needle_len - 1 <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + pneedle = &needle[i]; + phaystack = &haystack[i + j]; + while (memory < i + 1 && (CANON_ELEMENT (*pneedle--) + == CANON_ELEMENT (*phaystack--))) + --i; + if (i + 1 < memory + 1) + return (RETURN_TYPE) (haystack + j); + /* No match, so remember how many repetitions of period + on the right half were scanned. */ + j += period; + memory = needle_len - period; + } + else + { + j += i - suffix + 1; + memory = 0; + } + } + } + else + { + /* The two halves of needle are distinct; no extra memory is + required, and any mismatch results in a maximal shift. */ + size_t shift; + period = MAX (suffix, needle_len - suffix) + 1; + j = 0; + while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + const unsigned char *pneedle; + const unsigned char *phaystack; + + /* Check the last byte first; if it does not match, then + shift to the next possible match location. */ + shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])]; + if (0 < shift) + { + j += shift; + continue; + } + /* Scan for matches in right half. The last byte has + already been matched, by virtue of the shift table. */ + i = suffix; + pneedle = &needle[i]; + phaystack = &haystack[i + j]; + while (i < needle_len - 1 && (CANON_ELEMENT (*pneedle++) + == CANON_ELEMENT (*phaystack++))) + ++i; + if (needle_len - 1 <= i) + { + /* Scan for matches in left half. */ + i = suffix - 1; + pneedle = &needle[i]; + phaystack = &haystack[i + j]; + while (i != SIZE_MAX && (CANON_ELEMENT (*pneedle--) + == CANON_ELEMENT (*phaystack--))) + --i; + if (i == SIZE_MAX) + return (RETURN_TYPE) (haystack + j); + j += period; + } + else + j += i - suffix + 1; + } + } + return NULL; +} + +#undef AVAILABLE +#undef CANON_ELEMENT +#undef CMP_FUNC +#undef RET0_IF_0 +#undef RETURN_TYPE +#undef CHECK_EOL diff --git a/REORG.TODO/string/stratcliff.c b/REORG.TODO/string/stratcliff.c new file mode 100644 index 0000000000..e28b0c5058 --- /dev/null +++ b/REORG.TODO/string/stratcliff.c @@ -0,0 +1,561 @@ +/* Test for string function add boundaries of usable memory. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define _GNU_SOURCE 1 + +/* Make sure we don't test the optimized inline functions if we want to + test the real implementation. */ +#undef __USE_STRING_INLINES + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/param.h> + +#ifndef CHAR +# define L(c) c +# define CHAR char +# define MEMSET memset +# define STRLEN strlen +# define STRNLEN strnlen +# define STRCHR strchr +# define STRRCHR strrchr +# define STRCPY strcpy +# define STRNCPY strncpy +# define MEMCMP memcmp +# define STPCPY stpcpy +# define STPNCPY stpncpy +# define MEMCPY memcpy +# define MEMPCPY mempcpy +# define MEMCHR memchr +# define STRCMP strcmp +# define STRNCMP strncmp +#endif + + +#define STRINGIFY(s) STRINGIFY2 (s) +#define STRINGIFY2(s) #s + + +int +do_test (void) +{ + int size = sysconf (_SC_PAGESIZE); + int nchars = size / sizeof (CHAR); + CHAR *adr; + CHAR *dest; + int result = 0; + + adr = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + dest = (CHAR *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (adr == MAP_FAILED || dest == MAP_FAILED) + { + if (errno == ENOSYS) + puts ("No test, mmap not available."); + else + { + printf ("mmap failed: %m"); + result = 1; + } + } + else + { + int inner, middle, outer; + + mprotect (adr, size, PROT_NONE); + mprotect (adr + 2 * nchars, size, PROT_NONE); + adr += nchars; + + mprotect (dest, size, PROT_NONE); + mprotect (dest + 2 * nchars, size, PROT_NONE); + dest += nchars; + + MEMSET (adr, L('T'), nchars); + + /* strlen/wcslen test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if (STRLEN (&adr[outer]) != (size_t) (inner - outer)) + { + printf ("%s flunked for outer = %d, inner = %d\n", + STRINGIFY (STRLEN), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } + } + + /* strnlen/wcsnlen test */ + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + { + for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if (STRNLEN (&adr[outer], inner - outer + 1) + != (size_t) (inner - outer)) + { + printf ("%s flunked for outer = %d, inner = %d\n", + STRINGIFY (STRNLEN), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } + } + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + { + for (inner = MAX (outer, nchars - 64); inner <= nchars; ++inner) + { + if (STRNLEN (&adr[outer], inner - outer) + != (size_t) (inner - outer)) + { + printf ("%s flunked bounded for outer = %d, inner = %d\n", + STRINGIFY (STRNLEN), outer, inner); + result = 1; + } + } + } + + /* strchr/wcschr test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + { + for (inner = middle; inner < nchars; ++inner) + { + adr[middle] = L('V'); + adr[inner] = L('\0'); + + CHAR *cp = STRCHR (&adr[outer], L('V')); + + if ((inner == middle && cp != NULL) + || (inner != middle + && (cp - &adr[outer]) != middle - outer)) + { + printf ("%s flunked for outer = %d, middle = %d, " + "inner = %d\n", + STRINGIFY (STRCHR), outer, middle, inner); + result = 1; + } + + adr[inner] = L('T'); + adr[middle] = L('T'); + } + } + } + + /* Special test. */ + adr[nchars - 1] = L('\0'); + if (STRCHR (&adr[nchars - 1], L('\n')) != NULL) + { + printf ("%s flunked test of empty string at end of page\n", + STRINGIFY (STRCHR)); + result = 1; + } + + /* strrchr/wcsrchr test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + { + for (inner = middle; inner < nchars; ++inner) + { + adr[middle] = L('V'); + adr[inner] = L('\0'); + + CHAR *cp = STRRCHR (&adr[outer], L('V')); + + if ((inner == middle && cp != NULL) + || (inner != middle + && (cp - &adr[outer]) != middle - outer)) + { + printf ("%s flunked for outer = %d, middle = %d, " + "inner = %d\n", + STRINGIFY (STRRCHR), outer, middle, inner); + result = 1; + } + + adr[inner] = L('T'); + adr[middle] = L('T'); + } + } + } + + /* memchr test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + { + adr[middle] = L('V'); + + CHAR *cp = MEMCHR (&adr[outer], L('V'), 3 * size); + + if (cp - &adr[outer] != middle - outer) + { + printf ("%s flunked for outer = %d, middle = %d\n", + STRINGIFY (MEMCHR), outer, middle); + result = 1; + } + + adr[middle] = L('T'); + } + } + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + { + CHAR *cp = MEMCHR (&adr[outer], L('V'), nchars - outer); + + if (cp != NULL) + { + printf ("%s flunked for outer = %d\n", + STRINGIFY (MEMCHR), outer); + result = 1; + } + } + + /* These functions only exist for single-byte characters. */ +#ifndef WCSTEST + /* rawmemchr test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + { + adr[middle] = L('V'); + + CHAR *cp = rawmemchr (&adr[outer], L('V')); + + if (cp - &adr[outer] != middle - outer) + { + printf ("%s flunked for outer = %d, middle = %d\n", + STRINGIFY (rawmemchr), outer, middle); + result = 1; + } + + adr[middle] = L('T'); + } + } + + /* memrchr test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + { + adr[middle] = L('V'); + + CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer); + + if (cp - &adr[outer] != middle - outer) + { + printf ("%s flunked for outer = %d, middle = %d\n", + STRINGIFY (memrchr), outer, middle); + result = 1; + } + + adr[middle] = L('T'); + } + } + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + { + CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer); + + if (cp != NULL) + { + printf ("%s flunked for outer = %d\n", + STRINGIFY (memrchr), outer); + result = 1; + } + } +#endif + + /* strcpy/wcscpy test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if (STRCPY (dest, &adr[outer]) != dest + || STRLEN (dest) != (size_t) (inner - outer)) + { + printf ("%s flunked for outer = %d, inner = %d\n", + STRINGIFY (STRCPY), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } + } + + /* strcmp/wcscmp tests */ + for (outer = 1; outer < 32; ++outer) + for (middle = 0; middle < 16; ++middle) + { + MEMSET (adr + middle, L('T'), 256); + adr[256] = L('\0'); + MEMSET (dest + nchars - outer, L('T'), outer - 1); + dest[nchars - 1] = L('\0'); + + if (STRCMP (adr + middle, dest + nchars - outer) <= 0) + { + printf ("%s 1 flunked for outer = %d, middle = %d\n", + STRINGIFY (STRCMP), outer, middle); + result = 1; + } + + if (STRCMP (dest + nchars - outer, adr + middle) >= 0) + { + printf ("%s 2 flunked for outer = %d, middle = %d\n", + STRINGIFY (STRCMP), outer, middle); + result = 1; + } + } + + /* strncmp/wcsncmp tests */ + for (outer = 1; outer < 32; ++outer) + for (middle = 0; middle < 16; ++middle) + { + MEMSET (adr + middle, L('T'), 256); + adr[256] = L('\0'); + MEMSET (dest + nchars - outer, L('T'), outer - 1); + dest[nchars - 1] = L('U'); + + for (inner = 0; inner < outer; ++inner) + { + if (STRNCMP (adr + middle, dest + nchars - outer, inner) != 0) + { + printf ("%s 1 flunked for outer = %d, middle = %d, " + "inner = %d\n", + STRINGIFY (STRNCMP), outer, middle, inner); + result = 1; + } + + if (STRNCMP (dest + nchars - outer, adr + middle, inner) != 0) + { + printf ("%s 2 flunked for outer = %d, middle = %d, " + "inner = %d\n", + STRINGIFY (STRNCMP), outer, middle, inner); + result = 1; + } + } + + if (STRNCMP (adr + middle, dest + nchars - outer, outer) >= 0) + { + printf ("%s 1 flunked for outer = %d, middle = %d, full\n", + STRINGIFY (STRNCMP), outer, middle); + result = 1; + } + + if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0) + { + printf ("%s 2 flunked for outer = %d, middle = %d, full\n", + STRINGIFY (STRNCMP), outer, middle); + result = 1; + } + } + + /* strncpy/wcsncpy tests */ + adr[nchars - 1] = L('T'); + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + { + size_t len; + + for (len = 0; len < nchars - outer; ++len) + { + if (STRNCPY (dest, &adr[outer], len) != dest + || MEMCMP (dest, &adr[outer], len) != 0) + { + printf ("outer %s flunked for outer = %d, len = %Zd\n", + STRINGIFY (STRNCPY), outer, len); + result = 1; + } + } + } + adr[nchars - 1] = L('\0'); + + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + { + size_t len; + + adr[inner] = L('\0'); + + for (len = 0; len < nchars - outer + 64; ++len) + { + if (STRNCPY (dest, &adr[outer], len) != dest + || MEMCMP (dest, &adr[outer], + MIN (inner - outer, len)) != 0 + || (inner - outer < len + && STRLEN (dest) != (inner - outer))) + { + printf ("%s flunked for outer = %d, inner = %d, " + "len = %Zd\n", + STRINGIFY (STRNCPY), outer, inner, len); + result = 1; + } + if (STRNCPY (dest + 1, &adr[outer], len) != dest + 1 + || MEMCMP (dest + 1, &adr[outer], + MIN (inner - outer, len)) != 0 + || (inner - outer < len + && STRLEN (dest + 1) != (inner - outer))) + { + printf ("%s+1 flunked for outer = %d, inner = %d, " + "len = %Zd\n", + STRINGIFY (STRNCPY), outer, inner, len); + result = 1; + } + } + + adr[inner] = L('T'); + } + } + + /* stpcpy/wcpcpy test */ + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if ((STPCPY (dest, &adr[outer]) - dest) != inner - outer) + { + printf ("%s flunked for outer = %d, inner = %d\n", + STRINGIFY (STPCPY), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } + } + + /* stpncpy/wcpncpy test */ + adr[nchars - 1] = L('T'); + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + { + size_t len; + + for (len = 0; len < nchars - outer; ++len) + { + if (STPNCPY (dest, &adr[outer], len) != dest + len + || MEMCMP (dest, &adr[outer], len) != 0) + { + printf ("outer %s flunked for outer = %d, len = %Zd\n", + STRINGIFY (STPNCPY), outer, len); + result = 1; + } + } + } + adr[nchars - 1] = L('\0'); + + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + { + for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + { + adr[middle] = L('\0'); + + for (inner = 0; inner < nchars - outer; ++ inner) + { + if ((STPNCPY (dest, &adr[outer], inner) - dest) + != MIN (inner, middle - outer)) + { + printf ("%s flunked for outer = %d, middle = %d, " + "inner = %d\n", + STRINGIFY (STPNCPY), outer, middle, inner); + result = 1; + } + } + + adr[middle] = L('T'); + } + } + + /* memcpy/wmemcpy test */ + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (inner = 0; inner < nchars - outer; ++inner) + if (MEMCPY (dest, &adr[outer], inner) != dest) + { + printf ("%s flunked for outer = %d, inner = %d\n", + STRINGIFY (MEMCPY), outer, inner); + result = 1; + } + + /* mempcpy/wmempcpy test */ + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (inner = 0; inner < nchars - outer; ++inner) + if (MEMPCPY (dest, &adr[outer], inner) != dest + inner) + { + printf ("%s flunked for outer = %d, inner = %d\n", + STRINGIFY (MEMPCPY), outer, inner); + result = 1; + } + + /* This function only exists for single-byte characters. */ +#ifndef WCSTEST + /* memccpy test */ + memset (adr, '\0', nchars); + for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (inner = 0; inner < nchars - outer; ++inner) + if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL) + { + printf ("memccpy flunked full copy for outer = %d, inner = %d\n", + outer, inner); + result = 1; + } + for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (middle = 0; middle < nchars - outer; ++middle) + { + memset (dest, L('\2'), middle + 1); + for (inner = 0; inner < middle; ++inner) + { + adr[outer + inner] = L('\1'); + + if (memccpy (dest, &adr[outer], '\1', middle + 128) + != dest + inner + 1) + { + printf ("\ +memccpy flunked partial copy for outer = %d, middle = %d, inner = %d\n", + outer, middle, inner); + result = 1; + } + else if (dest[inner + 1] != L('\2')) + { + printf ("\ +memccpy copied too much for outer = %d, middle = %d, inner = %d\n", + outer, middle, inner); + result = 1; + } + adr[outer + inner] = L('\0'); + } + } +#endif + } + + return result; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/strcasecmp.c b/REORG.TODO/string/strcasecmp.c new file mode 100644 index 0000000000..2d6ae0fa9d --- /dev/null +++ b/REORG.TODO/string/strcasecmp.c @@ -0,0 +1,67 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 , __locale_t loc +#else +# define LOCALE_PARAM +#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 (const char *s1, const char *s2 LOCALE_PARAM) +{ +#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/REORG.TODO/string/strcasecmp_l.c b/REORG.TODO/string/strcasecmp_l.c new file mode 100644 index 0000000000..78271ad2ef --- /dev/null +++ b/REORG.TODO/string/strcasecmp_l.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1997-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define USE_IN_EXTENDED_LOCALE_MODEL 1 +#include "strcasecmp.c" + +libc_hidden_def (__strcasecmp_l) +weak_alias (__strcasecmp_l, strcasecmp_l) diff --git a/REORG.TODO/string/strcasestr.c b/REORG.TODO/string/strcasestr.c new file mode 100644 index 0000000000..2acf003155 --- /dev/null +++ b/REORG.TODO/string/strcasestr.c @@ -0,0 +1,104 @@ +/* Return the offset of one string within another. + Copyright (C) 1994-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * 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 */ + +/* Specification. */ +#include <string.h> + +#include <ctype.h> +#include <stdbool.h> +#include <strings.h> + +#define TOLOWER(Ch) tolower (Ch) + +/* Two-Way algorithm. */ +#define RETURN_TYPE char * +#define AVAILABLE(h, h_l, j, n_l) \ + (!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \ + && ((h_l) = (j) + (n_l))) +#define CHECK_EOL (1) +#define RET0_IF_0(a) if (!a) goto ret0 +#define CANON_ELEMENT(c) TOLOWER (c) +#define CMP_FUNC(p1, p2, l) \ + __strncasecmp ((const char *) (p1), (const char *) (p2), l) +#include "str-two-way.h" + +#undef strcasestr +#undef __strcasestr + +#ifndef STRCASESTR +#define STRCASESTR __strcasestr +#endif + + +/* Find the first occurrence of NEEDLE in HAYSTACK, using + case-insensitive comparison. This function gives unspecified + results in multibyte locales. */ +char * +STRCASESTR (const char *haystack_start, const char *needle_start) +{ + const char *haystack = haystack_start; + const char *needle = needle_start; + size_t needle_len; /* Length of NEEDLE. */ + size_t haystack_len; /* Known minimum length of HAYSTACK. */ + bool ok = true; /* True if NEEDLE is prefix of HAYSTACK. */ + + /* Determine length of NEEDLE, and in the process, make sure + HAYSTACK is at least as long (no point processing all of a long + NEEDLE if HAYSTACK is too short). */ + while (*haystack && *needle) + { + ok &= (TOLOWER ((unsigned char) *haystack) + == TOLOWER ((unsigned char) *needle)); + haystack++; + needle++; + } + if (*needle) + return NULL; + if (ok) + return (char *) haystack_start; + needle_len = needle - needle_start; + haystack = haystack_start + 1; + haystack_len = needle_len - 1; + + /* Perform the search. Abstract memory is considered to be an array + of 'unsigned char' values, not an array of 'char' values. See + ISO C 99 section 6.2.6.1. */ + if (needle_len < LONG_NEEDLE_THRESHOLD) + return two_way_short_needle ((const unsigned char *) haystack, + haystack_len, + (const unsigned char *) needle_start, + needle_len); + return two_way_long_needle ((const unsigned char *) haystack, haystack_len, + (const unsigned char *) needle_start, + needle_len); +} + +#undef LONG_NEEDLE_THRESHOLD + +#ifndef NO_ALIAS +weak_alias (__strcasestr, strcasestr) +#endif diff --git a/REORG.TODO/string/strcat.c b/REORG.TODO/string/strcat.c new file mode 100644 index 0000000000..8373fabc1d --- /dev/null +++ b/REORG.TODO/string/strcat.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef strcat + +#ifndef STRCAT +# define STRCAT strcat +#endif + +/* Append SRC on the end of DEST. */ +char * +STRCAT (char *dest, const char *src) +{ + strcpy (dest + strlen (dest), src); + return dest; +} +libc_hidden_builtin_def (strcat) diff --git a/REORG.TODO/string/strchr.c b/REORG.TODO/string/strchr.c new file mode 100644 index 0000000000..50e4172853 --- /dev/null +++ b/REORG.TODO/string/strchr.c @@ -0,0 +1,185 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <stdlib.h> + +#undef strchr + +#ifndef STRCHR +# define STRCHR strchr +#endif + +/* Find the first occurrence of C in S. */ +char * +STRCHR (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 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. */ + magic_bits = -1; + magic_bits = magic_bits / 0xff * 0xfe << 1 >> 1 | 1; + + /* 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/REORG.TODO/string/strchrnul.c b/REORG.TODO/string/strchrnul.c new file mode 100644 index 0000000000..d62dc9c595 --- /dev/null +++ b/REORG.TODO/string/strchrnul.c @@ -0,0 +1,166 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <memcopy.h> +#include <stdlib.h> + +#undef __strchrnul +#undef strchrnul + +#ifndef STRCHRNUL +# define STRCHRNUL __strchrnul +#endif + +/* Find the first occurrence of C in S or the final NUL byte. */ +char * +STRCHRNUL (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 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. */ + magic_bits = -1; + magic_bits = magic_bits / 0xff * 0xfe << 1 >> 1 | 1; + + /* 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/REORG.TODO/string/strcmp.c b/REORG.TODO/string/strcmp.c new file mode 100644 index 0000000000..a818285ea2 --- /dev/null +++ b/REORG.TODO/string/strcmp.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef strcmp + +#ifndef STRCMP +# define STRCMP strcmp +#endif + +/* 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 (const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned 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/REORG.TODO/string/strcoll.c b/REORG.TODO/string/strcoll.c new file mode 100644 index 0000000000..8996bf90f4 --- /dev/null +++ b/REORG.TODO/string/strcoll.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Ulrich Drepper <drepper@cygnus.com>, 1995. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#ifndef STRING_TYPE +# define STRING_TYPE char +# define STRCOLL strcoll +# define STRCOLL_L __strcoll_l +# define USE_HIDDEN_DEF +#endif + +#include "../locale/localeinfo.h" + + +int +STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2) +{ + return STRCOLL_L (s1, s2, _NL_CURRENT_LOCALE); +} + +#ifdef USE_HIDDEN_DEF +libc_hidden_def (STRCOLL) +#endif diff --git a/REORG.TODO/string/strcoll_l.c b/REORG.TODO/string/strcoll_l.c new file mode 100644 index 0000000000..8fd55b000a --- /dev/null +++ b/REORG.TODO/string/strcoll_l.c @@ -0,0 +1,363 @@ +/* Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Ulrich Drepper <drepper@gnu.org>, 1995. + + 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, see + <http://www.gnu.org/licenses/>. */ + + +#include <assert.h> +#include <langinfo.h> +#include <locale.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> + +#ifndef STRING_TYPE +# define STRING_TYPE char +# define USTRING_TYPE unsigned char +# define STRCOLL __strcoll_l +# define STRCMP strcmp +# define WEIGHT_H "../locale/weight.h" +# define SUFFIX MB +# define L(arg) arg +#endif + +#define CONCAT(a,b) CONCAT1(a,b) +#define CONCAT1(a,b) a##b + +#include "../locale/localeinfo.h" +#include WEIGHT_H + +/* Track status while looking for sequences in a string. */ +typedef struct +{ + int len; /* Length of the current sequence. */ + size_t val; /* Position of the sequence relative to the + previous non-ignored sequence. */ + size_t idxmax; /* Maximum index in sequences. */ + size_t idxcnt; /* Current count of indices. */ + size_t backw; /* Current Backward sequence index. */ + size_t backw_stop; /* Index where the backward sequences stop. */ + const USTRING_TYPE *us; /* The string. */ + unsigned char rule; /* Saved rule for the first sequence. */ + int32_t idx; /* Index to weight of the current sequence. */ + int32_t save_idx; /* Save looked up index of a forward + sequence after the last backward + sequence. */ + const USTRING_TYPE *back_us; /* Beginning of the backward sequence. */ +} coll_seq; + +/* Get next sequence. Traverse the string as required. */ +static __always_inline void +get_next_seq (coll_seq *seq, int nrules, const unsigned char *rulesets, + const USTRING_TYPE *weights, const int32_t *table, + const USTRING_TYPE *extra, const int32_t *indirect, + int pass) +{ + size_t val = seq->val = 0; + int len = seq->len; + size_t backw_stop = seq->backw_stop; + size_t backw = seq->backw; + size_t idxcnt = seq->idxcnt; + size_t idxmax = seq->idxmax; + int32_t idx = seq->idx; + const USTRING_TYPE *us = seq->us; + + while (len == 0) + { + ++val; + if (backw_stop != ~0ul) + { + /* There is something pushed. */ + if (backw == backw_stop) + { + /* The last pushed character was handled. Continue + with forward characters. */ + if (idxcnt < idxmax) + { + idx = seq->save_idx; + backw_stop = ~0ul; + } + else + { + /* Nothing anymore. The backward sequence ended with + the last sequence in the string. Note that len is + still zero. */ + idx = 0; + break; + } + } + else + { + /* XXX Traverse BACKW sequences from the beginning of + BACKW_STOP to get the next sequence. Is ther a quicker way + to do this? */ + size_t i = backw_stop; + us = seq->back_us; + while (i < backw) + { + int32_t tmp = findidx (table, indirect, extra, &us, -1); + idx = tmp & 0xffffff; + i++; + } + --backw; + us = seq->us; + } + } + else + { + backw_stop = idxmax; + int32_t prev_idx = idx; + + while (*us != L('\0')) + { + int32_t tmp = findidx (table, indirect, extra, &us, -1); + unsigned char rule = tmp >> 24; + prev_idx = idx; + idx = tmp & 0xffffff; + idxcnt = idxmax++; + + /* Save the rule for the first sequence. */ + if (__glibc_unlikely (idxcnt == 0)) + seq->rule = rule; + + if ((rulesets[rule * nrules + pass] + & sort_backward) == 0) + /* No more backward characters to push. */ + break; + ++idxcnt; + } + + if (backw_stop >= idxcnt) + { + /* No sequence at all or just one. */ + if (idxcnt == idxmax || backw_stop > idxcnt) + /* Note that len is still zero. */ + break; + + backw_stop = ~0ul; + } + else + { + /* We pushed backward sequences. If the stream ended with the + backward sequence, then we process the last sequence we + found. Otherwise we process the sequence before the last + one since the last one was a forward sequence. */ + seq->back_us = seq->us; + seq->us = us; + backw = idxcnt; + if (idxmax > idxcnt) + { + backw--; + seq->save_idx = idx; + idx = prev_idx; + } + if (backw > backw_stop) + backw--; + } + } + + /* With GCC 5.3 when compiling with -Os the compiler complains + that idx, taken from seq->idx (seq1 or seq2 from STRCOLL) may + be used uninitialized. In general this can't possibly be true + since seq1.idx and seq2.idx are initialized to zero in the + outer function. Only one case where seq->idx is restored from + seq->save_idx might result in an uninitialized idx value, but + it is guarded by a sequence of checks against backw_stop which + ensures that seq->save_idx was saved to first and contains a + valid value. */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); + len = weights[idx++]; + DIAG_POP_NEEDS_COMMENT; + /* Skip over indices of previous levels. */ + for (int i = 0; i < pass; i++) + { + idx += len; + len = weights[idx]; + idx++; + } + } + + /* Update the structure. */ + seq->val = val; + seq->len = len; + seq->backw_stop = backw_stop; + seq->backw = backw; + seq->idxcnt = idxcnt; + seq->idxmax = idxmax; + seq->us = us; + seq->idx = idx; +} + +/* Compare two sequences. */ +static __always_inline int +do_compare (coll_seq *seq1, coll_seq *seq2, int position, + const USTRING_TYPE *weights) +{ + int seq1len = seq1->len; + int seq2len = seq2->len; + size_t val1 = seq1->val; + size_t val2 = seq2->val; + int idx1 = seq1->idx; + int idx2 = seq2->idx; + int result = 0; + + /* Test for position if necessary. */ + if (position && val1 != val2) + { + result = val1 > val2 ? 1 : -1; + goto out; + } + + /* Compare the two sequences. */ + do + { + if (weights[idx1] != weights[idx2]) + { + /* The sequences differ. */ + result = weights[idx1] - weights[idx2]; + goto out; + } + + /* Increment the offsets. */ + ++idx1; + ++idx2; + + --seq1len; + --seq2len; + } + while (seq1len > 0 && seq2len > 0); + + if (position && seq1len != seq2len) + result = seq1len - seq2len; + +out: + seq1->len = seq1len; + seq2->len = seq2len; + seq1->idx = idx1; + seq2->idx = idx2; + return result; +} + +int +STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l) +{ + struct __locale_data *current = l->__locales[LC_COLLATE]; + uint_fast32_t nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word; + /* We don't assign the following values right away since it might be + unnecessary in case there are no rules. */ + const unsigned char *rulesets; + const int32_t *table; + const USTRING_TYPE *weights; + const USTRING_TYPE *extra; + const int32_t *indirect; + + if (nrules == 0) + return STRCMP (s1, s2); + + /* Catch empty strings. */ + if (__glibc_unlikely (*s1 == '\0') || __glibc_unlikely (*s2 == '\0')) + return (*s1 != '\0') - (*s2 != '\0'); + + rulesets = (const unsigned char *) + current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string; + table = (const int32_t *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string; + weights = (const USTRING_TYPE *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string; + extra = (const USTRING_TYPE *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string; + indirect = (const int32_t *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string; + + assert (((uintptr_t) table) % __alignof__ (table[0]) == 0); + assert (((uintptr_t) weights) % __alignof__ (weights[0]) == 0); + assert (((uintptr_t) extra) % __alignof__ (extra[0]) == 0); + assert (((uintptr_t) indirect) % __alignof__ (indirect[0]) == 0); + + int result = 0, rule = 0; + + coll_seq seq1, seq2; + seq1.len = 0; + seq1.idxmax = 0; + seq1.rule = 0; + seq2.len = 0; + seq2.idxmax = 0; + + for (int pass = 0; pass < nrules; ++pass) + { + seq1.idxcnt = 0; + seq1.idx = 0; + seq2.idx = 0; + seq1.backw_stop = ~0ul; + seq1.backw = ~0ul; + seq2.idxcnt = 0; + seq2.backw_stop = ~0ul; + seq2.backw = ~0ul; + + /* We need the elements of the strings as unsigned values since they + are used as indices. */ + seq1.us = (const USTRING_TYPE *) s1; + seq2.us = (const USTRING_TYPE *) s2; + + /* We assume that if a rule has defined `position' in one section + this is true for all of them. Please note that the localedef programs + makes sure that `position' is not used at the first level. */ + + int position = rulesets[rule * nrules + pass] & sort_position; + + while (1) + { + get_next_seq (&seq1, nrules, rulesets, weights, table, + extra, indirect, pass); + get_next_seq (&seq2, nrules, rulesets, weights, table, + extra, indirect, pass); + /* See whether any or both strings are empty. */ + if (seq1.len == 0 || seq2.len == 0) + { + if (seq1.len == seq2.len) + { + /* Both strings ended and are equal at this level. Do a + byte-level comparison to ensure that we don't waste time + going through multiple passes for totally equal strings + before proceeding to subsequent passes. */ + if (pass == 0 && STRCMP (s1, s2) == 0) + return result; + else + break; + } + + /* This means one string is shorter than the other. Find out + which one and return an appropriate value. */ + return seq1.len == 0 ? -1 : 1; + } + + result = do_compare (&seq1, &seq2, position, weights); + if (result != 0) + return result; + } + + rule = seq1.rule; + } + + return result; +} +libc_hidden_def (STRCOLL) + +#ifndef WIDE_CHAR_VERSION +weak_alias (__strcoll_l, strcoll_l) +#endif diff --git a/REORG.TODO/string/strcpy.c b/REORG.TODO/string/strcpy.c new file mode 100644 index 0000000000..120da44ee7 --- /dev/null +++ b/REORG.TODO/string/strcpy.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> +#include <string.h> + +#undef strcpy + +#ifndef STRCPY +# define STRCPY strcpy +#endif + +/* Copy SRC to DEST. */ +char * +STRCPY (char *dest, const char *src) +{ + return memcpy (dest, src, strlen (src) + 1); +} +libc_hidden_builtin_def (strcpy) diff --git a/REORG.TODO/string/strcspn.c b/REORG.TODO/string/strcspn.c new file mode 100644 index 0000000000..1035552a8e --- /dev/null +++ b/REORG.TODO/string/strcspn.c @@ -0,0 +1,72 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <stdint.h> +#include <libc-pointer-arith.h> + +#undef strcspn + +#ifndef STRCSPN +# define STRCSPN strcspn +#endif + +/* Return the length of the maximum initial segment of S + which contains no characters from REJECT. */ +size_t +STRCSPN (const char *str, const char *reject) +{ + if (__glibc_unlikely (reject[0] == '\0') || + __glibc_unlikely (reject[1] == '\0')) + return __strchrnul (str, reject [0]) - str; + + /* Use multiple small memsets to enable inlining on most targets. */ + unsigned char table[256]; + unsigned char *p = memset (table, 0, 64); + memset (p + 64, 0, 64); + memset (p + 128, 0, 64); + memset (p + 192, 0, 64); + + unsigned char *s = (unsigned char*) reject; + unsigned char tmp; + do + p[tmp = *s++] = 1; + while (tmp); + + s = (unsigned char*) str; + if (p[s[0]]) return 0; + if (p[s[1]]) return 1; + if (p[s[2]]) return 2; + if (p[s[3]]) return 3; + + s = (unsigned char *) PTR_ALIGN_DOWN (s, 4); + + unsigned int c0, c1, c2, c3; + do + { + s += 4; + c0 = p[s[0]]; + c1 = p[s[1]]; + c2 = p[s[2]]; + c3 = p[s[3]]; + } + while ((c0 | c1 | c2 | c3) == 0); + + size_t count = s - (unsigned char *) str; + return (c0 | c1) != 0 ? count - c0 + 1 : count - c2 + 3; +} +libc_hidden_builtin_def (strcspn) diff --git a/REORG.TODO/string/strdup.c b/REORG.TODO/string/strdup.c new file mode 100644 index 0000000000..40993fce1a --- /dev/null +++ b/REORG.TODO/string/strdup.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined _LIBC || defined STDC_HEADERS +# include <stdlib.h> +# include <string.h> +#else +char *malloc (); +char *memcpy (); +#endif + +#undef __strdup +#undef strdup + +#ifndef weak_alias +# define __strdup strdup +#endif + +/* Duplicate S, returning an identical malloc'd string. */ +char * +__strdup (const char *s) +{ + size_t len = strlen (s) + 1; + void *new = malloc (len); + + if (new == NULL) + return NULL; + + return (char *) memcpy (new, s, len); +} +#ifdef libc_hidden_def +libc_hidden_def (__strdup) +#endif +#ifdef weak_alias +weak_alias (__strdup, strdup) +#endif diff --git a/REORG.TODO/string/strerror.c b/REORG.TODO/string/strerror.c new file mode 100644 index 0000000000..0d235c6b6b --- /dev/null +++ b/REORG.TODO/string/strerror.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <libintl.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* Return a string describing the errno code in ERRNUM. + The storage is good only until the next call to strerror. + Writing to the storage causes undefined behavior. */ +libc_freeres_ptr (static char *buf); + +char * +strerror (int errnum) +{ + char *ret = __strerror_r (errnum, NULL, 0); + int saved_errno; + + if (__glibc_likely (ret != NULL)) + return ret; + saved_errno = errno; + if (buf == NULL) + buf = malloc (1024); + __set_errno (saved_errno); + if (buf == NULL) + return _("Unknown error"); + return __strerror_r (errnum, buf, 1024); +} diff --git a/REORG.TODO/string/strerror_l.c b/REORG.TODO/string/strerror_l.c new file mode 100644 index 0000000000..03a3257dfd --- /dev/null +++ b/REORG.TODO/string/strerror_l.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2007-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <libintl.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + + +static __thread char *last_value; + + +static const char * +translate (const char *str, locale_t loc) +{ + locale_t oldloc = __uselocale (loc); + const char *res = _(str); + __uselocale (oldloc); + return res; +} + + +/* Return a string describing the errno code in ERRNUM. */ +char * +strerror_l (int errnum, locale_t loc) +{ + + + if (__builtin_expect (errnum < 0 || errnum >= _sys_nerr_internal + || _sys_errlist_internal[errnum] == NULL, 0)) + { + free (last_value); + if (__asprintf (&last_value, "%s%d", + translate ("Unknown error ", loc), errnum) == -1) + last_value = NULL; + + return last_value; + } + + return (char *) translate (_sys_errlist_internal[errnum], loc); +} + + +#ifdef _LIBC +# ifdef _LIBC_REENTRANT +/* This is called when a thread is exiting to free the last_value string. */ +static void __attribute__ ((section ("__libc_thread_freeres_fn"))) +strerror_thread_freeres (void) +{ + free (last_value); +} +text_set_element (__libc_thread_subfreeres, strerror_thread_freeres); +text_set_element (__libc_subfreeres, strerror_thread_freeres); +# endif +#endif diff --git a/REORG.TODO/string/strfry.c b/REORG.TODO/string/strfry.c new file mode 100644 index 0000000000..9d1bd88d4d --- /dev/null +++ b/REORG.TODO/string/strfry.c @@ -0,0 +1,52 @@ +/* Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +char * +strfry (char *string) +{ + static int init; + static struct random_data rdata; + + if (!init) + { + static char state[32]; + rdata.state = NULL; + __initstate_r (time ((time_t *) NULL) ^ getpid (), + state, sizeof (state), &rdata); + init = 1; + } + + size_t len = strlen (string); + if (len > 0) + for (size_t i = 0; i < len - 1; ++i) + { + int32_t j; + __random_r (&rdata, &j); + j = j % (len - i) + i; + + char c = string[i]; + string[i] = string[j]; + string[j] = c; + } + + return string; +} diff --git a/REORG.TODO/string/string-inlines.c b/REORG.TODO/string/string-inlines.c new file mode 100644 index 0000000000..fa4a1594b2 --- /dev/null +++ b/REORG.TODO/string/string-inlines.c @@ -0,0 +1,570 @@ +/* Copyright (C) 1999-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* <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> + +#include "shlib-compat.h" + +#if SHLIB_COMPAT (libc, GLIBC_2_1_1, GLIBC_2_25) +/* The inline functions are not used from GLIBC 2.25 and forward, however + they are required to provide the symbols through string-inlines.c + (if inlining is not possible for compatibility reasons). */ + +char * +__old_strtok_r_1c (char *__s, char __sep, char **__nextp) +{ + char *__result; + if (__s == NULL) + __s = *__nextp; + while (*__s == __sep) + ++__s; + __result = NULL; + if (*__s != '\0') + { + __result = __s++; + while (*__s != '\0') + if (*__s++ == __sep) + { + __s[-1] = '\0'; + break; + } + } + *__nextp = __s; + return __result; +} +compat_symbol (libc, __old_strtok_r_1c, __strtok_r_1c, GLIBC_2_1_1); + +char * +__old_strsep_1c (char **__s, char __reject) +{ + char *__retval = *__s; + if (__retval != NULL && (*__s = strchr (__retval, __reject)) != NULL) + *(*__s)++ = '\0'; + return __retval; +} +compat_symbol (libc, __old_strsep_1c, __strsep_1c, GLIBC_2_1_1); + +char * +__old_strsep_2c (char **__s, char __reject1, char __reject2) +{ + char *__retval = *__s; + if (__retval != NULL) + { + char *__cp = __retval; + while (1) + { + if (*__cp == '\0') + { + __cp = NULL; + break; + } + if (*__cp == __reject1 || *__cp == __reject2) + { + *__cp++ = '\0'; + break; + } + ++__cp; + } + *__s = __cp; + } + return __retval; +} +compat_symbol (libc, __old_strsep_2c, __strsep_2c, GLIBC_2_1_1); + +char * +__old_strsep_3c (char **__s, char __reject1, char __reject2, char __reject3) +{ + char *__retval = *__s; + if (__retval != NULL) + { + char *__cp = __retval; + while (1) + { + if (*__cp == '\0') + { + __cp = NULL; + break; + } + if (*__cp == __reject1 || *__cp == __reject2 || *__cp == __reject3) + { + *__cp++ = '\0'; + break; + } + ++__cp; + } + *__s = __cp; + } + return __retval; +} +compat_symbol (libc, __old_strsep_3c, __strsep_3c, GLIBC_2_1_1); +#endif + +#if SHLIB_COMPAT (libc, GLIBC_2_1_1, GLIBC_2_24) +/* The inline functions are not used from GLIBC 2.24 and forward, however + they are required to provide the symbols through string-inlines.c + (if inlining is not possible for compatibility reasons). */ +size_t +__old_strcspn_c1 (const char *__s, int __reject) +{ + size_t __result = 0; + while (__s[__result] != '\0' && __s[__result] != __reject) + ++__result; + return __result; +} +compat_symbol (libc, __old_strcspn_c1, __strcspn_c1, GLIBC_2_1_1); + +size_t +__old_strcspn_c2 (const char *__s, int __reject1, int __reject2) +{ + size_t __result = 0; + while (__s[__result] != '\0' && __s[__result] != __reject1 + && __s[__result] != __reject2) + ++__result; + return __result; +} +compat_symbol (libc, __old_strcspn_c2, __strcspn_c2, GLIBC_2_1_1); + +size_t +__old_strcspn_c3 (const char *__s, int __reject1, int __reject2, + int __reject3) +{ + size_t __result = 0; + while (__s[__result] != '\0' && __s[__result] != __reject1 + && __s[__result] != __reject2 && __s[__result] != __reject3) + ++__result; + return __result; +} +compat_symbol (libc, __old_strcspn_c3, __strcspn_c3, GLIBC_2_1_1); + +size_t +__old_strspn_c1 (const char *__s, int __accept) +{ + size_t __result = 0; + /* Please note that __accept never can be '\0'. */ + while (__s[__result] == __accept) + ++__result; + return __result; +} +compat_symbol (libc, __old_strspn_c1, __strspn_c1, GLIBC_2_1_1); + +size_t +__old_strspn_c2 (const char *__s, int __accept1, int __accept2) +{ + size_t __result = 0; + /* Please note that __accept1 and __accept2 never can be '\0'. */ + while (__s[__result] == __accept1 || __s[__result] == __accept2) + ++__result; + return __result; +} +compat_symbol (libc, __old_strspn_c2, __strspn_c2, GLIBC_2_1_1); + +size_t +__old_strspn_c3 (const char *__s, int __accept1, int __accept2, + int __accept3) +{ + size_t __result = 0; + /* Please note that __accept1 to __accept3 never can be '\0'. */ + while (__s[__result] == __accept1 || __s[__result] == __accept2 + || __s[__result] == __accept3) + ++__result; + return __result; +} +compat_symbol (libc, __old_strspn_c3, __strspn_c3, GLIBC_2_1_1); + +char * +__old_strpbrk_c2 (const char *__s, int __accept1, int __accept2) +{ + /* Please note that __accept1 and __accept2 never can be '\0'. */ + while (*__s != '\0' && *__s != __accept1 && *__s != __accept2) + ++__s; + return *__s == '\0' ? NULL : (char *) (size_t) __s; +} +compat_symbol (libc, __old_strpbrk_c2, __strpbrk_c2, GLIBC_2_1_1); + +char * +__old_strpbrk_c3 (const char *__s, int __accept1, int __accept2, int __accept3) +{ + /* Please note that __accept1 to __accept3 never can be '\0'. */ + while (*__s != '\0' && *__s != __accept1 && *__s != __accept2 + && *__s != __accept3) + ++__s; + return *__s == '\0' ? NULL : (char *) (size_t) __s; +} +compat_symbol (libc, __old_strpbrk_c3, __strpbrk_c3, GLIBC_2_1_1); + +/* These are a few types we need for the optimizations if we cannot + use unaligned memory accesses. */ +# define __STRING2_COPY_TYPE(N) \ + typedef struct { unsigned char __arr[N]; } \ + __attribute__ ((__packed__)) __STRING2_COPY_ARR##N +__STRING2_COPY_TYPE (2); +__STRING2_COPY_TYPE (3); +__STRING2_COPY_TYPE (4); +__STRING2_COPY_TYPE (5); +__STRING2_COPY_TYPE (6); +__STRING2_COPY_TYPE (7); +__STRING2_COPY_TYPE (8); +# undef __STRING2_COPY_TYPE + + +# if _STRING_INLINE_unaligned +void * +__old_mempcpy_small (void *__dest1, + char __src0_1, char __src2_1, char __src4_1, char __src6_1, + __uint16_t __src0_2, __uint16_t __src4_2, + __uint32_t __src0_4, __uint32_t __src4_4, + size_t __srclen) +{ + union { + __uint32_t __ui; + __uint16_t __usi; + unsigned char __uc; + unsigned char __c; + } *__u = __dest1; + switch ((unsigned int) __srclen) + { + case 1: + __u->__c = __src0_1; + __u = __extension__ ((void *) __u + 1); + break; + case 2: + __u->__usi = __src0_2; + __u = __extension__ ((void *) __u + 2); + break; + case 3: + __u->__usi = __src0_2; + __u = __extension__ ((void *) __u + 2); + __u->__c = __src2_1; + __u = __extension__ ((void *) __u + 1); + break; + case 4: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + break; + case 5: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__c = __src4_1; + __u = __extension__ ((void *) __u + 1); + break; + case 6: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__usi = __src4_2; + __u = __extension__ ((void *) __u + 2); + break; + case 7: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__usi = __src4_2; + __u = __extension__ ((void *) __u + 2); + __u->__c = __src6_1; + __u = __extension__ ((void *) __u + 1); + break; + case 8: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__ui = __src4_4; + __u = __extension__ ((void *) __u + 4); + break; + } + return (void *) __u; +} + +# else + +void * +__old_mempcpy_small (void *__dest, char __src1, + __STRING2_COPY_ARR2 __src2, __STRING2_COPY_ARR3 __src3, + __STRING2_COPY_ARR4 __src4, __STRING2_COPY_ARR5 __src5, + __STRING2_COPY_ARR6 __src6, __STRING2_COPY_ARR7 __src7, + __STRING2_COPY_ARR8 __src8, size_t __srclen) +{ + union { + char __c; + __STRING2_COPY_ARR2 __sca2; + __STRING2_COPY_ARR3 __sca3; + __STRING2_COPY_ARR4 __sca4; + __STRING2_COPY_ARR5 __sca5; + __STRING2_COPY_ARR6 __sca6; + __STRING2_COPY_ARR7 __sca7; + __STRING2_COPY_ARR8 __sca8; + } *__u = __dest; + switch ((unsigned int) __srclen) + { + case 1: + __u->__c = __src1; + break; + case 2: + __extension__ __u->__sca2 = __src2; + break; + case 3: + __extension__ __u->__sca3 = __src3; + break; + case 4: + __extension__ __u->__sca4 = __src4; + break; + case 5: + __extension__ __u->__sca5 = __src5; + break; + case 6: + __extension__ __u->__sca6 = __src6; + break; + case 7: + __extension__ __u->__sca7 = __src7; + break; + case 8: + __extension__ __u->__sca8 = __src8; + break; + } + return __extension__ ((void *) __u + __srclen); +} +# endif +compat_symbol (libc, __old_mempcpy_small, __mempcpy_small, GLIBC_2_1_1); + +# if _STRING_INLINE_unaligned +char * +__old_strcpy_small (char *__dest, + __uint16_t __src0_2, __uint16_t __src4_2, + __uint32_t __src0_4, __uint32_t __src4_4, + size_t __srclen) +{ + union { + __uint32_t __ui; + __uint16_t __usi; + unsigned char __uc; + } *__u = (void *) __dest; + switch ((unsigned int) __srclen) + { + case 1: + __u->__uc = '\0'; + break; + case 2: + __u->__usi = __src0_2; + break; + case 3: + __u->__usi = __src0_2; + __u = __extension__ ((void *) __u + 2); + __u->__uc = '\0'; + break; + case 4: + __u->__ui = __src0_4; + break; + case 5: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__uc = '\0'; + break; + case 6: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__usi = __src4_2; + break; + case 7: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__usi = __src4_2; + __u = __extension__ ((void *) __u + 2); + __u->__uc = '\0'; + break; + case 8: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__ui = __src4_4; + break; + } + return __dest; +} + +# else + +char * +__old_strcpy_small (char *__dest, + __STRING2_COPY_ARR2 __src2, __STRING2_COPY_ARR3 __src3, + __STRING2_COPY_ARR4 __src4, __STRING2_COPY_ARR5 __src5, + __STRING2_COPY_ARR6 __src6, __STRING2_COPY_ARR7 __src7, + __STRING2_COPY_ARR8 __src8, size_t __srclen) +{ + union { + char __c; + __STRING2_COPY_ARR2 __sca2; + __STRING2_COPY_ARR3 __sca3; + __STRING2_COPY_ARR4 __sca4; + __STRING2_COPY_ARR5 __sca5; + __STRING2_COPY_ARR6 __sca6; + __STRING2_COPY_ARR7 __sca7; + __STRING2_COPY_ARR8 __sca8; + } *__u = (void *) __dest; + switch ((unsigned int) __srclen) + { + case 1: + __u->__c = '\0'; + break; + case 2: + __extension__ __u->__sca2 = __src2; + break; + case 3: + __extension__ __u->__sca3 = __src3; + break; + case 4: + __extension__ __u->__sca4 = __src4; + break; + case 5: + __extension__ __u->__sca5 = __src5; + break; + case 6: + __extension__ __u->__sca6 = __src6; + break; + case 7: + __extension__ __u->__sca7 = __src7; + break; + case 8: + __extension__ __u->__sca8 = __src8; + break; + } + return __dest; +} +# endif +compat_symbol (libc, __old_strcpy_small, __strcpy_small, GLIBC_2_1_1); + +# if _STRING_INLINE_unaligned +char * +__old_stpcpy_small (char *__dest, + __uint16_t __src0_2, __uint16_t __src4_2, + __uint32_t __src0_4, __uint32_t __src4_4, + size_t __srclen) +{ + union { + unsigned int __ui; + unsigned short int __usi; + unsigned char __uc; + char __c; + } *__u = (void *) __dest; + switch ((unsigned int) __srclen) + { + case 1: + __u->__uc = '\0'; + break; + case 2: + __u->__usi = __src0_2; + __u = __extension__ ((void *) __u + 1); + break; + case 3: + __u->__usi = __src0_2; + __u = __extension__ ((void *) __u + 2); + __u->__uc = '\0'; + break; + case 4: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 3); + break; + case 5: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__uc = '\0'; + break; + case 6: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__usi = __src4_2; + __u = __extension__ ((void *) __u + 1); + break; + case 7: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__usi = __src4_2; + __u = __extension__ ((void *) __u + 2); + __u->__uc = '\0'; + break; + case 8: + __u->__ui = __src0_4; + __u = __extension__ ((void *) __u + 4); + __u->__ui = __src4_4; + __u = __extension__ ((void *) __u + 3); + break; + } + return &__u->__c; +} + +# else + +char * +__old_stpcpy_small (char *__dest, + __STRING2_COPY_ARR2 __src2, __STRING2_COPY_ARR3 __src3, + __STRING2_COPY_ARR4 __src4, __STRING2_COPY_ARR5 __src5, + __STRING2_COPY_ARR6 __src6, __STRING2_COPY_ARR7 __src7, + __STRING2_COPY_ARR8 __src8, size_t __srclen) +{ + union { + char __c; + __STRING2_COPY_ARR2 __sca2; + __STRING2_COPY_ARR3 __sca3; + __STRING2_COPY_ARR4 __sca4; + __STRING2_COPY_ARR5 __sca5; + __STRING2_COPY_ARR6 __sca6; + __STRING2_COPY_ARR7 __sca7; + __STRING2_COPY_ARR8 __sca8; + } *__u = (void *) __dest; + switch ((unsigned int) __srclen) + { + case 1: + __u->__c = '\0'; + break; + case 2: + __extension__ __u->__sca2 = __src2; + break; + case 3: + __extension__ __u->__sca3 = __src3; + break; + case 4: + __extension__ __u->__sca4 = __src4; + break; + case 5: + __extension__ __u->__sca5 = __src5; + break; + case 6: + __extension__ __u->__sca6 = __src6; + break; + case 7: + __extension__ __u->__sca7 = __src7; + break; + case 8: + __extension__ __u->__sca8 = __src8; + break; + } + return __dest + __srclen - 1; +} +# endif +compat_symbol (libc, __old_stpcpy_small, __stpcpy_small, GLIBC_2_1_1); + +#endif diff --git a/REORG.TODO/string/string.h b/REORG.TODO/string/string.h new file mode 100644 index 0000000000..8eed67d77d --- /dev/null +++ b/REORG.TODO/string/string.h @@ -0,0 +1,544 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* + * ISO C99 Standard: 7.21 String handling <string.h> + */ + +#ifndef _STRING_H +#define _STRING_H 1 + +#define __GLIBC_INTERNAL_STARTING_HEADER_IMPLEMENTATION +#include <bits/libc-header-start.h> + +__BEGIN_DECLS + +/* Get size_t and NULL from <stddef.h>. */ +#define __need_size_t +#define __need_NULL +#include <stddef.h> + +/* Tell the caller that we provide correct C++ prototypes. */ +#if defined __cplusplus && __GNUC_PREREQ (4, 4) +# define __CORRECT_ISO_CPP_STRING_H_PROTO +#endif + + +/* Copy N bytes of SRC to DEST. */ +extern void *memcpy (void *__restrict __dest, const void *__restrict __src, + size_t __n) __THROW __nonnull ((1, 2)); +/* Copy N bytes of SRC to DEST, guaranteeing + correct behavior for overlapping strings. */ +extern void *memmove (void *__dest, const void *__src, size_t __n) + __THROW __nonnull ((1, 2)); + +/* 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. */ +#if defined __USE_MISC || defined __USE_XOPEN +extern void *memccpy (void *__restrict __dest, const void *__restrict __src, + int __c, size_t __n) + __THROW __nonnull ((1, 2)); +#endif /* Misc || X/Open. */ + + +/* Set N bytes of S to C. */ +extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1)); + +/* Compare N bytes of S1 and S2. */ +extern int memcmp (const void *__s1, const void *__s2, size_t __n) + __THROW __attribute_pure__ __nonnull ((1, 2)); + +/* Search N bytes of S for C. */ +#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" +{ +extern void *memchr (void *__s, int __c, size_t __n) + __THROW __asm ("memchr") __attribute_pure__ __nonnull ((1)); +extern const void *memchr (const void *__s, int __c, size_t __n) + __THROW __asm ("memchr") __attribute_pure__ __nonnull ((1)); + +# ifdef __OPTIMIZE__ +__extern_always_inline void * +memchr (void *__s, int __c, size_t __n) __THROW +{ + return __builtin_memchr (__s, __c, __n); +} + +__extern_always_inline const void * +memchr (const void *__s, int __c, size_t __n) __THROW +{ + return __builtin_memchr (__s, __c, __n); +} +# endif +} +#else +extern void *memchr (const void *__s, int __c, size_t __n) + __THROW __attribute_pure__ __nonnull ((1)); +#endif + +#ifdef __USE_GNU +/* Search in S for C. This is similar to `memchr' but there is no + length limit. */ +# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" void *rawmemchr (void *__s, int __c) + __THROW __asm ("rawmemchr") __attribute_pure__ __nonnull ((1)); +extern "C++" const void *rawmemchr (const void *__s, int __c) + __THROW __asm ("rawmemchr") __attribute_pure__ __nonnull ((1)); +# else +extern void *rawmemchr (const void *__s, int __c) + __THROW __attribute_pure__ __nonnull ((1)); +# endif + +/* Search N bytes of S for the final occurrence of C. */ +# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" void *memrchr (void *__s, int __c, size_t __n) + __THROW __asm ("memrchr") __attribute_pure__ __nonnull ((1)); +extern "C++" const void *memrchr (const void *__s, int __c, size_t __n) + __THROW __asm ("memrchr") __attribute_pure__ __nonnull ((1)); +# else +extern void *memrchr (const void *__s, int __c, size_t __n) + __THROW __attribute_pure__ __nonnull ((1)); +# endif +#endif + + +/* Copy SRC to DEST. */ +extern char *strcpy (char *__restrict __dest, const char *__restrict __src) + __THROW __nonnull ((1, 2)); +/* Copy no more than N characters of SRC to DEST. */ +extern char *strncpy (char *__restrict __dest, + const char *__restrict __src, size_t __n) + __THROW __nonnull ((1, 2)); + +/* Append SRC onto DEST. */ +extern char *strcat (char *__restrict __dest, const char *__restrict __src) + __THROW __nonnull ((1, 2)); +/* Append no more than N characters from SRC onto DEST. */ +extern char *strncat (char *__restrict __dest, const char *__restrict __src, + size_t __n) __THROW __nonnull ((1, 2)); + +/* Compare S1 and S2. */ +extern int strcmp (const char *__s1, const char *__s2) + __THROW __attribute_pure__ __nonnull ((1, 2)); +/* Compare N characters of S1 and S2. */ +extern int strncmp (const char *__s1, const char *__s2, size_t __n) + __THROW __attribute_pure__ __nonnull ((1, 2)); + +/* Compare the collated forms of S1 and S2. */ +extern int strcoll (const char *__s1, const char *__s2) + __THROW __attribute_pure__ __nonnull ((1, 2)); +/* Put a transformation of SRC into no more than N bytes of DEST. */ +extern size_t strxfrm (char *__restrict __dest, + const char *__restrict __src, size_t __n) + __THROW __nonnull ((2)); + +#ifdef __USE_XOPEN2K8 +# include <xlocale.h> + +/* Compare the collated forms of S1 and S2, using sorting rules from L. */ +extern int strcoll_l (const char *__s1, const char *__s2, __locale_t __l) + __THROW __attribute_pure__ __nonnull ((1, 2, 3)); +/* Put a transformation of SRC into no more than N bytes of DEST, + using sorting rules from L. */ +extern size_t strxfrm_l (char *__dest, const char *__src, size_t __n, + __locale_t __l) __THROW __nonnull ((2, 4)); +#endif + +#if (defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 \ + || __GLIBC_USE (LIB_EXT2)) +/* Duplicate S, returning an identical malloc'd string. */ +extern char *strdup (const char *__s) + __THROW __attribute_malloc__ __nonnull ((1)); +#endif + +/* Return a malloc'd copy of at most N bytes of STRING. The + resultant string is terminated even if no null terminator + appears before STRING[N]. */ +#if defined __USE_XOPEN2K8 || __GLIBC_USE (LIB_EXT2) +extern char *strndup (const char *__string, size_t __n) + __THROW __attribute_malloc__ __nonnull ((1)); +#endif + +#if defined __USE_GNU && defined __GNUC__ +/* Duplicate S, returning an identical alloca'd string. */ +# define strdupa(s) \ + (__extension__ \ + ({ \ + const char *__old = (s); \ + size_t __len = strlen (__old) + 1; \ + char *__new = (char *) __builtin_alloca (__len); \ + (char *) memcpy (__new, __old, __len); \ + })) + +/* Return an alloca'd copy of at most N bytes of string. */ +# define strndupa(s, n) \ + (__extension__ \ + ({ \ + const char *__old = (s); \ + size_t __len = strnlen (__old, (n)); \ + char *__new = (char *) __builtin_alloca (__len + 1); \ + __new[__len] = '\0'; \ + (char *) memcpy (__new, __old, __len); \ + })) +#endif + +/* Find the first occurrence of C in S. */ +#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" +{ +extern char *strchr (char *__s, int __c) + __THROW __asm ("strchr") __attribute_pure__ __nonnull ((1)); +extern const char *strchr (const char *__s, int __c) + __THROW __asm ("strchr") __attribute_pure__ __nonnull ((1)); + +# ifdef __OPTIMIZE__ +__extern_always_inline char * +strchr (char *__s, int __c) __THROW +{ + return __builtin_strchr (__s, __c); +} + +__extern_always_inline const char * +strchr (const char *__s, int __c) __THROW +{ + return __builtin_strchr (__s, __c); +} +# endif +} +#else +extern char *strchr (const char *__s, int __c) + __THROW __attribute_pure__ __nonnull ((1)); +#endif +/* Find the last occurrence of C in S. */ +#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" +{ +extern char *strrchr (char *__s, int __c) + __THROW __asm ("strrchr") __attribute_pure__ __nonnull ((1)); +extern const char *strrchr (const char *__s, int __c) + __THROW __asm ("strrchr") __attribute_pure__ __nonnull ((1)); + +# ifdef __OPTIMIZE__ +__extern_always_inline char * +strrchr (char *__s, int __c) __THROW +{ + return __builtin_strrchr (__s, __c); +} + +__extern_always_inline const char * +strrchr (const char *__s, int __c) __THROW +{ + return __builtin_strrchr (__s, __c); +} +# endif +} +#else +extern char *strrchr (const char *__s, int __c) + __THROW __attribute_pure__ __nonnull ((1)); +#endif + +#ifdef __USE_GNU +/* This function is similar to `strchr'. But it returns a pointer to + the closing NUL byte in case C is not found in S. */ +# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" char *strchrnul (char *__s, int __c) + __THROW __asm ("strchrnul") __attribute_pure__ __nonnull ((1)); +extern "C++" const char *strchrnul (const char *__s, int __c) + __THROW __asm ("strchrnul") __attribute_pure__ __nonnull ((1)); +# else +extern char *strchrnul (const char *__s, int __c) + __THROW __attribute_pure__ __nonnull ((1)); +# endif +#endif + +/* Return the length of the initial segment of S which + consists entirely of characters not in REJECT. */ +extern size_t strcspn (const char *__s, const char *__reject) + __THROW __attribute_pure__ __nonnull ((1, 2)); +/* Return the length of the initial segment of S which + consists entirely of characters in ACCEPT. */ +extern size_t strspn (const char *__s, const char *__accept) + __THROW __attribute_pure__ __nonnull ((1, 2)); +/* Find the first occurrence in S of any character in ACCEPT. */ +#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" +{ +extern char *strpbrk (char *__s, const char *__accept) + __THROW __asm ("strpbrk") __attribute_pure__ __nonnull ((1, 2)); +extern const char *strpbrk (const char *__s, const char *__accept) + __THROW __asm ("strpbrk") __attribute_pure__ __nonnull ((1, 2)); + +# ifdef __OPTIMIZE__ +__extern_always_inline char * +strpbrk (char *__s, const char *__accept) __THROW +{ + return __builtin_strpbrk (__s, __accept); +} + +__extern_always_inline const char * +strpbrk (const char *__s, const char *__accept) __THROW +{ + return __builtin_strpbrk (__s, __accept); +} +# endif +} +#else +extern char *strpbrk (const char *__s, const char *__accept) + __THROW __attribute_pure__ __nonnull ((1, 2)); +#endif +/* Find the first occurrence of NEEDLE in HAYSTACK. */ +#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" +{ +extern char *strstr (char *__haystack, const char *__needle) + __THROW __asm ("strstr") __attribute_pure__ __nonnull ((1, 2)); +extern const char *strstr (const char *__haystack, const char *__needle) + __THROW __asm ("strstr") __attribute_pure__ __nonnull ((1, 2)); + +# ifdef __OPTIMIZE__ +__extern_always_inline char * +strstr (char *__haystack, const char *__needle) __THROW +{ + return __builtin_strstr (__haystack, __needle); +} + +__extern_always_inline const char * +strstr (const char *__haystack, const char *__needle) __THROW +{ + return __builtin_strstr (__haystack, __needle); +} +# endif +} +#else +extern char *strstr (const char *__haystack, const char *__needle) + __THROW __attribute_pure__ __nonnull ((1, 2)); +#endif + + +/* Divide S into tokens separated by characters in DELIM. */ +extern char *strtok (char *__restrict __s, const char *__restrict __delim) + __THROW __nonnull ((2)); + +/* Divide S into tokens separated by characters in DELIM. Information + passed between calls are stored in SAVE_PTR. */ +extern char *__strtok_r (char *__restrict __s, + const char *__restrict __delim, + char **__restrict __save_ptr) + __THROW __nonnull ((2, 3)); +#ifdef __USE_POSIX +extern char *strtok_r (char *__restrict __s, const char *__restrict __delim, + char **__restrict __save_ptr) + __THROW __nonnull ((2, 3)); +#endif + +#ifdef __USE_GNU +/* Similar to `strstr' but this function ignores the case of both strings. */ +# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" char *strcasestr (char *__haystack, const char *__needle) + __THROW __asm ("strcasestr") __attribute_pure__ __nonnull ((1, 2)); +extern "C++" const char *strcasestr (const char *__haystack, + const char *__needle) + __THROW __asm ("strcasestr") __attribute_pure__ __nonnull ((1, 2)); +# else +extern char *strcasestr (const char *__haystack, const char *__needle) + __THROW __attribute_pure__ __nonnull ((1, 2)); +# endif +#endif + +#ifdef __USE_GNU +/* Find the first occurrence of NEEDLE in HAYSTACK. + NEEDLE is NEEDLELEN bytes long; + HAYSTACK is HAYSTACKLEN bytes long. */ +extern void *memmem (const void *__haystack, size_t __haystacklen, + const void *__needle, size_t __needlelen) + __THROW __attribute_pure__ __nonnull ((1, 3)); + +/* Copy N bytes of SRC to DEST, return pointer to bytes after the + last written byte. */ +extern void *__mempcpy (void *__restrict __dest, + const void *__restrict __src, size_t __n) + __THROW __nonnull ((1, 2)); +extern void *mempcpy (void *__restrict __dest, + const void *__restrict __src, size_t __n) + __THROW __nonnull ((1, 2)); +#endif + + +/* Return the length of S. */ +extern size_t strlen (const char *__s) + __THROW __attribute_pure__ __nonnull ((1)); + +#ifdef __USE_XOPEN2K8 +/* Find the length of STRING, but scan at most MAXLEN characters. + If no '\0' terminator is found in that many characters, return MAXLEN. */ +extern size_t strnlen (const char *__string, size_t __maxlen) + __THROW __attribute_pure__ __nonnull ((1)); +#endif + + +/* Return a string describing the meaning of the `errno' code in ERRNUM. */ +extern char *strerror (int __errnum) __THROW; +#ifdef __USE_XOPEN2K +/* Reentrant version of `strerror'. + There are 2 flavors of `strerror_r', GNU which returns the string + and may or may not use the supplied temporary buffer and POSIX one + which fills the string into the buffer. + To use the POSIX version, -D_XOPEN_SOURCE=600 or -D_POSIX_C_SOURCE=200112L + without -D_GNU_SOURCE is needed, otherwise the GNU version is + preferred. */ +# if defined __USE_XOPEN2K && !defined __USE_GNU +/* Fill BUF with a string describing the meaning of the `errno' code in + ERRNUM. */ +# ifdef __REDIRECT_NTH +extern int __REDIRECT_NTH (strerror_r, + (int __errnum, char *__buf, size_t __buflen), + __xpg_strerror_r) __nonnull ((2)); +# else +extern int __xpg_strerror_r (int __errnum, char *__buf, size_t __buflen) + __THROW __nonnull ((2)); +# define strerror_r __xpg_strerror_r +# endif +# else +/* If a temporary buffer is required, at most BUFLEN bytes of BUF will be + used. */ +extern char *strerror_r (int __errnum, char *__buf, size_t __buflen) + __THROW __nonnull ((2)) __wur; +# endif +#endif + +#ifdef __USE_XOPEN2K8 +/* Translate error number to string according to the locale L. */ +extern char *strerror_l (int __errnum, __locale_t __l) __THROW; +#endif + +#ifdef __USE_MISC +# include <strings.h> + +/* Set N bytes of S to 0. The compiler will not delete a call to this + function, even if S is dead after the call. */ +extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1)); + +/* Return the next DELIM-delimited token from *STRINGP, + terminating it with a '\0', and update *STRINGP to point past it. */ +extern char *strsep (char **__restrict __stringp, + const char *__restrict __delim) + __THROW __nonnull ((1, 2)); +#endif + +#ifdef __USE_XOPEN2K8 +/* Return a string describing the meaning of the signal number in SIG. */ +extern char *strsignal (int __sig) __THROW; + +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +extern char *__stpcpy (char *__restrict __dest, const char *__restrict __src) + __THROW __nonnull ((1, 2)); +extern char *stpcpy (char *__restrict __dest, const char *__restrict __src) + __THROW __nonnull ((1, 2)); + +/* Copy no more than N characters of SRC to DEST, returning the address of + the last character written into DEST. */ +extern char *__stpncpy (char *__restrict __dest, + const char *__restrict __src, size_t __n) + __THROW __nonnull ((1, 2)); +extern char *stpncpy (char *__restrict __dest, + const char *__restrict __src, size_t __n) + __THROW __nonnull ((1, 2)); +#endif + +#ifdef __USE_GNU +/* Compare S1 and S2 as strings holding name & indices/version numbers. */ +extern int strverscmp (const char *__s1, const char *__s2) + __THROW __attribute_pure__ __nonnull ((1, 2)); + +/* Sautee STRING briskly. */ +extern char *strfry (char *__string) __THROW __nonnull ((1)); + +/* Frobnicate N bytes of S. */ +extern void *memfrob (void *__s, size_t __n) __THROW __nonnull ((1)); + +# ifndef basename +/* Return the file name within directory of FILENAME. We don't + declare the function if the `basename' macro is available (defined + in <libgen.h>) which makes the XPG version of this function + available. */ +# ifdef __CORRECT_ISO_CPP_STRING_H_PROTO +extern "C++" char *basename (char *__filename) + __THROW __asm ("basename") __nonnull ((1)); +extern "C++" const char *basename (const char *__filename) + __THROW __asm ("basename") __nonnull ((1)); +# else +extern char *basename (const char *__filename) __THROW __nonnull ((1)); +# endif +# endif +#endif + + +#if __GNUC_PREREQ (3,4) +# if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ \ + && !defined __NO_INLINE__ && !defined __cplusplus +/* When using GNU CC we provide some optimized versions of selected + functions from this header. There are two kinds of optimizations: + + - machine-dependent optimizations, most probably using inline + assembler code; these might be quite expensive since the code + size can increase significantly. + These optimizations are not used unless the symbol + __USE_STRING_INLINES + is defined before including this header. + + - machine-independent optimizations which do not increase the + code size significantly and which optimize mainly situations + where one or more arguments are compile-time constants. + These optimizations are used always when the compiler is + taught to optimize. + + One can inhibit all optimizations by defining __NO_STRING_INLINES. */ + +/* Get the machine-dependent optimizations (if any). */ +# include <bits/string.h> + +/* These are generic optimizations which do not add too much inline code. */ +# include <bits/string2.h> +# endif + +# if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function +/* Functions with security checks. */ +# include <bits/string3.h> +# endif +#endif + +#if defined __USE_GNU && defined __OPTIMIZE__ \ + && defined __extern_always_inline && __GNUC_PREREQ (3,2) +# if !defined _FORCE_INLINES && !defined _HAVE_STRING_ARCH_mempcpy + +#define mempcpy(dest, src, n) __mempcpy_inline (dest, src, n) +#define __mempcpy(dest, src, n) __mempcpy_inline (dest, src, n) + +__extern_always_inline void * +__mempcpy_inline (void *__restrict __dest, + const void *__restrict __src, size_t __n) +{ + return (char *) memcpy (__dest, __src, __n) + __n; +} + +# endif +#endif + +__END_DECLS + +#endif /* string.h */ diff --git a/REORG.TODO/string/strings.h b/REORG.TODO/string/strings.h new file mode 100644 index 0000000000..43207af09c --- /dev/null +++ b/REORG.TODO/string/strings.h @@ -0,0 +1,147 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _STRINGS_H +#define _STRINGS_H 1 + +#include <features.h> +#define __need_size_t +#include <stddef.h> + +/* Tell the caller that we provide correct C++ prototypes. */ +#if defined __cplusplus && __GNUC_PREREQ (4, 4) +# define __CORRECT_ISO_CPP_STRINGS_H_PROTO +#endif + +__BEGIN_DECLS + +#if defined __USE_MISC || !defined __USE_XOPEN2K8 +/* Compare N bytes of S1 and S2 (same as memcmp). */ +extern int bcmp (const void *__s1, const void *__s2, size_t __n) + __THROW __attribute_pure__ __nonnull ((1, 2)); + +/* Copy N bytes of SRC to DEST (like memmove, but args reversed). */ +extern void bcopy (const void *__src, void *__dest, size_t __n) + __THROW __nonnull ((1, 2)); + +/* Set N bytes of S to 0. */ +extern void bzero (void *__s, size_t __n) __THROW __nonnull ((1)); + +/* Find the first occurrence of C in S (same as strchr). */ +# ifdef __CORRECT_ISO_CPP_STRINGS_H_PROTO +extern "C++" +{ +extern char *index (char *__s, int __c) + __THROW __asm ("index") __attribute_pure__ __nonnull ((1)); +extern const char *index (const char *__s, int __c) + __THROW __asm ("index") __attribute_pure__ __nonnull ((1)); + +# if defined __OPTIMIZE__ +__extern_always_inline char * +index (char *__s, int __c) __THROW +{ + return __builtin_index (__s, __c); +} + +__extern_always_inline const char * +index (const char *__s, int __c) __THROW +{ + return __builtin_index (__s, __c); +} +# endif +} +# else +extern char *index (const char *__s, int __c) + __THROW __attribute_pure__ __nonnull ((1)); +# endif + +/* Find the last occurrence of C in S (same as strrchr). */ +# ifdef __CORRECT_ISO_CPP_STRINGS_H_PROTO +extern "C++" +{ +extern char *rindex (char *__s, int __c) + __THROW __asm ("rindex") __attribute_pure__ __nonnull ((1)); +extern const char *rindex (const char *__s, int __c) + __THROW __asm ("rindex") __attribute_pure__ __nonnull ((1)); + +# if defined __OPTIMIZE__ +__extern_always_inline char * +rindex (char *__s, int __c) __THROW +{ + return __builtin_rindex (__s, __c); +} + +__extern_always_inline const char * +rindex (const char *__s, int __c) __THROW +{ + return __builtin_rindex (__s, __c); +} +# endif +} +# else +extern char *rindex (const char *__s, int __c) + __THROW __attribute_pure__ __nonnull ((1)); +# endif +#endif + +#if defined __USE_MISC || !defined __USE_XOPEN2K8 || defined __USE_XOPEN2K8XSI +/* Return the position of the first bit set in I, or 0 if none are set. + The least-significant bit is position 1, the most-significant 32. */ +extern int ffs (int __i) __THROW __attribute_const__; +#endif + +/* The following two functions are non-standard but necessary for non-32 bit + platforms. */ +# ifdef __USE_GNU +extern int ffsl (long int __l) __THROW __attribute_const__; +__extension__ extern int ffsll (long long int __ll) + __THROW __attribute_const__; +# endif + +/* Compare S1 and S2, ignoring case. */ +extern int strcasecmp (const char *__s1, const char *__s2) + __THROW __attribute_pure__ __nonnull ((1, 2)); + +/* Compare no more than N chars of S1 and S2, ignoring case. */ +extern int strncasecmp (const char *__s1, const char *__s2, size_t __n) + __THROW __attribute_pure__ __nonnull ((1, 2)); + +#ifdef __USE_XOPEN2K8 +# include <xlocale.h> + +/* Compare S1 and S2, ignoring case, using collation rules from LOC. */ +extern int strcasecmp_l (const char *__s1, const char *__s2, __locale_t __loc) + __THROW __attribute_pure__ __nonnull ((1, 2, 3)); + +/* Compare no more than N chars of S1 and S2, ignoring case, using + collation rules from LOC. */ +extern int strncasecmp_l (const char *__s1, const char *__s2, + size_t __n, __locale_t __loc) + __THROW __attribute_pure__ __nonnull ((1, 2, 4)); +#endif + +__END_DECLS + +#if __GNUC_PREREQ (3,4) && __USE_FORTIFY_LEVEL > 0 \ + && defined __fortify_function +/* Functions with security checks. */ +# if defined __USE_MISC || !defined __USE_XOPEN2K8 +# include <bits/strings_fortified.h> +# endif +#endif + +#endif /* strings.h */ diff --git a/REORG.TODO/string/strlen.c b/REORG.TODO/string/strlen.c new file mode 100644 index 0000000000..b368ccf58f --- /dev/null +++ b/REORG.TODO/string/strlen.c @@ -0,0 +1,109 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <stdlib.h> + +#undef strlen + +#ifndef STRLEN +# define STRLEN strlen +#endif + +/* 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 (const char *str) +{ + const char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, 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. */ + 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. */ + 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 (;;) + { + longword = *longword_ptr++; + + if (((longword - lomagic) & ~longword & himagic) != 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/REORG.TODO/string/strncase.c b/REORG.TODO/string/strncase.c new file mode 100644 index 0000000000..6cb996cf91 --- /dev/null +++ b/REORG.TODO/string/strncase.c @@ -0,0 +1,69 @@ +/* Compare at most N characters of two strings without taking care for + the case. + Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#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 , __locale_t loc +#else +# define LOCALE_PARAM +#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 (const char *s1, const char *s2, size_t n LOCALE_PARAM) +{ +#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/REORG.TODO/string/strncase_l.c b/REORG.TODO/string/strncase_l.c new file mode 100644 index 0000000000..395fc9fd08 --- /dev/null +++ b/REORG.TODO/string/strncase_l.c @@ -0,0 +1,24 @@ +/* Compare at most N characters of two strings without taking care for + the case using given locale. + Copyright (C) 1997-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define USE_IN_EXTENDED_LOCALE_MODEL 1 +#include "strncase.c" + +libc_hidden_def (__strncasecmp_l) +weak_alias (__strncasecmp_l, strncasecmp_l) diff --git a/REORG.TODO/string/strncat.c b/REORG.TODO/string/strncat.c new file mode 100644 index 0000000000..71a13eec0b --- /dev/null +++ b/REORG.TODO/string/strncat.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#ifndef STRNCAT +# undef strncat +# define STRNCAT strncat +#endif + +char * +STRNCAT (char *s1, const char *s2, size_t n) +{ + char *s = s1; + + /* Find the end of S1. */ + s1 += strlen (s1); + + size_t ss = __strnlen (s2, n); + + s1[ss] = '\0'; + memcpy (s1, s2, ss); + + return s; +} diff --git a/REORG.TODO/string/strncmp.c b/REORG.TODO/string/strncmp.c new file mode 100644 index 0000000000..c41e120091 --- /dev/null +++ b/REORG.TODO/string/strncmp.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <memcopy.h> + +#undef strncmp + +#ifndef STRNCMP +#define STRNCMP strncmp +#endif + +/* 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 (const char *s1, const char *s2, size_t n) +{ + unsigned char c1 = '\0'; + unsigned 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/REORG.TODO/string/strncpy.c b/REORG.TODO/string/strncpy.c new file mode 100644 index 0000000000..1b45c52e73 --- /dev/null +++ b/REORG.TODO/string/strncpy.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef strncpy + +#ifndef STRNCPY + #define STRNCPY strncpy +#endif + +char * +STRNCPY (char *s1, const char *s2, size_t n) +{ + size_t size = __strnlen (s2, n); + if (size != n) + memset (s1 + size, '\0', n - size); + return memcpy (s1, s2, size); +} +libc_hidden_builtin_def (strncpy) diff --git a/REORG.TODO/string/strndup.c b/REORG.TODO/string/strndup.c new file mode 100644 index 0000000000..fa0e7dcda1 --- /dev/null +++ b/REORG.TODO/string/strndup.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1996-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <sys/types.h> + +#if defined _LIBC || defined STDC_HEADERS +# include <stdlib.h> +# include <string.h> +#else +char *malloc (); +#endif + +#undef __strndup +#undef strndup + +#ifndef weak_alias +# define __strndup strndup +#endif + +char * +__strndup (const char *s, size_t n) +{ + size_t len = __strnlen (s, n); + char *new = (char *) malloc (len + 1); + + if (new == NULL) + return NULL; + + new[len] = '\0'; + return (char *) memcpy (new, s, len); +} +#ifdef libc_hidden_def +libc_hidden_def (__strndup) +#endif +#ifdef weak_alias +weak_alias (__strndup, strndup) +#endif diff --git a/REORG.TODO/string/strnlen.c b/REORG.TODO/string/strnlen.c new file mode 100644 index 0000000000..ff9fb6197a --- /dev/null +++ b/REORG.TODO/string/strnlen.c @@ -0,0 +1,166 @@ +/* Find the length of STRING, but scan at most MAXLEN characters. + Copyright (C) 1991-2017 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, see <http://www.gnu.org/licenses/>. */ + +#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. */ + +#ifdef STRNLEN +# define __strnlen STRNLEN +#endif + +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, himagic, lomagic; + + if (maxlen == 0) + return 0; + + if (__glibc_unlikely (end_ptr < str)) + 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. */ + 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. */ + 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; +} +#ifndef STRNLEN +libc_hidden_def (__strnlen) +weak_alias (__strnlen, strnlen) +#endif +libc_hidden_def (strnlen) diff --git a/REORG.TODO/string/strpbrk.c b/REORG.TODO/string/strpbrk.c new file mode 100644 index 0000000000..02d0bd2f63 --- /dev/null +++ b/REORG.TODO/string/strpbrk.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef strpbrk + +#ifndef STRPBRK +#define STRPBRK strpbrk +#endif + +/* Find the first occurrence in S of any character in ACCEPT. */ +char * +STRPBRK (const char *s, const char *accept) +{ + s += strcspn (s, accept); + return *s ? (char *)s : NULL; +} +libc_hidden_builtin_def (strpbrk) diff --git a/REORG.TODO/string/strrchr.c b/REORG.TODO/string/strrchr.c new file mode 100644 index 0000000000..92638a8fbd --- /dev/null +++ b/REORG.TODO/string/strrchr.c @@ -0,0 +1,53 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef strrchr + +#ifndef STRRCHR +# define STRRCHR strrchr +#endif + +/* Find the last occurrence of C in S. */ +char * +STRRCHR (const char *s, int c) +{ + 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/REORG.TODO/string/strsep.c b/REORG.TODO/string/strsep.c new file mode 100644 index 0000000000..7091234a6c --- /dev/null +++ b/REORG.TODO/string/strsep.c @@ -0,0 +1,49 @@ +/* Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +#undef __strsep +#undef strsep + +char * +__strsep (char **stringp, const char *delim) +{ + char *begin, *end; + + begin = *stringp; + if (begin == NULL) + return NULL; + + /* Find the end of the token. */ + end = begin + strcspn (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/REORG.TODO/string/strsignal.c b/REORG.TODO/string/strsignal.c new file mode 100644 index 0000000000..6cb4399934 --- /dev/null +++ b/REORG.TODO/string/strsignal.c @@ -0,0 +1,125 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <libc-lock.h> + +static __libc_key_t key; + +/* If nonzero the key allocation failed and we should better use a + static buffer than fail. */ +#define BUFFERSIZ 100 +static char local_buf[BUFFERSIZ]; +static char *static_buf; + +/* Destructor for the thread-specific data. */ +static void init (void); +static void free_key_mem (void *mem); +static char *getbuffer (void); + + +/* Return a string describing the meaning of the signal number SIGNUM. */ +char * +strsignal (int signum) +{ + __libc_once_define (static, once); + const char *desc; + + /* If we have not yet initialized the buffer do it now. */ + __libc_once (once, init); + + if ( +#ifdef SIGRTMIN + (signum >= SIGRTMIN && signum <= SIGRTMAX) || +#endif + signum < 0 || signum >= NSIG + || (desc = _sys_siglist[signum]) == NULL) + { + char *buffer = getbuffer (); + int len; +#ifdef SIGRTMIN + if (signum >= SIGRTMIN && signum <= SIGRTMAX) + len = __snprintf (buffer, BUFFERSIZ - 1, _("Real-time signal %d"), + signum - SIGRTMIN); + else +#endif + len = __snprintf (buffer, BUFFERSIZ - 1, _("Unknown signal %d"), + signum); + if (len >= BUFFERSIZ) + buffer = NULL; + else + buffer[len] = '\0'; + + return buffer; + } + + return (char *) _(desc); +} + + +/* Initialize buffer. */ +static void +init (void) +{ + if (__libc_key_create (&key, free_key_mem)) + /* Creating the key failed. This means something really went + wrong. In any case use a static buffer which is better than + nothing. */ + static_buf = local_buf; +} + + +/* Free the thread specific data, this is done if a thread terminates. */ +static void +free_key_mem (void *mem) +{ + free (mem); + __libc_setspecific (key, NULL); +} + + +/* Return the buffer to be used. */ +static char * +getbuffer (void) +{ + char *result; + + if (static_buf != NULL) + result = static_buf; + else + { + /* We don't use the static buffer and so we have a key. Use it + to get the thread-specific buffer. */ + result = __libc_getspecific (key); + if (result == NULL) + { + /* No buffer allocated so far. */ + result = malloc (BUFFERSIZ); + if (result == NULL) + /* No more memory available. We use the static buffer. */ + result = local_buf; + else + __libc_setspecific (key, result); + } + } + + return result; +} diff --git a/REORG.TODO/string/strspn.c b/REORG.TODO/string/strspn.c new file mode 100644 index 0000000000..c63197cdf0 --- /dev/null +++ b/REORG.TODO/string/strspn.c @@ -0,0 +1,76 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <stdint.h> +#include <libc-pointer-arith.h> + +#undef strspn +#ifndef STRSPN +# define STRSPN strspn +#endif + +/* Return the length of the maximum initial segment + of S which contains only characters in ACCEPT. */ +size_t +STRSPN (const char *str, const char *accept) +{ + if (accept[0] == '\0') + return 0; + if (__glibc_unlikely (accept[1] == '\0')) + { + const char *a = str; + for (; *str == *accept; str++); + return str - a; + } + + /* Use multiple small memsets to enable inlining on most targets. */ + unsigned char table[256]; + unsigned char *p = memset (table, 0, 64); + memset (p + 64, 0, 64); + memset (p + 128, 0, 64); + memset (p + 192, 0, 64); + + unsigned char *s = (unsigned char*) accept; + /* Different from strcspn it does not add the NULL on the table + so can avoid check if str[i] is NULL, since table['\0'] will + be 0 and thus stopping the loop check. */ + do + p[*s++] = 1; + while (*s); + + s = (unsigned char*) str; + if (!p[s[0]]) return 0; + if (!p[s[1]]) return 1; + if (!p[s[2]]) return 2; + if (!p[s[3]]) return 3; + + s = (unsigned char *) PTR_ALIGN_DOWN (s, 4); + + unsigned int c0, c1, c2, c3; + do { + s += 4; + c0 = p[s[0]]; + c1 = p[s[1]]; + c2 = p[s[2]]; + c3 = p[s[3]]; + } while ((c0 & c1 & c2 & c3) != 0); + + size_t count = s - (unsigned char *) str; + return (c0 & c1) == 0 ? count + c0 : count + c2 + 2; +} +libc_hidden_builtin_def (strspn) diff --git a/REORG.TODO/string/strstr.c b/REORG.TODO/string/strstr.c new file mode 100644 index 0000000000..88f1d5de36 --- /dev/null +++ b/REORG.TODO/string/strstr.c @@ -0,0 +1,92 @@ +/* Return the offset of one string within another. + Copyright (C) 1994-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* This particular implementation was written by Eric Blake, 2008. */ + +#ifndef _LIBC +# include <config.h> +#endif + +/* Specification of strstr. */ +#include <string.h> + +#include <stdbool.h> + +#ifndef _LIBC +# define __builtin_expect(expr, val) (expr) +#endif + +#define RETURN_TYPE char * +#define AVAILABLE(h, h_l, j, n_l) \ + (!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \ + && ((h_l) = (j) + (n_l))) +#define CHECK_EOL (1) +#define RET0_IF_0(a) if (!a) goto ret0 +#include "str-two-way.h" + +#undef strstr + +#ifndef STRSTR +#define STRSTR strstr +#endif + +/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK + if NEEDLE is empty, otherwise NULL if NEEDLE is not found in + HAYSTACK. */ +char * +STRSTR (const char *haystack_start, const char *needle_start) +{ + const char *haystack = haystack_start; + const char *needle = needle_start; + size_t needle_len; /* Length of NEEDLE. */ + size_t haystack_len; /* Known minimum length of HAYSTACK. */ + bool ok = true; /* True if NEEDLE is prefix of HAYSTACK. */ + + /* Determine length of NEEDLE, and in the process, make sure + HAYSTACK is at least as long (no point processing all of a long + NEEDLE if HAYSTACK is too short). */ + while (*haystack && *needle) + ok &= *haystack++ == *needle++; + if (*needle) + return NULL; + if (ok) + return (char *) haystack_start; + + /* Reduce the size of haystack using strchr, since it has a smaller + linear coefficient than the Two-Way algorithm. */ + needle_len = needle - needle_start; + haystack = strchr (haystack_start + 1, *needle_start); + if (!haystack || __builtin_expect (needle_len == 1, 0)) + return (char *) haystack; + needle -= needle_len; + haystack_len = (haystack > haystack_start + needle_len ? 1 + : needle_len + haystack_start - haystack); + + /* Perform the search. Abstract memory is considered to be an array + of 'unsigned char' values, not an array of 'char' values. See + ISO C 99 section 6.2.6.1. */ + if (needle_len < LONG_NEEDLE_THRESHOLD) + return two_way_short_needle ((const unsigned char *) haystack, + haystack_len, + (const unsigned char *) needle, needle_len); + return two_way_long_needle ((const unsigned char *) haystack, haystack_len, + (const unsigned char *) needle, needle_len); +} +libc_hidden_builtin_def (strstr) + +#undef LONG_NEEDLE_THRESHOLD diff --git a/REORG.TODO/string/strtok.c b/REORG.TODO/string/strtok.c new file mode 100644 index 0000000000..6b9de89747 --- /dev/null +++ b/REORG.TODO/string/strtok.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> + + +/* 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 (char *s, const char *delim) +{ + static char *olds; + return __strtok_r (s, delim, &olds); +} diff --git a/REORG.TODO/string/strtok_r.c b/REORG.TODO/string/strtok_r.c new file mode 100644 index 0000000000..ace3520a25 --- /dev/null +++ b/REORG.TODO/string/strtok_r.c @@ -0,0 +1,79 @@ +/* Reentrant string tokenizer. Generic version. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#ifndef _LIBC +/* Get specification. */ +# include "strtok_r.h" +# define __strtok_r strtok_r +#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 *end; + + if (s == NULL) + s = *save_ptr; + + if (*s == '\0') + { + *save_ptr = s; + return NULL; + } + + /* Scan leading delimiters. */ + s += strspn (s, delim); + if (*s == '\0') + { + *save_ptr = s; + return NULL; + } + + /* Find the end of the token. */ + end = s + strcspn (s, delim); + if (*end == '\0') + { + *save_ptr = end; + return s; + } + + /* Terminate the token and make *SAVE_PTR point past it. */ + *end = '\0'; + *save_ptr = end + 1; + return s; +} +#ifdef weak_alias +libc_hidden_def (__strtok_r) +weak_alias (__strtok_r, strtok_r) +#endif diff --git a/REORG.TODO/string/strverscmp.c b/REORG.TODO/string/strverscmp.c new file mode 100644 index 0000000000..383f6445c8 --- /dev/null +++ b/REORG.TODO/string/strverscmp.c @@ -0,0 +1,107 @@ +/* Compare strings while treating digits characters numerically. + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdint.h> +#include <string.h> +#include <ctype.h> + +/* states: S_N: normal, S_I: comparing integral part, S_F: comparing + fractionnal parts, S_Z: idem but with leading Zeroes only */ +#define S_N 0x0 +#define S_I 0x3 +#define S_F 0x6 +#define S_Z 0x9 + +/* result_type: CMP: return diff; LEN: compare using len_diff/diff */ +#define CMP 2 +#define LEN 3 + + +/* Compare S1 and S2 as strings holding indices/version numbers, + returning less than, equal to or greater than zero if S1 is less than, + equal to or greater than S2 (for more info, see the texinfo doc). +*/ + +int +__strverscmp (const char *s1, const char *s2) +{ + const unsigned char *p1 = (const unsigned char *) s1; + const unsigned char *p2 = (const unsigned char *) s2; + + /* Symbol(s) 0 [1-9] others + Transition (10) 0 (01) d (00) x */ + static const uint8_t next_state[] = + { + /* state x d 0 */ + /* S_N */ S_N, S_I, S_Z, + /* S_I */ S_N, S_I, S_I, + /* S_F */ S_N, S_F, S_F, + /* S_Z */ S_N, S_F, S_Z + }; + + static const int8_t result_type[] = + { + /* state x/x x/d x/0 d/x d/d d/0 0/x 0/d 0/0 */ + + /* S_N */ CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, + /* S_I */ CMP, -1, -1, +1, LEN, LEN, +1, LEN, LEN, + /* S_F */ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, + /* S_Z */ CMP, +1, +1, -1, CMP, CMP, -1, CMP, CMP + }; + + if (p1 == p2) + return 0; + + unsigned char c1 = *p1++; + unsigned char c2 = *p2++; + /* Hint: '0' is a digit too. */ + int state = S_N + ((c1 == '0') + (isdigit (c1) != 0)); + + int diff; + while ((diff = c1 - c2) == 0) + { + if (c1 == '\0') + return diff; + + state = next_state[state]; + c1 = *p1++; + c2 = *p2++; + state += (c1 == '0') + (isdigit (c1) != 0); + } + + state = result_type[state * 3 + (((c2 == '0') + (isdigit (c2) != 0)))]; + + switch (state) + { + case CMP: + return diff; + + case LEN: + while (isdigit (*p1++)) + if (!isdigit (*p2++)) + return 1; + + return isdigit (*p2) ? -1 : diff; + + default: + return state; + } +} +libc_hidden_def (__strverscmp) +weak_alias (__strverscmp, strverscmp) diff --git a/REORG.TODO/string/strxfrm.c b/REORG.TODO/string/strxfrm.c new file mode 100644 index 0000000000..5210466555 --- /dev/null +++ b/REORG.TODO/string/strxfrm.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Ulrich Drepper <drepper@cygnus.com>, 1995. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <locale/localeinfo.h> + +#ifndef STRING_TYPE +# define STRING_TYPE char +# define STRXFRM strxfrm +# define STRXFRM_L __strxfrm_l +#endif + +size_t +STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n) +{ + return STRXFRM_L (dest, src, n, _NL_CURRENT_LOCALE); +} diff --git a/REORG.TODO/string/strxfrm_l.c b/REORG.TODO/string/strxfrm_l.c new file mode 100644 index 0000000000..dd98a4caaf --- /dev/null +++ b/REORG.TODO/string/strxfrm_l.c @@ -0,0 +1,747 @@ +/* Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Ulrich Drepper <drepper@gnu.org>, 1995. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <langinfo.h> +#include <locale.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +#ifndef STRING_TYPE +# define STRING_TYPE char +# define USTRING_TYPE unsigned char +# define STRXFRM __strxfrm_l +# define STRLEN strlen +# define STPNCPY __stpncpy +# define WEIGHT_H "../locale/weight.h" +# define SUFFIX MB +# define L(arg) arg +#endif + +#define CONCAT(a,b) CONCAT1(a,b) +#define CONCAT1(a,b) a##b + +/* Maximum string size that is calculated with cached indices. Right now this + is an arbitrary value open to optimizations. SMALL_STR_SIZE * 4 has to be + lower than __MAX_ALLOCA_CUTOFF. Keep localedata/xfrm-test.c in sync. */ +#define SMALL_STR_SIZE 4095 + +#include "../locale/localeinfo.h" +#include WEIGHT_H + +/* Group locale data for shorter parameter lists. */ +typedef struct +{ + uint_fast32_t nrules; + unsigned char *rulesets; + USTRING_TYPE *weights; + int32_t *table; + USTRING_TYPE *extra; + int32_t *indirect; +} locale_data_t; + +#ifndef WIDE_CHAR_VERSION + +/* We need UTF-8 encoding of numbers. */ +static int +utf8_encode (char *buf, int val) +{ + int retval; + + if (val < 0x80) + { + *buf++ = (char) val; + retval = 1; + } + else + { + int step; + + for (step = 2; step < 6; ++step) + if ((val & (~(uint32_t)0 << (5 * step + 1))) == 0) + break; + retval = step; + + *buf = (unsigned char) (~0xff >> step); + --step; + do + { + buf[step] = 0x80 | (val & 0x3f); + val >>= 6; + } + while (--step > 0); + *buf |= val; + } + + return retval; +} +#endif + +/* Find next weight and rule index. Inlined since called for every char. */ +static __always_inline size_t +find_idx (const USTRING_TYPE **us, int32_t *weight_idx, + unsigned char *rule_idx, const locale_data_t *l_data, const int pass) +{ + int32_t tmp = findidx (l_data->table, l_data->indirect, l_data->extra, us, + -1); + *rule_idx = tmp >> 24; + int32_t idx = tmp & 0xffffff; + size_t len = l_data->weights[idx++]; + + /* Skip over indices of previous levels. */ + for (int i = 0; i < pass; i++) + { + idx += len; + len = l_data->weights[idx++]; + } + + *weight_idx = idx; + return len; +} + +static int +find_position (const USTRING_TYPE *us, const locale_data_t *l_data, + const int pass) +{ + int32_t weight_idx; + unsigned char rule_idx; + const USTRING_TYPE *usrc = us; + + find_idx (&usrc, &weight_idx, &rule_idx, l_data, pass); + return l_data->rulesets[rule_idx * l_data->nrules + pass] & sort_position; +} + +/* Do the transformation. */ +static size_t +do_xfrm (const USTRING_TYPE *usrc, STRING_TYPE *dest, size_t n, + const locale_data_t *l_data) +{ + int32_t weight_idx; + unsigned char rule_idx; + uint_fast32_t pass; + size_t needed = 0; + size_t last_needed; + + /* Now the passes over the weights. */ + for (pass = 0; pass < l_data->nrules; ++pass) + { + size_t backw_len = 0; + last_needed = needed; + const USTRING_TYPE *cur = usrc; + const USTRING_TYPE *backw_start = NULL; + + /* We assume that if a rule has defined `position' in one section + this is true for all of them. */ + int position = find_position (cur, l_data, pass); + + if (position == 0) + { + while (*cur != L('\0')) + { + const USTRING_TYPE *pos = cur; + size_t len = find_idx (&cur, &weight_idx, &rule_idx, l_data, + pass); + int rule = l_data->rulesets[rule_idx * l_data->nrules + pass]; + + if ((rule & sort_forward) != 0) + { + /* Handle the pushed backward sequence. */ + if (backw_start != NULL) + { + for (size_t i = backw_len; i > 0; ) + { + int32_t weight_idx; + unsigned char rule_idx; + size_t len = find_idx (&backw_start, &weight_idx, + &rule_idx, l_data, pass); + if (needed + i < n) + for (size_t j = len; j > 0; j--) + dest[needed + i - j] = + l_data->weights[weight_idx++]; + + i -= len; + } + + needed += backw_len; + backw_start = NULL; + backw_len = 0; + } + + /* Now handle the forward element. */ + if (needed + len < n) + while (len-- > 0) + dest[needed++] = l_data->weights[weight_idx++]; + else + /* No more characters fit into the buffer. */ + needed += len; + } + else + { + /* Remember start of the backward sequence & track length. */ + if (backw_start == NULL) + backw_start = pos; + backw_len += len; + } + } + + + /* Handle the pushed backward sequence. */ + if (backw_start != NULL) + { + for (size_t i = backw_len; i > 0; ) + { + size_t len = find_idx (&backw_start, &weight_idx, &rule_idx, + l_data, pass); + if (needed + i < n) + for (size_t j = len; j > 0; j--) + dest[needed + i - j] = + l_data->weights[weight_idx++]; + + i -= len; + } + + needed += backw_len; + } + } + else + { + int val = 1; +#ifndef WIDE_CHAR_VERSION + char buf[7]; + size_t buflen; +#endif + size_t i; + + while (*cur != L('\0')) + { + const USTRING_TYPE *pos = cur; + size_t len = find_idx (&cur, &weight_idx, &rule_idx, l_data, + pass); + int rule = l_data->rulesets[rule_idx * l_data->nrules + pass]; + + if ((rule & sort_forward) != 0) + { + /* Handle the pushed backward sequence. */ + if (backw_start != NULL) + { + for (size_t p = backw_len; p > 0; p--) + { + size_t len; + int32_t weight_idx; + unsigned char rule_idx; + const USTRING_TYPE *backw_cur = backw_start; + + /* To prevent a warning init the used vars. */ + len = find_idx (&backw_cur, &weight_idx, + &rule_idx, l_data, pass); + + for (i = 1; i < p; i++) + len = find_idx (&backw_cur, &weight_idx, + &rule_idx, l_data, pass); + + if (len != 0) + { +#ifdef WIDE_CHAR_VERSION + if (needed + 1 + len < n) + { + dest[needed] = val; + for (i = 0; i < len; ++i) + dest[needed + 1 + i] = + l_data->weights[weight_idx + i]; + } + needed += 1 + len; +#else + buflen = utf8_encode (buf, val); + if (needed + buflen + len < n) + { + for (i = 0; i < buflen; ++i) + dest[needed + i] = buf[i]; + for (i = 0; i < len; ++i) + dest[needed + buflen + i] = + l_data->weights[weight_idx + i]; + } + needed += buflen + len; +#endif + val = 1; + } + else + ++val; + } + + backw_start = NULL; + backw_len = 0; + } + + /* Now handle the forward element. */ + if (len != 0) + { +#ifdef WIDE_CHAR_VERSION + if (needed + 1 + len < n) + { + dest[needed] = val; + for (i = 0; i < len; ++i) + dest[needed + 1 + i] = + l_data->weights[weight_idx + i]; + } + needed += 1 + len; +#else + buflen = utf8_encode (buf, val); + if (needed + buflen + len < n) + { + for (i = 0; i < buflen; ++i) + dest[needed + i] = buf[i]; + for (i = 0; i < len; ++i) + dest[needed + buflen + i] = + l_data->weights[weight_idx + i]; + } + needed += buflen + len; +#endif + val = 1; + } + else + ++val; + } + else + { + /* Remember start of the backward sequence & track length. */ + if (backw_start == NULL) + backw_start = pos; + backw_len++; + } + } + + /* Handle the pushed backward sequence. */ + if (backw_start != NULL) + { + for (size_t p = backw_len; p > 0; p--) + { + size_t len; + int32_t weight_idx; + unsigned char rule_idx; + const USTRING_TYPE *backw_cur = backw_start; + + /* To prevent a warning init the used vars. */ + len = find_idx (&backw_cur, &weight_idx, + &rule_idx, l_data, pass); + + for (i = 1; i < p; i++) + len = find_idx (&backw_cur, &weight_idx, + &rule_idx, l_data, pass); + + if (len != 0) + { +#ifdef WIDE_CHAR_VERSION + if (needed + 1 + len < n) + { + dest[needed] = val; + for (i = 0; i < len; ++i) + dest[needed + 1 + i] = + l_data->weights[weight_idx + i]; + } + needed += 1 + len; +#else + buflen = utf8_encode (buf, val); + if (needed + buflen + len < n) + { + for (i = 0; i < buflen; ++i) + dest[needed + i] = buf[i]; + for (i = 0; i < len; ++i) + dest[needed + buflen + i] = + l_data->weights[weight_idx + i]; + } + needed += buflen + len; +#endif + val = 1; + } + else + ++val; + } + } + } + + /* Finally store the byte to separate the passes or terminate + the string. */ + if (needed < n) + dest[needed] = pass + 1 < l_data->nrules ? L('\1') : L('\0'); + ++needed; + } + + /* This is a little optimization: many collation specifications have + 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 > 2 && needed == last_needed + 1) + { + /* Remove the \1 byte. */ + if (--needed <= n) + dest[needed - 1] = L('\0'); + } + + /* Return the number of bytes/words we need, but don't count the NUL + byte/word at the end. */ + return needed - 1; +} + +/* Do the transformation using weight-index and rule cache. */ +static size_t +do_xfrm_cached (STRING_TYPE *dest, size_t n, const locale_data_t *l_data, + size_t idxmax, int32_t *idxarr, const unsigned char *rulearr) +{ + uint_fast32_t nrules = l_data->nrules; + unsigned char *rulesets = l_data->rulesets; + USTRING_TYPE *weights = l_data->weights; + uint_fast32_t pass; + size_t needed = 0; + size_t last_needed; + size_t idxcnt; + + /* Now the passes over the weights. */ + for (pass = 0; pass < nrules; ++pass) + { + size_t backw_stop = ~0ul; + int rule = rulesets[rulearr[0] * nrules + pass]; + /* We assume that if a rule has defined `position' in one section + this is true for all of them. */ + int position = rule & sort_position; + + last_needed = needed; + if (position == 0) + { + for (idxcnt = 0; idxcnt < idxmax; ++idxcnt) + { + if ((rule & sort_forward) != 0) + { + size_t len; + + if (backw_stop != ~0ul) + { + /* Handle the pushed elements now. */ + size_t backw; + + for (backw = idxcnt; backw > backw_stop; ) + { + --backw; + len = weights[idxarr[backw]++]; + + if (needed + len < n) + while (len-- > 0) + dest[needed++] = weights[idxarr[backw]++]; + else + { + /* No more characters fit into the buffer. */ + needed += len; + idxarr[backw] += len; + } + } + + backw_stop = ~0ul; + } + + /* Now handle the forward element. */ + len = weights[idxarr[idxcnt]++]; + if (needed + len < n) + while (len-- > 0) + dest[needed++] = weights[idxarr[idxcnt]++]; + else + { + /* No more characters fit into the buffer. */ + needed += len; + idxarr[idxcnt] += len; + } + } + else + { + /* Remember where the backwards series started. */ + if (backw_stop == ~0ul) + backw_stop = idxcnt; + } + + rule = rulesets[rulearr[idxcnt + 1] * nrules + pass]; + } + + + if (backw_stop != ~0ul) + { + /* Handle the pushed elements now. */ + size_t backw; + + backw = idxcnt; + while (backw > backw_stop) + { + size_t len = weights[idxarr[--backw]++]; + + if (needed + len < n) + while (len-- > 0) + dest[needed++] = weights[idxarr[backw]++]; + else + { + /* No more characters fit into the buffer. */ + needed += len; + idxarr[backw] += len; + } + } + } + } + else + { + int val = 1; +#ifndef WIDE_CHAR_VERSION + char buf[7]; + size_t buflen; +#endif + size_t i; + + for (idxcnt = 0; idxcnt < idxmax; ++idxcnt) + { + if ((rule & sort_forward) != 0) + { + size_t len; + + if (backw_stop != ~0ul) + { + /* Handle the pushed elements now. */ + size_t backw; + + for (backw = idxcnt; backw > backw_stop; ) + { + --backw; + len = weights[idxarr[backw]++]; + if (len != 0) + { +#ifdef WIDE_CHAR_VERSION + if (needed + 1 + len < n) + { + dest[needed] = val; + for (i = 0; i < len; ++i) + dest[needed + 1 + i] = + weights[idxarr[backw] + i]; + } + needed += 1 + len; +#else + buflen = utf8_encode (buf, val); + if (needed + buflen + len < n) + { + for (i = 0; i < buflen; ++i) + dest[needed + i] = buf[i]; + for (i = 0; i < len; ++i) + dest[needed + buflen + i] = + weights[idxarr[backw] + i]; + } + needed += buflen + len; +#endif + idxarr[backw] += len; + val = 1; + } + else + ++val; + } + + backw_stop = ~0ul; + } + + /* Now handle the forward element. */ + len = weights[idxarr[idxcnt]++]; + if (len != 0) + { +#ifdef WIDE_CHAR_VERSION + if (needed + 1+ len < n) + { + dest[needed] = val; + for (i = 0; i < len; ++i) + dest[needed + 1 + i] = + weights[idxarr[idxcnt] + i]; + } + needed += 1 + len; +#else + buflen = utf8_encode (buf, val); + if (needed + buflen + len < n) + { + for (i = 0; i < buflen; ++i) + dest[needed + i] = buf[i]; + for (i = 0; i < len; ++i) + dest[needed + buflen + i] = + weights[idxarr[idxcnt] + i]; + } + needed += buflen + len; +#endif + idxarr[idxcnt] += len; + val = 1; + } + else + /* Note that we don't have to increment `idxarr[idxcnt]' + since the length is zero. */ + ++val; + } + else + { + /* Remember where the backwards series started. */ + if (backw_stop == ~0ul) + backw_stop = idxcnt; + } + + rule = rulesets[rulearr[idxcnt + 1] * nrules + pass]; + } + + if (backw_stop != ~0ul) + { + /* Handle the pushed elements now. */ + size_t backw; + + backw = idxmax - 1; + while (backw > backw_stop) + { + size_t len = weights[idxarr[--backw]++]; + if (len != 0) + { +#ifdef WIDE_CHAR_VERSION + if (needed + 1 + len < n) + { + dest[needed] = val; + for (i = 0; i < len; ++i) + dest[needed + 1 + i] = + weights[idxarr[backw] + i]; + } + needed += 1 + len; +#else + buflen = utf8_encode (buf, val); + if (needed + buflen + len < n) + { + for (i = 0; i < buflen; ++i) + dest[needed + i] = buf[i]; + for (i = 0; i < len; ++i) + dest[needed + buflen + i] = + weights[idxarr[backw] + i]; + } + needed += buflen + len; +#endif + idxarr[backw] += len; + val = 1; + } + else + ++val; + } + } + } + + /* Finally store the byte to separate the passes or terminate + the string. */ + if (needed < n) + dest[needed] = pass + 1 < nrules ? L('\1') : L('\0'); + ++needed; + } + + /* This is a little optimization: many collation specifications have + 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 > 2 && needed == last_needed + 1) + { + /* Remove the \1 byte. */ + if (--needed <= n) + dest[needed - 1] = L('\0'); + } + + /* Return the number of bytes/words we need, but don't count the NUL + byte/word at the end. */ + return needed - 1; +} + +size_t +STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n, __locale_t l) +{ + locale_data_t l_data; + struct __locale_data *current = l->__locales[LC_COLLATE]; + l_data.nrules = current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word; + + /* Handle byte comparison case. */ + if (l_data.nrules == 0) + { + size_t srclen = STRLEN (src); + + if (n != 0) + STPNCPY (dest, src, MIN (srclen + 1, n)); + + return srclen; + } + + /* Handle an empty string, code hereafter relies on strlen (src) > 0. */ + if (*src == L('\0')) + { + if (n != 0) + *dest = L('\0'); + return 0; + } + + /* Get the locale data. */ + l_data.rulesets = (unsigned char *) + current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULESETS)].string; + l_data.table = (int32_t *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_TABLE,SUFFIX))].string; + l_data.weights = (USTRING_TYPE *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_WEIGHT,SUFFIX))].string; + l_data.extra = (USTRING_TYPE *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_EXTRA,SUFFIX))].string; + l_data.indirect = (int32_t *) + current->values[_NL_ITEM_INDEX (CONCAT(_NL_COLLATE_INDIRECT,SUFFIX))].string; + + assert (((uintptr_t) l_data.table) % __alignof__ (l_data.table[0]) == 0); + assert (((uintptr_t) l_data.weights) % __alignof__ (l_data.weights[0]) == 0); + assert (((uintptr_t) l_data.extra) % __alignof__ (l_data.extra[0]) == 0); + assert (((uintptr_t) l_data.indirect) % __alignof__ (l_data.indirect[0]) == 0); + + /* We need the elements of the string as unsigned values since they + are used as indeces. */ + const USTRING_TYPE *usrc = (const USTRING_TYPE *) src; + + /* Allocate cache for small strings on the stack and fill it with weight and + rule indices. If the cache size is not sufficient, continue with the + uncached xfrm version. */ + size_t idxmax = 0; + const USTRING_TYPE *cur = usrc; + int32_t *idxarr = alloca (SMALL_STR_SIZE * sizeof (int32_t)); + unsigned char *rulearr = alloca (SMALL_STR_SIZE + 1); + + do + { + int32_t tmp = findidx (l_data.table, l_data.indirect, l_data.extra, &cur, + -1); + rulearr[idxmax] = tmp >> 24; + idxarr[idxmax] = tmp & 0xffffff; + + ++idxmax; + } + while (*cur != L('\0') && idxmax < SMALL_STR_SIZE); + + /* This element is only read, the value never used but to determine + another value which then is ignored. */ + rulearr[idxmax] = '\0'; + + /* Do the transformation. */ + if (*cur == L('\0')) + return do_xfrm_cached (dest, n, &l_data, idxmax, idxarr, rulearr); + else + return do_xfrm (usrc, dest, n, &l_data); +} +libc_hidden_def (STRXFRM) + +#ifndef WIDE_CHAR_VERSION +weak_alias (__strxfrm_l, strxfrm_l) +#endif diff --git a/REORG.TODO/string/swab.c b/REORG.TODO/string/swab.c new file mode 100644 index 0000000000..bcdf6595b6 --- /dev/null +++ b/REORG.TODO/string/swab.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1992-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +void +swab (const void *bfrom, void *bto, ssize_t n) +{ + const char *from = (const char *) bfrom; + char *to = (char *) bto; + + n &= ~((ssize_t) 1); + while (n > 1) + { + const char b0 = from[--n], b1 = from[--n]; + to[n] = b0; + to[n + 1] = b1; + } +} diff --git a/REORG.TODO/string/test-bcopy.c b/REORG.TODO/string/test-bcopy.c new file mode 100644 index 0000000000..11acf07b79 --- /dev/null +++ b/REORG.TODO/string/test-bcopy.c @@ -0,0 +1,20 @@ +/* Test and measure bcopy functions. + Copyright (C) 2012-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_BCOPY +#include "test-memmove.c" diff --git a/REORG.TODO/string/test-bzero.c b/REORG.TODO/string/test-bzero.c new file mode 100644 index 0000000000..a24c448804 --- /dev/null +++ b/REORG.TODO/string/test-bzero.c @@ -0,0 +1,19 @@ +/* Test and measure bzero functions. + Copyright (C) 2012-2017 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, see + <http://www.gnu.org/licenses/>. */ +#define TEST_BZERO +#include "test-memset.c" diff --git a/REORG.TODO/string/test-endian-types.c b/REORG.TODO/string/test-endian-types.c new file mode 100644 index 0000000000..86a89324f7 --- /dev/null +++ b/REORG.TODO/string/test-endian-types.c @@ -0,0 +1,49 @@ +/* Test endian.h endian-conversion macros always return the correct type. + Copyright (C) 2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <endian.h> +#include <stdint.h> + +int i; +uint16_t u16; +uint32_t u32; +uint64_t u64; + +int +do_test (void) +{ + /* This is a compilation test. */ + extern __typeof (htobe16 (i)) u16; + extern __typeof (htole16 (i)) u16; + extern __typeof (be16toh (i)) u16; + extern __typeof (le16toh (i)) u16; + extern __typeof (htobe32 (i)) u32; + extern __typeof (htole32 (i)) u32; + extern __typeof (be32toh (i)) u32; + extern __typeof (le32toh (i)) u32; + extern __typeof (htobe64 (i)) u64; + extern __typeof (htole64 (i)) u64; + extern __typeof (be64toh (i)) u64; + extern __typeof (le64toh (i)) u64; + (void) u16; + (void) u32; + (void) u64; + return 0; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-explicit_bzero.c b/REORG.TODO/string/test-explicit_bzero.c new file mode 100644 index 0000000000..7e41163eb1 --- /dev/null +++ b/REORG.TODO/string/test-explicit_bzero.c @@ -0,0 +1,20 @@ +/* Test and measure explicit_bzero. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ +#define TEST_EXPLICIT_BZERO +#define TEST_BZERO +#include "test-memset.c" diff --git a/REORG.TODO/string/test-ffs.c b/REORG.TODO/string/test-ffs.c new file mode 100644 index 0000000000..11b6ea838b --- /dev/null +++ b/REORG.TODO/string/test-ffs.c @@ -0,0 +1,65 @@ +/* Copyright (C) 1994-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Joel Sherrill (jsherril@redstone-emh2.army.mil), + On-Line Applications Research Corporation. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +int +do_test (void) +{ + int failures = 0; + int i; + + auto void try (const char *name, long long int param, int value, + int expected); + + void try (const char *name, long long int param, int value, int expected) + { + if (value != expected) + { + printf ("%s(%#llx) expected %d got %d\n", + name, param, expected, value); + ++failures; + } + else + printf ("%s(%#llx) as expected %d\n", name, param, value); + } + +#define TEST(fct, type) \ + try (#fct, 0, fct ((type) 0), 0); \ + for (i=0 ; i < 8 * sizeof (type); i++) \ + try (#fct, 1ll << i, fct (((type) 1) << i), i + 1); \ + for (i=0 ; i < 8 * sizeof (type) ; i++) \ + try (#fct, (~((type) 0) >> i) << i, fct ((~((type) 0) >> i) << i), i + 1);\ + try (#fct, 0x80008000, fct ((type) 0x80008000), 16) + + TEST (ffs, int); + TEST (ffsl, long int); + TEST (ffsll, long long int); + + if (failures) + printf ("Test FAILED! %d failure%s.\n", failures, &"s"[failures == 1]); + else + puts ("Test succeeded."); + + return failures; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-memccpy.c b/REORG.TODO/string/test-memccpy.c new file mode 100644 index 0000000000..7bd67a61e7 --- /dev/null +++ b/REORG.TODO/string/test-memccpy.c @@ -0,0 +1,269 @@ +/* Test and measure memccpy functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#define TEST_NAME "memccpy" +#include "test-string.h" + +void *simple_memccpy (void *, const void *, int, size_t); +void *stupid_memccpy (void *, const void *, int, size_t); + +IMPL (stupid_memccpy, 0) +IMPL (simple_memccpy, 0) +IMPL (memccpy, 1) + +void * +simple_memccpy (void *dst, const void *src, int c, size_t n) +{ + const char *s = src; + char *d = dst; + + while (n-- > 0) + if ((*d++ = *s++) == (char) c) + return d; + + return NULL; +} + +void * +stupid_memccpy (void *dst, const void *src, int c, size_t n) +{ + void *p = memchr (src, c, n); + + if (p != NULL) + return mempcpy (dst, src, p - src + 1); + + memcpy (dst, src, n); + return NULL; +} + +typedef void *(*proto_t) (void *, const void *, int c, size_t); + +static void +do_one_test (impl_t *impl, void *dst, const void *src, int c, size_t len, + size_t n) +{ + void *expect = len > n ? NULL : (char *) dst + len; + if (CALL (impl, dst, src, c, n) != expect) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + CALL (impl, dst, src, c, n), expect); + ret = 1; + return; + } + + if (memcmp (dst, src, len > n ? n : len) != 0) + { + error (0, 0, "Wrong result in function %s", impl->name); + ret = 1; + return; + } +} + +static void +do_test (size_t align1, size_t align2, int c, size_t len, size_t n, + int max_char) +{ + size_t i; + char *s1, *s2; + + align1 &= 7; + if (align1 + len >= page_size) + return; + + align2 &= 7; + if (align2 + len >= page_size) + return; + + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); + + for (i = 0; i < len - 1; ++i) + { + s1[i] = 32 + 23 * i % (max_char - 32); + if (s1[i] == (char) c) + --s1[i]; + } + s1[len - 1] = c; + for (i = len; i + align1 < page_size && i < len + 64; ++i) + s1[i] = 32 + 32 * i % (max_char - 32); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s2, s1, c, len, n); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, len, size, mode; + unsigned char *p1 = buf1 + page_size - 512; + unsigned char *p2 = buf2 + page_size - 512; + unsigned char *res, c; + + for (n = 0; n < ITERATIONS; n++) + { + mode = random (); + c = random (); + if (mode & 1) + { + size = random () & 255; + align1 = 512 - size - (random () & 15); + if (mode & 2) + align2 = align1 - (random () & 24); + else + align2 = align1 - (random () & 31); + if (mode & 4) + { + j = align1; + align1 = align2; + align2 = j; + } + if (mode & 8) + len = size - (random () & 31); + else + len = 512; + if (len >= 512) + len = random () & 511; + } + else + { + align1 = random () & 31; + if (mode & 2) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + len = random () & 511; + j = align1; + if (align2 > j) + j = align2; + if (mode & 4) + { + size = random () & 511; + if (size + j > 512) + size = 512 - j - (random() & 31); + } + else + size = 512 - j; + if ((mode & 8) && len + j >= 512) + len = 512 - j - (random () & 7); + } + j = len + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; i++) + { + if (i == len + align1) + p1[i] = c; + else + { + p1[i] = random () & 255; + if (i >= align1 && i < len + align1 && p1[i] == c) + p1[i] = (random () & 127) + 3 + c; + } + } + + FOR_EACH_IMPL (impl, 1) + { + unsigned char *expect; + memset (p2 - 64, '\1', 512 + 64); + res = CALL (impl, p2 + align2, p1 + align1, (char) c, size); + if (len >= size) + expect = NULL; + else + expect = p2 + align2 + len + 1; + + if (res != expect) + { + error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd, %d) %p != %p", + n, impl->name, align1, align2, len, size, c, res, expect); + ret = 1; + } + for (j = 0; j < align2 + 64; ++j) + { + if (p2[j - 64] != '\1') + { + error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + j = align2 + len + 1; + if (size + align2 < j) + j = size + align2; + for (; j < 512; ++j) + { + if (p2[j] != '\1') + { + error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + j = len + 1; + if (size < j) + j = size; + if (memcmp (p1 + align1, p2 + align2, j)) + { + error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + } + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%28s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 8; ++i) + { + do_test (i, i, 12, 16, 16, 127); + do_test (i, i, 23, 16, 16, 255); + do_test (i, 2 * i, 28, 16, 16, 127); + do_test (2 * i, i, 31, 16, 16, 255); + do_test (8 - i, 2 * i, 1, 1 << i, 2 << i, 127); + do_test (2 * i, 8 - i, 17, 2 << i, 1 << i, 127); + do_test (8 - i, 2 * i, 0, 1 << i, 2 << i, 255); + do_test (2 * i, 8 - i, i, 2 << i, 1 << i, 255); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, i, 4 << i, 8 << i, 127); + do_test (0, 0, i, 16 << i, 8 << i, 127); + do_test (8 - i, 2 * i, i, 4 << i, 8 << i, 127); + do_test (8 - i, 2 * i, i, 16 << i, 8 << i, 127); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-memchr.c b/REORG.TODO/string/test-memchr.c new file mode 100644 index 0000000000..73a93f0fc9 --- /dev/null +++ b/REORG.TODO/string/test-memchr.c @@ -0,0 +1,227 @@ +/* Test memchr functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "memchr" +#else +# define TEST_NAME "wmemchr" +#endif /* WIDE */ + +#include "test-string.h" +#include <stdint.h> + +#ifndef WIDE +# define MEMCHR memchr +# define CHAR char +# define UCHAR unsigned char +# define SIMPLE_MEMCHR simple_memchr +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +#else +# include <wchar.h> +# define MEMCHR wmemchr +# define CHAR wchar_t +# define UCHAR wchar_t +# define SIMPLE_MEMCHR simple_wmemchr +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +#endif /* WIDE */ + +typedef CHAR *(*proto_t) (const CHAR *, int, size_t); +CHAR *SIMPLE_MEMCHR (const CHAR *, int, size_t); + +IMPL (SIMPLE_MEMCHR, 0) +IMPL (MEMCHR, 1) + +CHAR * +SIMPLE_MEMCHR (const CHAR *s, int c, size_t n) +{ + while (n--) + if (*s++ == (CHAR) c) + return (CHAR *) s - 1; + return NULL; +} + +static void +do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res) +{ + CHAR *res = CALL (impl, s, c, n); + if (res != exp_res) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + res, exp_res); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char) +{ + size_t i; + CHAR *result; + + if ((align + len) * sizeof (CHAR) >= page_size) + return; + + CHAR *buf = (CHAR *) (buf1); + + for (i = 0; i < len; ++i) + { + buf[align + i] = 1 + 23 * i % SMALL_CHAR; + if (buf[align + i] == seek_char) + buf[align + i] = seek_char + 1; + } + buf[align + len] = 0; + + if (pos < len) + { + buf[align + pos] = seek_char; + buf[align + len] = -seek_char; + result = (CHAR *) (buf + align + pos); + } + else + { + result = NULL; + buf[align + len] = seek_char; + } + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, (CHAR *) (buf + align), seek_char, n, result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, pos, len; + int seek_char; + CHAR *result; + UCHAR *p = (UCHAR *) (buf1 + page_size) - 512; + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & 15; + pos = random () & 511; + if (pos + align >= 512) + pos = 511 - align - (random () & 7); + len = random () & 511; + if (pos >= len) + len = pos + (random () & 7); + if (len + align >= 512) + len = 512 - align - (random () & 7); + seek_char = random () & BIG_CHAR; + j = len + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == pos + align) + p[i] = seek_char; + else + { + p[i] = random () & BIG_CHAR; + if (i < pos + align && p[i] == seek_char) + p[i] = seek_char + 13; + } + } + + if (pos < len) + { + size_t r = random (); + if ((r & 31) == 0) + len = ~(uintptr_t) (p + align) - ((r >> 5) & 31); + result = (CHAR *) (p + pos + align); + } + else + result = NULL; + + FOR_EACH_IMPL (impl, 1) + 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, (CHAR *) (p + align), seek_char, len), + result, p); + ret = 1; + } + } +} + +int +test_main (void) +{ + size_t i, j; + + test_init (); + + printf ("%20s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 8; ++i) + { + /* Test n == 0. */ + do_test (i, i, 0, 0, 23); + do_test (i, i, 0, 0, 0); + + do_test (0, 16 << i, 2048, 2048, 23); + do_test (i, 64, 256, 256, 23); + do_test (0, 16 << i, 2048, 2048, 0); + do_test (i, 64, 256, 256, 0); + + /* Check for large input sizes and for these cases we need to + make sure the byte is within the size range (that's why + 7 << i must be smaller than 2048). */ + do_test (0, 7 << i, 2048, SIZE_MAX, 23); + do_test (0, 2048 - i, 2048, SIZE_MAX, 23); + do_test (i, 64, 256, SIZE_MAX, 23); + do_test (0, 7 << i, 2048, SIZE_MAX, 0); + do_test (0, 2048 - i, 2048, SIZE_MAX, 0); + do_test (i, 64, 256, SIZE_MAX, 0); + } + + for (i = 1; i < 64; ++i) + { + for (j = 1; j < 64; j++) + { + do_test (0, 64 - j, 64, SIZE_MAX, 23); + do_test (i, 64 - j, 64, SIZE_MAX, 23); + } + } + + for (i = 1; i < 32; ++i) + { + do_test (0, i, i + 1, i + 1, 23); + do_test (0, i, i + 1, i + 1, 0); + } + + /* BZ#21182 - wrong overflow calculation for i686 implementation + with address near end of the page. */ + for (i = 2; i < 16; ++i) + /* page_size is in fact getpagesize() * 2. */ + do_test (page_size / 2 - i, i, i, 1, 0x9B); + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-memcmp.c b/REORG.TODO/string/test-memcmp.c new file mode 100644 index 0000000000..a7969edaea --- /dev/null +++ b/REORG.TODO/string/test-memcmp.c @@ -0,0 +1,525 @@ +/* Test and measure memcmp functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + Added wmemcmp support by Liubov Dmitrieva <liubov.dmitrieva@gmail.com>, 2011. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifdef WIDE +# define TEST_NAME "wmemcmp" +#else +# define TEST_NAME "memcmp" +#endif +#include "test-string.h" +#ifdef WIDE +# include <inttypes.h> +# include <wchar.h> + +# define MEMCMP wmemcmp +# define MEMCPY wmemcpy +# define SIMPLE_MEMCMP simple_wmemcmp +# define CHAR wchar_t +# define UCHAR wchar_t +# define CHARBYTES 4 +# define CHAR__MIN WCHAR_MIN +# define CHAR__MAX WCHAR_MAX +int +simple_wmemcmp (const wchar_t *s1, const wchar_t *s2, size_t n) +{ + int ret = 0; + /* Warning! + wmemcmp has to use SIGNED comparison for elements. + memcmp has to use UNSIGNED comparison for elemnts. + */ + while (n-- && (ret = *s1 < *s2 ? -1 : *s1 == *s2 ? 0 : 1) == 0) {s1++; s2++;} + return ret; +} +#else +# include <limits.h> + +# define MEMCMP memcmp +# define MEMCPY memcpy +# define SIMPLE_MEMCMP simple_memcmp +# define CHAR char +# define MAX_CHAR 255 +# define UCHAR unsigned char +# define CHARBYTES 1 +# define CHAR__MIN CHAR_MIN +# define CHAR__MAX CHAR_MAX + +int +simple_memcmp (const char *s1, const char *s2, size_t n) +{ + int ret = 0; + + while (n-- && (ret = *(unsigned char *) s1++ - *(unsigned char *) s2++) == 0); + return ret; +} +#endif + +typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); + +IMPL (SIMPLE_MEMCMP, 0) +IMPL (MEMCMP, 1) + +static int +check_result (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t len, + int exp_result) +{ + int result = CALL (impl, s1, s2, len); + if ((exp_result == 0 && result != 0) + || (exp_result < 0 && result >= 0) + || (exp_result > 0 && result <= 0)) + { + error (0, 0, "Wrong result in function %s %d %d", impl->name, + result, exp_result); + ret = 1; + return -1; + } + + return 0; +} + +static void +do_one_test (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t len, + int exp_result) +{ + if (check_result (impl, s1, s2, len, exp_result) < 0) + return; +} + +static void +do_test (size_t align1, size_t align2, size_t len, int exp_result) +{ + size_t i; + CHAR *s1, *s2; + + if (len == 0) + return; + + align1 &= 63; + if (align1 + (len + 1) * CHARBYTES >= page_size) + return; + + align2 &= 63; + if (align2 + (len + 1) * CHARBYTES >= page_size) + return; + + s1 = (CHAR *) (buf1 + align1); + s2 = (CHAR *) (buf2 + align2); + + for (i = 0; i < len; i++) + s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % CHAR__MAX; + + s1[len] = align1; + s2[len] = align2; + s2[len - 1] -= exp_result; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, len, exp_result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, pos, len; + int result; + long r; + UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES); + UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES); + + for (n = 0; n < ITERATIONS; n++) + { + align1 = random () & 31; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + pos = random () & 511; + j = align1; + if (align2 > j) + j = align2; + if (pos + j >= 512) + pos = 511 - j - (random () & 7); + len = random () & 511; + if (len + j >= 512) + len = 511 - j - (random () & 7); + j = len + align1 + 64; + if (j > 512) j = 512; + for (i = 0; i < j; ++i) + p1[i] = random () & 255; + for (i = 0; i < j; ++i) + p2[i] = random () & 255; + + result = 0; + if (pos >= len) + MEMCPY ((CHAR *) p2 + align2, (const CHAR *) p1 + align1, len); + else + { + MEMCPY ((CHAR *) p2 + align2, (const CHAR *) p1 + align1, pos); + if (p2[align2 + pos] == p1[align1 + pos]) + { + p2[align2 + pos] = random () & 255; + if (p2[align2 + pos] == p1[align1 + pos]) + p2[align2 + pos] = p1[align1 + pos] + 3 + (random () & 127); + } + + if (p1[align1 + pos] < p2[align2 + pos]) + result = -1; + else + result = 1; + } + + FOR_EACH_IMPL (impl, 1) + { + r = CALL (impl, (CHAR *) p1 + align1, (const CHAR *) p2 + align2, + len); + if ((r == 0 && result) + || (r < 0 && result >= 0) + || (r > 0 && result <= 0)) + { + error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p", + n, impl->name, align1 * CHARBYTES & 63, align2 * CHARBYTES & 63, len, pos, r, result, p1, p2); + ret = 1; + } + } + } +} + +static void +check1 (void) +{ + CHAR s1[116], s2[116]; + int n, exp_result; + + s1[0] = -108; + s2[0] = -108; + s1[1] = 99; + s2[1] = 99; + s1[2] = -113; + s2[2] = -113; + s1[3] = 1; + s2[3] = 1; + s1[4] = 116; + s2[4] = 116; + s1[5] = 99; + s2[5] = 99; + s1[6] = -113; + s2[6] = -113; + s1[7] = 1; + s2[7] = 1; + s1[8] = 84; + s2[8] = 84; + s1[9] = 99; + s2[9] = 99; + s1[10] = -113; + s2[10] = -113; + s1[11] = 1; + s2[11] = 1; + s1[12] = 52; + s2[12] = 52; + s1[13] = 99; + s2[13] = 99; + s1[14] = -113; + s2[14] = -113; + s1[15] = 1; + s2[15] = 1; + s1[16] = -76; + s2[16] = -76; + s1[17] = -14; + s2[17] = -14; + s1[18] = -109; + s2[18] = -109; + s1[19] = 1; + s2[19] = 1; + s1[20] = -108; + s2[20] = -108; + s1[21] = -14; + s2[21] = -14; + s1[22] = -109; + s2[22] = -109; + s1[23] = 1; + s2[23] = 1; + s1[24] = 84; + s2[24] = 84; + s1[25] = -15; + s2[25] = -15; + s1[26] = -109; + s2[26] = -109; + s1[27] = 1; + s2[27] = 1; + s1[28] = 52; + s2[28] = 52; + s1[29] = -15; + s2[29] = -15; + s1[30] = -109; + s2[30] = -109; + s1[31] = 1; + s2[31] = 1; + s1[32] = 20; + s2[32] = 20; + s1[33] = -15; + s2[33] = -15; + s1[34] = -109; + s2[34] = -109; + s1[35] = 1; + s2[35] = 1; + s1[36] = 20; + s2[36] = 20; + s1[37] = -14; + s2[37] = -14; + s1[38] = -109; + s2[38] = -109; + s1[39] = 1; + s2[39] = 1; + s1[40] = 52; + s2[40] = 52; + s1[41] = -14; + s2[41] = -14; + s1[42] = -109; + s2[42] = -109; + s1[43] = 1; + s2[43] = 1; + s1[44] = 84; + s2[44] = 84; + s1[45] = -14; + s2[45] = -14; + s1[46] = -109; + s2[46] = -109; + s1[47] = 1; + s2[47] = 1; + s1[48] = 116; + s2[48] = 116; + s1[49] = -14; + s2[49] = -14; + s1[50] = -109; + s2[50] = -109; + s1[51] = 1; + s2[51] = 1; + s1[52] = 116; + s2[52] = 116; + s1[53] = -15; + s2[53] = -15; + s1[54] = -109; + s2[54] = -109; + s1[55] = 1; + s2[55] = 1; + s1[56] = -44; + s2[56] = -44; + s1[57] = -14; + s2[57] = -14; + s1[58] = -109; + s2[58] = -109; + s1[59] = 1; + s2[59] = 1; + s1[60] = -108; + s2[60] = -108; + s1[61] = -15; + s2[61] = -15; + s1[62] = -109; + s2[62] = -109; + s1[63] = 1; + s2[63] = 1; + s1[64] = -76; + s2[64] = -76; + s1[65] = -15; + s2[65] = -15; + s1[66] = -109; + s2[66] = -109; + s1[67] = 1; + s2[67] = 1; + s1[68] = -44; + s2[68] = -44; + s1[69] = -15; + s2[69] = -15; + s1[70] = -109; + s2[70] = -109; + s1[71] = 1; + s2[71] = 1; + s1[72] = -12; + s2[72] = -12; + s1[73] = -15; + s2[73] = -15; + s1[74] = -109; + s2[74] = -109; + s1[75] = 1; + s2[75] = 1; + s1[76] = -12; + s2[76] = -12; + s1[77] = -14; + s2[77] = -14; + s1[78] = -109; + s2[78] = -109; + s1[79] = 1; + s2[79] = 1; + s1[80] = 20; + s2[80] = -68; + s1[81] = -12; + s2[81] = 64; + s1[82] = -109; + s2[82] = -106; + s1[83] = 1; + s2[83] = 1; + s1[84] = -12; + s2[84] = -12; + s1[85] = -13; + s2[85] = -13; + s1[86] = -109; + s2[86] = -109; + s1[87] = 1; + s2[87] = 1; + s1[88] = -44; + s2[88] = -44; + s1[89] = -13; + s2[89] = -13; + s1[90] = -109; + s2[90] = -109; + s1[91] = 1; + s2[91] = 1; + s1[92] = -76; + s2[92] = -76; + s1[93] = -13; + s2[93] = -13; + s1[94] = -109; + s2[94] = -109; + s1[95] = 1; + s2[95] = 1; + s1[96] = -108; + s2[96] = -108; + s1[97] = -13; + s2[97] = -13; + s1[98] = -109; + s2[98] = -109; + s1[99] = 1; + s2[99] = 1; + s1[100] = 116; + s2[100] = 116; + s1[101] = CHAR__MIN; + s2[101] = CHAR__MAX; + s1[102] = -109; + s2[102] = -109; + s1[103] = 1; + s2[103] = 1; + s1[104] = 84; + s2[104] = 84; + s1[105] = -13; + s2[105] = -13; + s1[106] = -109; + s2[106] = -109; + s1[107] = 1; + s2[107] = 1; + s1[108] = 52; + s2[108] = 52; + s1[109] = -13; + s2[109] = -13; + s1[110] = -109; + s2[110] = -109; + s1[111] = 1; + s2[111] = 1; + s1[112] = CHAR__MAX; + s2[112] = CHAR__MIN; + s1[113] = -13; + s2[113] = -13; + s1[114] = -109; + s2[114] = -109; + s1[115] = 1; + s2[115] = 1; + + n = 116; + for (size_t i = 0; i < n; i++) + { + exp_result = SIMPLE_MEMCMP (s1 + i, s2 + i, n - i); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1 + i, s2 + i, n - i, exp_result); + } +} + +/* This test checks that memcmp doesn't overrun buffers. */ +static void +check2 (void) +{ + size_t max_length = page_size / sizeof (CHAR); + + /* Initialize buf2 to the same values as buf1. The bug requires the + last compared byte to be different. */ + memcpy (buf2, buf1, page_size); + ((char *) buf2)[page_size - 1] ^= 0x11; + + for (size_t length = 1; length < max_length; length++) + { + CHAR *s1 = (CHAR *) buf1 + max_length - length; + CHAR *s2 = (CHAR *) buf2 + max_length - length; + + const int exp_result = SIMPLE_MEMCMP (s1, s2, length); + + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1, s2, length, exp_result); + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + check1 (); + check2 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 16; ++i) + { + do_test (i * CHARBYTES, i * CHARBYTES, i, 0); + do_test (i * CHARBYTES, i * CHARBYTES, i, 1); + do_test (i * CHARBYTES, i * CHARBYTES, i, -1); + } + + for (i = 0; i < 16; ++i) + { + do_test (0, 0, i, 0); + do_test (0, 0, i, 1); + do_test (0, 0, i, -1); + } + + for (i = 1; i < 10; ++i) + { + do_test (0, 0, 2 << i, 0); + do_test (0, 0, 2 << i, 1); + do_test (0, 0, 2 << i, -1); + do_test (0, 0, 16 << i, 0); + do_test ((8 - i) * CHARBYTES, (2 * i) * CHARBYTES, 16 << i, 0); + do_test (0, 0, 16 << i, 1); + do_test (0, 0, 16 << i, -1); + } + + for (i = 1; i < 8; ++i) + { + do_test (i * CHARBYTES, 2 * (i * CHARBYTES), 8 << i, 0); + do_test (i * CHARBYTES, 2 * (i * CHARBYTES), 8 << i, 1); + do_test (i * CHARBYTES, 2 * (i * CHARBYTES), 8 << i, -1); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-memcpy.c b/REORG.TODO/string/test-memcpy.c new file mode 100644 index 0000000000..49f0a76047 --- /dev/null +++ b/REORG.TODO/string/test-memcpy.c @@ -0,0 +1,259 @@ +/* Test and measure memcpy functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef MEMCPY_RESULT +# define MEMCPY_RESULT(dst, len) dst +# define MIN_PAGE_SIZE 131072 +# define TEST_MAIN +# define TEST_NAME "memcpy" +# include "test-string.h" + +char *simple_memcpy (char *, const char *, size_t); +char *builtin_memcpy (char *, const char *, size_t); + +IMPL (simple_memcpy, 0) +IMPL (builtin_memcpy, 0) +IMPL (memcpy, 1) + +char * +simple_memcpy (char *dst, const char *src, size_t n) +{ + char *ret = dst; + while (n--) + *dst++ = *src++; + return ret; +} + +char * +builtin_memcpy (char *dst, const char *src, size_t n) +{ + return __builtin_memcpy (dst, src, n); +} +#endif + +typedef char *(*proto_t) (char *, const char *, size_t); + +static void +do_one_test (impl_t *impl, char *dst, const char *src, + size_t len) +{ + size_t i; + + /* Must clear the destination buffer set by the previous run. */ + for (i = 0; i < len; i++) + dst[i] = 0; + + if (CALL (impl, dst, src, len) != MEMCPY_RESULT (dst, len)) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + CALL (impl, dst, src, len), MEMCPY_RESULT (dst, len)); + ret = 1; + return; + } + + if (memcmp (dst, src, len) != 0) + { + error (0, 0, "Wrong result in function %s dst %p \"%.*s\" src %p \"%.*s\" len %zu", + impl->name, dst, (int) len, dst, src, (int) len, src, len); + ret = 1; + return; + } +} + +static void +do_test (size_t align1, size_t align2, size_t len) +{ + size_t i, j; + char *s1, *s2; + + align1 &= 63; + if (align1 + len >= page_size) + return; + + align2 &= 63; + if (align2 + len >= page_size) + return; + + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); + + for (i = 0, j = 1; i < len; i++, j += 23) + s1[i] = j; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s2, s1, len); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, len, size1, size2, size; + int c; + unsigned char *p1, *p2; + unsigned char *res; + + for (n = 0; n < ITERATIONS; n++) + { + if (n == 0) + { + len = getpagesize (); + size = len + 512; + size1 = size; + size2 = size; + align1 = 512; + align2 = 512; + } + else + { + if ((random () & 255) == 0) + size = 65536; + else + size = 768; + if (size > page_size) + size = page_size; + size1 = size; + size2 = size; + i = random (); + if (i & 3) + size -= 256; + if (i & 1) + size1 -= 256; + if (i & 2) + size2 -= 256; + if (i & 4) + { + len = random () % size; + align1 = size1 - len - (random () & 31); + align2 = size2 - len - (random () & 31); + if (align1 > size1) + align1 = 0; + if (align2 > size2) + align2 = 0; + } + else + { + align1 = random () & 63; + align2 = random () & 63; + len = random () % size; + if (align1 + len > size1) + align1 = size1 - len; + if (align2 + len > size2) + align2 = size2 - len; + } + } + p1 = buf1 + page_size - size1; + p2 = buf2 + page_size - size2; + c = random () & 255; + j = align1 + len + 256; + if (j > size1) + j = size1; + for (i = 0; i < j; ++i) + p1[i] = random () & 255; + + FOR_EACH_IMPL (impl, 1) + { + j = align2 + len + 256; + if (j > size2) + j = size2; + memset (p2, c, j); + 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", + n, impl->name, align1, align2, len, res, + MEMCPY_RESULT (p2 + align2, len)); + ret = 1; + } + for (i = 0; i < align2; ++i) + { + if (p2[i] != c) + { + error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + for (i = align2 + len; i < j; ++i) + { + if (p2[i] != c) + { + error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + if (memcmp (p1 + align1, p2 + align2, len)) + { + error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + } + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < 18; ++i) + { + do_test (0, 0, 1 << i); + do_test (i, 0, 1 << i); + do_test (0, i, 1 << i); + do_test (i, i, 1 << i); + } + + for (i = 0; i < 32; ++i) + { + do_test (0, 0, i); + do_test (i, 0, i); + do_test (0, i, i); + do_test (i, i, i); + } + + for (i = 3; i < 32; ++i) + { + if ((i & (i - 1)) == 0) + continue; + do_test (0, 0, 16 * i); + do_test (i, 0, 16 * i); + do_test (0, i, 16 * i); + do_test (i, i, 16 * i); + } + + do_test (0, 0, getpagesize ()); + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-memmem.c b/REORG.TODO/string/test-memmem.c new file mode 100644 index 0000000000..82fd93ccde --- /dev/null +++ b/REORG.TODO/string/test-memmem.c @@ -0,0 +1,184 @@ +/* Test and measure memmem functions. + Copyright (C) 2008-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Ulrich Drepper <drepper@redhat.com>, 2008. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#define TEST_NAME "memmem" +#define BUF1PAGES 20 +#define ITERATIONS 500 +#include "test-string.h" + +typedef char *(*proto_t) (const void *, size_t, const void *, size_t); +void *simple_memmem (const void *, size_t, const void *, size_t); + +IMPL (simple_memmem, 0) +IMPL (memmem, 1) + +void * +simple_memmem (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 (__glibc_unlikely (haystack_len < needle_len)) + 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; +} + +static int +check_result (impl_t *impl, const void *haystack, size_t haystack_len, + const void *needle, size_t needle_len, const void *expected) +{ + void *res; + + res = CALL (impl, haystack, haystack_len, needle, needle_len); + if (res != expected) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + res, expected); + ret = 1; + return -1; + } + + return 0; +} + +static void +do_one_test (impl_t *impl, const void *haystack, size_t haystack_len, + const void *needle, size_t needle_len, const void *expected) +{ + if (check_result (impl, haystack, haystack_len, needle, needle_len, + expected) < 0) + return; +} + +static void +do_test (const char *str, size_t len, size_t idx) +{ + char tmpbuf[len]; + + memcpy (tmpbuf, buf1 + idx, len); + memcpy (buf1 + idx, str, len); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, buf1, BUF1PAGES * page_size, str, len, buf1 + idx); + + memcpy (buf1 + idx, tmpbuf, len); +} + +static void +do_random_tests (void) +{ + for (size_t n = 0; n < ITERATIONS; ++n) + { + char tmpbuf[32]; + + size_t shift = random () % 11; + size_t rel = random () % ((2 << (shift + 1)) * 64); + size_t idx = MIN ((2 << shift) * 64 + rel, BUF1PAGES * page_size - 2); + size_t len = random () % (sizeof (tmpbuf) - 1) + 1; + len = MIN (len, BUF1PAGES * page_size - idx - 1); + memcpy (tmpbuf, buf1 + idx, len); + for (size_t i = random () % len / 2 + 1; i > 0; --i) + { + size_t off = random () % len; + char ch = '0' + random () % 10; + + buf1[idx + off] = ch; + } + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, buf1, BUF1PAGES * page_size, buf1 + idx, len, + buf1 + idx); + + memcpy (buf1 + idx, tmpbuf, len); + } +} + +static void +check1 (void) +{ + + const char search_buf_data[5] = { 0x56, 0x34, 0x12, 0x78, 0x78 }; + const char pattern[2] = { 0x78, 0x56 }; + void *search_buf = (void *) buf1 + page_size - sizeof search_buf_data; + void *exp_result; + + memcpy (search_buf, search_buf_data, sizeof search_buf_data); + exp_result = simple_memmem (search_buf, sizeof search_buf_data, + pattern, sizeof pattern); + FOR_EACH_IMPL (impl, 0) + check_result (impl, search_buf, sizeof search_buf_data, + pattern, sizeof pattern, exp_result); +} + +static const char *const strs[] = + { + "00000", "00112233", "0123456789", "0000111100001111", + "00000111110000022222", "012345678901234567890", + "abc0", "aaaa0", "abcabc0" + }; + + +int +test_main (void) +{ + size_t i; + + test_init (); + + check1 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < BUF1PAGES * page_size; ++i) + buf1[i] = 60 + random () % 32; + + for (i = 0; i < sizeof (strs) / sizeof (strs[0]); ++i) + for (size_t j = 0; j < 120; j += 7) + { + size_t len = strlen (strs[i]); + + do_test (strs[i], len, j); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-memmove.c b/REORG.TODO/string/test-memmove.c new file mode 100644 index 0000000000..51f79f6eb4 --- /dev/null +++ b/REORG.TODO/string/test-memmove.c @@ -0,0 +1,290 @@ +/* Test and measure memmove functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifdef TEST_BCOPY +# define TEST_NAME "bcopy" +#else +# define TEST_NAME "memmove" +#endif +#include "test-string.h" + +char *simple_memmove (char *, const char *, size_t); + +#ifdef TEST_BCOPY +typedef void (*proto_t) (const char *, char *, size_t); +void simple_bcopy (const char *, char *, size_t); + +IMPL (simple_bcopy, 0) +IMPL (bcopy, 1) + +void +simple_bcopy (const char *src, char *dst, size_t n) +{ + simple_memmove (dst, src, n); +} +#else +typedef char *(*proto_t) (char *, const char *, size_t); + +IMPL (simple_memmove, 0) +IMPL (memmove, 1) +#endif + +char * +inhibit_loop_to_libcall +simple_memmove (char *dst, const char *src, size_t n) +{ + char *ret = dst; + if (src < dst) + { + dst += n; + src += n; + while (n--) + *--dst = *--src; + } + else + while (n--) + *dst++ = *src++; + return ret; +} + +static void +do_one_test (impl_t *impl, char *dst, char *src, const char *orig_src, + size_t len) +{ + /* This also clears the destination buffer set by the previous run. */ + memcpy (src, orig_src, len); +#ifdef TEST_BCOPY + CALL (impl, src, dst, len); +#else + char *res; + + res = CALL (impl, dst, src, len); + if (res != dst) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + res, dst); + ret = 1; + return; + } +#endif + + if (memcmp (dst, orig_src, len) != 0) + { + error (0, 0, "Wrong result in function %s dst \"%s\" src \"%s\"", + impl->name, dst, src); + ret = 1; + return; + } +} + +static void +do_test (size_t align1, size_t align2, size_t len) +{ + size_t i, j; + char *s1, *s2; + + align1 &= 63; + if (align1 + len >= page_size) + return; + + align2 &= 63; + if (align2 + len >= page_size) + return; + + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); + + for (i = 0, j = 1; i < len; i++, j += 23) + s1[i] = j; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s2, (char *) (buf2 + align1), s1, len); +} + +static void +do_random_tests (void) +{ + size_t i, n, align1, align2, len, size; + size_t srcstart, srcend, dststart, dstend; + int c; + unsigned char *p1, *p2; +#ifndef TEST_BCOPY + unsigned char *res; +#endif + + for (n = 0; n < ITERATIONS; n++) + { + if ((random () & 255) == 0) + size = 65536; + else + size = 512; + if (size > page_size) + size = page_size; + if ((random () & 3) == 0) + { + len = random () & (size - 1); + align1 = size - len - (random () & 31); + align2 = size - len - (random () & 31); + if (align1 > size) + align1 = 0; + if (align2 > size) + align2 = 0; + } + else + { + align1 = random () & (size / 2 - 1); + align2 = random () & (size / 2 - 1); + len = random () & (size - 1); + if (align1 + len > size) + align1 = size - len; + if (align2 + len > size) + align2 = size - len; + } + + p1 = buf1 + page_size - size; + p2 = buf2 + page_size - size; + c = random () & 255; + srcend = align1 + len + 256; + if (srcend > size) + srcend = size; + if (align1 > 256) + srcstart = align1 - 256; + else + srcstart = 0; + for (i = srcstart; i < srcend; ++i) + p1[i] = random () & 255; + dstend = align2 + len + 256; + if (dstend > size) + dstend = size; + if (align2 > 256) + dststart = align2 - 256; + else + dststart = 0; + + FOR_EACH_IMPL (impl, 1) + { + memset (p2 + dststart, c, dstend - dststart); + memcpy (p2 + srcstart, p1 + srcstart, srcend - srcstart); +#ifdef TEST_BCOPY + CALL (impl, (char *) (p2 + align1), (char *) (p2 + align2), len); +#else + 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", + n, impl->name, align1, align2, len, res, p2 + align2); + ret = 1; + } +#endif + if (memcmp (p1 + align1, p2 + align2, len)) + { + error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + } + for (i = dststart; i < dstend; ++i) + { + if (i >= align2 && i < align2 + len) + { + i = align2 + len - 1; + continue; + } + if (i >= srcstart && i < srcend) + { + i = srcend - 1; + continue; + } + if (p2[i] != c) + { + error (0, 0, "Iteration %zd - garbage in memset area, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + + if (srcstart < align2 + && memcmp (p2 + srcstart, p1 + srcstart, + (srcend > align2 ? align2 : srcend) - srcstart)) + { + error (0, 0, "Iteration %zd - garbage before dst, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + + i = srcstart > align2 + len ? srcstart : align2 + len; + if (srcend > align2 + len + && memcmp (p2 + i, p1 + i, srcend - i)) + { + error (0, 0, "Iteration %zd - garbage after dst, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < 14; ++i) + { + do_test (0, 32, 1 << i); + do_test (32, 0, 1 << i); + do_test (0, i, 1 << i); + do_test (i, 0, 1 << i); + } + + for (i = 0; i < 32; ++i) + { + do_test (0, 32, i); + do_test (32, 0, i); + do_test (0, i, i); + do_test (i, 0, i); + } + + for (i = 3; i < 32; ++i) + { + if ((i & (i - 1)) == 0) + continue; + do_test (0, 32, 16 * i); + do_test (32, 0, 16 * i); + do_test (0, i, 16 * i); + do_test (i, 0, 16 * i); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-mempcpy.c b/REORG.TODO/string/test-mempcpy.c new file mode 100644 index 0000000000..364a811c62 --- /dev/null +++ b/REORG.TODO/string/test-mempcpy.c @@ -0,0 +1,38 @@ +/* Test and measure mempcpy functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define MEMCPY_RESULT(dst, len) (dst) + (len) +#define TEST_MAIN +#define TEST_NAME "mempcpy" +#include "test-string.h" + +char *simple_mempcpy (char *, const char *, size_t); + +IMPL (simple_mempcpy, 0) +IMPL (mempcpy, 1) + +char * +simple_mempcpy (char *dst, const char *src, size_t n) +{ + while (n--) + *dst++ = *src++; + return dst; +} + +#include "test-memcpy.c" diff --git a/REORG.TODO/string/test-memrchr.c b/REORG.TODO/string/test-memrchr.c new file mode 100644 index 0000000000..15483f5cb5 --- /dev/null +++ b/REORG.TODO/string/test-memrchr.c @@ -0,0 +1,186 @@ +/* Test and measure memrchr functions. + Copyright (C) 2013-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#define TEST_NAME "memrchr" +#include "test-string.h" + +typedef char *(*proto_t) (const char *, int, size_t); +char *simple_memrchr (const char *, int, size_t); + +IMPL (simple_memrchr, 0) +IMPL (memrchr, 1) + +char * +simple_memrchr (const char *s, int c, size_t n) +{ + s = s + n; + while (n--) + if (*--s == (char) c) + return (char *) s; + return NULL; +} + +static void +do_one_test (impl_t *impl, const char *s, int c, size_t n, char *exp_res) +{ + char *res = CALL (impl, s, c, n); + if (res != exp_res) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + res, exp_res); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t pos, size_t len, int seek_char) +{ + size_t i; + char *result; + + align &= 7; + if (align + len >= page_size) + return; + + for (i = 0; i < len; ++i) + { + buf1[align + i] = 1 + 23 * i % 127; + if (buf1[align + i] == seek_char) + buf1[align + i] = seek_char + 1; + } + buf1[align + len] = 0; + + if (pos < len) + { + buf1[align + pos] = seek_char; + buf1[align + len] = -seek_char; + result = (char *) (buf1 + align + pos); + } + else + { + result = NULL; + buf1[align + len] = seek_char; + } + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, (char *) (buf1 + align), seek_char, len, result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, pos, len; + int seek_char; + char *result; + unsigned char *p = buf1 + page_size - 512; + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & 15; + pos = random () & 511; + if (pos + align >= 512) + pos = 511 - align - (random () & 7); + len = random () & 511; + if (pos >= len) + len = pos + (random () & 7); + if (len + align >= 512) + len = 512 - align - (random () & 7); + seek_char = random () & 255; + j = len + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == pos + align) + p[i] = seek_char; + else + { + p[i] = random () & 255; + if (p[i] == seek_char) + p[i] = seek_char + 13; + } + } + + if (pos < len) + result = (char *) (p + pos + align); + else + result = NULL; + + FOR_EACH_IMPL (impl, 1) + 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, (char *) (p + align), seek_char, len), + result, p); + ret = 1; + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%20s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 8; ++i) + { + /* Test len == 0. */ + do_test (i, i, 0, 0); + do_test (i, i, 0, 23); + + do_test (0, 16 << i, 2048, 23); + do_test (i, 64, 256, 23); + do_test (0, 16 << i, 2048, 0); + do_test (i, 64, 256, 0); + + do_test (0, i, 256, 23); + do_test (0, i, 256, 0); + do_test (i, i, 256, 23); + do_test (i, i, 256, 0); + + } + for (i = 1; i < 32; ++i) + { + do_test (0, i, i + 1, 23); + do_test (0, i, i + 1, 0); + do_test (i, i, i + 1, 23); + do_test (i, i, i + 1, 0); + + do_test (0, 1, i + 1, 23); + do_test (0, 2, i + 1, 0); + do_test (i, 1, i + 1, 23); + do_test (i, 2, i + 1, 0); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-memset.c b/REORG.TODO/string/test-memset.c new file mode 100644 index 0000000000..ca1bfe1e3b --- /dev/null +++ b/REORG.TODO/string/test-memset.c @@ -0,0 +1,267 @@ +/* Test memset functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifdef TEST_BZERO +# ifdef TEST_EXPLICIT_BZERO +# define TEST_NAME "explicit_bzero" +# else +# define TEST_NAME "bzero" +# endif +#else +# ifndef WIDE +# define TEST_NAME "memset" +# else +# define TEST_NAME "wmemset" +# endif /* WIDE */ +#endif /* !TEST_BZERO */ +#define MIN_PAGE_SIZE 131072 +#include "test-string.h" + +#ifndef WIDE +# define MEMSET memset +# define CHAR char +# define UCHAR unsigned char +# define SIMPLE_MEMSET simple_memset +# define MEMCMP memcmp +# define BIG_CHAR CHAR_MAX +#else +# include <wchar.h> +# define MEMSET wmemset +# define CHAR wchar_t +# define UCHAR wchar_t +# define SIMPLE_MEMSET simple_wmemset +# define MEMCMP wmemcmp +# define BIG_CHAR WCHAR_MAX +#endif /* WIDE */ + +CHAR *SIMPLE_MEMSET (CHAR *, int, size_t); + +#ifdef TEST_BZERO +typedef void (*proto_t) (char *, size_t); +void simple_bzero (char *, size_t); +void builtin_bzero (char *, size_t); + +IMPL (simple_bzero, 0) +IMPL (builtin_bzero, 0) +#ifdef TEST_EXPLICIT_BZERO +IMPL (explicit_bzero, 1) +#else +IMPL (bzero, 1) +#endif + +void +simple_bzero (char *s, size_t n) +{ + SIMPLE_MEMSET (s, 0, n); +} + +void +builtin_bzero (char *s, size_t n) +{ + __builtin_bzero (s, n); +} +#else +typedef CHAR *(*proto_t) (CHAR *, int, size_t); + +IMPL (SIMPLE_MEMSET, 0) +# ifndef WIDE +char *builtin_memset (char *, int, size_t); +IMPL (builtin_memset, 0) +# endif /* !WIDE */ +IMPL (MEMSET, 1) + +# ifndef WIDE +char * +builtin_memset (char *s, int c, size_t n) +{ + return __builtin_memset (s, c, n); +} +# endif /* !WIDE */ +#endif /* !TEST_BZERO */ + +CHAR * +inhibit_loop_to_libcall +SIMPLE_MEMSET (CHAR *s, int c, size_t n) +{ + CHAR *r = s, *end = s + n; + while (r < end) + *r++ = c; + return s; +} + +static void +do_one_test (impl_t *impl, CHAR *s, int c __attribute ((unused)), size_t n) +{ + CHAR tstbuf[n]; +#ifdef TEST_BZERO + simple_bzero (tstbuf, n); + CALL (impl, s, n); + if (memcmp (s, tstbuf, n) != 0) +#else + CHAR *res = CALL (impl, s, c, n); + if (res != s + || SIMPLE_MEMSET (tstbuf, c, n) != tstbuf + || MEMCMP (s, tstbuf, n) != 0) +#endif /* !TEST_BZERO */ + { + error (0, 0, "Wrong result in function %s", impl->name); + ret = 1; + return; + } +} + +static void +do_test (size_t align, int c, size_t len) +{ + align &= 7; + if ((align + len) * sizeof (CHAR) > page_size) + return; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, (CHAR *) (buf1) + align, c, len); +} + +#ifndef TEST_BZERO +static void +do_random_tests (void) +{ + size_t i, j, k, n, align, len, size; + int c, o; + UCHAR *p, *res; + UCHAR *p2 = (UCHAR *) buf2; + + for (i = 0; i < 65536 / sizeof (CHAR); ++i) + p2[i] = random () & BIG_CHAR; + + for (n = 0; n < ITERATIONS; n++) + { + if ((random () & 31) == 0) + size = 65536 / sizeof (CHAR); + else + size = 512; + p = (UCHAR *) (buf1 + page_size) - size; + len = random () & (size - 1); + align = size - len - (random () & 31); + if (align > size) + align = size - len; + if ((random () & 7) == 0) + align &= ~63; + if ((random () & 7) == 0) + c = 0; + else + c = random () & BIG_CHAR; + o = random () & BIG_CHAR; + if (o == c) + o = (c + 1) & BIG_CHAR; + j = len + align + 128; + if (j > size) + j = size; + if (align >= 128) + k = align - 128; + else + k = 0; + for (i = k; i < align; ++i) + p[i] = o; + for (i = align + len; i < j; ++i) + p[i] = o; + + FOR_EACH_IMPL (impl, 1) + { + for (i = 0; i < len; ++i) + { + p[i + align] = p2[i]; + if (p[i + align] == c) + p[i + align] = o; + } + res = (UCHAR *) 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", + n, impl->name, align, c, len, res, p + align); + ret = 1; + } + for (i = k; i < align; ++i) + if (p[i] != o) + { + error (0, 0, "Iteration %zd - garbage before %s (%zd, %d, %zd)", + n, impl->name, align, c, len); + ret = 1; + break; + } + for (; i < align + len; ++i) + if (p[i] != c) + { + error (0, 0, "Iteration %zd - not cleared correctly %s (%zd, %d, %zd)", + n, impl->name, align, c, len); + ret = 1; + break; + } + for (; i < j; ++i) + if (p[i] != o) + { + error (0, 0, "Iteration %zd - garbage after %s (%zd, %d, %zd)", + n, impl->name, align, c, len); + ret = 1; + break; + } + } + } +} +#endif /* !TEST_BZERO */ + +int +test_main (void) +{ + size_t i; + int c = 0; + + test_init (); + + printf ("%24s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + +#ifndef TEST_BZERO + for (c = -65; c <= 130; c += 65) +#endif + { + for (i = 0; i < 18; ++i) + do_test (0, c, 1 << i); + for (i = 1; i < 32; ++i) + { + do_test (i, c, i); + if (i & (i - 1)) + do_test (0, c, i); + } + do_test (1, c, 14); + do_test (3, c, 1024); + do_test (4, c, 64); + do_test (2, c, 25); + } + +#ifndef TEST_BZERO + do_random_tests (); +#endif + + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-rawmemchr.c b/REORG.TODO/string/test-rawmemchr.c new file mode 100644 index 0000000000..2a53e71026 --- /dev/null +++ b/REORG.TODO/string/test-rawmemchr.c @@ -0,0 +1,165 @@ +/* Test and measure memchr functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> + +#define TEST_MAIN +#define TEST_NAME "rawmemchr" +#include "test-string.h" + +typedef char *(*proto_t) (const char *, int); +char *simple_rawmemchr (const char *, int); + +IMPL (simple_rawmemchr, 0) +IMPL (rawmemchr, 1) + +char * +simple_rawmemchr (const char *s, int c) +{ + while (1) + if (*s++ == (char) c) + return (char *) s - 1; + return NULL; +} + +static void +do_one_test (impl_t *impl, const char *s, int c, char *exp_res) +{ + char *res = CALL (impl, s, c); + if (res != exp_res) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + res, exp_res); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t pos, size_t len, int seek_char) +{ + size_t i; + char *result; + + align &= 7; + if (align + len >= page_size) + return; + + for (i = 0; i < len; ++i) + { + buf1[align + i] = 1 + 23 * i % 127; + if (buf1[align + i] == seek_char) + buf1[align + i] = seek_char + 1; + } + buf1[align + len] = 0; + + assert (pos < len); + + buf1[align + pos] = seek_char; + buf1[align + len] = -seek_char; + result = (char *) (buf1 + align + pos); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, (char *) (buf1 + align), seek_char, result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, pos, len; + int seek_char; + char *result; + unsigned char *p = buf1 + page_size - 512; + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & 15; + pos = random () & 511; + if (pos + align >= 512) + pos = 511 - align - (random () & 7); + len = random () & 511; + if (len + align >= 512) + len = 512 - align - (random () & 7); + if (pos >= len) + continue; + seek_char = random () & 255; + j = len + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == pos + align) + p[i] = seek_char; + else + { + p[i] = random () & 255; + if (i < pos + align && p[i] == seek_char) + p[i] = seek_char + 13; + } + } + + assert (pos < len); + size_t r = random (); + if ((r & 31) == 0) + len = ~(uintptr_t) (p + align) - ((r >> 5) & 31); + result = (char *) (p + pos + align); + + FOR_EACH_IMPL (impl, 1) + 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, (char *) (p + align), seek_char), + result, p); + ret = 1; + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%20s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 7; ++i) + { + do_test (0, 16 << i, 2048, 23); + do_test (i, 64, 256, 23); + do_test (0, 16 << i, 2048, 0); + do_test (i, 64, 256, 0); + } + for (i = 1; i < 32; ++i) + { + do_test (0, i, i + 1, 23); + do_test (0, i, i + 1, 0); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-stpcpy.c b/REORG.TODO/string/test-stpcpy.c new file mode 100644 index 0000000000..5e31abf962 --- /dev/null +++ b/REORG.TODO/string/test-stpcpy.c @@ -0,0 +1,52 @@ +/* Test stpcpy functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define STRCPY_RESULT(dst, len) ((dst) + (len)) +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "stpcpy" +#else +# define TEST_NAME "wcpcpy" +#endif /* !WIDE */ +#include "test-string.h" +#ifndef WIDE +# define CHAR char +# define SIMPLE_STPCPY simple_stpcpy +# define STPCPY stpcpy +#else +# include <wchar.h> +# define CHAR wchar_t +# define SIMPLE_STPCPY simple_wcpcpy +# define STPCPY wcpcpy +#endif /* !WIDE */ + +CHAR *SIMPLE_STPCPY (CHAR *, const CHAR *); + +IMPL (SIMPLE_STPCPY, 0) +IMPL (STPCPY, 1) + +CHAR * +SIMPLE_STPCPY (CHAR *dst, const CHAR *src) +{ + while ((*dst++ = *src++) != '\0'); + return dst - 1; +} + +#undef CHAR +#include "test-strcpy.c" diff --git a/REORG.TODO/string/test-stpncpy.c b/REORG.TODO/string/test-stpncpy.c new file mode 100644 index 0000000000..5b26ae5e4f --- /dev/null +++ b/REORG.TODO/string/test-stpncpy.c @@ -0,0 +1,79 @@ +/* Test and measure stpncpy functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define STRNCPY_RESULT(dst, len, n) ((dst) + ((len) > (n) ? (n) : (len))) +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "stpncpy" +#else +# define TEST_NAME "wcpncpy" +#endif /* WIDE */ +#include "test-string.h" +#ifndef WIDE +# define CHAR char +# define SIMPLE_STPNCPY simple_stpncpy +# define STUPID_STPNCPY stupid_stpncpy +# define STPNCPY stpncpy +# define STRNLEN strnlen +#else +# include <wchar.h> +# define CHAR wchar_t +# define SIMPLE_STPNCPY simple_wcpncpy +# define STUPID_STPNCPY stupid_wcpncpy +# define STPNCPY wcpncpy +# define STRNLEN wcsnlen +#endif /* WIDE */ + +CHAR *SIMPLE_STPNCPY (CHAR *, const CHAR *, size_t); +CHAR *STUPID_STPNCPY (CHAR *, const CHAR *, size_t); + +IMPL (STUPID_STPNCPY, 0) +IMPL (SIMPLE_STPNCPY, 0) +IMPL (STPNCPY, 1) + +CHAR * +SIMPLE_STPNCPY (CHAR *dst, const CHAR *src, size_t n) +{ + while (n--) + if ((*dst++ = *src++) == '\0') + { + size_t i; + + for (i = 0; i < n; ++i) + dst[i] = '\0'; + return dst - 1; + } + return dst; +} + +CHAR * +STUPID_STPNCPY (CHAR *dst, const CHAR *src, size_t n) +{ + size_t nc = STRNLEN (src, n); + size_t i; + + for (i = 0; i < nc; ++i) + dst[i] = src[i]; + for (; i < n; ++i) + dst[i] = '\0'; + return dst + nc; +} + +#undef CHAR +#include "test-strncpy.c" diff --git a/REORG.TODO/string/test-strcasecmp.c b/REORG.TODO/string/test-strcasecmp.c new file mode 100644 index 0000000000..9c333f0072 --- /dev/null +++ b/REORG.TODO/string/test-strcasecmp.c @@ -0,0 +1,270 @@ +/* Test and measure strcasecmp functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <locale.h> +#include <ctype.h> +#define TEST_MAIN +#define TEST_NAME "strcasecmp" +#include "test-string.h" + +typedef int (*proto_t) (const char *, const char *); +static int simple_strcasecmp (const char *, const char *); +static int stupid_strcasecmp (const char *, const char *); + +IMPL (stupid_strcasecmp, 0) +IMPL (simple_strcasecmp, 0) +IMPL (strcasecmp, 1) + +static int +simple_strcasecmp (const char *s1, const char *s2) +{ + int ret; + + while ((ret = ((unsigned char) tolower (*s1) + - (unsigned char) tolower (*s2))) == 0 + && *s1++) + ++s2; + return ret; +} + +static int +stupid_strcasecmp (const char *s1, const char *s2) +{ + size_t ns1 = strlen (s1) + 1, ns2 = strlen (s2) + 1; + size_t n = ns1 < ns2 ? ns1 : ns2; + int ret = 0; + + while (n--) + { + if ((ret = ((unsigned char) tolower (*s1) + - (unsigned char) tolower (*s2))) != 0) + break; + ++s1; + ++s2; + } + return ret; +} + +static void +do_one_test (impl_t *impl, const char *s1, const char *s2, int exp_result) +{ + int result = CALL (impl, s1, s2); + if ((exp_result == 0 && result != 0) + || (exp_result < 0 && result >= 0) + || (exp_result > 0 && result <= 0)) + { + error (0, 0, "Wrong result in function %s %d %d", impl->name, + result, exp_result); + ret = 1; + return; + } +} + +static void +do_test (size_t align1, size_t align2, size_t len, int max_char, + int exp_result) +{ + size_t i; + char *s1, *s2; + + if (len == 0) + return; + + align1 &= 7; + if (align1 + len + 1 >= page_size) + return; + + align2 &= 7; + if (align2 + len + 1 >= page_size) + return; + + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); + + for (i = 0; i < len; i++) + { + s1[i] = toupper (1 + 23 * i % max_char); + s2[i] = tolower (s1[i]); + } + + s1[len] = s2[len] = 0; + s1[len + 1] = 23; + s2[len + 1] = 24 + exp_result; + if ((s2[len - 1] == 'z' && exp_result == -1) + || (s2[len - 1] == 'a' && exp_result == 1)) + s1[len - 1] += exp_result; + else + s2[len - 1] -= exp_result; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, exp_result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, pos, len1, len2; + int result; + long r; + unsigned char *p1 = buf1 + page_size - 512; + unsigned char *p2 = buf2 + page_size - 512; + + for (n = 0; n < ITERATIONS; n++) + { + align1 = random () & 31; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + pos = random () & 511; + j = align1 > align2 ? align1 : align2; + if (pos + j >= 511) + pos = 510 - j - (random () & 7); + len1 = random () & 511; + if (pos >= len1 && (random () & 1)) + len1 = pos + (random () & 7); + if (len1 + j >= 512) + len1 = 511 - j - (random () & 7); + if (pos >= len1) + len2 = len1; + else + len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0); + j = (pos > len2 ? pos : len2) + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; ++i) + { + p1[i] = tolower (random () & 255); + if (i < len1 + align1 && !p1[i]) + { + p1[i] = tolower (random () & 255); + if (!p1[i]) + p1[i] = tolower (1 + (random () & 127)); + } + } + for (i = 0; i < j; ++i) + { + p2[i] = toupper (random () & 255); + if (i < len2 + align2 && !p2[i]) + { + p2[i] = toupper (random () & 255); + if (!p2[i]) + toupper (p2[i] = 1 + (random () & 127)); + } + } + + result = 0; + memcpy (p2 + align2, p1 + align1, pos); + if (pos < len1) + { + if (tolower (p2[align2 + pos]) == p1[align1 + pos]) + { + p2[align2 + pos] = toupper (random () & 255); + if (tolower (p2[align2 + pos]) == p1[align1 + pos]) + p2[align2 + pos] = toupper (p1[align1 + pos] + + 3 + (random () & 127)); + } + + if (p1[align1 + pos] < tolower (p2[align2 + pos])) + result = -1; + else + result = 1; + } + p1[len1 + align1] = 0; + p2[len2 + align2] = 0; + + FOR_EACH_IMPL (impl, 1) + { + 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)); + if ((r == 0 && result) + || (r < 0 && result >= 0) + || (r > 0 && result <= 0)) + { + error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p", + n, impl->name, align1, align2, len1, len2, pos, r, result, p1, p2); + ret = 1; + } + } + } +} + +static void +test_locale (const char *locale) +{ + size_t i; + + if (setlocale (LC_CTYPE, locale) == NULL) + { + error (0, 0, "cannot set locale \"%s\"", locale); + ret = 1; + } + + printf ("%-23s", locale); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 16; ++i) + { + do_test (i, i, i, 127, 0); + do_test (i, i, i, 127, 1); + do_test (i, i, i, 127, -1); + } + + for (i = 1; i < 10; ++i) + { + do_test (0, 0, 2 << i, 127, 0); + do_test (0, 0, 2 << i, 254, 0); + do_test (0, 0, 2 << i, 127, 1); + do_test (0, 0, 2 << i, 254, 1); + do_test (0, 0, 2 << i, 127, -1); + do_test (0, 0, 2 << i, 254, -1); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, 8 << i, 127, 0); + do_test (2 * i, i, 8 << i, 254, 0); + do_test (i, 2 * i, 8 << i, 127, 1); + do_test (2 * i, i, 8 << i, 254, 1); + do_test (i, 2 * i, 8 << i, 127, -1); + do_test (2 * i, i, 8 << i, 254, -1); + } + + do_random_tests (); +} + +int +test_main (void) +{ + test_init (); + + test_locale ("C"); + test_locale ("en_US.ISO-8859-1"); + test_locale ("en_US.UTF-8"); + test_locale ("tr_TR.ISO-8859-9"); + test_locale ("tr_TR.UTF-8"); + + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strcasestr.c b/REORG.TODO/string/test-strcasestr.c new file mode 100644 index 0000000000..abb3916732 --- /dev/null +++ b/REORG.TODO/string/test-strcasestr.c @@ -0,0 +1,194 @@ +/* Test and measure strcasestr functions. + Copyright (C) 2010-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Ulrich Drepper <drepper@redhat.com>, 2010. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#define TEST_NAME "strcasestr" +#include "test-string.h" + + +#define STRCASESTR simple_strcasestr +#define NO_ALIAS +#define __strncasecmp strncasecmp +#include "strcasestr.c" + + +static char * +stupid_strcasestr (const char *s1, const char *s2) +{ + ssize_t s1len = strlen (s1); + ssize_t s2len = strlen (s2); + + if (s2len > s1len) + return NULL; + + for (ssize_t i = 0; i <= s1len - s2len; ++i) + { + size_t j; + for (j = 0; j < s2len; ++j) + if (tolower (s1[i + j]) != tolower (s2[j])) + break; + if (j == s2len) + return (char *) s1 + i; + } + + return NULL; +} + + +typedef char *(*proto_t) (const char *, const char *); + +IMPL (stupid_strcasestr, 0) +IMPL (simple_strcasestr, 0) +IMPL (strcasestr, 1) + + +static int +check_result (impl_t *impl, const char *s1, const char *s2, + char *exp_result) +{ + char *result = CALL (impl, s1, s2); + if (result != exp_result) + { + error (0, 0, "Wrong result in function %s %s %s", impl->name, + result, exp_result); + ret = 1; + return -1; + } + return 0; +} + +static void +do_one_test (impl_t *impl, const char *s1, const char *s2, char *exp_result) +{ + if (check_result (impl, s1, s2, exp_result) < 0) + return; +} + + +static void +do_test (size_t align1, size_t align2, size_t len1, size_t len2, + int fail) +{ + char *s1 = (char *) (buf1 + align1); + char *s2 = (char *) (buf2 + align2); + + static const char d[] = "1234567890abcxyz"; +#define dl (sizeof (d) - 1) + char *ss2 = s2; + for (size_t l = len2; l > 0; l = l > dl ? l - dl : 0) + { + size_t t = l > dl ? dl : l; + ss2 = mempcpy (ss2, d, t); + } + s2[len2] = '\0'; + + if (fail) + { + char *ss1 = s1; + for (size_t l = len1; l > 0; l = l > dl ? l - dl : 0) + { + size_t t = l > dl ? dl : l; + memcpy (ss1, d, t); + ++ss1[len2 > 7 ? 7 : len2 - 1]; + ss1 += t; + } + } + else + { + memset (s1, '0', len1); + for (size_t i = 0; i < len2; ++i) + s1[len1 - len2 + i] = toupper (s2[i]); + } + s1[len1] = '\0'; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, fail ? NULL : s1 + len1 - len2); +} + +static void +check1 (void) +{ + const char s1[] = "AOKB"; + const char s2[] = "OK"; + char *exp_result; + + exp_result = stupid_strcasestr (s1, s2); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1, s2, exp_result); +} + +static int +test_main (void) +{ + test_init (); + + check1 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (size_t klen = 2; klen < 32; ++klen) + for (size_t hlen = 2 * klen; hlen < 16 * klen; hlen += klen) + { + do_test (0, 0, hlen, klen, 0); + do_test (0, 0, hlen, klen, 1); + do_test (0, 3, hlen, klen, 0); + do_test (0, 3, hlen, klen, 1); + do_test (0, 9, hlen, klen, 0); + do_test (0, 9, hlen, klen, 1); + do_test (0, 15, hlen, klen, 0); + do_test (0, 15, hlen, klen, 1); + + do_test (3, 0, hlen, klen, 0); + do_test (3, 0, hlen, klen, 1); + do_test (3, 3, hlen, klen, 0); + do_test (3, 3, hlen, klen, 1); + do_test (3, 9, hlen, klen, 0); + do_test (3, 9, hlen, klen, 1); + do_test (3, 15, hlen, klen, 0); + do_test (3, 15, hlen, klen, 1); + + do_test (9, 0, hlen, klen, 0); + do_test (9, 0, hlen, klen, 1); + do_test (9, 3, hlen, klen, 0); + do_test (9, 3, hlen, klen, 1); + do_test (9, 9, hlen, klen, 0); + do_test (9, 9, hlen, klen, 1); + do_test (9, 15, hlen, klen, 0); + do_test (9, 15, hlen, klen, 1); + + do_test (15, 0, hlen, klen, 0); + do_test (15, 0, hlen, klen, 1); + do_test (15, 3, hlen, klen, 0); + do_test (15, 3, hlen, klen, 1); + do_test (15, 9, hlen, klen, 0); + do_test (15, 9, hlen, klen, 1); + do_test (15, 15, hlen, klen, 0); + do_test (15, 15, hlen, klen, 1); + } + + do_test (0, 0, page_size - 1, 16, 0); + do_test (0, 0, page_size - 1, 16, 1); + + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strcat.c b/REORG.TODO/string/test-strcat.c new file mode 100644 index 0000000000..01d180eb50 --- /dev/null +++ b/REORG.TODO/string/test-strcat.c @@ -0,0 +1,272 @@ +/* Test strcat functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "strcat" +#else +# define TEST_NAME "wcscat" +#endif /* WIDE */ +#include "test-string.h" + +#ifndef WIDE +# define STRCAT strcat +# define CHAR char +# define UCHAR unsigned char +# define sfmt "s" +# define SIMPLE_STRCAT simple_strcat +# define STRLEN strlen +# define STRCMP strcmp +# define MEMSET memset +# define MEMCPY memcpy +# define MEMCMP memcmp +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +#else +# include <wchar.h> +# define STRCAT wcscat +# define CHAR wchar_t +# define UCHAR wchar_t +# define sfmt "ls" +# define SIMPLE_STRCAT simple_wcscat +# define STRLEN wcslen +# define STRCMP wcscmp +# define MEMSET wmemset +# define MEMCPY wmemcpy +# define MEMCMP wmemcmp +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +#endif /* WIDE */ + +typedef CHAR *(*proto_t) (CHAR *, const CHAR *); +CHAR *SIMPLE_STRCAT (CHAR *, const CHAR *); + +IMPL (SIMPLE_STRCAT, 0) +IMPL (STRCAT, 1) + +CHAR * +SIMPLE_STRCAT (CHAR *dst, const CHAR *src) +{ + CHAR *ret = dst; + while (*dst++ != '\0'); + --dst; + while ((*dst++ = *src++) != '\0'); + return ret; +} + +static void +do_one_test (impl_t *impl, CHAR *dst, const CHAR *src) +{ + size_t k = STRLEN (dst); + if (CALL (impl, dst, src) != dst) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + CALL (impl, dst, src), dst); + ret = 1; + return; + } + + if (STRCMP (dst + k, src) != 0) + { + error (0, 0, "Wrong result in function %s dst \"%" sfmt "\" src \"%" sfmt "\"", + impl->name, dst, src); + ret = 1; + return; + } +} + +static void +do_test (size_t align1, size_t align2, size_t len1, size_t len2, int max_char) +{ + size_t i; + CHAR *s1, *s2; + + align1 &= 7; + if ((align1 + len1) * sizeof (CHAR) >= page_size) + return; + + align2 &= 7; + if ((align2 + len1 + len2) * sizeof (CHAR) >= page_size) + return; + + s1 = (CHAR *) (buf1) + align1; + s2 = (CHAR *) (buf2) + align2; + + for (i = 0; i < len1; ++i) + s1[i] = 32 + 23 * i % (max_char - 32); + s1[len1] = '\0'; + + for (i = 0; i < len2; i++) + s2[i] = 32 + 23 * i % (max_char - 32); + + FOR_EACH_IMPL (impl, 0) + { + s2[len2] = '\0'; + do_one_test (impl, s2, s1); + } +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, len1, len2; + UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512; + UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512; + UCHAR *p3 = (UCHAR *) buf1; + UCHAR *res; + + for (n = 0; n < ITERATIONS; n++) + { + align1 = random () & 31; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + len1 = random () & 511; + if (len1 + align2 > 512) + len2 = random () & 7; + else + len2 = (512 - len1 - align2) * (random () & (1024 * 1024 - 1)) + / (1024 * 1024); + j = align1; + if (align2 + len2 > j) + j = align2 + len2; + if (len1 + j >= 511) + len1 = 510 - j - (random () & 7); + if (len1 >= 512) + len1 = 0; + if (align1 + len1 < 512 - 8) + { + j = 510 - align1 - len1 - (random () & 31); + if (j > 0 && j < 512) + align1 += j; + } + j = len1 + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; i++) + { + if (i == len1 + align1) + p1[i] = 0; + else + { + p1[i] = random () & BIG_CHAR; + if (i >= align1 && i < len1 + align1 && !p1[i]) + p1[i] = (random () & SMALL_CHAR) + 3; + } + } + for (i = 0; i < len2; i++) + { + p3[i] = random () & BIG_CHAR; + if (!p3[i]) + p3[i] = (random () & SMALL_CHAR) + 3; + } + p3[len2] = 0; + + FOR_EACH_IMPL (impl, 1) + { + MEMSET (p2 - 64, '\1', align2 + 64); + MEMSET (p2 + align2 + len2 + 1, '\1', 512 - align2 - len2 - 1); + MEMCPY (p2 + align2, p3, len2 + 1); + res = (UCHAR *) 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", + n, impl->name, align1, align2, len1, len2, res, + p2 + align2); + ret = 1; + } + for (j = 0; j < align2 + 64; ++j) + { + if (p2[j - 64] != '\1') + { + error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2); + ret = 1; + break; + } + } + if (MEMCMP (p2 + align2, p3, len2)) + { + error (0, 0, "Iteration %zd - garbage in string before, %s (%zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2); + ret = 1; + } + for (j = align2 + len1 + len2 + 1; j < 512; ++j) + { + if (p2[j] != '\1') + { + error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2); + ret = 1; + break; + } + } + if (MEMCMP (p1 + align1, p2 + align2 + len2, len1 + 1)) + { + error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2); + ret = 1; + } + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%28s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < 16; ++i) + { + do_test (0, 0, i, i, SMALL_CHAR); + do_test (0, 0, i, i, BIG_CHAR); + do_test (0, i, i, i, SMALL_CHAR); + do_test (i, 0, i, i, BIG_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 8 << i, 8 << i, SMALL_CHAR); + do_test (8 - i, 2 * i, 8 << i, 8 << i, SMALL_CHAR); + do_test (0, 0, 8 << i, 2 << i, SMALL_CHAR); + do_test (8 - i, 2 * i, 8 << i, 2 << i, SMALL_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, 8 << i, 1, SMALL_CHAR); + do_test (2 * i, i, 8 << i, 1, BIG_CHAR); + do_test (i, i, 8 << i, 10, SMALL_CHAR); + do_test (i, i, 8 << i, 10, BIG_CHAR); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strchr.c b/REORG.TODO/string/test-strchr.c new file mode 100644 index 0000000000..de9a274f7b --- /dev/null +++ b/REORG.TODO/string/test-strchr.c @@ -0,0 +1,296 @@ +/* Test STRCHR functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + Added wcschr support by Liubov Dmitrieva <liubov.dmitrieva@gmail.com>, 2011 + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifndef WIDE +# ifdef USE_FOR_STRCHRNUL +# define TEST_NAME "strchrnul" +# else +# define TEST_NAME "strchr" +# endif /* !USE_FOR_STRCHRNUL */ +#else +# ifdef USE_FOR_STRCHRNUL +# define TEST_NAME "wcschrnul" +# else +# define TEST_NAME "wcschr" +# endif /* !USE_FOR_STRCHRNUL */ +#endif /* WIDE */ +#include "test-string.h" + +#ifndef WIDE +# ifdef USE_FOR_STRCHRNUL +# define STRCHR strchrnul +# define stupid_STRCHR stupid_STRCHRNUL +# define simple_STRCHR simple_STRCHRNUL +# else +# define STRCHR strchr +# endif /* !USE_FOR_STRCHRNUL */ +# define STRLEN strlen +# define CHAR char +# define BIG_CHAR CHAR_MAX +# define MIDDLE_CHAR 127 +# define SMALL_CHAR 23 +# define UCHAR unsigned char +# define L(s) s +#else +# include <wchar.h> +# ifdef USE_FOR_STRCHRNUL +# define STRCHR wcschrnul +# define stupid_STRCHR stupid_WCSCHRNUL +# define simple_STRCHR simple_WCSCHRNUL +# else +# define STRCHR wcschr +# endif /* !USE_FOR_STRCHRNUL */ +# define STRLEN wcslen +# define CHAR wchar_t +# define BIG_CHAR WCHAR_MAX +# define MIDDLE_CHAR 1121 +# define SMALL_CHAR 851 +# define UCHAR wchar_t +# define L(s) L ## s +#endif /* WIDE */ + +#ifdef USE_FOR_STRCHRNUL +# define NULLRET(endptr) endptr +#else +# define NULLRET(endptr) NULL +#endif /* !USE_FOR_STRCHRNUL */ + + +typedef CHAR *(*proto_t) (const CHAR *, int); + +CHAR * +simple_STRCHR (const CHAR *s, int c) +{ + for (; *s != (CHAR) c; ++s) + if (*s == '\0') + return NULLRET ((CHAR *) s); + return (CHAR *) s; +} + +CHAR * +stupid_STRCHR (const CHAR *s, int c) +{ + size_t n = STRLEN (s) + 1; + + while (n--) + if (*s++ == (CHAR) c) + return (CHAR *) s - 1; + return NULLRET ((CHAR *) s - 1); +} + +IMPL (stupid_STRCHR, 0) +IMPL (simple_STRCHR, 0) +IMPL (STRCHR, 1) + +static int +check_result (impl_t *impl, const CHAR *s, int c, const CHAR *exp_res) +{ + CHAR *res = CALL (impl, s, c); + if (res != exp_res) + { + error (0, 0, "Wrong result in function %s %#x %p %p", impl->name, + c, res, exp_res); + ret = 1; + return -1; + } + return 0; +} + +static void +do_one_test (impl_t *impl, const CHAR *s, int c, const CHAR *exp_res) +{ + if (check_result (impl, s, c, exp_res) < 0) + return; +} + +static void +do_test (size_t align, size_t pos, size_t len, int seek_char, int max_char) +/* For wcschr: align here means align not in bytes, + but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)) + len for wcschr here isn't in bytes but it's number of wchar_t symbols. */ +{ + size_t i; + CHAR *result; + CHAR *buf = (CHAR *) buf1; + align &= 15; + if ((align + len) * sizeof (CHAR) >= page_size) + return; + + for (i = 0; i < len; ++i) + { + buf[align + i] = 32 + 23 * i % max_char; + if (buf[align + i] == seek_char) + buf[align + i] = seek_char + 1; + else if (buf[align + i] == 0) + buf[align + i] = 1; + } + buf[align + len] = 0; + + if (pos < len) + { + buf[align + pos] = seek_char; + result = buf + align + pos; + } + else if (seek_char == 0) + result = buf + align + len; + else + result = NULLRET (buf + align + len); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, buf + align, seek_char, result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, pos, len; + int seek_char; + CHAR *result; + UCHAR *p = (UCHAR *) (buf1 + page_size - 512 * sizeof (CHAR)); + + for (n = 0; n < ITERATIONS; n++) + { + /* For wcschr: align here means align not in bytes, but in wchar_ts, + in bytes it will equal to align * (sizeof (wchar_t)). */ + align = random () & 15; + pos = random () & 511; + seek_char = random () & 255; + if (pos + align >= 511) + pos = 510 - align - (random () & 7); + /* len for wcschr here isn't in bytes but it's number of wchar_t + symbols. */ + len = random () & 511; + if ((pos == len && seek_char) + || (pos > len && (random () & 1))) + len = pos + 1 + (random () & 7); + if (len + align >= 512) + len = 511 - align - (random () & 7); + if (pos == len && seek_char) + len = pos + 1; + j = (pos > len ? pos : len) + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == pos + align) + p[i] = seek_char; + else if (i == len + align) + p[i] = 0; + else + { + p[i] = random () & 255; + if (i < pos + align && p[i] == seek_char) + p[i] = seek_char + 13; + if (i < len + align && !p[i]) + { + p[i] = seek_char - 13; + if (!p[i]) + p[i] = 140; + } + } + } + + if (pos <= len) + result = (CHAR *) (p + pos + align); + else if (seek_char == 0) + result = (CHAR *) (p + len + align); + else + result = NULLRET ((CHAR *) (p + len + align)); + + FOR_EACH_IMPL (impl, 1) + if (CALL (impl, (CHAR *) (p + align), seek_char) != result) + { + error (0, 0, "Iteration %zd - wrong result in function \ + %s (align in bytes: %zd, seek_char: %d, len: %zd, pos: %zd) %p != %p, p %p", + n, impl->name, align * sizeof (CHAR), seek_char, len, pos, + CALL (impl, (CHAR *) (p + align), seek_char), result, p); + ret = 1; + } + } +} + +static void +check1 (void) +{ + CHAR s[] __attribute__((aligned(16))) = L ("\xff"); + CHAR c = L ('\xfe'); + CHAR *exp_result = stupid_STRCHR (s, c); + + FOR_EACH_IMPL (impl, 0) + check_result (impl, s, c, exp_result); +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + check1 (); + + printf ("%20s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 8; ++i) + { + do_test (0, 16 << i, 2048, SMALL_CHAR, MIDDLE_CHAR); + do_test (i, 16 << i, 2048, SMALL_CHAR, MIDDLE_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 64, 256, SMALL_CHAR, MIDDLE_CHAR); + do_test (i, 64, 256, SMALL_CHAR, BIG_CHAR); + } + + for (i = 0; i < 32; ++i) + { + do_test (0, i, i + 1, SMALL_CHAR, MIDDLE_CHAR); + do_test (0, i, i + 1, SMALL_CHAR, BIG_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 16 << i, 2048, 0, MIDDLE_CHAR); + do_test (i, 16 << i, 2048, 0, MIDDLE_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 64, 256, 0, MIDDLE_CHAR); + do_test (i, 64, 256, 0, BIG_CHAR); + } + + for (i = 0; i < 32; ++i) + { + do_test (0, i, i + 1, 0, MIDDLE_CHAR); + do_test (0, i, i + 1, 0, BIG_CHAR); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strchrnul.c b/REORG.TODO/string/test-strchrnul.c new file mode 100644 index 0000000000..b8f79b1897 --- /dev/null +++ b/REORG.TODO/string/test-strchrnul.c @@ -0,0 +1,21 @@ +/* Test and measure strchrnul function. + + Copyright (C) 2011-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define USE_FOR_STRCHRNUL 1 +#include "test-strchr.c" diff --git a/REORG.TODO/string/test-strcmp.c b/REORG.TODO/string/test-strcmp.c new file mode 100644 index 0000000000..f7af219149 --- /dev/null +++ b/REORG.TODO/string/test-strcmp.c @@ -0,0 +1,409 @@ +/* Test and measure strcmp and wcscmp functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + Added wcscmp support by Liubov Dmitrieva <liubov.dmitrieva@gmail.com>, 2011. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifdef WIDE +# define TEST_NAME "wcscmp" +#else +# define TEST_NAME "strcmp" +#endif +#include "test-string.h" + +#ifdef WIDE +# include <wchar.h> + +# define L(str) L##str +# define STRCMP wcscmp +# define STRCPY wcscpy +# define STRLEN wcslen +# define MEMCPY wmemcpy +# define SIMPLE_STRCMP simple_wcscmp +# define STUPID_STRCMP stupid_wcscmp +# define CHAR wchar_t +# define UCHAR wchar_t +# define CHARBYTES 4 +# define CHARBYTESLOG 2 +# define CHARALIGN __alignof__ (CHAR) +# define MIDCHAR 0x7fffffff +# define LARGECHAR 0xfffffffe +# define CHAR__MAX WCHAR_MAX +# define CHAR__MIN WCHAR_MIN + +/* Wcscmp uses signed semantics for comparison, not unsigned */ +/* Avoid using substraction since possible overflow */ + +int +simple_wcscmp (const wchar_t *s1, const wchar_t *s2) +{ + wchar_t c1, c2; + do + { + c1 = *s1++; + c2 = *s2++; + if (c2 == L'\0') + return c1 - c2; + } + while (c1 == c2); + + return c1 < c2 ? -1 : 1; +} + +int +stupid_wcscmp (const wchar_t *s1, const wchar_t *s2) +{ + size_t ns1 = wcslen (s1) + 1; + size_t ns2 = wcslen (s2) + 1; + size_t n = ns1 < ns2 ? ns1 : ns2; + int ret = 0; + + wchar_t c1, c2; + + while (n--) { + c1 = *s1++; + c2 = *s2++; + if ((ret = c1 < c2 ? -1 : c1 == c2 ? 0 : 1) != 0) + break; + } + return ret; +} + +#else +# include <limits.h> + +# define L(str) str +# define STRCMP strcmp +# define STRCPY strcpy +# define STRLEN strlen +# define MEMCPY memcpy +# define SIMPLE_STRCMP simple_strcmp +# define STUPID_STRCMP stupid_strcmp +# define CHAR char +# define UCHAR unsigned char +# define CHARBYTES 1 +# define CHARBYTESLOG 0 +# define CHARALIGN 1 +# define MIDCHAR 0x7f +# define LARGECHAR 0xfe +# define CHAR__MAX CHAR_MAX +# define CHAR__MIN CHAR_MIN + +/* Strcmp uses unsigned semantics for comparison. */ +int +simple_strcmp (const char *s1, const char *s2) +{ + int ret; + + while ((ret = *(unsigned char *) s1 - *(unsigned char*) s2++) == 0 && *s1++); + return ret; +} + +int +stupid_strcmp (const char *s1, const char *s2) +{ + size_t ns1 = strlen (s1) + 1; + size_t ns2 = strlen (s2) + 1; + size_t n = ns1 < ns2 ? ns1 : ns2; + int ret = 0; + + while (n--) + if ((ret = *(unsigned char *) s1++ - *(unsigned char *) s2++) != 0) + break; + return ret; +} +#endif + +typedef int (*proto_t) (const CHAR *, const CHAR *); + +IMPL (STUPID_STRCMP, 1) +IMPL (SIMPLE_STRCMP, 1) +IMPL (STRCMP, 1) + +static int +check_result (impl_t *impl, + const CHAR *s1, const CHAR *s2, + int exp_result) +{ + int result = CALL (impl, s1, s2); + if ((exp_result == 0 && result != 0) + || (exp_result < 0 && result >= 0) + || (exp_result > 0 && result <= 0)) + { + error (0, 0, "Wrong result in function %s %d %d", impl->name, + result, exp_result); + ret = 1; + return -1; + } + + return 0; +} + +static void +do_one_test (impl_t *impl, + const CHAR *s1, const CHAR *s2, + int exp_result) +{ + if (check_result (impl, s1, s2, exp_result) < 0) + return; +} + +static void +do_test (size_t align1, size_t align2, size_t len, int max_char, + int exp_result) +{ + size_t i; + + CHAR *s1, *s2; + + if (len == 0) + return; + + align1 &= 63; + if (align1 + (len + 1) * CHARBYTES >= page_size) + return; + + align2 &= 63; + if (align2 + (len + 1) * CHARBYTES >= page_size) + return; + + /* Put them close to the end of page. */ + i = align1 + CHARBYTES * (len + 2); + s1 = (CHAR *) (buf1 + ((page_size - i) / 16 * 16) + align1); + i = align2 + CHARBYTES * (len + 2); + s2 = (CHAR *) (buf2 + ((page_size - i) / 16 * 16) + align2); + + for (i = 0; i < len; i++) + s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % max_char; + + s1[len] = s2[len] = 0; + s1[len + 1] = 23; + s2[len + 1] = 24 + exp_result; + s2[len - 1] -= exp_result; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, exp_result); +} + +static void +do_random_tests (void) +{ + UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES); + UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES); + + for (size_t n = 0; n < ITERATIONS; n++) + { + /* for wcscmp case align1 and align2 mean here alignment + in wchar_t symbols, it equal 4*k alignment in bytes, we + don't check other alignments like for example + p1 = (wchar_t *)(buf1 + 1) + because it's wrong using of wchar_t type. */ + size_t align1 = random () & 31; + size_t align2; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + size_t pos = random () & 511; + size_t j = align1 > align2 ? align1 : align2; + if (pos + j >= 511) + pos = 510 - j - (random () & 7); + size_t len1 = random () & 511; + if (pos >= len1 && (random () & 1)) + len1 = pos + (random () & 7); + if (len1 + j >= 512) + len1 = 511 - j - (random () & 7); + size_t len2; + if (pos >= len1) + len2 = len1; + else + len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0); + j = (pos > len2 ? pos : len2) + align1 + 64; + if (j > 512) + j = 512; + for (size_t i = 0; i < j; ++i) + { + p1[i] = random () & 255; + if (i < len1 + align1 && !p1[i]) + { + p1[i] = random () & 255; + if (!p1[i]) + p1[i] = 1 + (random () & 127); + } + } + for (size_t i = 0; i < j; ++i) + { + p2[i] = random () & 255; + if (i < len2 + align2 && !p2[i]) + { + p2[i] = random () & 255; + if (!p2[i]) + p2[i] = 1 + (random () & 127); + } + } + + int result = 0; + MEMCPY (p2 + align2, p1 + align1, pos); + if (pos < len1) + { + if (p2[align2 + pos] == p1[align1 + pos]) + { + p2[align2 + pos] = random () & 255; + if (p2[align2 + pos] == p1[align1 + pos]) + p2[align2 + pos] = p1[align1 + pos] + 3 + (random () & 127); + } + + if (p1[align1 + pos] < p2[align2 + pos]) + result = -1; + else + result = 1; + } + p1[len1 + align1] = 0; + p2[len2 + align2] = 0; + + FOR_EACH_IMPL (impl, 1) + { + int 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)); + if ((r == 0 && result) + || (r < 0 && result >= 0) + || (r > 0 && result <= 0)) + { + error (0, 0, "Iteration %zd - wrong result in function %s (align in bytes: %zd, align in bytes: %zd, len1: %zd, len2: %zd, pos: %zd) %d != %d, p1 %p p2 %p", + n, impl->name, (size_t) (p1 + align1) & 63, (size_t) (p1 + align2) & 63, len1, len2, pos, r, result, p1, p2); + ret = 1; + } + } + } +} + +static void +check (void) +{ + CHAR *s1 = (CHAR *) (buf1 + 0xb2c); + CHAR *s2 = (CHAR *) (buf1 + 0xfd8); + + STRCPY(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs")); + STRCPY(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV")); + + /* Check correct working for negatives values */ + + s1[0] = 1; + s2[0] = 1; + s1[1] = 1; + s2[1] = 1; + s1[2] = -1; + s2[2] = 3; + s1[3] = 0; + s2[3] = -1; + + /* Check possible overflow bug, actual more for wcscmp */ + + s1[7] = CHAR__MIN; + s2[7] = CHAR__MAX; + + size_t l1 = STRLEN (s1); + size_t l2 = STRLEN (s2); + + for (size_t i1 = 0; i1 < l1; i1++) + for (size_t i2 = 0; i2 < l2; i2++) + { + int exp_result = SIMPLE_STRCMP (s1 + i1, s2 + i2); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1 + i1, s2 + i2, exp_result); + } + + /* Test cases where there are multiple zero bytes after the first. */ + + for (size_t i = 0; i < 16 + 1; i++) + { + s1[i] = 0x00; + s2[i] = 0x00; + } + + for (size_t i = 0; i < 16; i++) + { + int exp_result; + + for (int val = 0x01; val < 0x100; val++) + { + for (size_t j = 0; j < i; j++) + { + s1[j] = val; + s2[j] = val; + } + + s2[i] = val; + + exp_result = SIMPLE_STRCMP (s1, s2); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1, s2, exp_result); + } + } +} + + +int +test_main (void) +{ + size_t i; + + test_init (); + check(); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 32; ++i) + { + do_test (CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, 0); + do_test (CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, 1); + do_test (CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, -1); + } + + for (i = 1; i < 10 + CHARBYTESLOG; ++i) + { + do_test (0, 0, 2 << i, MIDCHAR, 0); + do_test (0, 0, 2 << i, LARGECHAR, 0); + do_test (0, 0, 2 << i, MIDCHAR, 1); + do_test (0, 0, 2 << i, LARGECHAR, 1); + do_test (0, 0, 2 << i, MIDCHAR, -1); + do_test (0, 0, 2 << i, LARGECHAR, -1); + do_test (0, CHARBYTES * i, 2 << i, MIDCHAR, 1); + do_test (CHARBYTES * i, CHARBYTES * (i + 1), 2 << i, LARGECHAR, 1); + } + + for (i = 1; i < 8; ++i) + { + do_test (CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, 0); + do_test (2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, 0); + do_test (CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, 1); + do_test (2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, 1); + do_test (CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, -1); + do_test (2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, -1); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strcpy.c b/REORG.TODO/string/test-strcpy.c new file mode 100644 index 0000000000..d4de65a590 --- /dev/null +++ b/REORG.TODO/string/test-strcpy.c @@ -0,0 +1,245 @@ +/* Test and measure strcpy functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + Added wcscpy support by Liubov Dmitrieva <liubov.dmitrieva@gmail.com>, 2011 + + 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef WIDE +# include <wchar.h> +# define CHAR wchar_t +# define UCHAR wchar_t +# define sfmt "ls" +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +# define STRCMP wcscmp +# define MEMCMP wmemcmp +# define MEMSET wmemset +#else +# define CHAR char +# define UCHAR unsigned char +# define sfmt "s" +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +# define STRCMP strcmp +# define MEMCMP memcmp +# define MEMSET memset +#endif + +#ifndef STRCPY_RESULT +# define STRCPY_RESULT(dst, len) dst +# define TEST_MAIN +# ifndef WIDE +# define TEST_NAME "strcpy" +# else +# define TEST_NAME "wcscpy" +# endif +# include "test-string.h" +# ifndef WIDE +# define SIMPLE_STRCPY simple_strcpy +# define STRCPY strcpy +# else +# define SIMPLE_STRCPY simple_wcscpy +# define STRCPY wcscpy +# endif + +CHAR *SIMPLE_STRCPY (CHAR *, const CHAR *); + +IMPL (SIMPLE_STRCPY, 0) +IMPL (STRCPY, 1) + +CHAR * +SIMPLE_STRCPY (CHAR *dst, const CHAR *src) +{ + CHAR *ret = dst; + while ((*dst++ = *src++) != '\0'); + return ret; +} +#endif + +typedef CHAR *(*proto_t) (CHAR *, const CHAR *); + +static void +do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, + size_t len __attribute__((unused))) +{ + if (CALL (impl, dst, src) != STRCPY_RESULT (dst, len)) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + CALL (impl, dst, src), STRCPY_RESULT (dst, len)); + ret = 1; + return; + } + + if (STRCMP (dst, src) != 0) + { + error (0, 0, + "Wrong result in function %s dst \"%" sfmt "\" src \"%" sfmt "\"", + impl->name, dst, src); + ret = 1; + return; + } +} + +static void +do_test (size_t align1, size_t align2, size_t len, int max_char) +{ + size_t i; + CHAR *s1, *s2; +/* For wcscpy: align1 and align2 here mean alignment not in bytes, + but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)) + len for wcschr here isn't in bytes but it's number of wchar_t symbols. */ + align1 &= 7; + if ((align1 + len) * sizeof(CHAR) >= page_size) + return; + + align2 &= 7; + if ((align2 + len) * sizeof(CHAR) >= page_size) + return; + + s1 = (CHAR *) (buf1) + align1; + s2 = (CHAR *) (buf2) + align2; + + for (i = 0; i < len; i++) + s1[i] = 32 + 23 * i % (max_char - 32); + s1[len] = 0; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s2, s1, len); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, len; + UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512; + UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512; + UCHAR *res; + + for (n = 0; n < ITERATIONS; n++) + { + /* For wcsrchr: align1 and align2 here mean align not in bytes, + but in wchar_ts, in bytes it will equal to align * (sizeof + (wchar_t)). For strrchr we need to check all alignments from + 0 to 63 since some assembly implementations have separate + prolog for alignments more 48. */ + + align1 = random () & (63 / sizeof(CHAR)); + if (random () & 1) + align2 = random () & (63 / sizeof(CHAR)); + else + align2 = align1 + (random () & 24); + len = random () & 511; + j = align1; + if (align2 > j) + j = align2; + if (len + j >= 511) + len = 510 - j - (random () & 7); + j = len + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; i++) + { + if (i == len + align1) + p1[i] = 0; + else + { + p1[i] = random () & BIG_CHAR; + if (i >= align1 && i < len + align1 && !p1[i]) + p1[i] = (random () & SMALL_CHAR) + 3; + } + } + + FOR_EACH_IMPL (impl, 1) + { + MEMSET (p2 - 64, '\1', 512 + 64); + res = (UCHAR *) 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", + n, impl->name, align1, align2, len, res, + STRCPY_RESULT (p2 + align2, len)); + ret = 1; + } + for (j = 0; j < align2 + 64; ++j) + { + if (p2[j - 64] != '\1') + { + error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + for (j = align2 + len + 1; j < 512; ++j) + { + if (p2[j] != '\1') + { + error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + if (MEMCMP (p1 + align1, p2 + align2, len + 1)) + { + error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + } + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < 16; ++i) + { + do_test (0, 0, i, SMALL_CHAR); + do_test (0, 0, i, BIG_CHAR); + do_test (0, i, i, SMALL_CHAR); + do_test (i, 0, i, BIG_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 8 << i, SMALL_CHAR); + do_test (8 - i, 2 * i, 8 << i, SMALL_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, 8 << i, SMALL_CHAR); + do_test (2 * i, i, 8 << i, BIG_CHAR); + do_test (i, i, 8 << i, SMALL_CHAR); + do_test (i, i, 8 << i, BIG_CHAR); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strcspn.c b/REORG.TODO/string/test-strcspn.c new file mode 100644 index 0000000000..d83c1347d1 --- /dev/null +++ b/REORG.TODO/string/test-strcspn.c @@ -0,0 +1,81 @@ +/* Test strcspn functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define STRPBRK_RESULT(s, pos) (pos) +#define RES_TYPE size_t +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "strcspn" +#else +# define TEST_NAME "wcscspn" +#endif /* WIDE */ +#include "test-string.h" + +#ifndef WIDE +# define STRCSPN strcspn +# define CHAR char +# define SIMPLE_STRCSPN simple_strcspn +# define STUPID_STRCSPN stupid_strcspn +# define STRLEN strlen +#else +# include <wchar.h> +# define STRCSPN wcscspn +# define CHAR wchar_t +# define SIMPLE_STRCSPN simple_wcscspn +# define STUPID_STRCSPN stupid_wcscspn +# define STRLEN wcslen +#endif /* WIDE */ + +typedef size_t (*proto_t) (const CHAR *, const CHAR *); +size_t SIMPLE_STRCSPN (const CHAR *, const CHAR *); +size_t STUPID_STRCSPN (const CHAR *, const CHAR *); + +IMPL (STUPID_STRCSPN, 0) +IMPL (SIMPLE_STRCSPN, 0) +IMPL (STRCSPN, 1) + +size_t +SIMPLE_STRCSPN (const CHAR *s, const CHAR *rej) +{ + const CHAR *r, *str = s; + CHAR c; + + while ((c = *s++) != '\0') + for (r = rej; *r != '\0'; ++r) + if (*r == c) + return s - str - 1; + return s - str - 1; +} + +size_t +STUPID_STRCSPN (const CHAR *s, const CHAR *rej) +{ + size_t ns = STRLEN (s), nrej = STRLEN (rej); + size_t i, j; + + for (i = 0; i < ns; ++i) + for (j = 0; j < nrej; ++j) + if (s[i] == rej[j]) + return i; + return i; +} + +#undef CHAR +#undef STRLEN +#include "test-strpbrk.c" diff --git a/REORG.TODO/string/test-string.h b/REORG.TODO/string/test-string.h new file mode 100644 index 0000000000..6e13bf4aa3 --- /dev/null +++ b/REORG.TODO/string/test-string.h @@ -0,0 +1,219 @@ +/* Test and measure string and memory functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/cdefs.h> + +typedef struct +{ + const char *name; + void (*fn) (void); + long test; +} impl_t; +extern impl_t __start_impls[], __stop_impls[]; + +#define IMPL(name, test) \ + impl_t tst_ ## name \ + __attribute__ ((section ("impls"), aligned (sizeof (void *)))) \ + = { __STRING (name), (void (*) (void))name, test }; + +#ifdef TEST_MAIN + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#undef __USE_STRING_INLINES + +/* We are compiled under _ISOMAC, so libc-symbols.h does not do this + for us. */ +#include "config.h" +#ifdef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL +# define inhibit_loop_to_libcall \ + __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns"))) +#else +# define inhibit_loop_to_libcall +#endif + +#include <getopt.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <unistd.h> +#include <fcntl.h> +#include <error.h> +#include <errno.h> +#include <time.h> +#include <ifunc-impl-list.h> +#define GL(x) _##x +#define GLRO(x) _##x + + +# define TEST_FUNCTION test_main +# define TIMEOUT (4 * 60) +# define OPT_ITERATIONS 10000 +# define OPT_RANDOM 10001 +# define OPT_SEED 10002 + +unsigned char *buf1, *buf2; +int ret, do_srandom; +unsigned int seed; +size_t page_size; + +# ifndef ITERATIONS +size_t iterations = 100000; +# define ITERATIONS_OPTIONS \ + { "iterations", required_argument, NULL, OPT_ITERATIONS }, +# define ITERATIONS_PROCESS \ + case OPT_ITERATIONS: \ + iterations = strtoul (optarg, NULL, 0); \ + break; +# define ITERATIONS iterations +# else +# define ITERATIONS_OPTIONS +# define ITERATIONS_PROCESS +# endif + +# define CMDLINE_OPTIONS ITERATIONS_OPTIONS \ + { "random", no_argument, NULL, OPT_RANDOM }, \ + { "seed", required_argument, NULL, OPT_SEED }, + +static void __attribute__ ((used)) +cmdline_process_function (int c) +{ + switch (c) + { + ITERATIONS_PROCESS + case OPT_RANDOM: + { + int fdr = open ("/dev/urandom", O_RDONLY); + if (fdr < 0 || read (fdr, &seed, sizeof (seed)) != sizeof (seed)) + seed = time (NULL); + if (fdr >= 0) + close (fdr); + do_srandom = 1; + break; + } + + case OPT_SEED: + seed = strtoul (optarg, NULL, 0); + do_srandom = 1; + break; + } +} +# define CMDLINE_PROCESS cmdline_process_function + +#define CALL(impl, ...) \ + (* (proto_t) (impl)->fn) (__VA_ARGS__) + +#ifdef TEST_NAME +/* Increase size of FUNC_LIST if assert is triggered at run-time. */ +static struct libc_ifunc_impl func_list[32]; +static int func_count; +static int impl_count = -1; +static impl_t *impl_array; + +# define FOR_EACH_IMPL(impl, notall) \ + impl_t *impl; \ + int count; \ + if (impl_count == -1) \ + { \ + impl_count = 0; \ + if (func_count != 0) \ + { \ + int f; \ + impl_t *skip = NULL, *a; \ + for (impl = __start_impls; impl < __stop_impls; ++impl) \ + if (strcmp (impl->name, TEST_NAME) == 0) \ + skip = impl; \ + else \ + impl_count++; \ + a = impl_array = malloc ((impl_count + func_count) * \ + sizeof (impl_t)); \ + for (impl = __start_impls; impl < __stop_impls; ++impl) \ + if (impl != skip) \ + *a++ = *impl; \ + for (f = 0; f < func_count; f++) \ + if (func_list[f].usable) \ + { \ + a->name = func_list[f].name; \ + a->fn = func_list[f].fn; \ + a->test = 1; \ + a++; \ + } \ + impl_count = a - impl_array; \ + } \ + else \ + { \ + impl_count = __stop_impls - __start_impls; \ + impl_array = __start_impls; \ + } \ + } \ + impl = impl_array; \ + for (count = 0; count < impl_count; ++count, ++impl) \ + if (!notall || impl->test) +#else +# define FOR_EACH_IMPL(impl, notall) \ + for (impl_t *impl = __start_impls; impl < __stop_impls; ++impl) \ + if (!notall || impl->test) +#endif + +#ifndef BUF1PAGES +# define BUF1PAGES 1 +#endif + +static void +test_init (void) +{ +#ifdef TEST_NAME + func_count = __libc_ifunc_impl_list (TEST_NAME, func_list, + (sizeof func_list + / sizeof func_list[0])); +#endif + + page_size = 2 * getpagesize (); +#ifdef MIN_PAGE_SIZE + if (page_size < MIN_PAGE_SIZE) + page_size = MIN_PAGE_SIZE; +#endif + buf1 = mmap (0, (BUF1PAGES + 1) * page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (buf1 == MAP_FAILED) + error (EXIT_FAILURE, errno, "mmap failed"); + if (mprotect (buf1 + BUF1PAGES * page_size, page_size, PROT_NONE)) + error (EXIT_FAILURE, errno, "mprotect failed"); + buf2 = mmap (0, 2 * page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (buf2 == MAP_FAILED) + error (EXIT_FAILURE, errno, "mmap failed"); + if (mprotect (buf2 + page_size, page_size, PROT_NONE)) + error (EXIT_FAILURE, errno, "mprotect failed"); + if (do_srandom) + { + printf ("Setting seed to 0x%x\n", seed); + srandom (seed); + } + + memset (buf1, 0xa5, BUF1PAGES * page_size); + memset (buf2, 0x5a, page_size); +} + +#endif diff --git a/REORG.TODO/string/test-strlen.c b/REORG.TODO/string/test-strlen.c new file mode 100644 index 0000000000..99be380e6e --- /dev/null +++ b/REORG.TODO/string/test-strlen.c @@ -0,0 +1,167 @@ +/* Test and measure STRLEN functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + Added wcslen support by Liubov Dmitrieva <liubov.dmitrieva@gmail.com>, 2011 + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "strlen" +#else +# define TEST_NAME "wcslen" +#endif +#include "test-string.h" + +#ifndef WIDE +# define STRLEN strlen +# define CHAR char +# define MAX_CHAR CHAR_MAX +#else +# include <wchar.h> +# define STRLEN wcslen +# define CHAR wchar_t +# define MAX_CHAR WCHAR_MAX +#endif + +typedef size_t (*proto_t) (const CHAR *); + +size_t +simple_STRLEN (const CHAR *s) +{ + const CHAR *p; + + for (p = s; *p; ++p); + return p - s; +} + +#ifndef WIDE +size_t +builtin_strlen (const CHAR *p) +{ + return __builtin_strlen (p); +} +IMPL (builtin_strlen, 0) +#endif + +IMPL (simple_STRLEN, 0) +IMPL (STRLEN, 1) + + +static void +do_one_test (impl_t *impl, const CHAR *s, size_t exp_len) +{ + size_t len = CALL (impl, s); + if (len != exp_len) + { + error (0, 0, "Wrong result in function %s %zd %zd", impl->name, + len, exp_len); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t len) +{ + size_t i; + + align &= 63; + if (align + sizeof(CHAR) * len >= page_size) + return; + + CHAR *buf = (CHAR *) (buf1); + + for (i = 0; i < len; ++i) + buf[align + i] = 1 + 11111 * i % MAX_CHAR; + buf[align + len] = 0; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, (CHAR *) (buf + align), len); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, len; + CHAR *p = (CHAR *) (buf1 + page_size - 512 * sizeof(CHAR)); + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & 15; + len = random () & 511; + if (len + align > 510) + len = 511 - align - (random () & 7); + j = len + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == len + align) + p[i] = 0; + else + { + p[i] = random () & 255; + if (i >= align && i < len + align && !p[i]) + p[i] = (random () & 127) + 1; + } + } + + FOR_EACH_IMPL (impl, 1) + 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, (CHAR *) (p + align)), + len, p); + ret = 1; + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%20s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + /* Checking with only 4 * N alignments for wcslen, other alignments are wrong for wchar_t type arrays*/ + + for (i = 1; i < 8; ++i) + { + do_test (sizeof(CHAR) * i, i); + do_test (0, i); + } + + for (i = 2; i <= 12; ++i) + { + do_test (0, 1 << i); + do_test (sizeof(CHAR) * 7, 1 << i); + do_test (sizeof(CHAR) * i, 1 << i); + do_test (sizeof(CHAR) * i, (size_t)((1 << i) / 1.5)); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strncasecmp.c b/REORG.TODO/string/test-strncasecmp.c new file mode 100644 index 0000000000..bf501cf798 --- /dev/null +++ b/REORG.TODO/string/test-strncasecmp.c @@ -0,0 +1,353 @@ +/* Test and measure strncasecmp functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <locale.h> +#include <ctype.h> +#define TEST_MAIN +#define TEST_NAME "strncasecmp" +#include "test-string.h" + +typedef int (*proto_t) (const char *, const char *, size_t); +static int simple_strncasecmp (const char *, const char *, size_t); +static int stupid_strncasecmp (const char *, const char *, size_t); + +IMPL (stupid_strncasecmp, 0) +IMPL (simple_strncasecmp, 0) +IMPL (strncasecmp, 1) + +static int +simple_strncasecmp (const char *s1, const char *s2, size_t n) +{ + int ret; + + if (n == 0) + return 0; + + while ((ret = ((unsigned char) tolower (*s1) + - (unsigned char) tolower (*s2))) == 0 + && *s1++) + { + if (--n == 0) + return 0; + ++s2; + } + return ret; +} + +static int +stupid_strncasecmp (const char *s1, const char *s2, size_t max) +{ + size_t ns1 = strlen (s1) + 1; + size_t ns2 = strlen (s2) + 1; + size_t n = ns1 < ns2 ? ns1 : ns2; + if (n > max) + n = max; + int ret = 0; + + while (n--) + { + if ((ret = ((unsigned char) tolower (*s1) + - (unsigned char) tolower (*s2))) != 0) + break; + ++s1; + ++s2; + } + return ret; +} + +static int +check_result (impl_t *impl, const char *s1, const char *s2, size_t n, + int exp_result) +{ + int result = CALL (impl, s1, s2, n); + if ((exp_result == 0 && result != 0) + || (exp_result < 0 && result >= 0) + || (exp_result > 0 && result <= 0)) + { + error (0, 0, "Wrong result in function %s %d %d", impl->name, + result, exp_result); + ret = 1; + return -1; + } + + return 0; +} + +static void +do_one_test (impl_t *impl, const char *s1, const char *s2, size_t n, + int exp_result) +{ + if (check_result (impl, s1, s2, n, exp_result) < 0) + return; +} + +static void +do_test (size_t align1, size_t align2, size_t n, size_t len, int max_char, + int exp_result) +{ + size_t i; + char *s1, *s2; + + if (len == 0) + return; + + align1 &= 7; + if (align1 + len + 1 >= page_size) + return; + + align2 &= 7; + if (align2 + len + 1 >= page_size) + return; + + s1 = (char *) (buf1 + align1); + s2 = (char *) (buf2 + align2); + + for (i = 0; i < len; i++) + { + s1[i] = toupper (1 + 23 * i % max_char); + s2[i] = tolower (s1[i]); + } + + s1[len] = s2[len] = 0; + s1[len + 1] = 23; + s2[len + 1] = 24 + exp_result; + if ((s2[len - 1] == 'z' && exp_result == -1) + || (s2[len - 1] == 'a' && exp_result == 1)) + s1[len - 1] += exp_result; + else + s2[len - 1] -= exp_result; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, n, exp_result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, pos, len1, len2; + int result; + long r; + unsigned char *p1 = buf1 + page_size - 512; + unsigned char *p2 = buf2 + page_size - 512; + + for (n = 0; n < ITERATIONS; n++) + { + align1 = random () & 31; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + pos = random () & 511; + j = align1 > align2 ? align1 : align2; + if (pos + j >= 511) + pos = 510 - j - (random () & 7); + len1 = random () & 511; + if (pos >= len1 && (random () & 1)) + len1 = pos + (random () & 7); + if (len1 + j >= 512) + len1 = 511 - j - (random () & 7); + if (pos >= len1) + len2 = len1; + else + len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0); + j = (pos > len2 ? pos : len2) + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; ++i) + { + p1[i] = tolower (random () & 255); + if (i < len1 + align1 && !p1[i]) + { + p1[i] = tolower (random () & 255); + if (!p1[i]) + p1[i] = tolower (1 + (random () & 127)); + } + } + for (i = 0; i < j; ++i) + { + p2[i] = toupper (random () & 255); + if (i < len2 + align2 && !p2[i]) + { + p2[i] = toupper (random () & 255); + if (!p2[i]) + toupper (p2[i] = 1 + (random () & 127)); + } + } + + result = 0; + memcpy (p2 + align2, p1 + align1, pos); + if (pos < len1) + { + if (tolower (p2[align2 + pos]) == p1[align1 + pos]) + { + p2[align2 + pos] = toupper (random () & 255); + if (tolower (p2[align2 + pos]) == p1[align1 + pos]) + p2[align2 + pos] = toupper (p1[align1 + pos] + + 3 + (random () & 127)); + } + + if (p1[align1 + pos] < tolower (p2[align2 + pos])) + result = -1; + else + result = 1; + } + p1[len1 + align1] = 0; + p2[len2 + align2] = 0; + + FOR_EACH_IMPL (impl, 1) + { + r = CALL (impl, (char *) (p1 + align1), (char *) (p2 + align2), + pos + 1 + (random () & 255)); + /* Test whether on 64-bit architectures where ABI requires + callee to promote has the promotion been done. */ + asm ("" : "=g" (r) : "0" (r)); + if ((r == 0 && result) + || (r < 0 && result >= 0) + || (r > 0 && result <= 0)) + { + error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p", + n, impl->name, align1, align2, len1, len2, pos, r, result, p1, p2); + ret = 1; + } + } + } +} + +/* Regression test for BZ #12205 */ +static void +bz12205 (void) +{ + static char cp [4096+16] __attribute__ ((aligned(4096))); + static char gotrel[4096] __attribute__ ((aligned(4096))); + char *s1 = cp + 0xffa; + char *s2 = gotrel + 0xcbe; + int exp_result; + size_t n = 6; + + strcpy (s1, "gottpoff"); + strcpy (s2, "GOTPLT"); + + exp_result = simple_strncasecmp (s1, s2, n); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1, s2, n, exp_result); +} + +/* Regression test for BZ #14195 */ +static void +bz14195 (void) +{ + const char *empty_string = ""; + FOR_EACH_IMPL (impl, 0) + check_result (impl, empty_string, "", 5, 0); +} + +static void +test_locale (const char *locale) +{ + size_t i; + + if (setlocale (LC_CTYPE, locale) == NULL) + { + error (0, 0, "cannot set locale \"%s\"", locale); + ret = 1; + } + + bz12205 (); + bz14195 (); + + printf ("%23s", locale); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 16; ++i) + { + do_test (i, i, i - 1, i, 127, 0); + + do_test (i, i, i, i, 127, 0); + do_test (i, i, i, i, 127, 1); + do_test (i, i, i, i, 127, -1); + + do_test (i, i, i + 1, i, 127, 0); + do_test (i, i, i + 1, i, 127, 1); + do_test (i, i, i + 1, i, 127, -1); + } + + for (i = 1; i < 10; ++i) + { + do_test (0, 0, (2 << i) - 1, 2 << i, 127, 0); + do_test (0, 0, 2 << i, 2 << i, 254, 0); + do_test (0, 0, (2 << i) + 1, 2 << i, 127, 0); + + do_test (0, 0, (2 << i) + 1, 2 << i, 254, 0); + + do_test (0, 0, 2 << i, 2 << i, 127, 1); + do_test (0, 0, (2 << i) + 10, 2 << i, 127, 1); + + do_test (0, 0, 2 << i, 2 << i, 254, 1); + do_test (0, 0, (2 << i) + 10, 2 << i, 254, 1); + + do_test (0, 0, 2 << i, 2 << i, 127, -1); + do_test (0, 0, (2 << i) + 10, 2 << i, 127, -1); + + do_test (0, 0, 2 << i, 2 << i, 254, -1); + do_test (0, 0, (2 << i) + 10, 2 << i, 254, -1); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, (8 << i) - 1, 8 << i, 127, 0); + do_test (i, 2 * i, 8 << i, 8 << i, 127, 0); + do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, 0); + + do_test (2 * i, i, (8 << i) - 1, 8 << i, 254, 0); + do_test (2 * i, i, 8 << i, 8 << i, 254, 0); + do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, 0); + + do_test (i, 2 * i, 8 << i, 8 << i, 127, 1); + do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, 1); + + do_test (2 * i, i, 8 << i, 8 << i, 254, 1); + do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, 1); + + do_test (i, 2 * i, 8 << i, 8 << i, 127, -1); + do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, -1); + + do_test (2 * i, i, 8 << i, 8 << i, 254, -1); + do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, -1); + } + + do_random_tests (); +} + +int +test_main (void) +{ + test_init (); + + test_locale ("C"); + test_locale ("en_US.ISO-8859-1"); + test_locale ("en_US.UTF-8"); + test_locale ("tr_TR.ISO-8859-9"); + test_locale ("tr_TR.UTF-8"); + + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strncat.c b/REORG.TODO/string/test-strncat.c new file mode 100644 index 0000000000..66d58e534d --- /dev/null +++ b/REORG.TODO/string/test-strncat.c @@ -0,0 +1,322 @@ +/* Test strncat functions. + Copyright (C) 2011-2017 Free Software Foundation, Inc. + Contributed by Intel Corporation. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "strncat" +#else +# define TEST_NAME "wcsncat" +#endif /* WIDE */ +#include "test-string.h" + +#ifndef WIDE +# define STRNCAT strncat +# define CHAR char +# define UCHAR unsigned char +# define SIMPLE_STRNCAT simple_strncat +# define STUPID_STRNCAT stupid_strncat +# define STRLEN strlen +# define MEMSET memset +# define MEMCPY memcpy +# define MEMCMP memcmp +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +#else +# include <wchar.h> +# define STRNCAT wcsncat +# define CHAR wchar_t +# define UCHAR wchar_t +# define SIMPLE_STRNCAT simple_wcsncat +# define STUPID_STRNCAT stupid_wcsncat +# define STRLEN wcslen +# define MEMSET wmemset +# define MEMCPY wmemcpy +# define MEMCMP wmemcmp +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +#endif /* WIDE */ + +typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t); +CHAR *STUPID_STRNCAT (CHAR *, const CHAR *, size_t); +CHAR *SIMPLE_STRNCAT (CHAR *, const CHAR *, size_t); + +IMPL (STUPID_STRNCAT, 0) +IMPL (STRNCAT, 2) + +CHAR * +STUPID_STRNCAT (CHAR *dst, const CHAR *src, size_t n) +{ + CHAR *ret = dst; + while (*dst++ != '\0'); + --dst; + while (n--) + if ((*dst++ = *src++) == '\0') + return ret; + *dst = '\0'; + return ret; +} + +static void +do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t n) +{ + size_t k = STRLEN (dst); + if (CALL (impl, dst, src, n) != dst) + { + error (0, 0, "Wrong result in function %s %p != %p", impl->name, + CALL (impl, dst, src, n), dst); + ret = 1; + return; + } + + size_t len = STRLEN (src); + if (MEMCMP (dst + k, src, len + 1 > n ? n : len + 1) != 0) + { + error (0, 0, "Incorrect concatenation in function %s", + impl->name); + ret = 1; + return; + } + if (n < len && dst[k + n] != '\0') + { + error (0, 0, "There is no zero in the end of output string in %s", + impl->name); + ret = 1; + return; + } +} + +static void +do_test (size_t align1, size_t align2, size_t len1, size_t len2, + size_t n, int max_char) +{ + size_t i; + CHAR *s1, *s2; + + align1 &= 7; + if ((align1 + len1) * sizeof (CHAR) >= page_size) + return; + if ((align1 + n) * sizeof (CHAR) > page_size) + return; + align2 &= 7; + if ((align2 + len1 + len2) * sizeof (CHAR) >= page_size) + return; + if ((align2 + len1 + n) * sizeof (CHAR) > page_size) + return; + s1 = (CHAR *) (buf1) + align1; + s2 = (CHAR *) (buf2) + align2; + + for (i = 0; i < len1; ++i) + s1[i] = 32 + 23 * i % (max_char - 32); + s1[len1] = '\0'; + + for (i = 0; i < len2; i++) + s2[i] = 32 + 23 * i % (max_char - 32); + + FOR_EACH_IMPL (impl, 0) + { + s2[len2] = '\0'; + do_one_test (impl, s2, s1, n); + } +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, len1, len2, N; + UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512; + UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512; + UCHAR *p3 = (UCHAR *) buf1; + UCHAR *res; + fprintf (stdout, "Number of iterations in random test = %zd\n", + ITERATIONS); + for (n = 0; n < ITERATIONS; n++) + { + N = random () & 255; + align1 = random () & 31; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + len1 = random () & 511; + if (len1 + align2 > 512) + len2 = random () & 7; + else + len2 = (512 - len1 - align2) * (random () & (1024 * 1024 - 1)) + / (1024 * 1024); + j = align1; + if (align2 + len2 > j) + j = align2 + len2; + if (len1 + j >= 511) + len1 = 510 - j - (random () & 7); + if (len1 >= 512) + len1 = 0; + if (align1 + len1 < 512 - 8) + { + j = 510 - align1 - len1 - (random () & 31); + if (j > 0 && j < 512) + align1 += j; + } + j = len1 + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; i++) + { + if (i == len1 + align1) + p1[i] = 0; + else + { + p1[i] = random () & BIG_CHAR; + if (i >= align1 && i < len1 + align1 && !p1[i]) + p1[i] = (random () & SMALL_CHAR) + 3; + } + } + for (i = 0; i < len2; i++) + { + p3[i] = random () & BIG_CHAR; + if (!p3[i]) + p3[i] = (random () & SMALL_CHAR) + 3; + } + p3[len2] = 0; + + FOR_EACH_IMPL (impl, 1) + { + MEMSET (p2 - 64, '\1', align2 + 64); + MEMSET (p2 + align2 + len2 + 1, '\1', 512 - align2 - len2 - 1); + MEMCPY (p2 + align2, p3, len2 + 1); + res = (UCHAR *) CALL (impl, (CHAR *) (p2 + align2), + (CHAR *) (p1 + align1), N); + if (res != p2 + align2) + { + error (0, 0, "Iteration %zd - wrong result in function %s " + "(%zd, %zd, %zd, %zd, %zd) %p != %p", + n, impl->name, align1, align2, len1, len2, N, + res, p2 + align2); + ret = 1; + } + for (j = 0; j < align2 + 64; ++j) + { + if (p2[j - 64] != '\1') + { + error (0, 0, "Iteration %zd - garbage before dst, %s " + "%zd, %zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2, N); + ret = 1; + break; + } + } + if (MEMCMP (p2 + align2, p3, len2)) + { + error (0, 0, "Iteration %zd - garbage in string before, %s " + "(%zd, %zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2, N); + ret = 1; + } + + if ((len1 + 1) > N) + j = align2 + N + 1 + len2; + else + j = align2 + len1 + 1 + len2; + for (; j < 512; ++j) + { + if (p2[j] != '\1') + { + error (0, 0, "Iteration %zd - garbage after, %s " + "(%zd, %zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2, N); + ret = 1; + break; + } + } + if (len1 + 1 > N) + { + if (p2[align2 + N + len2] != '\0') + { + error (0, 0, "Iteration %zd - there is no zero at the " + "end of output string, %s (%zd, %zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2, N); + ret = 1; + } + } + if (MEMCMP (p1 + align1, p2 + align2 + len2, + (len1 + 1) > N ? N : len1 + 1)) + { + error (0, 0, "Iteration %zd - different strings, %s " + "(%zd, %zd, %zd, %zd, %zd)", + n, impl->name, align1, align2, len1, len2, N); + ret = 1; + } + } + } +} + +int +test_main (void) +{ + size_t i, n; + + test_init (); + + printf ("%28s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (n = 2; n <= 2048; n*=4) + { + do_test (0, 2, 2, 2, n, SMALL_CHAR); + do_test (0, 0, 4, 4, n, SMALL_CHAR); + do_test (4, 0, 4, 4, n, BIG_CHAR); + do_test (0, 0, 8, 8, n, SMALL_CHAR); + do_test (0, 8, 8, 8, n, SMALL_CHAR); + + do_test (0, 2, 2, 2, SIZE_MAX, SMALL_CHAR); + do_test (0, 0, 4, 4, SIZE_MAX, SMALL_CHAR); + do_test (4, 0, 4, 4, SIZE_MAX, BIG_CHAR); + do_test (0, 0, 8, 8, SIZE_MAX, SMALL_CHAR); + do_test (0, 8, 8, 8, SIZE_MAX, SMALL_CHAR); + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 8 << i, 8 << i, n, SMALL_CHAR); + do_test (8 - i, 2 * i, 8 << i, 8 << i, n, SMALL_CHAR); + do_test (0, 0, 8 << i, 2 << i, n, SMALL_CHAR); + do_test (8 - i, 2 * i, 8 << i, 2 << i, n, SMALL_CHAR); + + do_test (0, 0, 8 << i, 8 << i, SIZE_MAX, SMALL_CHAR); + do_test (8 - i, 2 * i, 8 << i, 8 << i, SIZE_MAX, SMALL_CHAR); + do_test (0, 0, 8 << i, 2 << i, SIZE_MAX, SMALL_CHAR); + do_test (8 - i, 2 * i, 8 << i, 2 << i, SIZE_MAX, SMALL_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 2 * i, 8 << i, 1, n, SMALL_CHAR); + do_test (2 * i, i, 8 << i, 1, n, BIG_CHAR); + do_test (i, i, 8 << i, 10, n, SMALL_CHAR); + + do_test (i, 2 * i, 8 << i, 1, SIZE_MAX, SMALL_CHAR); + do_test (2 * i, i, 8 << i, 1, SIZE_MAX, BIG_CHAR); + do_test (i, i, 8 << i, 10, SIZE_MAX, SMALL_CHAR); + } + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strncmp.c b/REORG.TODO/string/test-strncmp.c new file mode 100644 index 0000000000..fe3c4e3320 --- /dev/null +++ b/REORG.TODO/string/test-strncmp.c @@ -0,0 +1,479 @@ +/* Test strncmp and wcsncmp functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifdef WIDE +# define TEST_NAME "wcsncmp" +#else +# define TEST_NAME "strncmp" +#endif +#include "test-string.h" + +#ifdef WIDE +# include <wchar.h> + +# define L(str) L##str +# define STRNCMP wcsncmp +# define STRCPY wcscpy +# define STRDUP wcsdup +# define MEMCPY wmemcpy +# define SIMPLE_STRNCMP simple_wcsncmp +# define STUPID_STRNCMP stupid_wcsncmp +# define CHAR wchar_t +# define UCHAR wchar_t +# define CHARBYTES 4 +# define CHAR__MAX WCHAR_MAX +# define CHAR__MIN WCHAR_MIN + +/* Wcsncmp uses signed semantics for comparison, not unsigned. + Avoid using substraction since possible overflow */ +int +simple_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n) +{ + wchar_t c1, c2; + + while (n--) + { + c1 = *s1++; + c2 = *s2++; + if (c1 == L('\0') || c1 != c2) + return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0); + } + return 0; +} + +int +stupid_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n) +{ + wchar_t c1, c2; + size_t ns1 = wcsnlen (s1, n) + 1, ns2 = wcsnlen (s2, n) + 1; + + n = ns1 < n ? ns1 : n; + n = ns2 < n ? ns2 : n; + + while (n--) + { + c1 = *s1++; + c2 = *s2++; + if (c1 != c2) + return c1 > c2 ? 1 : -1; + } + return 0; +} + +#else +# define L(str) str +# define STRNCMP strncmp +# define STRCPY strcpy +# define STRDUP strdup +# define MEMCPY memcpy +# define SIMPLE_STRNCMP simple_strncmp +# define STUPID_STRNCMP stupid_strncmp +# define CHAR char +# define UCHAR unsigned char +# define CHARBYTES 1 +# define CHAR__MAX CHAR_MAX +# define CHAR__MIN CHAR_MIN + +/* Strncmp uses unsigned semantics for comparison. */ +int +simple_strncmp (const char *s1, const char *s2, size_t n) +{ + int ret = 0; + + while (n-- && (ret = *(unsigned char *) s1 - * (unsigned char *) s2++) == 0 + && *s1++); + return ret; +} + +int +stupid_strncmp (const char *s1, const char *s2, size_t n) +{ + size_t ns1 = strnlen (s1, n) + 1, ns2 = strnlen (s2, n) + 1; + int ret = 0; + + n = ns1 < n ? ns1 : n; + n = ns2 < n ? ns2 : n; + while (n-- && (ret = *(unsigned char *) s1++ - * (unsigned char *) s2++) == 0); + return ret; +} + +#endif + +typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); + +IMPL (STUPID_STRNCMP, 0) +IMPL (SIMPLE_STRNCMP, 0) +IMPL (STRNCMP, 1) + + +static int +check_result (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n, + int exp_result) +{ + int result = CALL (impl, s1, s2, n); + if ((exp_result == 0 && result != 0) + || (exp_result < 0 && result >= 0) + || (exp_result > 0 && result <= 0)) + { + error (0, 0, "Wrong result in function %s %d %d", impl->name, + result, exp_result); + ret = 1; + return -1; + } + + return 0; +} + +static void +do_one_test (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n, + int exp_result) +{ + if (check_result (impl, s1, s2, n, exp_result) < 0) + return; +} + +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; + + align1 &= ~(CHARBYTES - 1); + align2 &= ~(CHARBYTES - 1); + + if (n == 0) + { + s1 = (CHAR *) (buf1 + page_size); + s2 = (CHAR *) (buf2 + page_size); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, n, 0); + + return; + } + + align1 &= 15; + align2 &= 15; + align_n = (page_size - n * CHARBYTES) & 15; + + s1 = (CHAR *) (buf1 + page_size - n * CHARBYTES); + s2 = (CHAR *) (buf2 + page_size - n * CHARBYTES); + + if (align1 < align_n) + s1 = (CHAR *) ((char *) s1 - (align_n - align1)); + + if (align2 < align_n) + s2 = (CHAR *) ((char *) 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; + } + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, n, exp_result); +} + +static void +do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char, + int exp_result) +{ + size_t i; + CHAR *s1, *s2; + + align1 &= ~(CHARBYTES - 1); + align2 &= ~(CHARBYTES - 1); + + if (n == 0) + return; + + align1 &= 63; + if (align1 + (n + 1) * CHARBYTES >= page_size) + return; + + align2 &= 63; + if (align2 + (n + 1) * CHARBYTES >= page_size) + return; + + s1 = (CHAR *) (buf1 + align1); + s2 = (CHAR *) (buf2 + align2); + + for (i = 0; i < n; i++) + s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % max_char; + + s1[n] = 24 + exp_result; + s2[n] = 23; + s1[len] = 0; + s2[len] = 0; + if (exp_result < 0) + s2[len] = 32; + else if (exp_result > 0) + s1[len] = 64; + if (len >= n) + s2[n - 1] -= exp_result; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, n, exp_result); +} + +static void +do_page_test (size_t offset1, size_t offset2, CHAR *s2) +{ + CHAR *s1; + int exp_result; + + if (offset1 * CHARBYTES >= page_size || offset2 * CHARBYTES >= page_size) + return; + + s1 = (CHAR *) buf1; + s1 += offset1; + s2 += offset2; + + exp_result= *s1; + + FOR_EACH_IMPL (impl, 0) + { + check_result (impl, s1, s2, page_size, -exp_result); + check_result (impl, s2, s1, page_size, exp_result); + } +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, pos, len1, len2, size; + int result; + long r; + UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES); + UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES); + + for (n = 0; n < ITERATIONS; n++) + { + align1 = random () & 31; + if (random () & 1) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + pos = random () & 511; + size = random () & 511; + j = align1 > align2 ? align1 : align2; + if (pos + j >= 511) + pos = 510 - j - (random () & 7); + len1 = random () & 511; + if (pos >= len1 && (random () & 1)) + len1 = pos + (random () & 7); + if (len1 + j >= 512) + len1 = 511 - j - (random () & 7); + if (pos >= len1) + len2 = len1; + else + len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0); + j = (pos > len2 ? pos : len2) + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; ++i) + { + p1[i] = random () & 255; + if (i < len1 + align1 && !p1[i]) + { + p1[i] = random () & 255; + if (!p1[i]) + p1[i] = 1 + (random () & 127); + } + } + for (i = 0; i < j; ++i) + { + p2[i] = random () & 255; + if (i < len2 + align2 && !p2[i]) + { + p2[i] = random () & 255; + if (!p2[i]) + p2[i] = 1 + (random () & 127); + } + } + + result = 0; + MEMCPY (p2 + align2, p1 + align1, pos); + if (pos < len1) + { + if (p2[align2 + pos] == p1[align1 + pos]) + { + p2[align2 + pos] = random () & 255; + if (p2[align2 + pos] == p1[align1 + pos]) + p2[align2 + pos] = p1[align1 + pos] + 3 + (random () & 127); + } + + if (pos < size) + { + if (p1[align1 + pos] < p2[align2 + pos]) + result = -1; + else + result = 1; + } + } + p1[len1 + align1] = 0; + p2[len2 + align2] = 0; + + FOR_EACH_IMPL (impl, 1) + { + 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)); + if ((r == 0 && result) + || (r < 0 && result >= 0) + || (r > 0 && result <= 0)) + { + error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p", + n, impl->name, align1, align2, len1, len2, pos, size, r, result, p1, p2); + ret = 1; + } + } + } +} + +static void +check1 (void) +{ + CHAR *s1 = (CHAR *) (buf1 + 0xb2c); + CHAR *s2 = (CHAR *) (buf1 + 0xfd8); + size_t i, offset; + int exp_result; + + STRCPY(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs")); + STRCPY(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV")); + + /* Check possible overflow bug for wcsncmp */ + s1[4] = CHAR__MAX; + s2[4] = CHAR__MIN; + + for (offset = 0; offset < 6; offset++) + { + for (i = 0; i < 80; i++) + { + exp_result = SIMPLE_STRNCMP (s1 + offset, s2 + offset, i); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1 + offset, s2 + offset, i, exp_result); + } + } +} + +static void +check2 (void) +{ + size_t i; + CHAR *s1, *s2; + + s1 = (CHAR *) buf1; + for (i = 0; i < (page_size / CHARBYTES) - 1; i++) + s1[i] = 23; + s1[i] = 0; + + s2 = STRDUP (s1); + + for (i = 0; i < 64; ++i) + do_page_test ((3988 / CHARBYTES) + i, (2636 / CHARBYTES), s2); + + free (s2); +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + check1 (); + check2 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i =0; i < 16; ++i) + { + do_test (0, 0, 8, i, 127, 0); + do_test (0, 0, 8, i, 127, -1); + do_test (0, 0, 8, i, 127, 1); + do_test (i, i, 8, i, 127, 0); + do_test (i, i, 8, i, 127, 1); + do_test (i, i, 8, i, 127, -1); + do_test (i, 2 * i, 8, i, 127, 0); + do_test (2 * i, i, 8, i, 127, 1); + do_test (i, 3 * i, 8, i, 127, -1); + do_test (0, 0, 8, i, 255, 0); + do_test (0, 0, 8, i, 255, -1); + do_test (0, 0, 8, i, 255, 1); + do_test (i, i, 8, i, 255, 0); + do_test (i, i, 8, i, 255, 1); + do_test (i, i, 8, i, 255, -1); + do_test (i, 2 * i, 8, i, 255, 0); + do_test (2 * i, i, 8, i, 255, 1); + do_test (i, 3 * i, 8, i, 255, -1); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 8 << i, 16 << i, 127, 0); + do_test (0, 0, 8 << i, 16 << i, 127, 1); + do_test (0, 0, 8 << i, 16 << i, 127, -1); + do_test (0, 0, 8 << i, 16 << i, 255, 0); + do_test (0, 0, 8 << i, 16 << i, 255, 1); + do_test (0, 0, 8 << i, 16 << i, 255, -1); + do_test (8 - i, 2 * i, 8 << i, 16 << i, 127, 0); + do_test (8 - i, 2 * i, 8 << i, 16 << i, 127, 1); + 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; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strncpy.c b/REORG.TODO/string/test-strncpy.c new file mode 100644 index 0000000000..43f9c236f1 --- /dev/null +++ b/REORG.TODO/string/test-strncpy.c @@ -0,0 +1,323 @@ +/* Test strncpy functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#ifdef WIDE +# include <wchar.h> +# define CHAR wchar_t +# define UCHAR wchar_t +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +# define MEMCMP wmemcmp +# define MEMSET wmemset +# define STRNLEN wcsnlen +#else +# define CHAR char +# define UCHAR unsigned char +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +# define MEMCMP memcmp +# define MEMSET memset +# define STRNLEN strnlen +#endif /* !WIDE */ + + +#ifndef STRNCPY_RESULT +# define STRNCPY_RESULT(dst, len, n) dst +# define TEST_MAIN +# ifndef WIDE +# define TEST_NAME "strncpy" +# else +# define TEST_NAME "wcsncpy" +# endif /* WIDE */ +# include "test-string.h" +# ifndef WIDE +# define SIMPLE_STRNCPY simple_strncpy +# define STUPID_STRNCPY stupid_strncpy +# define STRNCPY strncpy +# else +# define SIMPLE_STRNCPY simple_wcsncpy +# define STUPID_STRNCPY stupid_wcsncpy +# define STRNCPY wcsncpy +# endif /* WIDE */ + +CHAR *SIMPLE_STRNCPY (CHAR *, const CHAR *, size_t); +CHAR *STUPID_STRNCPY (CHAR *, const CHAR *, size_t); + +IMPL (STUPID_STRNCPY, 0) +IMPL (SIMPLE_STRNCPY, 0) +IMPL (STRNCPY, 1) + +CHAR * +SIMPLE_STRNCPY (CHAR *dst, const CHAR *src, size_t n) +{ + CHAR *ret = dst; + while (n--) + if ((*dst++ = *src++) == '\0') + { + while (n--) + *dst++ = '\0'; + return ret; + } + return ret; +} + +CHAR * +STUPID_STRNCPY (CHAR *dst, const CHAR *src, size_t n) +{ + size_t nc = STRNLEN (src, n); + size_t i; + + for (i = 0; i < nc; ++i) + dst[i] = src[i]; + for (; i < n; ++i) + dst[i] = '\0'; + return dst; +} +#endif /* !STRNCPY_RESULT */ + +typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t); + +static void +do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t len, size_t n) +{ + if (CALL (impl, dst, src, n) != STRNCPY_RESULT (dst, len, n)) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + CALL (impl, dst, src, n), dst); + ret = 1; + return; + } + + if (memcmp (dst, src, (len > n ? n : len) * sizeof (CHAR)) != 0) + { + error (0, 0, "Wrong result in function %s", impl->name); + ret = 1; + return; + } + + if (n > len) + { + size_t i; + + for (i = len; i < n; ++i) + if (dst [i] != '\0') + { + error (0, 0, "Wrong result in function %s", impl->name); + ret = 1; + return; + } + } +} + +static void +do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char) +{ + size_t i; + CHAR *s1, *s2; + +/* For wcsncpy: align1 and align2 here mean alignment not in bytes, + but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)). */ + align1 &= 7; + if ((align1 + len) * sizeof (CHAR) >= page_size) + return; + + align2 &= 7; + if ((align2 + len) * sizeof (CHAR) >= page_size) + return; + + s1 = (CHAR *) (buf1) + align1; + s2 = (CHAR *) (buf2) + align2; + + for (i = 0; i < len; ++i) + s1[i] = 32 + 23 * i % (max_char - 32); + s1[len] = 0; + for (i = len + 1; (i + align1) * sizeof (CHAR) < page_size && i < len + 64; + ++i) + s1[i] = 32 + 32 * i % (max_char - 32); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s2, s1, len, n); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align1, align2, len, size, mode; + UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512; + UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512; + UCHAR *res; + + for (n = 0; n < ITERATIONS; n++) + { + /* For wcsncpy: align1 and align2 here mean align not in bytes, + but in wchar_ts, in bytes it will equal to align * (sizeof + (wchar_t)). */ + + mode = random (); + if (mode & 1) + { + size = random () & 255; + align1 = 512 - size - (random () & 15); + if (mode & 2) + align2 = align1 - (random () & 24); + else + align2 = align1 - (random () & 31); + if (mode & 4) + { + j = align1; + align1 = align2; + align2 = j; + } + if (mode & 8) + len = size - (random () & 31); + else + len = 512; + if (len >= 512) + len = random () & 511; + } + else + { + align1 = random () & 31; + if (mode & 2) + align2 = random () & 31; + else + align2 = align1 + (random () & 24); + len = random () & 511; + j = align1; + if (align2 > j) + j = align2; + if (mode & 4) + { + size = random () & 511; + if (size + j > 512) + size = 512 - j - (random () & 31); + } + else + size = 512 - j; + if ((mode & 8) && len + j >= 512) + len = 512 - j - (random () & 7); + } + j = len + align1 + 64; + if (j > 512) + j = 512; + for (i = 0; i < j; i++) + { + if (i == len + align1) + p1[i] = 0; + else + { + p1[i] = random () & BIG_CHAR; + if (i >= align1 && i < len + align1 && !p1[i]) + p1[i] = (random () & SMALL_CHAR) + 3; + } + } + + FOR_EACH_IMPL (impl, 1) + { + MEMSET (p2 - 64, '\1', 512 + 64); + res = (UCHAR *) 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", + n, impl->name, align1, align2, len, res, + STRNCPY_RESULT (p2 + align2, len, size)); + ret = 1; + } + for (j = 0; j < align2 + 64; ++j) + { + if (p2[j - 64] != '\1') + { + error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + j = align2 + len + 1; + if (size + align2 > j) + j = size + align2; + for (; j < 512; ++j) + { + if (p2[j] != '\1') + { + error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + } + for (j = align2 + len + 1; j < align2 + size; ++j) + if (p2[j]) + { + error (0, 0, "Iteration %zd - garbage after size, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + break; + } + j = len + 1; + if (size < j) + j = size; + if (MEMCMP (p1 + align1, p2 + align2, j)) + { + error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)", + n, impl->name, align1, align2, len); + ret = 1; + } + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%28s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 8; ++i) + { + do_test (i, i, 16, 16, SMALL_CHAR); + do_test (i, i, 16, 16, BIG_CHAR); + do_test (i, 2 * i, 16, 16, SMALL_CHAR); + do_test (2 * i, i, 16, 16, BIG_CHAR); + do_test (8 - i, 2 * i, 1 << i, 2 << i, SMALL_CHAR); + do_test (2 * i, 8 - i, 2 << i, 1 << i, SMALL_CHAR); + do_test (8 - i, 2 * i, 1 << i, 2 << i, BIG_CHAR); + do_test (2 * i, 8 - i, 2 << i, 1 << i, BIG_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 0, 4 << i, 8 << i, SMALL_CHAR); + do_test (0, 0, 16 << i, 8 << i, SMALL_CHAR); + do_test (8 - i, 2 * i, 4 << i, 8 << i, SMALL_CHAR); + do_test (8 - i, 2 * i, 16 << i, 8 << i, SMALL_CHAR); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strnlen.c b/REORG.TODO/string/test-strnlen.c new file mode 100644 index 0000000000..e56cdb6708 --- /dev/null +++ b/REORG.TODO/string/test-strnlen.c @@ -0,0 +1,248 @@ +/* Test strlen functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "strnlen" +#else +# define TEST_NAME "wcsnlen" +#endif /* !WIDE */ +#include "test-string.h" + +#ifndef WIDE +# define STRNLEN strnlen +# define CHAR char +# define BIG_CHAR CHAR_MAX +# define MIDDLE_CHAR 127 +# define SIMPLE_STRNLEN simple_strnlen +#else +# include <wchar.h> +# define STRNLEN wcsnlen +# define CHAR wchar_t +# define BIG_CHAR WCHAR_MAX +# define MIDDLE_CHAR 1121 +# define SIMPLE_STRNLEN simple_wcsnlen +#endif /* !WIDE */ + +typedef size_t (*proto_t) (const CHAR *, size_t); +size_t SIMPLE_STRNLEN (const CHAR *, size_t); + +IMPL (SIMPLE_STRNLEN, 0) +IMPL (STRNLEN, 1) + +size_t +SIMPLE_STRNLEN (const CHAR *s, size_t maxlen) +{ + size_t i; + + for (i = 0; i < maxlen && s[i]; ++i); + return i; +} + +static void +do_one_test (impl_t *impl, const CHAR *s, size_t maxlen, size_t exp_len) +{ + size_t len = CALL (impl, s, maxlen); + if (len != exp_len) + { + error (0, 0, "Wrong result in function %s %zd %zd", impl->name, + len, exp_len); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t len, size_t maxlen, int max_char) +{ + size_t i; + + align &= 63; + if ((align + len) * sizeof (CHAR) >= page_size) + return; + + CHAR *buf = (CHAR *) (buf1); + + for (i = 0; i < len; ++i) + buf[align + i] = 1 + 11111 * i % max_char; + buf[align + len] = 0; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, (CHAR *) (buf + align), maxlen, MIN (len, maxlen)); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, len; + CHAR *p = (CHAR *) (buf1 + page_size - 512 * sizeof (CHAR)); + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & 15; + len = random () & 511; + if (len + align > 510) + len = 511 - align - (random () & 7); + j = len + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == len + align) + p[i] = 0; + else + { + p[i] = random () & 255; + if (i >= align && i < len + align && !p[i]) + p[i] = (random () & 127) + 1; + } + } + + FOR_EACH_IMPL (impl, 1) + { + if (len > 0 + && CALL (impl, (CHAR *) (p + align), len - 1) != len - 1) + { + error (0, 0, "Iteration %zd (limited) - wrong result in function %s (%zd) %zd != %zd, p %p", + n, impl->name, align, + CALL (impl, (CHAR *) (p + align), len - 1), len - 1, p); + ret = 1; + } + if (CALL (impl, (CHAR *) (p + align), len) != len) + { + error (0, 0, "Iteration %zd (exact) - wrong result in function %s (%zd) %zd != %zd, p %p", + n, impl->name, align, + CALL (impl, (CHAR *) (p + align), len), len, p); + ret = 1; + } + if (CALL (impl, (CHAR *) (p + align), len + 1) != len) + { + error (0, 0, "Iteration %zd (long) - wrong result in function %s (%zd) %zd != %zd, p %p", + n, impl->name, align, + CALL (impl, (CHAR *) (p + align), len + 1), len, p); + ret = 1; + } + } + } +} + +/* Tests meant to unveil fail on implementation that does not access bytes + around the page boundary accordingly. */ +static void +do_page_tests (void) +{ + size_t i, exp_len, start_offset, offset; + /* Calculate the null character offset. */ + size_t last_offset = (page_size / sizeof (CHAR)) - 1; + + CHAR *s = (CHAR *) buf2; + memset (s, 65, (last_offset - 1)); + s[last_offset] = 0; + + /* Place short strings ending at page boundary. */ + offset = last_offset; + for (i = 0; i < 128; i++) + { + /* Decrease offset to stress several sizes and alignments. */ + offset--; + exp_len = last_offset - offset; + FOR_EACH_IMPL (impl, 0) + { + /* Varies maxlen value to cover the cases where it is: + - larger than length; + - slightly greater than length; + - equal to length; + - slightly less than length. */ + do_one_test (impl, (CHAR *) (s + offset), page_size, exp_len); + do_one_test (impl, (CHAR *) (s + offset), exp_len + 1, exp_len); + do_one_test (impl, (CHAR *) (s + offset), exp_len, exp_len); + if (exp_len > 0) + do_one_test (impl, (CHAR *) (s + offset), exp_len - 1, exp_len - 1); + } + } + + /* Place long strings ending at page boundary. */ + start_offset = (last_offset + 1) / 2; + for (i = 0; i < 64; ++i) + { + /* Increase offset to stress several alignments. */ + offset = start_offset + i; + if (offset >= (last_offset + 1)) + break; + exp_len = last_offset - offset; + FOR_EACH_IMPL (impl, 0) + { + /* Checks only for maxlen much larger than length because smaller + values are already covered in do_random_tests function. */ + do_one_test (impl, (CHAR *) (s + offset), page_size, exp_len); + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%20s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 8; ++i) + { + do_test (0, i, i - 1, MIDDLE_CHAR); + do_test (0, i, i, MIDDLE_CHAR); + do_test (0, i, i + 1, MIDDLE_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, i, i - 1, MIDDLE_CHAR); + do_test (i, i, i, MIDDLE_CHAR); + do_test (i, i, i + 1, MIDDLE_CHAR); + } + + for (i = 2; i <= 10; ++i) + { + do_test (0, 1 << i, 5000, MIDDLE_CHAR); + do_test (1, 1 << i, 5000, MIDDLE_CHAR); + } + + for (i = 1; i < 8; ++i) + do_test (0, i, 5000, BIG_CHAR); + + for (i = 1; i < 8; ++i) + do_test (i, i, 5000, BIG_CHAR); + + for (i = 2; i <= 10; ++i) + { + do_test (0, 1 << i, 5000, BIG_CHAR); + do_test (1, 1 << i, 5000, BIG_CHAR); + } + + do_random_tests (); + do_page_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strpbrk.c b/REORG.TODO/string/test-strpbrk.c new file mode 100644 index 0000000000..4d680ab354 --- /dev/null +++ b/REORG.TODO/string/test-strpbrk.c @@ -0,0 +1,267 @@ +/* Test and measure strpbrk functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef WIDE +# define CHAR char +# define UCHAR unsigned char +# define STRLEN strlen +# define STRCHR strchr +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +#else +# include <wchar.h> +# define CHAR wchar_t +# define UCHAR wchar_t +# define STRLEN wcslen +# define STRCHR wcschr +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +#endif /* WIDE */ + +#ifndef STRPBRK_RESULT +# define STRPBRK_RESULT(s, pos) ((s)[(pos)] ? (s) + (pos) : NULL) +# define RES_TYPE CHAR * +# define TEST_MAIN +# ifndef WIDE +# define TEST_NAME "strpbrk" +# else +# define TEST_NAME "wcspbrk" +# endif /* WIDE */ +# include "test-string.h" + +# ifndef WIDE +# define STRPBRK strpbrk +# define SIMPLE_STRPBRK simple_strpbrk +# define STUPID_STRPBRK stupid_strpbrk +# else +# include <wchar.h> +# define STRPBRK wcspbrk +# define SIMPLE_STRPBRK simple_wcspbrk +# define STUPID_STRPBRK stupid_wcspbrk +# endif /* WIDE */ + +typedef CHAR *(*proto_t) (const CHAR *, const CHAR *); +CHAR *SIMPLE_STRPBRK (const CHAR *, const CHAR *); +CHAR *STUPID_STRPBRK (const CHAR *, const CHAR *); + +IMPL (STUPID_STRPBRK, 0) +IMPL (SIMPLE_STRPBRK, 0) +IMPL (STRPBRK, 1) + +CHAR * +SIMPLE_STRPBRK (const CHAR *s, const CHAR *rej) +{ + const CHAR *r; + CHAR c; + + while ((c = *s++) != '\0') + for (r = rej; *r != '\0'; ++r) + if (*r == c) + return (CHAR *) s - 1; + return NULL; +} + +CHAR * +STUPID_STRPBRK (const CHAR *s, const CHAR *rej) +{ + size_t ns = STRLEN (s), nrej = STRLEN (rej); + size_t i, j; + + for (i = 0; i < ns; ++i) + for (j = 0; j < nrej; ++j) + if (s[i] == rej[j]) + return (CHAR *) s + i; + return NULL; +} +#endif /* !STRPBRK_RESULT */ + +static void +do_one_test (impl_t *impl, const CHAR *s, const CHAR *rej, RES_TYPE exp_res) +{ + RES_TYPE res = CALL (impl, s, rej); + if (res != exp_res) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + (void *) res, (void *) exp_res); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t pos, size_t len) +{ + size_t i; + int c; + RES_TYPE result; + CHAR *rej, *s; + + align &= 7; + if ((align + pos + 10) * sizeof (CHAR) >= page_size || len > 240) + return; + + rej = (CHAR *) (buf2) + (random () & 255); + s = (CHAR *) (buf1) + align; + + for (i = 0; i < len; ++i) + { + rej[i] = random () & BIG_CHAR; + if (!rej[i]) + rej[i] = random () & BIG_CHAR; + if (!rej[i]) + rej[i] = 1 + (random () & SMALL_CHAR); + } + rej[len] = '\0'; + for (c = 1; c <= BIG_CHAR; ++c) + if (STRCHR (rej, c) == NULL) + break; + + for (i = 0; i < pos; ++i) + { + s[i] = random () & BIG_CHAR; + if (STRCHR (rej, s[i])) + { + s[i] = random () & BIG_CHAR; + if (STRCHR (rej, s[i])) + s[i] = c; + } + } + s[pos] = rej[random () % (len + 1)]; + if (s[pos]) + { + for (i = pos + 1; i < pos + 10; ++i) + s[i] = random () & BIG_CHAR; + s[i] = '\0'; + } + result = STRPBRK_RESULT (s, pos); + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s, rej, result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, pos, len, rlen; + RES_TYPE result; + int c; + UCHAR *p = (UCHAR *) (buf1 + page_size) - 512; + UCHAR *rej; + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & 15; + pos = random () & 511; + if (pos + align >= 511) + pos = 510 - align - (random () & 7); + len = random () & 511; + if (pos >= len && (random () & 1)) + len = pos + 1 + (random () & 7); + if (len + align >= 512) + len = 511 - align - (random () & 7); + if (random () & 1) + rlen = random () & 63; + else + rlen = random () & 15; + rej = (UCHAR *) (buf2 + page_size) - rlen - 1 - (random () & 7); + for (i = 0; i < rlen; ++i) + { + rej[i] = random () & BIG_CHAR; + if (!rej[i]) + rej[i] = random () & BIG_CHAR; + if (!rej[i]) + rej[i] = 1 + (random () & SMALL_CHAR); + } + rej[i] = '\0'; + for (c = 1; c <= BIG_CHAR; ++c) + if (STRCHR ((CHAR *) rej, c) == NULL) + break; + j = (pos > len ? pos : len) + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == len + align) + p[i] = '\0'; + else if (i == pos + align) + p[i] = rej[random () % (rlen + 1)]; + else if (i < align || i > pos + align) + p[i] = random () & BIG_CHAR; + else + { + p[i] = random () & BIG_CHAR; + if (STRCHR ((CHAR *) rej, p[i])) + { + p[i] = random () & BIG_CHAR; + if (STRCHR ((CHAR *) rej, p[i])) + p[i] = c; + } + } + } + + result = STRPBRK_RESULT ((CHAR *) (p + align), pos < len ? pos : len); + + FOR_EACH_IMPL (impl, 1) + 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, (CHAR *) (p + align), (CHAR *) rej), + (void *) result); + ret = 1; + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%32s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < 32; ++i) + { + do_test (0, 512, i); + do_test (i, 512, i); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 16 << i, 4); + do_test (i, 16 << i, 4); + } + + for (i = 1; i < 8; ++i) + do_test (i, 64, 10); + + for (i = 0; i < 64; ++i) + do_test (0, i, 6); + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strrchr.c b/REORG.TODO/string/test-strrchr.c new file mode 100644 index 0000000000..10c070aef1 --- /dev/null +++ b/REORG.TODO/string/test-strrchr.c @@ -0,0 +1,247 @@ +/* Test and measure STRCHR functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + Added wcsrrchr support by Liubov Dmitrieva <liubov.dmitrieva@gmail.com>, + 2011. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifdef WIDE +# define TEST_NAME "wcsrchr" +#else +# define TEST_NAME "strrchr" +#endif +#include "test-string.h" + +#ifdef WIDE +# include <wchar.h> +# define SIMPLE_STRRCHR simple_wcsrchr +# define STRRCHR wcsrchr +# define CHAR wchar_t +# define UCHAR wchar_t +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +#else +# define SIMPLE_STRRCHR simple_strrchr +# define STRRCHR strrchr +# define CHAR char +# define UCHAR unsigned char +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +#endif + +typedef CHAR *(*proto_t) (const CHAR *, int); +CHAR *SIMPLE_STRRCHR (const CHAR *, int); + +IMPL (SIMPLE_STRRCHR, 0) +IMPL (STRRCHR, 1) + +CHAR * +SIMPLE_STRRCHR (const CHAR *s, int c) +{ + const CHAR *ret = NULL; + + for (; *s != '\0'; ++s) + if (*s == (CHAR) c) + ret = s; + + return (CHAR *) (c == '\0' ? s : ret); +} + +static void +do_one_test (impl_t *impl, const CHAR *s, int c, CHAR *exp_res) +{ + CHAR *res = CALL (impl, s, c); + if (res != exp_res) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + res, exp_res); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t pos, size_t len, int seek_char, int max_char) +/* For wcsrchr: align here means align not in bytes, + but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)) + len for wcschr here isn't in bytes but it's number of wchar_t symbols. */ +{ + size_t i; + CHAR *result; + CHAR *buf = (CHAR *) buf1; + + align &= 7; + if ( (align + len) * sizeof(CHAR) >= page_size) + return; + + for (i = 0; i < len; ++i) + { + buf[align + i] = (random () * random ()) & max_char; + if (!buf[align + i]) + buf[align + i] = (random () * random ()) & max_char; + if (!buf[align + i]) + buf[align + i] = 1; + if ((i > pos || pos >= len) && buf[align + i] == seek_char) + buf[align + i] = seek_char + 10 + (random () & 15); + } + buf[align + len] = 0; + + if (pos < len) + { + buf[align + pos] = seek_char; + result = (CHAR *) (buf + align + pos); + } + else if (seek_char == 0) + result = (CHAR *) (buf + align + len); + else + result = NULL; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, (CHAR *) (buf + align), seek_char, result); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, pos, len; + int seek_char; + CHAR *result; + UCHAR *p = (UCHAR *) (buf1 + page_size) - 512; + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & (63 / sizeof(CHAR)); + /* For wcsrchr: align here means align not in bytes, but in wchar_ts, + in bytes it will equal to align * (sizeof (wchar_t)). + For strrchr we need to check all alignments from 0 to 63 since + some assembly implementations have separate prolog for alignments + more 48. */ + pos = random () & 511; + if (pos + align >= 511) + pos = 510 - align - (random () & 7); + len = random () & 511; + /* len for wcschr here isn't in bytes but it's number of wchar_t + symbols. */ + if (pos >= len) + len = pos + (random () & 7); + if (len + align >= 512) + len = 511 - align - (random () & 7); + seek_char = random () & 255; + if (seek_char && pos == len) + { + if (pos) + --pos; + else + ++len; + } + j = len + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == pos + align) + p[i] = seek_char; + else if (i == len + align) + p[i] = 0; + else + { + p[i] = random () & 255; + if (((i > pos + align && i < len + align) || pos > len) + && p[i] == seek_char) + p[i] = seek_char + 13; + if (i < len + align && !p[i]) + { + p[i] = seek_char - 13; + if (!p[i]) + p[i] = 140; + } + } + } + + if (pos <= len) + result = (CHAR *) (p + pos + align); + else if (seek_char == 0) + result = (CHAR *) (p + len + align); + else + result = NULL; + + FOR_EACH_IMPL (impl, 1) + 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, (CHAR *) (p + align), seek_char), result, p); + ret = 1; + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%20s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 1; i < 8; ++i) + { + do_test (0, 16 << i, 2048, 23, SMALL_CHAR); + do_test (i, 16 << i, 2048, 23, SMALL_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 64, 256, 23, SMALL_CHAR); + do_test (i, 64, 256, 23, BIG_CHAR); + } + + for (i = 0; i < 32; ++i) + { + do_test (0, i, i + 1, 23, SMALL_CHAR); + do_test (0, i, i + 1, 23, BIG_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 16 << i, 2048, 0, SMALL_CHAR); + do_test (i, 16 << i, 2048, 0, SMALL_CHAR); + } + + for (i = 1; i < 8; ++i) + { + do_test (i, 64, 256, 0, SMALL_CHAR); + do_test (i, 64, 256, 0, BIG_CHAR); + } + + for (i = 0; i < 32; ++i) + { + do_test (0, i, i + 1, 0, SMALL_CHAR); + do_test (0, i, i + 1, 0, BIG_CHAR); + } + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strspn.c b/REORG.TODO/string/test-strspn.c new file mode 100644 index 0000000000..d26331fb6d --- /dev/null +++ b/REORG.TODO/string/test-strspn.c @@ -0,0 +1,245 @@ +/* Test and measure strspn functions. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Jakub Jelinek <jakub@redhat.com>, 1999. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#ifndef WIDE +# define TEST_NAME "strspn" +#else +# define TEST_NAME "wcsspn" +#endif /* WIDE */ +#include "test-string.h" + +#ifndef WIDE +# define STRSPN strspn +# define CHAR char +# define UCHAR unsigned char +# define SIMPLE_STRSPN simple_strspn +# define STUPID_STRSPN stupid_strspn +# define STRLEN strlen +# define STRCHR strchr +# define BIG_CHAR CHAR_MAX +# define SMALL_CHAR 127 +#else +# include <wchar.h> +# define STRSPN wcsspn +# define CHAR wchar_t +# define UCHAR wchar_t +# define SIMPLE_STRSPN simple_wcsspn +# define STUPID_STRSPN stupid_wcsspn +# define STRLEN wcslen +# define STRCHR wcschr +# define BIG_CHAR WCHAR_MAX +# define SMALL_CHAR 1273 +#endif /* WIDE */ + +typedef size_t (*proto_t) (const CHAR *, const CHAR *); +size_t SIMPLE_STRSPN (const CHAR *, const CHAR *); +size_t STUPID_STRSPN (const CHAR *, const CHAR *); + +IMPL (STUPID_STRSPN, 0) +IMPL (SIMPLE_STRSPN, 0) +IMPL (STRSPN, 1) + +size_t +SIMPLE_STRSPN (const CHAR *s, const CHAR *acc) +{ + const CHAR *r, *str = s; + CHAR c; + + while ((c = *s++) != '\0') + { + for (r = acc; *r != '\0'; ++r) + if (*r == c) + break; + if (*r == '\0') + return s - str - 1; + } + return s - str - 1; +} + +size_t +STUPID_STRSPN (const CHAR *s, const CHAR *acc) +{ + size_t ns = STRLEN (s), nacc = STRLEN (acc); + size_t i, j; + + for (i = 0; i < ns; ++i) + { + for (j = 0; j < nacc; ++j) + if (s[i] == acc[j]) + break; + if (j == nacc) + return i; + } + return i; +} + +static void +do_one_test (impl_t *impl, const CHAR *s, const CHAR *acc, size_t exp_res) +{ + size_t res = CALL (impl, s, acc); + if (res != exp_res) + { + error (0, 0, "Wrong result in function %s %p %p", impl->name, + (void *) res, (void *) exp_res); + ret = 1; + return; + } +} + +static void +do_test (size_t align, size_t pos, size_t len) +{ + size_t i; + CHAR *acc, *s; + + align &= 7; + if ((align + pos + 10) * sizeof (CHAR) >= page_size || len > 240 || ! len) + return; + + acc = (CHAR *) (buf2) + (random () & 255); + s = (CHAR *) (buf1) + align; + + for (i = 0; i < len; ++i) + { + acc[i] = random () & BIG_CHAR; + if (!acc[i]) + acc[i] = random () & BIG_CHAR; + if (!acc[i]) + acc[i] = 1 + (random () & SMALL_CHAR); + } + acc[len] = '\0'; + + for (i = 0; i < pos; ++i) + s[i] = acc[random () % len]; + s[pos] = random () & BIG_CHAR; + if (STRCHR (acc, s[pos])) + s[pos] = '\0'; + else + { + for (i = pos + 1; i < pos + 10; ++i) + s[i] = random () & BIG_CHAR; + s[i] = '\0'; + } + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s, acc, pos); +} + +static void +do_random_tests (void) +{ + size_t i, j, n, align, pos, alen, len; + UCHAR *p = (UCHAR *) (buf1 + page_size) - 512; + UCHAR *acc; + + for (n = 0; n < ITERATIONS; n++) + { + align = random () & 15; + if (random () & 1) + alen = random () & 63; + else + alen = random () & 15; + if (!alen) + pos = 0; + else + pos = random () & 511; + if (pos + align >= 511) + pos = 510 - align - (random () & 7); + len = random () & 511; + if (len + align >= 512) + len = 511 - align - (random () & 7); + acc = (UCHAR *) (buf2 + page_size) - alen - 1 - (random () & 7); + for (i = 0; i < alen; ++i) + { + acc[i] = random () & BIG_CHAR; + if (!acc[i]) + acc[i] = random () & BIG_CHAR; + if (!acc[i]) + acc[i] = 1 + (random () & SMALL_CHAR); + } + acc[i] = '\0'; + j = (pos > len ? pos : len) + align + 64; + if (j > 512) + j = 512; + + for (i = 0; i < j; i++) + { + if (i == len + align) + p[i] = '\0'; + else if (i == pos + align) + { + p[i] = random () & BIG_CHAR; + if (STRCHR ((CHAR *) acc, p[i])) + p[i] = '\0'; + } + else if (i < align || i > pos + align) + p[i] = random () & BIG_CHAR; + else + p[i] = acc [random () % alen]; + } + + FOR_EACH_IMPL (impl, 1) + 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, (CHAR *) (p + align), (CHAR *) acc), + (pos < len ? pos : len)); + ret = 1; + } + } +} + +int +test_main (void) +{ + size_t i; + + test_init (); + + printf ("%32s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (i = 0; i < 32; ++i) + { + do_test (0, 512, i); + do_test (i, 512, i); + } + + for (i = 1; i < 8; ++i) + { + do_test (0, 16 << i, 4); + do_test (i, 16 << i, 4); + } + + for (i = 1; i < 8; ++i) + do_test (i, 64, 10); + + for (i = 0; i < 64; ++i) + do_test (0, i, 6); + + do_random_tests (); + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/test-strstr.c b/REORG.TODO/string/test-strstr.c new file mode 100644 index 0000000000..33f221149a --- /dev/null +++ b/REORG.TODO/string/test-strstr.c @@ -0,0 +1,212 @@ +/* Test and measure strstr functions. + Copyright (C) 2010-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Ulrich Drepper <drepper@redhat.com>, 2010. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#define TEST_NAME "strstr" +#include "test-string.h" + + +#define STRSTR simple_strstr +#define libc_hidden_builtin_def(arg) /* nothing */ +#include "strstr.c" + + +static char * +stupid_strstr (const char *s1, const char *s2) +{ + ssize_t s1len = strlen (s1); + ssize_t s2len = strlen (s2); + + if (s2len > s1len) + return NULL; + + for (ssize_t i = 0; i <= s1len - s2len; ++i) + { + size_t j; + for (j = 0; j < s2len; ++j) + if (s1[i + j] != s2[j]) + break; + if (j == s2len) + return (char *) s1 + i; + } + + return NULL; +} + + +typedef char *(*proto_t) (const char *, const char *); + +IMPL (stupid_strstr, 0) +IMPL (simple_strstr, 0) +IMPL (strstr, 1) + + +static int +check_result (impl_t *impl, const char *s1, const char *s2, + char *exp_result) +{ + char *result = CALL (impl, s1, s2); + if (result != exp_result) + { + error (0, 0, "Wrong result in function %s %s %s", impl->name, + result, exp_result); + ret = 1; + return -1; + } + + return 0; +} + +static void +do_one_test (impl_t *impl, const char *s1, const char *s2, char *exp_result) +{ + if (check_result (impl, s1, s2, exp_result) < 0) + return; +} + + +static void +do_test (size_t align1, size_t align2, size_t len1, size_t len2, + int fail) +{ + char *s1 = (char *) (buf1 + align1); + char *s2 = (char *) (buf2 + align2); + + static const char d[] = "1234567890abcdef"; +#define dl (sizeof (d) - 1) + char *ss2 = s2; + for (size_t l = len2; l > 0; l = l > dl ? l - dl : 0) + { + size_t t = l > dl ? dl : l; + ss2 = mempcpy (ss2, d, t); + } + s2[len2] = '\0'; + + if (fail) + { + char *ss1 = s1; + for (size_t l = len1; l > 0; l = l > dl ? l - dl : 0) + { + size_t t = l > dl ? dl : l; + memcpy (ss1, d, t); + ++ss1[len2 > 7 ? 7 : len2 - 1]; + ss1 += t; + } + } + else + { + memset (s1, '0', len1); + memcpy (s1 + len1 - len2, s2, len2); + } + s1[len1] = '\0'; + + FOR_EACH_IMPL (impl, 0) + do_one_test (impl, s1, s2, fail ? NULL : s1 + len1 - len2); + +} + +static void +check1 (void) +{ + const char s1[] = + "F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD_C3_A7_20_EF_BF_BD"; + const char s2[] = "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"; + char *exp_result; + + exp_result = stupid_strstr (s1, s2); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1, s2, exp_result); +} + +static void +check2 (void) +{ + const char s1[] = ", enable_static, \0, enable_shared, "; + char *exp_result; + char *s2 = (void *) buf1 + page_size - 18; + + strcpy (s2, s1); + exp_result = stupid_strstr (s1, s1 + 18); + FOR_EACH_IMPL (impl, 0) + { + check_result (impl, s1, s1 + 18, exp_result); + check_result (impl, s2, s1 + 18, exp_result); + } +} + +static int +test_main (void) +{ + test_init (); + + check1 (); + check2 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) + printf ("\t%s", impl->name); + putchar ('\n'); + + for (size_t klen = 2; klen < 32; ++klen) + for (size_t hlen = 2 * klen; hlen < 16 * klen; hlen += klen) + { + do_test (0, 0, hlen, klen, 0); + do_test (0, 0, hlen, klen, 1); + do_test (0, 3, hlen, klen, 0); + do_test (0, 3, hlen, klen, 1); + do_test (0, 9, hlen, klen, 0); + do_test (0, 9, hlen, klen, 1); + do_test (0, 15, hlen, klen, 0); + do_test (0, 15, hlen, klen, 1); + + do_test (3, 0, hlen, klen, 0); + do_test (3, 0, hlen, klen, 1); + do_test (3, 3, hlen, klen, 0); + do_test (3, 3, hlen, klen, 1); + do_test (3, 9, hlen, klen, 0); + do_test (3, 9, hlen, klen, 1); + do_test (3, 15, hlen, klen, 0); + do_test (3, 15, hlen, klen, 1); + + do_test (9, 0, hlen, klen, 0); + do_test (9, 0, hlen, klen, 1); + do_test (9, 3, hlen, klen, 0); + do_test (9, 3, hlen, klen, 1); + do_test (9, 9, hlen, klen, 0); + do_test (9, 9, hlen, klen, 1); + do_test (9, 15, hlen, klen, 0); + do_test (9, 15, hlen, klen, 1); + + do_test (15, 0, hlen, klen, 0); + do_test (15, 0, hlen, klen, 1); + do_test (15, 3, hlen, klen, 0); + do_test (15, 3, hlen, klen, 1); + do_test (15, 9, hlen, klen, 0); + do_test (15, 9, hlen, klen, 1); + do_test (15, 15, hlen, klen, 0); + do_test (15, 15, hlen, klen, 1); + } + + do_test (0, 0, page_size - 1, 16, 0); + do_test (0, 0, page_size - 1, 16, 1); + + return ret; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/testcopy.c b/REORG.TODO/string/testcopy.c new file mode 100644 index 0000000000..8c9dd4c500 --- /dev/null +++ b/REORG.TODO/string/testcopy.c @@ -0,0 +1,107 @@ +/* Copyright (C) 1990-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <malloc.h> + +int +main (void) +{ + char *mem, *memp; + char *rand_mem; + char *lo_around, *hi_around; + int size, max_size; + int src_off, dst_off; + int i; + int space_around = 10; + + max_size = 256; + + mem = malloc (max_size + 2 * max_size + 2 * space_around); + rand_mem = malloc (max_size); + lo_around = malloc (space_around); + hi_around = malloc (space_around); + memp = mem + space_around; + + /* Fill RAND_MEM with random bytes, each non-zero. */ + for (i = 0; i < max_size; i++) + { + int x; + do + x = random (); + while (x == 0); + rand_mem[i] = x; + } + + for (size = 0; size < max_size; size++) + { + printf("phase %d\n", size); + for (src_off = 0; src_off <= 16; src_off++) + { + for (dst_off = 0; dst_off <= 16; dst_off++) + { + /* Put zero around the intended destination, to check + that it's not clobbered. */ + for (i = 1; i < space_around; i++) + { + memp[dst_off - i] = 0; + memp[dst_off + size - 1 + i] = 0; + } + + /* Fill the source area with known contents. */ + for (i = 0; i < size; i++) + memp[src_off + i] = rand_mem[i]; + + /* Remember the contents around the destination area. + (It might not be what we wrote some lines above, since + the src area and the dst area overlap.) */ + for (i = 1; i < space_around; i++) + { + lo_around[i] = memp[dst_off - i]; + hi_around[i] = memp[dst_off + size - 1 + i]; + } + + memmove (memp + dst_off, memp + src_off, size); + + /* Check that the destination area has the same + contents we wrote to the source area. */ + for (i = 0; i < size; i++) + { + if (memp[dst_off + i] != rand_mem[i]) + abort (); + } + + /* Check that the area around the destination is not + clobbered. */ + for (i = 1; i < space_around; i++) + { + if (memp[dst_off - i] != lo_around[i]) + abort (); + if (memp[dst_off + size - 1 + i] != hi_around[i]) + abort (); + } + } + } + } + + puts ("Test succeeded."); + + return 0; +} diff --git a/REORG.TODO/string/tester.c b/REORG.TODO/string/tester.c new file mode 100644 index 0000000000..4b928b4f5e --- /dev/null +++ b/REORG.TODO/string/tester.c @@ -0,0 +1,1685 @@ +/* Tester for string functions. + Copyright (C) 1995-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +/* Make sure we don't test the optimized inline functions if we want to + test the real implementation. */ +#if !defined DO_STRING_INLINES +#undef __USE_STRING_INLINES +#endif + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <fcntl.h> +#include <libc-diag.h> + + +#define STREQ(a, b) (strcmp((a), (b)) == 0) + +const char *it = "<UNSET>"; /* Routine name for message routines. */ +size_t errors = 0; + +/* Complain if condition is not true. */ +static void +check (int thing, int number) +{ + if (!thing) + { + printf ("%s flunked test %d\n", it, number); + ++errors; + } +} + +/* Complain if first two args don't strcmp as equal. */ +static void +equal (const char *a, const char *b, int number) +{ + check (a != NULL && b != NULL && STREQ (a, b), number); +} + +char one[50]; +char two[50]; +char *cp; + +static void +test_strcmp (void) +{ + it = "strcmp"; + check (strcmp ("", "") == 0, 1); /* Trivial case. */ + check (strcmp ("a", "a") == 0, 2); /* Identity. */ + check (strcmp ("abc", "abc") == 0, 3); /* Multicharacter. */ + check (strcmp ("abc", "abcd") < 0, 4); /* Length mismatches. */ + check (strcmp ("abcd", "abc") > 0, 5); + check (strcmp ("abcd", "abce") < 0, 6); /* Honest miscompares. */ + check (strcmp ("abce", "abcd") > 0, 7); + check (strcmp ("a\203", "a") > 0, 8); /* Tricky if char signed. */ + check (strcmp ("a\203", "a\003") > 0, 9); + + { + char buf1[0x40], buf2[0x40]; + int i, j; + for (i=0; i < 0x10; i++) + for (j = 0; j < 0x10; j++) + { + int k; + for (k = 0; k < 0x3f; k++) + { + buf1[k] = '0' ^ (k & 4); + buf2[k] = '4' ^ (k & 4); + } + buf1[i] = buf1[0x3f] = 0; + buf2[j] = buf2[0x3f] = 0; + for (k = 0; k < 0xf; k++) + { + int cnum = 0x10+0x10*k+0x100*j+0x1000*i; + check (strcmp (buf1+i,buf2+j) == 0, cnum); + buf1[i+k] = 'A' + i + k; + buf1[i+k+1] = 0; + check (strcmp (buf1+i,buf2+j) > 0, cnum+1); + check (strcmp (buf2+j,buf1+i) < 0, cnum+2); + buf2[j+k] = 'B' + i + k; + buf2[j+k+1] = 0; + check (strcmp (buf1+i,buf2+j) < 0, cnum+3); + check (strcmp (buf2+j,buf1+i) > 0, cnum+4); + buf2[j+k] = 'A' + i + k; + buf1[i] = 'A' + i + 0x80; + check (strcmp (buf1+i,buf2+j) > 0, cnum+5); + check (strcmp (buf2+j,buf1+i) < 0, cnum+6); + buf1[i] = 'A' + i; + } + } + } +} + +#define SIMPLE_COPY(fn, n, str, ntest) \ + do { \ + int __n; \ + char *cp; \ + for (__n = 0; __n < (int) sizeof (one); ++__n) \ + one[__n] = 'Z'; \ + fn (one, str); \ + for (cp = one, __n = 0; __n < n; ++__n, ++cp) \ + check (*cp == '0' + (n % 10), ntest); \ + check (*cp == '\0', ntest); \ + } while (0) + +static void +test_strcpy (void) +{ + int i; + it = "strcpy"; + check (strcpy (one, "abcd") == one, 1); /* Returned value. */ + equal (one, "abcd", 2); /* Basic test. */ + + (void) strcpy (one, "x"); + equal (one, "x", 3); /* Writeover. */ + equal (one+2, "cd", 4); /* Wrote too much? */ + + (void) strcpy (two, "hi there"); + (void) strcpy (one, two); + equal (one, "hi there", 5); /* Basic test encore. */ + equal (two, "hi there", 6); /* Stomped on source? */ + + (void) strcpy (one, ""); + equal (one, "", 7); /* Boundary condition. */ + + for (i = 0; i < 16; i++) + { + (void) strcpy (one + i, "hi there"); /* Unaligned destination. */ + equal (one + i, "hi there", 8 + (i * 2)); + (void) strcpy (two, one + i); /* Unaligned source. */ + equal (two, "hi there", 9 + (i * 2)); + } + + SIMPLE_COPY(strcpy, 0, "", 41); + SIMPLE_COPY(strcpy, 1, "1", 42); + SIMPLE_COPY(strcpy, 2, "22", 43); + SIMPLE_COPY(strcpy, 3, "333", 44); + SIMPLE_COPY(strcpy, 4, "4444", 45); + SIMPLE_COPY(strcpy, 5, "55555", 46); + SIMPLE_COPY(strcpy, 6, "666666", 47); + SIMPLE_COPY(strcpy, 7, "7777777", 48); + SIMPLE_COPY(strcpy, 8, "88888888", 49); + SIMPLE_COPY(strcpy, 9, "999999999", 50); + SIMPLE_COPY(strcpy, 10, "0000000000", 51); + SIMPLE_COPY(strcpy, 11, "11111111111", 52); + SIMPLE_COPY(strcpy, 12, "222222222222", 53); + SIMPLE_COPY(strcpy, 13, "3333333333333", 54); + SIMPLE_COPY(strcpy, 14, "44444444444444", 55); + SIMPLE_COPY(strcpy, 15, "555555555555555", 56); + SIMPLE_COPY(strcpy, 16, "6666666666666666", 57); + + /* Simple test using implicitly coerced `void *' arguments. */ + const void *src = "frobozz"; + void *dst = one; + check (strcpy (dst, src) == dst, 1); + equal (dst, "frobozz", 2); +} + +static void +test_stpcpy (void) +{ + it = "stpcpy"; + check ((stpcpy (one, "a") - one) == 1, 1); + equal (one, "a", 2); + + check ((stpcpy (one, "ab") - one) == 2, 3); + equal (one, "ab", 4); + + check ((stpcpy (one, "abc") - one) == 3, 5); + equal (one, "abc", 6); + + check ((stpcpy (one, "abcd") - one) == 4, 7); + equal (one, "abcd", 8); + + check ((stpcpy (one, "abcde") - one) == 5, 9); + equal (one, "abcde", 10); + + check ((stpcpy (one, "abcdef") - one) == 6, 11); + equal (one, "abcdef", 12); + + check ((stpcpy (one, "abcdefg") - one) == 7, 13); + equal (one, "abcdefg", 14); + + check ((stpcpy (one, "abcdefgh") - one) == 8, 15); + equal (one, "abcdefgh", 16); + + check ((stpcpy (one, "abcdefghi") - one) == 9, 17); + equal (one, "abcdefghi", 18); + + check ((stpcpy (one, "x") - one) == 1, 19); + equal (one, "x", 20); /* Writeover. */ + equal (one+2, "cdefghi", 21); /* Wrote too much? */ + + check ((stpcpy (one, "xx") - one) == 2, 22); + equal (one, "xx", 23); /* Writeover. */ + equal (one+3, "defghi", 24); /* Wrote too much? */ + + check ((stpcpy (one, "xxx") - one) == 3, 25); + equal (one, "xxx", 26); /* Writeover. */ + equal (one+4, "efghi", 27); /* Wrote too much? */ + + check ((stpcpy (one, "xxxx") - one) == 4, 28); + equal (one, "xxxx", 29); /* Writeover. */ + equal (one+5, "fghi", 30); /* Wrote too much? */ + + check ((stpcpy (one, "xxxxx") - one) == 5, 31); + equal (one, "xxxxx", 32); /* Writeover. */ + equal (one+6, "ghi", 33); /* Wrote too much? */ + + check ((stpcpy (one, "xxxxxx") - one) == 6, 34); + equal (one, "xxxxxx", 35); /* Writeover. */ + equal (one+7, "hi", 36); /* Wrote too much? */ + + check ((stpcpy (one, "xxxxxxx") - one) == 7, 37); + equal (one, "xxxxxxx", 38); /* Writeover. */ + equal (one+8, "i", 39); /* Wrote too much? */ + + check ((stpcpy (stpcpy (stpcpy (one, "a"), "b"), "c") - one) == 3, 40); + equal (one, "abc", 41); + equal (one + 4, "xxx", 42); + + SIMPLE_COPY(stpcpy, 0, "", 43); + SIMPLE_COPY(stpcpy, 1, "1", 44); + SIMPLE_COPY(stpcpy, 2, "22", 45); + SIMPLE_COPY(stpcpy, 3, "333", 46); + SIMPLE_COPY(stpcpy, 4, "4444", 47); + SIMPLE_COPY(stpcpy, 5, "55555", 48); + SIMPLE_COPY(stpcpy, 6, "666666", 49); + SIMPLE_COPY(stpcpy, 7, "7777777", 50); + SIMPLE_COPY(stpcpy, 8, "88888888", 51); + SIMPLE_COPY(stpcpy, 9, "999999999", 52); + SIMPLE_COPY(stpcpy, 10, "0000000000", 53); + SIMPLE_COPY(stpcpy, 11, "11111111111", 54); + SIMPLE_COPY(stpcpy, 12, "222222222222", 55); + SIMPLE_COPY(stpcpy, 13, "3333333333333", 56); + SIMPLE_COPY(stpcpy, 14, "44444444444444", 57); + SIMPLE_COPY(stpcpy, 15, "555555555555555", 58); + SIMPLE_COPY(stpcpy, 16, "6666666666666666", 59); +} + +static void +test_stpncpy (void) +{ + it = "stpncpy"; + memset (one, 'x', sizeof (one)); + check (stpncpy (one, "abc", 2) == one + 2, 1); + check (stpncpy (one, "abc", 3) == one + 3, 2); + check (stpncpy (one, "abc", 4) == one + 3, 3); + check (one[3] == '\0' && one[4] == 'x', 4); + check (stpncpy (one, "abcd", 5) == one + 4, 5); + check (one[4] == '\0' && one[5] == 'x', 6); + check (stpncpy (one, "abcd", 6) == one + 4, 7); + check (one[4] == '\0' && one[5] == '\0' && one[6] == 'x', 8); +} + +static void +test_strcat (void) +{ + it = "strcat"; + (void) strcpy (one, "ijk"); + check (strcat (one, "lmn") == one, 1); /* Returned value. */ + equal (one, "ijklmn", 2); /* Basic test. */ + + (void) strcpy (one, "x"); + (void) strcat (one, "yz"); + equal (one, "xyz", 3); /* Writeover. */ + equal (one+4, "mn", 4); /* Wrote too much? */ + + (void) strcpy (one, "gh"); + (void) strcpy (two, "ef"); + (void) strcat (one, two); + equal (one, "ghef", 5); /* Basic test encore. */ + equal (two, "ef", 6); /* Stomped on source? */ + + (void) strcpy (one, ""); + (void) strcat (one, ""); + equal (one, "", 7); /* Boundary conditions. */ + (void) strcpy (one, "ab"); + (void) strcat (one, ""); + equal (one, "ab", 8); + (void) strcpy (one, ""); + (void) strcat (one, "cd"); + equal (one, "cd", 9); + + int ntest = 10; + char buf1[80] __attribute__ ((aligned (16))); + char buf2[32] __attribute__ ((aligned (16))); + for (size_t n1 = 0; n1 < 16; ++n1) + for (size_t n2 = 0; n2 < 16; ++n2) + for (size_t n3 = 0; n3 < 32; ++n3) + { + size_t olderrors = errors; + + memset (buf1, 'b', sizeof (buf1)); + + memset (buf1 + n2, 'a', n3); + buf1[n2 + n3] = '\0'; + strcpy (buf2 + n1, "123"); + + check (strcat (buf1 + n2, buf2 + n1) == buf1 + n2, ntest); + if (errors == olderrors) + for (size_t i = 0; i < sizeof (buf1); ++i) + { + if (i < n2) + check (buf1[i] == 'b', ntest); + else if (i < n2 + n3) + check (buf1[i] == 'a', ntest); + else if (i < n2 + n3 + 3) + check (buf1[i] == "123"[i - (n2 + n3)], ntest); + else if (i == n2 + n3 + 3) + check (buf1[i] == '\0', ntest); + else + check (buf1[i] == 'b', ntest); + + if (errors != olderrors) + { + printf ("n1=%zu, n2=%zu, n3=%zu, buf1=%02hhx", + n1, n2, n3, buf1[0]); + for (size_t j = 1; j < sizeof (buf1); ++j) + printf (",%02hhx", buf1[j]); + putchar_unlocked ('\n'); + break; + } + } + } +} + +static void +test_strncat (void) +{ + /* First test it as strcat, with big counts, then test the count + mechanism. */ + it = "strncat"; + (void) strcpy (one, "ijk"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being larger than + the size of the buffer; this is deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + check (strncat (one, "lmn", 99) == one, 1); /* Returned value. */ + DIAG_POP_NEEDS_COMMENT; + equal (one, "ijklmn", 2); /* Basic test. */ + + (void) strcpy (one, "x"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being larger than + the size of the buffer; this is deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + (void) strncat (one, "yz", 99); + DIAG_POP_NEEDS_COMMENT; + equal (one, "xyz", 3); /* Writeover. */ + equal (one+4, "mn", 4); /* Wrote too much? */ + + (void) strcpy (one, "gh"); + (void) strcpy (two, "ef"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being larger than + the size of the buffer; this is deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + (void) strncat (one, two, 99); + DIAG_POP_NEEDS_COMMENT; + equal (one, "ghef", 5); /* Basic test encore. */ + equal (two, "ef", 6); /* Stomped on source? */ + + (void) strcpy (one, ""); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being larger than + the size of the buffer; this is deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + (void) strncat (one, "", 99); + DIAG_POP_NEEDS_COMMENT; + equal (one, "", 7); /* Boundary conditions. */ + (void) strcpy (one, "ab"); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being larger than + the size of the buffer; this is deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + (void) strncat (one, "", 99); + DIAG_POP_NEEDS_COMMENT; + equal (one, "ab", 8); + (void) strcpy (one, ""); + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being larger than + the size of the buffer; this is deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + (void) strncat (one, "cd", 99); + DIAG_POP_NEEDS_COMMENT; + equal (one, "cd", 9); + + (void) strcpy (one, "ab"); + (void) strncat (one, "cdef", 2); + equal (one, "abcd", 10); /* Count-limited. */ + + (void) strncat (one, "gh", 0); + equal (one, "abcd", 11); /* Zero count. */ + + (void) strncat (one, "gh", 2); + equal (one, "abcdgh", 12); /* Count and length equal. */ + + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being larger than + the size of the buffer; this is deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + (void) strncat (one, "ij", (size_t)-1); /* set sign bit in count */ + DIAG_POP_NEEDS_COMMENT; + equal (one, "abcdghij", 13); + + int ntest = 14; + char buf1[80] __attribute__ ((aligned (16))); + char buf2[32] __attribute__ ((aligned (16))); + for (size_t n1 = 0; n1 < 16; ++n1) + for (size_t n2 = 0; n2 < 16; ++n2) + for (size_t n3 = 0; n3 < 32; ++n3) + for (size_t n4 = 0; n4 < 16; ++n4) + { + size_t olderrors = errors; + + memset (buf1, 'b', sizeof (buf1)); + + memset (buf1 + n2, 'a', n3); + buf1[n2 + n3] = '\0'; + strcpy (buf2 + n1, "123"); + + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (7, 0) + /* GCC 7 warns about the size passed to strncat being + larger than the size of the buffer; this is + deliberately tested here.. */ + DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow="); +#endif + check (strncat (buf1 + n2, buf2 + n1, ~((size_t) 0) - n4) + == buf1 + n2, ntest); + DIAG_POP_NEEDS_COMMENT; + if (errors == olderrors) + for (size_t i = 0; i < sizeof (buf1); ++i) + { + if (i < n2) + check (buf1[i] == 'b', ntest); + else if (i < n2 + n3) + check (buf1[i] == 'a', ntest); + else if (i < n2 + n3 + 3) + check (buf1[i] == "123"[i - (n2 + n3)], ntest); + else if (i == n2 + n3 + 3) + check (buf1[i] == '\0', ntest); + else + check (buf1[i] == 'b', ntest); + + if (errors != olderrors) + { + printf ("n1=%zu, n2=%zu, n3=%zu, n4=%zu, buf1=%02hhx", + n1, n2, n3, n4, buf1[0]); + for (size_t j = 1; j < sizeof (buf1); ++j) + printf (",%02hhx", buf1[j]); + putchar_unlocked ('\n'); + break; + } + } + } +} + +static void +test_strncmp (void) +{ + /* First test as strcmp with big counts, then test count code. */ + it = "strncmp"; + check (strncmp ("", "", 99) == 0, 1); /* Trivial case. */ + check (strncmp ("a", "a", 99) == 0, 2); /* Identity. */ + check (strncmp ("abc", "abc", 99) == 0, 3); /* Multicharacter. */ + check (strncmp ("abc", "abcd", 99) < 0, 4); /* Length unequal. */ + check (strncmp ("abcd", "abc", 99) > 0, 5); + check (strncmp ("abcd", "abce", 99) < 0, 6); /* Honestly unequal. */ + check (strncmp ("abce", "abcd", 99) > 0, 7); + check (strncmp ("a\203", "a", 2) > 0, 8); /* Tricky if '\203' < 0 */ + check (strncmp ("a\203", "a\003", 2) > 0, 9); + check (strncmp ("abce", "abcd", 3) == 0, 10); /* Count limited. */ + 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 +test_strncpy (void) +{ + /* Testing is a bit different because of odd semantics. */ + it = "strncpy"; + check (strncpy (one, "abc", 4) == one, 1); /* Returned value. */ + equal (one, "abc", 2); /* Did the copy go right? */ + + (void) strcpy (one, "abcdefgh"); + (void) strncpy (one, "xyz", 2); + equal (one, "xycdefgh", 3); /* Copy cut by count. */ + + (void) strcpy (one, "abcdefgh"); + (void) strncpy (one, "xyz", 3); /* Copy cut just before NUL. */ + equal (one, "xyzdefgh", 4); + + (void) strcpy (one, "abcdefgh"); + (void) strncpy (one, "xyz", 4); /* Copy just includes NUL. */ + equal (one, "xyz", 5); + equal (one+4, "efgh", 6); /* Wrote too much? */ + + (void) strcpy (one, "abcdefgh"); + (void) strncpy (one, "xyz", 5); /* Copy includes padding. */ + equal (one, "xyz", 7); + equal (one+4, "", 8); + equal (one+5, "fgh", 9); + + (void) strcpy (one, "abc"); + (void) strncpy (one, "xyz", 0); /* Zero-length copy. */ + equal (one, "abc", 10); + + (void) strncpy (one, "", 2); /* Zero-length source. */ + equal (one, "", 11); + equal (one+1, "", 12); + equal (one+2, "c", 13); + + (void) strcpy (one, "hi there"); + (void) strncpy (two, one, 9); + equal (two, "hi there", 14); /* Just paranoia. */ + equal (one, "hi there", 15); /* Stomped on source? */ +} + +static void +test_strlen (void) +{ + it = "strlen"; + check (strlen ("") == 0, 1); /* Empty. */ + check (strlen ("a") == 1, 2); /* Single char. */ + check (strlen ("abcd") == 4, 3); /* Multiple chars. */ + { + 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 (strlen (p) == 2, 4+i); + } + } +} + +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. */ + check (strnlen ("abcd", 0) == 0, 5); /* Restricted. */ + check (strnlen ("abcd", 1) == 1, 6); /* Restricted. */ + check (strnlen ("abcd", 2) == 2, 7); /* Restricted. */ + check (strnlen ("abcd", 3) == 3, 8); /* Restricted. */ + check (strnlen ("abcd", 4) == 4, 9); /* Restricted. */ + + char buf[4096]; + for (int i = 0; i < 0x100; ++i) + { + char *p = (char *) ((unsigned long int)(buf + 0xff) & ~0xff) + i; + strcpy (p, "OK"); + strcpy (p + 3, "BAD/WRONG"); + check (strnlen (p, 100) == 2, 10 + i); + } +} + +static void +test_strchr (void) +{ + it = "strchr"; + check (strchr ("abcd", 'z') == NULL, 1); /* Not found. */ + (void) strcpy (one, "abcd"); + check (strchr (one, 'c') == one+2, 2); /* Basic test. */ + check (strchr (one, 'd') == one+3, 3); /* End of string. */ + check (strchr (one, 'a') == one, 4); /* Beginning. */ + check (strchr (one, '\0') == one+4, 5); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + check (strchr (one, 'b') == one+1, 6); /* Finding first. */ + (void) strcpy (one, ""); + check (strchr (one, 'b') == NULL, 7); /* Empty string. */ + check (strchr (one, '\0') == one, 8); /* NUL in empty string. */ + { + 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 (strchr (p, '/') == NULL, 9+i); + } + } +} + +static void +test_strchrnul (void) +{ + const char *os; + it = "strchrnul"; + cp = strchrnul ((os = "abcd"), 'z'); + check (*cp == '\0', 1); /* Not found. */ + check (cp == os + 4, 2); + (void) strcpy (one, "abcd"); + check (strchrnul (one, 'c') == one+2, 3); /* Basic test. */ + check (strchrnul (one, 'd') == one+3, 4); /* End of string. */ + check (strchrnul (one, 'a') == one, 5); /* Beginning. */ + check (strchrnul (one, '\0') == one+4, 6); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + check (strchrnul (one, 'b') == one+1, 7); /* Finding first. */ + (void) strcpy (one, ""); + check (strchrnul (one, 'b') == one, 8); /* Empty string. */ + check (strchrnul (one, '\0') == one, 9); /* NUL in empty string. */ + { + 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"); + cp = strchrnul (p, '/'); + check (*cp == '\0', 9+2*i); + check (cp == p+2, 10+2*i); + } + } +} + +static void +test_rawmemchr (void) +{ + it = "rawmemchr"; + (void) strcpy (one, "abcd"); + check (rawmemchr (one, 'c') == one+2, 1); /* Basic test. */ + check (rawmemchr (one, 'd') == one+3, 2); /* End of string. */ + check (rawmemchr (one, 'a') == one, 3); /* Beginning. */ + check (rawmemchr (one, '\0') == one+4, 4); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + check (rawmemchr (one, 'b') == one+1, 5); /* Finding first. */ + (void) strcpy (one, ""); + check (rawmemchr (one, '\0') == one, 6); /* NUL in empty string. */ + { + 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 (rawmemchr (p, 'R') == p+8, 6+i); + } + } +} + +static void +test_index (void) +{ + it = "index"; + check (index ("abcd", 'z') == NULL, 1); /* Not found. */ + (void) strcpy (one, "abcd"); + check (index (one, 'c') == one+2, 2); /* Basic test. */ + check (index (one, 'd') == one+3, 3); /* End of string. */ + check (index (one, 'a') == one, 4); /* Beginning. */ + check (index (one, '\0') == one+4, 5); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + check (index (one, 'b') == one+1, 6); /* Finding first. */ + (void) strcpy (one, ""); + check (index (one, 'b') == NULL, 7); /* Empty string. */ + check (index (one, '\0') == one, 8); /* NUL in empty string. */ +} + +static void +test_strrchr (void) +{ + it = "strrchr"; + check (strrchr ("abcd", 'z') == NULL, 1); /* Not found. */ + (void) strcpy (one, "abcd"); + check (strrchr (one, 'c') == one+2, 2); /* Basic test. */ + check (strrchr (one, 'd') == one+3, 3); /* End of string. */ + check (strrchr (one, 'a') == one, 4); /* Beginning. */ + check (strrchr (one, '\0') == one+4, 5); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + check (strrchr (one, 'b') == one+3, 6); /* Finding last. */ + (void) strcpy (one, ""); + check (strrchr (one, 'b') == NULL, 7); /* Empty string. */ + check (strrchr (one, '\0') == one, 8); /* NUL in empty string. */ + { + 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 (strrchr (p, '/') == NULL, 9+i); + } + } +} + +static void +test_memrchr (void) +{ + size_t l; + it = "memrchr"; + check (memrchr ("abcd", 'z', 5) == NULL, 1); /* Not found. */ + (void) strcpy (one, "abcd"); + l = strlen (one) + 1; + check (memrchr (one, 'c', l) == one+2, 2); /* Basic test. */ + check (memrchr (one, 'd', l) == one+3, 3); /* End of string. */ + check (memrchr (one, 'a', l) == one, 4); /* Beginning. */ + check (memrchr (one, '\0', l) == one+4, 5); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + l = strlen (one) + 1; + check (memrchr (one, 'b', l) == one+3, 6); /* Finding last. */ + (void) strcpy (one, ""); + l = strlen (one) + 1; + check (memrchr (one, 'b', l) == NULL, 7); /* Empty string. */ + check (memrchr (one, '\0', l) == one, 8); /* NUL in empty string. */ + + /* now test all possible alignment and length combinations to catch + bugs due to unrolled loops (assuming unrolling is limited to no + more than 128 byte chunks: */ + { + char buf[128 + sizeof(long)]; + long align, len, i, pos, n = 9; + + for (align = 0; align < (long) sizeof(long); ++align) { + for (len = 0; len < (long) (sizeof(buf) - align); ++len) { + for (i = 0; i < len; ++i) + buf[align + i] = 'x'; /* don't depend on memset... */ + + for (pos = len - 1; pos >= 0; --pos) { +#if 0 + printf("align %d, len %d, pos %d\n", align, len, pos); +#endif + check(memrchr(buf + align, 'x', len) == buf + align + pos, n++); + check(memrchr(buf + align + pos + 1, 'x', len - (pos + 1)) == NULL, + n++); + buf[align + pos] = '-'; + } + } + } + } +} + +static void +test_rindex (void) +{ + it = "rindex"; + check (rindex ("abcd", 'z') == NULL, 1); /* Not found. */ + (void) strcpy (one, "abcd"); + check (rindex (one, 'c') == one+2, 2); /* Basic test. */ + check (rindex (one, 'd') == one+3, 3); /* End of string. */ + check (rindex (one, 'a') == one, 4); /* Beginning. */ + check (rindex (one, '\0') == one+4, 5); /* Finding NUL. */ + (void) strcpy (one, "ababa"); + check (rindex (one, 'b') == one+3, 6); /* Finding last. */ + (void) strcpy (one, ""); + check (rindex (one, 'b') == NULL, 7); /* Empty string. */ + check (rindex (one, '\0') == one, 8); /* NUL in empty string. */ +} + +static void +test_strpbrk (void) +{ + it = "strpbrk"; + check(strpbrk("abcd", "z") == NULL, 1); /* Not found. */ + (void) strcpy(one, "abcd"); + check(strpbrk(one, "c") == one+2, 2); /* Basic test. */ + check(strpbrk(one, "d") == one+3, 3); /* End of string. */ + check(strpbrk(one, "a") == one, 4); /* Beginning. */ + check(strpbrk(one, "") == NULL, 5); /* Empty search list. */ + check(strpbrk(one, "cb") == one+1, 6); /* Multiple search. */ + (void) strcpy(one, "abcabdea"); + check(strpbrk(one, "b") == one+1, 7); /* Finding first. */ + check(strpbrk(one, "cb") == one+1, 8); /* With multiple search. */ + check(strpbrk(one, "db") == one+1, 9); /* Another variant. */ + (void) strcpy(one, ""); + check(strpbrk(one, "bc") == NULL, 10); /* Empty string. */ + (void) strcpy(one, ""); + check(strpbrk(one, "bcd") == NULL, 11); /* Empty string. */ + (void) strcpy(one, ""); + check(strpbrk(one, "bcde") == NULL, 12); /* Empty string. */ + check(strpbrk(one, "") == NULL, 13); /* Both strings empty. */ + (void) strcpy(one, "abcabdea"); + check(strpbrk(one, "befg") == one+1, 14); /* Finding first. */ + check(strpbrk(one, "cbr") == one+1, 15); /* With multiple search. */ + check(strpbrk(one, "db") == one+1, 16); /* Another variant. */ + check(strpbrk(one, "efgh") == one+6, 17); /* And yet another. */ +} + +static void +test_strstr (void) +{ + it = "strstr"; + check(strstr("abcd", "z") == NULL, 1); /* Not found. */ + check(strstr("abcd", "abx") == NULL, 2); /* Dead end. */ + (void) strcpy(one, "abcd"); + check(strstr(one, "c") == one+2, 3); /* Basic test. */ + check(strstr(one, "bc") == one+1, 4); /* Multichar. */ + check(strstr(one, "d") == one+3, 5); /* End of string. */ + check(strstr(one, "cd") == one+2, 6); /* Tail of string. */ + check(strstr(one, "abc") == one, 7); /* Beginning. */ + check(strstr(one, "abcd") == one, 8); /* Exact match. */ + check(strstr(one, "abcde") == NULL, 9); /* Too long. */ + check(strstr(one, "de") == NULL, 10); /* Past end. */ + check(strstr(one, "") == one, 11); /* Finding empty. */ + (void) strcpy(one, "ababa"); + check(strstr(one, "ba") == one+1, 12); /* Finding first. */ + (void) strcpy(one, ""); + check(strstr(one, "b") == NULL, 13); /* Empty string. */ + check(strstr(one, "") == one, 14); /* Empty in empty string. */ + (void) strcpy(one, "bcbca"); + check(strstr(one, "bca") == one+2, 15); /* False start. */ + (void) strcpy(one, "bbbcabbca"); + check(strstr(one, "bbca") == one+1, 16); /* With overlap. */ +} + +static void +test_strspn (void) +{ + it = "strspn"; + check(strspn("abcba", "abc") == 5, 1); /* Whole string. */ + check(strspn("abcba", "ab") == 2, 2); /* Partial. */ + check(strspn("abc", "qx") == 0, 3); /* None. */ + check(strspn("", "ab") == 0, 4); /* Null string. */ + check(strspn("abc", "") == 0, 5); /* Null search list. */ +} + +static void +test_strcspn (void) +{ + it = "strcspn"; + check(strcspn("abcba", "qx") == 5, 1); /* Whole string. */ + check(strcspn("abcba", "cx") == 2, 2); /* Partial. */ + check(strcspn("abc", "abc") == 0, 3); /* None. */ + check(strcspn("", "ab") == 0, 4); /* Null string. */ + check(strcspn("abc", "") == 3, 5); /* Null search list. */ +} + +static void +test_strtok (void) +{ + it = "strtok"; + (void) strcpy(one, "first, second, third"); + equal(strtok(one, ", "), "first", 1); /* Basic test. */ + equal(one, "first", 2); + equal(strtok((char *)NULL, ", "), "second", 3); + equal(strtok((char *)NULL, ", "), "third", 4); + check(strtok((char *)NULL, ", ") == NULL, 5); + (void) strcpy(one, ", first, "); + equal(strtok(one, ", "), "first", 6); /* Extra delims, 1 tok. */ + check(strtok((char *)NULL, ", ") == NULL, 7); + (void) strcpy(one, "1a, 1b; 2a, 2b"); + equal(strtok(one, ", "), "1a", 8); /* Changing delim lists. */ + equal(strtok((char *)NULL, "; "), "1b", 9); + equal(strtok((char *)NULL, ", "), "2a", 10); + (void) strcpy(two, "x-y"); + equal(strtok(two, "-"), "x", 11); /* New string before done. */ + equal(strtok((char *)NULL, "-"), "y", 12); + check(strtok((char *)NULL, "-") == NULL, 13); + (void) strcpy(one, "a,b, c,, ,d"); + equal(strtok(one, ", "), "a", 14); /* Different separators. */ + equal(strtok((char *)NULL, ", "), "b", 15); + equal(strtok((char *)NULL, " ,"), "c", 16); /* Permute list too. */ + equal(strtok((char *)NULL, " ,"), "d", 17); + check(strtok((char *)NULL, ", ") == NULL, 18); + check(strtok((char *)NULL, ", ") == NULL, 19); /* Persistence. */ + (void) strcpy(one, ", "); + check(strtok(one, ", ") == NULL, 20); /* No tokens. */ + (void) strcpy(one, ""); + check(strtok(one, ", ") == NULL, 21); /* Empty string. */ + (void) strcpy(one, "abc"); + equal(strtok(one, ", "), "abc", 22); /* No delimiters. */ + check(strtok((char *)NULL, ", ") == NULL, 23); + (void) strcpy(one, "abc"); + equal(strtok(one, ""), "abc", 24); /* Empty delimiter list. */ + check(strtok((char *)NULL, "") == NULL, 25); + (void) strcpy(one, "abcdefgh"); + (void) strcpy(one, "a,b,c"); + equal(strtok(one, ","), "a", 26); /* Basics again... */ + equal(strtok((char *)NULL, ","), "b", 27); + equal(strtok((char *)NULL, ","), "c", 28); + check(strtok((char *)NULL, ",") == NULL, 29); + equal(one+6, "gh", 30); /* Stomped past end? */ + equal(one, "a", 31); /* Stomped old tokens? */ + equal(one+2, "b", 32); + equal(one+4, "c", 33); +} + +static void +test_strtok_r (void) +{ + it = "strtok_r"; + (void) strcpy(one, "first, second, third"); + cp = NULL; /* Always initialize cp to make sure it doesn't point to some old data. */ + equal(strtok_r(one, ", ", &cp), "first", 1); /* Basic test. */ + equal(one, "first", 2); + equal(strtok_r((char *)NULL, ", ", &cp), "second", 3); + equal(strtok_r((char *)NULL, ", ", &cp), "third", 4); + check(strtok_r((char *)NULL, ", ", &cp) == NULL, 5); + (void) strcpy(one, ", first, "); + cp = NULL; + equal(strtok_r(one, ", ", &cp), "first", 6); /* Extra delims, 1 tok. */ + check(strtok_r((char *)NULL, ", ", &cp) == NULL, 7); + (void) strcpy(one, "1a, 1b; 2a, 2b"); + cp = NULL; + equal(strtok_r(one, ", ", &cp), "1a", 8); /* Changing delim lists. */ + equal(strtok_r((char *)NULL, "; ", &cp), "1b", 9); + equal(strtok_r((char *)NULL, ", ", &cp), "2a", 10); + (void) strcpy(two, "x-y"); + cp = NULL; + equal(strtok_r(two, "-", &cp), "x", 11); /* New string before done. */ + equal(strtok_r((char *)NULL, "-", &cp), "y", 12); + check(strtok_r((char *)NULL, "-", &cp) == NULL, 13); + (void) strcpy(one, "a,b, c,, ,d"); + cp = NULL; + equal(strtok_r(one, ", ", &cp), "a", 14); /* Different separators. */ + equal(strtok_r((char *)NULL, ", ", &cp), "b", 15); + equal(strtok_r((char *)NULL, " ,", &cp), "c", 16); /* Permute list too. */ + equal(strtok_r((char *)NULL, " ,", &cp), "d", 17); + check(strtok_r((char *)NULL, ", ", &cp) == NULL, 18); + check(strtok_r((char *)NULL, ", ", &cp) == NULL, 19); /* Persistence. */ + (void) strcpy(one, ", "); + cp = NULL; + check(strtok_r(one, ", ", &cp) == NULL, 20); /* No tokens. */ + (void) strcpy(one, ""); + cp = NULL; + check(strtok_r(one, ", ", &cp) == NULL, 21); /* Empty string. */ + check(strtok_r((char *)NULL, ", ", &cp) == NULL, 22); /* Persistence. */ + (void) strcpy(one, "abc"); + cp = NULL; + equal(strtok_r(one, ", ", &cp), "abc", 23); /* No delimiters. */ + check(strtok_r((char *)NULL, ", ", &cp) == NULL, 24); + (void) strcpy(one, "abc"); + cp = NULL; + equal(strtok_r(one, "", &cp), "abc", 25); /* Empty delimiter list. */ + check(strtok_r((char *)NULL, "", &cp) == NULL, 26); + (void) strcpy(one, "abcdefgh"); + (void) strcpy(one, "a,b,c"); + cp = NULL; + equal(strtok_r(one, ",", &cp), "a", 27); /* Basics again... */ + equal(strtok_r((char *)NULL, ",", &cp), "b", 28); + equal(strtok_r((char *)NULL, ",", &cp), "c", 29); + check(strtok_r((char *)NULL, ",", &cp) == NULL, 30); + equal(one+6, "gh", 31); /* Stomped past end? */ + equal(one, "a", 32); /* Stomped old tokens? */ + equal(one+2, "b", 33); + equal(one+4, "c", 34); + strcpy (one, ":::"); + cp = NULL; + check (strtok_r (one, ":", &cp) == NULL, 35); /* Must store pointer in cp. */ + check (strtok_r (NULL, ":", &cp) == NULL, 36); +} + +static void +test_strsep (void) +{ + char *ptr; + it = "strsep"; + cp = strcpy(one, "first, second, third"); + equal(strsep(&cp, ", "), "first", 1); /* Basic test. */ + equal(one, "first", 2); + equal(strsep(&cp, ", "), "", 3); + equal(strsep(&cp, ", "), "second", 4); + equal(strsep(&cp, ", "), "", 5); + equal(strsep(&cp, ", "), "third", 6); + check(strsep(&cp, ", ") == NULL, 7); + cp = strcpy(one, ", first, "); + equal(strsep(&cp, ", "), "", 8); + equal(strsep(&cp, ", "), "", 9); + equal(strsep(&cp, ", "), "first", 10); /* Extra delims, 1 tok. */ + equal(strsep(&cp, ", "), "", 11); + equal(strsep(&cp, ", "), "", 12); + check(strsep(&cp, ", ") == NULL, 13); + cp = strcpy(one, "1a, 1b; 2a, 2b"); + equal(strsep(&cp, ", "), "1a", 14); /* Changing delim lists. */ + equal(strsep(&cp, ", "), "", 15); + equal(strsep(&cp, "; "), "1b", 16); + equal(strsep(&cp, ", "), "", 17); + equal(strsep(&cp, ", "), "2a", 18); + cp = strcpy(two, "x-y"); + equal(strsep(&cp, "-"), "x", 19); /* New string before done. */ + equal(strsep(&cp, "-"), "y", 20); + check(strsep(&cp, "-") == NULL, 21); + cp = strcpy(one, "a,b, c,, ,d "); + equal(strsep(&cp, ", "), "a", 22); /* Different separators. */ + equal(strsep(&cp, ", "), "b", 23); + equal(strsep(&cp, " ,"), "", 24); + equal(strsep(&cp, " ,"), "c", 25); /* Permute list too. */ + equal(strsep(&cp, " ,"), "", 26); + equal(strsep(&cp, " ,"), "", 27); + equal(strsep(&cp, " ,"), "", 28); + equal(strsep(&cp, " ,"), "d", 29); + equal(strsep(&cp, " ,"), "", 30); + check(strsep(&cp, ", ") == NULL, 31); + check(strsep(&cp, ", ") == NULL, 32); /* Persistence. */ + cp = strcpy(one, ", "); + equal(strsep(&cp, ", "), "", 33); + equal(strsep(&cp, ", "), "", 34); + equal(strsep(&cp, ", "), "", 35); + check(strsep(&cp, ", ") == NULL, 36); /* No tokens. */ + cp = strcpy(one, ""); + equal(strsep(&cp, ", "), "", 37); + check(strsep(&cp, ", ") == NULL, 38); /* Empty string. */ + cp = strcpy(one, "abc"); + equal(strsep(&cp, ", "), "abc", 39); /* No delimiters. */ + check(strsep(&cp, ", ") == NULL, 40); + cp = strcpy(one, "abc"); + equal(strsep(&cp, ""), "abc", 41); /* Empty delimiter list. */ + check(strsep(&cp, "") == NULL, 42); + (void) strcpy(one, "abcdefgh"); + cp = strcpy(one, "a,b,c"); + equal(strsep(&cp, ","), "a", 43); /* Basics again... */ + equal(strsep(&cp, ","), "b", 44); + equal(strsep(&cp, ","), "c", 45); + check(strsep(&cp, ",") == NULL, 46); + equal(one+6, "gh", 47); /* Stomped past end? */ + equal(one, "a", 48); /* Stomped old tokens? */ + equal(one+2, "b", 49); + equal(one+4, "c", 50); + + { + char text[] = "This,is,a,test"; + char *list = strdupa (text); + equal (strsep (&list, ","), "This", 51); + equal (strsep (&list, ","), "is", 52); + equal (strsep (&list, ","), "a", 53); + equal (strsep (&list, ","), "test", 54); + check (strsep (&list, ",") == NULL, 55); + } + + cp = strcpy(one, "a,b, c,, ,d,"); + equal(strsep(&cp, ","), "a", 56); /* Different separators. */ + equal(strsep(&cp, ","), "b", 57); + equal(strsep(&cp, ","), " c", 58); /* Permute list too. */ + equal(strsep(&cp, ","), "", 59); + equal(strsep(&cp, ","), " ", 60); + equal(strsep(&cp, ","), "d", 61); + equal(strsep(&cp, ","), "", 62); + check(strsep(&cp, ",") == NULL, 63); + check(strsep(&cp, ",") == NULL, 64); /* Persistence. */ + + cp = strcpy(one, "a,b, c,, ,d,"); + equal(strsep(&cp, "xy,"), "a", 65); /* Different separators. */ + equal(strsep(&cp, "x,y"), "b", 66); + equal(strsep(&cp, ",xy"), " c", 67); /* Permute list too. */ + equal(strsep(&cp, "xy,"), "", 68); + equal(strsep(&cp, "x,y"), " ", 69); + equal(strsep(&cp, ",xy"), "d", 70); + equal(strsep(&cp, "xy,"), "", 71); + check(strsep(&cp, "x,y") == NULL, 72); + check(strsep(&cp, ",xy") == NULL, 73); /* Persistence. */ + + cp = strcpy(one, "ABC"); + one[4] = ':'; + equal(strsep(&cp, "C"), "AB", 74); /* Access beyond NUL. */ + ptr = strsep(&cp, ":"); + equal(ptr, "", 75); + check(ptr == one + 3, 76); + check(cp == NULL, 77); + + cp = strcpy(one, "ABC"); + one[4] = ':'; + equal(strsep(&cp, "CD"), "AB", 78); /* Access beyond NUL. */ + ptr = strsep(&cp, ":."); + equal(ptr, "", 79); + check(ptr == one + 3, 80); + + cp = strcpy(one, "ABC"); /* No token in string. */ + equal(strsep(&cp, ","), "ABC", 81); + check(cp == NULL, 82); + + *one = '\0'; /* Empty string. */ + cp = one; + ptr = strsep(&cp, ","); + equal(ptr, "", 83); + check(ptr == one, 84); + check(cp == NULL, 85); + + *one = '\0'; /* Empty string and no token. */ + cp = one; + ptr = strsep(&cp, ""); + equal(ptr, "", 86); + check(ptr == one , 87); + check(cp == NULL, 88); +} + +static void +test_memcmp (void) +{ + int cnt = 1; + char one[21]; + char two[21]; + + it = "memcmp"; + check(memcmp("a", "a", 1) == 0, cnt++); /* Identity. */ + check(memcmp("abc", "abc", 3) == 0, cnt++); /* Multicharacter. */ + check(memcmp("abcd", "abcf", 4) < 0, cnt++); /* Honestly unequal. */ + check(memcmp("abcf", "abcd", 4) > 0, cnt++); + check(memcmp("alph", "cold", 4) < 0, cnt++); + check(memcmp("a\203", "a\003", 2) > 0, cnt++); + check(memcmp("a\003", "a\203", 2) < 0, cnt++); + check(memcmp("a\003bc", "a\203bc", 2) < 0, cnt++); + check(memcmp("abc\203", "abc\003", 4) > 0, cnt++); + check(memcmp("abc\003", "abc\203", 4) < 0, cnt++); + check(memcmp("abcf", "abcd", 3) == 0, cnt++); /* Count limited. */ + check(memcmp("abc", "def", 0) == 0, cnt++); /* Zero count. */ + /* Comparisons with shifting 4-byte boundaries. */ + for (int i = 0; i < 4; ++i) + { + char *a = one + i; + char *b = two + i; + strncpy(a, "--------11112222", 16); + strncpy(b, "--------33334444", 16); + check(memcmp(b, a, 16) > 0, cnt++); + check(memcmp(a, b, 16) < 0, cnt++); + } +} + +static void +test_memchr (void) +{ + it = "memchr"; + check(memchr("abcd", 'z', 4) == NULL, 1); /* Not found. */ + (void) strcpy(one, "abcd"); + check(memchr(one, 'c', 4) == one+2, 2); /* Basic test. */ + check(memchr(one, ~0xff|'c', 4) == one+2, 2); /* ignore highorder bits. */ + check(memchr(one, 'd', 4) == one+3, 3); /* End of string. */ + check(memchr(one, 'a', 4) == one, 4); /* Beginning. */ + check(memchr(one, '\0', 5) == one+4, 5); /* Finding NUL. */ + (void) strcpy(one, "ababa"); + check(memchr(one, 'b', 5) == one+1, 6); /* Finding first. */ + check(memchr(one, 'b', 0) == NULL, 7); /* Zero count. */ + check(memchr(one, 'a', 1) == one, 8); /* Singleton case. */ + (void) strcpy(one, "a\203b"); + check(memchr(one, 0203, 3) == one+1, 9); /* Unsignedness. */ + + /* now test all possible alignment and length combinations to catch + bugs due to unrolled loops (assuming unrolling is limited to no + more than 128 byte chunks: */ + { + char buf[128 + sizeof(long)]; + long align, len, i, pos; + + for (align = 0; align < (long) sizeof(long); ++align) { + for (len = 0; len < (long) (sizeof(buf) - align); ++len) { + for (i = 0; i < len; ++i) { + buf[align + i] = 'x'; /* don't depend on memset... */ + } + for (pos = 0; pos < len; ++pos) { +#if 0 + printf("align %d, len %d, pos %d\n", align, len, pos); +#endif + check(memchr(buf + align, 'x', len) == buf + align + pos, 10); + check(memchr(buf + align, 'x', pos) == NULL, 11); + buf[align + pos] = '-'; + } + } + } + } +} + +static void +test_memcpy (void) +{ + int i; + it = "memcpy"; + check(memcpy(one, "abc", 4) == one, 1); /* Returned value. */ + equal(one, "abc", 2); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) memcpy(one+1, "xyz", 2); + equal(one, "axydefgh", 3); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) memcpy(one, "xyz", 0); + equal(one, "abc", 4); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) memcpy(two, one, 9); + equal(two, "hi there", 5); /* Just paranoia. */ + equal(one, "hi there", 6); /* Stomped on source? */ + + for (i = 0; i < 16; i++) + { + const char *x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + strcpy (one, x); + check (memcpy (one + i, "hi there", 9) == one + i, + 7 + (i * 6)); /* Unaligned destination. */ + check (memcmp (one, x, i) == 0, 8 + (i * 6)); /* Wrote under? */ + equal (one + i, "hi there", 9 + (i * 6)); + check (one[i + 9] == 'x', 10 + (i * 6)); /* Wrote over? */ + check (memcpy (two, one + i, 9) == two, + 11 + (i * 6)); /* Unaligned source. */ + equal (two, "hi there", 12 + (i * 6)); + } +} + +static void +test_mempcpy (void) +{ + int i; + it = "mempcpy"; + check(mempcpy(one, "abc", 4) == one + 4, 1); /* Returned value. */ + equal(one, "abc", 2); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) mempcpy(one+1, "xyz", 2); + equal(one, "axydefgh", 3); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) mempcpy(one, "xyz", 0); + equal(one, "abc", 4); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) mempcpy(two, one, 9); + equal(two, "hi there", 5); /* Just paranoia. */ + equal(one, "hi there", 6); /* Stomped on source? */ + + for (i = 0; i < 16; i++) + { + const char *x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + strcpy (one, x); + check (mempcpy (one + i, "hi there", 9) == one + i + 9, + 7 + (i * 6)); /* Unaligned destination. */ + check (memcmp (one, x, i) == 0, 8 + (i * 6)); /* Wrote under? */ + equal (one + i, "hi there", 9 + (i * 6)); + check (one[i + 9] == 'x', 10 + (i * 6)); /* Wrote over? */ + check (mempcpy (two, one + i, 9) == two + 9, + 11 + (i * 6)); /* Unaligned source. */ + equal (two, "hi there", 12 + (i * 6)); + } +} + +static void +test_memmove (void) +{ + it = "memmove"; + check(memmove(one, "abc", 4) == one, 1); /* Returned value. */ + equal(one, "abc", 2); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one+1, "xyz", 2); + equal(one, "axydefgh", 3); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) memmove(one, "xyz", 0); + equal(one, "abc", 4); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) memmove(two, one, 9); + equal(two, "hi there", 5); /* Just paranoia. */ + equal(one, "hi there", 6); /* Stomped on source? */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one+1, one, 9); + equal(one, "aabcdefgh", 7); /* Overlap, right-to-left. */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one+1, one+2, 7); + equal(one, "acdefgh", 8); /* Overlap, left-to-right. */ + + (void) strcpy(one, "abcdefgh"); + (void) memmove(one, one, 9); + equal(one, "abcdefgh", 9); /* 100% overlap. */ +} + +static void +test_memccpy (void) +{ + /* First test like memcpy, then the search part The SVID, the only + place where memccpy is mentioned, says overlap might fail, so we + don't try it. Besides, it's hard to see the rationale for a + non-left-to-right memccpy. */ + it = "memccpy"; + check(memccpy(one, "abc", 'q', 4) == NULL, 1); /* Returned value. */ + equal(one, "abc", 2); /* Did the copy go right? */ + + (void) strcpy(one, "abcdefgh"); + (void) memccpy(one+1, "xyz", 'q', 2); + equal(one, "axydefgh", 3); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) memccpy(one, "xyz", 'q', 0); + equal(one, "abc", 4); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) memccpy(two, one, 'q', 9); + equal(two, "hi there", 5); /* Just paranoia. */ + equal(one, "hi there", 6); /* Stomped on source? */ + + (void) strcpy(one, "abcdefgh"); + (void) strcpy(two, "horsefeathers"); + check(memccpy(two, one, 'f', 9) == two+6, 7); /* Returned value. */ + equal(one, "abcdefgh", 8); /* Source intact? */ + equal(two, "abcdefeathers", 9); /* Copy correct? */ + + (void) strcpy(one, "abcd"); + (void) strcpy(two, "bumblebee"); + check(memccpy(two, one, 'a', 4) == two+1, 10); /* First char. */ + equal(two, "aumblebee", 11); + check(memccpy(two, one, 'd', 4) == two+4, 12); /* Last char. */ + equal(two, "abcdlebee", 13); + (void) strcpy(one, "xyz"); + check(memccpy(two, one, 'x', 1) == two+1, 14); /* Singleton. */ + equal(two, "xbcdlebee", 15); +} + +static void +test_memset (void) +{ + int i; + + it = "memset"; + (void) strcpy(one, "abcdefgh"); + check(memset(one+1, 'x', 3) == one+1, 1); /* Return value. */ + equal(one, "axxxefgh", 2); /* Basic test. */ + + DIAG_PUSH_NEEDS_COMMENT; +#if __GNUC_PREREQ (5, 0) + /* GCC 5.0 warns about a zero-length memset because the arguments to memset + may be in the wrong order. But we really want to test this. */ + DIAG_IGNORE_NEEDS_COMMENT (5.0, "-Wmemset-transposed-args") +#endif + (void) memset(one+2, 'y', 0); + equal(one, "axxxefgh", 3); /* Zero-length set. */ + DIAG_POP_NEEDS_COMMENT; + + (void) memset(one+5, 0, 1); + equal(one, "axxxe", 4); /* Zero fill. */ + equal(one+6, "gh", 5); /* And the leftover. */ + + (void) memset(one+2, 010045, 1); + equal(one, "ax\045xe", 6); /* Unsigned char convert. */ + + /* Non-8bit fill character. */ + memset (one, 0x101, sizeof (one)); + for (i = 0; i < (int) sizeof (one); ++i) + check (one[i] == '\01', 7); + + /* Test for more complex versions of memset, for all alignments and + lengths up to 256. This test takes a little while, perhaps it should + be made weaker? */ + { + char data[512]; + int j; + int k; + int c; + + for (i = 0; i < 512; i++) + data[i] = 'x'; + for (c = 0; c <= 'y'; c += 'y') /* check for memset(,0,) and + memset(,'y',) */ + for (j = 0; j < 256; j++) + for (i = 0; i < 256; i++) + { + memset (data + i, c, j); + for (k = 0; k < i; k++) + if (data[k] != 'x') + goto fail; + for (k = i; k < i+j; k++) + { + if (data[k] != c) + goto fail; + data[k] = 'x'; + } + for (k = i+j; k < 512; k++) + if (data[k] != 'x') + goto fail; + continue; + + fail: + check (0, 8 + i + j * 256 + (c != 0) * 256 * 256); + } + } +} + +static void +test_bcopy (void) +{ + /* Much like memcpy. Berklix manual is silent about overlap, so + don't test it. */ + it = "bcopy"; + (void) bcopy("abc", one, 4); + equal(one, "abc", 1); /* Simple copy. */ + + (void) strcpy(one, "abcdefgh"); + (void) bcopy("xyz", one+1, 2); + equal(one, "axydefgh", 2); /* Basic test. */ + + (void) strcpy(one, "abc"); + (void) bcopy("xyz", one, 0); + equal(one, "abc", 3); /* Zero-length copy. */ + + (void) strcpy(one, "hi there"); + (void) strcpy(two, "foo"); + (void) bcopy(one, two, 9); + equal(two, "hi there", 4); /* Just paranoia. */ + equal(one, "hi there", 5); /* Stomped on source? */ +} + +static void +test_bzero (void) +{ + it = "bzero"; + (void) strcpy(one, "abcdef"); + bzero(one+2, 2); + equal(one, "ab", 1); /* Basic test. */ + equal(one+3, "", 2); + equal(one+4, "ef", 3); + + (void) strcpy(one, "abcdef"); + bzero(one+2, 0); + equal(one, "abcdef", 4); /* Zero-length copy. */ +} + +static void +test_strndup (void) +{ + char *p, *q; + it = "strndup"; + p = strndup("abcdef", 12); + check(p != NULL, 1); + if (p != NULL) + { + equal(p, "abcdef", 2); + q = strndup(p + 1, 2); + check(q != NULL, 3); + if (q != NULL) + equal(q, "bc", 4); + free (q); + } + free (p); + p = strndup("abc def", 3); + check(p != NULL, 5); + if (p != NULL) + equal(p, "abc", 6); + free (p); +} + +static void +test_bcmp (void) +{ + it = "bcmp"; + check(bcmp("a", "a", 1) == 0, 1); /* Identity. */ + check(bcmp("abc", "abc", 3) == 0, 2); /* Multicharacter. */ + check(bcmp("abcd", "abce", 4) != 0, 3); /* Honestly unequal. */ + check(bcmp("abce", "abcd", 4) != 0, 4); + check(bcmp("alph", "beta", 4) != 0, 5); + check(bcmp("abce", "abcd", 3) == 0, 6); /* Count limited. */ + check(bcmp("abc", "def", 0) == 0, 8); /* Zero count. */ +} + +static void +test_strerror (void) +{ + it = "strerror"; + check(strerror(EDOM) != 0, 1); + check(strerror(ERANGE) != 0, 2); + check(strerror(ENOENT) != 0, 3); +} + +static void +test_strcasecmp (void) +{ + it = "strcasecmp"; + /* Note that the locale is "C". */ + check(strcasecmp("a", "a") == 0, 1); + check(strcasecmp("a", "A") == 0, 2); + check(strcasecmp("A", "a") == 0, 3); + check(strcasecmp("a", "b") < 0, 4); + check(strcasecmp("c", "b") > 0, 5); + check(strcasecmp("abc", "AbC") == 0, 6); + check(strcasecmp("0123456789", "0123456789") == 0, 7); + check(strcasecmp("", "0123456789") < 0, 8); + check(strcasecmp("AbC", "") > 0, 9); + check(strcasecmp("AbC", "A") > 0, 10); + check(strcasecmp("AbC", "Ab") > 0, 11); + check(strcasecmp("AbC", "ab") > 0, 12); +} + +static void +test_strncasecmp (void) +{ + it = "strncasecmp"; + /* Note that the locale is "C". */ + check(strncasecmp("a", "a", 5) == 0, 1); + check(strncasecmp("a", "A", 5) == 0, 2); + check(strncasecmp("A", "a", 5) == 0, 3); + check(strncasecmp("a", "b", 5) < 0, 4); + check(strncasecmp("c", "b", 5) > 0, 5); + check(strncasecmp("abc", "AbC", 5) == 0, 6); + check(strncasecmp("0123456789", "0123456789", 10) == 0, 7); + check(strncasecmp("", "0123456789", 10) < 0, 8); + check(strncasecmp("AbC", "", 5) > 0, 9); + check(strncasecmp("AbC", "A", 5) > 0, 10); + check(strncasecmp("AbC", "Ab", 5) > 0, 11); + check(strncasecmp("AbC", "ab", 5) > 0, 12); + check(strncasecmp("0123456789", "AbC", 0) == 0, 13); + check(strncasecmp("AbC", "abc", 1) == 0, 14); + check(strncasecmp("AbC", "abc", 2) == 0, 15); + check(strncasecmp("AbC", "abc", 3) == 0, 16); + check(strncasecmp("AbC", "abcd", 3) == 0, 17); + check(strncasecmp("AbC", "abcd", 4) < 0, 18); + check(strncasecmp("ADC", "abcd", 1) == 0, 19); + check(strncasecmp("ADC", "abcd", 2) > 0, 20); +} + +int +main (void) +{ + int status; + + /* Test strcmp first because we use it to test other things. */ + test_strcmp (); + + /* Test strcpy next because we need it to set up other tests. */ + test_strcpy (); + + /* A closely related function is stpcpy. */ + test_stpcpy (); + + /* stpncpy. */ + test_stpncpy (); + + /* strcat. */ + test_strcat (); + + /* strncat. */ + test_strncat (); + + /* strncmp. */ + test_strncmp (); + + /* strncpy. */ + test_strncpy (); + + /* strlen. */ + test_strlen (); + + /* strnlen. */ + test_strnlen (); + + /* strchr. */ + test_strchr (); + + /* strchrnul. */ + test_strchrnul (); + + /* rawmemchr. */ + test_rawmemchr (); + + /* index - just like strchr. */ + test_index (); + + /* strrchr. */ + test_strrchr (); + + /* memrchr. */ + test_memrchr (); + + /* rindex - just like strrchr. */ + test_rindex (); + + /* strpbrk - somewhat like strchr. */ + test_strpbrk (); + + /* strstr - somewhat like strchr. */ + test_strstr (); + + /* strspn. */ + test_strspn (); + + /* strcspn. */ + test_strcspn (); + + /* strtok - the hard one. */ + test_strtok (); + + /* strtok_r. */ + test_strtok_r (); + + /* strsep. */ + test_strsep (); + + /* memcmp. */ + test_memcmp (); + + /* memchr. */ + test_memchr (); + + /* memcpy - need not work for overlap. */ + test_memcpy (); + + /* memmove - must work on overlap. */ + test_memmove (); + + /* mempcpy */ + test_mempcpy (); + + /* memccpy. */ + test_memccpy (); + + /* memset. */ + test_memset (); + + /* bcopy. */ + test_bcopy (); + + /* bzero. */ + test_bzero (); + + /* bcmp - somewhat like memcmp. */ + test_bcmp (); + + /* strndup. */ + test_strndup (); + + /* strerror - VERY system-dependent. */ + test_strerror (); + + /* strcasecmp. Without locale dependencies. */ + test_strcasecmp (); + + /* strncasecmp. Without locale dependencies. */ + test_strncasecmp (); + + if (errors == 0) + { + status = EXIT_SUCCESS; + puts("No errors."); + } + else + { + status = EXIT_FAILURE; + printf("%Zd errors.\n", errors); + } + + return status; +} diff --git a/REORG.TODO/string/tst-bswap.c b/REORG.TODO/string/tst-bswap.c new file mode 100644 index 0000000000..def6e2f28a --- /dev/null +++ b/REORG.TODO/string/tst-bswap.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2000-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>. + + 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, see + <http://www.gnu.org/licenses/>. */ + +#include <byteswap.h> +#include <stdio.h> + +extern unsigned long long int wash (unsigned long long int a); + +int +do_test (void) +{ + int result = 0; + + /* Test the functions with constant arguments. */ + if (bswap_16 (0x1234) != 0x3412) + { + puts ("bswap_16 (constant) flunked"); + result = 1; + } + if (bswap_32 (0x12345678) != 0x78563412) + { + puts ("bswap_32 (constant) flunked"); + result = 1; + } + if (bswap_64 (0x1234567890abcdefULL) != 0xefcdab9078563412ULL) + { + puts ("bswap_64 (constant) flunked"); + result = 1; + } + + /* Test the functions with non-constant arguments. */ + if (bswap_16 (wash (0x1234)) != 0x3412) + { + puts ("bswap_16 (non-constant) flunked"); + result = 1; + } + if (bswap_32 (wash (0x12345678)) != 0x78563412) + { + puts ("bswap_32 (non-constant) flunked"); + result = 1; + } + if (bswap_64 (wash (0x1234567890abcdefULL)) != 0xefcdab9078563412ULL) + { + puts ("bswap_64 (non-constant) flunked"); + result = 1; + } + + return result; +} + + +unsigned long long int +wash (unsigned long long int a) +{ + /* Do nothing. This function simply exists to avoid that the compiler + regards the argument to the bswap_*() functions as constant. */ + return a + 0; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-cmp.c b/REORG.TODO/string/tst-cmp.c new file mode 100644 index 0000000000..d7720194e9 --- /dev/null +++ b/REORG.TODO/string/tst-cmp.c @@ -0,0 +1,212 @@ +/* Alignment/padding coverage test for string comparison. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* This performs test comparisons with various (mis)alignments and + characters in the padding. It is partly a regression test for bug + 20327. */ + +#include <limits.h> +#include <malloc.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +static int +signum (int val) +{ + if (val < 0) + return -1; + if (val > 0) + return 1; + else + return 0; +} + +static size_t +max_size_t (size_t left, size_t right) +{ + if (left > right) + return left; + else + return right; +} + +/* Wrappers for strncmp and strncasecmp which determine the maximum + string length in some, either based on the input string length, or + using fixed constants. */ + +static int +strncmp_no_terminator (const char *left, const char *right) +{ + size_t left_len = strlen (left); + size_t right_len = strlen (right); + return strncmp (left, right, max_size_t (left_len, right_len)); +} + +static int +strncasecmp_no_terminator (const char *left, const char *right) +{ + size_t left_len = strlen (left); + size_t right_len = strlen (right); + return strncasecmp (left, right, max_size_t (left_len, right_len)); +} + +static int +strncmp_terminator (const char *left, const char *right) +{ + size_t left_len = strlen (left); + size_t right_len = strlen (right); + return strncmp (left, right, max_size_t (left_len, right_len)); +} + +static int +strncasecmp_terminator (const char *left, const char *right) +{ + size_t left_len = strlen (left); + size_t right_len = strlen (right); + return strncasecmp (left, right, max_size_t (left_len, right_len)); +} + +static int +strncmp_64 (const char *left, const char *right) +{ + return strncmp (left, right, 64); +} + +static int +strncasecmp_64 (const char *left, const char *right) +{ + return strncasecmp (left, right, 64); +} + +static int +strncmp_max (const char *left, const char *right) +{ + return strncmp (left, right, SIZE_MAX); +} + +static int +strncasecmp_max (const char *left, const char *right) +{ + return strncasecmp (left, right, SIZE_MAX); +} + +int +do_test (void) +{ + enum { + max_align = 64, + max_string_length = 33 + }; + size_t blob_size = max_align + max_string_length + 1; + char *left = memalign (max_align, blob_size); + char *right = memalign (max_align, blob_size); + if (left == NULL || right == NULL) + { + printf ("error: out of memory\n"); + return 1; + } + + const struct + { + const char *name; + int (*implementation) (const char *, const char *); + } functions[] = + { + { "strcmp", strcmp }, + { "strcasecmp", strcasecmp }, + { "strncmp (without NUL)", strncmp_no_terminator}, + { "strncasecmp (without NUL)", strncasecmp_no_terminator}, + { "strncmp (with NUL)", strncmp_terminator}, + { "strncasecmp (with NUL)", strncasecmp_terminator}, + { "strncmp (length 64)", strncmp_64}, + { "strncasecmp (length 64)", strncasecmp_64}, + { "strncmp (length SIZE_MAX)", strncmp_max}, + { "strncasecmp (length SIZE_MAX)", strncasecmp_max}, + { NULL, NULL } + }; + const char *const strings[] = + { + "", + "0", + "01", + "01234567", + "0123456789abcde", + "0123456789abcdef", + "0123456789abcdefg", + "1", + "10", + "123456789abcdef", + "123456789abcdefg", + "23456789abcdef", + "23456789abcdefg", + "abcdefghijklmnopqrstuvwxyzABCDEF", + NULL + }; + const unsigned char pads[] = + { 0, 1, 32, 64, 128, '0', '1', 'e', 'f', 'g', 127, 192, 255 }; + + bool errors = false; + for (int left_idx = 0; strings[left_idx] != NULL; ++left_idx) + for (int left_align = 0; left_align < max_align; ++left_align) + for (unsigned pad_left = 0; pad_left < sizeof (pads); ++pad_left) + { + memset (left, pads[pad_left], blob_size); + strcpy (left + left_align, strings[left_idx]); + + for (int right_idx = 0; strings[right_idx] != NULL; ++right_idx) + for (unsigned pad_right = 0; pad_right < sizeof (pads); + ++pad_right) + for (int right_align = 0; right_align < max_align; + ++right_align) + { + memset (right, pads[pad_right], blob_size); + strcpy (right + right_align, strings[right_idx]); + + for (int func = 0; functions[func].name != NULL; ++func) + { + int expected = left_idx - right_idx; + int actual = functions[func].implementation + (left + left_align, right + right_align); + if (signum (actual) != signum (expected)) + { + printf ("error: mismatch for %s: %d\n" + " left: \"%s\"\n" + " right: \"%s\"\n" + " pad_left = %u, pad_right = %u,\n" + " left_align = %d, right_align = %d\n", + functions[func].name, actual, + strings[left_idx], strings[right_idx], + pad_left, pad_right, + left_align, right_align); + errors = true; + } + } + } + } + free (right); + free (left); + return errors; +} + +/* The nested loops need a long time to complete on slower + machines. */ +#define TIMEOUT 300 + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-endian.c b/REORG.TODO/string/tst-endian.c new file mode 100644 index 0000000000..b156ede199 --- /dev/null +++ b/REORG.TODO/string/tst-endian.c @@ -0,0 +1,134 @@ +#include <byteswap.h> +#include <endian.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdint.h> +#include <libc-diag.h> + +#if __GNUC_PREREQ (6, 0) +/* GCC 6.0 warns on big endian systems about: + htobeXX (beXXtoh (i)) != i + warning: self-comparison always evaluates to false [-Wtautological-compare] + because htobeXX(x) and beXXtoh(x) is defined to (x) + in string/endian.h on big endian systems. + The same applies to htoleXX/leXXtoh on little endian systems. */ +# define DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE() \ + DIAG_IGNORE_NEEDS_COMMENT (6, "-Wtautological-compare") +#else +# define DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE() +#endif + +int +do_test (void) +{ + int result = 0; + + for (uint64_t i = 0; i < (~UINT64_C (0)) >> 2; i = (i << 1) + 3) + { + if (i < UINT64_C (65536)) + { + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE (); + if (htobe16 (be16toh (i)) != i) + { + printf ("htobe16 (be16toh (%" PRIx64 ")) == %" PRIx16 "\n", + i, (uint16_t) htobe16 (be16toh (i))); + result = 1; + } + if (htole16 (le16toh (i)) != i) + { + printf ("htole16 (le16toh (%" PRIx64 ")) == %" PRIx16 "\n", + i, (uint16_t) htole16 (le16toh (i))); + result = 1; + } + DIAG_POP_NEEDS_COMMENT; + + uint16_t n[2]; + n[__BYTE_ORDER == __LITTLE_ENDIAN] = bswap_16 (i); + n[__BYTE_ORDER == __BIG_ENDIAN] = i; + if (htole16 (i) != n[0]) + { + printf ("htole16 (%" PRIx64 ") == %" PRIx16 " != %" PRIx16 "\n", + i, (uint16_t) htole16 (i), n[0]); + result = 1; + } + if (htobe16 (i) != n[1]) + { + printf ("htobe16 (%" PRIx64 ") == %" PRIx16 " != %" PRIx16 "\n", + i, (uint16_t) htobe16 (i), n[1]); + result = 1; + } + } + + if (i < UINT64_C (4294967296)) + { + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE (); + if (htobe32 (be32toh (i)) != i) + { + printf ("htobe32 (be32toh (%" PRIx64 ")) == %" PRIx32 "\n", + i, (uint32_t) htobe32 (be32toh (i))); + result = 1; + } + if (htole32 (le32toh (i)) != i) + { + printf ("htole32 (le32toh (%" PRIx64 ")) == %" PRIx32 "\n", + i, (uint32_t) htole32 (le32toh (i))); + result = 1; + } + DIAG_POP_NEEDS_COMMENT; + + uint32_t n[2]; + n[__BYTE_ORDER == __LITTLE_ENDIAN] = bswap_32 (i); + n[__BYTE_ORDER == __BIG_ENDIAN] = i; + if (htole32 (i) != n[0]) + { + printf ("htole32 (%" PRIx64 ") == %" PRIx32 " != %" PRIx32 "\n", + i, (uint32_t) htole32 (i), n[0]); + result = 1; + } + if (htobe32 (i) != n[1]) + { + printf ("htobe32 (%" PRIx64 ") == %" PRIx32 " != %" PRIx32 "\n", + i, (uint32_t) htobe32 (i), n[1]); + result = 1; + } + } + + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT_TAUTOLOGICAL_COMPARE (); + if (htobe64 (be64toh (i)) != i) + { + printf ("htobe64 (be64toh (%" PRIx64 ")) == %" PRIx64 "\n", + i, htobe64 (be64toh (i))); + result = 1; + } + if (htole64 (le64toh (i)) != i) + { + printf ("htole64 (le64toh (%" PRIx64 ")) == %" PRIx64 "\n", + i, htole64 (le64toh (i))); + result = 1; + } + DIAG_POP_NEEDS_COMMENT; + + uint64_t n[2]; + n[__BYTE_ORDER == __LITTLE_ENDIAN] = bswap_64 (i); + n[__BYTE_ORDER == __BIG_ENDIAN] = i; + if (htole64 (i) != n[0]) + { + printf ("htole64 (%" PRIx64 ") == %" PRIx64 " != %" PRIx64 "\n", + i, htole64 (i), n[0]); + result = 1; + } + if (htobe64 (i) != n[1]) + { + printf ("htobe64 (%" PRIx64 ") == %" PRIx64 " != %" PRIx64 "\n", + i, htobe64 (i), n[1]); + result = 1; + } + } + + return result; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-inlcall.c b/REORG.TODO/string/tst-inlcall.c new file mode 100644 index 0000000000..f39f2c33a0 --- /dev/null +++ b/REORG.TODO/string/tst-inlcall.c @@ -0,0 +1,84 @@ +/* Tester for calling inline string functions. + Copyright (C) 1998-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +/* Make sure we test the optimized inline functions. */ +#define __USE_STRING_INLINES 1 + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <fcntl.h> + + +int +do_test (void) +{ + int status; + int errors = 0; + char buf1[1000]; + char *cp; + char ch; + + cp = strcpy (buf1, "hello world"); + if (strcmp ("hello world", cp++) != 0) + { + puts ("strcmp test 1 failed"); + ++errors; + } + + cp = buf1; + if (strcmp (cp++, "hello world") != 0) + { + puts ("strcmp test 2 failed"); + ++errors; + } + + ch = 'h'; + if (strchr ("hello world", ch++) == NULL) + { + puts ("strchr test 1 failed"); + ++errors; + } + + const char * const hw = "hello world"; + if (strpbrk (hw, "o") - hw != 4) + { + puts ("strpbrk test 1 failed"); + ++errors; + } + + if (errors == 0) + { + status = EXIT_SUCCESS; + puts ("No errors."); + } + else + { + status = EXIT_FAILURE; + printf ("%d errors.\n", errors); + } + return status; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-strcoll-overflow.c b/REORG.TODO/string/tst-strcoll-overflow.c new file mode 100644 index 0000000000..826af4f8a8 --- /dev/null +++ b/REORG.TODO/string/tst-strcoll-overflow.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2013-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <locale.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <support/check.h> +#include <support/test-driver.h> + +/* Verify that strcoll does not crash for large strings for which it + cannot cache weight lookup results. The size is large enough to + cause integer overflows on 32-bit as well as buffer overflows on + 64-bit. */ +#define SIZE 0x40000000ul + +int +do_test (void) +{ + TEST_VERIFY_EXIT (setlocale (LC_COLLATE, "en_GB.UTF-8") != NULL); + + char *p = malloc (SIZE); + if (p == NULL) + { + puts ("info: could not allocate memory, cannot run test"); + return EXIT_UNSUPPORTED; + } + + memset (p, 'x', SIZE - 1); + p[SIZE - 1] = 0; + printf ("info: strcoll result: %d\n", strcoll (p, p)); + return 0; +} + +/* This test can rung for a long time, but it should complete within + this time on reasonably current hardware. */ +#define TIMEOUT 300 +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-strfry.c b/REORG.TODO/string/tst-strfry.c new file mode 100644 index 0000000000..e4e9018c5b --- /dev/null +++ b/REORG.TODO/string/tst-strfry.c @@ -0,0 +1,14 @@ +#include <stdio.h> +#include <string.h> + +int +do_test (void) +{ + char str[] = "this is a test"; + + strfry (str); + + return 0; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-strlen.c b/REORG.TODO/string/tst-strlen.c new file mode 100644 index 0000000000..15fbc8bd7b --- /dev/null +++ b/REORG.TODO/string/tst-strlen.c @@ -0,0 +1,57 @@ +/* Make sure we don't test the optimized inline functions if we want to + test the real implementation. */ +#undef __USE_STRING_INLINES + +#include <stdio.h> +#include <string.h> + +int +do_test (void) +{ + static const size_t lens[] = { 0, 1, 0, 2, 0, 1, 0, 3, + 0, 1, 0, 2, 0, 1, 0, 4 }; + char basebuf[24 + 32]; + size_t base; + + for (base = 0; base < 32; ++base) + { + char *buf = basebuf + base; + size_t words; + + for (words = 0; words < 4; ++words) + { + size_t last; + memset (buf, 'a', words * 4); + + for (last = 0; last < 16; ++last) + { + buf[words * 4 + 0] = (last & 1) != 0 ? 'b' : '\0'; + buf[words * 4 + 1] = (last & 2) != 0 ? 'c' : '\0'; + buf[words * 4 + 2] = (last & 4) != 0 ? 'd' : '\0'; + buf[words * 4 + 3] = (last & 8) != 0 ? 'e' : '\0'; + buf[words * 4 + 4] = '\0'; + + if (strlen (buf) != words * 4 + lens[last]) + { + printf ("\ +strlen failed for base=%Zu, words=%Zu, and last=%Zu (is %zd, expected %zd)\n", + base, words, last, + strlen (buf), words * 4 + lens[last]); + return 1; + } + + if (strnlen (buf, -1) != words * 4 + lens[last]) + { + printf ("\ +strnlen failed for base=%Zu, words=%Zu, and last=%Zu (is %zd, expected %zd)\n", + base, words, last, + strnlen (buf, -1), words * 4 + lens[last]); + return 1; + } + } + } + } + return 0; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-strtok.c b/REORG.TODO/string/tst-strtok.c new file mode 100644 index 0000000000..628e106a46 --- /dev/null +++ b/REORG.TODO/string/tst-strtok.c @@ -0,0 +1,25 @@ +/* Testcase for strtok reported by Andrew Church <achurch@achurch.org>. */ +#include <stdio.h> +#include <string.h> + +int +do_test (void) +{ + char buf[1] = { 0 }; + int result = 0; + + if (strtok (buf, " ") != NULL) + { + puts ("first strtok call did not return NULL"); + result = 1; + } + else if (strtok (NULL, " ") != NULL) + { + puts ("second strtok call did not return NULL"); + result = 1; + } + + return result; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-strtok_r.c b/REORG.TODO/string/tst-strtok_r.c new file mode 100644 index 0000000000..fc3ed60b63 --- /dev/null +++ b/REORG.TODO/string/tst-strtok_r.c @@ -0,0 +1,38 @@ +/* Test strtok_r regression for BZ #14229. + Copyright (C) 2012-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#define TEST_MAIN +#define BUF1PAGES 1 +#include "test-string.h" + +int +test_main (void) +{ + char line[] = "udf 75868 1 - Live 0xffffffffa0bfb000\n"; + char **saveptrp; + char *tok; + + test_init (); + + /* Check strtok_r won't write beyond the size of (*saveptrp). */ + saveptrp = (char **) (buf1 + page_size - sizeof (*saveptrp)); + tok = strtok_r (line, " \t", saveptrp); + return strcmp (tok, "udf") != 0; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-strxfrm.c b/REORG.TODO/string/tst-strxfrm.c new file mode 100644 index 0000000000..ffe191c60d --- /dev/null +++ b/REORG.TODO/string/tst-strxfrm.c @@ -0,0 +1,73 @@ +/* Based on a test case by Paul Eggert. */ +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +char const string[] = ""; + + +static int +test (const char *locale) +{ + size_t bufsize; + size_t r; + size_t l; + char *buf; + locale_t loc; + int result = 0; + + if (setlocale (LC_COLLATE, locale) == NULL) + { + printf ("cannot set locale \"%s\"\n", locale); + return 1; + } + bufsize = strxfrm (NULL, string, 0) + 1; + buf = malloc (bufsize); + if (buf == NULL) + { + printf ("cannot allocate %zd bytes\n", bufsize); + return 1; + } + r = strxfrm (buf, string, bufsize); + l = strlen (buf); + if (r != l) + { + printf ("locale \"%s\": strxfrm returned %zu, strlen returned %zu\n", + locale, r, l); + result = 1; + } + + loc = newlocale (1 << LC_ALL, locale, NULL); + + r = strxfrm_l (buf, string, bufsize, loc); + l = strlen (buf); + if (r != l) + { + printf ("locale \"%s\": strxfrm_l returned %zu, strlen returned %zu\n", + locale, r, l); + result = 1; + } + + freelocale (loc); + + free (buf); + + return result; +} + + +int +do_test (void) +{ + int result = 0; + + result |= test ("C"); + result |= test ("en_US.ISO-8859-1"); + result |= test ("de_DE.UTF-8"); + + return result; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-strxfrm2.c b/REORG.TODO/string/tst-strxfrm2.c new file mode 100644 index 0000000000..12117e80d6 --- /dev/null +++ b/REORG.TODO/string/tst-strxfrm2.c @@ -0,0 +1,84 @@ +#include <locale.h> +#include <stdio.h> +#include <string.h> + +int +do_test (void) +{ + static const char test_locale[] = "de_DE.UTF-8"; + + 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, test_locale) == NULL) + { + printf ("cannot set locale \"%s\"\n", test_locale); + 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; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-svc.c b/REORG.TODO/string/tst-svc.c new file mode 100644 index 0000000000..d5cf2c19c9 --- /dev/null +++ b/REORG.TODO/string/tst-svc.c @@ -0,0 +1,47 @@ +/* Test for strverscmp() */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define MAX_STRINGS 256 +#define MAX_LINE_SIZE 32 + +static int +compare (const void *p1, const void *p2) +{ + return strverscmp (*((char **) p1), *((char **) p2)); +} + +int +do_test (void) +{ + char line[MAX_LINE_SIZE + 1]; + char *str[MAX_STRINGS]; + int count = 0; + int i, n; + + while (count < MAX_STRINGS && fgets (line, MAX_LINE_SIZE, stdin) != NULL) + { + n = strlen (line) - 1; + + if (line[n] == '\n') + line[n] = '\0'; + + str[count] = strdup (line); + + if (str[count] == NULL) + exit (EXIT_FAILURE); + + ++count; + } + + qsort (str, count, sizeof (char *), compare); + + for (i = 0; i < count; ++i) + puts (str[i]); + + return EXIT_SUCCESS; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-svc.expect b/REORG.TODO/string/tst-svc.expect new file mode 100644 index 0000000000..6240112772 --- /dev/null +++ b/REORG.TODO/string/tst-svc.expect @@ -0,0 +1,33 @@ +000 +001 +00 +00a +01 +01a +0 +0a +2.6.20 +2.6.21 +2.8 +2.8-0.4 +20 +21 +22 +212 +CP037 +CP345 +CP1257 +foo +foo-0.4 +foo-0.4a +foo-0.4b +foo-0.5 +foo-0.10.5 +foo-3.01 +foo-3.0 +foo-3.0.0 +foo-3.0.1 +foo-3.2 +foo-3.10 +foo00 +foo0 diff --git a/REORG.TODO/string/tst-svc.input b/REORG.TODO/string/tst-svc.input new file mode 100644 index 0000000000..247b1c48f9 --- /dev/null +++ b/REORG.TODO/string/tst-svc.input @@ -0,0 +1,33 @@ +0a +00 +0 +01 +001 +01a +00a +000 +2.6.21 +20 +212 +21 +22 +foo0 +foo00 +foo-0.4 +foo-3.0 +foo +foo-3.0.0 +foo-3.0.1 +foo-0.5 +2.6.20 +foo-0.4b +foo-3.10 +foo-3.2 +foo-3.01 +foo-0.4a +foo-0.10.5 +CP037 +CP1257 +CP345 +2.8-0.4 +2.8 diff --git a/REORG.TODO/string/tst-svc2.c b/REORG.TODO/string/tst-svc2.c new file mode 100644 index 0000000000..c0aa03dc18 --- /dev/null +++ b/REORG.TODO/string/tst-svc2.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static struct +{ + const char *str1; + const char *str2; +} tests[] = + { + { "B0075022800016.gbp.corp.com", "B007502280067.gbp.corp.com" }, + { "B0075022800016.gbp.corp.com", "B007502357019.GBP.CORP.COM" }, + { "B007502280067.gbp.corp.com", "B007502357019.GBP.CORP.COM" } + }; +#define ntests (sizeof (tests) / sizeof (tests[0])) + + +int +compare (const char *str1, const char *str2, int exp) +{ + int c = strverscmp (str1, str2); + if (c != 0) + c /= abs (c); + return c != exp; +} + + +int +do_test (void) +{ + int res = 0; + for (int i = 0; i < ntests; ++i) + { + if (compare (tests[i].str1, tests[i].str2, -1)) + { + printf ("FAIL: \"%s\" > \"%s\"\n", tests[i].str1, tests[i].str2); + res = 1; + } + if (compare (tests[i].str2, tests[i].str1, +1)) + { + printf ("FAIL: \"%s\" > \"%s\"\n", tests[i].str2, tests[i].str1); + res = 1; + } + char *copy1 = strdupa (tests[i].str1); + if (compare (tests[i].str1, copy1, 0)) + { + printf ("FAIL: \"%s\" != \"%s\"\n", tests[i].str1, copy1); + res = 1; + } + char *copy2 = strdupa (tests[i].str2); + if (compare (tests[i].str2, copy2, 0)) + { + printf ("FAIL: \"%s\" != \"%s\"\n", tests[i].str2, copy2); + res = 1; + } + } + return res; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/tst-xbzero-opt.c b/REORG.TODO/string/tst-xbzero-opt.c new file mode 100644 index 0000000000..7c25632724 --- /dev/null +++ b/REORG.TODO/string/tst-xbzero-opt.c @@ -0,0 +1,298 @@ +/* Test that explicit_bzero block clears are not optimized out. + Copyright (C) 2016-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* This test is conceptually based on a test designed by Matthew + Dempsky for the OpenBSD regression suite: + <openbsd>/src/regress/lib/libc/explicit_bzero/explicit_bzero.c. + The basic idea is, we have a function that contains a + block-clearing operation (not necessarily explicit_bzero), after + which the block is dead, in the compiler-jargon sense. Execute + that function while running on a user-allocated alternative + stack. Then we have another pointer to the memory region affected + by the block clear -- namely, the original allocation for the + alternative stack -- and can find out whether it actually happened. + + The OpenBSD test uses sigaltstack and SIGUSR1 to get onto an + alternative stack. This causes a number of awkward problems; some + operating systems (e.g. Solaris and OSX) wipe the signal stack upon + returning to the normal stack, there's no way to be sure that other + processes running on the same system will not interfere, and the + signal stack is very small so it's not safe to call printf there. + This implementation instead uses the <ucontext.h> coroutine + interface. The coroutine stack is still too small to safely use + printf, but we know the OS won't erase it, so we can do all the + checks and printing from the normal stack. */ + +#define _GNU_SOURCE 1 + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> +#include <unistd.h> + +/* A byte pattern that is unlikely to occur by chance: the first 16 + prime numbers (OEIS A000040). */ +static const unsigned char test_pattern[16] = +{ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53 +}; + +/* Immediately after each subtest returns, we call swapcontext to get + back onto the main stack. That call might itself overwrite the + test pattern, so we fill a modest-sized buffer with copies of it + and check whether any of them survived. */ + +#define PATTERN_SIZE (sizeof test_pattern) +#define PATTERN_REPS 32 +#define TEST_BUFFER_SIZE (PATTERN_SIZE * PATTERN_REPS) + +/* There are three subtests, two of which are sanity checks. + Each test follows this sequence: + + main coroutine + ---- -------- + advance cur_subtest + swap + call setup function + prepare test buffer + swap + verify that buffer + was filled in + swap + possibly clear buffer + return + swap + check buffer again, + according to test + expectation + + In the "no_clear" case, we don't do anything to the test buffer + between preparing it and letting it go out of scope, and we expect + to find it. This confirms that the test buffer does get filled in + and we can find it from the stack buffer. In the "ordinary_clear" + case, we clear it using memset. Depending on the target, the + compiler may not be able to apply dead store elimination to the + memset call, so the test does not fail if the memset is not + eliminated. Finally, the "explicit_clear" case uses explicit_bzero + and expects _not_ to find the test buffer, which is the real + test. */ + +static ucontext_t uc_main, uc_co; + +/* Always check the test buffer immediately after filling it; this + makes externally visible side effects depend on the buffer existing + and having been filled in. */ +static inline __attribute__ ((always_inline)) void +prepare_test_buffer (unsigned char *buf) +{ + for (unsigned int i = 0; i < PATTERN_REPS; i++) + memcpy (buf + i*PATTERN_SIZE, test_pattern, PATTERN_SIZE); + + if (swapcontext (&uc_co, &uc_main)) + abort (); +} + +static void +setup_no_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf); +} + +static void +setup_ordinary_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf); + memset (buf, 0, TEST_BUFFER_SIZE); +} + +static void +setup_explicit_clear (void) +{ + unsigned char buf[TEST_BUFFER_SIZE]; + prepare_test_buffer (buf); + explicit_bzero (buf, TEST_BUFFER_SIZE); +} + +enum test_expectation + { + EXPECT_NONE, EXPECT_SOME, EXPECT_ALL, NO_EXPECTATIONS + }; +struct subtest +{ + void (*setup_subtest) (void); + const char *label; + enum test_expectation expected; +}; +static const struct subtest *cur_subtest; + +static const struct subtest subtests[] = +{ + { setup_no_clear, "no clear", EXPECT_SOME }, + /* The memset may happen or not, depending on compiler + optimizations. */ + { setup_ordinary_clear, "ordinary clear", NO_EXPECTATIONS }, + { setup_explicit_clear, "explicit clear", EXPECT_NONE }, + { 0, 0, -1 } +}; + +static void +test_coroutine (void) +{ + while (cur_subtest->setup_subtest) + { + cur_subtest->setup_subtest (); + if (swapcontext (&uc_co, &uc_main)) + abort (); + } +} + +/* All the code above this point runs on the coroutine stack. + All the code below this point runs on the main stack. */ + +static int test_status; +static unsigned char *co_stack_buffer; +static size_t co_stack_size; + +static unsigned int +count_test_patterns (unsigned char *buf, size_t bufsiz) +{ + unsigned char *first = memmem (buf, bufsiz, test_pattern, PATTERN_SIZE); + if (!first) + return 0; + unsigned int cnt = 0; + for (unsigned int i = 0; i < PATTERN_REPS; i++) + { + unsigned char *p = first + i*PATTERN_SIZE; + if (p + PATTERN_SIZE - buf > bufsiz) + break; + if (memcmp (p, test_pattern, PATTERN_SIZE) == 0) + cnt++; + } + return cnt; +} + +static void +check_test_buffer (enum test_expectation expected, + const char *label, const char *stage) +{ + unsigned int cnt = count_test_patterns (co_stack_buffer, co_stack_size); + switch (expected) + { + case EXPECT_NONE: + if (cnt == 0) + printf ("PASS: %s/%s: expected 0 got %d\n", label, stage, cnt); + else + { + printf ("FAIL: %s/%s: expected 0 got %d\n", label, stage, cnt); + test_status = 1; + } + break; + + case EXPECT_SOME: + if (cnt > 0) + printf ("PASS: %s/%s: expected some got %d\n", label, stage, cnt); + else + { + printf ("FAIL: %s/%s: expected some got 0\n", label, stage); + test_status = 1; + } + break; + + case EXPECT_ALL: + if (cnt == PATTERN_REPS) + printf ("PASS: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + else + { + printf ("FAIL: %s/%s: expected %d got %d\n", label, stage, + PATTERN_REPS, cnt); + test_status = 1; + } + break; + + case NO_EXPECTATIONS: + printf ("INFO: %s/%s: found %d patterns%s\n", label, stage, cnt, + cnt == 0 ? " (memset not eliminated)" : ""); + break; + + default: + printf ("ERROR: %s/%s: invalid value for 'expected' = %d\n", + label, stage, (int)expected); + test_status = 1; + } +} + +static void +test_loop (void) +{ + cur_subtest = subtests; + while (cur_subtest->setup_subtest) + { + if (swapcontext (&uc_main, &uc_co)) + abort (); + check_test_buffer (EXPECT_ALL, cur_subtest->label, "prepare"); + if (swapcontext (&uc_main, &uc_co)) + abort (); + check_test_buffer (cur_subtest->expected, cur_subtest->label, "test"); + cur_subtest++; + } + /* Terminate the coroutine. */ + if (swapcontext (&uc_main, &uc_co)) + abort (); +} + +int +do_test (void) +{ + size_t page_alignment = sysconf (_SC_PAGESIZE); + if (page_alignment < sizeof (void *)) + page_alignment = sizeof (void *); + + co_stack_size = SIGSTKSZ + TEST_BUFFER_SIZE; + if (co_stack_size < page_alignment * 4) + co_stack_size = page_alignment * 4; + + void *p; + int err = posix_memalign (&p, page_alignment, co_stack_size); + if (err || !p) + { + printf ("ERROR: allocating alt stack: %s\n", strerror (err)); + return 2; + } + co_stack_buffer = p; + + if (getcontext (&uc_co)) + { + printf ("ERROR: allocating coroutine context: %s\n", strerror (err)); + return 2; + } + uc_co.uc_stack.ss_sp = co_stack_buffer; + uc_co.uc_stack.ss_size = co_stack_size; + uc_co.uc_link = &uc_main; + makecontext (&uc_co, test_coroutine, 0); + + test_loop (); + return test_status; +} + +#include <support/test-driver.c> diff --git a/REORG.TODO/string/wordcopy.c b/REORG.TODO/string/wordcopy.c new file mode 100644 index 0000000000..65961cd03a --- /dev/null +++ b/REORG.TODO/string/wordcopy.c @@ -0,0 +1,416 @@ +/* _memcopy.c -- subroutines for memory copy functions. + Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +/* 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. */ + +#ifndef WORDCOPY_FWD_ALIGNED +# define WORDCOPY_FWD_ALIGNED _wordcopy_fwd_aligned +#endif + +void +WORDCOPY_FWD_ALIGNED (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. */ + +#ifndef WORDCOPY_FWD_DEST_ALIGNED +# define WORDCOPY_FWD_DEST_ALIGNED _wordcopy_fwd_dest_aligned +#endif + +void +WORDCOPY_FWD_DEST_ALIGNED (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. */ + +#ifndef WORDCOPY_BWD_ALIGNED +# define WORDCOPY_BWD_ALIGNED _wordcopy_bwd_aligned +#endif + +void +WORDCOPY_BWD_ALIGNED (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. */ + +#ifndef WORDCOPY_BWD_DEST_ALIGNED +# define WORDCOPY_BWD_DEST_ALIGNED _wordcopy_bwd_dest_aligned +#endif + +void +WORDCOPY_BWD_DEST_ALIGNED (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/REORG.TODO/string/xpg-strerror.c b/REORG.TODO/string/xpg-strerror.c new file mode 100644 index 0000000000..4a5e59d5ab --- /dev/null +++ b/REORG.TODO/string/xpg-strerror.c @@ -0,0 +1,53 @@ +/* Copyright (C) 1991-2017 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, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/param.h> + + +/* Fill buf with a string describing the errno code in ERRNUM. */ +int +__xpg_strerror_r (int errnum, char *buf, size_t buflen) +{ + const char *estr = __strerror_r (errnum, buf, buflen); + + /* We know that __strerror_r returns buf (with a dynamically computed + string) if errnum is invalid, otherwise it returns a string whose + storage has indefinite extent. */ + if (estr == buf) + { + assert (errnum < 0 || errnum >= _sys_nerr_internal + || _sys_errlist_internal[errnum] == NULL); + return EINVAL; + } + else + { + assert (errnum >= 0 && errnum < _sys_nerr_internal + && _sys_errlist_internal[errnum] != NULL); + + size_t estrlen = strlen (estr); + + /* Terminate the string in any case. */ + if (buflen > 0) + *((char *) __mempcpy (buf, estr, MIN (buflen - 1, estrlen))) = '\0'; + + return buflen <= estrlen ? ERANGE : 0; + } +} |