1bc421551SDag-Erling Smørgrav /* Convert timestamp from time_t to struct tm. */ 2bc421551SDag-Erling Smørgrav 3bc421551SDag-Erling Smørgrav /* 4bc421551SDag-Erling Smørgrav ** This file is in the public domain, so clarified as of 5bc421551SDag-Erling Smørgrav ** 1996-06-05 by Arthur David Olson. 6bc421551SDag-Erling Smørgrav */ 7bc421551SDag-Erling Smørgrav 8bc421551SDag-Erling Smørgrav /* 9bc421551SDag-Erling Smørgrav ** Leap second handling from Bradley White. 1046c59934SDag-Erling Smørgrav ** POSIX.1-1988 style TZ environment variable handling from Guy Harris. 11bc421551SDag-Erling Smørgrav */ 12bc421551SDag-Erling Smørgrav 13bc421551SDag-Erling Smørgrav /*LINTLIBRARY*/ 14bc421551SDag-Erling Smørgrav 15bc421551SDag-Erling Smørgrav #define LOCALTIME_IMPLEMENTATION 16bc421551SDag-Erling Smørgrav #include "namespace.h" 17bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES 18bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES_INTERVAL 19bc421551SDag-Erling Smørgrav #define DETECT_TZ_CHANGES_INTERVAL 61 20bc421551SDag-Erling Smørgrav #endif 21bc421551SDag-Erling Smørgrav #include <sys/stat.h> 22bc421551SDag-Erling Smørgrav #endif 23bc421551SDag-Erling Smørgrav #include <fcntl.h> 24bc421551SDag-Erling Smørgrav #if THREAD_SAFE 25bc421551SDag-Erling Smørgrav #include <pthread.h> 26bc421551SDag-Erling Smørgrav #endif 27bc421551SDag-Erling Smørgrav #include "private.h" 28bc421551SDag-Erling Smørgrav #include "un-namespace.h" 29bc421551SDag-Erling Smørgrav 3046c59934SDag-Erling Smørgrav #include "tzdir.h" 31bc421551SDag-Erling Smørgrav #include "tzfile.h" 32bc421551SDag-Erling Smørgrav 33bc421551SDag-Erling Smørgrav #include "libc_private.h" 34bc421551SDag-Erling Smørgrav 35bc421551SDag-Erling Smørgrav #if defined THREAD_SAFE && THREAD_SAFE 36bc421551SDag-Erling Smørgrav static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER; 37bc421551SDag-Erling Smørgrav static int lock(void) { 38bc421551SDag-Erling Smørgrav if (__isthreaded) 39bc421551SDag-Erling Smørgrav return _pthread_mutex_lock(&locallock); 40bc421551SDag-Erling Smørgrav return 0; 41bc421551SDag-Erling Smørgrav } 42bc421551SDag-Erling Smørgrav static void unlock(void) { 43bc421551SDag-Erling Smørgrav if (__isthreaded) 44bc421551SDag-Erling Smørgrav _pthread_mutex_unlock(&locallock); 45bc421551SDag-Erling Smørgrav } 46bc421551SDag-Erling Smørgrav #else 47bc421551SDag-Erling Smørgrav static int lock(void) { return 0; } 48bc421551SDag-Erling Smørgrav static void unlock(void) { } 49bc421551SDag-Erling Smørgrav #endif 50bc421551SDag-Erling Smørgrav 51bc421551SDag-Erling Smørgrav #ifndef TZ_ABBR_CHAR_SET 52bc421551SDag-Erling Smørgrav # define TZ_ABBR_CHAR_SET \ 53bc421551SDag-Erling Smørgrav "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" 54bc421551SDag-Erling Smørgrav #endif /* !defined TZ_ABBR_CHAR_SET */ 55bc421551SDag-Erling Smørgrav 56bc421551SDag-Erling Smørgrav #ifndef TZ_ABBR_ERR_CHAR 57bc421551SDag-Erling Smørgrav # define TZ_ABBR_ERR_CHAR '_' 58bc421551SDag-Erling Smørgrav #endif /* !defined TZ_ABBR_ERR_CHAR */ 59bc421551SDag-Erling Smørgrav 60bc421551SDag-Erling Smørgrav /* 61bc421551SDag-Erling Smørgrav ** Support non-POSIX platforms that distinguish between text and binary files. 62bc421551SDag-Erling Smørgrav */ 63bc421551SDag-Erling Smørgrav 64bc421551SDag-Erling Smørgrav #ifndef O_BINARY 65bc421551SDag-Erling Smørgrav # define O_BINARY 0 66bc421551SDag-Erling Smørgrav #endif 67bc421551SDag-Erling Smørgrav 68bc421551SDag-Erling Smørgrav #ifndef WILDABBR 69bc421551SDag-Erling Smørgrav /* 70bc421551SDag-Erling Smørgrav ** Someone might make incorrect use of a time zone abbreviation: 71bc421551SDag-Erling Smørgrav ** 1. They might reference tzname[0] before calling tzset (explicitly 72bc421551SDag-Erling Smørgrav ** or implicitly). 73bc421551SDag-Erling Smørgrav ** 2. They might reference tzname[1] before calling tzset (explicitly 74bc421551SDag-Erling Smørgrav ** or implicitly). 75bc421551SDag-Erling Smørgrav ** 3. They might reference tzname[1] after setting to a time zone 76bc421551SDag-Erling Smørgrav ** in which Daylight Saving Time is never observed. 77bc421551SDag-Erling Smørgrav ** 4. They might reference tzname[0] after setting to a time zone 78bc421551SDag-Erling Smørgrav ** in which Standard Time is never observed. 79bc421551SDag-Erling Smørgrav ** 5. They might reference tm.TM_ZONE after calling offtime. 80bc421551SDag-Erling Smørgrav ** What's best to do in the above cases is open to debate; 81bc421551SDag-Erling Smørgrav ** for now, we just set things up so that in any of the five cases 82bc421551SDag-Erling Smørgrav ** WILDABBR is used. Another possibility: initialize tzname[0] to the 83bc421551SDag-Erling Smørgrav ** string "tzname[0] used before set", and similarly for the other cases. 84bc421551SDag-Erling Smørgrav ** And another: initialize tzname[0] to "ERA", with an explanation in the 85bc421551SDag-Erling Smørgrav ** manual page of what this "time zone abbreviation" means (doing this so 86bc421551SDag-Erling Smørgrav ** that tzname[0] has the "normal" length of three characters). 87bc421551SDag-Erling Smørgrav */ 88bc421551SDag-Erling Smørgrav # define WILDABBR " " 89bc421551SDag-Erling Smørgrav #endif /* !defined WILDABBR */ 90bc421551SDag-Erling Smørgrav 91bc421551SDag-Erling Smørgrav static const char wildabbr[] = WILDABBR; 92bc421551SDag-Erling Smørgrav 93bc421551SDag-Erling Smørgrav static char const etc_utc[] = "Etc/UTC"; 94bc421551SDag-Erling Smørgrav static char const *utc = etc_utc + sizeof "Etc/" - 1; 95bc421551SDag-Erling Smørgrav 96bc421551SDag-Erling Smørgrav /* 97bc421551SDag-Erling Smørgrav ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. 98bc421551SDag-Erling Smørgrav ** Default to US rules as of 2017-05-07. 99bc421551SDag-Erling Smørgrav ** POSIX does not specify the default DST rules; 100bc421551SDag-Erling Smørgrav ** for historical reasons, US rules are a common default. 101bc421551SDag-Erling Smørgrav */ 102bc421551SDag-Erling Smørgrav #ifndef TZDEFRULESTRING 103bc421551SDag-Erling Smørgrav # define TZDEFRULESTRING ",M3.2.0,M11.1.0" 104bc421551SDag-Erling Smørgrav #endif 105bc421551SDag-Erling Smørgrav 106bc421551SDag-Erling Smørgrav struct ttinfo { /* time type information */ 107bc421551SDag-Erling Smørgrav int_fast32_t tt_utoff; /* UT offset in seconds */ 108bc421551SDag-Erling Smørgrav bool tt_isdst; /* used to set tm_isdst */ 109bc421551SDag-Erling Smørgrav int tt_desigidx; /* abbreviation list index */ 110bc421551SDag-Erling Smørgrav bool tt_ttisstd; /* transition is std time */ 111bc421551SDag-Erling Smørgrav bool tt_ttisut; /* transition is UT */ 112bc421551SDag-Erling Smørgrav }; 113bc421551SDag-Erling Smørgrav 114bc421551SDag-Erling Smørgrav struct lsinfo { /* leap second information */ 115bc421551SDag-Erling Smørgrav time_t ls_trans; /* transition time */ 116bc421551SDag-Erling Smørgrav int_fast32_t ls_corr; /* correction to apply */ 117bc421551SDag-Erling Smørgrav }; 118bc421551SDag-Erling Smørgrav 119bc421551SDag-Erling Smørgrav /* This abbreviation means local time is unspecified. */ 120bc421551SDag-Erling Smørgrav static char const UNSPEC[] = "-00"; 121bc421551SDag-Erling Smørgrav 122bc421551SDag-Erling Smørgrav /* How many extra bytes are needed at the end of struct state's chars array. 123bc421551SDag-Erling Smørgrav This needs to be at least 1 for null termination in case the input 124bc421551SDag-Erling Smørgrav data isn't properly terminated, and it also needs to be big enough 125bc421551SDag-Erling Smørgrav for ttunspecified to work without crashing. */ 126bc421551SDag-Erling Smørgrav enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; 127bc421551SDag-Erling Smørgrav 128*a979394aSDag-Erling Smørgrav /* Limit to time zone abbreviation length in proleptic TZ strings. 12975411d15SDag-Erling Smørgrav This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */ 13075411d15SDag-Erling Smørgrav #ifndef TZNAME_MAXIMUM 13175411d15SDag-Erling Smørgrav # define TZNAME_MAXIMUM 255 13275411d15SDag-Erling Smørgrav #endif 133bc421551SDag-Erling Smørgrav 13446c59934SDag-Erling Smørgrav /* A representation of the contents of a TZif file. Ideally this 13546c59934SDag-Erling Smørgrav would have no size limits; the following sizes should suffice for 13646c59934SDag-Erling Smørgrav practical use. This struct should not be too large, as instances 13746c59934SDag-Erling Smørgrav are put on the stack and stacks are relatively small on some platforms. 13846c59934SDag-Erling Smørgrav See tzfile.h for more about the sizes. */ 139bc421551SDag-Erling Smørgrav struct state { 140bc421551SDag-Erling Smørgrav int leapcnt; 141bc421551SDag-Erling Smørgrav int timecnt; 142bc421551SDag-Erling Smørgrav int typecnt; 143bc421551SDag-Erling Smørgrav int charcnt; 144bc421551SDag-Erling Smørgrav bool goback; 145bc421551SDag-Erling Smørgrav bool goahead; 146bc421551SDag-Erling Smørgrav time_t ats[TZ_MAX_TIMES]; 147bc421551SDag-Erling Smørgrav unsigned char types[TZ_MAX_TIMES]; 148bc421551SDag-Erling Smørgrav struct ttinfo ttis[TZ_MAX_TYPES]; 149bc421551SDag-Erling Smørgrav char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"), 15075411d15SDag-Erling Smørgrav 2 * (TZNAME_MAXIMUM + 1))]; 151bc421551SDag-Erling Smørgrav struct lsinfo lsis[TZ_MAX_LEAPS]; 152bc421551SDag-Erling Smørgrav }; 153bc421551SDag-Erling Smørgrav 154bc421551SDag-Erling Smørgrav enum r_type { 155bc421551SDag-Erling Smørgrav JULIAN_DAY, /* Jn = Julian day */ 156bc421551SDag-Erling Smørgrav DAY_OF_YEAR, /* n = day of year */ 157bc421551SDag-Erling Smørgrav MONTH_NTH_DAY_OF_WEEK /* Mm.n.d = month, week, day of week */ 158bc421551SDag-Erling Smørgrav }; 159bc421551SDag-Erling Smørgrav 160bc421551SDag-Erling Smørgrav struct rule { 161bc421551SDag-Erling Smørgrav enum r_type r_type; /* type of rule */ 162bc421551SDag-Erling Smørgrav int r_day; /* day number of rule */ 163bc421551SDag-Erling Smørgrav int r_week; /* week number of rule */ 164bc421551SDag-Erling Smørgrav int r_mon; /* month number of rule */ 165bc421551SDag-Erling Smørgrav int_fast32_t r_time; /* transition time of rule */ 166bc421551SDag-Erling Smørgrav }; 167bc421551SDag-Erling Smørgrav 168bc421551SDag-Erling Smørgrav static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t, 169bc421551SDag-Erling Smørgrav struct tm *); 170bc421551SDag-Erling Smørgrav static bool increment_overflow(int *, int); 171bc421551SDag-Erling Smørgrav static bool increment_overflow_time(time_t *, int_fast32_t); 172bc421551SDag-Erling Smørgrav static int_fast32_t leapcorr(struct state const *, time_t); 173bc421551SDag-Erling Smørgrav static bool normalize_overflow32(int_fast32_t *, int *, int); 174bc421551SDag-Erling Smørgrav static struct tm *timesub(time_t const *, int_fast32_t, struct state const *, 175bc421551SDag-Erling Smørgrav struct tm *); 17646c59934SDag-Erling Smørgrav static bool tzparse(char const *, struct state *, struct state const *); 177bc421551SDag-Erling Smørgrav 178bc421551SDag-Erling Smørgrav #ifdef ALL_STATE 179bc421551SDag-Erling Smørgrav static struct state * lclptr; 180bc421551SDag-Erling Smørgrav static struct state * gmtptr; 181bc421551SDag-Erling Smørgrav #endif /* defined ALL_STATE */ 182bc421551SDag-Erling Smørgrav 183bc421551SDag-Erling Smørgrav #ifndef ALL_STATE 184bc421551SDag-Erling Smørgrav static struct state lclmem; 185bc421551SDag-Erling Smørgrav static struct state gmtmem; 186bc421551SDag-Erling Smørgrav static struct state *const lclptr = &lclmem; 187bc421551SDag-Erling Smørgrav static struct state *const gmtptr = &gmtmem; 188bc421551SDag-Erling Smørgrav #endif /* State Farm */ 189bc421551SDag-Erling Smørgrav 190bc421551SDag-Erling Smørgrav #ifndef TZ_STRLEN_MAX 191bc421551SDag-Erling Smørgrav # define TZ_STRLEN_MAX 255 192bc421551SDag-Erling Smørgrav #endif /* !defined TZ_STRLEN_MAX */ 193bc421551SDag-Erling Smørgrav 194bc421551SDag-Erling Smørgrav static char lcl_TZname[TZ_STRLEN_MAX + 1]; 195bc421551SDag-Erling Smørgrav static int lcl_is_set; 196bc421551SDag-Erling Smørgrav 197bc421551SDag-Erling Smørgrav static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; 198bc421551SDag-Erling Smørgrav static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT; 199bc421551SDag-Erling Smørgrav static pthread_key_t gmtime_key; 200bc421551SDag-Erling Smørgrav static int gmtime_key_error; 20175411d15SDag-Erling Smørgrav static pthread_once_t offtime_once = PTHREAD_ONCE_INIT; 20275411d15SDag-Erling Smørgrav static pthread_key_t offtime_key; 20375411d15SDag-Erling Smørgrav static int offtime_key_error; 204bc421551SDag-Erling Smørgrav static pthread_once_t localtime_once = PTHREAD_ONCE_INIT; 205bc421551SDag-Erling Smørgrav static pthread_key_t localtime_key; 206bc421551SDag-Erling Smørgrav static int localtime_key_error; 207bc421551SDag-Erling Smørgrav 208bc421551SDag-Erling Smørgrav /* 209bc421551SDag-Erling Smørgrav ** Section 4.12.3 of X3.159-1989 requires that 210bc421551SDag-Erling Smørgrav ** Except for the strftime function, these functions [asctime, 211bc421551SDag-Erling Smørgrav ** ctime, gmtime, localtime] return values in one of two static 212bc421551SDag-Erling Smørgrav ** objects: a broken-down time structure and an array of char. 213bc421551SDag-Erling Smørgrav ** Thanks to Paul Eggert for noting this. 21475411d15SDag-Erling Smørgrav ** 215*a979394aSDag-Erling Smørgrav ** Although this requirement was removed in C99 it is still present in POSIX. 216*a979394aSDag-Erling Smørgrav ** Follow the requirement if SUPPORT_C89, even though this is more likely to 217*a979394aSDag-Erling Smørgrav ** trigger latent bugs in programs. 218bc421551SDag-Erling Smørgrav */ 219bc421551SDag-Erling Smørgrav 22075411d15SDag-Erling Smørgrav #if SUPPORT_C89 221bc421551SDag-Erling Smørgrav static struct tm tm; 22275411d15SDag-Erling Smørgrav #endif 223bc421551SDag-Erling Smørgrav 224bc421551SDag-Erling Smørgrav #if 2 <= HAVE_TZNAME + TZ_TIME_T 225bc421551SDag-Erling Smørgrav char * tzname[2] = { 226bc421551SDag-Erling Smørgrav (char *) wildabbr, 227bc421551SDag-Erling Smørgrav (char *) wildabbr 228bc421551SDag-Erling Smørgrav }; 229bc421551SDag-Erling Smørgrav #endif 230bc421551SDag-Erling Smørgrav #if 2 <= USG_COMPAT + TZ_TIME_T 231bc421551SDag-Erling Smørgrav long timezone; 232bc421551SDag-Erling Smørgrav int daylight; 233bc421551SDag-Erling Smørgrav #endif 234bc421551SDag-Erling Smørgrav #if 2 <= ALTZONE + TZ_TIME_T 235bc421551SDag-Erling Smørgrav long altzone; 236bc421551SDag-Erling Smørgrav #endif 237bc421551SDag-Erling Smørgrav 238bc421551SDag-Erling Smørgrav /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */ 239bc421551SDag-Erling Smørgrav static void 240bc421551SDag-Erling Smørgrav init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx) 241bc421551SDag-Erling Smørgrav { 242bc421551SDag-Erling Smørgrav s->tt_utoff = utoff; 243bc421551SDag-Erling Smørgrav s->tt_isdst = isdst; 244bc421551SDag-Erling Smørgrav s->tt_desigidx = desigidx; 245bc421551SDag-Erling Smørgrav s->tt_ttisstd = false; 246bc421551SDag-Erling Smørgrav s->tt_ttisut = false; 247bc421551SDag-Erling Smørgrav } 248bc421551SDag-Erling Smørgrav 249bc421551SDag-Erling Smørgrav /* Return true if SP's time type I does not specify local time. */ 250bc421551SDag-Erling Smørgrav static bool 251bc421551SDag-Erling Smørgrav ttunspecified(struct state const *sp, int i) 252bc421551SDag-Erling Smørgrav { 253bc421551SDag-Erling Smørgrav char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx]; 254bc421551SDag-Erling Smørgrav /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA. */ 255bc421551SDag-Erling Smørgrav return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0; 256bc421551SDag-Erling Smørgrav } 257bc421551SDag-Erling Smørgrav 258bc421551SDag-Erling Smørgrav static int_fast32_t 259bc421551SDag-Erling Smørgrav detzcode(const char *const codep) 260bc421551SDag-Erling Smørgrav { 261bc421551SDag-Erling Smørgrav register int_fast32_t result; 262bc421551SDag-Erling Smørgrav register int i; 263bc421551SDag-Erling Smørgrav int_fast32_t one = 1; 264bc421551SDag-Erling Smørgrav int_fast32_t halfmaxval = one << (32 - 2); 265bc421551SDag-Erling Smørgrav int_fast32_t maxval = halfmaxval - 1 + halfmaxval; 266bc421551SDag-Erling Smørgrav int_fast32_t minval = -1 - maxval; 267bc421551SDag-Erling Smørgrav 268bc421551SDag-Erling Smørgrav result = codep[0] & 0x7f; 269bc421551SDag-Erling Smørgrav for (i = 1; i < 4; ++i) 270bc421551SDag-Erling Smørgrav result = (result << 8) | (codep[i] & 0xff); 271bc421551SDag-Erling Smørgrav 272bc421551SDag-Erling Smørgrav if (codep[0] & 0x80) { 273bc421551SDag-Erling Smørgrav /* Do two's-complement negation even on non-two's-complement machines. 274bc421551SDag-Erling Smørgrav If the result would be minval - 1, return minval. */ 275bc421551SDag-Erling Smørgrav result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0; 276bc421551SDag-Erling Smørgrav result += minval; 277bc421551SDag-Erling Smørgrav } 278bc421551SDag-Erling Smørgrav return result; 279bc421551SDag-Erling Smørgrav } 280bc421551SDag-Erling Smørgrav 281bc421551SDag-Erling Smørgrav static int_fast64_t 282bc421551SDag-Erling Smørgrav detzcode64(const char *const codep) 283bc421551SDag-Erling Smørgrav { 284bc421551SDag-Erling Smørgrav register int_fast64_t result; 285bc421551SDag-Erling Smørgrav register int i; 286bc421551SDag-Erling Smørgrav int_fast64_t one = 1; 287bc421551SDag-Erling Smørgrav int_fast64_t halfmaxval = one << (64 - 2); 288bc421551SDag-Erling Smørgrav int_fast64_t maxval = halfmaxval - 1 + halfmaxval; 289bc421551SDag-Erling Smørgrav int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval; 290bc421551SDag-Erling Smørgrav 291bc421551SDag-Erling Smørgrav result = codep[0] & 0x7f; 292bc421551SDag-Erling Smørgrav for (i = 1; i < 8; ++i) 293bc421551SDag-Erling Smørgrav result = (result << 8) | (codep[i] & 0xff); 294bc421551SDag-Erling Smørgrav 295bc421551SDag-Erling Smørgrav if (codep[0] & 0x80) { 296bc421551SDag-Erling Smørgrav /* Do two's-complement negation even on non-two's-complement machines. 297bc421551SDag-Erling Smørgrav If the result would be minval - 1, return minval. */ 298bc421551SDag-Erling Smørgrav result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0; 299bc421551SDag-Erling Smørgrav result += minval; 300bc421551SDag-Erling Smørgrav } 301bc421551SDag-Erling Smørgrav return result; 302bc421551SDag-Erling Smørgrav } 303bc421551SDag-Erling Smørgrav 304bc421551SDag-Erling Smørgrav static void 305bc421551SDag-Erling Smørgrav update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp) 306bc421551SDag-Erling Smørgrav { 307bc421551SDag-Erling Smørgrav #if HAVE_TZNAME 308bc421551SDag-Erling Smørgrav tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx]; 309bc421551SDag-Erling Smørgrav #endif 310bc421551SDag-Erling Smørgrav #if USG_COMPAT 311bc421551SDag-Erling Smørgrav if (!ttisp->tt_isdst) 312bc421551SDag-Erling Smørgrav timezone = - ttisp->tt_utoff; 313bc421551SDag-Erling Smørgrav #endif 314bc421551SDag-Erling Smørgrav #if ALTZONE 315bc421551SDag-Erling Smørgrav if (ttisp->tt_isdst) 316bc421551SDag-Erling Smørgrav altzone = - ttisp->tt_utoff; 317bc421551SDag-Erling Smørgrav #endif 318bc421551SDag-Erling Smørgrav } 319bc421551SDag-Erling Smørgrav 320bc421551SDag-Erling Smørgrav /* If STDDST_MASK indicates that SP's TYPE provides useful info, 321bc421551SDag-Erling Smørgrav update tzname, timezone, and/or altzone and return STDDST_MASK, 322bc421551SDag-Erling Smørgrav diminished by the provided info if it is a specified local time. 323bc421551SDag-Erling Smørgrav Otherwise, return STDDST_MASK. See settzname for STDDST_MASK. */ 324bc421551SDag-Erling Smørgrav static int 325bc421551SDag-Erling Smørgrav may_update_tzname_etc(int stddst_mask, struct state *sp, int type) 326bc421551SDag-Erling Smørgrav { 327bc421551SDag-Erling Smørgrav struct ttinfo *ttisp = &sp->ttis[type]; 328bc421551SDag-Erling Smørgrav int this_bit = 1 << ttisp->tt_isdst; 329bc421551SDag-Erling Smørgrav if (stddst_mask & this_bit) { 330bc421551SDag-Erling Smørgrav update_tzname_etc(sp, ttisp); 331bc421551SDag-Erling Smørgrav if (!ttunspecified(sp, type)) 332bc421551SDag-Erling Smørgrav return stddst_mask & ~this_bit; 333bc421551SDag-Erling Smørgrav } 334bc421551SDag-Erling Smørgrav return stddst_mask; 335bc421551SDag-Erling Smørgrav } 336bc421551SDag-Erling Smørgrav 337bc421551SDag-Erling Smørgrav static void 338bc421551SDag-Erling Smørgrav settzname(void) 339bc421551SDag-Erling Smørgrav { 340bc421551SDag-Erling Smørgrav register struct state * const sp = lclptr; 341bc421551SDag-Erling Smørgrav register int i; 342bc421551SDag-Erling Smørgrav 343bc421551SDag-Erling Smørgrav /* If STDDST_MASK & 1 we need info about a standard time. 344bc421551SDag-Erling Smørgrav If STDDST_MASK & 2 we need info about a daylight saving time. 345bc421551SDag-Erling Smørgrav When STDDST_MASK becomes zero we can stop looking. */ 346bc421551SDag-Erling Smørgrav int stddst_mask = 0; 347bc421551SDag-Erling Smørgrav 348bc421551SDag-Erling Smørgrav #if HAVE_TZNAME 349bc421551SDag-Erling Smørgrav tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc); 350bc421551SDag-Erling Smørgrav stddst_mask = 3; 351bc421551SDag-Erling Smørgrav #endif 352bc421551SDag-Erling Smørgrav #if USG_COMPAT 353bc421551SDag-Erling Smørgrav timezone = 0; 354bc421551SDag-Erling Smørgrav stddst_mask = 3; 355bc421551SDag-Erling Smørgrav #endif 356bc421551SDag-Erling Smørgrav #if ALTZONE 357bc421551SDag-Erling Smørgrav altzone = 0; 358bc421551SDag-Erling Smørgrav stddst_mask |= 2; 359bc421551SDag-Erling Smørgrav #endif 360bc421551SDag-Erling Smørgrav /* 361bc421551SDag-Erling Smørgrav ** And to get the latest time zone abbreviations into tzname. . . 362bc421551SDag-Erling Smørgrav */ 363bc421551SDag-Erling Smørgrav if (sp) { 364bc421551SDag-Erling Smørgrav for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--) 365bc421551SDag-Erling Smørgrav stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]); 366bc421551SDag-Erling Smørgrav for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--) 367bc421551SDag-Erling Smørgrav stddst_mask = may_update_tzname_etc(stddst_mask, sp, i); 368bc421551SDag-Erling Smørgrav } 369bc421551SDag-Erling Smørgrav #if USG_COMPAT 370bc421551SDag-Erling Smørgrav daylight = stddst_mask >> 1 ^ 1; 371bc421551SDag-Erling Smørgrav #endif 372bc421551SDag-Erling Smørgrav } 373bc421551SDag-Erling Smørgrav 37475411d15SDag-Erling Smørgrav /* Replace bogus characters in time zone abbreviations. 37575411d15SDag-Erling Smørgrav Return 0 on success, an errno value if a time zone abbreviation is 37675411d15SDag-Erling Smørgrav too long. */ 37775411d15SDag-Erling Smørgrav static int 378bc421551SDag-Erling Smørgrav scrub_abbrs(struct state *sp) 379bc421551SDag-Erling Smørgrav { 380bc421551SDag-Erling Smørgrav int i; 38175411d15SDag-Erling Smørgrav 38275411d15SDag-Erling Smørgrav /* Reject overlong abbreviations. */ 38375411d15SDag-Erling Smørgrav for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) { 38475411d15SDag-Erling Smørgrav int len = strlen(&sp->chars[i]); 38575411d15SDag-Erling Smørgrav if (TZNAME_MAXIMUM < len) 38675411d15SDag-Erling Smørgrav return EOVERFLOW; 38775411d15SDag-Erling Smørgrav i += len + 1; 38875411d15SDag-Erling Smørgrav } 38975411d15SDag-Erling Smørgrav 39075411d15SDag-Erling Smørgrav /* Replace bogus characters. */ 391bc421551SDag-Erling Smørgrav for (i = 0; i < sp->charcnt; ++i) 392bc421551SDag-Erling Smørgrav if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL) 393bc421551SDag-Erling Smørgrav sp->chars[i] = TZ_ABBR_ERR_CHAR; 394bc421551SDag-Erling Smørgrav 39575411d15SDag-Erling Smørgrav return 0; 396bc421551SDag-Erling Smørgrav } 397bc421551SDag-Erling Smørgrav 398bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES 399bc421551SDag-Erling Smørgrav /* 400bc421551SDag-Erling Smørgrav * Determine if there's a change in the timezone since the last time we checked. 401bc421551SDag-Erling Smørgrav * Returns: -1 on error 402bc421551SDag-Erling Smørgrav * 0 if the timezone has not changed 403bc421551SDag-Erling Smørgrav * 1 if the timezone has changed 404bc421551SDag-Erling Smørgrav */ 405bc421551SDag-Erling Smørgrav static int 406bc421551SDag-Erling Smørgrav change_in_tz(const char *name) 407bc421551SDag-Erling Smørgrav { 408bc421551SDag-Erling Smørgrav static char old_name[PATH_MAX]; 409bc421551SDag-Erling Smørgrav static struct stat old_sb; 410bc421551SDag-Erling Smørgrav struct stat sb; 411bc421551SDag-Erling Smørgrav int error; 412bc421551SDag-Erling Smørgrav 413bc421551SDag-Erling Smørgrav error = stat(name, &sb); 414bc421551SDag-Erling Smørgrav if (error != 0) 415bc421551SDag-Erling Smørgrav return -1; 416bc421551SDag-Erling Smørgrav 417bc421551SDag-Erling Smørgrav if (strcmp(name, old_name) != 0) { 418bc421551SDag-Erling Smørgrav strlcpy(old_name, name, sizeof(old_name)); 419bc421551SDag-Erling Smørgrav old_sb = sb; 420bc421551SDag-Erling Smørgrav return 1; 421bc421551SDag-Erling Smørgrav } 422bc421551SDag-Erling Smørgrav 423bc421551SDag-Erling Smørgrav if (sb.st_dev != old_sb.st_dev || 424bc421551SDag-Erling Smørgrav sb.st_ino != old_sb.st_ino || 425bc421551SDag-Erling Smørgrav sb.st_ctime != old_sb.st_ctime || 426bc421551SDag-Erling Smørgrav sb.st_mtime != old_sb.st_mtime) { 427bc421551SDag-Erling Smørgrav old_sb = sb; 428bc421551SDag-Erling Smørgrav return 1; 429bc421551SDag-Erling Smørgrav } 430bc421551SDag-Erling Smørgrav 431bc421551SDag-Erling Smørgrav return 0; 432bc421551SDag-Erling Smørgrav } 433bc421551SDag-Erling Smørgrav #else /* !DETECT_TZ_CHANGES */ 434bc421551SDag-Erling Smørgrav #define change_in_tz(X) 1 435bc421551SDag-Erling Smørgrav #endif /* !DETECT_TZ_CHANGES */ 436bc421551SDag-Erling Smørgrav 437bc421551SDag-Erling Smørgrav /* Input buffer for data read from a compiled tz file. */ 438bc421551SDag-Erling Smørgrav union input_buffer { 439bc421551SDag-Erling Smørgrav /* The first part of the buffer, interpreted as a header. */ 440bc421551SDag-Erling Smørgrav struct tzhead tzhead; 441bc421551SDag-Erling Smørgrav 44246c59934SDag-Erling Smørgrav /* The entire buffer. Ideally this would have no size limits; 44346c59934SDag-Erling Smørgrav the following should suffice for practical use. */ 444bc421551SDag-Erling Smørgrav char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state) 445bc421551SDag-Erling Smørgrav + 4 * TZ_MAX_TIMES]; 446bc421551SDag-Erling Smørgrav }; 447bc421551SDag-Erling Smørgrav 448bc421551SDag-Erling Smørgrav /* TZDIR with a trailing '/' rather than a trailing '\0'. */ 449bc421551SDag-Erling Smørgrav static char const tzdirslash[sizeof TZDIR] = TZDIR "/"; 450bc421551SDag-Erling Smørgrav 451bc421551SDag-Erling Smørgrav /* Local storage needed for 'tzloadbody'. */ 452bc421551SDag-Erling Smørgrav union local_storage { 453bc421551SDag-Erling Smørgrav /* The results of analyzing the file's contents after it is opened. */ 454bc421551SDag-Erling Smørgrav struct file_analysis { 455bc421551SDag-Erling Smørgrav /* The input buffer. */ 456bc421551SDag-Erling Smørgrav union input_buffer u; 457bc421551SDag-Erling Smørgrav 458bc421551SDag-Erling Smørgrav /* A temporary state used for parsing a TZ string in the file. */ 459bc421551SDag-Erling Smørgrav struct state st; 460bc421551SDag-Erling Smørgrav } u; 461bc421551SDag-Erling Smørgrav 46246c59934SDag-Erling Smørgrav /* The name of the file to be opened. Ideally this would have no 46346c59934SDag-Erling Smørgrav size limits, to support arbitrarily long Zone names. 46446c59934SDag-Erling Smørgrav Limiting Zone names to 1024 bytes should suffice for practical use. 46546c59934SDag-Erling Smørgrav However, there is no need for this to be smaller than struct 46646c59934SDag-Erling Smørgrav file_analysis as that struct is allocated anyway, as the other 46746c59934SDag-Erling Smørgrav union member. */ 468bc421551SDag-Erling Smørgrav char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)]; 469bc421551SDag-Erling Smørgrav }; 470bc421551SDag-Erling Smørgrav 471bc421551SDag-Erling Smørgrav /* Load tz data from the file named NAME into *SP. Read extended 472bc421551SDag-Erling Smørgrav format if DOEXTEND. Use *LSP for temporary storage. Return 0 on 473bc421551SDag-Erling Smørgrav success, an errno value on failure. */ 474bc421551SDag-Erling Smørgrav static int 475bc421551SDag-Erling Smørgrav tzloadbody(char const *name, struct state *sp, bool doextend, 476bc421551SDag-Erling Smørgrav union local_storage *lsp) 477bc421551SDag-Erling Smørgrav { 478bc421551SDag-Erling Smørgrav register int i; 479bc421551SDag-Erling Smørgrav register int fid; 480bc421551SDag-Erling Smørgrav register int stored; 481bc421551SDag-Erling Smørgrav register ssize_t nread; 482bc421551SDag-Erling Smørgrav register union input_buffer *up = &lsp->u.u; 483bc421551SDag-Erling Smørgrav register int tzheadsize = sizeof(struct tzhead); 484bc421551SDag-Erling Smørgrav 485bc421551SDag-Erling Smørgrav sp->goback = sp->goahead = false; 486bc421551SDag-Erling Smørgrav 487bc421551SDag-Erling Smørgrav if (! name) { 488bc421551SDag-Erling Smørgrav name = TZDEFAULT; 489bc421551SDag-Erling Smørgrav if (! name) 490bc421551SDag-Erling Smørgrav return EINVAL; 491bc421551SDag-Erling Smørgrav } 492bc421551SDag-Erling Smørgrav 493bc421551SDag-Erling Smørgrav if (name[0] == ':') 494bc421551SDag-Erling Smørgrav ++name; 4953e2e5eebSDag-Erling Smørgrav if (name[0] != '/') { 496bc421551SDag-Erling Smørgrav if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name)) 497bc421551SDag-Erling Smørgrav return ENAMETOOLONG; 498bc421551SDag-Erling Smørgrav 499bc421551SDag-Erling Smørgrav /* Create a string "TZDIR/NAME". Using sprintf here 500bc421551SDag-Erling Smørgrav would pull in stdio (and would fail if the 501bc421551SDag-Erling Smørgrav resulting string length exceeded INT_MAX!). */ 502bc421551SDag-Erling Smørgrav memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash); 503bc421551SDag-Erling Smørgrav strcpy(lsp->fullname + sizeof tzdirslash, name); 504bc421551SDag-Erling Smørgrav 505bc421551SDag-Erling Smørgrav name = lsp->fullname; 506bc421551SDag-Erling Smørgrav } 507bc421551SDag-Erling Smørgrav if (doextend) { 508bc421551SDag-Erling Smørgrav /* 509bc421551SDag-Erling Smørgrav * Detect if the timezone file has changed. Check 510bc421551SDag-Erling Smørgrav * 'doextend' to ignore TZDEFRULES; the change_in_tz() 511bc421551SDag-Erling Smørgrav * function can only keep state for a single file. 512bc421551SDag-Erling Smørgrav */ 513bc421551SDag-Erling Smørgrav int ret = change_in_tz(name); 514bc421551SDag-Erling Smørgrav if (ret <= 0) { 515bc421551SDag-Erling Smørgrav /* 516bc421551SDag-Erling Smørgrav * Returns an errno value if there was an error, 517bc421551SDag-Erling Smørgrav * and 0 if the timezone had not changed. 518bc421551SDag-Erling Smørgrav */ 519bc421551SDag-Erling Smørgrav return errno; 520bc421551SDag-Erling Smørgrav } 521bc421551SDag-Erling Smørgrav } 522bc421551SDag-Erling Smørgrav fid = _open(name, O_RDONLY | O_BINARY); 523bc421551SDag-Erling Smørgrav if (fid < 0) 524bc421551SDag-Erling Smørgrav return errno; 525bc421551SDag-Erling Smørgrav 526bc421551SDag-Erling Smørgrav nread = _read(fid, up->buf, sizeof up->buf); 527bc421551SDag-Erling Smørgrav if (nread < tzheadsize) { 528bc421551SDag-Erling Smørgrav int err = nread < 0 ? errno : EINVAL; 529bc421551SDag-Erling Smørgrav _close(fid); 530bc421551SDag-Erling Smørgrav return err; 531bc421551SDag-Erling Smørgrav } 532bc421551SDag-Erling Smørgrav if (_close(fid) < 0) 533bc421551SDag-Erling Smørgrav return errno; 534bc421551SDag-Erling Smørgrav for (stored = 4; stored <= 8; stored *= 2) { 535bc421551SDag-Erling Smørgrav char version = up->tzhead.tzh_version[0]; 536bc421551SDag-Erling Smørgrav bool skip_datablock = stored == 4 && version; 537bc421551SDag-Erling Smørgrav int_fast32_t datablock_size; 538bc421551SDag-Erling Smørgrav int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt); 539bc421551SDag-Erling Smørgrav int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt); 540bc421551SDag-Erling Smørgrav int_fast64_t prevtr = -1; 541bc421551SDag-Erling Smørgrav int_fast32_t prevcorr; 542bc421551SDag-Erling Smørgrav int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt); 543bc421551SDag-Erling Smørgrav int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt); 544bc421551SDag-Erling Smørgrav int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt); 545bc421551SDag-Erling Smørgrav int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt); 546bc421551SDag-Erling Smørgrav char const *p = up->buf + tzheadsize; 547bc421551SDag-Erling Smørgrav /* Although tzfile(5) currently requires typecnt to be nonzero, 548bc421551SDag-Erling Smørgrav support future formats that may allow zero typecnt 549bc421551SDag-Erling Smørgrav in files that have a TZ string and no transitions. */ 550bc421551SDag-Erling Smørgrav if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS 551bc421551SDag-Erling Smørgrav && 0 <= typecnt && typecnt < TZ_MAX_TYPES 552bc421551SDag-Erling Smørgrav && 0 <= timecnt && timecnt < TZ_MAX_TIMES 553bc421551SDag-Erling Smørgrav && 0 <= charcnt && charcnt < TZ_MAX_CHARS 554bc421551SDag-Erling Smørgrav && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES 555bc421551SDag-Erling Smørgrav && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES)) 556bc421551SDag-Erling Smørgrav return EINVAL; 557bc421551SDag-Erling Smørgrav datablock_size 558bc421551SDag-Erling Smørgrav = (timecnt * stored /* ats */ 559bc421551SDag-Erling Smørgrav + timecnt /* types */ 560bc421551SDag-Erling Smørgrav + typecnt * 6 /* ttinfos */ 561bc421551SDag-Erling Smørgrav + charcnt /* chars */ 562bc421551SDag-Erling Smørgrav + leapcnt * (stored + 4) /* lsinfos */ 563bc421551SDag-Erling Smørgrav + ttisstdcnt /* ttisstds */ 564bc421551SDag-Erling Smørgrav + ttisutcnt); /* ttisuts */ 565bc421551SDag-Erling Smørgrav if (nread < tzheadsize + datablock_size) 566bc421551SDag-Erling Smørgrav return EINVAL; 567bc421551SDag-Erling Smørgrav if (skip_datablock) 568bc421551SDag-Erling Smørgrav p += datablock_size; 569bc421551SDag-Erling Smørgrav else { 570bc421551SDag-Erling Smørgrav if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0) 571bc421551SDag-Erling Smørgrav && (ttisutcnt == typecnt || ttisutcnt == 0))) 572bc421551SDag-Erling Smørgrav return EINVAL; 573bc421551SDag-Erling Smørgrav 574bc421551SDag-Erling Smørgrav sp->leapcnt = leapcnt; 575bc421551SDag-Erling Smørgrav sp->timecnt = timecnt; 576bc421551SDag-Erling Smørgrav sp->typecnt = typecnt; 577bc421551SDag-Erling Smørgrav sp->charcnt = charcnt; 578bc421551SDag-Erling Smørgrav 579bc421551SDag-Erling Smørgrav /* Read transitions, discarding those out of time_t range. 580bc421551SDag-Erling Smørgrav But pretend the last transition before TIME_T_MIN 581bc421551SDag-Erling Smørgrav occurred at TIME_T_MIN. */ 582bc421551SDag-Erling Smørgrav timecnt = 0; 583bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) { 584bc421551SDag-Erling Smørgrav int_fast64_t at 585bc421551SDag-Erling Smørgrav = stored == 4 ? detzcode(p) : detzcode64(p); 586bc421551SDag-Erling Smørgrav sp->types[i] = at <= TIME_T_MAX; 587bc421551SDag-Erling Smørgrav if (sp->types[i]) { 588bc421551SDag-Erling Smørgrav time_t attime 589bc421551SDag-Erling Smørgrav = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0) 590bc421551SDag-Erling Smørgrav ? TIME_T_MIN : at); 591bc421551SDag-Erling Smørgrav if (timecnt && attime <= sp->ats[timecnt - 1]) { 592bc421551SDag-Erling Smørgrav if (attime < sp->ats[timecnt - 1]) 593bc421551SDag-Erling Smørgrav return EINVAL; 594bc421551SDag-Erling Smørgrav sp->types[i - 1] = 0; 595bc421551SDag-Erling Smørgrav timecnt--; 596bc421551SDag-Erling Smørgrav } 597bc421551SDag-Erling Smørgrav sp->ats[timecnt++] = attime; 598bc421551SDag-Erling Smørgrav } 599bc421551SDag-Erling Smørgrav p += stored; 600bc421551SDag-Erling Smørgrav } 601bc421551SDag-Erling Smørgrav 602bc421551SDag-Erling Smørgrav timecnt = 0; 603bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) { 604bc421551SDag-Erling Smørgrav unsigned char typ = *p++; 605bc421551SDag-Erling Smørgrav if (sp->typecnt <= typ) 606bc421551SDag-Erling Smørgrav return EINVAL; 607bc421551SDag-Erling Smørgrav if (sp->types[i]) 608bc421551SDag-Erling Smørgrav sp->types[timecnt++] = typ; 609bc421551SDag-Erling Smørgrav } 610bc421551SDag-Erling Smørgrav sp->timecnt = timecnt; 611bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i) { 612bc421551SDag-Erling Smørgrav register struct ttinfo * ttisp; 613bc421551SDag-Erling Smørgrav unsigned char isdst, desigidx; 614bc421551SDag-Erling Smørgrav 615bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i]; 616bc421551SDag-Erling Smørgrav ttisp->tt_utoff = detzcode(p); 617bc421551SDag-Erling Smørgrav p += 4; 618bc421551SDag-Erling Smørgrav isdst = *p++; 619bc421551SDag-Erling Smørgrav if (! (isdst < 2)) 620bc421551SDag-Erling Smørgrav return EINVAL; 621bc421551SDag-Erling Smørgrav ttisp->tt_isdst = isdst; 622bc421551SDag-Erling Smørgrav desigidx = *p++; 623bc421551SDag-Erling Smørgrav if (! (desigidx < sp->charcnt)) 624bc421551SDag-Erling Smørgrav return EINVAL; 625bc421551SDag-Erling Smørgrav ttisp->tt_desigidx = desigidx; 626bc421551SDag-Erling Smørgrav } 627bc421551SDag-Erling Smørgrav for (i = 0; i < sp->charcnt; ++i) 628bc421551SDag-Erling Smørgrav sp->chars[i] = *p++; 629bc421551SDag-Erling Smørgrav /* Ensure '\0'-terminated, and make it safe to call 630bc421551SDag-Erling Smørgrav ttunspecified later. */ 631bc421551SDag-Erling Smørgrav memset(&sp->chars[i], 0, CHARS_EXTRA); 632bc421551SDag-Erling Smørgrav 633bc421551SDag-Erling Smørgrav /* Read leap seconds, discarding those out of time_t range. */ 634bc421551SDag-Erling Smørgrav leapcnt = 0; 635bc421551SDag-Erling Smørgrav for (i = 0; i < sp->leapcnt; ++i) { 636bc421551SDag-Erling Smørgrav int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p); 637bc421551SDag-Erling Smørgrav int_fast32_t corr = detzcode(p + stored); 638bc421551SDag-Erling Smørgrav p += stored + 4; 639bc421551SDag-Erling Smørgrav 640bc421551SDag-Erling Smørgrav /* Leap seconds cannot occur before the Epoch, 641bc421551SDag-Erling Smørgrav or out of order. */ 642bc421551SDag-Erling Smørgrav if (tr <= prevtr) 643bc421551SDag-Erling Smørgrav return EINVAL; 644bc421551SDag-Erling Smørgrav 645bc421551SDag-Erling Smørgrav /* To avoid other botches in this code, each leap second's 646bc421551SDag-Erling Smørgrav correction must differ from the previous one's by 1 647bc421551SDag-Erling Smørgrav second or less, except that the first correction can be 648bc421551SDag-Erling Smørgrav any value; these requirements are more generous than 649bc421551SDag-Erling Smørgrav RFC 8536, to allow future RFC extensions. */ 650bc421551SDag-Erling Smørgrav if (! (i == 0 651bc421551SDag-Erling Smørgrav || (prevcorr < corr 652bc421551SDag-Erling Smørgrav ? corr == prevcorr + 1 653bc421551SDag-Erling Smørgrav : (corr == prevcorr 654bc421551SDag-Erling Smørgrav || corr == prevcorr - 1)))) 655bc421551SDag-Erling Smørgrav return EINVAL; 656bc421551SDag-Erling Smørgrav prevtr = tr; 657bc421551SDag-Erling Smørgrav prevcorr = corr; 658bc421551SDag-Erling Smørgrav 659bc421551SDag-Erling Smørgrav if (tr <= TIME_T_MAX) { 660bc421551SDag-Erling Smørgrav sp->lsis[leapcnt].ls_trans = tr; 661bc421551SDag-Erling Smørgrav sp->lsis[leapcnt].ls_corr = corr; 662bc421551SDag-Erling Smørgrav leapcnt++; 663bc421551SDag-Erling Smørgrav } 664bc421551SDag-Erling Smørgrav } 665bc421551SDag-Erling Smørgrav sp->leapcnt = leapcnt; 666bc421551SDag-Erling Smørgrav 667bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i) { 668bc421551SDag-Erling Smørgrav register struct ttinfo * ttisp; 669bc421551SDag-Erling Smørgrav 670bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i]; 671bc421551SDag-Erling Smørgrav if (ttisstdcnt == 0) 672bc421551SDag-Erling Smørgrav ttisp->tt_ttisstd = false; 673bc421551SDag-Erling Smørgrav else { 674bc421551SDag-Erling Smørgrav if (*p != true && *p != false) 675bc421551SDag-Erling Smørgrav return EINVAL; 676bc421551SDag-Erling Smørgrav ttisp->tt_ttisstd = *p++; 677bc421551SDag-Erling Smørgrav } 678bc421551SDag-Erling Smørgrav } 679bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i) { 680bc421551SDag-Erling Smørgrav register struct ttinfo * ttisp; 681bc421551SDag-Erling Smørgrav 682bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i]; 683bc421551SDag-Erling Smørgrav if (ttisutcnt == 0) 684bc421551SDag-Erling Smørgrav ttisp->tt_ttisut = false; 685bc421551SDag-Erling Smørgrav else { 686bc421551SDag-Erling Smørgrav if (*p != true && *p != false) 687bc421551SDag-Erling Smørgrav return EINVAL; 688bc421551SDag-Erling Smørgrav ttisp->tt_ttisut = *p++; 689bc421551SDag-Erling Smørgrav } 690bc421551SDag-Erling Smørgrav } 691bc421551SDag-Erling Smørgrav } 692bc421551SDag-Erling Smørgrav 693bc421551SDag-Erling Smørgrav nread -= p - up->buf; 694bc421551SDag-Erling Smørgrav memmove(up->buf, p, nread); 695bc421551SDag-Erling Smørgrav 696bc421551SDag-Erling Smørgrav /* If this is an old file, we're done. */ 697bc421551SDag-Erling Smørgrav if (!version) 698bc421551SDag-Erling Smørgrav break; 699bc421551SDag-Erling Smørgrav } 700bc421551SDag-Erling Smørgrav if (doextend && nread > 2 && 701bc421551SDag-Erling Smørgrav up->buf[0] == '\n' && up->buf[nread - 1] == '\n' && 702bc421551SDag-Erling Smørgrav sp->typecnt + 2 <= TZ_MAX_TYPES) { 703bc421551SDag-Erling Smørgrav struct state *ts = &lsp->u.st; 704bc421551SDag-Erling Smørgrav 705bc421551SDag-Erling Smørgrav up->buf[nread - 1] = '\0'; 706bc421551SDag-Erling Smørgrav if (tzparse(&up->buf[1], ts, sp)) { 707bc421551SDag-Erling Smørgrav 708bc421551SDag-Erling Smørgrav /* Attempt to reuse existing abbreviations. 709bc421551SDag-Erling Smørgrav Without this, America/Anchorage would be right on 710bc421551SDag-Erling Smørgrav the edge after 2037 when TZ_MAX_CHARS is 50, as 711bc421551SDag-Erling Smørgrav sp->charcnt equals 40 (for LMT AST AWT APT AHST 712bc421551SDag-Erling Smørgrav AHDT YST AKDT AKST) and ts->charcnt equals 10 713bc421551SDag-Erling Smørgrav (for AKST AKDT). Reusing means sp->charcnt can 714bc421551SDag-Erling Smørgrav stay 40 in this example. */ 715bc421551SDag-Erling Smørgrav int gotabbr = 0; 716bc421551SDag-Erling Smørgrav int charcnt = sp->charcnt; 717bc421551SDag-Erling Smørgrav for (i = 0; i < ts->typecnt; i++) { 718bc421551SDag-Erling Smørgrav char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx; 719bc421551SDag-Erling Smørgrav int j; 720bc421551SDag-Erling Smørgrav for (j = 0; j < charcnt; j++) 721bc421551SDag-Erling Smørgrav if (strcmp(sp->chars + j, tsabbr) == 0) { 722bc421551SDag-Erling Smørgrav ts->ttis[i].tt_desigidx = j; 723bc421551SDag-Erling Smørgrav gotabbr++; 724bc421551SDag-Erling Smørgrav break; 725bc421551SDag-Erling Smørgrav } 726bc421551SDag-Erling Smørgrav if (! (j < charcnt)) { 727bc421551SDag-Erling Smørgrav int tsabbrlen = strlen(tsabbr); 728bc421551SDag-Erling Smørgrav if (j + tsabbrlen < TZ_MAX_CHARS) { 729bc421551SDag-Erling Smørgrav strcpy(sp->chars + j, tsabbr); 730bc421551SDag-Erling Smørgrav charcnt = j + tsabbrlen + 1; 731bc421551SDag-Erling Smørgrav ts->ttis[i].tt_desigidx = j; 732bc421551SDag-Erling Smørgrav gotabbr++; 733bc421551SDag-Erling Smørgrav } 734bc421551SDag-Erling Smørgrav } 735bc421551SDag-Erling Smørgrav } 736bc421551SDag-Erling Smørgrav if (gotabbr == ts->typecnt) { 737bc421551SDag-Erling Smørgrav sp->charcnt = charcnt; 738bc421551SDag-Erling Smørgrav 739bc421551SDag-Erling Smørgrav /* Ignore any trailing, no-op transitions generated 740bc421551SDag-Erling Smørgrav by zic as they don't help here and can run afoul 741bc421551SDag-Erling Smørgrav of bugs in zic 2016j or earlier. */ 742bc421551SDag-Erling Smørgrav while (1 < sp->timecnt 743bc421551SDag-Erling Smørgrav && (sp->types[sp->timecnt - 1] 744bc421551SDag-Erling Smørgrav == sp->types[sp->timecnt - 2])) 745bc421551SDag-Erling Smørgrav sp->timecnt--; 746bc421551SDag-Erling Smørgrav 74746c59934SDag-Erling Smørgrav sp->goahead = ts->goahead; 74846c59934SDag-Erling Smørgrav 74946c59934SDag-Erling Smørgrav for (i = 0; i < ts->timecnt; i++) { 750bc421551SDag-Erling Smørgrav time_t t = ts->ats[i]; 751bc421551SDag-Erling Smørgrav if (increment_overflow_time(&t, leapcorr(sp, t)) 752bc421551SDag-Erling Smørgrav || (0 < sp->timecnt 753bc421551SDag-Erling Smørgrav && t <= sp->ats[sp->timecnt - 1])) 754bc421551SDag-Erling Smørgrav continue; 75546c59934SDag-Erling Smørgrav if (TZ_MAX_TIMES <= sp->timecnt) { 75646c59934SDag-Erling Smørgrav sp->goahead = false; 75746c59934SDag-Erling Smørgrav break; 75846c59934SDag-Erling Smørgrav } 759bc421551SDag-Erling Smørgrav sp->ats[sp->timecnt] = t; 760bc421551SDag-Erling Smørgrav sp->types[sp->timecnt] = (sp->typecnt 761bc421551SDag-Erling Smørgrav + ts->types[i]); 762bc421551SDag-Erling Smørgrav sp->timecnt++; 763bc421551SDag-Erling Smørgrav } 764bc421551SDag-Erling Smørgrav for (i = 0; i < ts->typecnt; i++) 765bc421551SDag-Erling Smørgrav sp->ttis[sp->typecnt++] = ts->ttis[i]; 766bc421551SDag-Erling Smørgrav } 767bc421551SDag-Erling Smørgrav } 768bc421551SDag-Erling Smørgrav } 769bc421551SDag-Erling Smørgrav if (sp->typecnt == 0) 770bc421551SDag-Erling Smørgrav return EINVAL; 771bc421551SDag-Erling Smørgrav 772bc421551SDag-Erling Smørgrav return 0; 773bc421551SDag-Erling Smørgrav } 774bc421551SDag-Erling Smørgrav 775bc421551SDag-Erling Smørgrav /* Load tz data from the file named NAME into *SP. Read extended 776bc421551SDag-Erling Smørgrav format if DOEXTEND. Return 0 on success, an errno value on failure. */ 777bc421551SDag-Erling Smørgrav static int 778bc421551SDag-Erling Smørgrav tzload(char const *name, struct state *sp, bool doextend) 779bc421551SDag-Erling Smørgrav { 780bc421551SDag-Erling Smørgrav #ifdef ALL_STATE 781bc421551SDag-Erling Smørgrav union local_storage *lsp = malloc(sizeof *lsp); 782bc421551SDag-Erling Smørgrav if (!lsp) { 783bc421551SDag-Erling Smørgrav return HAVE_MALLOC_ERRNO ? errno : ENOMEM; 784bc421551SDag-Erling Smørgrav } else { 785bc421551SDag-Erling Smørgrav int err = tzloadbody(name, sp, doextend, lsp); 786bc421551SDag-Erling Smørgrav free(lsp); 787bc421551SDag-Erling Smørgrav return err; 788bc421551SDag-Erling Smørgrav } 789bc421551SDag-Erling Smørgrav #else 790bc421551SDag-Erling Smørgrav union local_storage ls; 791bc421551SDag-Erling Smørgrav return tzloadbody(name, sp, doextend, &ls); 792bc421551SDag-Erling Smørgrav #endif 793bc421551SDag-Erling Smørgrav } 794bc421551SDag-Erling Smørgrav 795bc421551SDag-Erling Smørgrav static const int mon_lengths[2][MONSPERYEAR] = { 796bc421551SDag-Erling Smørgrav { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 797bc421551SDag-Erling Smørgrav { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 798bc421551SDag-Erling Smørgrav }; 799bc421551SDag-Erling Smørgrav 800bc421551SDag-Erling Smørgrav static const int year_lengths[2] = { 801bc421551SDag-Erling Smørgrav DAYSPERNYEAR, DAYSPERLYEAR 802bc421551SDag-Erling Smørgrav }; 803bc421551SDag-Erling Smørgrav 804bc421551SDag-Erling Smørgrav /* Is C an ASCII digit? */ 805bc421551SDag-Erling Smørgrav static bool 806bc421551SDag-Erling Smørgrav is_digit(char c) 807bc421551SDag-Erling Smørgrav { 808bc421551SDag-Erling Smørgrav return '0' <= c && c <= '9'; 809bc421551SDag-Erling Smørgrav } 810bc421551SDag-Erling Smørgrav 811bc421551SDag-Erling Smørgrav /* 812bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, scan until a character that is not 813bc421551SDag-Erling Smørgrav ** a valid character in a time zone abbreviation is found. 814bc421551SDag-Erling Smørgrav ** Return a pointer to that character. 815bc421551SDag-Erling Smørgrav */ 816bc421551SDag-Erling Smørgrav 817*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static const char * 818bc421551SDag-Erling Smørgrav getzname(register const char *strp) 819bc421551SDag-Erling Smørgrav { 820bc421551SDag-Erling Smørgrav register char c; 821bc421551SDag-Erling Smørgrav 822bc421551SDag-Erling Smørgrav while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && 823bc421551SDag-Erling Smørgrav c != '+') 824bc421551SDag-Erling Smørgrav ++strp; 825bc421551SDag-Erling Smørgrav return strp; 826bc421551SDag-Erling Smørgrav } 827bc421551SDag-Erling Smørgrav 828bc421551SDag-Erling Smørgrav /* 829bc421551SDag-Erling Smørgrav ** Given a pointer into an extended timezone string, scan until the ending 830bc421551SDag-Erling Smørgrav ** delimiter of the time zone abbreviation is located. 831bc421551SDag-Erling Smørgrav ** Return a pointer to the delimiter. 832bc421551SDag-Erling Smørgrav ** 833bc421551SDag-Erling Smørgrav ** As with getzname above, the legal character set is actually quite 834bc421551SDag-Erling Smørgrav ** restricted, with other characters producing undefined results. 835bc421551SDag-Erling Smørgrav ** We don't do any checking here; checking is done later in common-case code. 836bc421551SDag-Erling Smørgrav */ 837bc421551SDag-Erling Smørgrav 838*a979394aSDag-Erling Smørgrav ATTRIBUTE_PURE_114833 static const char * 839bc421551SDag-Erling Smørgrav getqzname(register const char *strp, const int delim) 840bc421551SDag-Erling Smørgrav { 841bc421551SDag-Erling Smørgrav register int c; 842bc421551SDag-Erling Smørgrav 843bc421551SDag-Erling Smørgrav while ((c = *strp) != '\0' && c != delim) 844bc421551SDag-Erling Smørgrav ++strp; 845bc421551SDag-Erling Smørgrav return strp; 846bc421551SDag-Erling Smørgrav } 847bc421551SDag-Erling Smørgrav 848bc421551SDag-Erling Smørgrav /* 849bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a number from that string. 850bc421551SDag-Erling Smørgrav ** Check that the number is within a specified range; if it is not, return 851bc421551SDag-Erling Smørgrav ** NULL. 852bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the number. 853bc421551SDag-Erling Smørgrav */ 854bc421551SDag-Erling Smørgrav 855bc421551SDag-Erling Smørgrav static const char * 856bc421551SDag-Erling Smørgrav getnum(register const char *strp, int *const nump, const int min, const int max) 857bc421551SDag-Erling Smørgrav { 858bc421551SDag-Erling Smørgrav register char c; 859bc421551SDag-Erling Smørgrav register int num; 860bc421551SDag-Erling Smørgrav 861bc421551SDag-Erling Smørgrav if (strp == NULL || !is_digit(c = *strp)) 862bc421551SDag-Erling Smørgrav return NULL; 863bc421551SDag-Erling Smørgrav num = 0; 864bc421551SDag-Erling Smørgrav do { 865bc421551SDag-Erling Smørgrav num = num * 10 + (c - '0'); 866bc421551SDag-Erling Smørgrav if (num > max) 867bc421551SDag-Erling Smørgrav return NULL; /* illegal value */ 868bc421551SDag-Erling Smørgrav c = *++strp; 869bc421551SDag-Erling Smørgrav } while (is_digit(c)); 870bc421551SDag-Erling Smørgrav if (num < min) 871bc421551SDag-Erling Smørgrav return NULL; /* illegal value */ 872bc421551SDag-Erling Smørgrav *nump = num; 873bc421551SDag-Erling Smørgrav return strp; 874bc421551SDag-Erling Smørgrav } 875bc421551SDag-Erling Smørgrav 876bc421551SDag-Erling Smørgrav /* 877bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a number of seconds, 878bc421551SDag-Erling Smørgrav ** in hh[:mm[:ss]] form, from the string. 879bc421551SDag-Erling Smørgrav ** If any error occurs, return NULL. 880bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the number 881bc421551SDag-Erling Smørgrav ** of seconds. 882bc421551SDag-Erling Smørgrav */ 883bc421551SDag-Erling Smørgrav 884bc421551SDag-Erling Smørgrav static const char * 885bc421551SDag-Erling Smørgrav getsecs(register const char *strp, int_fast32_t *const secsp) 886bc421551SDag-Erling Smørgrav { 887bc421551SDag-Erling Smørgrav int num; 888bc421551SDag-Erling Smørgrav int_fast32_t secsperhour = SECSPERHOUR; 889bc421551SDag-Erling Smørgrav 890bc421551SDag-Erling Smørgrav /* 89146c59934SDag-Erling Smørgrav ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-POSIX rules like 89246c59934SDag-Erling Smørgrav ** "M10.4.6/26", which does not conform to POSIX, 893bc421551SDag-Erling Smørgrav ** but which specifies the equivalent of 894bc421551SDag-Erling Smørgrav ** "02:00 on the first Sunday on or after 23 Oct". 895bc421551SDag-Erling Smørgrav */ 896bc421551SDag-Erling Smørgrav strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); 897bc421551SDag-Erling Smørgrav if (strp == NULL) 898bc421551SDag-Erling Smørgrav return NULL; 899bc421551SDag-Erling Smørgrav *secsp = num * secsperhour; 900bc421551SDag-Erling Smørgrav if (*strp == ':') { 901bc421551SDag-Erling Smørgrav ++strp; 902bc421551SDag-Erling Smørgrav strp = getnum(strp, &num, 0, MINSPERHOUR - 1); 903bc421551SDag-Erling Smørgrav if (strp == NULL) 904bc421551SDag-Erling Smørgrav return NULL; 905bc421551SDag-Erling Smørgrav *secsp += num * SECSPERMIN; 906bc421551SDag-Erling Smørgrav if (*strp == ':') { 907bc421551SDag-Erling Smørgrav ++strp; 908bc421551SDag-Erling Smørgrav /* 'SECSPERMIN' allows for leap seconds. */ 909bc421551SDag-Erling Smørgrav strp = getnum(strp, &num, 0, SECSPERMIN); 910bc421551SDag-Erling Smørgrav if (strp == NULL) 911bc421551SDag-Erling Smørgrav return NULL; 912bc421551SDag-Erling Smørgrav *secsp += num; 913bc421551SDag-Erling Smørgrav } 914bc421551SDag-Erling Smørgrav } 915bc421551SDag-Erling Smørgrav return strp; 916bc421551SDag-Erling Smørgrav } 917bc421551SDag-Erling Smørgrav 918bc421551SDag-Erling Smørgrav /* 919bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract an offset, in 920bc421551SDag-Erling Smørgrav ** [+-]hh[:mm[:ss]] form, from the string. 921bc421551SDag-Erling Smørgrav ** If any error occurs, return NULL. 922bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the time. 923bc421551SDag-Erling Smørgrav */ 924bc421551SDag-Erling Smørgrav 925bc421551SDag-Erling Smørgrav static const char * 926bc421551SDag-Erling Smørgrav getoffset(register const char *strp, int_fast32_t *const offsetp) 927bc421551SDag-Erling Smørgrav { 928bc421551SDag-Erling Smørgrav register bool neg = false; 929bc421551SDag-Erling Smørgrav 930bc421551SDag-Erling Smørgrav if (*strp == '-') { 931bc421551SDag-Erling Smørgrav neg = true; 932bc421551SDag-Erling Smørgrav ++strp; 933bc421551SDag-Erling Smørgrav } else if (*strp == '+') 934bc421551SDag-Erling Smørgrav ++strp; 935bc421551SDag-Erling Smørgrav strp = getsecs(strp, offsetp); 936bc421551SDag-Erling Smørgrav if (strp == NULL) 937bc421551SDag-Erling Smørgrav return NULL; /* illegal time */ 938bc421551SDag-Erling Smørgrav if (neg) 939bc421551SDag-Erling Smørgrav *offsetp = -*offsetp; 940bc421551SDag-Erling Smørgrav return strp; 941bc421551SDag-Erling Smørgrav } 942bc421551SDag-Erling Smørgrav 943bc421551SDag-Erling Smørgrav /* 944bc421551SDag-Erling Smørgrav ** Given a pointer into a timezone string, extract a rule in the form 94546c59934SDag-Erling Smørgrav ** date[/time]. See POSIX Base Definitions section 8.3 variable TZ 94646c59934SDag-Erling Smørgrav ** for the format of "date" and "time". 947bc421551SDag-Erling Smørgrav ** If a valid rule is not found, return NULL. 948bc421551SDag-Erling Smørgrav ** Otherwise, return a pointer to the first character not part of the rule. 949bc421551SDag-Erling Smørgrav */ 950bc421551SDag-Erling Smørgrav 951bc421551SDag-Erling Smørgrav static const char * 952bc421551SDag-Erling Smørgrav getrule(const char *strp, register struct rule *const rulep) 953bc421551SDag-Erling Smørgrav { 954bc421551SDag-Erling Smørgrav if (*strp == 'J') { 955bc421551SDag-Erling Smørgrav /* 956bc421551SDag-Erling Smørgrav ** Julian day. 957bc421551SDag-Erling Smørgrav */ 958bc421551SDag-Erling Smørgrav rulep->r_type = JULIAN_DAY; 959bc421551SDag-Erling Smørgrav ++strp; 960bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); 961bc421551SDag-Erling Smørgrav } else if (*strp == 'M') { 962bc421551SDag-Erling Smørgrav /* 963bc421551SDag-Erling Smørgrav ** Month, week, day. 964bc421551SDag-Erling Smørgrav */ 965bc421551SDag-Erling Smørgrav rulep->r_type = MONTH_NTH_DAY_OF_WEEK; 966bc421551SDag-Erling Smørgrav ++strp; 967bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); 968bc421551SDag-Erling Smørgrav if (strp == NULL) 969bc421551SDag-Erling Smørgrav return NULL; 970bc421551SDag-Erling Smørgrav if (*strp++ != '.') 971bc421551SDag-Erling Smørgrav return NULL; 972bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_week, 1, 5); 973bc421551SDag-Erling Smørgrav if (strp == NULL) 974bc421551SDag-Erling Smørgrav return NULL; 975bc421551SDag-Erling Smørgrav if (*strp++ != '.') 976bc421551SDag-Erling Smørgrav return NULL; 977bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); 978bc421551SDag-Erling Smørgrav } else if (is_digit(*strp)) { 979bc421551SDag-Erling Smørgrav /* 980bc421551SDag-Erling Smørgrav ** Day of year. 981bc421551SDag-Erling Smørgrav */ 982bc421551SDag-Erling Smørgrav rulep->r_type = DAY_OF_YEAR; 983bc421551SDag-Erling Smørgrav strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); 984bc421551SDag-Erling Smørgrav } else return NULL; /* invalid format */ 985bc421551SDag-Erling Smørgrav if (strp == NULL) 986bc421551SDag-Erling Smørgrav return NULL; 987bc421551SDag-Erling Smørgrav if (*strp == '/') { 988bc421551SDag-Erling Smørgrav /* 989bc421551SDag-Erling Smørgrav ** Time specified. 990bc421551SDag-Erling Smørgrav */ 991bc421551SDag-Erling Smørgrav ++strp; 992bc421551SDag-Erling Smørgrav strp = getoffset(strp, &rulep->r_time); 993bc421551SDag-Erling Smørgrav } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ 994bc421551SDag-Erling Smørgrav return strp; 995bc421551SDag-Erling Smørgrav } 996bc421551SDag-Erling Smørgrav 997bc421551SDag-Erling Smørgrav /* 998bc421551SDag-Erling Smørgrav ** Given a year, a rule, and the offset from UT at the time that rule takes 999bc421551SDag-Erling Smørgrav ** effect, calculate the year-relative time that rule takes effect. 1000bc421551SDag-Erling Smørgrav */ 1001bc421551SDag-Erling Smørgrav 1002bc421551SDag-Erling Smørgrav static int_fast32_t 1003bc421551SDag-Erling Smørgrav transtime(const int year, register const struct rule *const rulep, 1004bc421551SDag-Erling Smørgrav const int_fast32_t offset) 1005bc421551SDag-Erling Smørgrav { 1006bc421551SDag-Erling Smørgrav register bool leapyear; 1007bc421551SDag-Erling Smørgrav register int_fast32_t value; 1008bc421551SDag-Erling Smørgrav register int i; 1009bc421551SDag-Erling Smørgrav int d, m1, yy0, yy1, yy2, dow; 1010bc421551SDag-Erling Smørgrav 1011bc421551SDag-Erling Smørgrav leapyear = isleap(year); 1012bc421551SDag-Erling Smørgrav switch (rulep->r_type) { 1013bc421551SDag-Erling Smørgrav 1014bc421551SDag-Erling Smørgrav case JULIAN_DAY: 1015bc421551SDag-Erling Smørgrav /* 1016bc421551SDag-Erling Smørgrav ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap 1017bc421551SDag-Erling Smørgrav ** years. 1018bc421551SDag-Erling Smørgrav ** In non-leap years, or if the day number is 59 or less, just 1019bc421551SDag-Erling Smørgrav ** add SECSPERDAY times the day number-1 to the time of 1020bc421551SDag-Erling Smørgrav ** January 1, midnight, to get the day. 1021bc421551SDag-Erling Smørgrav */ 1022bc421551SDag-Erling Smørgrav value = (rulep->r_day - 1) * SECSPERDAY; 1023bc421551SDag-Erling Smørgrav if (leapyear && rulep->r_day >= 60) 1024bc421551SDag-Erling Smørgrav value += SECSPERDAY; 1025bc421551SDag-Erling Smørgrav break; 1026bc421551SDag-Erling Smørgrav 1027bc421551SDag-Erling Smørgrav case DAY_OF_YEAR: 1028bc421551SDag-Erling Smørgrav /* 1029bc421551SDag-Erling Smørgrav ** n - day of year. 1030bc421551SDag-Erling Smørgrav ** Just add SECSPERDAY times the day number to the time of 1031bc421551SDag-Erling Smørgrav ** January 1, midnight, to get the day. 1032bc421551SDag-Erling Smørgrav */ 1033bc421551SDag-Erling Smørgrav value = rulep->r_day * SECSPERDAY; 1034bc421551SDag-Erling Smørgrav break; 1035bc421551SDag-Erling Smørgrav 1036bc421551SDag-Erling Smørgrav case MONTH_NTH_DAY_OF_WEEK: 1037bc421551SDag-Erling Smørgrav /* 1038bc421551SDag-Erling Smørgrav ** Mm.n.d - nth "dth day" of month m. 1039bc421551SDag-Erling Smørgrav */ 1040bc421551SDag-Erling Smørgrav 1041bc421551SDag-Erling Smørgrav /* 1042bc421551SDag-Erling Smørgrav ** Use Zeller's Congruence to get day-of-week of first day of 1043bc421551SDag-Erling Smørgrav ** month. 1044bc421551SDag-Erling Smørgrav */ 1045bc421551SDag-Erling Smørgrav m1 = (rulep->r_mon + 9) % 12 + 1; 1046bc421551SDag-Erling Smørgrav yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; 1047bc421551SDag-Erling Smørgrav yy1 = yy0 / 100; 1048bc421551SDag-Erling Smørgrav yy2 = yy0 % 100; 1049bc421551SDag-Erling Smørgrav dow = ((26 * m1 - 2) / 10 + 1050bc421551SDag-Erling Smørgrav 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; 1051bc421551SDag-Erling Smørgrav if (dow < 0) 1052bc421551SDag-Erling Smørgrav dow += DAYSPERWEEK; 1053bc421551SDag-Erling Smørgrav 1054bc421551SDag-Erling Smørgrav /* 1055bc421551SDag-Erling Smørgrav ** "dow" is the day-of-week of the first day of the month. Get 1056bc421551SDag-Erling Smørgrav ** the day-of-month (zero-origin) of the first "dow" day of the 1057bc421551SDag-Erling Smørgrav ** month. 1058bc421551SDag-Erling Smørgrav */ 1059bc421551SDag-Erling Smørgrav d = rulep->r_day - dow; 1060bc421551SDag-Erling Smørgrav if (d < 0) 1061bc421551SDag-Erling Smørgrav d += DAYSPERWEEK; 1062bc421551SDag-Erling Smørgrav for (i = 1; i < rulep->r_week; ++i) { 1063bc421551SDag-Erling Smørgrav if (d + DAYSPERWEEK >= 1064bc421551SDag-Erling Smørgrav mon_lengths[leapyear][rulep->r_mon - 1]) 1065bc421551SDag-Erling Smørgrav break; 1066bc421551SDag-Erling Smørgrav d += DAYSPERWEEK; 1067bc421551SDag-Erling Smørgrav } 1068bc421551SDag-Erling Smørgrav 1069bc421551SDag-Erling Smørgrav /* 1070bc421551SDag-Erling Smørgrav ** "d" is the day-of-month (zero-origin) of the day we want. 1071bc421551SDag-Erling Smørgrav */ 1072bc421551SDag-Erling Smørgrav value = d * SECSPERDAY; 1073bc421551SDag-Erling Smørgrav for (i = 0; i < rulep->r_mon - 1; ++i) 1074bc421551SDag-Erling Smørgrav value += mon_lengths[leapyear][i] * SECSPERDAY; 1075bc421551SDag-Erling Smørgrav break; 1076bc421551SDag-Erling Smørgrav 1077bc421551SDag-Erling Smørgrav default: unreachable(); 1078bc421551SDag-Erling Smørgrav } 1079bc421551SDag-Erling Smørgrav 1080bc421551SDag-Erling Smørgrav /* 1081bc421551SDag-Erling Smørgrav ** "value" is the year-relative time of 00:00:00 UT on the day in 1082bc421551SDag-Erling Smørgrav ** question. To get the year-relative time of the specified local 1083bc421551SDag-Erling Smørgrav ** time on that day, add the transition time and the current offset 1084bc421551SDag-Erling Smørgrav ** from UT. 1085bc421551SDag-Erling Smørgrav */ 1086bc421551SDag-Erling Smørgrav return value + rulep->r_time + offset; 1087bc421551SDag-Erling Smørgrav } 1088bc421551SDag-Erling Smørgrav 1089bc421551SDag-Erling Smørgrav /* 1090*a979394aSDag-Erling Smørgrav ** Given a POSIX.1 proleptic TZ string, fill in the rule tables as 1091bc421551SDag-Erling Smørgrav ** appropriate. 1092bc421551SDag-Erling Smørgrav */ 1093bc421551SDag-Erling Smørgrav 1094bc421551SDag-Erling Smørgrav static bool 109546c59934SDag-Erling Smørgrav tzparse(const char *name, struct state *sp, struct state const *basep) 1096bc421551SDag-Erling Smørgrav { 1097bc421551SDag-Erling Smørgrav const char * stdname; 1098bc421551SDag-Erling Smørgrav const char * dstname; 1099bc421551SDag-Erling Smørgrav int_fast32_t stdoffset; 1100bc421551SDag-Erling Smørgrav int_fast32_t dstoffset; 1101bc421551SDag-Erling Smørgrav register char * cp; 1102bc421551SDag-Erling Smørgrav register bool load_ok; 1103bc421551SDag-Erling Smørgrav ptrdiff_t stdlen, dstlen, charcnt; 1104bc421551SDag-Erling Smørgrav time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN; 1105bc421551SDag-Erling Smørgrav 1106bc421551SDag-Erling Smørgrav stdname = name; 1107bc421551SDag-Erling Smørgrav if (*name == '<') { 1108bc421551SDag-Erling Smørgrav name++; 1109bc421551SDag-Erling Smørgrav stdname = name; 1110bc421551SDag-Erling Smørgrav name = getqzname(name, '>'); 1111bc421551SDag-Erling Smørgrav if (*name != '>') 1112bc421551SDag-Erling Smørgrav return false; 1113bc421551SDag-Erling Smørgrav stdlen = name - stdname; 1114bc421551SDag-Erling Smørgrav name++; 1115bc421551SDag-Erling Smørgrav } else { 1116bc421551SDag-Erling Smørgrav name = getzname(name); 1117bc421551SDag-Erling Smørgrav stdlen = name - stdname; 1118bc421551SDag-Erling Smørgrav } 111975411d15SDag-Erling Smørgrav if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM)) 1120bc421551SDag-Erling Smørgrav return false; 1121bc421551SDag-Erling Smørgrav name = getoffset(name, &stdoffset); 1122bc421551SDag-Erling Smørgrav if (name == NULL) 1123bc421551SDag-Erling Smørgrav return false; 1124bc421551SDag-Erling Smørgrav charcnt = stdlen + 1; 1125bc421551SDag-Erling Smørgrav if (basep) { 1126bc421551SDag-Erling Smørgrav if (0 < basep->timecnt) 1127bc421551SDag-Erling Smørgrav atlo = basep->ats[basep->timecnt - 1]; 1128bc421551SDag-Erling Smørgrav load_ok = false; 1129bc421551SDag-Erling Smørgrav sp->leapcnt = basep->leapcnt; 1130bc421551SDag-Erling Smørgrav memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis); 1131bc421551SDag-Erling Smørgrav } else { 1132bc421551SDag-Erling Smørgrav load_ok = tzload(TZDEFRULES, sp, false) == 0; 1133bc421551SDag-Erling Smørgrav if (!load_ok) 1134bc421551SDag-Erling Smørgrav sp->leapcnt = 0; /* So, we're off a little. */ 1135bc421551SDag-Erling Smørgrav } 1136bc421551SDag-Erling Smørgrav if (0 < sp->leapcnt) 1137bc421551SDag-Erling Smørgrav leaplo = sp->lsis[sp->leapcnt - 1].ls_trans; 113846c59934SDag-Erling Smørgrav sp->goback = sp->goahead = false; 1139bc421551SDag-Erling Smørgrav if (*name != '\0') { 1140bc421551SDag-Erling Smørgrav if (*name == '<') { 1141bc421551SDag-Erling Smørgrav dstname = ++name; 1142bc421551SDag-Erling Smørgrav name = getqzname(name, '>'); 1143bc421551SDag-Erling Smørgrav if (*name != '>') 1144bc421551SDag-Erling Smørgrav return false; 1145bc421551SDag-Erling Smørgrav dstlen = name - dstname; 1146bc421551SDag-Erling Smørgrav name++; 1147bc421551SDag-Erling Smørgrav } else { 1148bc421551SDag-Erling Smørgrav dstname = name; 1149bc421551SDag-Erling Smørgrav name = getzname(name); 1150bc421551SDag-Erling Smørgrav dstlen = name - dstname; /* length of DST abbr. */ 1151bc421551SDag-Erling Smørgrav } 115275411d15SDag-Erling Smørgrav if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM)) 1153bc421551SDag-Erling Smørgrav return false; 1154bc421551SDag-Erling Smørgrav charcnt += dstlen + 1; 1155bc421551SDag-Erling Smørgrav if (*name != '\0' && *name != ',' && *name != ';') { 1156bc421551SDag-Erling Smørgrav name = getoffset(name, &dstoffset); 1157bc421551SDag-Erling Smørgrav if (name == NULL) 1158bc421551SDag-Erling Smørgrav return false; 1159bc421551SDag-Erling Smørgrav } else dstoffset = stdoffset - SECSPERHOUR; 1160bc421551SDag-Erling Smørgrav if (*name == '\0' && !load_ok) 1161bc421551SDag-Erling Smørgrav name = TZDEFRULESTRING; 1162bc421551SDag-Erling Smørgrav if (*name == ',' || *name == ';') { 1163bc421551SDag-Erling Smørgrav struct rule start; 1164bc421551SDag-Erling Smørgrav struct rule end; 1165bc421551SDag-Erling Smørgrav register int year; 1166bc421551SDag-Erling Smørgrav register int timecnt; 1167bc421551SDag-Erling Smørgrav time_t janfirst; 1168bc421551SDag-Erling Smørgrav int_fast32_t janoffset = 0; 1169bc421551SDag-Erling Smørgrav int yearbeg, yearlim; 1170bc421551SDag-Erling Smørgrav 1171bc421551SDag-Erling Smørgrav ++name; 1172bc421551SDag-Erling Smørgrav if ((name = getrule(name, &start)) == NULL) 1173bc421551SDag-Erling Smørgrav return false; 1174bc421551SDag-Erling Smørgrav if (*name++ != ',') 1175bc421551SDag-Erling Smørgrav return false; 1176bc421551SDag-Erling Smørgrav if ((name = getrule(name, &end)) == NULL) 1177bc421551SDag-Erling Smørgrav return false; 1178bc421551SDag-Erling Smørgrav if (*name != '\0') 1179bc421551SDag-Erling Smørgrav return false; 1180bc421551SDag-Erling Smørgrav sp->typecnt = 2; /* standard time and DST */ 1181bc421551SDag-Erling Smørgrav /* 1182bc421551SDag-Erling Smørgrav ** Two transitions per year, from EPOCH_YEAR forward. 1183bc421551SDag-Erling Smørgrav */ 1184bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); 1185bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1); 1186bc421551SDag-Erling Smørgrav timecnt = 0; 1187bc421551SDag-Erling Smørgrav janfirst = 0; 1188bc421551SDag-Erling Smørgrav yearbeg = EPOCH_YEAR; 1189bc421551SDag-Erling Smørgrav 1190bc421551SDag-Erling Smørgrav do { 1191bc421551SDag-Erling Smørgrav int_fast32_t yearsecs 1192bc421551SDag-Erling Smørgrav = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY; 11931365bb72SDag-Erling Smørgrav time_t janfirst1 = janfirst; 1194bc421551SDag-Erling Smørgrav yearbeg--; 11951365bb72SDag-Erling Smørgrav if (increment_overflow_time(&janfirst1, -yearsecs)) { 1196bc421551SDag-Erling Smørgrav janoffset = -yearsecs; 1197bc421551SDag-Erling Smørgrav break; 1198bc421551SDag-Erling Smørgrav } 11991365bb72SDag-Erling Smørgrav janfirst = janfirst1; 1200bc421551SDag-Erling Smørgrav } while (atlo < janfirst 1201bc421551SDag-Erling Smørgrav && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg); 1202bc421551SDag-Erling Smørgrav 1203bc421551SDag-Erling Smørgrav while (true) { 1204bc421551SDag-Erling Smørgrav int_fast32_t yearsecs 1205bc421551SDag-Erling Smørgrav = year_lengths[isleap(yearbeg)] * SECSPERDAY; 1206bc421551SDag-Erling Smørgrav int yearbeg1 = yearbeg; 1207bc421551SDag-Erling Smørgrav time_t janfirst1 = janfirst; 1208bc421551SDag-Erling Smørgrav if (increment_overflow_time(&janfirst1, yearsecs) 1209bc421551SDag-Erling Smørgrav || increment_overflow(&yearbeg1, 1) 1210bc421551SDag-Erling Smørgrav || atlo <= janfirst1) 1211bc421551SDag-Erling Smørgrav break; 1212bc421551SDag-Erling Smørgrav yearbeg = yearbeg1; 1213bc421551SDag-Erling Smørgrav janfirst = janfirst1; 1214bc421551SDag-Erling Smørgrav } 1215bc421551SDag-Erling Smørgrav 1216bc421551SDag-Erling Smørgrav yearlim = yearbeg; 121746c59934SDag-Erling Smørgrav if (increment_overflow(&yearlim, years_of_observations)) 1218bc421551SDag-Erling Smørgrav yearlim = INT_MAX; 1219bc421551SDag-Erling Smørgrav for (year = yearbeg; year < yearlim; year++) { 1220bc421551SDag-Erling Smørgrav int_fast32_t 1221bc421551SDag-Erling Smørgrav starttime = transtime(year, &start, stdoffset), 1222bc421551SDag-Erling Smørgrav endtime = transtime(year, &end, dstoffset); 1223bc421551SDag-Erling Smørgrav int_fast32_t 1224bc421551SDag-Erling Smørgrav yearsecs = (year_lengths[isleap(year)] 1225bc421551SDag-Erling Smørgrav * SECSPERDAY); 1226bc421551SDag-Erling Smørgrav bool reversed = endtime < starttime; 1227bc421551SDag-Erling Smørgrav if (reversed) { 1228bc421551SDag-Erling Smørgrav int_fast32_t swap = starttime; 1229bc421551SDag-Erling Smørgrav starttime = endtime; 1230bc421551SDag-Erling Smørgrav endtime = swap; 1231bc421551SDag-Erling Smørgrav } 1232bc421551SDag-Erling Smørgrav if (reversed 1233bc421551SDag-Erling Smørgrav || (starttime < endtime 1234bc421551SDag-Erling Smørgrav && endtime - starttime < yearsecs)) { 1235bc421551SDag-Erling Smørgrav if (TZ_MAX_TIMES - 2 < timecnt) 1236bc421551SDag-Erling Smørgrav break; 1237bc421551SDag-Erling Smørgrav sp->ats[timecnt] = janfirst; 1238bc421551SDag-Erling Smørgrav if (! increment_overflow_time 1239bc421551SDag-Erling Smørgrav (&sp->ats[timecnt], 1240bc421551SDag-Erling Smørgrav janoffset + starttime) 1241bc421551SDag-Erling Smørgrav && atlo <= sp->ats[timecnt]) 1242bc421551SDag-Erling Smørgrav sp->types[timecnt++] = !reversed; 1243bc421551SDag-Erling Smørgrav sp->ats[timecnt] = janfirst; 1244bc421551SDag-Erling Smørgrav if (! increment_overflow_time 1245bc421551SDag-Erling Smørgrav (&sp->ats[timecnt], 1246bc421551SDag-Erling Smørgrav janoffset + endtime) 1247bc421551SDag-Erling Smørgrav && atlo <= sp->ats[timecnt]) { 1248bc421551SDag-Erling Smørgrav sp->types[timecnt++] = reversed; 1249bc421551SDag-Erling Smørgrav } 1250bc421551SDag-Erling Smørgrav } 1251bc421551SDag-Erling Smørgrav if (endtime < leaplo) { 1252bc421551SDag-Erling Smørgrav yearlim = year; 1253bc421551SDag-Erling Smørgrav if (increment_overflow(&yearlim, 125446c59934SDag-Erling Smørgrav years_of_observations)) 1255bc421551SDag-Erling Smørgrav yearlim = INT_MAX; 1256bc421551SDag-Erling Smørgrav } 1257bc421551SDag-Erling Smørgrav if (increment_overflow_time 1258bc421551SDag-Erling Smørgrav (&janfirst, janoffset + yearsecs)) 1259bc421551SDag-Erling Smørgrav break; 1260bc421551SDag-Erling Smørgrav janoffset = 0; 1261bc421551SDag-Erling Smørgrav } 1262bc421551SDag-Erling Smørgrav sp->timecnt = timecnt; 1263bc421551SDag-Erling Smørgrav if (! timecnt) { 1264bc421551SDag-Erling Smørgrav sp->ttis[0] = sp->ttis[1]; 1265bc421551SDag-Erling Smørgrav sp->typecnt = 1; /* Perpetual DST. */ 126646c59934SDag-Erling Smørgrav } else if (years_of_observations <= year - yearbeg) 1267bc421551SDag-Erling Smørgrav sp->goback = sp->goahead = true; 1268bc421551SDag-Erling Smørgrav } else { 1269bc421551SDag-Erling Smørgrav register int_fast32_t theirstdoffset; 1270bc421551SDag-Erling Smørgrav register int_fast32_t theirdstoffset; 1271bc421551SDag-Erling Smørgrav register int_fast32_t theiroffset; 1272bc421551SDag-Erling Smørgrav register bool isdst; 1273bc421551SDag-Erling Smørgrav register int i; 1274bc421551SDag-Erling Smørgrav register int j; 1275bc421551SDag-Erling Smørgrav 1276bc421551SDag-Erling Smørgrav if (*name != '\0') 1277bc421551SDag-Erling Smørgrav return false; 1278bc421551SDag-Erling Smørgrav /* 1279bc421551SDag-Erling Smørgrav ** Initial values of theirstdoffset and theirdstoffset. 1280bc421551SDag-Erling Smørgrav */ 1281bc421551SDag-Erling Smørgrav theirstdoffset = 0; 1282bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) { 1283bc421551SDag-Erling Smørgrav j = sp->types[i]; 1284bc421551SDag-Erling Smørgrav if (!sp->ttis[j].tt_isdst) { 1285bc421551SDag-Erling Smørgrav theirstdoffset = 1286bc421551SDag-Erling Smørgrav - sp->ttis[j].tt_utoff; 1287bc421551SDag-Erling Smørgrav break; 1288bc421551SDag-Erling Smørgrav } 1289bc421551SDag-Erling Smørgrav } 1290bc421551SDag-Erling Smørgrav theirdstoffset = 0; 1291bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) { 1292bc421551SDag-Erling Smørgrav j = sp->types[i]; 1293bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_isdst) { 1294bc421551SDag-Erling Smørgrav theirdstoffset = 1295bc421551SDag-Erling Smørgrav - sp->ttis[j].tt_utoff; 1296bc421551SDag-Erling Smørgrav break; 1297bc421551SDag-Erling Smørgrav } 1298bc421551SDag-Erling Smørgrav } 1299bc421551SDag-Erling Smørgrav /* 1300bc421551SDag-Erling Smørgrav ** Initially we're assumed to be in standard time. 1301bc421551SDag-Erling Smørgrav */ 1302bc421551SDag-Erling Smørgrav isdst = false; 1303bc421551SDag-Erling Smørgrav /* 1304bc421551SDag-Erling Smørgrav ** Now juggle transition times and types 1305bc421551SDag-Erling Smørgrav ** tracking offsets as you do. 1306bc421551SDag-Erling Smørgrav */ 1307bc421551SDag-Erling Smørgrav for (i = 0; i < sp->timecnt; ++i) { 1308bc421551SDag-Erling Smørgrav j = sp->types[i]; 1309bc421551SDag-Erling Smørgrav sp->types[i] = sp->ttis[j].tt_isdst; 1310bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_ttisut) { 1311bc421551SDag-Erling Smørgrav /* No adjustment to transition time */ 1312bc421551SDag-Erling Smørgrav } else { 1313bc421551SDag-Erling Smørgrav /* 1314bc421551SDag-Erling Smørgrav ** If daylight saving time is in 1315bc421551SDag-Erling Smørgrav ** effect, and the transition time was 1316bc421551SDag-Erling Smørgrav ** not specified as standard time, add 1317bc421551SDag-Erling Smørgrav ** the daylight saving time offset to 1318bc421551SDag-Erling Smørgrav ** the transition time; otherwise, add 1319bc421551SDag-Erling Smørgrav ** the standard time offset to the 1320bc421551SDag-Erling Smørgrav ** transition time. 1321bc421551SDag-Erling Smørgrav */ 1322bc421551SDag-Erling Smørgrav /* 1323bc421551SDag-Erling Smørgrav ** Transitions from DST to DDST 1324bc421551SDag-Erling Smørgrav ** will effectively disappear since 1325*a979394aSDag-Erling Smørgrav ** proleptic TZ strings have only one 132646c59934SDag-Erling Smørgrav ** DST offset. 1327bc421551SDag-Erling Smørgrav */ 1328bc421551SDag-Erling Smørgrav if (isdst && !sp->ttis[j].tt_ttisstd) { 1329bc421551SDag-Erling Smørgrav sp->ats[i] += dstoffset - 1330bc421551SDag-Erling Smørgrav theirdstoffset; 1331bc421551SDag-Erling Smørgrav } else { 1332bc421551SDag-Erling Smørgrav sp->ats[i] += stdoffset - 1333bc421551SDag-Erling Smørgrav theirstdoffset; 1334bc421551SDag-Erling Smørgrav } 1335bc421551SDag-Erling Smørgrav } 1336bc421551SDag-Erling Smørgrav theiroffset = -sp->ttis[j].tt_utoff; 1337bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_isdst) 1338bc421551SDag-Erling Smørgrav theirdstoffset = theiroffset; 1339bc421551SDag-Erling Smørgrav else theirstdoffset = theiroffset; 1340bc421551SDag-Erling Smørgrav } 1341bc421551SDag-Erling Smørgrav /* 1342bc421551SDag-Erling Smørgrav ** Finally, fill in ttis. 1343bc421551SDag-Erling Smørgrav */ 1344bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); 1345bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1); 1346bc421551SDag-Erling Smørgrav sp->typecnt = 2; 1347bc421551SDag-Erling Smørgrav } 1348bc421551SDag-Erling Smørgrav } else { 1349bc421551SDag-Erling Smørgrav dstlen = 0; 1350bc421551SDag-Erling Smørgrav sp->typecnt = 1; /* only standard time */ 1351bc421551SDag-Erling Smørgrav sp->timecnt = 0; 1352bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], -stdoffset, false, 0); 1353bc421551SDag-Erling Smørgrav } 1354bc421551SDag-Erling Smørgrav sp->charcnt = charcnt; 1355bc421551SDag-Erling Smørgrav cp = sp->chars; 1356bc421551SDag-Erling Smørgrav memcpy(cp, stdname, stdlen); 1357bc421551SDag-Erling Smørgrav cp += stdlen; 1358bc421551SDag-Erling Smørgrav *cp++ = '\0'; 1359bc421551SDag-Erling Smørgrav if (dstlen != 0) { 1360bc421551SDag-Erling Smørgrav memcpy(cp, dstname, dstlen); 1361bc421551SDag-Erling Smørgrav *(cp + dstlen) = '\0'; 1362bc421551SDag-Erling Smørgrav } 1363bc421551SDag-Erling Smørgrav return true; 1364bc421551SDag-Erling Smørgrav } 1365bc421551SDag-Erling Smørgrav 1366bc421551SDag-Erling Smørgrav static void 1367bc421551SDag-Erling Smørgrav gmtload(struct state *const sp) 1368bc421551SDag-Erling Smørgrav { 1369bc421551SDag-Erling Smørgrav if (tzload(etc_utc, sp, true) != 0) 1370bc421551SDag-Erling Smørgrav tzparse("UTC0", sp, NULL); 1371bc421551SDag-Erling Smørgrav } 1372bc421551SDag-Erling Smørgrav 1373bc421551SDag-Erling Smørgrav #ifdef DETECT_TZ_CHANGES 1374bc421551SDag-Erling Smørgrav static int 1375bc421551SDag-Erling Smørgrav recheck_tzdata() 1376bc421551SDag-Erling Smørgrav { 1377bc421551SDag-Erling Smørgrav static time_t last_checked; 1378bc421551SDag-Erling Smørgrav struct timespec now; 1379bc421551SDag-Erling Smørgrav time_t current_time; 1380bc421551SDag-Erling Smørgrav int error; 1381bc421551SDag-Erling Smørgrav 1382bc421551SDag-Erling Smørgrav /* 1383bc421551SDag-Erling Smørgrav * We want to recheck the timezone file every 61 sec. 1384bc421551SDag-Erling Smørgrav */ 1385bc421551SDag-Erling Smørgrav error = clock_gettime(CLOCK_MONOTONIC, &now); 1386bc421551SDag-Erling Smørgrav if (error < 0) { 1387bc421551SDag-Erling Smørgrav /* XXX: Can we somehow report this? */ 1388bc421551SDag-Erling Smørgrav return 0; 1389bc421551SDag-Erling Smørgrav } 1390bc421551SDag-Erling Smørgrav 1391bc421551SDag-Erling Smørgrav current_time = now.tv_sec; 1392bc421551SDag-Erling Smørgrav if ((current_time - last_checked > DETECT_TZ_CHANGES_INTERVAL) || 1393bc421551SDag-Erling Smørgrav (last_checked > current_time)) { 1394bc421551SDag-Erling Smørgrav last_checked = current_time; 1395bc421551SDag-Erling Smørgrav return 1; 1396bc421551SDag-Erling Smørgrav } 1397bc421551SDag-Erling Smørgrav 1398bc421551SDag-Erling Smørgrav return 0; 1399bc421551SDag-Erling Smørgrav } 1400bc421551SDag-Erling Smørgrav #else /* !DETECT_TZ_CHANGES */ 1401bc421551SDag-Erling Smørgrav #define recheck_tzdata() 0 1402bc421551SDag-Erling Smørgrav #endif /* !DETECT_TZ_CHANGES */ 1403bc421551SDag-Erling Smørgrav 1404bc421551SDag-Erling Smørgrav /* Initialize *SP to a value appropriate for the TZ setting NAME. 1405bc421551SDag-Erling Smørgrav Return 0 on success, an errno value on failure. */ 1406bc421551SDag-Erling Smørgrav static int 1407bc421551SDag-Erling Smørgrav zoneinit(struct state *sp, char const *name) 1408bc421551SDag-Erling Smørgrav { 1409bc421551SDag-Erling Smørgrav if (name && ! name[0]) { 1410bc421551SDag-Erling Smørgrav /* 1411bc421551SDag-Erling Smørgrav ** User wants it fast rather than right. 1412bc421551SDag-Erling Smørgrav */ 1413bc421551SDag-Erling Smørgrav sp->leapcnt = 0; /* so, we're off a little */ 1414bc421551SDag-Erling Smørgrav sp->timecnt = 0; 1415bc421551SDag-Erling Smørgrav sp->typecnt = 0; 1416bc421551SDag-Erling Smørgrav sp->charcnt = 0; 1417bc421551SDag-Erling Smørgrav sp->goback = sp->goahead = false; 1418bc421551SDag-Erling Smørgrav init_ttinfo(&sp->ttis[0], 0, false, 0); 1419bc421551SDag-Erling Smørgrav strcpy(sp->chars, utc); 1420bc421551SDag-Erling Smørgrav return 0; 1421bc421551SDag-Erling Smørgrav } else { 1422bc421551SDag-Erling Smørgrav int err = tzload(name, sp, true); 1423bc421551SDag-Erling Smørgrav if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL)) 1424bc421551SDag-Erling Smørgrav err = 0; 1425bc421551SDag-Erling Smørgrav if (err == 0) 142675411d15SDag-Erling Smørgrav err = scrub_abbrs(sp); 1427bc421551SDag-Erling Smørgrav return err; 1428bc421551SDag-Erling Smørgrav } 1429bc421551SDag-Erling Smørgrav } 1430bc421551SDag-Erling Smørgrav 1431bc421551SDag-Erling Smørgrav static void 143271e0c890SDag-Erling Smørgrav tzset_unlocked_name(char const *name) 1433bc421551SDag-Erling Smørgrav { 1434bc421551SDag-Erling Smørgrav struct state *sp = lclptr; 1435bc421551SDag-Erling Smørgrav int lcl = name ? strlen(name) < sizeof lcl_TZname : -1; 1436bc421551SDag-Erling Smørgrav if (lcl < 0 1437bc421551SDag-Erling Smørgrav ? lcl_is_set < 0 1438bc421551SDag-Erling Smørgrav : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0) 1439bc421551SDag-Erling Smørgrav if (recheck_tzdata() == 0) 1440bc421551SDag-Erling Smørgrav return; 1441bc421551SDag-Erling Smørgrav #ifdef ALL_STATE 1442bc421551SDag-Erling Smørgrav if (! sp) 1443bc421551SDag-Erling Smørgrav lclptr = sp = malloc(sizeof *lclptr); 1444bc421551SDag-Erling Smørgrav #endif /* defined ALL_STATE */ 1445bc421551SDag-Erling Smørgrav if (sp) { 1446bc421551SDag-Erling Smørgrav if (zoneinit(sp, name) != 0) 1447bc421551SDag-Erling Smørgrav zoneinit(sp, ""); 1448bc421551SDag-Erling Smørgrav if (0 < lcl) 1449bc421551SDag-Erling Smørgrav strcpy(lcl_TZname, name); 1450bc421551SDag-Erling Smørgrav } 1451bc421551SDag-Erling Smørgrav settzname(); 1452bc421551SDag-Erling Smørgrav lcl_is_set = lcl; 1453bc421551SDag-Erling Smørgrav } 1454bc421551SDag-Erling Smørgrav 145571e0c890SDag-Erling Smørgrav static void 145671e0c890SDag-Erling Smørgrav tzset_unlocked(void) 145771e0c890SDag-Erling Smørgrav { 145871e0c890SDag-Erling Smørgrav tzset_unlocked_name(getenv("TZ")); 145971e0c890SDag-Erling Smørgrav } 146071e0c890SDag-Erling Smørgrav 1461bc421551SDag-Erling Smørgrav void 1462bc421551SDag-Erling Smørgrav tzset(void) 1463bc421551SDag-Erling Smørgrav { 1464bc421551SDag-Erling Smørgrav if (lock() != 0) 1465bc421551SDag-Erling Smørgrav return; 1466bc421551SDag-Erling Smørgrav tzset_unlocked(); 1467bc421551SDag-Erling Smørgrav unlock(); 1468bc421551SDag-Erling Smørgrav } 1469bc421551SDag-Erling Smørgrav 147071e0c890SDag-Erling Smørgrav void 147171e0c890SDag-Erling Smørgrav freebsd13_tzsetwall(void) 147271e0c890SDag-Erling Smørgrav { 147371e0c890SDag-Erling Smørgrav if (lock() != 0) 147471e0c890SDag-Erling Smørgrav return; 147571e0c890SDag-Erling Smørgrav tzset_unlocked_name(NULL); 147671e0c890SDag-Erling Smørgrav unlock(); 147771e0c890SDag-Erling Smørgrav } 147871e0c890SDag-Erling Smørgrav __sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0); 147971e0c890SDag-Erling Smørgrav __warn_references(tzsetwall, 148071e0c890SDag-Erling Smørgrav "warning: tzsetwall() is deprecated, use tzset() instead."); 148171e0c890SDag-Erling Smørgrav 1482bc421551SDag-Erling Smørgrav static void 1483bc421551SDag-Erling Smørgrav gmtcheck(void) 1484bc421551SDag-Erling Smørgrav { 1485bc421551SDag-Erling Smørgrav static bool gmt_is_set; 1486bc421551SDag-Erling Smørgrav if (lock() != 0) 1487bc421551SDag-Erling Smørgrav return; 1488bc421551SDag-Erling Smørgrav if (! gmt_is_set) { 1489bc421551SDag-Erling Smørgrav #ifdef ALL_STATE 1490bc421551SDag-Erling Smørgrav gmtptr = malloc(sizeof *gmtptr); 1491bc421551SDag-Erling Smørgrav #endif 1492bc421551SDag-Erling Smørgrav if (gmtptr) 1493bc421551SDag-Erling Smørgrav gmtload(gmtptr); 1494bc421551SDag-Erling Smørgrav gmt_is_set = true; 1495bc421551SDag-Erling Smørgrav } 1496bc421551SDag-Erling Smørgrav unlock(); 1497bc421551SDag-Erling Smørgrav } 1498bc421551SDag-Erling Smørgrav 1499bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED 1500bc421551SDag-Erling Smørgrav 1501bc421551SDag-Erling Smørgrav timezone_t 1502bc421551SDag-Erling Smørgrav tzalloc(char const *name) 1503bc421551SDag-Erling Smørgrav { 1504bc421551SDag-Erling Smørgrav timezone_t sp = malloc(sizeof *sp); 1505bc421551SDag-Erling Smørgrav if (sp) { 1506bc421551SDag-Erling Smørgrav int err = zoneinit(sp, name); 1507bc421551SDag-Erling Smørgrav if (err != 0) { 1508bc421551SDag-Erling Smørgrav free(sp); 1509bc421551SDag-Erling Smørgrav errno = err; 1510bc421551SDag-Erling Smørgrav return NULL; 1511bc421551SDag-Erling Smørgrav } 1512bc421551SDag-Erling Smørgrav } else if (!HAVE_MALLOC_ERRNO) 1513bc421551SDag-Erling Smørgrav errno = ENOMEM; 1514bc421551SDag-Erling Smørgrav return sp; 1515bc421551SDag-Erling Smørgrav } 1516bc421551SDag-Erling Smørgrav 1517bc421551SDag-Erling Smørgrav void 1518bc421551SDag-Erling Smørgrav tzfree(timezone_t sp) 1519bc421551SDag-Erling Smørgrav { 1520bc421551SDag-Erling Smørgrav free(sp); 1521bc421551SDag-Erling Smørgrav } 1522bc421551SDag-Erling Smørgrav 1523bc421551SDag-Erling Smørgrav /* 1524*a979394aSDag-Erling Smørgrav ** NetBSD 6.1.4 has ctime_rz, but omit it because C23 deprecates ctime and 1525*a979394aSDag-Erling Smørgrav ** POSIX.1-2024 removes ctime_r. Both have potential security problems that 1526bc421551SDag-Erling Smørgrav ** ctime_rz would share. Callers can instead use localtime_rz + strftime. 1527bc421551SDag-Erling Smørgrav ** 1528bc421551SDag-Erling Smørgrav ** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work 1529bc421551SDag-Erling Smørgrav ** in zones with three or more time zone abbreviations. 1530bc421551SDag-Erling Smørgrav ** Callers can instead use localtime_rz + strftime. 1531bc421551SDag-Erling Smørgrav */ 1532bc421551SDag-Erling Smørgrav 1533bc421551SDag-Erling Smørgrav #endif 1534bc421551SDag-Erling Smørgrav 1535bc421551SDag-Erling Smørgrav /* 1536bc421551SDag-Erling Smørgrav ** The easy way to behave "as if no library function calls" localtime 1537bc421551SDag-Erling Smørgrav ** is to not call it, so we drop its guts into "localsub", which can be 1538bc421551SDag-Erling Smørgrav ** freely called. (And no, the PANS doesn't require the above behavior, 1539bc421551SDag-Erling Smørgrav ** but it *is* desirable.) 1540bc421551SDag-Erling Smørgrav ** 1541bc421551SDag-Erling Smørgrav ** If successful and SETNAME is nonzero, 1542bc421551SDag-Erling Smørgrav ** set the applicable parts of tzname, timezone and altzone; 1543*a979394aSDag-Erling Smørgrav ** however, it's OK to omit this step for proleptic TZ strings 1544bc421551SDag-Erling Smørgrav ** since in that case tzset should have already done this step correctly. 1545bc421551SDag-Erling Smørgrav ** SETNAME's type is int_fast32_t for compatibility with gmtsub, 1546bc421551SDag-Erling Smørgrav ** but it is actually a boolean and its value should be 0 or 1. 1547bc421551SDag-Erling Smørgrav */ 1548bc421551SDag-Erling Smørgrav 1549bc421551SDag-Erling Smørgrav /*ARGSUSED*/ 1550bc421551SDag-Erling Smørgrav static struct tm * 1551bc421551SDag-Erling Smørgrav localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, 1552bc421551SDag-Erling Smørgrav struct tm *const tmp) 1553bc421551SDag-Erling Smørgrav { 1554bc421551SDag-Erling Smørgrav register const struct ttinfo * ttisp; 1555bc421551SDag-Erling Smørgrav register int i; 1556bc421551SDag-Erling Smørgrav register struct tm * result; 1557bc421551SDag-Erling Smørgrav const time_t t = *timep; 1558bc421551SDag-Erling Smørgrav 1559bc421551SDag-Erling Smørgrav if (sp == NULL) { 1560bc421551SDag-Erling Smørgrav /* Don't bother to set tzname etc.; tzset has already done it. */ 1561bc421551SDag-Erling Smørgrav return gmtsub(gmtptr, timep, 0, tmp); 1562bc421551SDag-Erling Smørgrav } 1563bc421551SDag-Erling Smørgrav if ((sp->goback && t < sp->ats[0]) || 1564bc421551SDag-Erling Smørgrav (sp->goahead && t > sp->ats[sp->timecnt - 1])) { 1565bc421551SDag-Erling Smørgrav time_t newt; 1566bc421551SDag-Erling Smørgrav register time_t seconds; 1567bc421551SDag-Erling Smørgrav register time_t years; 1568bc421551SDag-Erling Smørgrav 1569bc421551SDag-Erling Smørgrav if (t < sp->ats[0]) 1570bc421551SDag-Erling Smørgrav seconds = sp->ats[0] - t; 1571bc421551SDag-Erling Smørgrav else seconds = t - sp->ats[sp->timecnt - 1]; 1572bc421551SDag-Erling Smørgrav --seconds; 1573bc421551SDag-Erling Smørgrav 1574bc421551SDag-Erling Smørgrav /* Beware integer overflow, as SECONDS might 1575bc421551SDag-Erling Smørgrav be close to the maximum time_t. */ 1576bc421551SDag-Erling Smørgrav years = seconds / SECSPERREPEAT * YEARSPERREPEAT; 1577bc421551SDag-Erling Smørgrav seconds = years * AVGSECSPERYEAR; 1578bc421551SDag-Erling Smørgrav years += YEARSPERREPEAT; 1579bc421551SDag-Erling Smørgrav if (t < sp->ats[0]) 1580bc421551SDag-Erling Smørgrav newt = t + seconds + SECSPERREPEAT; 1581bc421551SDag-Erling Smørgrav else 1582bc421551SDag-Erling Smørgrav newt = t - seconds - SECSPERREPEAT; 1583bc421551SDag-Erling Smørgrav 1584bc421551SDag-Erling Smørgrav if (newt < sp->ats[0] || 1585bc421551SDag-Erling Smørgrav newt > sp->ats[sp->timecnt - 1]) 1586bc421551SDag-Erling Smørgrav return NULL; /* "cannot happen" */ 1587bc421551SDag-Erling Smørgrav result = localsub(sp, &newt, setname, tmp); 1588bc421551SDag-Erling Smørgrav if (result) { 1589bc421551SDag-Erling Smørgrav #if defined ckd_add && defined ckd_sub 1590bc421551SDag-Erling Smørgrav if (t < sp->ats[0] 1591bc421551SDag-Erling Smørgrav ? ckd_sub(&result->tm_year, 1592bc421551SDag-Erling Smørgrav result->tm_year, years) 1593bc421551SDag-Erling Smørgrav : ckd_add(&result->tm_year, 1594bc421551SDag-Erling Smørgrav result->tm_year, years)) 1595bc421551SDag-Erling Smørgrav return NULL; 1596bc421551SDag-Erling Smørgrav #else 1597bc421551SDag-Erling Smørgrav register int_fast64_t newy; 1598bc421551SDag-Erling Smørgrav 1599bc421551SDag-Erling Smørgrav newy = result->tm_year; 1600bc421551SDag-Erling Smørgrav if (t < sp->ats[0]) 1601bc421551SDag-Erling Smørgrav newy -= years; 1602bc421551SDag-Erling Smørgrav else newy += years; 1603bc421551SDag-Erling Smørgrav if (! (INT_MIN <= newy && newy <= INT_MAX)) 1604bc421551SDag-Erling Smørgrav return NULL; 1605bc421551SDag-Erling Smørgrav result->tm_year = newy; 1606bc421551SDag-Erling Smørgrav #endif 1607bc421551SDag-Erling Smørgrav } 1608bc421551SDag-Erling Smørgrav return result; 1609bc421551SDag-Erling Smørgrav } 1610bc421551SDag-Erling Smørgrav if (sp->timecnt == 0 || t < sp->ats[0]) { 1611*a979394aSDag-Erling Smørgrav i = 0; 1612bc421551SDag-Erling Smørgrav } else { 1613bc421551SDag-Erling Smørgrav register int lo = 1; 1614bc421551SDag-Erling Smørgrav register int hi = sp->timecnt; 1615bc421551SDag-Erling Smørgrav 1616bc421551SDag-Erling Smørgrav while (lo < hi) { 1617bc421551SDag-Erling Smørgrav register int mid = (lo + hi) >> 1; 1618bc421551SDag-Erling Smørgrav 1619bc421551SDag-Erling Smørgrav if (t < sp->ats[mid]) 1620bc421551SDag-Erling Smørgrav hi = mid; 1621bc421551SDag-Erling Smørgrav else lo = mid + 1; 1622bc421551SDag-Erling Smørgrav } 1623bc421551SDag-Erling Smørgrav i = sp->types[lo - 1]; 1624bc421551SDag-Erling Smørgrav } 1625bc421551SDag-Erling Smørgrav ttisp = &sp->ttis[i]; 1626bc421551SDag-Erling Smørgrav /* 1627bc421551SDag-Erling Smørgrav ** To get (wrong) behavior that's compatible with System V Release 2.0 1628bc421551SDag-Erling Smørgrav ** you'd replace the statement below with 1629bc421551SDag-Erling Smørgrav ** t += ttisp->tt_utoff; 1630bc421551SDag-Erling Smørgrav ** timesub(&t, 0L, sp, tmp); 1631bc421551SDag-Erling Smørgrav */ 1632bc421551SDag-Erling Smørgrav result = timesub(&t, ttisp->tt_utoff, sp, tmp); 1633bc421551SDag-Erling Smørgrav if (result) { 1634bc421551SDag-Erling Smørgrav result->tm_isdst = ttisp->tt_isdst; 1635bc421551SDag-Erling Smørgrav #ifdef TM_ZONE 1636bc421551SDag-Erling Smørgrav result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx]; 1637bc421551SDag-Erling Smørgrav #endif /* defined TM_ZONE */ 1638bc421551SDag-Erling Smørgrav if (setname) 1639bc421551SDag-Erling Smørgrav update_tzname_etc(sp, ttisp); 1640bc421551SDag-Erling Smørgrav } 1641bc421551SDag-Erling Smørgrav return result; 1642bc421551SDag-Erling Smørgrav } 1643bc421551SDag-Erling Smørgrav 1644bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED 1645bc421551SDag-Erling Smørgrav 1646bc421551SDag-Erling Smørgrav struct tm * 164775411d15SDag-Erling Smørgrav localtime_rz(struct state *restrict sp, time_t const *restrict timep, 164875411d15SDag-Erling Smørgrav struct tm *restrict tmp) 1649bc421551SDag-Erling Smørgrav { 1650bc421551SDag-Erling Smørgrav return localsub(sp, timep, 0, tmp); 1651bc421551SDag-Erling Smørgrav } 1652bc421551SDag-Erling Smørgrav 1653bc421551SDag-Erling Smørgrav #endif 1654bc421551SDag-Erling Smørgrav 1655bc421551SDag-Erling Smørgrav static struct tm * 1656bc421551SDag-Erling Smørgrav localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) 1657bc421551SDag-Erling Smørgrav { 1658bc421551SDag-Erling Smørgrav int err = lock(); 1659bc421551SDag-Erling Smørgrav if (err) { 1660bc421551SDag-Erling Smørgrav errno = err; 1661bc421551SDag-Erling Smørgrav return NULL; 1662bc421551SDag-Erling Smørgrav } 1663bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES 1664bc421551SDag-Erling Smørgrav if (setname || !lcl_is_set) 1665bc421551SDag-Erling Smørgrav #endif 1666bc421551SDag-Erling Smørgrav tzset_unlocked(); 1667bc421551SDag-Erling Smørgrav tmp = localsub(lclptr, timep, setname, tmp); 1668bc421551SDag-Erling Smørgrav unlock(); 1669bc421551SDag-Erling Smørgrav return tmp; 1670bc421551SDag-Erling Smørgrav } 1671bc421551SDag-Erling Smørgrav 1672bc421551SDag-Erling Smørgrav static void 1673bc421551SDag-Erling Smørgrav localtime_key_init(void) 1674bc421551SDag-Erling Smørgrav { 1675bc421551SDag-Erling Smørgrav 1676bc421551SDag-Erling Smørgrav localtime_key_error = _pthread_key_create(&localtime_key, free); 1677bc421551SDag-Erling Smørgrav } 1678bc421551SDag-Erling Smørgrav 1679bc421551SDag-Erling Smørgrav struct tm * 1680bc421551SDag-Erling Smørgrav localtime(const time_t *timep) 1681bc421551SDag-Erling Smørgrav { 168275411d15SDag-Erling Smørgrav #if !SUPPORT_C89 168375411d15SDag-Erling Smørgrav static struct tm tm; 168475411d15SDag-Erling Smørgrav #endif 1685bc421551SDag-Erling Smørgrav struct tm *p_tm = &tm; 1686bc421551SDag-Erling Smørgrav 1687bc421551SDag-Erling Smørgrav if (__isthreaded != 0) { 1688bc421551SDag-Erling Smørgrav _pthread_once(&localtime_once, localtime_key_init); 1689bc421551SDag-Erling Smørgrav if (localtime_key_error != 0) { 1690bc421551SDag-Erling Smørgrav errno = localtime_key_error; 1691bc421551SDag-Erling Smørgrav return (NULL); 1692bc421551SDag-Erling Smørgrav } 1693bc421551SDag-Erling Smørgrav if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) { 1694bc421551SDag-Erling Smørgrav if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { 1695bc421551SDag-Erling Smørgrav return (NULL); 1696bc421551SDag-Erling Smørgrav } 169796e68c39SDag-Erling Smørgrav if (_pthread_setspecific(localtime_key, p_tm) != 0) { 169896e68c39SDag-Erling Smørgrav free(p_tm); 169996e68c39SDag-Erling Smørgrav return (NULL); 170096e68c39SDag-Erling Smørgrav } 1701bc421551SDag-Erling Smørgrav } 1702bc421551SDag-Erling Smørgrav } 1703bc421551SDag-Erling Smørgrav return localtime_tzset(timep, p_tm, true); 1704bc421551SDag-Erling Smørgrav } 1705bc421551SDag-Erling Smørgrav 1706bc421551SDag-Erling Smørgrav struct tm * 170775411d15SDag-Erling Smørgrav localtime_r(const time_t *restrict timep, struct tm *restrict tmp) 1708bc421551SDag-Erling Smørgrav { 1709bc421551SDag-Erling Smørgrav return localtime_tzset(timep, tmp, false); 1710bc421551SDag-Erling Smørgrav } 1711bc421551SDag-Erling Smørgrav 1712bc421551SDag-Erling Smørgrav /* 1713bc421551SDag-Erling Smørgrav ** gmtsub is to gmtime as localsub is to localtime. 1714bc421551SDag-Erling Smørgrav */ 1715bc421551SDag-Erling Smørgrav 1716bc421551SDag-Erling Smørgrav static struct tm * 1717bc421551SDag-Erling Smørgrav gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, 1718bc421551SDag-Erling Smørgrav int_fast32_t offset, struct tm *tmp) 1719bc421551SDag-Erling Smørgrav { 1720bc421551SDag-Erling Smørgrav register struct tm * result; 1721bc421551SDag-Erling Smørgrav 1722bc421551SDag-Erling Smørgrav result = timesub(timep, offset, gmtptr, tmp); 1723bc421551SDag-Erling Smørgrav #ifdef TM_ZONE 1724bc421551SDag-Erling Smørgrav /* 1725bc421551SDag-Erling Smørgrav ** Could get fancy here and deliver something such as 1726bc421551SDag-Erling Smørgrav ** "+xx" or "-xx" if offset is non-zero, 1727bc421551SDag-Erling Smørgrav ** but this is no time for a treasure hunt. 1728bc421551SDag-Erling Smørgrav */ 1729bc421551SDag-Erling Smørgrav tmp->TM_ZONE = ((char *) 1730bc421551SDag-Erling Smørgrav (offset ? wildabbr : gmtptr ? gmtptr->chars : utc)); 1731bc421551SDag-Erling Smørgrav #endif /* defined TM_ZONE */ 1732bc421551SDag-Erling Smørgrav return result; 1733bc421551SDag-Erling Smørgrav } 1734bc421551SDag-Erling Smørgrav 1735bc421551SDag-Erling Smørgrav /* 1736bc421551SDag-Erling Smørgrav * Re-entrant version of gmtime. 1737bc421551SDag-Erling Smørgrav */ 1738bc421551SDag-Erling Smørgrav 1739bc421551SDag-Erling Smørgrav struct tm * 174075411d15SDag-Erling Smørgrav gmtime_r(time_t const *restrict timep, struct tm *restrict tmp) 1741bc421551SDag-Erling Smørgrav { 1742bc421551SDag-Erling Smørgrav _once(&gmt_once, gmtcheck); 1743bc421551SDag-Erling Smørgrav return gmtsub(gmtptr, timep, 0, tmp); 1744bc421551SDag-Erling Smørgrav } 1745bc421551SDag-Erling Smørgrav 1746bc421551SDag-Erling Smørgrav static void 1747bc421551SDag-Erling Smørgrav gmtime_key_init(void) 1748bc421551SDag-Erling Smørgrav { 1749bc421551SDag-Erling Smørgrav 1750bc421551SDag-Erling Smørgrav gmtime_key_error = _pthread_key_create(&gmtime_key, free); 1751bc421551SDag-Erling Smørgrav } 1752bc421551SDag-Erling Smørgrav 1753bc421551SDag-Erling Smørgrav struct tm * 1754bc421551SDag-Erling Smørgrav gmtime(const time_t *timep) 1755bc421551SDag-Erling Smørgrav { 175675411d15SDag-Erling Smørgrav #if !SUPPORT_C89 175775411d15SDag-Erling Smørgrav static struct tm tm; 175875411d15SDag-Erling Smørgrav #endif 1759bc421551SDag-Erling Smørgrav struct tm *p_tm = &tm; 1760bc421551SDag-Erling Smørgrav 1761bc421551SDag-Erling Smørgrav if (__isthreaded != 0) { 1762bc421551SDag-Erling Smørgrav _pthread_once(&gmtime_once, gmtime_key_init); 1763bc421551SDag-Erling Smørgrav if (gmtime_key_error != 0) { 1764bc421551SDag-Erling Smørgrav errno = gmtime_key_error; 1765bc421551SDag-Erling Smørgrav return (NULL); 1766bc421551SDag-Erling Smørgrav } 1767bc421551SDag-Erling Smørgrav if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { 1768bc421551SDag-Erling Smørgrav if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { 1769bc421551SDag-Erling Smørgrav return (NULL); 1770bc421551SDag-Erling Smørgrav } 177196e68c39SDag-Erling Smørgrav if (_pthread_setspecific(gmtime_key, p_tm) != 0) { 177296e68c39SDag-Erling Smørgrav free(p_tm); 177396e68c39SDag-Erling Smørgrav return (NULL); 177496e68c39SDag-Erling Smørgrav } 1775bc421551SDag-Erling Smørgrav } 1776bc421551SDag-Erling Smørgrav } 1777bc421551SDag-Erling Smørgrav return gmtime_r(timep, p_tm); 1778bc421551SDag-Erling Smørgrav } 1779bc421551SDag-Erling Smørgrav 178075411d15SDag-Erling Smørgrav #if STD_INSPIRED 178175411d15SDag-Erling Smørgrav 178246c59934SDag-Erling Smørgrav /* This function is obsolescent and may disappear in future releases. 178346c59934SDag-Erling Smørgrav Callers can instead use localtime_rz with a fixed-offset zone. */ 178446c59934SDag-Erling Smørgrav 178575411d15SDag-Erling Smørgrav struct tm * 178675411d15SDag-Erling Smørgrav offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp) 178775411d15SDag-Erling Smørgrav { 178875411d15SDag-Erling Smørgrav _once(&gmt_once, gmtcheck); 178975411d15SDag-Erling Smørgrav return gmtsub(gmtptr, timep, offset, tmp); 179075411d15SDag-Erling Smørgrav } 179175411d15SDag-Erling Smørgrav 179275411d15SDag-Erling Smørgrav static void 179375411d15SDag-Erling Smørgrav offtime_key_init(void) 179475411d15SDag-Erling Smørgrav { 179575411d15SDag-Erling Smørgrav 179675411d15SDag-Erling Smørgrav offtime_key_error = _pthread_key_create(&offtime_key, free); 179775411d15SDag-Erling Smørgrav } 1798bc421551SDag-Erling Smørgrav 1799bc421551SDag-Erling Smørgrav struct tm * 1800bc421551SDag-Erling Smørgrav offtime(const time_t *timep, long offset) 1801bc421551SDag-Erling Smørgrav { 180275411d15SDag-Erling Smørgrav #if !SUPPORT_C89 180375411d15SDag-Erling Smørgrav static struct tm tm; 180475411d15SDag-Erling Smørgrav #endif 180575411d15SDag-Erling Smørgrav struct tm *p_tm = &tm; 180675411d15SDag-Erling Smørgrav 180775411d15SDag-Erling Smørgrav if (__isthreaded != 0) { 180875411d15SDag-Erling Smørgrav _pthread_once(&offtime_once, offtime_key_init); 180975411d15SDag-Erling Smørgrav if (offtime_key_error != 0) { 181075411d15SDag-Erling Smørgrav errno = offtime_key_error; 181175411d15SDag-Erling Smørgrav return (NULL); 181275411d15SDag-Erling Smørgrav } 181375411d15SDag-Erling Smørgrav if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) { 181475411d15SDag-Erling Smørgrav if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { 181575411d15SDag-Erling Smørgrav return (NULL); 181675411d15SDag-Erling Smørgrav } 181775411d15SDag-Erling Smørgrav if (_pthread_setspecific(offtime_key, p_tm) != 0) { 181875411d15SDag-Erling Smørgrav free(p_tm); 181975411d15SDag-Erling Smørgrav return (NULL); 182075411d15SDag-Erling Smørgrav } 182175411d15SDag-Erling Smørgrav } 182275411d15SDag-Erling Smørgrav } 182375411d15SDag-Erling Smørgrav return offtime_r(timep, offset, p_tm); 1824bc421551SDag-Erling Smørgrav } 1825bc421551SDag-Erling Smørgrav 182675411d15SDag-Erling Smørgrav #endif 1827bc421551SDag-Erling Smørgrav 1828bc421551SDag-Erling Smørgrav /* 1829bc421551SDag-Erling Smørgrav ** Return the number of leap years through the end of the given year 1830bc421551SDag-Erling Smørgrav ** where, to make the math easy, the answer for year zero is defined as zero. 1831bc421551SDag-Erling Smørgrav */ 1832bc421551SDag-Erling Smørgrav 1833bc421551SDag-Erling Smørgrav static time_t 1834bc421551SDag-Erling Smørgrav leaps_thru_end_of_nonneg(time_t y) 1835bc421551SDag-Erling Smørgrav { 1836bc421551SDag-Erling Smørgrav return y / 4 - y / 100 + y / 400; 1837bc421551SDag-Erling Smørgrav } 1838bc421551SDag-Erling Smørgrav 1839bc421551SDag-Erling Smørgrav static time_t 1840bc421551SDag-Erling Smørgrav leaps_thru_end_of(time_t y) 1841bc421551SDag-Erling Smørgrav { 1842bc421551SDag-Erling Smørgrav return (y < 0 1843bc421551SDag-Erling Smørgrav ? -1 - leaps_thru_end_of_nonneg(-1 - y) 1844bc421551SDag-Erling Smørgrav : leaps_thru_end_of_nonneg(y)); 1845bc421551SDag-Erling Smørgrav } 1846bc421551SDag-Erling Smørgrav 1847bc421551SDag-Erling Smørgrav static struct tm * 1848bc421551SDag-Erling Smørgrav timesub(const time_t *timep, int_fast32_t offset, 1849bc421551SDag-Erling Smørgrav const struct state *sp, struct tm *tmp) 1850bc421551SDag-Erling Smørgrav { 1851bc421551SDag-Erling Smørgrav register const struct lsinfo * lp; 1852bc421551SDag-Erling Smørgrav register time_t tdays; 1853bc421551SDag-Erling Smørgrav register const int * ip; 1854bc421551SDag-Erling Smørgrav register int_fast32_t corr; 1855bc421551SDag-Erling Smørgrav register int i; 1856bc421551SDag-Erling Smørgrav int_fast32_t idays, rem, dayoff, dayrem; 1857bc421551SDag-Erling Smørgrav time_t y; 1858bc421551SDag-Erling Smørgrav 1859bc421551SDag-Erling Smørgrav /* If less than SECSPERMIN, the number of seconds since the 1860bc421551SDag-Erling Smørgrav most recent positive leap second; otherwise, do not add 1 1861bc421551SDag-Erling Smørgrav to localtime tm_sec because of leap seconds. */ 1862bc421551SDag-Erling Smørgrav time_t secs_since_posleap = SECSPERMIN; 1863bc421551SDag-Erling Smørgrav 1864bc421551SDag-Erling Smørgrav corr = 0; 1865bc421551SDag-Erling Smørgrav i = (sp == NULL) ? 0 : sp->leapcnt; 1866bc421551SDag-Erling Smørgrav while (--i >= 0) { 1867bc421551SDag-Erling Smørgrav lp = &sp->lsis[i]; 1868bc421551SDag-Erling Smørgrav if (*timep >= lp->ls_trans) { 1869bc421551SDag-Erling Smørgrav corr = lp->ls_corr; 1870bc421551SDag-Erling Smørgrav if ((i == 0 ? 0 : lp[-1].ls_corr) < corr) 1871bc421551SDag-Erling Smørgrav secs_since_posleap = *timep - lp->ls_trans; 1872bc421551SDag-Erling Smørgrav break; 1873bc421551SDag-Erling Smørgrav } 1874bc421551SDag-Erling Smørgrav } 1875bc421551SDag-Erling Smørgrav 1876bc421551SDag-Erling Smørgrav /* Calculate the year, avoiding integer overflow even if 1877bc421551SDag-Erling Smørgrav time_t is unsigned. */ 1878bc421551SDag-Erling Smørgrav tdays = *timep / SECSPERDAY; 1879bc421551SDag-Erling Smørgrav rem = *timep % SECSPERDAY; 1880bc421551SDag-Erling Smørgrav rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY; 1881bc421551SDag-Erling Smørgrav dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3; 1882bc421551SDag-Erling Smørgrav rem %= SECSPERDAY; 1883bc421551SDag-Erling Smørgrav /* y = (EPOCH_YEAR 1884bc421551SDag-Erling Smørgrav + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), 1885bc421551SDag-Erling Smørgrav sans overflow. But calculate against 1570 (EPOCH_YEAR - 1886bc421551SDag-Erling Smørgrav YEARSPERREPEAT) instead of against 1970 so that things work 1887bc421551SDag-Erling Smørgrav for localtime values before 1970 when time_t is unsigned. */ 1888bc421551SDag-Erling Smørgrav dayrem = tdays % DAYSPERREPEAT; 1889bc421551SDag-Erling Smørgrav dayrem += dayoff % DAYSPERREPEAT; 1890bc421551SDag-Erling Smørgrav y = (EPOCH_YEAR - YEARSPERREPEAT 1891bc421551SDag-Erling Smørgrav + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT 1892bc421551SDag-Erling Smørgrav - ((dayrem % DAYSPERREPEAT) < 0) 1893bc421551SDag-Erling Smørgrav + tdays / DAYSPERREPEAT) 1894bc421551SDag-Erling Smørgrav * YEARSPERREPEAT)); 1895bc421551SDag-Erling Smørgrav /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */ 1896bc421551SDag-Erling Smørgrav idays = tdays % DAYSPERREPEAT; 1897bc421551SDag-Erling Smørgrav idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT; 1898bc421551SDag-Erling Smørgrav idays %= DAYSPERREPEAT; 1899bc421551SDag-Erling Smørgrav /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */ 1900bc421551SDag-Erling Smørgrav while (year_lengths[isleap(y)] <= idays) { 1901bc421551SDag-Erling Smørgrav int tdelta = idays / DAYSPERLYEAR; 1902bc421551SDag-Erling Smørgrav int_fast32_t ydelta = tdelta + !tdelta; 1903bc421551SDag-Erling Smørgrav time_t newy = y + ydelta; 1904bc421551SDag-Erling Smørgrav register int leapdays; 1905bc421551SDag-Erling Smørgrav leapdays = leaps_thru_end_of(newy - 1) - 1906bc421551SDag-Erling Smørgrav leaps_thru_end_of(y - 1); 1907bc421551SDag-Erling Smørgrav idays -= ydelta * DAYSPERNYEAR; 1908bc421551SDag-Erling Smørgrav idays -= leapdays; 1909bc421551SDag-Erling Smørgrav y = newy; 1910bc421551SDag-Erling Smørgrav } 1911bc421551SDag-Erling Smørgrav 1912bc421551SDag-Erling Smørgrav #ifdef ckd_add 1913bc421551SDag-Erling Smørgrav if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) { 1914bc421551SDag-Erling Smørgrav errno = EOVERFLOW; 1915bc421551SDag-Erling Smørgrav return NULL; 1916bc421551SDag-Erling Smørgrav } 1917bc421551SDag-Erling Smørgrav #else 1918bc421551SDag-Erling Smørgrav if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) { 1919bc421551SDag-Erling Smørgrav int signed_y = y; 1920bc421551SDag-Erling Smørgrav tmp->tm_year = signed_y - TM_YEAR_BASE; 1921bc421551SDag-Erling Smørgrav } else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y) 1922bc421551SDag-Erling Smørgrav && y - TM_YEAR_BASE <= INT_MAX) 1923bc421551SDag-Erling Smørgrav tmp->tm_year = y - TM_YEAR_BASE; 1924bc421551SDag-Erling Smørgrav else { 1925bc421551SDag-Erling Smørgrav errno = EOVERFLOW; 1926bc421551SDag-Erling Smørgrav return NULL; 1927bc421551SDag-Erling Smørgrav } 1928bc421551SDag-Erling Smørgrav #endif 1929bc421551SDag-Erling Smørgrav tmp->tm_yday = idays; 1930bc421551SDag-Erling Smørgrav /* 1931bc421551SDag-Erling Smørgrav ** The "extra" mods below avoid overflow problems. 1932bc421551SDag-Erling Smørgrav */ 1933bc421551SDag-Erling Smørgrav tmp->tm_wday = (TM_WDAY_BASE 1934bc421551SDag-Erling Smørgrav + ((tmp->tm_year % DAYSPERWEEK) 1935bc421551SDag-Erling Smørgrav * (DAYSPERNYEAR % DAYSPERWEEK)) 1936bc421551SDag-Erling Smørgrav + leaps_thru_end_of(y - 1) 1937bc421551SDag-Erling Smørgrav - leaps_thru_end_of(TM_YEAR_BASE - 1) 1938bc421551SDag-Erling Smørgrav + idays); 1939bc421551SDag-Erling Smørgrav tmp->tm_wday %= DAYSPERWEEK; 1940bc421551SDag-Erling Smørgrav if (tmp->tm_wday < 0) 1941bc421551SDag-Erling Smørgrav tmp->tm_wday += DAYSPERWEEK; 1942bc421551SDag-Erling Smørgrav tmp->tm_hour = rem / SECSPERHOUR; 1943bc421551SDag-Erling Smørgrav rem %= SECSPERHOUR; 1944bc421551SDag-Erling Smørgrav tmp->tm_min = rem / SECSPERMIN; 1945bc421551SDag-Erling Smørgrav tmp->tm_sec = rem % SECSPERMIN; 1946bc421551SDag-Erling Smørgrav 1947bc421551SDag-Erling Smørgrav /* Use "... ??:??:60" at the end of the localtime minute containing 1948bc421551SDag-Erling Smørgrav the second just before the positive leap second. */ 1949bc421551SDag-Erling Smørgrav tmp->tm_sec += secs_since_posleap <= tmp->tm_sec; 1950bc421551SDag-Erling Smørgrav 1951bc421551SDag-Erling Smørgrav ip = mon_lengths[isleap(y)]; 1952bc421551SDag-Erling Smørgrav for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) 1953bc421551SDag-Erling Smørgrav idays -= ip[tmp->tm_mon]; 1954bc421551SDag-Erling Smørgrav tmp->tm_mday = idays + 1; 1955bc421551SDag-Erling Smørgrav tmp->tm_isdst = 0; 1956bc421551SDag-Erling Smørgrav #ifdef TM_GMTOFF 1957bc421551SDag-Erling Smørgrav tmp->TM_GMTOFF = offset; 1958bc421551SDag-Erling Smørgrav #endif /* defined TM_GMTOFF */ 1959bc421551SDag-Erling Smørgrav return tmp; 1960bc421551SDag-Erling Smørgrav } 1961bc421551SDag-Erling Smørgrav 1962bc421551SDag-Erling Smørgrav /* 1963bc421551SDag-Erling Smørgrav ** Adapted from code provided by Robert Elz, who writes: 1964bc421551SDag-Erling Smørgrav ** The "best" way to do mktime I think is based on an idea of Bob 1965bc421551SDag-Erling Smørgrav ** Kridle's (so its said...) from a long time ago. 1966bc421551SDag-Erling Smørgrav ** It does a binary search of the time_t space. Since time_t's are 1967bc421551SDag-Erling Smørgrav ** just 32 bits, its a max of 32 iterations (even at 64 bits it 1968bc421551SDag-Erling Smørgrav ** would still be very reasonable). 1969bc421551SDag-Erling Smørgrav */ 1970bc421551SDag-Erling Smørgrav 1971bc421551SDag-Erling Smørgrav #ifndef WRONG 1972bc421551SDag-Erling Smørgrav # define WRONG (-1) 1973bc421551SDag-Erling Smørgrav #endif /* !defined WRONG */ 1974bc421551SDag-Erling Smørgrav 1975bc421551SDag-Erling Smørgrav /* 1976bc421551SDag-Erling Smørgrav ** Normalize logic courtesy Paul Eggert. 1977bc421551SDag-Erling Smørgrav */ 1978bc421551SDag-Erling Smørgrav 1979bc421551SDag-Erling Smørgrav static bool 1980bc421551SDag-Erling Smørgrav increment_overflow(int *ip, int j) 1981bc421551SDag-Erling Smørgrav { 1982bc421551SDag-Erling Smørgrav #ifdef ckd_add 1983bc421551SDag-Erling Smørgrav return ckd_add(ip, *ip, j); 1984bc421551SDag-Erling Smørgrav #else 1985bc421551SDag-Erling Smørgrav register int const i = *ip; 1986bc421551SDag-Erling Smørgrav 1987bc421551SDag-Erling Smørgrav /* 1988bc421551SDag-Erling Smørgrav ** If i >= 0 there can only be overflow if i + j > INT_MAX 1989bc421551SDag-Erling Smørgrav ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow. 1990bc421551SDag-Erling Smørgrav ** If i < 0 there can only be overflow if i + j < INT_MIN 1991bc421551SDag-Erling Smørgrav ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow. 1992bc421551SDag-Erling Smørgrav */ 1993bc421551SDag-Erling Smørgrav if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) 1994bc421551SDag-Erling Smørgrav return true; 1995bc421551SDag-Erling Smørgrav *ip += j; 1996bc421551SDag-Erling Smørgrav return false; 1997bc421551SDag-Erling Smørgrav #endif 1998bc421551SDag-Erling Smørgrav } 1999bc421551SDag-Erling Smørgrav 2000bc421551SDag-Erling Smørgrav static bool 2001bc421551SDag-Erling Smørgrav increment_overflow32(int_fast32_t *const lp, int const m) 2002bc421551SDag-Erling Smørgrav { 2003bc421551SDag-Erling Smørgrav #ifdef ckd_add 2004bc421551SDag-Erling Smørgrav return ckd_add(lp, *lp, m); 2005bc421551SDag-Erling Smørgrav #else 2006bc421551SDag-Erling Smørgrav register int_fast32_t const l = *lp; 2007bc421551SDag-Erling Smørgrav 2008bc421551SDag-Erling Smørgrav if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) 2009bc421551SDag-Erling Smørgrav return true; 2010bc421551SDag-Erling Smørgrav *lp += m; 2011bc421551SDag-Erling Smørgrav return false; 2012bc421551SDag-Erling Smørgrav #endif 2013bc421551SDag-Erling Smørgrav } 2014bc421551SDag-Erling Smørgrav 2015bc421551SDag-Erling Smørgrav static bool 2016bc421551SDag-Erling Smørgrav increment_overflow_time(time_t *tp, int_fast32_t j) 2017bc421551SDag-Erling Smørgrav { 2018bc421551SDag-Erling Smørgrav #ifdef ckd_add 2019bc421551SDag-Erling Smørgrav return ckd_add(tp, *tp, j); 2020bc421551SDag-Erling Smørgrav #else 2021bc421551SDag-Erling Smørgrav /* 2022bc421551SDag-Erling Smørgrav ** This is like 2023bc421551SDag-Erling Smørgrav ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...', 2024bc421551SDag-Erling Smørgrav ** except that it does the right thing even if *tp + j would overflow. 2025bc421551SDag-Erling Smørgrav */ 2026bc421551SDag-Erling Smørgrav if (! (j < 0 2027bc421551SDag-Erling Smørgrav ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp) 2028bc421551SDag-Erling Smørgrav : *tp <= TIME_T_MAX - j)) 2029bc421551SDag-Erling Smørgrav return true; 2030bc421551SDag-Erling Smørgrav *tp += j; 2031bc421551SDag-Erling Smørgrav return false; 2032bc421551SDag-Erling Smørgrav #endif 2033bc421551SDag-Erling Smørgrav } 2034bc421551SDag-Erling Smørgrav 2035bc421551SDag-Erling Smørgrav static bool 2036bc421551SDag-Erling Smørgrav normalize_overflow(int *const tensptr, int *const unitsptr, const int base) 2037bc421551SDag-Erling Smørgrav { 2038bc421551SDag-Erling Smørgrav register int tensdelta; 2039bc421551SDag-Erling Smørgrav 2040bc421551SDag-Erling Smørgrav tensdelta = (*unitsptr >= 0) ? 2041bc421551SDag-Erling Smørgrav (*unitsptr / base) : 2042bc421551SDag-Erling Smørgrav (-1 - (-1 - *unitsptr) / base); 2043bc421551SDag-Erling Smørgrav *unitsptr -= tensdelta * base; 2044bc421551SDag-Erling Smørgrav return increment_overflow(tensptr, tensdelta); 2045bc421551SDag-Erling Smørgrav } 2046bc421551SDag-Erling Smørgrav 2047bc421551SDag-Erling Smørgrav static bool 2048bc421551SDag-Erling Smørgrav normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base) 2049bc421551SDag-Erling Smørgrav { 2050bc421551SDag-Erling Smørgrav register int tensdelta; 2051bc421551SDag-Erling Smørgrav 2052bc421551SDag-Erling Smørgrav tensdelta = (*unitsptr >= 0) ? 2053bc421551SDag-Erling Smørgrav (*unitsptr / base) : 2054bc421551SDag-Erling Smørgrav (-1 - (-1 - *unitsptr) / base); 2055bc421551SDag-Erling Smørgrav *unitsptr -= tensdelta * base; 2056bc421551SDag-Erling Smørgrav return increment_overflow32(tensptr, tensdelta); 2057bc421551SDag-Erling Smørgrav } 2058bc421551SDag-Erling Smørgrav 2059bc421551SDag-Erling Smørgrav static int 2060bc421551SDag-Erling Smørgrav tmcomp(register const struct tm *const atmp, 2061bc421551SDag-Erling Smørgrav register const struct tm *const btmp) 2062bc421551SDag-Erling Smørgrav { 2063bc421551SDag-Erling Smørgrav register int result; 2064bc421551SDag-Erling Smørgrav 2065bc421551SDag-Erling Smørgrav if (atmp->tm_year != btmp->tm_year) 2066bc421551SDag-Erling Smørgrav return atmp->tm_year < btmp->tm_year ? -1 : 1; 2067bc421551SDag-Erling Smørgrav if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && 2068bc421551SDag-Erling Smørgrav (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && 2069bc421551SDag-Erling Smørgrav (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && 2070bc421551SDag-Erling Smørgrav (result = (atmp->tm_min - btmp->tm_min)) == 0) 2071bc421551SDag-Erling Smørgrav result = atmp->tm_sec - btmp->tm_sec; 2072bc421551SDag-Erling Smørgrav return result; 2073bc421551SDag-Erling Smørgrav } 2074bc421551SDag-Erling Smørgrav 2075bc421551SDag-Erling Smørgrav /* Copy to *DEST from *SRC. Copy only the members needed for mktime, 2076bc421551SDag-Erling Smørgrav as other members might not be initialized. */ 2077bc421551SDag-Erling Smørgrav static void 2078bc421551SDag-Erling Smørgrav mktmcpy(struct tm *dest, struct tm const *src) 2079bc421551SDag-Erling Smørgrav { 2080bc421551SDag-Erling Smørgrav dest->tm_sec = src->tm_sec; 2081bc421551SDag-Erling Smørgrav dest->tm_min = src->tm_min; 2082bc421551SDag-Erling Smørgrav dest->tm_hour = src->tm_hour; 2083bc421551SDag-Erling Smørgrav dest->tm_mday = src->tm_mday; 2084bc421551SDag-Erling Smørgrav dest->tm_mon = src->tm_mon; 2085bc421551SDag-Erling Smørgrav dest->tm_year = src->tm_year; 2086bc421551SDag-Erling Smørgrav dest->tm_isdst = src->tm_isdst; 2087bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF && ! UNINIT_TRAP 2088bc421551SDag-Erling Smørgrav dest->TM_GMTOFF = src->TM_GMTOFF; 2089bc421551SDag-Erling Smørgrav #endif 2090bc421551SDag-Erling Smørgrav } 2091bc421551SDag-Erling Smørgrav 2092bc421551SDag-Erling Smørgrav static time_t 2093bc421551SDag-Erling Smørgrav time2sub(struct tm *const tmp, 2094bc421551SDag-Erling Smørgrav struct tm *(*funcp)(struct state const *, time_t const *, 2095bc421551SDag-Erling Smørgrav int_fast32_t, struct tm *), 2096bc421551SDag-Erling Smørgrav struct state const *sp, 2097bc421551SDag-Erling Smørgrav const int_fast32_t offset, 2098bc421551SDag-Erling Smørgrav bool *okayp, 2099bc421551SDag-Erling Smørgrav bool do_norm_secs) 2100bc421551SDag-Erling Smørgrav { 2101bc421551SDag-Erling Smørgrav register int dir; 2102bc421551SDag-Erling Smørgrav register int i, j; 2103bc421551SDag-Erling Smørgrav register int saved_seconds; 2104bc421551SDag-Erling Smørgrav register int_fast32_t li; 2105bc421551SDag-Erling Smørgrav register time_t lo; 2106bc421551SDag-Erling Smørgrav register time_t hi; 2107bc421551SDag-Erling Smørgrav int_fast32_t y; 2108bc421551SDag-Erling Smørgrav time_t newt; 2109bc421551SDag-Erling Smørgrav time_t t; 2110bc421551SDag-Erling Smørgrav struct tm yourtm, mytm; 2111bc421551SDag-Erling Smørgrav 2112bc421551SDag-Erling Smørgrav *okayp = false; 2113bc421551SDag-Erling Smørgrav mktmcpy(&yourtm, tmp); 2114bc421551SDag-Erling Smørgrav 2115bc421551SDag-Erling Smørgrav if (do_norm_secs) { 2116bc421551SDag-Erling Smørgrav if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, 2117bc421551SDag-Erling Smørgrav SECSPERMIN)) 2118bc421551SDag-Erling Smørgrav return WRONG; 2119bc421551SDag-Erling Smørgrav } 2120bc421551SDag-Erling Smørgrav if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) 2121bc421551SDag-Erling Smørgrav return WRONG; 2122bc421551SDag-Erling Smørgrav if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) 2123bc421551SDag-Erling Smørgrav return WRONG; 2124bc421551SDag-Erling Smørgrav y = yourtm.tm_year; 2125bc421551SDag-Erling Smørgrav if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR)) 2126bc421551SDag-Erling Smørgrav return WRONG; 2127bc421551SDag-Erling Smørgrav /* 2128bc421551SDag-Erling Smørgrav ** Turn y into an actual year number for now. 2129bc421551SDag-Erling Smørgrav ** It is converted back to an offset from TM_YEAR_BASE later. 2130bc421551SDag-Erling Smørgrav */ 2131bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, TM_YEAR_BASE)) 2132bc421551SDag-Erling Smørgrav return WRONG; 2133bc421551SDag-Erling Smørgrav while (yourtm.tm_mday <= 0) { 2134bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, -1)) 2135bc421551SDag-Erling Smørgrav return WRONG; 2136bc421551SDag-Erling Smørgrav li = y + (1 < yourtm.tm_mon); 2137bc421551SDag-Erling Smørgrav yourtm.tm_mday += year_lengths[isleap(li)]; 2138bc421551SDag-Erling Smørgrav } 2139bc421551SDag-Erling Smørgrav while (yourtm.tm_mday > DAYSPERLYEAR) { 2140bc421551SDag-Erling Smørgrav li = y + (1 < yourtm.tm_mon); 2141bc421551SDag-Erling Smørgrav yourtm.tm_mday -= year_lengths[isleap(li)]; 2142bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, 1)) 2143bc421551SDag-Erling Smørgrav return WRONG; 2144bc421551SDag-Erling Smørgrav } 2145bc421551SDag-Erling Smørgrav for ( ; ; ) { 2146bc421551SDag-Erling Smørgrav i = mon_lengths[isleap(y)][yourtm.tm_mon]; 2147bc421551SDag-Erling Smørgrav if (yourtm.tm_mday <= i) 2148bc421551SDag-Erling Smørgrav break; 2149bc421551SDag-Erling Smørgrav yourtm.tm_mday -= i; 2150bc421551SDag-Erling Smørgrav if (++yourtm.tm_mon >= MONSPERYEAR) { 2151bc421551SDag-Erling Smørgrav yourtm.tm_mon = 0; 2152bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, 1)) 2153bc421551SDag-Erling Smørgrav return WRONG; 2154bc421551SDag-Erling Smørgrav } 2155bc421551SDag-Erling Smørgrav } 2156bc421551SDag-Erling Smørgrav #ifdef ckd_add 2157bc421551SDag-Erling Smørgrav if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE)) 2158bc421551SDag-Erling Smørgrav return WRONG; 2159bc421551SDag-Erling Smørgrav #else 2160bc421551SDag-Erling Smørgrav if (increment_overflow32(&y, -TM_YEAR_BASE)) 2161bc421551SDag-Erling Smørgrav return WRONG; 2162bc421551SDag-Erling Smørgrav if (! (INT_MIN <= y && y <= INT_MAX)) 2163bc421551SDag-Erling Smørgrav return WRONG; 2164bc421551SDag-Erling Smørgrav yourtm.tm_year = y; 2165bc421551SDag-Erling Smørgrav #endif 2166bc421551SDag-Erling Smørgrav if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) 2167bc421551SDag-Erling Smørgrav saved_seconds = 0; 2168bc421551SDag-Erling Smørgrav else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) { 2169bc421551SDag-Erling Smørgrav /* 2170bc421551SDag-Erling Smørgrav ** We can't set tm_sec to 0, because that might push the 2171bc421551SDag-Erling Smørgrav ** time below the minimum representable time. 2172bc421551SDag-Erling Smørgrav ** Set tm_sec to 59 instead. 2173bc421551SDag-Erling Smørgrav ** This assumes that the minimum representable time is 2174bc421551SDag-Erling Smørgrav ** not in the same minute that a leap second was deleted from, 2175bc421551SDag-Erling Smørgrav ** which is a safer assumption than using 58 would be. 2176bc421551SDag-Erling Smørgrav */ 2177bc421551SDag-Erling Smørgrav if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) 2178bc421551SDag-Erling Smørgrav return WRONG; 2179bc421551SDag-Erling Smørgrav saved_seconds = yourtm.tm_sec; 2180bc421551SDag-Erling Smørgrav yourtm.tm_sec = SECSPERMIN - 1; 2181bc421551SDag-Erling Smørgrav } else { 2182bc421551SDag-Erling Smørgrav saved_seconds = yourtm.tm_sec; 2183bc421551SDag-Erling Smørgrav yourtm.tm_sec = 0; 2184bc421551SDag-Erling Smørgrav } 2185bc421551SDag-Erling Smørgrav /* 2186bc421551SDag-Erling Smørgrav ** Do a binary search (this works whatever time_t's type is). 2187bc421551SDag-Erling Smørgrav */ 2188bc421551SDag-Erling Smørgrav lo = TIME_T_MIN; 2189bc421551SDag-Erling Smørgrav hi = TIME_T_MAX; 2190bc421551SDag-Erling Smørgrav for ( ; ; ) { 2191bc421551SDag-Erling Smørgrav t = lo / 2 + hi / 2; 2192bc421551SDag-Erling Smørgrav if (t < lo) 2193bc421551SDag-Erling Smørgrav t = lo; 2194bc421551SDag-Erling Smørgrav else if (t > hi) 2195bc421551SDag-Erling Smørgrav t = hi; 2196bc421551SDag-Erling Smørgrav if (! funcp(sp, &t, offset, &mytm)) { 2197bc421551SDag-Erling Smørgrav /* 2198bc421551SDag-Erling Smørgrav ** Assume that t is too extreme to be represented in 2199bc421551SDag-Erling Smørgrav ** a struct tm; arrange things so that it is less 2200bc421551SDag-Erling Smørgrav ** extreme on the next pass. 2201bc421551SDag-Erling Smørgrav */ 2202bc421551SDag-Erling Smørgrav dir = (t > 0) ? 1 : -1; 2203bc421551SDag-Erling Smørgrav } else dir = tmcomp(&mytm, &yourtm); 2204bc421551SDag-Erling Smørgrav if (dir != 0) { 2205bc421551SDag-Erling Smørgrav if (t == lo) { 2206bc421551SDag-Erling Smørgrav if (t == TIME_T_MAX) 2207bc421551SDag-Erling Smørgrav return WRONG; 2208bc421551SDag-Erling Smørgrav ++t; 2209bc421551SDag-Erling Smørgrav ++lo; 2210bc421551SDag-Erling Smørgrav } else if (t == hi) { 2211bc421551SDag-Erling Smørgrav if (t == TIME_T_MIN) 2212bc421551SDag-Erling Smørgrav return WRONG; 2213bc421551SDag-Erling Smørgrav --t; 2214bc421551SDag-Erling Smørgrav --hi; 2215bc421551SDag-Erling Smørgrav } 2216bc421551SDag-Erling Smørgrav if (lo > hi) 2217bc421551SDag-Erling Smørgrav return WRONG; 2218bc421551SDag-Erling Smørgrav if (dir > 0) 2219bc421551SDag-Erling Smørgrav hi = t; 2220bc421551SDag-Erling Smørgrav else lo = t; 2221bc421551SDag-Erling Smørgrav continue; 2222bc421551SDag-Erling Smørgrav } 2223bc421551SDag-Erling Smørgrav #if defined TM_GMTOFF && ! UNINIT_TRAP 2224bc421551SDag-Erling Smørgrav if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF 2225bc421551SDag-Erling Smørgrav && (yourtm.TM_GMTOFF < 0 2226bc421551SDag-Erling Smørgrav ? (-SECSPERDAY <= yourtm.TM_GMTOFF 2227bc421551SDag-Erling Smørgrav && (mytm.TM_GMTOFF <= 2228bc421551SDag-Erling Smørgrav (min(INT_FAST32_MAX, LONG_MAX) 2229bc421551SDag-Erling Smørgrav + yourtm.TM_GMTOFF))) 2230bc421551SDag-Erling Smørgrav : (yourtm.TM_GMTOFF <= SECSPERDAY 2231bc421551SDag-Erling Smørgrav && ((max(INT_FAST32_MIN, LONG_MIN) 2232bc421551SDag-Erling Smørgrav + yourtm.TM_GMTOFF) 2233bc421551SDag-Erling Smørgrav <= mytm.TM_GMTOFF)))) { 2234bc421551SDag-Erling Smørgrav /* MYTM matches YOURTM except with the wrong UT offset. 2235bc421551SDag-Erling Smørgrav YOURTM.TM_GMTOFF is plausible, so try it instead. 2236bc421551SDag-Erling Smørgrav It's OK if YOURTM.TM_GMTOFF contains uninitialized data, 2237bc421551SDag-Erling Smørgrav since the guess gets checked. */ 2238bc421551SDag-Erling Smørgrav time_t altt = t; 2239bc421551SDag-Erling Smørgrav int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF; 2240bc421551SDag-Erling Smørgrav if (!increment_overflow_time(&altt, diff)) { 2241bc421551SDag-Erling Smørgrav struct tm alttm; 2242bc421551SDag-Erling Smørgrav if (funcp(sp, &altt, offset, &alttm) 2243bc421551SDag-Erling Smørgrav && alttm.tm_isdst == mytm.tm_isdst 2244bc421551SDag-Erling Smørgrav && alttm.TM_GMTOFF == yourtm.TM_GMTOFF 2245bc421551SDag-Erling Smørgrav && tmcomp(&alttm, &yourtm) == 0) { 2246bc421551SDag-Erling Smørgrav t = altt; 2247bc421551SDag-Erling Smørgrav mytm = alttm; 2248bc421551SDag-Erling Smørgrav } 2249bc421551SDag-Erling Smørgrav } 2250bc421551SDag-Erling Smørgrav } 2251bc421551SDag-Erling Smørgrav #endif 2252bc421551SDag-Erling Smørgrav if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) 2253bc421551SDag-Erling Smørgrav break; 2254bc421551SDag-Erling Smørgrav /* 2255bc421551SDag-Erling Smørgrav ** Right time, wrong type. 2256bc421551SDag-Erling Smørgrav ** Hunt for right time, right type. 2257bc421551SDag-Erling Smørgrav ** It's okay to guess wrong since the guess 2258bc421551SDag-Erling Smørgrav ** gets checked. 2259bc421551SDag-Erling Smørgrav */ 2260bc421551SDag-Erling Smørgrav if (sp == NULL) 2261bc421551SDag-Erling Smørgrav return WRONG; 2262bc421551SDag-Erling Smørgrav for (i = sp->typecnt - 1; i >= 0; --i) { 2263bc421551SDag-Erling Smørgrav if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) 2264bc421551SDag-Erling Smørgrav continue; 2265bc421551SDag-Erling Smørgrav for (j = sp->typecnt - 1; j >= 0; --j) { 2266bc421551SDag-Erling Smørgrav if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) 2267bc421551SDag-Erling Smørgrav continue; 2268bc421551SDag-Erling Smørgrav if (ttunspecified(sp, j)) 2269bc421551SDag-Erling Smørgrav continue; 2270bc421551SDag-Erling Smørgrav newt = (t + sp->ttis[j].tt_utoff 2271bc421551SDag-Erling Smørgrav - sp->ttis[i].tt_utoff); 2272bc421551SDag-Erling Smørgrav if (! funcp(sp, &newt, offset, &mytm)) 2273bc421551SDag-Erling Smørgrav continue; 2274bc421551SDag-Erling Smørgrav if (tmcomp(&mytm, &yourtm) != 0) 2275bc421551SDag-Erling Smørgrav continue; 2276bc421551SDag-Erling Smørgrav if (mytm.tm_isdst != yourtm.tm_isdst) 2277bc421551SDag-Erling Smørgrav continue; 2278bc421551SDag-Erling Smørgrav /* 2279bc421551SDag-Erling Smørgrav ** We have a match. 2280bc421551SDag-Erling Smørgrav */ 2281bc421551SDag-Erling Smørgrav t = newt; 2282bc421551SDag-Erling Smørgrav goto label; 2283bc421551SDag-Erling Smørgrav } 2284bc421551SDag-Erling Smørgrav } 2285bc421551SDag-Erling Smørgrav return WRONG; 2286bc421551SDag-Erling Smørgrav } 2287bc421551SDag-Erling Smørgrav label: 2288bc421551SDag-Erling Smørgrav newt = t + saved_seconds; 2289bc421551SDag-Erling Smørgrav if ((newt < t) != (saved_seconds < 0)) 2290bc421551SDag-Erling Smørgrav return WRONG; 2291bc421551SDag-Erling Smørgrav t = newt; 2292bc421551SDag-Erling Smørgrav if (funcp(sp, &t, offset, tmp)) 2293bc421551SDag-Erling Smørgrav *okayp = true; 2294bc421551SDag-Erling Smørgrav return t; 2295bc421551SDag-Erling Smørgrav } 2296bc421551SDag-Erling Smørgrav 2297bc421551SDag-Erling Smørgrav static time_t 2298bc421551SDag-Erling Smørgrav time2(struct tm * const tmp, 2299bc421551SDag-Erling Smørgrav struct tm *(*funcp)(struct state const *, time_t const *, 2300bc421551SDag-Erling Smørgrav int_fast32_t, struct tm *), 2301bc421551SDag-Erling Smørgrav struct state const *sp, 2302bc421551SDag-Erling Smørgrav const int_fast32_t offset, 2303bc421551SDag-Erling Smørgrav bool *okayp) 2304bc421551SDag-Erling Smørgrav { 2305bc421551SDag-Erling Smørgrav time_t t; 2306bc421551SDag-Erling Smørgrav 2307bc421551SDag-Erling Smørgrav /* 2308bc421551SDag-Erling Smørgrav ** First try without normalization of seconds 2309bc421551SDag-Erling Smørgrav ** (in case tm_sec contains a value associated with a leap second). 2310bc421551SDag-Erling Smørgrav ** If that fails, try with normalization of seconds. 2311bc421551SDag-Erling Smørgrav */ 2312bc421551SDag-Erling Smørgrav t = time2sub(tmp, funcp, sp, offset, okayp, false); 2313bc421551SDag-Erling Smørgrav return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true); 2314bc421551SDag-Erling Smørgrav } 2315bc421551SDag-Erling Smørgrav 2316bc421551SDag-Erling Smørgrav static time_t 2317bc421551SDag-Erling Smørgrav time1(struct tm *const tmp, 2318bc421551SDag-Erling Smørgrav struct tm *(*funcp)(struct state const *, time_t const *, 2319bc421551SDag-Erling Smørgrav int_fast32_t, struct tm *), 2320bc421551SDag-Erling Smørgrav struct state const *sp, 2321bc421551SDag-Erling Smørgrav const int_fast32_t offset) 2322bc421551SDag-Erling Smørgrav { 2323bc421551SDag-Erling Smørgrav register time_t t; 2324bc421551SDag-Erling Smørgrav register int samei, otheri; 2325bc421551SDag-Erling Smørgrav register int sameind, otherind; 2326bc421551SDag-Erling Smørgrav register int i; 2327bc421551SDag-Erling Smørgrav register int nseen; 2328bc421551SDag-Erling Smørgrav char seen[TZ_MAX_TYPES]; 2329bc421551SDag-Erling Smørgrav unsigned char types[TZ_MAX_TYPES]; 2330bc421551SDag-Erling Smørgrav bool okay; 2331bc421551SDag-Erling Smørgrav 2332bc421551SDag-Erling Smørgrav if (tmp == NULL) { 2333bc421551SDag-Erling Smørgrav errno = EINVAL; 2334bc421551SDag-Erling Smørgrav return WRONG; 2335bc421551SDag-Erling Smørgrav } 2336bc421551SDag-Erling Smørgrav 2337bc421551SDag-Erling Smørgrav if (tmp->tm_isdst > 1) 2338bc421551SDag-Erling Smørgrav tmp->tm_isdst = 1; 2339bc421551SDag-Erling Smørgrav t = time2(tmp, funcp, sp, offset, &okay); 2340bc421551SDag-Erling Smørgrav if (okay) 2341bc421551SDag-Erling Smørgrav return t; 2342bc421551SDag-Erling Smørgrav if (tmp->tm_isdst < 0) 2343bc421551SDag-Erling Smørgrav #ifdef PCTS 2344bc421551SDag-Erling Smørgrav /* 2345bc421551SDag-Erling Smørgrav ** POSIX Conformance Test Suite code courtesy Grant Sullivan. 2346bc421551SDag-Erling Smørgrav */ 2347bc421551SDag-Erling Smørgrav tmp->tm_isdst = 0; /* reset to std and try again */ 2348bc421551SDag-Erling Smørgrav #else 2349bc421551SDag-Erling Smørgrav return t; 2350bc421551SDag-Erling Smørgrav #endif /* !defined PCTS */ 2351bc421551SDag-Erling Smørgrav /* 2352bc421551SDag-Erling Smørgrav ** We're supposed to assume that somebody took a time of one type 2353bc421551SDag-Erling Smørgrav ** and did some math on it that yielded a "struct tm" that's bad. 2354bc421551SDag-Erling Smørgrav ** We try to divine the type they started from and adjust to the 2355bc421551SDag-Erling Smørgrav ** type they need. 2356bc421551SDag-Erling Smørgrav */ 2357bc421551SDag-Erling Smørgrav if (sp == NULL) 2358bc421551SDag-Erling Smørgrav return WRONG; 2359bc421551SDag-Erling Smørgrav for (i = 0; i < sp->typecnt; ++i) 2360bc421551SDag-Erling Smørgrav seen[i] = false; 2361bc421551SDag-Erling Smørgrav nseen = 0; 2362bc421551SDag-Erling Smørgrav for (i = sp->timecnt - 1; i >= 0; --i) 2363bc421551SDag-Erling Smørgrav if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) { 2364bc421551SDag-Erling Smørgrav seen[sp->types[i]] = true; 2365bc421551SDag-Erling Smørgrav types[nseen++] = sp->types[i]; 2366bc421551SDag-Erling Smørgrav } 2367bc421551SDag-Erling Smørgrav for (sameind = 0; sameind < nseen; ++sameind) { 2368bc421551SDag-Erling Smørgrav samei = types[sameind]; 2369bc421551SDag-Erling Smørgrav if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) 2370bc421551SDag-Erling Smørgrav continue; 2371bc421551SDag-Erling Smørgrav for (otherind = 0; otherind < nseen; ++otherind) { 2372bc421551SDag-Erling Smørgrav otheri = types[otherind]; 2373bc421551SDag-Erling Smørgrav if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) 2374bc421551SDag-Erling Smørgrav continue; 2375bc421551SDag-Erling Smørgrav tmp->tm_sec += (sp->ttis[otheri].tt_utoff 2376bc421551SDag-Erling Smørgrav - sp->ttis[samei].tt_utoff); 2377bc421551SDag-Erling Smørgrav tmp->tm_isdst = !tmp->tm_isdst; 2378bc421551SDag-Erling Smørgrav t = time2(tmp, funcp, sp, offset, &okay); 2379bc421551SDag-Erling Smørgrav if (okay) 2380bc421551SDag-Erling Smørgrav return t; 2381bc421551SDag-Erling Smørgrav tmp->tm_sec -= (sp->ttis[otheri].tt_utoff 2382bc421551SDag-Erling Smørgrav - sp->ttis[samei].tt_utoff); 2383bc421551SDag-Erling Smørgrav tmp->tm_isdst = !tmp->tm_isdst; 2384bc421551SDag-Erling Smørgrav } 2385bc421551SDag-Erling Smørgrav } 2386bc421551SDag-Erling Smørgrav return WRONG; 2387bc421551SDag-Erling Smørgrav } 2388bc421551SDag-Erling Smørgrav 2389bc421551SDag-Erling Smørgrav static time_t 2390bc421551SDag-Erling Smørgrav mktime_tzname(struct state *sp, struct tm *tmp, bool setname) 2391bc421551SDag-Erling Smørgrav { 2392bc421551SDag-Erling Smørgrav if (sp) 2393bc421551SDag-Erling Smørgrav return time1(tmp, localsub, sp, setname); 2394bc421551SDag-Erling Smørgrav else { 2395bc421551SDag-Erling Smørgrav _once(&gmt_once, gmtcheck); 2396bc421551SDag-Erling Smørgrav return time1(tmp, gmtsub, gmtptr, 0); 2397bc421551SDag-Erling Smørgrav } 2398bc421551SDag-Erling Smørgrav } 2399bc421551SDag-Erling Smørgrav 2400bc421551SDag-Erling Smørgrav #if NETBSD_INSPIRED 2401bc421551SDag-Erling Smørgrav 2402bc421551SDag-Erling Smørgrav time_t 240375411d15SDag-Erling Smørgrav mktime_z(struct state *restrict sp, struct tm *restrict tmp) 2404bc421551SDag-Erling Smørgrav { 2405bc421551SDag-Erling Smørgrav return mktime_tzname(sp, tmp, false); 2406bc421551SDag-Erling Smørgrav } 2407bc421551SDag-Erling Smørgrav 2408bc421551SDag-Erling Smørgrav #endif 2409bc421551SDag-Erling Smørgrav 2410bc421551SDag-Erling Smørgrav time_t 2411bc421551SDag-Erling Smørgrav mktime(struct tm *tmp) 2412bc421551SDag-Erling Smørgrav { 2413bc421551SDag-Erling Smørgrav time_t t; 2414bc421551SDag-Erling Smørgrav int err = lock(); 2415bc421551SDag-Erling Smørgrav if (err) { 2416bc421551SDag-Erling Smørgrav errno = err; 2417bc421551SDag-Erling Smørgrav return -1; 2418bc421551SDag-Erling Smørgrav } 2419bc421551SDag-Erling Smørgrav tzset_unlocked(); 2420bc421551SDag-Erling Smørgrav t = mktime_tzname(lclptr, tmp, true); 2421bc421551SDag-Erling Smørgrav unlock(); 2422bc421551SDag-Erling Smørgrav return t; 2423bc421551SDag-Erling Smørgrav } 2424bc421551SDag-Erling Smørgrav 242575411d15SDag-Erling Smørgrav #if STD_INSPIRED 2426*a979394aSDag-Erling Smørgrav /* This function is obsolescent and may disappear in future releases. 242746c59934SDag-Erling Smørgrav Callers can instead use mktime. */ 2428bc421551SDag-Erling Smørgrav time_t 2429bc421551SDag-Erling Smørgrav timelocal(struct tm *tmp) 2430bc421551SDag-Erling Smørgrav { 2431bc421551SDag-Erling Smørgrav if (tmp != NULL) 2432bc421551SDag-Erling Smørgrav tmp->tm_isdst = -1; /* in case it wasn't initialized */ 2433bc421551SDag-Erling Smørgrav return mktime(tmp); 2434bc421551SDag-Erling Smørgrav } 2435bc421551SDag-Erling Smørgrav #endif 243646c59934SDag-Erling Smørgrav 243746c59934SDag-Erling Smørgrav #ifndef EXTERN_TIMEOFF 243846c59934SDag-Erling Smørgrav # ifndef timeoff 243946c59934SDag-Erling Smørgrav # define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */ 244046c59934SDag-Erling Smørgrav # endif 244146c59934SDag-Erling Smørgrav # define EXTERN_TIMEOFF static 244246c59934SDag-Erling Smørgrav #endif 244346c59934SDag-Erling Smørgrav 2444*a979394aSDag-Erling Smørgrav /* This function is obsolescent and may disappear in future releases. 244546c59934SDag-Erling Smørgrav Callers can instead use mktime_z with a fixed-offset zone. */ 244646c59934SDag-Erling Smørgrav EXTERN_TIMEOFF time_t 2447bc421551SDag-Erling Smørgrav timeoff(struct tm *tmp, long offset) 2448bc421551SDag-Erling Smørgrav { 2449bc421551SDag-Erling Smørgrav if (tmp) 2450bc421551SDag-Erling Smørgrav tmp->tm_isdst = 0; 2451bc421551SDag-Erling Smørgrav _once(&gmt_once, gmtcheck); 2452bc421551SDag-Erling Smørgrav return time1(tmp, gmtsub, gmtptr, offset); 2453bc421551SDag-Erling Smørgrav } 2454bc421551SDag-Erling Smørgrav 2455bc421551SDag-Erling Smørgrav time_t 2456bc421551SDag-Erling Smørgrav timegm(struct tm *tmp) 2457bc421551SDag-Erling Smørgrav { 2458bc421551SDag-Erling Smørgrav time_t t; 2459bc421551SDag-Erling Smørgrav struct tm tmcpy; 2460bc421551SDag-Erling Smørgrav mktmcpy(&tmcpy, tmp); 2461bc421551SDag-Erling Smørgrav tmcpy.tm_wday = -1; 2462bc421551SDag-Erling Smørgrav t = timeoff(&tmcpy, 0); 2463bc421551SDag-Erling Smørgrav if (0 <= tmcpy.tm_wday) 2464bc421551SDag-Erling Smørgrav *tmp = tmcpy; 2465bc421551SDag-Erling Smørgrav return t; 2466bc421551SDag-Erling Smørgrav } 2467bc421551SDag-Erling Smørgrav 2468bc421551SDag-Erling Smørgrav static int_fast32_t 2469bc421551SDag-Erling Smørgrav leapcorr(struct state const *sp, time_t t) 2470bc421551SDag-Erling Smørgrav { 2471bc421551SDag-Erling Smørgrav register struct lsinfo const * lp; 2472bc421551SDag-Erling Smørgrav register int i; 2473bc421551SDag-Erling Smørgrav 2474bc421551SDag-Erling Smørgrav i = sp->leapcnt; 2475bc421551SDag-Erling Smørgrav while (--i >= 0) { 2476bc421551SDag-Erling Smørgrav lp = &sp->lsis[i]; 2477bc421551SDag-Erling Smørgrav if (t >= lp->ls_trans) 2478bc421551SDag-Erling Smørgrav return lp->ls_corr; 2479bc421551SDag-Erling Smørgrav } 2480bc421551SDag-Erling Smørgrav return 0; 2481bc421551SDag-Erling Smørgrav } 2482bc421551SDag-Erling Smørgrav 2483bc421551SDag-Erling Smørgrav /* 2484bc421551SDag-Erling Smørgrav ** XXX--is the below the right way to conditionalize?? 2485bc421551SDag-Erling Smørgrav */ 2486bc421551SDag-Erling Smørgrav 248775411d15SDag-Erling Smørgrav #if STD_INSPIRED 2488bc421551SDag-Erling Smørgrav 2489bc421551SDag-Erling Smørgrav /* NETBSD_INSPIRED_EXTERN functions are exported to callers if 2490bc421551SDag-Erling Smørgrav NETBSD_INSPIRED is defined, and are private otherwise. */ 2491bc421551SDag-Erling Smørgrav # if NETBSD_INSPIRED 2492bc421551SDag-Erling Smørgrav # define NETBSD_INSPIRED_EXTERN 2493bc421551SDag-Erling Smørgrav # else 2494bc421551SDag-Erling Smørgrav # define NETBSD_INSPIRED_EXTERN static 2495bc421551SDag-Erling Smørgrav # endif 2496bc421551SDag-Erling Smørgrav 2497bc421551SDag-Erling Smørgrav /* 2498bc421551SDag-Erling Smørgrav ** IEEE Std 1003.1 (POSIX) says that 536457599 2499bc421551SDag-Erling Smørgrav ** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which 2500bc421551SDag-Erling Smørgrav ** is not the case if we are accounting for leap seconds. 2501bc421551SDag-Erling Smørgrav ** So, we provide the following conversion routines for use 2502bc421551SDag-Erling Smørgrav ** when exchanging timestamps with POSIX conforming systems. 2503bc421551SDag-Erling Smørgrav */ 2504bc421551SDag-Erling Smørgrav 2505bc421551SDag-Erling Smørgrav NETBSD_INSPIRED_EXTERN time_t 2506bc421551SDag-Erling Smørgrav time2posix_z(struct state *sp, time_t t) 2507bc421551SDag-Erling Smørgrav { 2508bc421551SDag-Erling Smørgrav return t - leapcorr(sp, t); 2509bc421551SDag-Erling Smørgrav } 2510bc421551SDag-Erling Smørgrav 2511bc421551SDag-Erling Smørgrav time_t 2512bc421551SDag-Erling Smørgrav time2posix(time_t t) 2513bc421551SDag-Erling Smørgrav { 2514bc421551SDag-Erling Smørgrav int err = lock(); 2515bc421551SDag-Erling Smørgrav if (err) { 2516bc421551SDag-Erling Smørgrav errno = err; 2517bc421551SDag-Erling Smørgrav return -1; 2518bc421551SDag-Erling Smørgrav } 2519bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES 2520bc421551SDag-Erling Smørgrav if (!lcl_is_set) 2521bc421551SDag-Erling Smørgrav #endif 2522bc421551SDag-Erling Smørgrav tzset_unlocked(); 2523bc421551SDag-Erling Smørgrav if (lclptr) 2524bc421551SDag-Erling Smørgrav t = time2posix_z(lclptr, t); 2525bc421551SDag-Erling Smørgrav unlock(); 2526bc421551SDag-Erling Smørgrav return t; 2527bc421551SDag-Erling Smørgrav } 2528bc421551SDag-Erling Smørgrav 2529bc421551SDag-Erling Smørgrav NETBSD_INSPIRED_EXTERN time_t 2530bc421551SDag-Erling Smørgrav posix2time_z(struct state *sp, time_t t) 2531bc421551SDag-Erling Smørgrav { 2532bc421551SDag-Erling Smørgrav time_t x; 2533bc421551SDag-Erling Smørgrav time_t y; 2534bc421551SDag-Erling Smørgrav /* 2535bc421551SDag-Erling Smørgrav ** For a positive leap second hit, the result 2536bc421551SDag-Erling Smørgrav ** is not unique. For a negative leap second 2537bc421551SDag-Erling Smørgrav ** hit, the corresponding time doesn't exist, 2538bc421551SDag-Erling Smørgrav ** so we return an adjacent second. 2539bc421551SDag-Erling Smørgrav */ 2540bc421551SDag-Erling Smørgrav x = t + leapcorr(sp, t); 2541bc421551SDag-Erling Smørgrav y = x - leapcorr(sp, x); 2542bc421551SDag-Erling Smørgrav if (y < t) { 2543bc421551SDag-Erling Smørgrav do { 2544bc421551SDag-Erling Smørgrav x++; 2545bc421551SDag-Erling Smørgrav y = x - leapcorr(sp, x); 2546bc421551SDag-Erling Smørgrav } while (y < t); 2547bc421551SDag-Erling Smørgrav x -= y != t; 2548bc421551SDag-Erling Smørgrav } else if (y > t) { 2549bc421551SDag-Erling Smørgrav do { 2550bc421551SDag-Erling Smørgrav --x; 2551bc421551SDag-Erling Smørgrav y = x - leapcorr(sp, x); 2552bc421551SDag-Erling Smørgrav } while (y > t); 2553bc421551SDag-Erling Smørgrav x += y != t; 2554bc421551SDag-Erling Smørgrav } 2555bc421551SDag-Erling Smørgrav return x; 2556bc421551SDag-Erling Smørgrav } 2557bc421551SDag-Erling Smørgrav 2558bc421551SDag-Erling Smørgrav time_t 2559bc421551SDag-Erling Smørgrav posix2time(time_t t) 2560bc421551SDag-Erling Smørgrav { 2561bc421551SDag-Erling Smørgrav int err = lock(); 2562bc421551SDag-Erling Smørgrav if (err) { 2563bc421551SDag-Erling Smørgrav errno = err; 2564bc421551SDag-Erling Smørgrav return -1; 2565bc421551SDag-Erling Smørgrav } 2566bc421551SDag-Erling Smørgrav #ifndef DETECT_TZ_CHANGES 2567bc421551SDag-Erling Smørgrav if (!lcl_is_set) 2568bc421551SDag-Erling Smørgrav #endif 2569bc421551SDag-Erling Smørgrav tzset_unlocked(); 2570bc421551SDag-Erling Smørgrav if (lclptr) 2571bc421551SDag-Erling Smørgrav t = posix2time_z(lclptr, t); 2572bc421551SDag-Erling Smørgrav unlock(); 2573bc421551SDag-Erling Smørgrav return t; 2574bc421551SDag-Erling Smørgrav } 2575bc421551SDag-Erling Smørgrav 257675411d15SDag-Erling Smørgrav #endif /* STD_INSPIRED */ 2577bc421551SDag-Erling Smørgrav 2578bc421551SDag-Erling Smørgrav #if TZ_TIME_T 2579bc421551SDag-Erling Smørgrav 2580bc421551SDag-Erling Smørgrav # if !USG_COMPAT 2581bc421551SDag-Erling Smørgrav # define daylight 0 2582bc421551SDag-Erling Smørgrav # define timezone 0 2583bc421551SDag-Erling Smørgrav # endif 2584bc421551SDag-Erling Smørgrav # if !ALTZONE 2585bc421551SDag-Erling Smørgrav # define altzone 0 2586bc421551SDag-Erling Smørgrav # endif 2587bc421551SDag-Erling Smørgrav 2588bc421551SDag-Erling Smørgrav /* Convert from the underlying system's time_t to the ersatz time_tz, 2589bc421551SDag-Erling Smørgrav which is called 'time_t' in this file. Typically, this merely 2590bc421551SDag-Erling Smørgrav converts the time's integer width. On some platforms, the system 2591bc421551SDag-Erling Smørgrav time is local time not UT, or uses some epoch other than the POSIX 2592bc421551SDag-Erling Smørgrav epoch. 2593bc421551SDag-Erling Smørgrav 2594bc421551SDag-Erling Smørgrav Although this code appears to define a function named 'time' that 2595bc421551SDag-Erling Smørgrav returns time_t, the macros in private.h cause this code to actually 2596bc421551SDag-Erling Smørgrav define a function named 'tz_time' that returns tz_time_t. The call 2597bc421551SDag-Erling Smørgrav to sys_time invokes the underlying system's 'time' function. */ 2598bc421551SDag-Erling Smørgrav 2599bc421551SDag-Erling Smørgrav time_t 2600bc421551SDag-Erling Smørgrav time(time_t *p) 2601bc421551SDag-Erling Smørgrav { 2602bc421551SDag-Erling Smørgrav time_t r = sys_time(0); 2603bc421551SDag-Erling Smørgrav if (r != (time_t) -1) { 2604bc421551SDag-Erling Smørgrav int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0; 2605bc421551SDag-Erling Smørgrav if (increment_overflow32(&offset, -EPOCH_OFFSET) 2606bc421551SDag-Erling Smørgrav || increment_overflow_time(&r, offset)) { 2607bc421551SDag-Erling Smørgrav errno = EOVERFLOW; 2608bc421551SDag-Erling Smørgrav r = -1; 2609bc421551SDag-Erling Smørgrav } 2610bc421551SDag-Erling Smørgrav } 2611bc421551SDag-Erling Smørgrav if (p) 2612bc421551SDag-Erling Smørgrav *p = r; 2613bc421551SDag-Erling Smørgrav return r; 2614bc421551SDag-Erling Smørgrav } 2615bc421551SDag-Erling Smørgrav 2616bc421551SDag-Erling Smørgrav #endif 2617