diff options
Diffstat (limited to 'localtime.c')
-rw-r--r-- | localtime.c | 111 |
1 files changed, 60 insertions, 51 deletions
diff --git a/localtime.c b/localtime.c index 913c7e8..073b096 100644 --- a/localtime.c +++ b/localtime.c @@ -29,28 +29,25 @@ static void unlock(void) { } #endif #ifndef TZ_ABBR_MAX_LEN -#define TZ_ABBR_MAX_LEN 16 +# define TZ_ABBR_MAX_LEN 16 #endif /* !defined TZ_ABBR_MAX_LEN */ #ifndef TZ_ABBR_CHAR_SET -#define TZ_ABBR_CHAR_SET \ +# define TZ_ABBR_CHAR_SET \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" #endif /* !defined TZ_ABBR_CHAR_SET */ #ifndef TZ_ABBR_ERR_CHAR -#define TZ_ABBR_ERR_CHAR '_' +# define TZ_ABBR_ERR_CHAR '_' #endif /* !defined TZ_ABBR_ERR_CHAR */ /* -** SunOS 4.1.1 headers lack O_BINARY. +** Support non-POSIX platforms that distinguish between text and binary files. */ -#ifdef O_BINARY -#define OPEN_MODE (O_RDONLY | O_BINARY) -#endif /* defined O_BINARY */ #ifndef O_BINARY -#define OPEN_MODE O_RDONLY -#endif /* !defined O_BINARY */ +# define O_BINARY 0 +#endif #ifndef WILDABBR /* @@ -72,12 +69,13 @@ static void unlock(void) { } ** manual page of what this "time zone abbreviation" means (doing this so ** that tzname[0] has the "normal" length of three characters). */ -#define WILDABBR " " +# define WILDABBR " " #endif /* !defined WILDABBR */ static const char wildabbr[] = WILDABBR; -static const char gmt[] = "GMT"; +static char const etc_utc[] = "Etc/UTC"; +static char const *utc = etc_utc + sizeof "Etc/" - 1; /* ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. @@ -86,7 +84,7 @@ static const char gmt[] = "GMT"; ** for historical reasons, US rules are a common default. */ #ifndef TZDEFRULESTRING -#define TZDEFRULESTRING ",M3.2.0,M11.1.0" +# define TZDEFRULESTRING ",M3.2.0,M11.1.0" #endif struct ttinfo { /* time type information */ @@ -102,9 +100,6 @@ struct lsinfo { /* leap second information */ int_fast32_t ls_corr; /* correction to apply */ }; -#define SMALLEST(a, b) (((a) < (b)) ? (a) : (b)) -#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) - /* This abbreviation means local time is unspecified. */ static char const UNSPEC[] = "-00"; @@ -112,13 +107,13 @@ static char const UNSPEC[] = "-00"; This needs to be at least 1 for null termination in case the input data isn't properly terminated, and it also needs to be big enough for ttunspecified to work without crashing. */ -enum { CHARS_EXTRA = BIGGEST(sizeof UNSPEC, 2) - 1 }; +enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; #ifdef TZNAME_MAX -#define MY_TZNAME_MAX TZNAME_MAX +# define MY_TZNAME_MAX TZNAME_MAX #endif /* defined TZNAME_MAX */ #ifndef TZNAME_MAX -#define MY_TZNAME_MAX 255 +# define MY_TZNAME_MAX 255 #endif /* !defined TZNAME_MAX */ struct state { @@ -131,9 +126,8 @@ struct state { time_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + CHARS_EXTRA, - sizeof gmt), - (2 * (MY_TZNAME_MAX + 1)))]; + char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"), + 2 * (MY_TZNAME_MAX + 1))]; struct lsinfo lsis[TZ_MAX_LEAPS]; /* The time type to use for early times or if no transitions. @@ -175,12 +169,12 @@ static struct state * gmtptr; #ifndef ALL_STATE static struct state lclmem; static struct state gmtmem; -#define lclptr (&lclmem) -#define gmtptr (&gmtmem) +static struct state *const lclptr = &lclmem; +static struct state *const gmtptr = &gmtmem; #endif /* State Farm */ #ifndef TZ_STRLEN_MAX -#define TZ_STRLEN_MAX 255 +# define TZ_STRLEN_MAX 255 #endif /* !defined TZ_STRLEN_MAX */ static char lcl_TZname[TZ_STRLEN_MAX + 1]; @@ -292,42 +286,58 @@ update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp) #endif } +/* If STDDST_MASK indicates that SP's TYPE provides useful info, + update tzname, timezone, and/or altzone and return STDDST_MASK, + diminished by the provided info if it is a specified local time. + Otherwise, return STDDST_MASK. See settzname for STDDST_MASK. */ +static int +may_update_tzname_etc(int stddst_mask, struct state *sp, int type) +{ + struct ttinfo *ttisp = &sp->ttis[type]; + int this_bit = 1 << ttisp->tt_isdst; + if (stddst_mask & this_bit) { + update_tzname_etc(sp, ttisp); + if (!ttunspecified(sp, type)) + return stddst_mask & ~this_bit; + } + return stddst_mask; +} + static void settzname(void) { register struct state * const sp = lclptr; register int i; + /* If STDDST_MASK & 1 we need info about a standard time. + If STDDST_MASK & 2 we need info about a daylight saving time. + When STDDST_MASK becomes zero we can stop looking. */ + int stddst_mask = 0; + #if HAVE_TZNAME - tzname[0] = tzname[1] = (char *) (sp ? wildabbr : gmt); + tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc); + stddst_mask = 3; #endif #if USG_COMPAT - daylight = 0; timezone = 0; + stddst_mask = 3; #endif #if ALTZONE altzone = 0; + stddst_mask |= 2; #endif - if (sp == NULL) { - return; - } /* ** And to get the latest time zone abbreviations into tzname. . . */ - for (i = 0; i < sp->typecnt; ++i) { - register const struct ttinfo * const ttisp = &sp->ttis[i]; - update_tzname_etc(sp, ttisp); + if (sp) { + for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--) + stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]); + for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--) + stddst_mask = may_update_tzname_etc(stddst_mask, sp, i); } - for (i = 0; i < sp->timecnt; ++i) { - register const struct ttinfo * const ttisp = - &sp->ttis[ - sp->types[i]]; - update_tzname_etc(sp, ttisp); #if USG_COMPAT - if (ttisp->tt_isdst) - daylight = 1; + daylight = stddst_mask >> 1 ^ 1; #endif - } } static void @@ -378,8 +388,7 @@ union local_storage { } u; /* The file name to be opened. */ - char fullname[BIGGEST(sizeof(struct file_analysis), - sizeof tzdirslash + 1024)]; + char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)]; }; /* Load tz data from the file named NAME into *SP. Read extended @@ -440,7 +449,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, } if (doaccess && access(name, R_OK) != 0) return errno; - fid = open(name, OPEN_MODE); + fid = open(name, O_RDONLY | O_BINARY); if (fid < 0) return errno; @@ -1385,8 +1394,8 @@ tzparse(const char *name, struct state *sp, struct state *basep) static void gmtload(struct state *const sp) { - if (tzload(gmt, sp, true) != 0) - tzparse("GMT0", sp, NULL); + if (tzload(etc_utc, sp, true) != 0) + tzparse("UTC0", sp, NULL); } /* Initialize *SP to a value appropriate for the TZ setting NAME. @@ -1404,7 +1413,7 @@ zoneinit(struct state *sp, char const *name) sp->charcnt = 0; sp->goback = sp->goahead = false; init_ttinfo(&sp->ttis[0], 0, false, 0); - strcpy(sp->chars, gmt); + strcpy(sp->chars, utc); sp->defaulttype = 0; return 0; } else { @@ -1513,7 +1522,7 @@ tzfree(timezone_t sp) ** set the applicable parts of tzname, timezone and altzone; ** however, it's OK to omit this step if the timezone is POSIX-compatible, ** since in that case tzset should have already done this step correctly. -** SETNAME's type is intfast32_t for compatibility with gmtsub, +** SETNAME's type is int_fast32_t for compatibility with gmtsub, ** but it is actually a boolean and its value should be 0 or 1. */ @@ -1658,7 +1667,7 @@ gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset, ** but this is no time for a treasure hunt. */ tmp->TM_ZONE = ((char *) - (offset ? wildabbr : gmtptr ? gmtptr->chars : gmt)); + (offset ? wildabbr : gmtptr ? gmtptr->chars : utc)); #endif /* defined TM_ZONE */ return result; } @@ -1849,7 +1858,7 @@ ctime_r(const time_t *timep, char *buf) */ #ifndef WRONG -#define WRONG (-1) +# define WRONG (-1) #endif /* !defined WRONG */ /* @@ -2070,10 +2079,10 @@ time2sub(struct tm *const tmp, && (yourtm.TM_GMTOFF < 0 ? (-SECSPERDAY <= yourtm.TM_GMTOFF && (mytm.TM_GMTOFF <= - (SMALLEST(INT_FAST32_MAX, LONG_MAX) + (min(INT_FAST32_MAX, LONG_MAX) + yourtm.TM_GMTOFF))) : (yourtm.TM_GMTOFF <= SECSPERDAY - && ((BIGGEST(INT_FAST32_MIN, LONG_MIN) + && ((max(INT_FAST32_MIN, LONG_MIN) + yourtm.TM_GMTOFF) <= mytm.TM_GMTOFF)))) { /* MYTM matches YOURTM except with the wrong UT offset. |