summaryrefslogtreecommitdiff
path: root/localtime.c
diff options
context:
space:
mode:
Diffstat (limited to 'localtime.c')
-rw-r--r--localtime.c111
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.