aboutsummaryrefslogtreecommitdiff
path: root/private.h
diff options
context:
space:
mode:
Diffstat (limited to 'private.h')
-rw-r--r--private.h130
1 files changed, 99 insertions, 31 deletions
diff --git a/private.h b/private.h
index 7a73eff7c576..838ab2b2df8f 100644
--- a/private.h
+++ b/private.h
@@ -17,12 +17,25 @@
** Thank you!
*/
+/* PORT_TO_C89 means the code should work even if the underlying
+ compiler and library support only C89. SUPPORT_C89 means the
+ tzcode library should support C89 callers in addition to the usual
+ support for C99-and-later callers. These macros are obsolescent,
+ and the plan is to remove them along with any code needed only when
+ they are nonzero. */
+#ifndef PORT_TO_C89
+# define PORT_TO_C89 0
+#endif
+#ifndef SUPPORT_C89
+# define SUPPORT_C89 0
+#endif
+
#ifndef __STDC_VERSION__
# define __STDC_VERSION__ 0
#endif
/* Define true, false and bool if they don't work out of the box. */
-#if __STDC_VERSION__ < 199901
+#if PORT_TO_C89 && __STDC_VERSION__ < 199901
# define true 1
# define false 0
# define bool int
@@ -30,6 +43,10 @@
# include <stdbool.h>
#endif
+#if __STDC_VERSION__ < 202311
+# define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1]
+#endif
+
/*
** zdump has been made independent of the rest of the time
** conversion package to increase confidence in the verification it provides.
@@ -52,19 +69,19 @@
# define HAVE_DECL_ASCTIME_R 1
#endif
-#if !defined HAVE_GENERIC && defined __has_extension
+#if !defined HAVE__GENERIC && defined __has_extension
# if __has_extension(c_generic_selections)
-# define HAVE_GENERIC 1
+# define HAVE__GENERIC 1
# else
-# define HAVE_GENERIC 0
+# define HAVE__GENERIC 0
# endif
#endif
/* _Generic is buggy in pre-4.9 GCC. */
-#if !defined HAVE_GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__
-# define HAVE_GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
+#if !defined HAVE__GENERIC && defined __GNUC__ && !defined __STRICT_ANSI__
+# define HAVE__GENERIC (4 < __GNUC__ + (9 <= __GNUC_MINOR__))
#endif
-#ifndef HAVE_GENERIC
-# define HAVE_GENERIC (201112 <= __STDC_VERSION__)
+#ifndef HAVE__GENERIC
+# define HAVE__GENERIC (201112 <= __STDC_VERSION__)
#endif
#if !defined HAVE_GETTEXT && defined __has_include
@@ -100,10 +117,6 @@
# define HAVE_STRDUP 1
#endif
-#ifndef HAVE_STRTOLL
-# define HAVE_STRTOLL 1
-#endif
-
#ifndef HAVE_SYMLINK
# define HAVE_SYMLINK 1
#endif /* !defined HAVE_SYMLINK */
@@ -185,6 +198,9 @@
#include <stddef.h>
#include <string.h>
+#if !PORT_TO_C89
+# include <inttypes.h>
+#endif
#include <limits.h> /* for CHAR_BIT et al. */
#include <stdlib.h>
@@ -254,10 +270,12 @@
# define R_OK 4
#endif /* !defined R_OK */
+#if PORT_TO_C89
+
/*
** Define HAVE_STDINT_H's default value here, rather than at the
** start, since __GLIBC__ and INTMAX_MAX's values depend on
-** previously-included files. glibc 2.1 and Solaris 10 and later have
+** previously included files. glibc 2.1 and Solaris 10 and later have
** stdint.h, even with pre-C99 compilers.
*/
#if !defined HAVE_STDINT_H && defined __has_include
@@ -334,6 +352,9 @@ typedef int int_fast32_t;
#ifndef INTMAX_MAX
# ifdef LLONG_MAX
typedef long long intmax_t;
+# ifndef HAVE_STRTOLL
+# define HAVE_STRTOLL true
+# endif
# if HAVE_STRTOLL
# define strtoimax strtoll
# endif
@@ -379,8 +400,10 @@ typedef unsigned long long uint_fast64_t;
#ifndef UINTMAX_MAX
# ifdef ULLONG_MAX
typedef unsigned long long uintmax_t;
+# define UINTMAX_MAX ULLONG_MAX
# else
typedef unsigned long uintmax_t;
+# define UINTMAX_MAX ULONG_MAX
# endif
#endif
@@ -396,6 +419,16 @@ typedef unsigned long uintmax_t;
# define SIZE_MAX ((size_t) -1)
#endif
+#endif /* PORT_TO_C89 */
+
+/* The maximum size of any created object, as a signed integer.
+ Although the C standard does not outright prohibit larger objects,
+ behavior is undefined if the result of pointer subtraction does not
+ fit into ptrdiff_t, and the code assumes in several places that
+ pointer subtraction works. As a practical matter it's OK to not
+ support objects larger than this. */
+#define INDEX_MAX ((ptrdiff_t) min(PTRDIFF_MAX, SIZE_MAX))
+
/* Support ckd_add, ckd_sub, ckd_mul on C23 or recent-enough GCC-like
hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */
#if !defined HAVE_STDCKDINT_H && defined __has_include
@@ -435,12 +468,25 @@ typedef unsigned long uintmax_t;
#if (defined __has_c_attribute \
&& (202311 <= __STDC_VERSION__ || !defined __STRICT_ANSI__))
-# define HAVE_HAS_C_ATTRIBUTE true
+# define HAVE___HAS_C_ATTRIBUTE true
#else
-# define HAVE_HAS_C_ATTRIBUTE false
+# define HAVE___HAS_C_ATTRIBUTE false
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
+# if __has_c_attribute(deprecated)
+# define ATTRIBUTE_DEPRECATED [[deprecated]]
+# endif
+#endif
+#ifndef ATTRIBUTE_DEPRECATED
+# if 3 < __GNUC__ + (2 <= __GNUC_MINOR__)
+# define ATTRIBUTE_DEPRECATED __attribute__((deprecated))
+# else
+# define ATTRIBUTE_DEPRECATED /* empty */
+# endif
+#endif
+
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(fallthrough)
# define ATTRIBUTE_FALLTHROUGH [[fallthrough]]
# endif
@@ -453,7 +499,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(maybe_unused)
# define ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]]
# endif
@@ -466,7 +512,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(noreturn)
# define ATTRIBUTE_NORETURN [[noreturn]]
# endif
@@ -481,7 +527,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(reproducible)
# define ATTRIBUTE_REPRODUCIBLE [[reproducible]]
# endif
@@ -494,7 +540,7 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if HAVE_HAS_C_ATTRIBUTE
+#if HAVE___HAS_C_ATTRIBUTE
# if __has_c_attribute(unsequenced)
# define ATTRIBUTE_UNSEQUENCED [[unsequenced]]
# endif
@@ -507,7 +553,8 @@ typedef unsigned long uintmax_t;
# endif
#endif
-#if __STDC_VERSION__ < 199901 && !defined restrict
+#if (__STDC_VERSION__ < 199901 && !defined restrict \
+ && (PORT_TO_C89 || defined _MSC_VER))
# define restrict /* empty */
#endif
@@ -624,11 +671,16 @@ typedef time_tz tz_time_t;
# define altzone tz_altzone
# endif
-char *asctime(struct tm const *);
+# if __STDC_VERSION__ < 202311
+# define DEPRECATED_IN_C23 /* empty */
+# else
+# define DEPRECATED_IN_C23 ATTRIBUTE_DEPRECATED
+# endif
+DEPRECATED_IN_C23 char *asctime(struct tm const *);
char *asctime_r(struct tm const *restrict, char *restrict);
-char *ctime(time_t const *);
+DEPRECATED_IN_C23 char *ctime(time_t const *);
char *ctime_r(time_t const *, char *);
-double difftime(time_t, time_t) ATTRIBUTE_UNSEQUENCED;
+ATTRIBUTE_UNSEQUENCED double difftime(time_t, time_t);
size_t strftime(char *restrict, size_t, char const *restrict,
struct tm const *restrict);
# if HAVE_STRFTIME_L
@@ -691,7 +743,10 @@ extern long altzone;
** declarations if time_tz is defined.
*/
-#ifdef STD_INSPIRED
+#ifndef STD_INSPIRED
+# define STD_INSPIRED 0
+#endif
+#if STD_INSPIRED
# if TZ_TIME_T || !defined offtime
struct tm *offtime(time_t const *, long);
# endif
@@ -738,12 +793,12 @@ struct tm *localtime_rz(timezone_t restrict, time_t const *restrict,
time_t mktime_z(timezone_t restrict, struct tm *restrict);
timezone_t tzalloc(char const *);
void tzfree(timezone_t);
-# ifdef STD_INSPIRED
+# if STD_INSPIRED
# if TZ_TIME_T || !defined posix2time_z
-time_t posix2time_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
+ATTRIBUTE_REPRODUCIBLE time_t posix2time_z(timezone_t, time_t);
# endif
# if TZ_TIME_T || !defined time2posix_z
-time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
+ATTRIBUTE_REPRODUCIBLE time_t time2posix_z(timezone_t, time_t);
# endif
# endif
#endif
@@ -752,7 +807,7 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
** Finally, some convenience items.
*/
-#define TYPE_BIT(type) (sizeof(type) * CHAR_BIT)
+#define TYPE_BIT(type) (CHAR_BIT * (ptrdiff_t) sizeof(type))
#define TYPE_SIGNED(type) (((type) -1) < 0)
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
@@ -780,7 +835,7 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
This implementation assumes no padding if time_t is signed and
either the compiler lacks support for _Generic or time_t is not one
of the standard signed integer types. */
-#if HAVE_GENERIC
+#if HAVE__GENERIC
# define TIME_T_MIN \
_Generic((time_t) 0, \
signed char: SCHAR_MIN, short: SHRT_MIN, \
@@ -793,10 +848,23 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX, \
default: TIME_T_MAX_NO_PADDING) \
: (time_t) -1)
+enum { SIGNED_PADDING_CHECK_NEEDED
+ = _Generic((time_t) 0,
+ signed char: false, short: false,
+ int: false, long: false, long long: false,
+ default: true) };
#else
# define TIME_T_MIN TIME_T_MIN_NO_PADDING
# define TIME_T_MAX TIME_T_MAX_NO_PADDING
+enum { SIGNED_PADDING_CHECK_NEEDED = true };
#endif
+/* Try to check the padding assumptions. Although TIME_T_MAX and the
+ following check can both have undefined behavior on oddball
+ platforms due to shifts exceeding widths of signed integers, these
+ platforms' compilers are likely to diagnose these issues in integer
+ constant expressions, so it shouldn't hurt to check statically. */
+static_assert(! TYPE_SIGNED(time_t) || ! SIGNED_PADDING_CHECK_NEEDED
+ || TIME_T_MAX >> (TYPE_BIT(time_t) - 2) == 1);
/*
** 302 / 1000 is log10(2.0) rounded up.
@@ -863,7 +931,7 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_REPRODUCIBLE;
#if HAVE_INCOMPATIBLE_CTIME_R
#undef asctime_r
#undef ctime_r
-char *asctime_r(struct tm const *, char *);
+char *asctime_r(struct tm const *restrict, char *restrict);
char *ctime_r(time_t const *, char *);
#endif /* HAVE_INCOMPATIBLE_CTIME_R */