* 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:
Ulrich Drepper 2006-11-11 02:05:42 +00:00
parent 6decd24cc2
commit 064737fb74
10 changed files with 754 additions and 238 deletions

View File

@ -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>.

View File

@ -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. */

View File

@ -1,6 +1,6 @@
# Check tz tables for consistency.
# @(#)checktab.awk 1.7
# @(#)checktab.awk 8.1
# Contributed by Paul Eggert.

View File

@ -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 */

View File

@ -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.
*/

View File

@ -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 */

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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)