xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Copyright (C) 1991-2016 Free Software Foundation, Inc. |
| 2 | This file is part of the GNU C Library. |
| 3 | |
| 4 | The GNU C Library is free software; you can redistribute it and/or |
| 5 | modify it under the terms of the GNU Lesser General Public |
| 6 | License as published by the Free Software Foundation; either |
| 7 | version 2.1 of the License, or (at your option) any later version. |
| 8 | |
| 9 | The GNU C Library is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | Lesser General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU Lesser General Public |
| 15 | License along with the GNU C Library; if not, see |
| 16 | <http://www.gnu.org/licenses/>. */ |
| 17 | |
| 18 | #include <ctype.h> |
| 19 | #include <errno.h> |
| 20 | #include <libc-lock.h> |
| 21 | #include <stdbool.h> |
| 22 | #include <stddef.h> |
| 23 | #include <stdio.h> |
| 24 | #include <stdlib.h> |
| 25 | #include <string.h> |
| 26 | #include <time.h> |
| 27 | |
| 28 | |
| 29 | #define NOID |
| 30 | #include <timezone/tzfile.h> |
| 31 | |
| 32 | char *__tzname[2] = { (char *) "GMT", (char *) "GMT" }; |
| 33 | int __daylight = 0; |
| 34 | long int __timezone = 0L; |
| 35 | |
| 36 | weak_alias (__tzname, tzname) |
| 37 | weak_alias (__daylight, daylight) |
| 38 | weak_alias (__timezone, timezone) |
| 39 | |
| 40 | /* This locks all the state variables in tzfile.c and this file. */ |
| 41 | __libc_lock_define_initialized (static, tzset_lock) |
| 42 | |
| 43 | |
| 44 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
| 45 | #define max(a, b) ((a) > (b) ? (a) : (b)) |
| 46 | #define sign(x) ((x) < 0 ? -1 : 1) |
| 47 | |
| 48 | |
| 49 | /* This structure contains all the information about a |
| 50 | timezone given in the POSIX standard TZ envariable. */ |
| 51 | typedef struct |
| 52 | { |
| 53 | const char *name; |
| 54 | |
| 55 | /* When to change. */ |
| 56 | enum { J0, J1, M } type; /* Interpretation of: */ |
| 57 | unsigned short int m, n, d; /* Month, week, day. */ |
| 58 | int secs; /* Time of day. */ |
| 59 | |
| 60 | long int offset; /* Seconds east of GMT (west if < 0). */ |
| 61 | |
| 62 | /* We cache the computed time of change for a |
| 63 | given year so we don't have to recompute it. */ |
| 64 | time_t change; /* When to change to this zone. */ |
| 65 | int computed_for; /* Year above is computed for. */ |
| 66 | } tz_rule; |
| 67 | |
| 68 | /* tz_rules[0] is standard, tz_rules[1] is daylight. */ |
| 69 | static tz_rule tz_rules[2]; |
| 70 | |
| 71 | |
| 72 | static void compute_change (tz_rule *rule, int year) __THROW internal_function; |
| 73 | static void tzset_internal (int always, int explicit) |
| 74 | __THROW internal_function; |
| 75 | |
| 76 | /* List of buffers containing time zone strings. */ |
| 77 | struct tzstring_l |
| 78 | { |
| 79 | struct tzstring_l *next; |
| 80 | size_t len; /* strlen(data) - doesn't count terminating NUL! */ |
| 81 | char data[0]; |
| 82 | }; |
| 83 | |
| 84 | static struct tzstring_l *tzstring_list; |
| 85 | |
| 86 | /* Allocate a permanent home for the first LEN characters of S. It |
| 87 | will never be moved or deallocated, but may share space with other |
| 88 | strings. Don't modify the returned string. */ |
| 89 | static char * |
| 90 | __tzstring_len (const char *s, size_t len) |
| 91 | { |
| 92 | char *p; |
| 93 | struct tzstring_l *t, *u, *new; |
| 94 | |
| 95 | /* Walk the list and look for a match. If this string is the same |
| 96 | as the end of an already-allocated string, it can share space. */ |
| 97 | for (u = t = tzstring_list; t; u = t, t = t->next) |
| 98 | if (len <= t->len) |
| 99 | { |
| 100 | p = &t->data[t->len - len]; |
| 101 | if (memcmp (s, p, len) == 0) |
| 102 | return p; |
| 103 | } |
| 104 | |
| 105 | /* Not found; allocate a new buffer. */ |
| 106 | new = malloc (sizeof (struct tzstring_l) + len + 1); |
| 107 | if (!new) |
| 108 | return NULL; |
| 109 | |
| 110 | new->next = NULL; |
| 111 | new->len = len; |
| 112 | memcpy (new->data, s, len); |
| 113 | new->data[len] = '\0'; |
| 114 | |
| 115 | if (u) |
| 116 | u->next = new; |
| 117 | else |
| 118 | tzstring_list = new; |
| 119 | |
| 120 | return new->data; |
| 121 | } |
| 122 | |
| 123 | /* Allocate a permanent home for S. It will never be moved or |
| 124 | deallocated, but may share space with other strings. Don't modify |
| 125 | the returned string. */ |
| 126 | char * |
| 127 | __tzstring (const char *s) |
| 128 | { |
| 129 | return __tzstring_len (s, strlen (s)); |
| 130 | } |
| 131 | |
| 132 | /* Maximum length of a timezone name. tzset_internal keeps this up to date |
| 133 | (never decreasing it) when ! __use_tzfile. |
| 134 | tzfile.c keeps it up to date when __use_tzfile. */ |
| 135 | size_t __tzname_cur_max; |
| 136 | |
| 137 | long int |
| 138 | __tzname_max (void) |
| 139 | { |
| 140 | __libc_lock_lock (tzset_lock); |
| 141 | |
| 142 | tzset_internal (0, 0); |
| 143 | |
| 144 | __libc_lock_unlock (tzset_lock); |
| 145 | |
| 146 | return __tzname_cur_max; |
| 147 | } |
| 148 | |
| 149 | static char *old_tz; |
| 150 | |
| 151 | static void |
| 152 | internal_function |
| 153 | update_vars (void) |
| 154 | { |
| 155 | __daylight = tz_rules[0].offset != tz_rules[1].offset; |
| 156 | __timezone = -tz_rules[0].offset; |
| 157 | __tzname[0] = (char *) tz_rules[0].name; |
| 158 | __tzname[1] = (char *) tz_rules[1].name; |
| 159 | |
| 160 | /* Keep __tzname_cur_max up to date. */ |
| 161 | size_t len0 = strlen (__tzname[0]); |
| 162 | size_t len1 = strlen (__tzname[1]); |
| 163 | if (len0 > __tzname_cur_max) |
| 164 | __tzname_cur_max = len0; |
| 165 | if (len1 > __tzname_cur_max) |
| 166 | __tzname_cur_max = len1; |
| 167 | } |
| 168 | |
| 169 | |
| 170 | static unsigned int |
| 171 | __attribute_noinline__ |
| 172 | compute_offset (unsigned int ss, unsigned int mm, unsigned int hh) |
| 173 | { |
| 174 | return min (ss, 59) + min (mm, 59) * 60 + min (hh, 24) * 60 * 60; |
| 175 | } |
| 176 | |
| 177 | /* Parses the time zone name at *TZP, and writes a pointer to an |
| 178 | interned string to tz_rules[WHICHRULE].name. On success, advances |
| 179 | *TZP, and returns true. Returns false otherwise. */ |
| 180 | static bool |
| 181 | parse_tzname (const char **tzp, int whichrule) |
| 182 | { |
| 183 | const char *start = *tzp; |
| 184 | const char *p = start; |
| 185 | while (('a' <= *p && *p <= 'z') |
| 186 | || ('A' <= *p && *p <= 'Z')) |
| 187 | ++p; |
| 188 | size_t len = p - start; |
| 189 | if (len < 3) |
| 190 | { |
| 191 | p = *tzp; |
| 192 | if (__glibc_unlikely (*p++ != '<')) |
| 193 | return false; |
| 194 | start = p; |
| 195 | while (('a' <= *p && *p <= 'z') |
| 196 | || ('A' <= *p && *p <= 'Z') |
| 197 | || ('0' <= *p && *p <= '9') |
| 198 | || *p == '+' || *p == '-') |
| 199 | ++p; |
| 200 | len = p - start; |
| 201 | if (*p++ != '>' || len < 3) |
| 202 | return false; |
| 203 | } |
| 204 | |
| 205 | const char *name = __tzstring_len (start, len); |
| 206 | if (name == NULL) |
| 207 | return false; |
| 208 | tz_rules[whichrule].name = name; |
| 209 | |
| 210 | *tzp = p; |
| 211 | return true; |
| 212 | } |
| 213 | |
| 214 | /* Parses the time zone offset at *TZP, and writes it to |
| 215 | tz_rules[WHICHRULE].offset. Returns true if the parse was |
| 216 | successful. */ |
| 217 | static bool |
| 218 | parse_offset (const char **tzp, int whichrule) |
| 219 | { |
| 220 | const char *tz = *tzp; |
| 221 | if (whichrule == 0 |
| 222 | && (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))) |
| 223 | return false; |
| 224 | |
| 225 | long sign; |
| 226 | if (*tz == '-' || *tz == '+') |
| 227 | sign = *tz++ == '-' ? 1L : -1L; |
| 228 | else |
| 229 | sign = -1L; |
| 230 | *tzp = tz; |
| 231 | |
| 232 | unsigned short int hh; |
| 233 | unsigned short mm = 0; |
| 234 | unsigned short ss = 0; |
| 235 | int consumed = 0; |
| 236 | if (sscanf (tz, "%hu%n:%hu%n:%hu%n", |
| 237 | &hh, &consumed, &mm, &consumed, &ss, &consumed) > 0) |
| 238 | tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh); |
| 239 | else |
| 240 | /* Nothing could be parsed. */ |
| 241 | if (whichrule == 0) |
| 242 | { |
| 243 | /* Standard time defaults to offset zero. */ |
| 244 | tz_rules[0].offset = 0; |
| 245 | return false; |
| 246 | } |
| 247 | else |
| 248 | /* DST defaults to one hour later than standard time. */ |
| 249 | tz_rules[1].offset = tz_rules[0].offset + (60 * 60); |
| 250 | *tzp = tz + consumed; |
| 251 | return true; |
| 252 | } |
| 253 | |
| 254 | /* Parses the standard <-> DST rules at *TZP. Updates |
| 255 | tz_rule[WHICHRULE]. On success, advances *TZP and returns true. |
| 256 | Otherwise, returns false. */ |
| 257 | static bool |
| 258 | parse_rule (const char **tzp, int whichrule) |
| 259 | { |
| 260 | const char *tz = *tzp; |
| 261 | tz_rule *tzr = &tz_rules[whichrule]; |
| 262 | |
| 263 | /* Ignore comma to support string following the incorrect |
| 264 | specification in early POSIX.1 printings. */ |
| 265 | tz += *tz == ','; |
| 266 | |
| 267 | /* Get the date of the change. */ |
| 268 | if (*tz == 'J' || isdigit (*tz)) |
| 269 | { |
| 270 | char *end; |
| 271 | tzr->type = *tz == 'J' ? J1 : J0; |
| 272 | if (tzr->type == J1 && !isdigit (*++tz)) |
| 273 | return false; |
| 274 | unsigned long int d = strtoul (tz, &end, 10); |
| 275 | if (end == tz || d > 365) |
| 276 | return false; |
| 277 | if (tzr->type == J1 && d == 0) |
| 278 | return false; |
| 279 | tzr->d = d; |
| 280 | tz = end; |
| 281 | } |
| 282 | else if (*tz == 'M') |
| 283 | { |
| 284 | tzr->type = M; |
| 285 | int consumed; |
| 286 | if (sscanf (tz, "M%hu.%hu.%hu%n", |
| 287 | &tzr->m, &tzr->n, &tzr->d, &consumed) != 3 |
| 288 | || tzr->m < 1 || tzr->m > 12 |
| 289 | || tzr->n < 1 || tzr->n > 5 || tzr->d > 6) |
| 290 | return false; |
| 291 | tz += consumed; |
| 292 | } |
| 293 | else if (*tz == '\0') |
| 294 | { |
| 295 | /* Daylight time rules in the U.S. are defined in the U.S. Code, |
| 296 | Title 15, Chapter 6, Subchapter IX - Standard Time. These |
| 297 | dates were established by Congress in the Energy Policy Act |
| 298 | of 2005 [Pub. L. no. 109-58, 119 Stat 594 (2005)]. |
| 299 | Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed |
| 300 | since 2:00AM is the default]. */ |
| 301 | tzr->type = M; |
| 302 | if (tzr == &tz_rules[0]) |
| 303 | { |
| 304 | tzr->m = 3; |
| 305 | tzr->n = 2; |
| 306 | tzr->d = 0; |
| 307 | } |
| 308 | else |
| 309 | { |
| 310 | tzr->m = 11; |
| 311 | tzr->n = 1; |
| 312 | tzr->d = 0; |
| 313 | } |
| 314 | } |
| 315 | else |
| 316 | return false; |
| 317 | |
| 318 | if (*tz != '\0' && *tz != '/' && *tz != ',') |
| 319 | return false; |
| 320 | else if (*tz == '/') |
| 321 | { |
| 322 | /* Get the time of day of the change. */ |
| 323 | int negative; |
| 324 | ++tz; |
| 325 | if (*tz == '\0') |
| 326 | return false; |
| 327 | negative = *tz == '-'; |
| 328 | tz += negative; |
| 329 | /* Default to 2:00 AM. */ |
| 330 | unsigned short hh = 2; |
| 331 | unsigned short mm = 0; |
| 332 | unsigned short ss = 0; |
| 333 | int consumed = 0; |
| 334 | sscanf (tz, "%hu%n:%hu%n:%hu%n", |
| 335 | &hh, &consumed, &mm, &consumed, &ss, &consumed);; |
| 336 | tz += consumed; |
| 337 | tzr->secs = (negative ? -1 : 1) * ((hh * 60 * 60) + (mm * 60) + ss); |
| 338 | } |
| 339 | else |
| 340 | /* Default to 2:00 AM. */ |
| 341 | tzr->secs = 2 * 60 * 60; |
| 342 | |
| 343 | tzr->computed_for = -1; |
| 344 | *tzp = tz; |
| 345 | return true; |
| 346 | } |
| 347 | |
| 348 | /* Parse the POSIX TZ-style string. */ |
| 349 | void |
| 350 | __tzset_parse_tz (const char *tz) |
| 351 | { |
| 352 | /* Clear out old state and reset to unnamed UTC. */ |
| 353 | memset (tz_rules, '\0', sizeof tz_rules); |
| 354 | tz_rules[0].name = tz_rules[1].name = ""; |
| 355 | |
| 356 | /* Get the standard timezone name. */ |
| 357 | if (parse_tzname (&tz, 0) && parse_offset (&tz, 0)) |
| 358 | { |
| 359 | /* Get the DST timezone name (if any). */ |
| 360 | if (*tz != '\0') |
| 361 | { |
| 362 | if (parse_tzname (&tz, 1)) |
| 363 | { |
| 364 | parse_offset (&tz, 1); |
| 365 | if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0')) |
| 366 | { |
| 367 | /* There is no rule. See if there is a default rule |
| 368 | file. */ |
| 369 | __tzfile_default (tz_rules[0].name, tz_rules[1].name, |
| 370 | tz_rules[0].offset, tz_rules[1].offset); |
| 371 | if (__use_tzfile) |
| 372 | { |
| 373 | free (old_tz); |
| 374 | old_tz = NULL; |
| 375 | return; |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | /* Figure out the standard <-> DST rules. */ |
| 380 | if (parse_rule (&tz, 0)) |
| 381 | parse_rule (&tz, 1); |
| 382 | } |
| 383 | else |
| 384 | { |
| 385 | /* There is no DST. */ |
| 386 | tz_rules[1].name = tz_rules[0].name; |
| 387 | tz_rules[1].offset = tz_rules[0].offset; |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | update_vars (); |
| 392 | } |
| 393 | |
| 394 | /* Interpret the TZ envariable. */ |
| 395 | static void |
| 396 | internal_function |
| 397 | tzset_internal (int always, int explicit) |
| 398 | { |
| 399 | static int is_initialized; |
| 400 | const char *tz; |
| 401 | |
| 402 | if (is_initialized && !always) |
| 403 | return; |
| 404 | is_initialized = 1; |
| 405 | |
| 406 | /* Examine the TZ environment variable. */ |
| 407 | tz = getenv ("TZ"); |
| 408 | if (tz == NULL && !explicit) |
| 409 | /* Use the site-wide default. This is a file name which means we |
| 410 | would not see changes to the file if we compare only the file |
| 411 | name for change. We want to notice file changes if tzset() has |
| 412 | been called explicitly. Leave TZ as NULL in this case. */ |
| 413 | tz = TZDEFAULT; |
| 414 | if (tz && *tz == '\0') |
| 415 | /* User specified the empty string; use UTC explicitly. */ |
| 416 | tz = "Universal"; |
| 417 | |
| 418 | /* A leading colon means "implementation defined syntax". |
| 419 | We ignore the colon and always use the same algorithm: |
| 420 | try a data file, and if none exists parse the 1003.1 syntax. */ |
| 421 | if (tz && *tz == ':') |
| 422 | ++tz; |
| 423 | |
| 424 | /* Check whether the value changed since the last run. */ |
| 425 | if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0) |
| 426 | /* No change, simply return. */ |
| 427 | return; |
| 428 | |
| 429 | if (tz == NULL) |
| 430 | /* No user specification; use the site-wide default. */ |
| 431 | tz = TZDEFAULT; |
| 432 | |
| 433 | tz_rules[0].name = NULL; |
| 434 | tz_rules[1].name = NULL; |
| 435 | |
| 436 | /* Save the value of `tz'. */ |
| 437 | free (old_tz); |
| 438 | old_tz = tz ? __strdup (tz) : NULL; |
| 439 | |
| 440 | /* Try to read a data file. */ |
| 441 | __tzfile_read (tz, 0, NULL); |
| 442 | if (__use_tzfile) |
| 443 | return; |
| 444 | |
| 445 | /* No data file found. Default to UTC if nothing specified. */ |
| 446 | |
| 447 | if (tz == NULL || *tz == '\0' |
| 448 | || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0)) |
| 449 | { |
| 450 | memset (tz_rules, '\0', sizeof tz_rules); |
| 451 | tz_rules[0].name = tz_rules[1].name = "UTC"; |
| 452 | if (J0 != 0) |
| 453 | tz_rules[0].type = tz_rules[1].type = J0; |
| 454 | tz_rules[0].change = tz_rules[1].change = (time_t) -1; |
| 455 | update_vars (); |
| 456 | return; |
| 457 | } |
| 458 | |
| 459 | __tzset_parse_tz (tz); |
| 460 | } |
| 461 | |
| 462 | /* Figure out the exact time (as a time_t) in YEAR |
| 463 | when the change described by RULE will occur and |
| 464 | put it in RULE->change, saving YEAR in RULE->computed_for. */ |
| 465 | static void |
| 466 | internal_function |
| 467 | compute_change (tz_rule *rule, int year) |
| 468 | { |
| 469 | time_t t; |
| 470 | |
| 471 | if (year != -1 && rule->computed_for == year) |
| 472 | /* Operations on times in 2 BC will be slower. Oh well. */ |
| 473 | return; |
| 474 | |
| 475 | /* First set T to January 1st, 0:00:00 GMT in YEAR. */ |
| 476 | if (year > 1970) |
| 477 | t = ((year - 1970) * 365 |
| 478 | + /* Compute the number of leapdays between 1970 and YEAR |
| 479 | (exclusive). There is a leapday every 4th year ... */ |
| 480 | + ((year - 1) / 4 - 1970 / 4) |
| 481 | /* ... except every 100th year ... */ |
| 482 | - ((year - 1) / 100 - 1970 / 100) |
| 483 | /* ... but still every 400th year. */ |
| 484 | + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY; |
| 485 | else |
| 486 | t = 0; |
| 487 | |
| 488 | switch (rule->type) |
| 489 | { |
| 490 | case J1: |
| 491 | /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years. |
| 492 | In non-leap years, or if the day number is 59 or less, just |
| 493 | add SECSPERDAY times the day number-1 to the time of |
| 494 | January 1, midnight, to get the day. */ |
| 495 | t += (rule->d - 1) * SECSPERDAY; |
| 496 | if (rule->d >= 60 && __isleap (year)) |
| 497 | t += SECSPERDAY; |
| 498 | break; |
| 499 | |
| 500 | case J0: |
| 501 | /* n - Day of year. |
| 502 | Just add SECSPERDAY times the day number to the time of Jan 1st. */ |
| 503 | t += rule->d * SECSPERDAY; |
| 504 | break; |
| 505 | |
| 506 | case M: |
| 507 | /* Mm.n.d - Nth "Dth day" of month M. */ |
| 508 | { |
| 509 | unsigned int i; |
| 510 | int d, m1, yy0, yy1, yy2, dow; |
| 511 | const unsigned short int *myday = |
| 512 | &__mon_yday[__isleap (year)][rule->m]; |
| 513 | |
| 514 | /* First add SECSPERDAY for each day in months before M. */ |
| 515 | t += myday[-1] * SECSPERDAY; |
| 516 | |
| 517 | /* Use Zeller's Congruence to get day-of-week of first day of month. */ |
| 518 | m1 = (rule->m + 9) % 12 + 1; |
| 519 | yy0 = (rule->m <= 2) ? (year - 1) : year; |
| 520 | yy1 = yy0 / 100; |
| 521 | yy2 = yy0 % 100; |
| 522 | dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; |
| 523 | if (dow < 0) |
| 524 | dow += 7; |
| 525 | |
| 526 | /* DOW is the day-of-week of the first day of the month. Get the |
| 527 | day-of-month (zero-origin) of the first DOW day of the month. */ |
| 528 | d = rule->d - dow; |
| 529 | if (d < 0) |
| 530 | d += 7; |
| 531 | for (i = 1; i < rule->n; ++i) |
| 532 | { |
| 533 | if (d + 7 >= (int) myday[0] - myday[-1]) |
| 534 | break; |
| 535 | d += 7; |
| 536 | } |
| 537 | |
| 538 | /* D is the day-of-month (zero-origin) of the day we want. */ |
| 539 | t += d * SECSPERDAY; |
| 540 | } |
| 541 | break; |
| 542 | } |
| 543 | |
| 544 | /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want. |
| 545 | Just add the time of day and local offset from GMT, and we're done. */ |
| 546 | |
| 547 | rule->change = t - rule->offset + rule->secs; |
| 548 | rule->computed_for = year; |
| 549 | } |
| 550 | |
| 551 | |
| 552 | /* Figure out the correct timezone for TM and set `__tzname', |
| 553 | `__timezone', and `__daylight' accordingly. */ |
| 554 | void |
| 555 | internal_function |
| 556 | __tz_compute (time_t timer, struct tm *tm, int use_localtime) |
| 557 | { |
| 558 | compute_change (&tz_rules[0], 1900 + tm->tm_year); |
| 559 | compute_change (&tz_rules[1], 1900 + tm->tm_year); |
| 560 | |
| 561 | if (use_localtime) |
| 562 | { |
| 563 | int isdst; |
| 564 | |
| 565 | /* We have to distinguish between northern and southern |
| 566 | hemisphere. For the latter the daylight saving time |
| 567 | ends in the next year. */ |
| 568 | if (__builtin_expect (tz_rules[0].change |
| 569 | > tz_rules[1].change, 0)) |
| 570 | isdst = (timer < tz_rules[1].change |
| 571 | || timer >= tz_rules[0].change); |
| 572 | else |
| 573 | isdst = (timer >= tz_rules[0].change |
| 574 | && timer < tz_rules[1].change); |
| 575 | tm->tm_isdst = isdst; |
| 576 | tm->tm_zone = __tzname[isdst]; |
| 577 | tm->tm_gmtoff = tz_rules[isdst].offset; |
| 578 | } |
| 579 | } |
| 580 | |
| 581 | /* Reinterpret the TZ environment variable and set `tzname'. */ |
| 582 | #undef tzset |
| 583 | |
| 584 | void |
| 585 | __tzset (void) |
| 586 | { |
| 587 | __libc_lock_lock (tzset_lock); |
| 588 | |
| 589 | tzset_internal (1, 1); |
| 590 | |
| 591 | if (!__use_tzfile) |
| 592 | { |
| 593 | /* Set `tzname'. */ |
| 594 | __tzname[0] = (char *) tz_rules[0].name; |
| 595 | __tzname[1] = (char *) tz_rules[1].name; |
| 596 | } |
| 597 | |
| 598 | __libc_lock_unlock (tzset_lock); |
| 599 | } |
| 600 | weak_alias (__tzset, tzset) |
| 601 | |
| 602 | /* Return the `struct tm' representation of *TIMER in the local timezone. |
| 603 | Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */ |
| 604 | struct tm * |
| 605 | __tz_convert (const time_t *timer, int use_localtime, struct tm *tp) |
| 606 | { |
| 607 | long int leap_correction; |
| 608 | int leap_extra_secs; |
| 609 | |
| 610 | if (timer == NULL) |
| 611 | { |
| 612 | __set_errno (EINVAL); |
| 613 | return NULL; |
| 614 | } |
| 615 | |
| 616 | __libc_lock_lock (tzset_lock); |
| 617 | |
| 618 | /* Update internal database according to current TZ setting. |
| 619 | POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname. |
| 620 | This is a good idea since this allows at least a bit more parallelism. */ |
| 621 | tzset_internal (tp == &_tmbuf && use_localtime, 1); |
| 622 | |
| 623 | if (__use_tzfile) |
| 624 | __tzfile_compute (*timer, use_localtime, &leap_correction, |
| 625 | &leap_extra_secs, tp); |
| 626 | else |
| 627 | { |
| 628 | if (! __offtime (timer, 0, tp)) |
| 629 | tp = NULL; |
| 630 | else |
| 631 | __tz_compute (*timer, tp, use_localtime); |
| 632 | leap_correction = 0L; |
| 633 | leap_extra_secs = 0; |
| 634 | } |
| 635 | |
| 636 | __libc_lock_unlock (tzset_lock); |
| 637 | |
| 638 | if (tp) |
| 639 | { |
| 640 | if (! use_localtime) |
| 641 | { |
| 642 | tp->tm_isdst = 0; |
| 643 | tp->tm_zone = "GMT"; |
| 644 | tp->tm_gmtoff = 0L; |
| 645 | } |
| 646 | |
| 647 | if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp)) |
| 648 | tp->tm_sec += leap_extra_secs; |
| 649 | else |
| 650 | tp = NULL; |
| 651 | } |
| 652 | |
| 653 | return tp; |
| 654 | } |
| 655 | |
| 656 | |
| 657 | libc_freeres_fn (free_mem) |
| 658 | { |
| 659 | while (tzstring_list != NULL) |
| 660 | { |
| 661 | struct tzstring_l *old = tzstring_list; |
| 662 | |
| 663 | tzstring_list = tzstring_list->next; |
| 664 | free (old); |
| 665 | } |
| 666 | free (old_tz); |
| 667 | old_tz = NULL; |
| 668 | } |