OSDN Git Service

Upgrade to tzcode2013f plus Android modifications (from tzcode2013d plus Android...
authorElliott Hughes <enh@google.com>
Fri, 27 Sep 2013 07:04:30 +0000 (00:04 -0700)
committerElliott Hughes <enh@google.com>
Fri, 27 Sep 2013 07:04:30 +0000 (00:04 -0700)
localtime.c and strftime.c are still quite different from upstream because of
our extensions, but the other files continue to be identical, and the two
exceptions should be otherwise identical.

From the tzcode2013e release notes:

  Changes affecting Godthab time stamps after 2037 if version mismatch

    Allow POSIX-like TZ strings where the transition time's hour can
    range from -167 through 167, instead of the POSIX-required 0
    through 24.  E.g., TZ='FJT-12FJST,M10.3.1/146,M1.3.4/75' for the
    new Fiji rules.  This is a more-compact way to represent
    far-future time stamps for America/Godthab, America/Santiago,
    Antarctica/Palmer, Asia/Gaza, Asia/Hebron, Asia/Jerusalem,
    Pacific/Easter, and Pacific/Fiji.  Other zones are unaffected by
    this change.  (Derived from a suggestion by Arthur David Olson.)

    Allow POSIX-like TZ strings where daylight saving time is in
    effect all year.  E.g., TZ='WART4WARST,J1/0,J365/25' for Western
    Argentina Summer Time all year.  This supports a more-compact way
    to represent the 2013d data for America/Argentina/San_Luis.
    Because of the change for San Luis noted above this change does not
    affect the current data.  (Thanks to Andrew Main (Zefram) for
    suggestions that improved this change.)

    Where these two TZ changes take effect, there is a minor extension
    to the tz file format in that it allows new values for the
    embedded TZ-format string, and the tz file format version number
    has therefore been increased from 2 to 3 as a precaution.
    Version-2-based client code should continue to work as before for
    all time stamps before 2038.  Existing version-2-based client code
    (tzcode, GNU/Linux, Solaris) has been tested on version-3-format
    files, and typically works in practice even for time stamps after
    2037; the only known exception is America/Godthab.

  Changes affecting API

    Support for floating-point time_t has been removed.
    It was always dicey, and POSIX no longer requires it.
    (Thanks to Eric Blake for suggesting to the POSIX committee to
    remove it, and thanks to Alan Barrett, Clive D.W. Feather, Andy
    Heninger, Arthur David Olson, and Alois Treindl, for reporting
    bugs and elucidating some of the corners of the old floating-point
    implementation.)

    The signatures of 'offtime', 'timeoff', and 'gtime' have been
    changed back to the old practice of using 'long' to represent UT
    offsets.  This had been inadvertently and mistakenly changed to
    'int_fast32_t'.  (Thanks to Christos Zoulos.)

    The code avoids undefined behavior on integer overflow in some
    more places, including gmtime, localtime, mktime and zdump.

  Changes affecting code internals

    Minor changes pacify GCC 4.7.3 and GCC 4.8.1.

  Changes affecting documentation and commentary

    Documentation and commentary is more careful to distinguish UT in
    general from UTC in particular.  (Thanks to Steve Allen.)

From the tzcode2013f release notes:

  Changes affecting API

    The types of the global variables 'timezone' and 'altzone' (if present)
    have been changed back to 'long'.  This is required for 'timezone'
    by POSIX, and for 'altzone' by common practice, e.g., Solaris 11.
    These variables were originally 'long' in the tz code, but were
    mistakenly changed to 'time_t' in 1987; nobody reported the
    incompatibility until now.  The difference matters on x32, where
    'long' is 32 bits and 'time_t' is 64.  (Thanks to Elliott Hughes.)

Change-Id: I14937c42a391ddb865e4d89f0783961bcc6baa21

libc/tzcode/difftime.c
libc/tzcode/localtime.c
libc/tzcode/private.h
libc/tzcode/strftime.c
libc/tzcode/tzfile.h

index fcd18ce..449cdf0 100644 (file)
@@ -5,7 +5,7 @@
 
 /*LINTLIBRARY*/
 
-#include "private.h"   /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */
+#include "private.h"   /* for time_t and TYPE_SIGNED */
 
 double ATTRIBUTE_CONST
 difftime(const time_t time1, const time_t time0)
@@ -16,15 +16,8 @@ difftime(const time_t time1, const time_t time0)
        */
        if (sizeof (double) > sizeof (time_t))
                return (double) time1 - (double) time0;
-       if (!TYPE_INTEGRAL(time_t)) {
-               /*
-               ** time_t is floating.
-               */
-               return time1 - time0;
-       }
        if (!TYPE_SIGNED(time_t)) {
                /*
-               ** time_t is integral and unsigned.
                ** The difference of two unsigned values can't overflow
                ** if the minuend is greater than or equal to the subtrahend.
                */
@@ -33,7 +26,6 @@ difftime(const time_t time1, const time_t time0)
                else    return -(double) (time0 - time1);
        }
        /*
-       ** time_t is integral and signed.
        ** Handle cases where both time1 and time0 have the same sign
        ** (meaning that their difference cannot overflow).
        */
index f374541..a52e334 100644 (file)
@@ -13,7 +13,6 @@
 #include "private.h"
 #include "tzfile.h"
 #include "fcntl.h"
-#include "float.h"  /* for FLT_MAX and DBL_MAX */
 
 #ifndef TZ_ABBR_MAX_LEN
 #define TZ_ABBR_MAX_LEN 16
@@ -91,11 +90,11 @@ static const char   gmt[] = "GMT";
 #endif /* !defined TZDEFDST */
 
 struct ttinfo {             /* time type information */
-    int_fast32_t tt_gmtoff;  /* UTC offset in seconds */
+    int_fast32_t tt_gmtoff;  /* UT offset in seconds */
     int          tt_isdst;   /* used to set tm_isdst */
     int          tt_abbrind; /* abbreviation list index */
     int          tt_ttisstd; /* TRUE if transition is std time */
-    int          tt_ttisgmt; /* TRUE if transition is UTC */
+    int          tt_ttisgmt; /* TRUE if transition is UT */
 };
 
 struct lsinfo {             /* leap second information */
@@ -232,12 +231,12 @@ char *          tzname[2] = {
 static struct tm    tmGlobal;
 
 #ifdef USG_COMPAT
-time_t          timezone = 0;
-int         daylight = 0;
+long                   timezone = 0;
+int                    daylight = 0;
 #endif /* defined USG_COMPAT */
 
 #ifdef ALTZONE
-time_t          altzone = 0;
+long                   altzone = 0;
 #endif /* defined ALTZONE */
 
 static int_fast32_t
@@ -334,8 +333,7 @@ settzname(void)
 static int
 differ_by_repeat(const time_t t1, const time_t t0)
 {
-       if (TYPE_INTEGRAL(time_t) &&
-               TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
+       if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
                        return 0;
        return t1 - t0 == SECSPERREPEAT;
 }
@@ -514,9 +512,9 @@ tzload(register const char* name, register struct state* const sp,
         for (i = 0; i < nread; ++i)
             up->buf[i] = p[i];
         /*
-        ** If this is a narrow integer time_t system, we're done.
+        ** If this is a narrow time_t system, we're done.
         */
-        if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
+        if (stored >= (int) sizeof(time_t))
             break;
     }
     if (doextend && nread > 2 &&
@@ -824,14 +822,14 @@ getrule(const char * strp, register struct rule * const rulep)
         ** Time specified.
         */
         ++strp;
-        strp = getsecs(strp, &rulep->r_time);
+        strp = getoffset(strp, &rulep->r_time);
     } else  rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
     return strp;
 }
 
 /*
 ** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
-** year, a rule, and the offset from UTC at the time that rule takes effect,
+** year, a rule, and the offset from UT at the time that rule takes effect,
 ** calculate the Epoch-relative time that rule takes effect.
 */
 
@@ -914,10 +912,10 @@ transtime(const time_t janfirst, const int year,
     }
 
     /*
-    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
+    ** "value" is the Epoch-relative time of 00:00:00 UT on the day in
     ** question. To get the Epoch-relative time of the specified local
     ** time on that day, add the transition time and the current offset
-    ** from UTC.
+    ** from UT.
     */
     return value + rulep->r_time + offset;
 }
@@ -997,6 +995,7 @@ tzparse(const char * name, register struct state * const sp,
             struct rule start;
             struct rule end;
             register int    year;
+            register int    yearlim;
             register time_t janfirst;
             time_t      starttime;
             time_t      endtime;
@@ -1024,35 +1023,43 @@ tzparse(const char * name, register struct state * const sp,
             atp = sp->ats;
             typep = sp->types;
             janfirst = 0;
-            sp->timecnt = 0;
-            for (year = EPOCH_YEAR;
-                sp->timecnt + 2 <= TZ_MAX_TIMES;
-                ++year) {
-                    time_t  newfirst;
+            yearlim = EPOCH_YEAR + YEARSPERREPEAT;
+            for (year = EPOCH_YEAR; year < yearlim; year++) {
+                int_fast32_t yearsecs;
 
                 starttime = transtime(janfirst, year, &start,
                     stdoffset);
                 endtime = transtime(janfirst, year, &end,
                     dstoffset);
-                if (starttime > endtime) {
-                    *atp++ = endtime;
-                    *typep++ = 1;   /* DST ends */
-                    *atp++ = starttime;
-                    *typep++ = 0;   /* DST begins */
-                } else {
-                    *atp++ = starttime;
-                    *typep++ = 0;   /* DST begins */
-                    *atp++ = endtime;
-                    *typep++ = 1;   /* DST ends */
+                yearsecs = (year_lengths[isleap(year)]
+                            * SECSPERDAY);
+                if (starttime > endtime
+                    || (starttime < endtime
+                        && (endtime - starttime
+                            < (yearsecs
+                               + (stdoffset - dstoffset))))) {
+                    if (&sp->ats[TZ_MAX_TIMES - 2] < atp)
+                        break;
+                    yearlim = year + YEARSPERREPEAT + 1;
+                    if (starttime > endtime) {
+                        *atp++ = endtime;
+                        *typep++ = 1;   /* DST ends */
+                        *atp++ = starttime;
+                        *typep++ = 0;   /* DST begins */
+                    } else {
+                        *atp++ = starttime;
+                        *typep++ = 0;   /* DST begins */
+                         *atp++ = endtime;
+                        *typep++ = 1;   /* DST ends */
+                    }
                 }
-                sp->timecnt += 2;
-                newfirst = janfirst;
-                newfirst += year_lengths[isleap(year)] *
-                    SECSPERDAY;
-                if (newfirst <= janfirst)
+                if (time_t_max - janfirst < yearsecs)
                     break;
-                janfirst = newfirst;
+                janfirst += yearsecs;
             }
+            sp->timecnt = atp - sp->ats;
+            if (!sp->timecnt)
+                sp->typecnt = 1;       /* Perpetual DST.  */
         } else {
             register int_fast32_t   theirstdoffset;
             register int_fast32_t   theirdstoffset;
@@ -1290,21 +1297,14 @@ localsub(const time_t * const timep, const int_fast32_t offset,
         (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
             time_t          newt = t;
             register time_t     seconds;
-            register time_t     tcycles;
-            register int_fast64_t   icycles;
+            register time_t     years;
 
             if (t < sp->ats[0])
                 seconds = sp->ats[0] - t;
             else    seconds = t - sp->ats[sp->timecnt - 1];
             --seconds;
-            tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
-            ++tcycles;
-            icycles = tcycles;
-            if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
-                return NULL;
-            seconds = icycles;
-            seconds *= YEARSPERREPEAT;
-            seconds *= AVGSECSPERYEAR;
+            years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
+            seconds = years * AVGSECSPERYEAR;
             if (t < sp->ats[0])
                 newt += seconds;
             else    newt -= seconds;
@@ -1317,8 +1317,8 @@ localsub(const time_t * const timep, const int_fast32_t offset,
 
                 newy = tmp->tm_year;
                 if (t < sp->ats[0])
-                    newy -= icycles * YEARSPERREPEAT;
-                else    newy += icycles * YEARSPERREPEAT;
+                    newy -= years;
+                else    newy += years;
                 tmp->tm_year = newy;
                 if (tmp->tm_year != newy)
                     return NULL;
@@ -1403,7 +1403,7 @@ gmtsub(const time_t * const timep, const int_fast32_t offset,
 #ifdef TM_ZONE
     /*
     ** Could get fancy here and deliver something such as
-    ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
+    ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
     ** but this is no time for a treasure hunt.
     */
     if (offset != 0)
@@ -1509,9 +1509,10 @@ timesub(const time_t *const timep, const int_fast32_t offset,
         register int    leapdays;
 
         tdelta = tdays / DAYSPERLYEAR;
+        if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
+               && tdelta <= INT_MAX))
+                return NULL;
         idelta = tdelta;
-        if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
-            return NULL;
         if (idelta == 0)
             idelta = (tdays < 0) ? -1 : 1;
         newy = y;
@@ -1525,9 +1526,8 @@ timesub(const time_t *const timep, const int_fast32_t offset,
     }
     {
         register int_fast32_t   seconds;
-        register time_t half_second = 0.5;
 
-        seconds = tdays * SECSPERDAY + half_second;
+        seconds = tdays * SECSPERDAY;
         tdays = seconds / SECSPERDAY;
         rem += seconds - tdays * SECSPERDAY;
     }
@@ -1685,8 +1685,9 @@ tmcomp(register const struct tm * const atmp,
 {
     register int    result;
 
-    if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
-        (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+    if (atmp->tm_year != btmp->tm_year)
+        return atmp->tm_year < btmp->tm_year ? -1 : 1;
+    if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
         (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
         (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
         (result = (atmp->tm_min - btmp->tm_min)) == 0)
@@ -1785,11 +1786,6 @@ time2sub(struct tm * const tmp,
     if (!TYPE_SIGNED(time_t)) {
         lo = 0;
         hi = lo - 1;
-    } else if (!TYPE_INTEGRAL(time_t)) {
-        if (sizeof(time_t) > sizeof(float))
-            hi = (time_t) DBL_MAX;
-        else    hi = (time_t) FLT_MAX;
-        lo = -hi;
     } else {
         lo = 1;
         for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
@@ -2019,7 +2015,7 @@ timegm(struct tm * const tmp)
 ** previous versions of the CMUCS runtime library.
 */
 
-int_fast32_t
+long
 gtime(struct tm * const tmp)
 {
     const time_t    t = mktime(tmp);
index 1a938a2..3a19305 100644 (file)
@@ -166,10 +166,21 @@ typedef int int_fast32_t;
 #ifndef INTMAX_MAX
 # if defined LLONG_MAX || defined __LONG_LONG_MAX__
 typedef long long intmax_t;
+#  define strtoimax strtoll
 #  define PRIdMAX "lld"
+#  ifdef LLONG_MAX
+#   define INTMAX_MAX LLONG_MAX
+#   define INTMAX_MIN LLONG_MIN
+#  else
+#   define INTMAX_MAX __LONG_LONG_MAX__
+#   define INTMAX_MIN __LONG_LONG_MIN__
+#  endif
 # else
 typedef long intmax_t;
+#  define strtoimax strtol
 #  define PRIdMAX "ld"
+#  define INTMAX_MAX LONG_MAX
+#  define INTMAX_MIN LONG_MIN
 # endif
 #endif
 
@@ -193,9 +204,11 @@ typedef unsigned long uintmax_t;
 #if 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
 # define ATTRIBUTE_CONST __attribute__ ((const))
 # define ATTRIBUTE_PURE __attribute__ ((__pure__))
+# define ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
 #else
 # define ATTRIBUTE_CONST /* empty */
 # define ATTRIBUTE_PURE /* empty */
+# define ATTRIBUTE_FORMAT(spec) /* empty */
 #endif
 
 #if !defined _Noreturn && __STDC_VERSION__ < 201112
@@ -314,15 +327,6 @@ static time_t const time_t_max =
    ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
    : -1);
 
-/*
-** Since the definition of TYPE_INTEGRAL contains floating point numbers,
-** it cannot be used in preprocessor directives.
-*/
-
-#ifndef TYPE_INTEGRAL
-#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
-#endif /* !defined TYPE_INTEGRAL */
-
 #ifndef INT_STRLEN_MAXIMUM
 /*
 ** 302 / 1000 is log10(2.0) rounded up.
index e92c44d..1b223e5 100644 (file)
@@ -592,7 +592,7 @@ label:
                 continue;
             case 'z':
                 {
-                int     diff;
+                long     diff;
                 char const *    sign;
 
                 if (t->tm_isdst < 0)
@@ -601,7 +601,7 @@ label:
                 diff = t->TM_GMTOFF;
 #else /* !defined TM_GMTOFF */
                 /*
-                ** C99 says that the UTC offset must
+                ** C99 says that the UT offset must
                 ** be computed by looking only at
                 ** tm_isdst. This requirement is
                 ** incorrect, since it means the code
index d04fe04..a2955dd 100644 (file)
@@ -39,7 +39,7 @@
 
 struct tzhead {
        char    tzh_magic[4];           /* TZ_MAGIC */
-       char    tzh_version[1];         /* '\0' or '2' as of 2005 */
+       char    tzh_version[1];         /* '\0' or '2' or '3' as of 2013 */
        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 */
@@ -55,7 +55,7 @@ struct tzhead {
 **     tzh_timecnt (char [4])s         coded transition times a la time(2)
 **     tzh_timecnt (unsigned char)s    types of local time starting at above
 **     tzh_typecnt repetitions of
-**             one (char [4])          coded UTC offset in seconds
+**             one (char [4])          coded UT offset in seconds
 **             one (unsigned char)     used to set tm_isdst
 **             one (unsigned char)     that's an abbreviation list index
 **     tzh_charcnt (char)s             '\0'-terminated zone abbreviations
@@ -68,7 +68,7 @@ struct tzhead {
 **                                     if absent, transition times are
 **                                     assumed to be wall clock time
 **     tzh_ttisgmtcnt (char)s          indexed by type; if TRUE, transition
-**                                     time is UTC, if FALSE,
+**                                     time is UT, if FALSE,
 **                                     transition time is local time
 **                                     if absent, transition times are
 **                                     assumed to be local time
@@ -82,6 +82,13 @@ struct tzhead {
 ** instants after the last transition time stored in the file
 ** (with nothing between the newlines if there is no POSIX representation for
 ** such instants).
+**
+** If tz_version is '3' or greater, the above is extended as follows.
+** First, the POSIX TZ string's hour offset may range from -167
+** through 167 as compared to the POSIX-required 0 through 24.
+** Second, its DST start time may be January 1 at 00:00 and its stop
+** time December 31 at 24:00 plus the difference between DST and
+** standard time, indicating DST all year.
 */
 
 /*