Several functions in string.h, strings.h, and wchar.h return a pointer
into a buffer passed as their first argument. That pointer logically
ought to inherit the 'const'-ness of the original buffer. There's no
way to express that in C, so all these functions are specified with a
prototype that, as a side-effect, strips the 'const', potentially
leading to bugs:
char *strfoo(const char *buf, ...);
In C++, however, you can get it exactly right via function overloads:
char *strfoo(char *buf, ...);
const char *strfoo(const char *buf, ...);
and the C++ standard (21.7 [c.strings]) requires the library to do
just that. We were implementing this requirement via a repetitive and
error-prone mess of #ifdefs for each and every one of the affected
functions.
This patch absorbs the entire mess into a pair of macros,
__CONST_COV_PROTO and __CONST_COV_BUILTIN, which are far less
error-prone to use, and which make the public header files much nicer
to read, too. They needed some black magic to _implement_, but it's
hiding in a bits header and hopefully nobody need ever change that
file again.
Tested on x86-64-linux-gnu. OK?
(The only change from the previous iteration of this patch is to give
wchar.h the same treatment, as suggested by Joseph.)
zw
* string/bits/const-covariance.h: New file.
* string/Makefile (headers): Add it.
* string/string.h: Use __CONST_COV_PROTO and __CONST_COV_BUILTIN to
declare memchr, rawmemchr, memrchr, strchr, strrchr, strchrnul,
strpbrk, strstr, strcasestr, memmem, and basename.
* string/strings.h: Likewise for index and rindex.
* wcsmbs/wchar.h: Likewise for wcschr, wcsrchr, wcschrnul,
wcspbrk, wcsstr, wcswcs, and wmemchr.
* include/bits/const-covariance.h: New wrapper.
---
include/bits/const-covariance.h | 1 +
string/Makefile | 3 +-
string/bits/const-covariance.h | 130 ++++++++++++++++++++
string/string.h | 266
+++++++++++-----------------------------
string/strings.h | 71 +++--------
wcsmbs/wchar.h | 131 +++++++++-----------
6 files changed, 281 insertions(+), 321 deletions(-)
create mode 100644 include/bits/const-covariance.h
create mode 100644 string/bits/const-covariance.h
__THROW __attribute_malloc__;
#endif
__BEGIN_NAMESPACE_STD
-/* Find the first occurrence of WC in WCS. */
-#ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO
-extern "C++" wchar_t *wcschr (wchar_t *__wcs, wchar_t __wc)
- __THROW __asm ("wcschr") __attribute_pure__;
-extern "C++" const wchar_t *wcschr (const wchar_t *__wcs, wchar_t __wc)
- __THROW __asm ("wcschr") __attribute_pure__;
-#else
-extern wchar_t *wcschr (const wchar_t *__wcs, wchar_t __wc)
- __THROW __attribute_pure__;
-#endif
-/* Find the last occurrence of WC in WCS. */
-#ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO
-extern "C++" wchar_t *wcsrchr (wchar_t *__wcs, wchar_t __wc)
- __THROW __asm ("wcsrchr") __attribute_pure__;
-extern "C++" const wchar_t *wcsrchr (const wchar_t *__wcs, wchar_t __wc)
- __THROW __asm ("wcsrchr") __attribute_pure__;
-#else
-extern wchar_t *wcsrchr (const wchar_t *__wcs, wchar_t __wc)
- __THROW __attribute_pure__;
-#endif
+/* Find the first occurrence of WC in WCS.
+ [C] extern wchar_t *wcschr (const wchar_t *wcs, wchar_t wc);
+ [C++] extern wchar_t *wcschr (wchar_t *wcs, wchar_t wc);
+ extern const wchar_t *wcschr (const wchar_t *wcs, wchar_t wc); */
+__CONST_COV_PROTO (wcschr, __attribute_pure__,
+ wchar_t *, __wcs, wchar_t, __wc);
+
+/* Find the last occurrence of WC in WCS.
+ [C] extern wchar_t *wcsrchr (const wchar_t *wcs, wchar_t wc);
+ [C++] extern wchar_t *wcsrchr (wchar_t *wcs, wchar_t wc);
+ extern const wchar_t *wcsrchr (const wchar_t *wcs, wchar_t wc); */
+__CONST_COV_PROTO (wcsrchr, __attribute_pure__,
+ wchar_t *, __wcs, wchar_t, __wc);
__END_NAMESPACE_STD
#ifdef __USE_GNU
/* This function is similar to `wcschr'. But it returns a pointer to
- the closing NUL wide character in case C is not found in S. */
-extern wchar_t *wcschrnul (const wchar_t *__s, wchar_t __wc)
- __THROW __attribute_pure__;
+ the closing NUL wide character in case C is not found in S.
+ [C] extern wchar_t *wcschrnul (const wchar_t *wcs, wchar_t wc);
+ [C++] extern wchar_t *wcschrnul (wchar_t *wcs, wchar_t wc);
+ extern const wchar_t *wcschrnul (const wchar_t *wcs, wchar_t
wc); */
+__CONST_COV_PROTO (wcschrnul, __attribute_pure__,
+ wchar_t *, __wcs, wchar_t, __wc);
#endif
__BEGIN_NAMESPACE_STD
@@ -259,28 +256,23 @@ extern size_t wcscspn (const wchar_t *__wcs, const
wchar_t *__reject)
consists entirely of wide characters in ACCEPT. */
extern size_t wcsspn (const wchar_t *__wcs, const wchar_t *__accept)
__THROW __attribute_pure__;
-/* Find the first occurrence in WCS of any character in ACCEPT. */
-#ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO
-extern "C++" wchar_t *wcspbrk (wchar_t *__wcs, const wchar_t *__accept)
- __THROW __asm ("wcspbrk") __attribute_pure__;
-extern "C++" const wchar_t *wcspbrk (const wchar_t *__wcs,
- const wchar_t *__accept)
- __THROW __asm ("wcspbrk") __attribute_pure__;
-#else
-extern wchar_t *wcspbrk (const wchar_t *__wcs, const wchar_t *__accept)
- __THROW __attribute_pure__;
-#endif
-/* Find the first occurrence of NEEDLE in HAYSTACK. */
-#ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO
-extern "C++" wchar_t *wcsstr (wchar_t *__haystack, const wchar_t *__needle)
- __THROW __asm ("wcsstr") __attribute_pure__;
-extern "C++" const wchar_t *wcsstr (const wchar_t *__haystack,
- const wchar_t *__needle)
- __THROW __asm ("wcsstr") __attribute_pure__;
-#else
-extern wchar_t *wcsstr (const wchar_t *__haystack, const wchar_t *__needle)
- __THROW __attribute_pure__;
-#endif
+/* Find the first occurrence in WCS of any character in ACCEPT.
+ [C] extern wchar_t *wcspbrk (const wchar_t *wcs, const wchar_t
*accept);
+ [C++] extern wchar_t *wcspbrk (wchar_t *wcs, const wchar_t *accept);
+ extern const wchar_t *wcspbrk (const wchar_t *wcs,
+ const wchar_t *accept); */
+__CONST_COV_PROTO (wcspbrk, __attribute_pure__,
+ wchar_t *, __wcs, const wchar_t *, __accept);
+
+/* Find the first occurrence of NEEDLE in HAYSTACK.
+ [C] extern wchar_t *wcsstr (const wchar_t *haystack,
+ const wchar_t *needle);
+ [C++] extern wchar_t *wcsstr (wchar_t *haystack,
+ const wchar_t *needle);
+ extern const wchar_t *wcsstr (const wchar_t *haystack,
+ const wchar_t *needle); */
+__CONST_COV_PROTO (wcsstr, __attribute_pure__,
+ wchar_t *, __haystack, const wchar_t *, __needle);
/* Divide WCS into tokens separated by characters in DELIM. */
extern wchar_t *wcstok (wchar_t *__restrict __s,
@@ -292,17 +284,15 @@ extern size_t wcslen (const wchar_t *__s) __THROW
__attribute_pure__;
__END_NAMESPACE_STD
#ifdef __USE_XOPEN
-/* Another name for `wcsstr' from XPG4. */
-# ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO
-extern "C++" wchar_t *wcswcs (wchar_t *__haystack, const wchar_t *__needle)
- __THROW __asm ("wcswcs") __attribute_pure__;
-extern "C++" const wchar_t *wcswcs (const wchar_t *__haystack,
- const wchar_t *__needle)
- __THROW __asm ("wcswcs") __attribute_pure__;
-# else
-extern wchar_t *wcswcs (const wchar_t *__haystack, const wchar_t *__needle)
- __THROW __attribute_pure__;
-# endif
+/* Another name for `wcsstr' from XPG4.
+ [C] extern wchar_t *wcswcs (const wchar_t *haystack,
+ const wchar_t *needle);
+ [C++] extern wchar_t *wcswcs (wchar_t *haystack,
+ const wchar_t *needle);
+ extern const wchar_t *wcswcs (const wchar_t *haystack,
+ const wchar_t *needle); */
+__CONST_COV_PROTO (wcswcs, __attribute_pure__,
+ wchar_t *, __haystack, const wchar_t *, __needle);
#endif
#ifdef __USE_XOPEN2K8
@@ -311,19 +301,14 @@ extern size_t wcsnlen (const wchar_t *__s, size_t
__maxlen)
__THROW __attribute_pure__;
#endif
-
__BEGIN_NAMESPACE_STD
-/* Search N wide characters of S for C. */
-#ifdef __CORRECT_ISO_CPP_WCHAR_H_PROTO
-extern "C++" wchar_t *wmemchr (wchar_t *__s, wchar_t __c, size_t __n)
- __THROW __asm ("wmemchr") __attribute_pure__;
-extern "C++" const wchar_t *wmemchr (const wchar_t *__s, wchar_t __c,
- size_t __n)
- __THROW __asm ("wmemchr") __attribute_pure__;
-#else
-extern wchar_t *wmemchr (const wchar_t *__s, wchar_t __c, size_t __n)
- __THROW __attribute_pure__;
-#endif
+/* Search N wide characters of S for C.
+ [C] extern wchar_t *wmemchr (const wchar_t *s, wchar_t wc, size_t n);
+ [C++] extern wchar_t *wmemchr (wchar_t *s, wchar_t wc, size_t n);
+ extern const wchar_t *wmemchr (const wchar_t *s, wchar_t wc,
+ size_t n); */
+__CONST_COV_PROTO (wmemchr, __attribute_pure__,
+ wchar_t *, __s, wchar_t, __c, size_t, __n);
/* Compare N wide characters of S1 and S2. */
extern int wmemcmp (const wchar_t *__s1, const wchar_t *__s2, size_t __n)
b/include/bits/const-covariance.h
new file mode 100644
@@ -0,0 +1 @@
+#include <string/bits/const-covariance.h>
@@ -24,7 +24,8 @@ 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/string.h bits/string2.h bits/string3.h \
+ bits/const-covariance.h
routines := strcat strchr strcmp strcoll strcpy strcspn \
strverscmp strdup strndup \
new file mode 100644
@@ -0,0 +1,130 @@
+/* Copyright (C) 2016 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 _BITS_CONST_COVARIANCE_H
+#define _BITS_CONST_COVARIANCE_H 1
+
+#if !defined _STRING_H && !defined _STRINGS_H && !defined _WCHAR_H
+# error "Never use <bits/const-covariance.h> directly; include
<string.h>, <strings.h>, or <wchar.h> instead."
+#endif
+
+/* This header defines internal-use macros that expand a C prototype
+ declaration like
+
+ extern void *memchr (const void *, int, size_t) attrs;
+
+ to a pair of C++ overloaded function declarations with improved
+ const-correctness:
+
+ extern void *memchr (void *, int, size_t) attrs;
+ extern const void *memchr (const void *, int, size_t) attrs;
+
+ You use them like this:
+
+ __CONST_COV_PROTO (memchr, attrs,
+ void *, __s, int, __c, size_t, __n);
+
+ where the arguments after 'attrs' are the function's arguments,
+ alternating with argument names. The first of these will be used
+ as the const-covariant return type. It should be written without
+ a 'const' qualifier.
+
+ If the compiler has intrinsic knowledge of the function, use
+ __CONST_COV_BUILTIN instead of __CONST_COV_PROTO. In C++ mode,
+ this will also generate inline functions of the form
+
+ __extern_always_inline [const] void *
+ memchr (void *__s, int __c, size_t __n) attrs
+ {
+ return __builtin_memchr (__s, __c, __n);
+ }
+
+ Due to limitations in the preprocessor, these macros support no
+ more than four arguments to any function. This is all that
+ string.h/strings.h currently require.
+
+ Because g++ only accepts throw(), __asm("..."), and
+ __attribute__((whatever)) annotations in a specific order, all
+ functions declared with __CONST_COV_PROTO or defined with
+ __CONST_COV_BUILTIN are automatically marked __THROW. Do not put
+ __THROW in 'attrs'. */
+
+#define __CC_VA_NARGS(...) __CC_VA_NARGS_(__VA_ARGS__, __CC_RSEQ)
+#define __CC_VA_NARGS_(...) __CC_VA_NARGS__(__VA_ARGS__)
+#define __CC_VA_NARGS__(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
+#define __CC_RSEQ 8, 7, 6, 5, 4, 3, 2, 1
+
+#define __CC_2FOR2(op, a, b) op (a, b)
+#define __CC_2FOR4(op, a, b, ...) op (a, b), __CC_2FOR2 (op, __VA_ARGS__)
+#define __CC_2FOR6(op, a, b, ...) op (a, b), __CC_2FOR4 (op, __VA_ARGS__)
+#define __CC_2FOR8(op, a, b, ...) op (a, b), __CC_2FOR6 (op, __VA_ARGS__)
+
+#define __CC_2FOR(op, ...) \
+ __CC_2FOR_ (__CC_VA_NARGS (__VA_ARGS__)) (op, __VA_ARGS__)
+#define __CC_2FOR_(n) __CC_2FOR__ (n)
+#define __CC_2FOR__(n) __CC_2FOR##n
+
+#define __CC_XPROTO(...) (__CC_2FOR (__CC_XPROTO_, __VA_ARGS__))
+#define __CC_XPROTO_(type, name) type name
+
+#define __CC_XCALL(...) (__CC_2FOR (__CC_XCALL_, __VA_ARGS__))
+#define __CC_XCALL_(type, name) name
+
+#if !defined __cplusplus || !__GNUC_PREREQ (4, 4)
+
+# define __CONST_COV_PROTO(name, attrs, rtype, ...) \
+ extern rtype name __CC_XPROTO(const rtype, __VA_ARGS__) __THROW attrs
+
+# define __CONST_COV_BUILTIN(...) __CONST_COV_PROTO (__VA_ARGS__)
+
+#else
+
+# define __CONST_COV_PROTO_BODY(name, attrs, rtype, ...) \
+ extern rtype name __CC_XPROTO(rtype, __VA_ARGS__) \
+ __THROW __asm (#name) attrs; \
+ extern const rtype name __CC_XPROTO(const rtype, __VA_ARGS__) \
+ __THROW __asm (#name) attrs;
+
+# define __CONST_COV_PROTO(...) \
+ extern "C++" \
+ { \
+ __CONST_COV_PROTO_BODY(__VA_ARGS__) \
+ } \
+ struct __require_semicolon
+
+# ifndef __OPTIMIZE__
+# define __CONST_COV_BUILTIN(...) __CONST_COV_PROTO (__VA_ARGS__)
+
+# else
+
+# define __CONST_COV_BUILTIN(name, attrs, rtype, ...) \
+ extern "C++" \
+ { \
+ __CONST_COV_PROTO_BODY (name, attrs, rtype, __VA_ARGS__) \
+ __extern_always_inline rtype \
+ name __CC_XPROTO (rtype, __VA_ARGS__) __THROW \
+ { return __builtin_##name __CC_XCALL (rtype, __VA_ARGS__); } \
+ __extern_always_inline const rtype \
+ name __CC_XPROTO (const rtype, __VA_ARGS__) __THROW \
+ { return __builtin_##name __CC_XCALL (rtype, __VA_ARGS__); } \
+ } \
+ struct __require_semicolon
+
+# endif /* __OPTIMIZE__ */
+#endif /* C++ and GCC >=4.4 */
+
+#endif /* const-covariance.h */
@@ -36,7 +36,7 @@ __BEGIN_DECLS
#if defined __cplusplus && __GNUC_PREREQ (4, 4)
# define __CORRECT_ISO_CPP_STRING_H_PROTO
#endif
-
+#include <bits/const-covariance.h>
__BEGIN_NAMESPACE_STD
/* Copy N bytes of SRC to DEST. */
@@ -66,61 +66,31 @@ extern void *memset (void *__s, int __c, size_t __n)
__THROW __nonnull ((1));
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
+/* Search N bytes of S for C.
+ [C] extern void *memchr (const void *s, int c, size_t n);
+ [C++] extern void *memchr (void *s, int c, size_t n);
+ extern const void *memchr (const void *s, int c, size_t n); */
+__CONST_COV_BUILTIN (memchr, __attribute_pure__ __nonnull ((1)),
+ void *, __s, int, __c, size_t, __n);
__END_NAMESPACE_STD
#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 in S for C. This is similar to 'memchr' but there is no
+ length limit.
+ [C] extern void *rawmemchr (const void *s, int c);
+ [C++] extern void *rawmemchr (void *s, int c);
+ extern const void *rawmemchr (const void *s, int c); */
+__CONST_COV_PROTO (rawmemchr, __attribute_pure__ __nonnull ((1)),
+ void *, __s, int, __c);
-/* 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
+/* Search N bytes of S for the final occurrence of C.
+ [C] extern void *memrchr (const void *s, int c, size_t n);
+ [C++] extern void *memrchr (void *s, int c, size_t n);
+ extern const void *memrchr (const void *s, int c, size_t n); */
+__CONST_COV_PROTO (memrchr, __attribute_pure__ __nonnull ((1)),
+ void *, __s, int, __c, size_t, __n);
#endif
-
__BEGIN_NAMESPACE_STD
/* Copy SRC to DEST. */
extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
@@ -204,74 +174,30 @@ extern char *strndup (const char *__string, size_t
__n)
#endif
__BEGIN_NAMESPACE_STD
-/* 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));
+/* Find the first occurrence of C in S.
+ [C] extern char *strchr (const char *s, int c);
+ [C++] extern char *strchr (char *s, int c);
+ extern const char *strchr (const char *s, int c); */
+__CONST_COV_BUILTIN (strchr, __attribute_pure__ __nonnull ((1)),
+ char *, __s, int, __c);
-# ifdef __OPTIMIZE__
-__extern_always_inline char *
-strchr (char *__s, int __c) __THROW
-{
- return __builtin_strchr (__s, __c);
-}
+/* Find the last occurrence of C in S.
+ [C] extern char *strrchr (const char *s, int c);
+ [C++] extern char *strrchr (char *s, int c);
+ extern const char *strrchr (const char *s, int c); */
+__CONST_COV_BUILTIN (strrchr, __attribute_pure__ __nonnull ((1)),
+ char *, __s, int, __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
__END_NAMESPACE_STD
#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
+ the closing NUL byte in case C is not found in S.
+ [C] extern char *strchrnul (const char *s, int c);
+ [C++] extern char *strchrnul (char *s, int c);
+ extern const char *strchrnul (const char *s, int c); */
+__CONST_COV_PROTO (strchrnul, __attribute_pure__ __nonnull ((1)),
+ char *, __s, int, __c);
#endif
__BEGIN_NAMESPACE_STD
@@ -279,65 +205,26 @@ __BEGIN_NAMESPACE_STD
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
+/* Find the first occurrence in S of any character in ACCEPT.
+ [C] extern char *strpbrk (const char *s, const char *accept);
+ [C++] extern char *strpbrk (char *s, const char *accept);
+ extern const char *strpbrk (const char *s, const char *accept); */
+__CONST_COV_BUILTIN (strpbrk, __attribute_pure__ __nonnull ((1, 2)),
+ char *, __s, const char *, __accept);
+/* Find the first occurrence of NEEDLE in HAYSTACK.
+ [C] extern char *strstr (const char *haystack, const char *needle);
+ [C++] extern char *strstr (char *haystack, const char *needle);
+ extern const char *strstr (const char *haystack, const char
*needle);
+ */
+__CONST_COV_BUILTIN (strstr, __attribute_pure__ __nonnull ((1, 2)),
+ char *, __haystack, const char *, __needle);
/* Divide S into tokens separated by characters in DELIM. */
extern char *strtok (char *__restrict __s, const char *__restrict __delim)
@@ -357,26 +244,26 @@ extern char *strtok_r (char *__restrict __s, const
char *__restrict __delim,
#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
+/* Similar to 'strstr', but ignores the case of both strings.
+ [C] extern char *strcasestr (const char *haystack, const char
*needle);
+ [C++] extern char *strcasestr (char *haystack, const char *needle);
+ extern const char *strcasestr (const char *haystack,
+ const char *needle); */
+__CONST_COV_PROTO (strcasestr, __attribute_pure__ __nonnull ((1, 2)),
+ char *, __haystack, const char *, __needle);
-#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));
+ HAYSTACK is HAYSTACKLEN bytes long.
+ [C] extern void *memmem (const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+ [C++] extern void *memmem (void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+ extern const void *memmem (const void *haystack, size_t
haystacklen,
+ const void *needle, size_t
needlelen); */
+__CONST_COV_PROTO (memmem, __attribute_pure__ __nonnull ((1, 3)),
+ void *, __haystack, size_t, __haystacklen,
+ const void *, __needle, size_t, __needlelen);
/* Copy N bytes of SRC to DEST, return pointer to bytes after the
last written byte. */
@@ -487,15 +374,12 @@ extern void *memfrob (void *__s, size_t __n)
__THROW __nonnull ((1));
/* 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
+ available.
+ [C] char *basename (const char *filename);
+ [C++] char *basename (char *filename);
+ const char *basename (const char *filename); */
+__CONST_COV_PROTO (basename, __nonnull ((1)),
+ char *, __filename);
# endif
#endif
diff --git a/string/strings.h b/string/strings.h
@@ -26,6 +26,7 @@
#if defined __cplusplus && __GNUC_PREREQ (4, 4)
# define __CORRECT_ISO_CPP_STRINGS_H_PROTO
#endif
+#include <bits/const-covariance.h>
__BEGIN_DECLS
@@ -41,61 +42,19 @@ extern void bcopy (const void *__src, void *__dest,
size_t __n)
/* 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));
+/* Find the first occurrence of C in S (same as strchr).
+ [C] extern char *index (const char *s, int c);
+ [C++] extern char *index (char *s, int c);
+ extern const char *index (const char *s, int c); */
+__CONST_COV_BUILTIN (index, __attribute_pure__ __nonnull ((1)),
+ char *, __s, int, __c);
-# 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
+/* Find the last occurrence of C in S (same as strrchr).
+ [C] extern char *rindex (const char *s, int c);
+ [C++] extern char *rindex (char *s, int c);
+ extern const char *rindex (const char *s, int c); */
+__CONST_COV_BUILTIN (rindex, __attribute_pure__ __nonnull ((1)),
+ char *, __s, int, __c);
#endif
#if defined __USE_MISC || !defined __USE_XOPEN2K8 || defined
__USE_XOPEN2K8XSI
@@ -106,11 +65,11 @@ extern int ffs (int __i) __THROW __attribute_const__;
/* The following two functions are non-standard but necessary for
non-32 bit
platforms. */
-# ifdef __USE_GNU
+#ifdef __USE_GNU
extern int ffsl (long int __l) __THROW __attribute_const__;
__extension__ extern int ffsll (long long int __ll)
__THROW __attribute_const__;
-# endif
+#endif
/* Compare S1 and S2, ignoring case. */
extern int strcasecmp (const char *__s1, const char *__s2)
@@ -70,11 +70,6 @@ typedef __WINT_TYPE__ wint_t;
__END_NAMESPACE_STD
# endif
# endif
-
-/* Tell the caller that we provide correct C++ prototypes. */
-# if defined __cplusplus && __GNUC_PREREQ (4, 4)
-# define __CORRECT_ISO_CPP_WCHAR_H_PROTO
-# endif
#endif
#if (defined _WCHAR_H || defined __need_mbstate_t) && !defined
____mbstate_t_defined
@@ -101,6 +96,12 @@ typedef struct
defined. */
#ifdef _WCHAR_H
+/* Tell the caller that we provide correct C++ prototypes. */
+# if defined __cplusplus && __GNUC_PREREQ (4, 4)
+# define __CORRECT_ISO_CPP_WCHAR_H_PROTO
+# endif
+# include <bits/const-covariance.h>
+
# ifndef __mbstate_t_defined
__BEGIN_NAMESPACE_C99
/* Public type. */
@@ -221,33 +222,29 @@ extern wchar_t *wcsdup (const wchar_t *__s)