mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-22 10:50:07 +00:00
Update timezone code from tzcode 2017b.
This patch updates files coming from tzcode to the versions in tzcode 2017b. A couple of changes to other glibc code are needed. time/tzset.c was using the SECSPERDAY macro from tzfile.h, which no longer defines that macro, so a local definition is added to tzset.c. Because timezone/private.h now defines the _ macro whenever HAVE_GETTEXT is true, even if it was previously defined, it is also necessary to avoid a conflict with the definition in include/libintl.h. Defining _ISOMAC is the obvious way to avoid such internal definitions being visible, together with defining TZ_DOMAIN so that zic and zdump continue to get the messages from the libc domain as desired. However, zic and zdump rely on PKGVERSION and REPORT_BUGS_TO from config.h, which is not included by default with _ISOMAC, so -include config.h needs adding to the options for these programs as well. Together those changes allow unmodified tzcode 2017b sources to work in glibc. Tested for x86_64. * timezone/private.h: Update from tzcode 2017b. * timezone/tzfile.h: Likewise. * timezone/tzselect.ksh: Likewise. * timezone/zdump.c: Likewise. * timezone/zic.c: Likewise. * timezone/Makefile (tz-cflags): Add -D_ISOMAC -DTZ_DOMAIN='"libc"' -include $(common-objpfx)config.h. * time/tzset.c (SECSPERDAY): New macro.
This commit is contained in:
parent
a448ee41e7
commit
92bd70fb85
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
||||
2017-06-16 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* timezone/private.h: Update from tzcode 2017b.
|
||||
* timezone/tzfile.h: Likewise.
|
||||
* timezone/tzselect.ksh: Likewise.
|
||||
* timezone/zdump.c: Likewise.
|
||||
* timezone/zic.c: Likewise.
|
||||
* timezone/Makefile (tz-cflags): Add -D_ISOMAC
|
||||
-DTZ_DOMAIN='"libc"' -include $(common-objpfx)config.h.
|
||||
* time/tzset.c (SECSPERDAY): New macro.
|
||||
|
||||
2017-06-16 Rical Jasan <ricaljasan@pacific.net>
|
||||
|
||||
* manual/string.texi (strdup): Complete header and standards
|
||||
|
@ -27,6 +27,8 @@
|
||||
|
||||
#include <timezone/tzfile.h>
|
||||
|
||||
#define SECSPERDAY 86400
|
||||
|
||||
char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
|
||||
int __daylight = 0;
|
||||
long int __timezone = 0L;
|
||||
|
@ -59,7 +59,8 @@ tz-cflags = -DTZDIR='"$(zonedir)"' \
|
||||
-DTZDEFAULT='"$(localtime-file)"' \
|
||||
-DTZDEFRULES='"$(posixrules-file)"' \
|
||||
-DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone \
|
||||
-DHAVE_GETTEXT -DUSE_LTZ=0 -Wno-maybe-uninitialized
|
||||
-DHAVE_GETTEXT -DUSE_LTZ=0 -D_ISOMAC -DTZ_DOMAIN='"libc"' \
|
||||
-include $(common-objpfx)config.h -Wno-maybe-uninitialized
|
||||
|
||||
# The -Wno-unused-variable flag is used to prevent GCC 6
|
||||
# from warning about time_t_min and time_t_max which are
|
||||
|
@ -15,6 +15,7 @@
|
||||
** Thank you!
|
||||
*/
|
||||
|
||||
/* This string was in the Factory zone through version 2016f. */
|
||||
#define GRANDPARENTED "Local time zone must be set--see zic manual page"
|
||||
|
||||
/*
|
||||
@ -22,6 +23,10 @@
|
||||
** You can override these in your C compiler options, e.g. '-DHAVE_GETTEXT=1'.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_DECL_ASCTIME_R
|
||||
#define HAVE_DECL_ASCTIME_R 1
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETTEXT
|
||||
#define HAVE_GETTEXT 0
|
||||
#endif /* !defined HAVE_GETTEXT */
|
||||
@ -34,6 +39,10 @@
|
||||
#define HAVE_LINK 1
|
||||
#endif /* !defined HAVE_LINK */
|
||||
|
||||
#ifndef HAVE_POSIX_DECLS
|
||||
#define HAVE_POSIX_DECLS 1
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
#define HAVE_STRDUP 1
|
||||
#endif
|
||||
@ -69,9 +78,9 @@
|
||||
|
||||
/* Enable tm_gmtoff and tm_zone on GNUish systems. */
|
||||
#define _GNU_SOURCE 1
|
||||
/* Fix asctime_r on Solaris 10. */
|
||||
/* Fix asctime_r on Solaris 11. */
|
||||
#define _POSIX_PTHREAD_SEMANTICS 1
|
||||
/* Enable strtoimax on Solaris 10. */
|
||||
/* Enable strtoimax on pre-C99 Solaris 11. */
|
||||
#define __EXTENSIONS__ 1
|
||||
|
||||
/*
|
||||
@ -95,23 +104,26 @@
|
||||
#undef tzalloc
|
||||
#undef tzfree
|
||||
|
||||
#include "sys/types.h" /* for time_t */
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "limits.h" /* for CHAR_BIT et al. */
|
||||
#include "stdlib.h"
|
||||
#include <sys/types.h> /* for time_t */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> /* for CHAR_BIT et al. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "errno.h"
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef ENAMETOOLONG
|
||||
# define ENAMETOOLONG EINVAL
|
||||
#endif
|
||||
#ifndef ENOTSUP
|
||||
# define ENOTSUP EINVAL
|
||||
#endif
|
||||
#ifndef EOVERFLOW
|
||||
# define EOVERFLOW EINVAL
|
||||
#endif
|
||||
|
||||
#if HAVE_GETTEXT
|
||||
#include "libintl.h"
|
||||
#include <libintl.h>
|
||||
#endif /* HAVE_GETTEXT */
|
||||
|
||||
#if HAVE_SYS_WAIT_H
|
||||
@ -126,7 +138,7 @@
|
||||
#endif /* !defined WEXITSTATUS */
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include "unistd.h" /* for F_OK, R_OK, and other POSIX goodness */
|
||||
#include <unistd.h> /* for F_OK, R_OK, and other POSIX goodness */
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#ifndef HAVE_STRFTIME_L
|
||||
@ -149,19 +161,19 @@
|
||||
|
||||
/*
|
||||
** Define HAVE_STDINT_H's default value here, rather than at the
|
||||
** start, since __GLIBC__'s value depends on previously-included
|
||||
** files.
|
||||
** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
|
||||
** start, since __GLIBC__ and INTMAX_MAX's values depend on
|
||||
** previously-included files. glibc 2.1 and Solaris 10 and later have
|
||||
** stdint.h, even with pre-C99 compilers.
|
||||
*/
|
||||
#ifndef HAVE_STDINT_H
|
||||
#define HAVE_STDINT_H \
|
||||
(199901 <= __STDC_VERSION__ \
|
||||
|| 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \
|
||||
|| __CYGWIN__)
|
||||
|| __CYGWIN__ || INTMAX_MAX)
|
||||
#endif /* !defined HAVE_STDINT_H */
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
#include "stdint.h"
|
||||
#include <stdint.h>
|
||||
#endif /* !HAVE_STDINT_H */
|
||||
|
||||
#ifndef HAVE_INTTYPES_H
|
||||
@ -197,14 +209,18 @@ typedef long int_fast64_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SCNdFAST64
|
||||
#ifndef PRIdFAST64
|
||||
# if INT_FAST64_MAX == LLONG_MAX
|
||||
# define SCNdFAST64 "lld"
|
||||
# define PRIdFAST64 "lld"
|
||||
# else
|
||||
# define SCNdFAST64 "ld"
|
||||
# define PRIdFAST64 "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SCNdFAST64
|
||||
# define SCNdFAST64 PRIdFAST64
|
||||
#endif
|
||||
|
||||
#ifndef INT_FAST32_MAX
|
||||
# if INT_MAX >> 31 == 0
|
||||
typedef long int_fast32_t;
|
||||
@ -304,6 +320,13 @@ typedef unsigned long uintmax_t;
|
||||
** Workarounds for compilers/systems.
|
||||
*/
|
||||
|
||||
#ifndef EPOCH_LOCAL
|
||||
# define EPOCH_LOCAL 0
|
||||
#endif
|
||||
#ifndef EPOCH_OFFSET
|
||||
# define EPOCH_OFFSET 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Compile with -Dtime_tz=T to build the tz package with a private
|
||||
** time_t type equivalent to T rather than the system-supplied time_t.
|
||||
@ -311,7 +334,7 @@ typedef unsigned long uintmax_t;
|
||||
** (e.g., time_t wider than 'long', or unsigned time_t) even on
|
||||
** typical platforms.
|
||||
*/
|
||||
#ifdef time_tz
|
||||
#if defined time_tz || EPOCH_LOCAL || EPOCH_OFFSET != 0
|
||||
# ifdef LOCALTIME_IMPLEMENTATION
|
||||
static time_t sys_time(time_t *x) { return time(x); }
|
||||
# endif
|
||||
@ -379,25 +402,21 @@ time_t time(time_t *);
|
||||
void tzset(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Some time.h implementations don't declare asctime_r.
|
||||
** Others might define it as a macro.
|
||||
** Fix the former without affecting the latter.
|
||||
** Similarly for timezone, daylight, and altzone.
|
||||
*/
|
||||
|
||||
#ifndef asctime_r
|
||||
extern char * asctime_r(struct tm const *restrict, char *restrict);
|
||||
#if !HAVE_DECL_ASCTIME_R && !defined asctime_r
|
||||
extern char *asctime_r(struct tm const *restrict, char *restrict);
|
||||
#endif
|
||||
|
||||
#ifdef USG_COMPAT
|
||||
# ifndef timezone
|
||||
#if !HAVE_POSIX_DECLS
|
||||
# ifdef USG_COMPAT
|
||||
# ifndef timezone
|
||||
extern long timezone;
|
||||
# endif
|
||||
# ifndef daylight
|
||||
# endif
|
||||
# ifndef daylight
|
||||
extern int daylight;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined ALTZONE && !defined altzone
|
||||
extern long altzone;
|
||||
#endif
|
||||
@ -481,14 +500,8 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
|
||||
# include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifndef TYPE_BIT
|
||||
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
|
||||
#endif /* !defined TYPE_BIT */
|
||||
|
||||
#ifndef TYPE_SIGNED
|
||||
#define TYPE_SIGNED(type) (((type) -1) < 0)
|
||||
#endif /* !defined TYPE_SIGNED */
|
||||
|
||||
#define TWOS_COMPLEMENT(t) ((t) ~ (t) 0 < 0)
|
||||
|
||||
/* Max and min values of the integer type T, of which only the bottom
|
||||
@ -500,11 +513,29 @@ time_t time2posix_z(timezone_t, time_t) ATTRIBUTE_PURE;
|
||||
#define MINVAL(t, b) \
|
||||
((t) (TYPE_SIGNED(t) ? - TWOS_COMPLEMENT(t) - MAXVAL(t, b) : 0))
|
||||
|
||||
/* The minimum and maximum finite time values. This assumes no padding. */
|
||||
/* The minimum and maximum finite time values. This implementation
|
||||
assumes no padding if time_t is signed and either the compiler is
|
||||
pre-C11 or time_t is not one of the standard signed integer types. */
|
||||
#if 201112 <= __STDC_VERSION__
|
||||
static time_t const time_t_min
|
||||
= (TYPE_SIGNED(time_t)
|
||||
? _Generic((time_t) 0,
|
||||
signed char: SCHAR_MIN, short: SHRT_MIN,
|
||||
int: INT_MIN, long: LONG_MIN, long long: LLONG_MIN,
|
||||
default: MINVAL(time_t, TYPE_BIT(time_t)))
|
||||
: 0);
|
||||
static time_t const time_t_max
|
||||
= (TYPE_SIGNED(time_t)
|
||||
? _Generic((time_t) 0,
|
||||
signed char: SCHAR_MAX, short: SHRT_MAX,
|
||||
int: INT_MAX, long: LONG_MAX, long long: LLONG_MAX,
|
||||
default: MAXVAL(time_t, TYPE_BIT(time_t)))
|
||||
: -1);
|
||||
#else
|
||||
static time_t const time_t_min = MINVAL(time_t, TYPE_BIT(time_t));
|
||||
static time_t const time_t_max = MAXVAL(time_t, TYPE_BIT(time_t));
|
||||
#endif
|
||||
|
||||
#ifndef INT_STRLEN_MAXIMUM
|
||||
/*
|
||||
** 302 / 1000 is log10(2.0) rounded up.
|
||||
** Subtract one for the sign bit if the type is signed;
|
||||
@ -514,7 +545,6 @@ static time_t const time_t_max = MAXVAL(time_t, TYPE_BIT(time_t));
|
||||
#define INT_STRLEN_MAXIMUM(type) \
|
||||
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
|
||||
1 + TYPE_SIGNED(type))
|
||||
#endif /* !defined INT_STRLEN_MAXIMUM */
|
||||
|
||||
/*
|
||||
** INITIALIZE(x)
|
||||
@ -536,13 +566,11 @@ static time_t const time_t_max = MAXVAL(time_t, TYPE_BIT(time_t));
|
||||
** The default is to use gettext if available, and use MSGID otherwise.
|
||||
*/
|
||||
|
||||
#ifndef _
|
||||
#if HAVE_GETTEXT
|
||||
#define _(msgid) gettext(msgid)
|
||||
#else /* !HAVE_GETTEXT */
|
||||
#define _(msgid) msgid
|
||||
#endif /* !HAVE_GETTEXT */
|
||||
#endif /* !defined _ */
|
||||
|
||||
#if !defined TZ_DOMAIN && defined HAVE_GETTEXT
|
||||
# define TZ_DOMAIN "tz"
|
||||
@ -555,24 +583,70 @@ char *asctime_r(struct tm const *, char *);
|
||||
char *ctime_r(time_t const *, char *);
|
||||
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
|
||||
|
||||
#ifndef YEARSPERREPEAT
|
||||
/* Handy macros that are independent of tzfile implementation. */
|
||||
|
||||
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
|
||||
#endif /* !defined YEARSPERREPEAT */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
/*
|
||||
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
|
||||
** isleap(y) == isleap(y % 400)
|
||||
** and so
|
||||
** isleap(a + b) == isleap((a + b) % 400)
|
||||
** or
|
||||
** isleap(a + b) == isleap(a % 400 + b % 400)
|
||||
** This is true even if % means modulo rather than Fortran remainder
|
||||
** (which is allowed by C89 but not C99).
|
||||
** We use this to avoid addition overflow problems.
|
||||
*/
|
||||
|
||||
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
|
||||
|
||||
|
||||
/*
|
||||
** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
|
||||
*/
|
||||
|
||||
#ifndef AVGSECSPERYEAR
|
||||
#define AVGSECSPERYEAR 31556952L
|
||||
#endif /* !defined AVGSECSPERYEAR */
|
||||
|
||||
#ifndef SECSPERREPEAT
|
||||
#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
|
||||
#endif /* !defined SECSPERREPEAT */
|
||||
|
||||
#ifndef SECSPERREPEAT_BITS
|
||||
#define SECSPERREPEAT \
|
||||
((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
|
||||
#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
|
||||
#endif /* !defined SECSPERREPEAT_BITS */
|
||||
|
||||
#endif /* !defined PRIVATE_H */
|
||||
|
@ -114,56 +114,4 @@ struct tzhead {
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
#endif /* !defined TZ_MAX_LEAPS */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
/*
|
||||
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
|
||||
** isleap(y) == isleap(y % 400)
|
||||
** and so
|
||||
** isleap(a + b) == isleap((a + b) % 400)
|
||||
** or
|
||||
** isleap(a + b) == isleap(a % 400 + b % 400)
|
||||
** This is true even if % means modulo rather than Fortran remainder
|
||||
** (which is allowed by C89 but not C99).
|
||||
** We use this to avoid addition overflow problems.
|
||||
*/
|
||||
|
||||
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
|
||||
|
||||
#endif /* !defined TZFILE_H */
|
||||
|
@ -7,7 +7,7 @@ REPORT_BUGS_TO=tz@iana.org
|
||||
# Ask the user about the time zone, and output the resulting TZ value to stdout.
|
||||
# Interact with the user via stderr and stdin.
|
||||
|
||||
# Contributed by Paul Eggert.
|
||||
# Contributed by Paul Eggert. This file is in the public domain.
|
||||
|
||||
# Porting notes:
|
||||
#
|
||||
@ -346,11 +346,14 @@ while
|
||||
'that is 10 hours ahead (east) of UTC.'
|
||||
read TZ
|
||||
$AWK -v TZ="$TZ" 'BEGIN {
|
||||
tzname = "[^-+,0-9][^-+,0-9][^-+,0-9]+"
|
||||
time = "[0-2]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?"
|
||||
tzname = "(<[[:alnum:]+-]{3,}>|[[:alpha:]]{3,})"
|
||||
time = "(2[0-4]|[0-1]?[0-9])" \
|
||||
"(:[0-5][0-9](:[0-5][0-9])?)?"
|
||||
offset = "[-+]?" time
|
||||
date = "(J?[0-9]+|M[0-9]+\\.[0-9]+\\.[0-9]+)"
|
||||
datetime = "," date "(/" time ")?"
|
||||
mdate = "M([1-9]|1[0-2])\\.[1-5]\\.[0-6]"
|
||||
jdate = "((J[1-9]|[0-9]|J?[1-9][0-9]" \
|
||||
"|J?[1-2][0-9][0-9])|J?3[0-5][0-9]|J?36[0-5])"
|
||||
datetime = ",(" mdate "|" jdate ")(/" time ")?"
|
||||
tzpattern = "^(:.*|" tzname offset "(" tzname \
|
||||
"(" offset ")?(" datetime datetime ")?)?)$"
|
||||
if (TZ ~ tzpattern) exit 1
|
||||
@ -509,7 +512,7 @@ while
|
||||
case $TZsec in
|
||||
$UTsec)
|
||||
extra_info="
|
||||
Local time is now: $TZdate.
|
||||
Selected time is now: $TZdate.
|
||||
Universal Time is now: $UTdate."
|
||||
break
|
||||
esac
|
||||
@ -545,7 +548,7 @@ case $SHELL in
|
||||
*) file=.profile line="TZ='$TZ'; export TZ"
|
||||
esac
|
||||
|
||||
say >&2 "
|
||||
test -t 1 && say >&2 "
|
||||
You can make this change permanent for yourself by appending the line
|
||||
$line
|
||||
to the file '$file' in your home directory; then log out and log in again.
|
||||
|
543
timezone/zdump.c
543
timezone/zdump.c
@ -19,89 +19,7 @@
|
||||
# define USE_LTZ 1
|
||||
#endif
|
||||
|
||||
#if USE_LTZ
|
||||
# include "private.h"
|
||||
#endif
|
||||
|
||||
/* Enable tm_gmtoff and tm_zone on GNUish systems. */
|
||||
#define _GNU_SOURCE 1
|
||||
/* Enable strtoimax on Solaris 10. */
|
||||
#define __EXTENSIONS__ 1
|
||||
|
||||
#include "stdio.h" /* for stdout, stderr, perror */
|
||||
#include "string.h" /* for strcpy */
|
||||
#include "sys/types.h" /* for time_t */
|
||||
#include "time.h" /* for struct tm */
|
||||
#include "stdlib.h" /* for exit, malloc, atoi */
|
||||
#include "limits.h" /* for CHAR_BIT, LLONG_MAX */
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
** Substitutes for pre-C99 compilers.
|
||||
** Much of this section of code is stolen from private.h.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_STDINT_H
|
||||
# define HAVE_STDINT_H \
|
||||
(199901 <= __STDC_VERSION__ \
|
||||
|| 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \
|
||||
|| __CYGWIN__)
|
||||
#endif
|
||||
#if HAVE_STDINT_H
|
||||
# include "stdint.h"
|
||||
#endif
|
||||
#ifndef HAVE_INTTYPES_H
|
||||
# define HAVE_INTTYPES_H HAVE_STDINT_H
|
||||
#endif
|
||||
#if HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifndef INT_FAST32_MAX
|
||||
# if INT_MAX >> 31 == 0
|
||||
typedef long int_fast32_t;
|
||||
# else
|
||||
typedef int int_fast32_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
|
||||
#if !defined LLONG_MAX && defined __LONG_LONG_MAX__
|
||||
# define LLONG_MAX __LONG_LONG_MAX__
|
||||
#endif
|
||||
|
||||
#ifndef INTMAX_MAX
|
||||
# ifdef LLONG_MAX
|
||||
typedef long long intmax_t;
|
||||
# define strtoimax strtoll
|
||||
# define INTMAX_MAX LLONG_MAX
|
||||
# else
|
||||
typedef long intmax_t;
|
||||
# define strtoimax strtol
|
||||
# define INTMAX_MAX LONG_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PRIdMAX
|
||||
# if INTMAX_MAX == LLONG_MAX
|
||||
# define PRIdMAX "lld"
|
||||
# else
|
||||
# define PRIdMAX "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Infer TM_ZONE on systems where this information is known, but suppress
|
||||
guessing if NO_TM_ZONE is defined. Similarly for TM_GMTOFF. */
|
||||
#if (defined __GLIBC__ \
|
||||
|| defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \
|
||||
|| (defined __APPLE__ && defined __MACH__))
|
||||
# if !defined TM_GMTOFF && !defined NO_TM_GMTOFF
|
||||
# define TM_GMTOFF tm_gmtoff
|
||||
# endif
|
||||
# if !defined TM_ZONE && !defined NO_TM_ZONE
|
||||
# define TM_ZONE tm_zone
|
||||
# endif
|
||||
#endif
|
||||
#include "private.h"
|
||||
|
||||
#ifndef HAVE_LOCALTIME_R
|
||||
# define HAVE_LOCALTIME_R 1
|
||||
@ -131,62 +49,6 @@ typedef long intmax_t;
|
||||
#define MAX_STRING_LENGTH 1024
|
||||
#endif /* !defined MAX_STRING_LENGTH */
|
||||
|
||||
#if __STDC_VERSION__ < 199901
|
||||
# define true 1
|
||||
# define false 0
|
||||
# define bool int
|
||||
#else
|
||||
# include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXIT_SUCCESS
|
||||
#define EXIT_SUCCESS 0
|
||||
#endif /* !defined EXIT_SUCCESS */
|
||||
|
||||
#ifndef EXIT_FAILURE
|
||||
#define EXIT_FAILURE 1
|
||||
#endif /* !defined EXIT_FAILURE */
|
||||
|
||||
#ifndef SECSPERMIN
|
||||
#define SECSPERMIN 60
|
||||
#endif /* !defined SECSPERMIN */
|
||||
|
||||
#ifndef MINSPERHOUR
|
||||
#define MINSPERHOUR 60
|
||||
#endif /* !defined MINSPERHOUR */
|
||||
|
||||
#ifndef SECSPERHOUR
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#endif /* !defined SECSPERHOUR */
|
||||
|
||||
#ifndef HOURSPERDAY
|
||||
#define HOURSPERDAY 24
|
||||
#endif /* !defined HOURSPERDAY */
|
||||
|
||||
#ifndef EPOCH_YEAR
|
||||
#define EPOCH_YEAR 1970
|
||||
#endif /* !defined EPOCH_YEAR */
|
||||
|
||||
#ifndef TM_YEAR_BASE
|
||||
#define TM_YEAR_BASE 1900
|
||||
#endif /* !defined TM_YEAR_BASE */
|
||||
|
||||
#ifndef DAYSPERNYEAR
|
||||
#define DAYSPERNYEAR 365
|
||||
#endif /* !defined DAYSPERNYEAR */
|
||||
|
||||
#ifndef isleap
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
#endif /* !defined isleap */
|
||||
|
||||
#ifndef isleap_sum
|
||||
/*
|
||||
** See tzfile.h for details on isleap_sum.
|
||||
*/
|
||||
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
|
||||
#endif /* !defined isleap_sum */
|
||||
|
||||
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
|
||||
#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
|
||||
#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
|
||||
#define SECSPER400YEARS (SECSPERNYEAR * (intmax_t) (300 + 3) \
|
||||
@ -201,49 +63,24 @@ typedef long intmax_t;
|
||||
*/
|
||||
enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
|
||||
|
||||
#ifndef HAVE_GETTEXT
|
||||
#define HAVE_GETTEXT 0
|
||||
#endif
|
||||
#if HAVE_GETTEXT
|
||||
#include "locale.h" /* for setlocale */
|
||||
#include "libintl.h"
|
||||
#include <locale.h> /* for setlocale */
|
||||
#endif /* HAVE_GETTEXT */
|
||||
|
||||
#if 2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)
|
||||
# define ATTRIBUTE_PURE __attribute__ ((__pure__))
|
||||
#else
|
||||
# define ATTRIBUTE_PURE /* empty */
|
||||
#endif
|
||||
|
||||
/*
|
||||
** For the benefit of GNU folk...
|
||||
** '_(MSGID)' uses the current locale's message library string for MSGID.
|
||||
** The default is to use gettext if available, and use MSGID otherwise.
|
||||
*/
|
||||
|
||||
#ifndef _
|
||||
#if HAVE_GETTEXT
|
||||
#define _(msgid) gettext(msgid)
|
||||
#else /* !HAVE_GETTEXT */
|
||||
#define _(msgid) msgid
|
||||
#endif /* !HAVE_GETTEXT */
|
||||
#endif /* !defined _ */
|
||||
|
||||
#if !defined TZ_DOMAIN && defined HAVE_GETTEXT
|
||||
# define TZ_DOMAIN "tz"
|
||||
#endif
|
||||
|
||||
#if ! HAVE_LOCALTIME_RZ
|
||||
# undef timezone_t
|
||||
# define timezone_t char **
|
||||
#endif
|
||||
|
||||
extern char ** environ;
|
||||
|
||||
#if !HAVE_POSIX_DECLS
|
||||
extern int getopt(int argc, char * const argv[],
|
||||
const char * options);
|
||||
extern char * optarg;
|
||||
extern int optind;
|
||||
extern char * tzname[2];
|
||||
extern char * tzname[];
|
||||
#endif
|
||||
|
||||
/* The minimum and maximum finite time values. */
|
||||
enum { atime_shift = CHAR_BIT * sizeof (time_t) - 2 };
|
||||
@ -266,6 +103,8 @@ static intmax_t delta(struct tm *, struct tm *) ATTRIBUTE_PURE;
|
||||
static void dumptime(struct tm const *);
|
||||
static time_t hunt(timezone_t, char *, time_t, time_t);
|
||||
static void show(timezone_t, char *, time_t, bool);
|
||||
static void showtrans(char const *, struct tm const *, time_t, char const *,
|
||||
char const *);
|
||||
static const char *tformat(void);
|
||||
static time_t yeartot(intmax_t) ATTRIBUTE_PURE;
|
||||
|
||||
@ -303,6 +142,19 @@ sumsize(size_t a, size_t b)
|
||||
return sum;
|
||||
}
|
||||
|
||||
/* Return a pointer to a newly allocated buffer of size SIZE, exiting
|
||||
on failure. SIZE should be nonzero. */
|
||||
static void *
|
||||
xmalloc(size_t size)
|
||||
{
|
||||
void *p = malloc(size);
|
||||
if (!p) {
|
||||
perror(progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
#if ! HAVE_TZSET
|
||||
# undef tzset
|
||||
# define tzset zdump_tzset
|
||||
@ -390,21 +242,13 @@ tzalloc(char const *val)
|
||||
|
||||
while (*e++)
|
||||
continue;
|
||||
env = malloc(sumsize(sizeof *environ,
|
||||
(e - environ) * sizeof *environ));
|
||||
if (! env) {
|
||||
perror(progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
env = xmalloc(sumsize(sizeof *environ,
|
||||
(e - environ) * sizeof *environ));
|
||||
to = 1;
|
||||
for (e = environ; (env[to] = *e); e++)
|
||||
to += strncmp(*e, "TZ=", 3) != 0;
|
||||
}
|
||||
env0 = malloc(sumsize(sizeof "TZ=", strlen(val)));
|
||||
if (! env0) {
|
||||
perror(progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
env0 = xmalloc(sumsize(sizeof "TZ=", strlen(val)));
|
||||
env[0] = strcat(strcpy(env0, "TZ="), val);
|
||||
environ = fakeenv = env;
|
||||
tzset();
|
||||
@ -525,11 +369,7 @@ saveabbr(char **buf, size_t *bufalloc, struct tm const *tmp)
|
||||
to avoid O(N**2) behavior on repeated calls. */
|
||||
*bufalloc = sumsize(*bufalloc, ablen + 1);
|
||||
|
||||
*buf = malloc(*bufalloc);
|
||||
if (! *buf) {
|
||||
perror(progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*buf = xmalloc(*bufalloc);
|
||||
}
|
||||
return strcpy(*buf, ab);
|
||||
}
|
||||
@ -550,10 +390,18 @@ static void
|
||||
usage(FILE * const stream, const int status)
|
||||
{
|
||||
fprintf(stream,
|
||||
_("%s: usage: %s [--version] [--help] [-{vV}] [-{ct} [lo,]hi] zonename ...\n"
|
||||
_("%s: usage: %s OPTIONS ZONENAME ...\n"
|
||||
"Options include:\n"
|
||||
" -c [L,]U Start at year L (default -500), end before year U (default 2500)\n"
|
||||
" -t [L,]U Start at time L, end before time U (in seconds since 1970)\n"
|
||||
" -i List transitions briefly (format is experimental)\n" \
|
||||
" -v List transitions verbosely\n"
|
||||
" -V List transitions a bit less verbosely\n"
|
||||
" --help Output this help\n"
|
||||
" --version Output version info\n"
|
||||
"\n"
|
||||
"Report bugs to %s.\n"),
|
||||
progname, progname, REPORT_BUGS_TO);
|
||||
progname, progname, REPORT_BUGS_TO);
|
||||
if (status == EXIT_SUCCESS)
|
||||
close_file(stream);
|
||||
exit(status);
|
||||
@ -565,7 +413,6 @@ main(int argc, char *argv[])
|
||||
/* These are static so that they're initially zero. */
|
||||
static char * abbrev;
|
||||
static size_t abbrevsize;
|
||||
static struct tm newtm;
|
||||
|
||||
register int i;
|
||||
register bool vflag;
|
||||
@ -575,11 +422,7 @@ main(int argc, char *argv[])
|
||||
register time_t cutlotime;
|
||||
register time_t cuthitime;
|
||||
time_t now;
|
||||
time_t t;
|
||||
time_t newt;
|
||||
struct tm tm;
|
||||
register struct tm * tmp;
|
||||
register struct tm * newtmp;
|
||||
bool iflag = false;
|
||||
|
||||
cutlotime = absolute_min_time;
|
||||
cuthitime = absolute_max_time;
|
||||
@ -601,9 +444,10 @@ main(int argc, char *argv[])
|
||||
vflag = Vflag = false;
|
||||
cutarg = cuttimes = NULL;
|
||||
for (;;)
|
||||
switch (getopt(argc, argv, "c:t:vV")) {
|
||||
switch (getopt(argc, argv, "c:it:vV")) {
|
||||
case 'c': cutarg = optarg; break;
|
||||
case 't': cuttimes = optarg; break;
|
||||
case 'i': iflag = true; break;
|
||||
case 'v': vflag = true; break;
|
||||
case 'V': Vflag = true; break;
|
||||
case -1:
|
||||
@ -615,7 +459,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
arg_processing_done:;
|
||||
|
||||
if (vflag | Vflag) {
|
||||
if (iflag | vflag | Vflag) {
|
||||
intmax_t lo;
|
||||
intmax_t hi;
|
||||
char *loend, *hiend;
|
||||
@ -672,7 +516,9 @@ main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
gmtzinit();
|
||||
now = time(NULL);
|
||||
INITIALIZE (now);
|
||||
if (! (iflag | vflag | Vflag))
|
||||
now = time(NULL);
|
||||
longest = 0;
|
||||
for (i = optind; i < argc; i++) {
|
||||
size_t arglen = strlen(argv[i]);
|
||||
@ -683,48 +529,66 @@ main(int argc, char *argv[])
|
||||
for (i = optind; i < argc; ++i) {
|
||||
timezone_t tz = tzalloc(argv[i]);
|
||||
char const *ab;
|
||||
time_t t;
|
||||
struct tm tm, newtm;
|
||||
bool tm_ok;
|
||||
if (!tz) {
|
||||
perror(argv[i]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (! (vflag | Vflag)) {
|
||||
if (! (iflag | vflag | Vflag)) {
|
||||
show(tz, argv[i], now, false);
|
||||
tzfree(tz);
|
||||
continue;
|
||||
}
|
||||
warned = false;
|
||||
t = absolute_min_time;
|
||||
if (!Vflag) {
|
||||
if (! (iflag | Vflag)) {
|
||||
show(tz, argv[i], t, true);
|
||||
t += SECSPERDAY;
|
||||
show(tz, argv[i], t, true);
|
||||
}
|
||||
if (t < cutlotime)
|
||||
t = cutlotime;
|
||||
tmp = my_localtime_rz(tz, &t, &tm);
|
||||
if (tmp)
|
||||
tm_ok = my_localtime_rz(tz, &t, &tm) != NULL;
|
||||
if (tm_ok) {
|
||||
ab = saveabbr(&abbrev, &abbrevsize, &tm);
|
||||
while (t < cuthitime) {
|
||||
newt = ((t < absolute_max_time - SECSPERDAY / 2
|
||||
&& t + SECSPERDAY / 2 < cuthitime)
|
||||
? t + SECSPERDAY / 2
|
||||
: cuthitime);
|
||||
newtmp = localtime_rz(tz, &newt, &newtm);
|
||||
if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
|
||||
(delta(&newtm, &tm) != (newt - t) ||
|
||||
newtm.tm_isdst != tm.tm_isdst ||
|
||||
strcmp(abbr(&newtm), ab) != 0)) {
|
||||
newt = hunt(tz, argv[i], t, newt);
|
||||
newtmp = localtime_rz(tz, &newt, &newtm);
|
||||
if (newtmp)
|
||||
ab = saveabbr(&abbrev, &abbrevsize,
|
||||
&newtm);
|
||||
}
|
||||
t = newt;
|
||||
tm = newtm;
|
||||
tmp = newtmp;
|
||||
if (iflag) {
|
||||
showtrans("\nTZ=%f", &tm, t, ab, argv[i]);
|
||||
showtrans("-\t-\t%Q", &tm, t, ab, argv[i]);
|
||||
}
|
||||
}
|
||||
if (!Vflag) {
|
||||
while (t < cuthitime) {
|
||||
time_t newt = ((t < absolute_max_time - SECSPERDAY / 2
|
||||
&& t + SECSPERDAY / 2 < cuthitime)
|
||||
? t + SECSPERDAY / 2
|
||||
: cuthitime);
|
||||
struct tm *newtmp = localtime_rz(tz, &newt, &newtm);
|
||||
bool newtm_ok = newtmp != NULL;
|
||||
if (! (tm_ok & newtm_ok
|
||||
? (delta(&newtm, &tm) == newt - t
|
||||
&& newtm.tm_isdst == tm.tm_isdst
|
||||
&& strcmp(abbr(&newtm), ab) == 0)
|
||||
: tm_ok == newtm_ok)) {
|
||||
newt = hunt(tz, argv[i], t, newt);
|
||||
newtmp = localtime_rz(tz, &newt, &newtm);
|
||||
newtm_ok = newtmp != NULL;
|
||||
if (iflag)
|
||||
showtrans("%Y-%m-%d\t%L\t%Q", newtmp, newt,
|
||||
newtm_ok ? abbr(&newtm) : NULL, argv[i]);
|
||||
else {
|
||||
show(tz, argv[i], newt - 1, true);
|
||||
show(tz, argv[i], newt, true);
|
||||
}
|
||||
}
|
||||
t = newt;
|
||||
tm_ok = newtm_ok;
|
||||
if (newtm_ok) {
|
||||
ab = saveabbr(&abbrev, &abbrevsize, &newtm);
|
||||
tm = newtm;
|
||||
}
|
||||
}
|
||||
if (! (iflag | Vflag)) {
|
||||
t = absolute_max_time;
|
||||
t -= SECSPERDAY;
|
||||
show(tz, argv[i], t, true);
|
||||
@ -790,12 +654,11 @@ hunt(timezone_t tz, char *name, time_t lot, time_t hit)
|
||||
char const * ab;
|
||||
time_t t;
|
||||
struct tm lotm;
|
||||
register struct tm * lotmp;
|
||||
struct tm tm;
|
||||
register struct tm * tmp;
|
||||
bool lotm_ok = my_localtime_rz(tz, &lot, &lotm) != NULL;
|
||||
bool tm_ok;
|
||||
|
||||
lotmp = my_localtime_rz(tz, &lot, &lotm);
|
||||
if (lotmp)
|
||||
if (lotm_ok)
|
||||
ab = saveabbr(&loab, &loabsize, &lotm);
|
||||
for ( ; ; ) {
|
||||
time_t diff = hit - lot;
|
||||
@ -807,18 +670,17 @@ hunt(timezone_t tz, char *name, time_t lot, time_t hit)
|
||||
++t;
|
||||
else if (t >= hit)
|
||||
--t;
|
||||
tmp = my_localtime_rz(tz, &t, &tm);
|
||||
if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
|
||||
(delta(&tm, &lotm) == (t - lot) &&
|
||||
tm.tm_isdst == lotm.tm_isdst &&
|
||||
strcmp(abbr(&tm), ab) == 0)) {
|
||||
lot = t;
|
||||
lotm = tm;
|
||||
lotmp = tmp;
|
||||
tm_ok = my_localtime_rz(tz, &t, &tm) != NULL;
|
||||
if (lotm_ok & tm_ok
|
||||
? (delta(&tm, &lotm) == t - lot
|
||||
&& tm.tm_isdst == lotm.tm_isdst
|
||||
&& strcmp(abbr(&tm), ab) == 0)
|
||||
: lotm_ok == tm_ok) {
|
||||
lot = t;
|
||||
if (tm_ok)
|
||||
lotm = tm;
|
||||
} else hit = t;
|
||||
}
|
||||
show(tz, name, lot, true);
|
||||
show(tz, name, hit, true);
|
||||
return hit;
|
||||
}
|
||||
|
||||
@ -862,13 +724,20 @@ adjusted_yday(struct tm const *a, struct tm const *b)
|
||||
|
||||
/* If A is the broken-down local time and B the broken-down UTC for
|
||||
the same instant, return A's UTC offset in seconds, where positive
|
||||
offsets are east of Greenwich. On failure, return LONG_MIN. */
|
||||
offsets are east of Greenwich. On failure, return LONG_MIN.
|
||||
|
||||
If T is nonnull, *T is the timestamp that corresponds to A; call
|
||||
my_gmtime_r and use its result instead of B. Otherwise, B is the
|
||||
possibly nonnull result of an earlier call to my_gmtime_r. */
|
||||
static long
|
||||
gmtoff(struct tm const *a, struct tm const *b)
|
||||
gmtoff(struct tm const *a, time_t *t, struct tm const *b)
|
||||
{
|
||||
#ifdef TM_GMTOFF
|
||||
return a->TM_GMTOFF;
|
||||
#else
|
||||
struct tm tm;
|
||||
if (t)
|
||||
b = my_gmtime_r(t, &tm);
|
||||
if (! b)
|
||||
return LONG_MIN;
|
||||
else {
|
||||
@ -907,7 +776,7 @@ show(timezone_t tz, char *zone, time_t t, bool v)
|
||||
if (*abbr(tmp) != '\0')
|
||||
printf(" %s", abbr(tmp));
|
||||
if (v) {
|
||||
long off = gmtoff(tmp, gmtmp);
|
||||
long off = gmtoff(tmp, NULL, gmtmp);
|
||||
printf(" isdst=%d", tmp->tm_isdst);
|
||||
if (off != LONG_MIN)
|
||||
printf(" gmtoff=%ld", off);
|
||||
@ -918,6 +787,206 @@ show(timezone_t tz, char *zone, time_t t, bool v)
|
||||
abbrok(abbr(tmp), zone);
|
||||
}
|
||||
|
||||
/* Store into BUF, of size SIZE, a formatted local time taken from *TM.
|
||||
Use ISO 8601 format +HH:MM:SS. Omit :SS if SS is zero, and omit
|
||||
:MM too if MM is also zero.
|
||||
|
||||
Return the length of the resulting string. If the string does not
|
||||
fit, return the length that the string would have been if it had
|
||||
fit; do not overrun the output buffer. */
|
||||
static int
|
||||
format_local_time(char *buf, size_t size, struct tm const *tm)
|
||||
{
|
||||
int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour;
|
||||
return (ss
|
||||
? snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss)
|
||||
: mm
|
||||
? snprintf(buf, size, "%02d:%02d", hh, mm)
|
||||
: snprintf(buf, size, "%02d", hh));
|
||||
}
|
||||
|
||||
/* Store into BUF, of size SIZE, a formatted UTC offset for the
|
||||
localtime *TM corresponding to time T. Use ISO 8601 format
|
||||
+HHMMSS, or -HHMMSS for timestamps west of Greenwich; use the
|
||||
format -00 for unknown UTC offsets. If the hour needs more than
|
||||
two digits to represent, extend the length of HH as needed.
|
||||
Otherwise, omit SS if SS is zero, and omit MM too if MM is also
|
||||
zero.
|
||||
|
||||
Return the length of the resulting string, or -1 if the result is
|
||||
not representable as a string. If the string does not fit, return
|
||||
the length that the string would have been if it had fit; do not
|
||||
overrun the output buffer. */
|
||||
static int
|
||||
format_utc_offset(char *buf, size_t size, struct tm const *tm, time_t t)
|
||||
{
|
||||
long off = gmtoff(tm, &t, NULL);
|
||||
char sign = ((off < 0
|
||||
|| (off == 0
|
||||
&& (*abbr(tm) == '-' || strcmp(abbr(tm), "zzz") == 0)))
|
||||
? '-' : '+');
|
||||
long hh;
|
||||
int mm, ss;
|
||||
if (off < 0)
|
||||
{
|
||||
if (off == LONG_MIN)
|
||||
return -1;
|
||||
off = -off;
|
||||
}
|
||||
ss = off % 60;
|
||||
mm = off / 60 % 60;
|
||||
hh = off / 60 / 60;
|
||||
return (ss || 100 <= hh
|
||||
? snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss)
|
||||
: mm
|
||||
? snprintf(buf, size, "%c%02ld%02d", sign, hh, mm)
|
||||
: snprintf(buf, size, "%c%02ld", sign, hh));
|
||||
}
|
||||
|
||||
/* Store into BUF (of size SIZE) a quoted string representation of P.
|
||||
If the representation's length is less than SIZE, return the
|
||||
length; the representation is not null terminated. Otherwise
|
||||
return SIZE, to indicate that BUF is too small. */
|
||||
static size_t
|
||||
format_quoted_string(char *buf, size_t size, char const *p)
|
||||
{
|
||||
char *b = buf;
|
||||
size_t s = size;
|
||||
if (!s)
|
||||
return size;
|
||||
*b++ = '"', s--;
|
||||
for (;;) {
|
||||
char c = *p++;
|
||||
if (s <= 1)
|
||||
return size;
|
||||
switch (c) {
|
||||
default: *b++ = c, s--; continue;
|
||||
case '\0': *b++ = '"', s--; return size - s;
|
||||
case '"': case '\\': break;
|
||||
case ' ': c = 's'; break;
|
||||
case '\f': c = 'f'; break;
|
||||
case '\n': c = 'n'; break;
|
||||
case '\r': c = 'r'; break;
|
||||
case '\t': c = 't'; break;
|
||||
case '\v': c = 'v'; break;
|
||||
}
|
||||
*b++ = '\\', *b++ = c, s -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store into BUF (of size SIZE) a timestamp formatted by TIME_FMT.
|
||||
TM is the broken-down time, T the seconds count, AB the time zone
|
||||
abbreviation, and ZONE_NAME the zone name. Return true if
|
||||
successful, false if the output would require more than SIZE bytes.
|
||||
TIME_FMT uses the same format that strftime uses, with these
|
||||
additions:
|
||||
|
||||
%f zone name
|
||||
%L local time as per format_local_time
|
||||
%Q like "U\t%Z\tD" where U is the UTC offset as for format_utc_offset
|
||||
and D is the isdst flag; except omit D if it is zero, omit %Z if
|
||||
it equals U, quote and escape %Z if it contains nonalphabetics,
|
||||
and omit any trailing tabs. */
|
||||
|
||||
static bool
|
||||
istrftime(char *buf, size_t size, char const *time_fmt,
|
||||
struct tm const *tm, time_t t, char const *ab, char const *zone_name)
|
||||
{
|
||||
char *b = buf;
|
||||
size_t s = size;
|
||||
char const *f = time_fmt, *p;
|
||||
|
||||
for (p = f; ; p++)
|
||||
if (*p == '%' && p[1] == '%')
|
||||
p++;
|
||||
else if (!*p
|
||||
|| (*p == '%'
|
||||
&& (p[1] == 'f' || p[1] == 'L' || p[1] == 'Q'))) {
|
||||
size_t formatted_len;
|
||||
size_t f_prefix_len = p - f;
|
||||
size_t f_prefix_copy_size = p - f + 2;
|
||||
char fbuf[100];
|
||||
bool oversized = sizeof fbuf <= f_prefix_copy_size;
|
||||
char *f_prefix_copy = oversized ? xmalloc(f_prefix_copy_size) : fbuf;
|
||||
memcpy(f_prefix_copy, f, f_prefix_len);
|
||||
strcpy(f_prefix_copy + f_prefix_len, "X");
|
||||
formatted_len = strftime(b, s, f_prefix_copy, tm);
|
||||
if (oversized)
|
||||
free(f_prefix_copy);
|
||||
if (formatted_len == 0)
|
||||
return false;
|
||||
formatted_len--;
|
||||
b += formatted_len, s -= formatted_len;
|
||||
if (!*p++)
|
||||
break;
|
||||
switch (*p) {
|
||||
case 'f':
|
||||
formatted_len = format_quoted_string(b, s, zone_name);
|
||||
break;
|
||||
case 'L':
|
||||
formatted_len = format_local_time(b, s, tm);
|
||||
break;
|
||||
case 'Q':
|
||||
{
|
||||
bool show_abbr;
|
||||
int offlen = format_utc_offset(b, s, tm, t);
|
||||
if (! (0 <= offlen && offlen < s))
|
||||
return false;
|
||||
show_abbr = strcmp(b, ab) != 0;
|
||||
b += offlen, s -= offlen;
|
||||
if (show_abbr) {
|
||||
char const *abp;
|
||||
size_t len;
|
||||
if (s <= 1)
|
||||
return false;
|
||||
*b++ = '\t', s--;
|
||||
for (abp = ab; is_alpha(*abp); abp++)
|
||||
continue;
|
||||
len = (!*abp && *ab
|
||||
? snprintf(b, s, "%s", ab)
|
||||
: format_quoted_string(b, s, ab));
|
||||
if (s <= len)
|
||||
return false;
|
||||
b += len, s -= len;
|
||||
}
|
||||
formatted_len = (tm->tm_isdst
|
||||
? snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst)
|
||||
: 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (s <= formatted_len)
|
||||
return false;
|
||||
b += formatted_len, s -= formatted_len;
|
||||
f = p + 1;
|
||||
}
|
||||
*b = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Show a time transition. */
|
||||
static void
|
||||
showtrans(char const *time_fmt, struct tm const *tm, time_t t, char const *ab,
|
||||
char const *zone_name)
|
||||
{
|
||||
if (!tm) {
|
||||
printf(tformat(), t);
|
||||
putchar('\n');
|
||||
} else {
|
||||
char stackbuf[1000];
|
||||
size_t size = sizeof stackbuf;
|
||||
char *buf = stackbuf;
|
||||
char *bufalloc = NULL;
|
||||
while (! istrftime(buf, size, time_fmt, tm, t, ab, zone_name)) {
|
||||
size = sumsize(size, size);
|
||||
free(bufalloc);
|
||||
buf = bufalloc = xmalloc(size);
|
||||
}
|
||||
puts(buf);
|
||||
free(bufalloc);
|
||||
}
|
||||
}
|
||||
|
||||
static char const *
|
||||
abbr(struct tm const *tmp)
|
||||
{
|
||||
|
686
timezone/zic.c
686
timezone/zic.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user