mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-23 17:53:37 +08:00
* time/tzfile.c (__tzfile_read): Extend to handle new file format
on machines with 64-bit time_t. * timezone/checktab.awk: Update from tzcode2006o. * timezone/ialloc.c: Likewise. * timezone/private.h: Likewise. * timezone/scheck.: Likewise. * timezone/tzfile.h: Likewise. * timezone/tzselect.ksh: Likewise. * timezone/zdump.c: Likewise. * timezone/zic.c: Likewise.
This commit is contained in:
parent
6decd24cc2
commit
064737fb74
12
ChangeLog
12
ChangeLog
@ -1,5 +1,17 @@
|
||||
2006-11-10 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* time/tzfile.c (__tzfile_read): Extend to handle new file format
|
||||
on machines with 64-bit time_t.
|
||||
|
||||
* timezone/checktab.awk: Update from tzcode2006o.
|
||||
* timezone/ialloc.c: Likewise.
|
||||
* timezone/private.h: Likewise.
|
||||
* timezone/scheck.: Likewise.
|
||||
* timezone/tzfile.h: Likewise.
|
||||
* timezone/tzselect.ksh: Likewise.
|
||||
* timezone/zdump.c: Likewise.
|
||||
* timezone/zic.c: Likewise.
|
||||
|
||||
[BZ #3483]
|
||||
* elf/ldconfig.c (main): Call setlocale and textdomain.
|
||||
Patch mostly by Benno Schulenberg <bensberg@justemail.net>.
|
||||
|
112
time/tzfile.c
112
time/tzfile.c
@ -1,4 +1,5 @@
|
||||
/* Copyright (C) 1991-1993,1995-2001,2003,2004 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1991-1993,1995-2001,2003,2004,2006
|
||||
Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
@ -71,24 +72,34 @@ static inline int
|
||||
__attribute ((always_inline))
|
||||
decode (const void *ptr)
|
||||
{
|
||||
if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
|
||||
if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
|
||||
return *(const int *) ptr;
|
||||
else if (BYTE_ORDER == LITTLE_ENDIAN && sizeof (int) == 4)
|
||||
if (sizeof (int) == 4)
|
||||
return bswap_32 (*(const int *) ptr);
|
||||
else
|
||||
{
|
||||
const unsigned char *p = ptr;
|
||||
int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
|
||||
|
||||
result = (result << 8) | *p++;
|
||||
result = (result << 8) | *p++;
|
||||
result = (result << 8) | *p++;
|
||||
result = (result << 8) | *p++;
|
||||
const unsigned char *p = ptr;
|
||||
int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
result = (result << 8) | *p++;
|
||||
result = (result << 8) | *p++;
|
||||
result = (result << 8) | *p++;
|
||||
result = (result << 8) | *p++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static inline int64_t
|
||||
__attribute ((always_inline))
|
||||
decode64 (const void *ptr)
|
||||
{
|
||||
if ((BYTE_ORDER == BIG_ENDIAN))
|
||||
return *(const int64_t *) ptr;
|
||||
|
||||
return bswap_64 (*(const int64_t *) ptr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
{
|
||||
@ -102,6 +113,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
size_t types_idx;
|
||||
size_t leaps_idx;
|
||||
int was_using_tzfile = __use_tzfile;
|
||||
int trans_width = 4;
|
||||
|
||||
if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
|
||||
abort ();
|
||||
|
||||
__use_tzfile = 0;
|
||||
|
||||
@ -185,8 +200,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
/* No threads reading this stream. */
|
||||
__fsetlocking (f, FSETLOCKING_BYCALLER);
|
||||
|
||||
read_again:
|
||||
if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),
|
||||
1, f) != 1, 0))
|
||||
1, f) != 1, 0)
|
||||
|| memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
|
||||
goto lose;
|
||||
|
||||
num_transitions = (size_t) decode (tzhead.tzh_timecnt);
|
||||
@ -196,6 +213,26 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
|
||||
num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
|
||||
|
||||
/* For platforms with 64-bit time_t we use the new format if available. */
|
||||
if (sizeof (time_t) == 8 && trans_width == 4
|
||||
&& tzhead.tzh_version[0] != '\0')
|
||||
{
|
||||
/* We use the 8-byte format. */
|
||||
trans_width = 8;
|
||||
|
||||
/* Position the stream before the second header. */
|
||||
size_t to_skip = (num_transitions * (4 + 1)
|
||||
+ num_types * 6
|
||||
+ chars
|
||||
+ num_leaps * 8
|
||||
+ num_isstd
|
||||
+ num_isgmt);
|
||||
if (fseek (f, to_skip, SEEK_CUR) != 0)
|
||||
goto lose;
|
||||
|
||||
goto read_again;
|
||||
}
|
||||
|
||||
total_size = num_transitions * (sizeof (time_t) + 1);
|
||||
total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
|
||||
& ~(__alignof__ (struct ttinfo) - 1));
|
||||
@ -205,10 +242,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
& ~(__alignof__ (struct leap) - 1));
|
||||
leaps_idx = total_size;
|
||||
total_size += num_leaps * sizeof (struct leap);
|
||||
/* This is for the extra memory required by the caller. */
|
||||
total_size += extra;
|
||||
|
||||
transitions = (time_t *) malloc (total_size);
|
||||
/* Allocate enough memory including the extra block requested by the
|
||||
caller. */
|
||||
transitions = (time_t *) malloc (total_size + extra);
|
||||
if (transitions == NULL)
|
||||
goto lose;
|
||||
|
||||
@ -220,14 +257,11 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
if (extra > 0)
|
||||
*extrap = (char *) &leaps[num_leaps];
|
||||
|
||||
if (sizeof (time_t) < 4)
|
||||
abort ();
|
||||
|
||||
if (sizeof (time_t) == 4)
|
||||
if (sizeof (time_t) == 4 || trans_width == 8)
|
||||
{
|
||||
if (__builtin_expect (fread_unlocked (transitions, 1,
|
||||
(4 + 1) * num_transitions, f)
|
||||
!= (4 + 1) * num_transitions, 0))
|
||||
if (__builtin_expect (fread_unlocked (transitions, trans_width + 1,
|
||||
num_transitions, f)
|
||||
!= num_transitions, 0))
|
||||
goto lose;
|
||||
}
|
||||
else
|
||||
@ -245,7 +279,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
if (__builtin_expect (type_idxs[i] >= num_types, 0))
|
||||
goto lose;
|
||||
|
||||
if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
|
||||
if (BYTE_ORDER != BIG_ENDIAN || (sizeof (time_t) == 8 && trans_width == 4))
|
||||
{
|
||||
/* Decode the transition times, stored as 4-byte integers in
|
||||
network (big-endian) byte order. We work from the end of
|
||||
@ -255,6 +289,13 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
while (i-- > 0)
|
||||
transitions[i] = decode ((char *) transitions + i * 4);
|
||||
}
|
||||
else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8)
|
||||
{
|
||||
/* Decode the transition times, stored as 8-byte integers in
|
||||
network (big-endian) byte order. */
|
||||
for (i = 0; i < num_transitions; ++i)
|
||||
transitions[i] = decode64 ((char *) transitions + i * 8);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_types; ++i)
|
||||
{
|
||||
@ -280,13 +321,16 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
|
||||
for (i = 0; i < num_leaps; ++i)
|
||||
{
|
||||
unsigned char x[4];
|
||||
if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
|
||||
0))
|
||||
unsigned char x[8];
|
||||
if (__builtin_expect (fread_unlocked (x, 1, trans_width, f)
|
||||
!= trans_width, 0))
|
||||
goto lose;
|
||||
leaps[i].transition = (time_t) decode (x);
|
||||
if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
|
||||
0))
|
||||
if (sizeof (time_t) == 4 || trans_width == 4)
|
||||
leaps[i].transition = (time_t) decode (x);
|
||||
else
|
||||
leaps[i].transition = (time_t) decode64 (x);
|
||||
|
||||
if (__builtin_expect (fread_unlocked (x, 1, 4, f) != 4, 0))
|
||||
goto lose;
|
||||
leaps[i].change = (long int) decode (x);
|
||||
}
|
||||
@ -311,6 +355,12 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
while (i < num_types)
|
||||
types[i++].isgmt = 0;
|
||||
|
||||
/* XXX When a version 2 file is available it can contain a POSIX TZ-style
|
||||
formatted string which specifies how times past the last one specified
|
||||
are supposed to be handled. We might want to handle this at some
|
||||
point. But it might be overhead since most/all? files have an
|
||||
open-ended last entry. */
|
||||
|
||||
fclose (f);
|
||||
|
||||
/* First "register" all timezone names. */
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Check tz tables for consistency.
|
||||
|
||||
# @(#)checktab.awk 1.7
|
||||
# @(#)checktab.awk 8.1
|
||||
|
||||
# Contributed by Paul Eggert.
|
||||
|
||||
|
@ -1,6 +1,11 @@
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 2006-07-17 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#ifndef NOID
|
||||
static char elsieid[] = "@(#)ialloc.c 8.29";
|
||||
static char elsieid[] = "@(#)ialloc.c 8.30";
|
||||
#endif /* !defined NOID */
|
||||
#endif /* !defined lint */
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#ifndef lint
|
||||
#ifndef NOID
|
||||
static char privatehid[] = "@(#)private.h 7.55";
|
||||
static char privatehid[] = "@(#)private.h 8.2";
|
||||
#endif /* !defined NOID */
|
||||
#endif /* !defined lint */
|
||||
|
||||
@ -89,7 +89,7 @@ static char privatehid[] = "@(#)private.h 7.55";
|
||||
#include "stdio.h"
|
||||
#include "errno.h"
|
||||
#include "string.h"
|
||||
#include "limits.h" /* for CHAR_BIT */
|
||||
#include "limits.h" /* for CHAR_BIT et al. */
|
||||
#include "time.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
@ -124,21 +124,52 @@ static char privatehid[] = "@(#)private.h 7.55";
|
||||
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
|
||||
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
|
||||
|
||||
/*
|
||||
** 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.)
|
||||
*/
|
||||
#ifndef HAVE_STDINT_H
|
||||
#define HAVE_STDINT_H \
|
||||
(199901 <= __STDC_VERSION__ || \
|
||||
2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
|
||||
#endif /* !defined HAVE_STDINT_H */
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
#include "stdint.h"
|
||||
#endif /* !HAVE_STDINT_H */
|
||||
|
||||
#ifndef INT_FAST64_MAX
|
||||
/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
|
||||
#if defined LLONG_MAX || defined __LONG_LONG_MAX__
|
||||
typedef long long int_fast64_t;
|
||||
#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
|
||||
#if (LONG_MAX >> 31) < 0xffffffff
|
||||
Please use a compiler that supports a 64-bit integer type (or wider);
|
||||
you may need to compile with "-DHAVE_STDINT_H".
|
||||
#endif /* (LONG_MAX >> 31) < 0xffffffff */
|
||||
typedef long int_fast64_t;
|
||||
#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
|
||||
#endif /* !defined INT_FAST64_MAX */
|
||||
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX 0x7fffffff
|
||||
#endif /* !defined INT32_MAX */
|
||||
#ifndef INT32_MIN
|
||||
#define INT32_MIN (-1 - INT32_MAX)
|
||||
#endif /* !defined INT32_MIN */
|
||||
|
||||
/*
|
||||
** Workarounds for compilers/systems.
|
||||
*/
|
||||
|
||||
/*
|
||||
** SunOS 4.1.1 cc lacks prototypes.
|
||||
** If your compiler lacks prototypes, "#define P(x) ()".
|
||||
*/
|
||||
|
||||
#ifndef P
|
||||
#ifdef __STDC__
|
||||
#define P(x) x
|
||||
#endif /* defined __STDC__ */
|
||||
#ifndef __STDC__
|
||||
#define P(x) ()
|
||||
#endif /* !defined __STDC__ */
|
||||
#endif /* !defined P */
|
||||
|
||||
/*
|
||||
@ -211,14 +242,14 @@ extern char * asctime_r();
|
||||
** Private function declarations.
|
||||
*/
|
||||
|
||||
char * icalloc P((int nelem, int elsize));
|
||||
char * icatalloc P((char * old, const char * new));
|
||||
char * icpyalloc P((const char * string));
|
||||
char * imalloc P((int n));
|
||||
void * irealloc P((void * pointer, int size));
|
||||
void icfree P((char * pointer));
|
||||
void ifree P((char * pointer));
|
||||
const char *scheck P((const char *string, const char *format));
|
||||
char * icalloc P((int nelem, int elsize));
|
||||
char * icatalloc P((char * old, const char * new));
|
||||
char * icpyalloc P((const char * string));
|
||||
char * imalloc P((int n));
|
||||
void * irealloc P((void * pointer, int size));
|
||||
void icfree P((char * pointer));
|
||||
void ifree P((char * pointer));
|
||||
const char * scheck P((const char * string, const char * format));
|
||||
|
||||
/*
|
||||
** Finally, some convenience items.
|
||||
@ -310,6 +341,26 @@ char *asctime_r P((struct tm const *, char *));
|
||||
char *ctime_r P((time_t const *, char *));
|
||||
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
|
||||
|
||||
#ifndef YEARSPERREPEAT
|
||||
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
|
||||
#endif /* !defined YEARSPERREPEAT */
|
||||
|
||||
/*
|
||||
** 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_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
|
||||
#endif /* !defined SECSPERREPEAT_BITS */
|
||||
|
||||
/*
|
||||
** UNIX was a registered trademark of The Open Group in 2003.
|
||||
*/
|
||||
|
@ -1,6 +1,11 @@
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 2006-07-17 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#ifndef NOID
|
||||
static char elsieid[] = "@(#)scheck.c 8.17";
|
||||
static char elsieid[] = "@(#)scheck.c 8.19";
|
||||
#endif /* !defined lint */
|
||||
#endif /* !defined NOID */
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#ifndef lint
|
||||
#ifndef NOID
|
||||
static char tzfilehid[] = "@(#)tzfile.h 7.18";
|
||||
static char tzfilehid[] = "@(#)tzfile.h 8.1";
|
||||
#endif /* !defined NOID */
|
||||
#endif /* !defined lint */
|
||||
|
||||
@ -49,7 +49,8 @@ static char tzfilehid[] = "@(#)tzfile.h 7.18";
|
||||
|
||||
struct tzhead {
|
||||
char tzh_magic[4]; /* TZ_MAGIC */
|
||||
char tzh_reserved[16]; /* reserved for future use */
|
||||
char tzh_version[1]; /* '\0' or '2' as of 2005 */
|
||||
char tzh_reserved[15]; /* reserved--must be zero */
|
||||
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_leapcnt[4]; /* coded number of leap seconds */
|
||||
@ -83,19 +84,23 @@ struct tzhead {
|
||||
** assumed to be local time
|
||||
*/
|
||||
|
||||
/*
|
||||
** If tzh_version is '2' or greater, the above is followed by a second instance
|
||||
** of tzhead and a second instance of the data in which each coded transition
|
||||
** time uses 8 rather than 4 chars,
|
||||
** then a POSIX-TZ-environment-variable-style string for use in handling
|
||||
** instants after the last transition time stored in the file
|
||||
** (with nothing between the newlines if there is no POSIX representation for
|
||||
** such instants).
|
||||
*/
|
||||
|
||||
/*
|
||||
** In the current implementation, "tzset()" refuses to deal with files that
|
||||
** exceed any of the limits below.
|
||||
*/
|
||||
|
||||
#ifndef TZ_MAX_TIMES
|
||||
/*
|
||||
** The TZ_MAX_TIMES value below is enough to handle a bit more than a
|
||||
** year's worth of solar time (corrected daily to the nearest second) or
|
||||
** 138 years of Pacific Presidential Election time
|
||||
** (where there are three time zone transitions every fourth year).
|
||||
*/
|
||||
#define TZ_MAX_TIMES 370
|
||||
#define TZ_MAX_TIMES 1200
|
||||
#endif /* !defined TZ_MAX_TIMES */
|
||||
|
||||
#ifndef TZ_MAX_TYPES
|
||||
|
@ -1,6 +1,6 @@
|
||||
#! @KSH@
|
||||
|
||||
# '@(#)tzselect.ksh 1.8'
|
||||
# '@(#)tzselect.ksh 8.1'
|
||||
|
||||
# Ask the user about the time zone, and output the resulting TZ value to stdout.
|
||||
# Interact with the user via stderr and stdin.
|
||||
|
@ -1,4 +1,4 @@
|
||||
static char elsieid[] = "@(#)zdump.c 7.74";
|
||||
static char elsieid[] = "@(#)zdump.c 8.2";
|
||||
|
||||
/*
|
||||
** This code has been made independent of the rest of the time
|
||||
@ -15,7 +15,7 @@ static char elsieid[] = "@(#)zdump.c 7.74";
|
||||
#include "ctype.h" /* for isalpha et al. */
|
||||
#ifndef isascii
|
||||
#define isascii(x) 1
|
||||
#endif
|
||||
#endif /* !defined isascii */
|
||||
|
||||
#ifndef ZDUMP_LO_YEAR
|
||||
#define ZDUMP_LO_YEAR (-500)
|
||||
@ -130,11 +130,7 @@ static char elsieid[] = "@(#)zdump.c 7.74";
|
||||
#endif /* !defined TZ_DOMAIN */
|
||||
|
||||
#ifndef P
|
||||
#ifdef __STDC__
|
||||
#define P(x) x
|
||||
#else /* !defined __STDC__ */
|
||||
#define P(x) ()
|
||||
#endif /* !defined __STDC__ */
|
||||
#endif /* !defined P */
|
||||
|
||||
extern char ** environ;
|
||||
@ -389,7 +385,7 @@ _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"),
|
||||
}
|
||||
if (fflush(stdout) || ferror(stdout)) {
|
||||
(void) fprintf(stderr, "%s: ", progname);
|
||||
(void) perror(_("Error writing to standard output"));
|
||||
(void) perror(_("Error writing standard output"));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -418,14 +414,21 @@ _("%s: use of -v on system with floating time_t other than float or double\n"),
|
||||
}
|
||||
} else if (0 > (time_t) -1) {
|
||||
/*
|
||||
** time_t is signed.
|
||||
** time_t is signed. Assume overflow wraps around.
|
||||
*/
|
||||
register time_t hibit;
|
||||
time_t t = 0;
|
||||
time_t t1 = 1;
|
||||
|
||||
for (hibit = 1; (hibit * 2) != 0; hibit *= 2)
|
||||
continue;
|
||||
absolute_min_time = hibit;
|
||||
absolute_max_time = -(hibit + 1);
|
||||
while (t < t1) {
|
||||
t = t1;
|
||||
t1 = 2 * t1 + 1;
|
||||
}
|
||||
|
||||
absolute_max_time = t;
|
||||
t = -t;
|
||||
absolute_min_time = t - 1;
|
||||
if (t < absolute_min_time)
|
||||
absolute_min_time = t;
|
||||
} else {
|
||||
/*
|
||||
** time_t is unsigned.
|
||||
@ -468,10 +471,7 @@ const long y;
|
||||
}
|
||||
|
||||
static time_t
|
||||
hunt(name, lot, hit)
|
||||
char * name;
|
||||
time_t lot;
|
||||
time_t hit;
|
||||
hunt(char *name, time_t lot, time_t hit)
|
||||
{
|
||||
time_t t;
|
||||
long diff;
|
||||
@ -541,10 +541,7 @@ struct tm * oldp;
|
||||
}
|
||||
|
||||
static void
|
||||
show(zone, t, v)
|
||||
char * zone;
|
||||
time_t t;
|
||||
int v;
|
||||
show(char *zone, time_t t, int v)
|
||||
{
|
||||
register struct tm * tmp;
|
||||
|
||||
|
705
timezone/zic.c
705
timezone/zic.c
@ -1,15 +1,18 @@
|
||||
static char elsieid[] = "@(#)zic.c 7.128";
|
||||
|
||||
/*
|
||||
** Regardless of the type of time_t, we do our work using this type.
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 2006-07-17 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
typedef int zic_t;
|
||||
static char elsieid[] = "@(#)zic.c 8.7";
|
||||
|
||||
#include "private.h"
|
||||
#include "locale.h"
|
||||
#include "tzfile.h"
|
||||
|
||||
#define ZIC_VERSION '2'
|
||||
|
||||
typedef int_fast64_t zic_t;
|
||||
|
||||
#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
|
||||
#define ZIC_MAX_ABBR_LEN_WO_WARN 6
|
||||
#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
|
||||
@ -36,6 +39,11 @@ typedef int zic_t;
|
||||
#define isascii(x) 1
|
||||
#endif
|
||||
|
||||
#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
|
||||
#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
|
||||
|
||||
#define end(cp) (strchr((cp), '\0'))
|
||||
|
||||
struct rule {
|
||||
const char * r_filename;
|
||||
int r_linenum;
|
||||
@ -44,6 +52,8 @@ struct rule {
|
||||
int r_loyear; /* for example, 1986 */
|
||||
int r_hiyear; /* for example, 1986 */
|
||||
const char * r_yrtype;
|
||||
int r_lowasnum;
|
||||
int r_hiwasnum;
|
||||
|
||||
int r_month; /* 0..11 */
|
||||
|
||||
@ -103,9 +113,10 @@ static void adjleap P((void));
|
||||
static void associate P((void));
|
||||
static int ciequal P((const char * ap, const char * bp));
|
||||
static void convert P((long val, char * buf));
|
||||
static void convert64 P((zic_t val, char * buf));
|
||||
static void dolink P((const char * fromfile, const char * tofile));
|
||||
static void doabbr P((char * abbr, const char * format,
|
||||
const char * letters, int isdst));
|
||||
const char * letters, int isdst, int doquotes));
|
||||
static void eat P((const char * name, int num));
|
||||
static void eats P((const char * name, int num,
|
||||
const char * rname, int rnum));
|
||||
@ -121,6 +132,7 @@ static void inrule P((char ** fields, int nfields));
|
||||
static int inzcont P((char ** fields, int nfields));
|
||||
static int inzone P((char ** fields, int nfields));
|
||||
static int inzsub P((char ** fields, int nfields, int iscont));
|
||||
static int is32 P((zic_t x));
|
||||
static int itsabbr P((const char * abbr, const char * word));
|
||||
static int itsdir P((const char * name));
|
||||
static int lowerit P((int c));
|
||||
@ -130,16 +142,22 @@ static void newabbr P((const char * abbr));
|
||||
static long oadd P((long t1, long t2));
|
||||
static void outzone P((const struct zone * zp, int ntzones));
|
||||
static void puttzcode P((long code, FILE * fp));
|
||||
static void puttzcode64 P((zic_t code, FILE * fp));
|
||||
static int rcomp P((const void * leftp, const void * rightp));
|
||||
static zic_t rpytime P((const struct rule * rp, int wantedy));
|
||||
static void rulesub P((struct rule * rp,
|
||||
const char * loyearp, const char * hiyearp,
|
||||
const char * typep, const char * monthp,
|
||||
const char * dayp, const char * timep));
|
||||
static int stringoffset P((char * result, long offset));
|
||||
static int stringrule P((char * result, const struct rule * rp,
|
||||
long dstoff, long gmtoff));
|
||||
static void stringzone P((char * result,
|
||||
const struct zone * zp, int ntzones));
|
||||
static void setboundaries P((void));
|
||||
static zic_t tadd P((zic_t t1, long t2));
|
||||
static void usage P((void));
|
||||
static void writezone P((const char * name));
|
||||
static void writezone P((const char * name, const char * string));
|
||||
static int yearistype P((int year, const char * type));
|
||||
|
||||
#if !HAVE_STRERROR
|
||||
@ -150,13 +168,16 @@ static int charcnt;
|
||||
static int errors;
|
||||
static const char * filename;
|
||||
static int leapcnt;
|
||||
static int leapseen;
|
||||
static int leapminyear;
|
||||
static int leapmaxyear;
|
||||
static int linenum;
|
||||
static int max_abbrvar_len;
|
||||
static int max_format_len;
|
||||
static zic_t max_time;
|
||||
static int max_year;
|
||||
static int max_year_representable;
|
||||
static zic_t min_time;
|
||||
static int min_year;
|
||||
static int min_year_representable;
|
||||
static int noise;
|
||||
static const char * rfilename;
|
||||
static int rlinenum;
|
||||
@ -453,7 +474,7 @@ static void
|
||||
usage P((void))
|
||||
{
|
||||
(void) fprintf(stderr, _("%s: usage is %s \
|
||||
[ --version ] [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
|
||||
[ --version ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
|
||||
\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
|
||||
progname, progname);
|
||||
exit(EXIT_FAILURE);
|
||||
@ -464,7 +485,6 @@ static const char * lcltime;
|
||||
static const char * directory;
|
||||
static const char * leapsec;
|
||||
static const char * yitcommand;
|
||||
static int sflag = FALSE;
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
@ -486,6 +506,11 @@ char * argv[];
|
||||
(void) textdomain(TZ_DOMAIN);
|
||||
#endif /* HAVE_GETTEXT */
|
||||
progname = argv[0];
|
||||
if (TYPE_BIT(zic_t) < 64) {
|
||||
(void) fprintf(stderr, "%s: %s\n", progname,
|
||||
_("wild compilation-time specification of zic_t"));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (i = 1; i < argc; ++i)
|
||||
if (strcmp(argv[i], "--version") == 0) {
|
||||
(void) printf("%s\n", elsieid);
|
||||
@ -549,7 +574,7 @@ _("%s: More than one -L option specified\n"),
|
||||
noise = TRUE;
|
||||
break;
|
||||
case 's':
|
||||
sflag = TRUE;
|
||||
(void) printf("%s: -s ignored\n", progname);
|
||||
break;
|
||||
}
|
||||
if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
|
||||
@ -671,54 +696,17 @@ warning(_("hard link failed, symbolic link used"));
|
||||
ifree(toname);
|
||||
}
|
||||
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX ((int) (((unsigned)~0)>>1))
|
||||
#endif /* !defined INT_MAX */
|
||||
|
||||
#ifndef INT_MIN
|
||||
#define INT_MIN ((int) ~(((unsigned)~0)>>1))
|
||||
#endif /* !defined INT_MIN */
|
||||
|
||||
/*
|
||||
** The tz file format currently allows at most 32-bit quantities.
|
||||
** This restriction should be removed before signed 32-bit values
|
||||
** wrap around in 2038, but unfortunately this will require a
|
||||
** change to the tz file format.
|
||||
*/
|
||||
|
||||
#define MAX_BITS_IN_FILE 32
|
||||
#define TIME_T_BITS_IN_FILE ((TYPE_BIT(zic_t) < MAX_BITS_IN_FILE) ? \
|
||||
TYPE_BIT(zic_t) : MAX_BITS_IN_FILE)
|
||||
#define TIME_T_BITS_IN_FILE 64
|
||||
|
||||
static void
|
||||
setboundaries P((void))
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (TYPE_SIGNED(zic_t)) {
|
||||
min_time = -1;
|
||||
for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
|
||||
min_time *= 2;
|
||||
max_time = -(min_time + 1);
|
||||
if (sflag)
|
||||
min_time = 0;
|
||||
} else {
|
||||
min_time = 0;
|
||||
max_time = 2 - sflag;
|
||||
for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
|
||||
max_time *= 2;
|
||||
--max_time;
|
||||
}
|
||||
{
|
||||
time_t t;
|
||||
|
||||
t = (time_t) min_time;
|
||||
min_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
|
||||
t = (time_t) max_time;
|
||||
max_year = TM_YEAR_BASE + gmtime(&t)->tm_year;
|
||||
}
|
||||
min_year_representable = min_year;
|
||||
max_year_representable = max_year;
|
||||
min_time = -1;
|
||||
for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
|
||||
min_time *= 2;
|
||||
max_time = -(min_time + 1);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -993,6 +981,8 @@ const int nfields;
|
||||
fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
|
||||
r.r_name = ecpyalloc(fields[RF_NAME]);
|
||||
r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
|
||||
if (max_abbrvar_len < strlen(r.r_abbrvar))
|
||||
max_abbrvar_len = strlen(r.r_abbrvar);
|
||||
rules = (struct rule *) (void *) erealloc((char *) rules,
|
||||
(int) ((nrules + 1) * sizeof *rules));
|
||||
rules[nrules++] = r;
|
||||
@ -1098,6 +1088,8 @@ const int iscont;
|
||||
}
|
||||
z.z_rule = ecpyalloc(fields[i_rule]);
|
||||
z.z_format = ecpyalloc(fields[i_format]);
|
||||
if (max_format_len < strlen(z.z_format))
|
||||
max_format_len = strlen(z.z_format);
|
||||
hasuntil = nfields > i_untilyear;
|
||||
if (hasuntil) {
|
||||
z.z_untilrule.r_filename = filename;
|
||||
@ -1159,6 +1151,11 @@ const int nfields;
|
||||
error(_("invalid leaping year"));
|
||||
return;
|
||||
}
|
||||
if (!leapseen || leapmaxyear < year)
|
||||
leapmaxyear = year;
|
||||
if (!leapseen || leapminyear > year)
|
||||
leapminyear = year;
|
||||
leapseen = TRUE;
|
||||
j = EPOCH_YEAR;
|
||||
while (j != year) {
|
||||
if (year > j) {
|
||||
@ -1313,7 +1310,8 @@ const char * const timep;
|
||||
*/
|
||||
cp = loyearp;
|
||||
lp = byword(cp, begin_years);
|
||||
if (lp != NULL) switch ((int) lp->l_value) {
|
||||
rp->r_lowasnum = lp == NULL;
|
||||
if (!rp->r_lowasnum) switch ((int) lp->l_value) {
|
||||
case YR_MINIMUM:
|
||||
rp->r_loyear = INT_MIN;
|
||||
break;
|
||||
@ -1328,14 +1326,11 @@ const char * const timep;
|
||||
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
|
||||
error(_("invalid starting year"));
|
||||
return;
|
||||
} else if (noise) {
|
||||
if (rp->r_loyear < min_year_representable)
|
||||
warning(_("starting year too low to be represented"));
|
||||
else if (rp->r_loyear > max_year_representable)
|
||||
warning(_("starting year too high to be represented"));
|
||||
}
|
||||
cp = hiyearp;
|
||||
if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
|
||||
lp = byword(cp, end_years);
|
||||
rp->r_hiwasnum = lp == NULL;
|
||||
if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
|
||||
case YR_MINIMUM:
|
||||
rp->r_hiyear = INT_MIN;
|
||||
break;
|
||||
@ -1353,11 +1348,6 @@ const char * const timep;
|
||||
} else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
|
||||
error(_("invalid ending year"));
|
||||
return;
|
||||
} else if (noise) {
|
||||
if (rp->r_loyear < min_year_representable)
|
||||
warning(_("ending year too low to be represented"));
|
||||
else if (rp->r_loyear > max_year_representable)
|
||||
warning(_("ending year too high to be represented"));
|
||||
}
|
||||
if (rp->r_loyear > rp->r_hiyear) {
|
||||
error(_("starting year greater than ending year"));
|
||||
@ -1372,8 +1362,6 @@ const char * const timep;
|
||||
}
|
||||
rp->r_yrtype = ecpyalloc(typep);
|
||||
}
|
||||
if (rp->r_loyear < min_year && rp->r_loyear > 0)
|
||||
min_year = rp->r_loyear;
|
||||
/*
|
||||
** Day work.
|
||||
** Accept things such as:
|
||||
@ -1427,12 +1415,24 @@ const long val;
|
||||
char * const buf;
|
||||
{
|
||||
register int i;
|
||||
register long shift;
|
||||
register int shift;
|
||||
|
||||
for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
|
||||
buf[i] = val >> shift;
|
||||
}
|
||||
|
||||
static void
|
||||
convert64(val, buf)
|
||||
const zic_t val;
|
||||
char * const buf;
|
||||
{
|
||||
register int i;
|
||||
register int shift;
|
||||
|
||||
for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
|
||||
buf[i] = val >> shift;
|
||||
}
|
||||
|
||||
static void
|
||||
puttzcode(val, fp)
|
||||
const long val;
|
||||
@ -1444,28 +1444,50 @@ FILE * const fp;
|
||||
(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
|
||||
}
|
||||
|
||||
static void
|
||||
puttzcode64(val, fp)
|
||||
const zic_t val;
|
||||
FILE * const fp;
|
||||
{
|
||||
char buf[8];
|
||||
|
||||
convert64(val, buf);
|
||||
(void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
|
||||
}
|
||||
|
||||
static int
|
||||
atcomp(avp, bvp)
|
||||
void * avp;
|
||||
void * bvp;
|
||||
const void * avp;
|
||||
const void * bvp;
|
||||
{
|
||||
if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
|
||||
return -1;
|
||||
else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
|
||||
return 1;
|
||||
else return 0;
|
||||
const zic_t a = ((const struct attype *) avp)->at;
|
||||
const zic_t b = ((const struct attype *) bvp)->at;
|
||||
|
||||
return (a < b) ? -1 : (a > b);
|
||||
}
|
||||
|
||||
static int
|
||||
is32(x)
|
||||
const zic_t x;
|
||||
{
|
||||
return INT32_MIN <= x && x <= INT32_MAX;
|
||||
}
|
||||
|
||||
static void
|
||||
writezone(name)
|
||||
writezone(name, string)
|
||||
const char * const name;
|
||||
const char * const string;
|
||||
{
|
||||
register FILE * fp;
|
||||
register int i, j;
|
||||
static char * fullname;
|
||||
static struct tzhead tzh;
|
||||
zic_t ats[TZ_MAX_TIMES];
|
||||
unsigned char types[TZ_MAX_TIMES];
|
||||
register FILE * fp;
|
||||
register int i, j;
|
||||
register int leapcnt32, leapi32;
|
||||
register int timecnt32, timei32;
|
||||
register int pass;
|
||||
static char * fullname;
|
||||
static const struct tzhead tzh0;
|
||||
static struct tzhead tzh;
|
||||
zic_t ats[TZ_MAX_TIMES];
|
||||
unsigned char types[TZ_MAX_TIMES];
|
||||
|
||||
/*
|
||||
** Sort.
|
||||
@ -1509,6 +1531,36 @@ const char * const name;
|
||||
ats[i] = attypes[i].at;
|
||||
types[i] = attypes[i].type;
|
||||
}
|
||||
/*
|
||||
** Correct for leap seconds.
|
||||
*/
|
||||
for (i = 0; i < timecnt; ++i) {
|
||||
j = leapcnt;
|
||||
while (--j >= 0)
|
||||
if (ats[i] > trans[j] - corr[j]) {
|
||||
ats[i] = tadd(ats[i], corr[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
** Figure out 32-bit-limited starts and counts.
|
||||
*/
|
||||
timecnt32 = timecnt;
|
||||
timei32 = 0;
|
||||
leapcnt32 = leapcnt;
|
||||
leapi32 = 0;
|
||||
while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
|
||||
--timecnt32;
|
||||
while (timecnt32 > 0 && !is32(ats[timei32])) {
|
||||
--timecnt32;
|
||||
++timei32;
|
||||
}
|
||||
while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
|
||||
--leapcnt32;
|
||||
while (leapcnt32 > 0 && !is32(trans[leapi32])) {
|
||||
--leapcnt32;
|
||||
++leapi32;
|
||||
}
|
||||
fullname = erealloc(fullname,
|
||||
(int) (strlen(directory) + 1 + strlen(name) + 1));
|
||||
(void) sprintf(fullname, "%s/%s", directory, name);
|
||||
@ -1533,67 +1585,150 @@ const char * const name;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
|
||||
convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
|
||||
convert(eitol(leapcnt), tzh.tzh_leapcnt);
|
||||
convert(eitol(timecnt), tzh.tzh_timecnt);
|
||||
convert(eitol(typecnt), tzh.tzh_typecnt);
|
||||
convert(eitol(charcnt), tzh.tzh_charcnt);
|
||||
(void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
|
||||
for (pass = 1; pass <= 2; ++pass) {
|
||||
register int thistimei, thistimecnt;
|
||||
register int thisleapi, thisleapcnt;
|
||||
register int thistimelim, thisleaplim;
|
||||
int writetype[TZ_MAX_TIMES];
|
||||
int typemap[TZ_MAX_TYPES];
|
||||
register int thistypecnt;
|
||||
char thischars[TZ_MAX_CHARS];
|
||||
char thischarcnt;
|
||||
int indmap[TZ_MAX_CHARS];
|
||||
|
||||
if (pass == 1) {
|
||||
thistimei = timei32;
|
||||
thistimecnt = timecnt32;
|
||||
thisleapi = leapi32;
|
||||
thisleapcnt = leapcnt32;
|
||||
} else {
|
||||
thistimei = 0;
|
||||
thistimecnt = timecnt;
|
||||
thisleapi = 0;
|
||||
thisleapcnt = leapcnt;
|
||||
}
|
||||
thistimelim = thistimei + thistimecnt;
|
||||
thisleaplim = thisleapi + thisleapcnt;
|
||||
for (i = 0; i < typecnt; ++i)
|
||||
writetype[i] = thistimecnt == timecnt;
|
||||
if (thistimecnt == 0) {
|
||||
/*
|
||||
** No transition times fall in the current
|
||||
** (32- or 64-bit) window.
|
||||
*/
|
||||
if (typecnt != 0)
|
||||
writetype[typecnt - 1] = TRUE;
|
||||
} else {
|
||||
for (i = thistimei - 1; i < thistimelim; ++i)
|
||||
if (i >= 0)
|
||||
writetype[types[i]] = TRUE;
|
||||
/*
|
||||
** For America/Godthab and Antarctica/Palmer
|
||||
*/
|
||||
if (thistimei == 0)
|
||||
writetype[0] = TRUE;
|
||||
}
|
||||
thistypecnt = 0;
|
||||
for (i = 0; i < typecnt; ++i)
|
||||
typemap[i] = writetype[i] ? thistypecnt++ : -1;
|
||||
for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
|
||||
indmap[i] = -1;
|
||||
thischarcnt = 0;
|
||||
for (i = 0; i < typecnt; ++i) {
|
||||
register char * thisabbr;
|
||||
|
||||
if (!writetype[i])
|
||||
continue;
|
||||
if (indmap[abbrinds[i]] >= 0)
|
||||
continue;
|
||||
thisabbr = &chars[abbrinds[i]];
|
||||
for (j = 0; j < thischarcnt; ++j)
|
||||
if (strcmp(&thischars[j], thisabbr) == 0)
|
||||
break;
|
||||
if (j == thischarcnt) {
|
||||
(void) strcpy(&thischars[(int) thischarcnt],
|
||||
thisabbr);
|
||||
thischarcnt += strlen(thisabbr) + 1;
|
||||
}
|
||||
indmap[abbrinds[i]] = j;
|
||||
}
|
||||
#define DO(field) (void) fwrite((void *) tzh.field, \
|
||||
(size_t) sizeof tzh.field, (size_t) 1, fp)
|
||||
DO(tzh_magic);
|
||||
DO(tzh_reserved);
|
||||
DO(tzh_ttisgmtcnt);
|
||||
DO(tzh_ttisstdcnt);
|
||||
DO(tzh_leapcnt);
|
||||
DO(tzh_timecnt);
|
||||
DO(tzh_typecnt);
|
||||
DO(tzh_charcnt);
|
||||
tzh = tzh0;
|
||||
(void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
|
||||
tzh.tzh_version[0] = ZIC_VERSION;
|
||||
convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
|
||||
convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
|
||||
convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
|
||||
convert(eitol(thistimecnt), tzh.tzh_timecnt);
|
||||
convert(eitol(thistypecnt), tzh.tzh_typecnt);
|
||||
convert(eitol(thischarcnt), tzh.tzh_charcnt);
|
||||
DO(tzh_magic);
|
||||
DO(tzh_version);
|
||||
DO(tzh_reserved);
|
||||
DO(tzh_ttisgmtcnt);
|
||||
DO(tzh_ttisstdcnt);
|
||||
DO(tzh_leapcnt);
|
||||
DO(tzh_timecnt);
|
||||
DO(tzh_typecnt);
|
||||
DO(tzh_charcnt);
|
||||
#undef DO
|
||||
for (i = 0; i < timecnt; ++i) {
|
||||
j = leapcnt;
|
||||
while (--j >= 0)
|
||||
if (ats[i] >= trans[j]) {
|
||||
ats[i] = tadd(ats[i], corr[j]);
|
||||
break;
|
||||
for (i = thistimei; i < thistimelim; ++i)
|
||||
if (pass == 1)
|
||||
puttzcode((long) ats[i], fp);
|
||||
else puttzcode64(ats[i], fp);
|
||||
for (i = thistimei; i < thistimelim; ++i) {
|
||||
unsigned char uc;
|
||||
|
||||
uc = typemap[types[i]];
|
||||
(void) fwrite((void *) &uc,
|
||||
(size_t) sizeof uc,
|
||||
(size_t) 1,
|
||||
fp);
|
||||
}
|
||||
for (i = 0; i < typecnt; ++i)
|
||||
if (writetype[i]) {
|
||||
puttzcode(gmtoffs[i], fp);
|
||||
(void) putc(isdsts[i], fp);
|
||||
(void) putc((unsigned char) indmap[abbrinds[i]], fp);
|
||||
}
|
||||
puttzcode((long) ats[i], fp);
|
||||
if (thischarcnt != 0)
|
||||
(void) fwrite((void *) thischars,
|
||||
(size_t) sizeof thischars[0],
|
||||
(size_t) thischarcnt, fp);
|
||||
for (i = thisleapi; i < thisleaplim; ++i) {
|
||||
register zic_t todo;
|
||||
|
||||
if (roll[i]) {
|
||||
if (timecnt == 0 || trans[i] < ats[0]) {
|
||||
j = 0;
|
||||
while (isdsts[j])
|
||||
if (++j >= typecnt) {
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
j = 1;
|
||||
while (j < timecnt &&
|
||||
trans[i] >= ats[j])
|
||||
++j;
|
||||
j = types[j - 1];
|
||||
}
|
||||
todo = tadd(trans[i], -gmtoffs[j]);
|
||||
} else todo = trans[i];
|
||||
if (pass == 1)
|
||||
puttzcode((long) todo, fp);
|
||||
else puttzcode64(todo, fp);
|
||||
puttzcode(corr[i], fp);
|
||||
}
|
||||
for (i = 0; i < typecnt; ++i)
|
||||
if (writetype[i])
|
||||
(void) putc(ttisstds[i], fp);
|
||||
for (i = 0; i < typecnt; ++i)
|
||||
if (writetype[i])
|
||||
(void) putc(ttisgmts[i], fp);
|
||||
}
|
||||
if (timecnt > 0)
|
||||
(void) fwrite((void *) types, (size_t) sizeof types[0],
|
||||
(size_t) timecnt, fp);
|
||||
for (i = 0; i < typecnt; ++i) {
|
||||
puttzcode((long) gmtoffs[i], fp);
|
||||
(void) putc(isdsts[i], fp);
|
||||
(void) putc(abbrinds[i], fp);
|
||||
}
|
||||
if (charcnt != 0)
|
||||
(void) fwrite((void *) chars, (size_t) sizeof chars[0],
|
||||
(size_t) charcnt, fp);
|
||||
for (i = 0; i < leapcnt; ++i) {
|
||||
if (roll[i]) {
|
||||
if (timecnt == 0 || trans[i] < ats[0]) {
|
||||
j = 0;
|
||||
while (isdsts[j])
|
||||
if (++j >= typecnt) {
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
j = 1;
|
||||
while (j < timecnt && trans[i] >= ats[j])
|
||||
++j;
|
||||
j = types[j - 1];
|
||||
}
|
||||
puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
|
||||
} else puttzcode((long) trans[i], fp);
|
||||
puttzcode((long) corr[i], fp);
|
||||
}
|
||||
for (i = 0; i < typecnt; ++i)
|
||||
(void) putc(ttisstds[i], fp);
|
||||
for (i = 0; i < typecnt; ++i)
|
||||
(void) putc(ttisgmts[i], fp);
|
||||
(void) fprintf(fp, "\n%s\n", string);
|
||||
if (ferror(fp) || fclose(fp)) {
|
||||
(void) fprintf(stderr, _("%s: Error writing %s\n"),
|
||||
progname, fullname);
|
||||
@ -1602,21 +1737,223 @@ const char * const name;
|
||||
}
|
||||
|
||||
static void
|
||||
doabbr(abbr, format, letters, isdst)
|
||||
doabbr(abbr, format, letters, isdst, doquotes)
|
||||
char * const abbr;
|
||||
const char * const format;
|
||||
const char * const letters;
|
||||
const int isdst;
|
||||
const int doquotes;
|
||||
{
|
||||
if (strchr(format, '/') == NULL) {
|
||||
register char * cp;
|
||||
register char * slashp;
|
||||
register int len;
|
||||
|
||||
slashp = strchr(format, '/');
|
||||
if (slashp == NULL) {
|
||||
if (letters == NULL)
|
||||
(void) strcpy(abbr, format);
|
||||
else (void) sprintf(abbr, format, letters);
|
||||
} else if (isdst)
|
||||
(void) strcpy(abbr, strchr(format, '/') + 1);
|
||||
else {
|
||||
(void) strcpy(abbr, format);
|
||||
*strchr(abbr, '/') = '\0';
|
||||
} else if (isdst) {
|
||||
(void) strcpy(abbr, slashp + 1);
|
||||
} else {
|
||||
if (slashp > format)
|
||||
(void) strncpy(abbr, format,
|
||||
(unsigned) (slashp - format));
|
||||
abbr[slashp - format] = '\0';
|
||||
}
|
||||
if (!doquotes)
|
||||
return;
|
||||
for (cp = abbr; *cp != '\0'; ++cp)
|
||||
if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
|
||||
strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
|
||||
break;
|
||||
len = strlen(abbr);
|
||||
if (len > 0 && *cp == '\0')
|
||||
return;
|
||||
abbr[len + 2] = '\0';
|
||||
abbr[len + 1] = '>';
|
||||
for ( ; len > 0; --len)
|
||||
abbr[len] = abbr[len - 1];
|
||||
abbr[0] = '<';
|
||||
}
|
||||
|
||||
static void
|
||||
updateminmax(x)
|
||||
const int x;
|
||||
{
|
||||
if (min_year > x)
|
||||
min_year = x;
|
||||
if (max_year < x)
|
||||
max_year = x;
|
||||
}
|
||||
|
||||
static int
|
||||
stringoffset(result, offset)
|
||||
char * result;
|
||||
long offset;
|
||||
{
|
||||
register int hours;
|
||||
register int minutes;
|
||||
register int seconds;
|
||||
|
||||
result[0] = '\0';
|
||||
if (offset < 0) {
|
||||
(void) strcpy(result, "-");
|
||||
offset = -offset;
|
||||
}
|
||||
seconds = offset % SECSPERMIN;
|
||||
offset /= SECSPERMIN;
|
||||
minutes = offset % MINSPERHOUR;
|
||||
offset /= MINSPERHOUR;
|
||||
hours = offset;
|
||||
if (hours >= HOURSPERDAY) {
|
||||
result[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
(void) sprintf(end(result), "%d", hours);
|
||||
if (minutes != 0 || seconds != 0) {
|
||||
(void) sprintf(end(result), ":%02d", minutes);
|
||||
if (seconds != 0)
|
||||
(void) sprintf(end(result), ":%02d", seconds);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
stringrule(result, rp, dstoff, gmtoff)
|
||||
char * result;
|
||||
const struct rule * const rp;
|
||||
const long dstoff;
|
||||
const long gmtoff;
|
||||
{
|
||||
register long tod;
|
||||
|
||||
result = end(result);
|
||||
if (rp->r_dycode == DC_DOM) {
|
||||
register int month, total;
|
||||
|
||||
if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
|
||||
return -1;
|
||||
total = 0;
|
||||
for (month = 0; month < rp->r_month; ++month)
|
||||
total += len_months[0][month];
|
||||
(void) sprintf(result, "J%d", total + rp->r_dayofmonth);
|
||||
} else {
|
||||
register int week;
|
||||
|
||||
if (rp->r_dycode == DC_DOWGEQ) {
|
||||
week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
|
||||
if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
|
||||
return -1;
|
||||
} else if (rp->r_dycode == DC_DOWLEQ) {
|
||||
if (rp->r_dayofmonth == len_months[1][rp->r_month])
|
||||
week = 5;
|
||||
else {
|
||||
week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
|
||||
if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
|
||||
return -1;
|
||||
}
|
||||
} else return -1; /* "cannot happen" */
|
||||
(void) sprintf(result, "M%d.%d.%d",
|
||||
rp->r_month + 1, week, rp->r_wday);
|
||||
}
|
||||
tod = rp->r_tod;
|
||||
if (rp->r_todisgmt)
|
||||
tod += gmtoff;
|
||||
if (rp->r_todisstd && rp->r_stdoff == 0)
|
||||
tod += dstoff;
|
||||
if (tod < 0) {
|
||||
result[0] = '\0';
|
||||
return -1;
|
||||
}
|
||||
if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
|
||||
(void) strcat(result, "/");
|
||||
if (stringoffset(end(result), tod) != 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
stringzone(result, zpfirst, zonecount)
|
||||
char * result;
|
||||
const struct zone * const zpfirst;
|
||||
const int zonecount;
|
||||
{
|
||||
register const struct zone * zp;
|
||||
register struct rule * rp;
|
||||
register struct rule * stdrp;
|
||||
register struct rule * dstrp;
|
||||
register int i;
|
||||
register const char * abbrvar;
|
||||
|
||||
result[0] = '\0';
|
||||
zp = zpfirst + zonecount - 1;
|
||||
stdrp = dstrp = NULL;
|
||||
for (i = 0; i < zp->z_nrules; ++i) {
|
||||
rp = &zp->z_rules[i];
|
||||
if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
|
||||
continue;
|
||||
if (rp->r_yrtype != NULL)
|
||||
continue;
|
||||
if (rp->r_stdoff == 0) {
|
||||
if (stdrp == NULL)
|
||||
stdrp = rp;
|
||||
else return;
|
||||
} else {
|
||||
if (dstrp == NULL)
|
||||
dstrp = rp;
|
||||
else return;
|
||||
}
|
||||
}
|
||||
if (stdrp == NULL && dstrp == NULL) {
|
||||
/*
|
||||
** There are no rules running through "max".
|
||||
** Let's find the latest rule.
|
||||
*/
|
||||
for (i = 0; i < zp->z_nrules; ++i) {
|
||||
rp = &zp->z_rules[i];
|
||||
if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
|
||||
(rp->r_hiyear == stdrp->r_hiyear &&
|
||||
rp->r_month > stdrp->r_month))
|
||||
stdrp = rp;
|
||||
}
|
||||
if (stdrp != NULL && stdrp->r_stdoff != 0)
|
||||
return; /* We end up in DST (a POSIX no-no). */
|
||||
/*
|
||||
** Horrid special case: if year is 2037,
|
||||
** presume this is a zone handled on a year-by-year basis;
|
||||
** do not try to apply a rule to the zone.
|
||||
*/
|
||||
if (stdrp != NULL && stdrp->r_hiyear == 2037)
|
||||
return;
|
||||
}
|
||||
if (stdrp == NULL && zp->z_nrules != 0)
|
||||
return;
|
||||
abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
|
||||
doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
|
||||
if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
|
||||
result[0] = '\0';
|
||||
return;
|
||||
}
|
||||
if (dstrp == NULL)
|
||||
return;
|
||||
doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
|
||||
if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
|
||||
if (stringoffset(end(result),
|
||||
-(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
|
||||
result[0] = '\0';
|
||||
return;
|
||||
}
|
||||
(void) strcat(result, ",");
|
||||
if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
|
||||
result[0] = '\0';
|
||||
return;
|
||||
}
|
||||
(void) strcat(result, ",");
|
||||
if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
|
||||
result[0] = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1637,8 +1974,17 @@ const int zonecount;
|
||||
register int startttisstd;
|
||||
register int startttisgmt;
|
||||
register int type;
|
||||
char startbuf[BUFSIZ];
|
||||
register char * startbuf;
|
||||
register char * ab;
|
||||
register char * envvar;
|
||||
register int max_abbr_len;
|
||||
register int max_envvar_len;
|
||||
|
||||
max_abbr_len = 2 + max_format_len + max_abbrvar_len;
|
||||
max_envvar_len = 2 * max_abbr_len + 5 * 9;
|
||||
startbuf = emalloc(max_abbr_len + 1);
|
||||
ab = emalloc(max_abbr_len + 1);
|
||||
envvar = emalloc(max_envvar_len + 1);
|
||||
INITIALIZE(untiltime);
|
||||
INITIALIZE(starttime);
|
||||
/*
|
||||
@ -1653,6 +1999,48 @@ const int zonecount;
|
||||
*/
|
||||
startttisstd = FALSE;
|
||||
startttisgmt = FALSE;
|
||||
min_year = max_year = EPOCH_YEAR;
|
||||
if (leapseen) {
|
||||
updateminmax(leapminyear);
|
||||
updateminmax(leapmaxyear);
|
||||
}
|
||||
for (i = 0; i < zonecount; ++i) {
|
||||
zp = &zpfirst[i];
|
||||
updateminmax(zp->z_untilrule.r_loyear);
|
||||
for (j = 0; j < zp->z_nrules; ++j) {
|
||||
rp = &zp->z_rules[j];
|
||||
if (rp->r_lowasnum)
|
||||
updateminmax(rp->r_loyear);
|
||||
if (rp->r_hiwasnum)
|
||||
updateminmax(rp->r_hiyear);
|
||||
}
|
||||
}
|
||||
/*
|
||||
** Generate lots of data if a rule can't cover all future times.
|
||||
*/
|
||||
stringzone(envvar, zpfirst, zonecount);
|
||||
if (noise && envvar[0] == '\0') {
|
||||
register char * wp;
|
||||
|
||||
wp = ecpyalloc(_("no POSIX environment variable for zone"));
|
||||
wp = ecatalloc(wp, " ");
|
||||
wp = ecatalloc(wp, zpfirst->z_name);
|
||||
warning(wp);
|
||||
ifree(wp);
|
||||
}
|
||||
if (envvar[0] == '\0') {
|
||||
if (min_year >= INT_MIN + YEARSPERREPEAT)
|
||||
min_year -= YEARSPERREPEAT;
|
||||
else min_year = INT_MIN;
|
||||
if (max_year <= INT_MAX - YEARSPERREPEAT)
|
||||
max_year += YEARSPERREPEAT;
|
||||
else max_year = INT_MAX;
|
||||
}
|
||||
/*
|
||||
** For the benefit of older systems, generate data through 2037.
|
||||
*/
|
||||
if (max_year < 2037)
|
||||
max_year = 2037;
|
||||
for (i = 0; i < zonecount; ++i) {
|
||||
/*
|
||||
** A guess that may well be corrected later.
|
||||
@ -1670,7 +2058,7 @@ const int zonecount;
|
||||
if (zp->z_nrules == 0) {
|
||||
stdoff = zp->z_stdoff;
|
||||
doabbr(startbuf, zp->z_format,
|
||||
(char *) NULL, stdoff != 0);
|
||||
(char *) NULL, stdoff != 0, FALSE);
|
||||
type = addtype(oadd(zp->z_gmtoff, stdoff),
|
||||
startbuf, stdoff != 0, startttisstd,
|
||||
startttisgmt);
|
||||
@ -1700,7 +2088,6 @@ const int zonecount;
|
||||
register int k;
|
||||
register zic_t jtime, ktime;
|
||||
register long offset;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
INITIALIZE(ktime);
|
||||
if (useuntil) {
|
||||
@ -1756,24 +2143,27 @@ const int zonecount;
|
||||
stdoff);
|
||||
doabbr(startbuf, zp->z_format,
|
||||
rp->r_abbrvar,
|
||||
rp->r_stdoff != 0);
|
||||
rp->r_stdoff != 0,
|
||||
FALSE);
|
||||
continue;
|
||||
}
|
||||
if (*startbuf == '\0' &&
|
||||
startoff == oadd(zp->z_gmtoff,
|
||||
stdoff))
|
||||
stdoff)) {
|
||||
doabbr(startbuf,
|
||||
zp->z_format,
|
||||
rp->r_abbrvar,
|
||||
rp->r_stdoff !=
|
||||
0);
|
||||
0,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
eats(zp->z_filename, zp->z_linenum,
|
||||
rp->r_filename, rp->r_linenum);
|
||||
doabbr(buf, zp->z_format, rp->r_abbrvar,
|
||||
rp->r_stdoff != 0);
|
||||
doabbr(ab, zp->z_format, rp->r_abbrvar,
|
||||
rp->r_stdoff != 0, FALSE);
|
||||
offset = oadd(zp->z_gmtoff, rp->r_stdoff);
|
||||
type = addtype(offset, buf, rp->r_stdoff != 0,
|
||||
type = addtype(offset, ab, rp->r_stdoff != 0,
|
||||
rp->r_todisstd, rp->r_todisgmt);
|
||||
addtt(ktime, type);
|
||||
}
|
||||
@ -1806,7 +2196,10 @@ error(_("can't determine time zone abbreviation to use just after until time"));
|
||||
starttime = tadd(starttime, -gmtoff);
|
||||
}
|
||||
}
|
||||
writezone(zpfirst->z_name);
|
||||
writezone(zpfirst->z_name, envvar);
|
||||
ifree(startbuf);
|
||||
ifree(ab);
|
||||
ifree(envvar);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2185,8 +2578,6 @@ register const int wantedy;
|
||||
will not work with pre-2004 versions of zic"));
|
||||
}
|
||||
}
|
||||
if (dayoff < 0 && !TYPE_SIGNED(zic_t))
|
||||
return min_time;
|
||||
if (dayoff < min_time / SECSPERDAY)
|
||||
return min_time;
|
||||
if (dayoff > max_time / SECSPERDAY)
|
||||
|
Loading…
Reference in New Issue
Block a user