(fmemopen): Add libc_hidden_def.
[glibc/history.git] / time / tzset.c
blob883a7ba1f00bb2353d724f8dd47b5c707bb6e1d0
1 /* Copyright (C) 1991-2002,2003,2004,2007,2009 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
19 #include <ctype.h>
20 #include <errno.h>
21 #include <bits/libc-lock.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
29 #define NOID
30 #include <timezone/tzfile.h>
32 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
33 int __daylight = 0;
34 long int __timezone = 0L;
36 weak_alias (__tzname, tzname)
37 weak_alias (__daylight, daylight)
38 weak_alias (__timezone, timezone)
40 /* This locks all the state variables in tzfile.c and this file. */
41 __libc_lock_define_initialized (static, tzset_lock)
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)
49 /* This structure contains all the information about a
50 timezone given in the POSIX standard TZ envariable. */
51 typedef struct
53 const char *name;
55 /* When to change. */
56 enum { J0, J1, M } type; /* Interpretation of: */
57 unsigned short int m, n, d; /* Month, week, day. */
58 unsigned int secs; /* Time of day. */
60 long int offset; /* Seconds east of GMT (west if < 0). */
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;
68 /* tz_rules[0] is standard, tz_rules[1] is daylight. */
69 static tz_rule tz_rules[2];
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;
76 /* List of buffers containing time zone strings. */
77 struct tzstring_l
79 struct tzstring_l *next;
80 size_t len; /* strlen(data) - doesn't count terminating NUL! */
81 char data[0];
84 static struct tzstring_l *tzstring_list;
86 /* Allocate a permanent home for S. It will never be moved or deallocated,
87 but may share space with other strings.
88 Don't modify the returned string. */
89 char *
90 __tzstring (const char *s)
92 char *p;
93 struct tzstring_l *t, *u, *new;
94 size_t len = strlen (s);
96 /* Walk the list and look for a match. If this string is the same
97 as the end of an already-allocated string, it can share space. */
98 for (u = t = tzstring_list; t; u = t, t = t->next)
99 if (len <= t->len)
101 p = &t->data[t->len - len];
102 if (strcmp (s, p) == 0)
103 return p;
106 /* Not found; allocate a new buffer. */
107 new = malloc (sizeof (struct tzstring_l) + len + 1);
108 if (!new)
109 return NULL;
111 new->next = NULL;
112 new->len = len;
113 strcpy (new->data, s);
115 if (u)
116 u->next = new;
117 else
118 tzstring_list = new;
120 return new->data;
123 /* Maximum length of a timezone name. tzset_internal keeps this up to date
124 (never decreasing it) when ! __use_tzfile.
125 tzfile.c keeps it up to date when __use_tzfile. */
126 size_t __tzname_cur_max;
128 long int
129 __tzname_max ()
131 __libc_lock_lock (tzset_lock);
133 tzset_internal (0, 0);
135 __libc_lock_unlock (tzset_lock);
137 return __tzname_cur_max;
140 static char *old_tz;
142 static void
143 internal_function
144 update_vars (void)
146 __daylight = tz_rules[0].offset != tz_rules[1].offset;
147 __timezone = -tz_rules[0].offset;
148 __tzname[0] = (char *) tz_rules[0].name;
149 __tzname[1] = (char *) tz_rules[1].name;
151 /* Keep __tzname_cur_max up to date. */
152 size_t len0 = strlen (__tzname[0]);
153 size_t len1 = strlen (__tzname[1]);
154 if (len0 > __tzname_cur_max)
155 __tzname_cur_max = len0;
156 if (len1 > __tzname_cur_max)
157 __tzname_cur_max = len1;
160 /* Parse the POSIX TZ-style string. */
161 void
162 __tzset_parse_tz (tz)
163 const char *tz;
165 register size_t l;
166 unsigned short int hh, mm, ss;
167 unsigned short int whichrule;
169 /* Clear out old state and reset to unnamed UTC. */
170 memset (tz_rules, 0, sizeof tz_rules);
171 tz_rules[0].name = tz_rules[1].name = "";
173 /* Get the standard timezone name. */
174 char *tzbuf = strdupa (tz);
176 if (sscanf (tz, "%[A-Za-z]", tzbuf) != 1)
178 /* Check for the quoted version. */
179 char *wp = tzbuf;
180 if (__builtin_expect (*tz++ != '<', 0))
181 goto out;
183 while (isalnum (*tz) || *tz == '+' || *tz == '-')
184 *wp++ = *tz++;
185 if (__builtin_expect (*tz++ != '>' || wp - tzbuf < 3, 0))
186 goto out;
187 *wp = '\0';
189 else if (__builtin_expect ((l = strlen (tzbuf)) < 3, 0))
190 goto out;
191 else
192 tz += l;
194 tz_rules[0].name = __tzstring (tzbuf);
196 /* Figure out the standard offset from UTC. */
197 if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))
198 goto out;
200 if (*tz == '-' || *tz == '+')
201 tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
202 else
203 tz_rules[0].offset = -1L;
204 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
206 default:
207 tz_rules[0].offset = 0;
208 goto out;
209 case 1:
210 mm = 0;
211 case 2:
212 ss = 0;
213 case 3:
214 break;
216 tz_rules[0].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
217 (min (hh, 24) * 60 * 60));
219 for (l = 0; l < 3; ++l)
221 while (isdigit (*tz))
222 ++tz;
223 if (l < 2 && *tz == ':')
224 ++tz;
227 /* Get the DST timezone name (if any). */
228 if (*tz != '\0')
230 if (sscanf (tz, "%[A-Za-z]", tzbuf) != 1)
232 /* Check for the quoted version. */
233 char *wp = tzbuf;
234 const char *rp = tz;
235 if (__builtin_expect (*rp++ != '<', 0))
236 /* Punt on name, set up the offsets. */
237 goto done_names;
239 while (isalnum (*rp) || *rp == '+' || *rp == '-')
240 *wp++ = *rp++;
241 if (__builtin_expect (*rp++ != '>' || wp - tzbuf < 3, 0))
242 /* Punt on name, set up the offsets. */
243 goto done_names;
244 *wp = '\0';
245 tz = rp;
247 else if (__builtin_expect ((l = strlen (tzbuf)) < 3, 0))
248 /* Punt on name, set up the offsets. */
249 goto done_names;
250 else
251 tz += l;
253 tz_rules[1].name = __tzstring (tzbuf);
255 /* Figure out the DST offset from GMT. */
256 if (*tz == '-' || *tz == '+')
257 tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
258 else
259 tz_rules[1].offset = -1L;
261 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
263 default:
264 /* Default to one hour later than standard time. */
265 tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
266 break;
268 case 1:
269 mm = 0;
270 case 2:
271 ss = 0;
272 case 3:
273 tz_rules[1].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
274 (min (hh, 24) * (60 * 60)));
275 break;
277 for (l = 0; l < 3; ++l)
279 while (isdigit (*tz))
280 ++tz;
281 if (l < 2 && *tz == ':')
282 ++tz;
284 if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
286 /* There is no rule. See if there is a default rule file. */
287 __tzfile_default (tz_rules[0].name, tz_rules[1].name,
288 tz_rules[0].offset, tz_rules[1].offset);
289 if (__use_tzfile)
291 free (old_tz);
292 old_tz = NULL;
293 return;
297 else
299 /* There is no DST. */
300 tz_rules[1].name = tz_rules[0].name;
301 tz_rules[1].offset = tz_rules[0].offset;
302 goto out;
305 done_names:
306 /* Figure out the standard <-> DST rules. */
307 for (whichrule = 0; whichrule < 2; ++whichrule)
309 register tz_rule *tzr = &tz_rules[whichrule];
311 /* Ignore comma to support string following the incorrect
312 specification in early POSIX.1 printings. */
313 tz += *tz == ',';
315 /* Get the date of the change. */
316 if (*tz == 'J' || isdigit (*tz))
318 char *end;
319 tzr->type = *tz == 'J' ? J1 : J0;
320 if (tzr->type == J1 && !isdigit (*++tz))
321 goto out;
322 tzr->d = (unsigned short int) strtoul (tz, &end, 10);
323 if (end == tz || tzr->d > 365)
324 goto out;
325 else if (tzr->type == J1 && tzr->d == 0)
326 goto out;
327 tz = end;
329 else if (*tz == 'M')
331 int n;
332 tzr->type = M;
333 if (sscanf (tz, "M%hu.%hu.%hu%n",
334 &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
335 tzr->m < 1 || tzr->m > 12 ||
336 tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
337 goto out;
338 tz += n;
340 else if (*tz == '\0')
342 /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0". */
343 tzr->type = M;
344 if (tzr == &tz_rules[0])
346 tzr->m = 4;
347 tzr->n = 1;
348 tzr->d = 0;
350 else
352 tzr->m = 10;
353 tzr->n = 5;
354 tzr->d = 0;
357 else
358 goto out;
360 if (*tz != '\0' && *tz != '/' && *tz != ',')
361 goto out;
362 else if (*tz == '/')
364 /* Get the time of day of the change. */
365 ++tz;
366 if (*tz == '\0')
367 goto out;
368 switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
370 default:
371 hh = 2; /* Default to 2:00 AM. */
372 case 1:
373 mm = 0;
374 case 2:
375 ss = 0;
376 case 3:
377 break;
379 for (l = 0; l < 3; ++l)
381 while (isdigit (*tz))
382 ++tz;
383 if (l < 2 && *tz == ':')
384 ++tz;
386 tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
388 else
389 /* Default to 2:00 AM. */
390 tzr->secs = 2 * 60 * 60;
392 tzr->computed_for = -1;
395 out:
396 update_vars ();
399 /* Interpret the TZ envariable. */
400 static void
401 internal_function
402 tzset_internal (always, explicit)
403 int always;
404 int explicit;
406 static int is_initialized;
407 register const char *tz;
409 if (is_initialized && !always)
410 return;
411 is_initialized = 1;
413 /* Examine the TZ environment variable. */
414 tz = getenv ("TZ");
415 if (tz == NULL && !explicit)
416 /* Use the site-wide default. This is a file name which means we
417 would not see changes to the file if we compare only the file
418 name for change. We want to notice file changes if tzset() has
419 been called explicitly. Leave TZ as NULL in this case. */
420 tz = TZDEFAULT;
421 if (tz && *tz == '\0')
422 /* User specified the empty string; use UTC explicitly. */
423 tz = "Universal";
425 /* A leading colon means "implementation defined syntax".
426 We ignore the colon and always use the same algorithm:
427 try a data file, and if none exists parse the 1003.1 syntax. */
428 if (tz && *tz == ':')
429 ++tz;
431 /* Check whether the value changed since the last run. */
432 if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
433 /* No change, simply return. */
434 return;
436 if (tz == NULL)
437 /* No user specification; use the site-wide default. */
438 tz = TZDEFAULT;
440 tz_rules[0].name = NULL;
441 tz_rules[1].name = NULL;
443 /* Save the value of `tz'. */
444 free (old_tz);
445 old_tz = tz ? __strdup (tz) : NULL;
447 /* Try to read a data file. */
448 __tzfile_read (tz, 0, NULL);
449 if (__use_tzfile)
450 return;
452 /* No data file found. Default to UTC if nothing specified. */
454 if (tz == NULL || *tz == '\0'
455 || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
457 tz_rules[0].name = tz_rules[1].name = "UTC";
458 tz_rules[0].type = tz_rules[1].type = J0;
459 tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
460 tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
461 tz_rules[0].secs = tz_rules[1].secs = 0;
462 tz_rules[0].offset = tz_rules[1].offset = 0L;
463 tz_rules[0].change = tz_rules[1].change = (time_t) -1;
464 tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
465 update_vars ();
466 return;
469 __tzset_parse_tz (tz);
472 /* Figure out the exact time (as a time_t) in YEAR
473 when the change described by RULE will occur and
474 put it in RULE->change, saving YEAR in RULE->computed_for. */
475 static void
476 internal_function
477 compute_change (rule, year)
478 tz_rule *rule;
479 int year;
481 register time_t t;
483 if (year != -1 && rule->computed_for == year)
484 /* Operations on times in 2 BC will be slower. Oh well. */
485 return;
487 /* First set T to January 1st, 0:00:00 GMT in YEAR. */
488 if (year > 1970)
489 t = ((year - 1970) * 365
490 + /* Compute the number of leapdays between 1970 and YEAR
491 (exclusive). There is a leapday every 4th year ... */
492 + ((year - 1) / 4 - 1970 / 4)
493 /* ... except every 100th year ... */
494 - ((year - 1) / 100 - 1970 / 100)
495 /* ... but still every 400th year. */
496 + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
497 else
498 t = 0;
500 switch (rule->type)
502 case J1:
503 /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
504 In non-leap years, or if the day number is 59 or less, just
505 add SECSPERDAY times the day number-1 to the time of
506 January 1, midnight, to get the day. */
507 t += (rule->d - 1) * SECSPERDAY;
508 if (rule->d >= 60 && __isleap (year))
509 t += SECSPERDAY;
510 break;
512 case J0:
513 /* n - Day of year.
514 Just add SECSPERDAY times the day number to the time of Jan 1st. */
515 t += rule->d * SECSPERDAY;
516 break;
518 case M:
519 /* Mm.n.d - Nth "Dth day" of month M. */
521 unsigned int i;
522 int d, m1, yy0, yy1, yy2, dow;
523 const unsigned short int *myday =
524 &__mon_yday[__isleap (year)][rule->m];
526 /* First add SECSPERDAY for each day in months before M. */
527 t += myday[-1] * SECSPERDAY;
529 /* Use Zeller's Congruence to get day-of-week of first day of month. */
530 m1 = (rule->m + 9) % 12 + 1;
531 yy0 = (rule->m <= 2) ? (year - 1) : year;
532 yy1 = yy0 / 100;
533 yy2 = yy0 % 100;
534 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
535 if (dow < 0)
536 dow += 7;
538 /* DOW is the day-of-week of the first day of the month. Get the
539 day-of-month (zero-origin) of the first DOW day of the month. */
540 d = rule->d - dow;
541 if (d < 0)
542 d += 7;
543 for (i = 1; i < rule->n; ++i)
545 if (d + 7 >= (int) myday[0] - myday[-1])
546 break;
547 d += 7;
550 /* D is the day-of-month (zero-origin) of the day we want. */
551 t += d * SECSPERDAY;
553 break;
556 /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
557 Just add the time of day and local offset from GMT, and we're done. */
559 rule->change = t - rule->offset + rule->secs;
560 rule->computed_for = year;
564 /* Figure out the correct timezone for TM and set `__tzname',
565 `__timezone', and `__daylight' accordingly. */
566 void
567 internal_function
568 __tz_compute (timer, tm, use_localtime)
569 time_t timer;
570 struct tm *tm;
571 int use_localtime;
573 compute_change (&tz_rules[0], 1900 + tm->tm_year);
574 compute_change (&tz_rules[1], 1900 + tm->tm_year);
576 if (use_localtime)
578 int isdst;
580 /* We have to distinguish between northern and southern
581 hemisphere. For the latter the daylight saving time
582 ends in the next year. */
583 if (__builtin_expect (tz_rules[0].change
584 > tz_rules[1].change, 0))
585 isdst = (timer < tz_rules[1].change
586 || timer >= tz_rules[0].change);
587 else
588 isdst = (timer >= tz_rules[0].change
589 && timer < tz_rules[1].change);
590 tm->tm_isdst = isdst;
591 tm->tm_zone = __tzname[isdst];
592 tm->tm_gmtoff = tz_rules[isdst].offset;
596 /* Reinterpret the TZ environment variable and set `tzname'. */
597 #undef tzset
599 void
600 __tzset (void)
602 __libc_lock_lock (tzset_lock);
604 tzset_internal (1, 1);
606 if (!__use_tzfile)
608 /* Set `tzname'. */
609 __tzname[0] = (char *) tz_rules[0].name;
610 __tzname[1] = (char *) tz_rules[1].name;
613 __libc_lock_unlock (tzset_lock);
615 weak_alias (__tzset, tzset)
617 /* Return the `struct tm' representation of *TIMER in the local timezone.
618 Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
619 struct tm *
620 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
622 long int leap_correction;
623 int leap_extra_secs;
625 if (timer == NULL)
627 __set_errno (EINVAL);
628 return NULL;
631 __libc_lock_lock (tzset_lock);
633 /* Update internal database according to current TZ setting.
634 POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
635 This is a good idea since this allows at least a bit more parallelism. */
636 tzset_internal (tp == &_tmbuf && use_localtime, 1);
638 if (__use_tzfile)
639 __tzfile_compute (*timer, use_localtime, &leap_correction,
640 &leap_extra_secs, tp);
641 else
643 if (! __offtime (timer, 0, tp))
644 tp = NULL;
645 else
646 __tz_compute (*timer, tp, use_localtime);
647 leap_correction = 0L;
648 leap_extra_secs = 0;
651 if (tp)
653 if (! use_localtime)
655 tp->tm_isdst = 0;
656 tp->tm_zone = "GMT";
657 tp->tm_gmtoff = 0L;
660 if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
661 tp->tm_sec += leap_extra_secs;
662 else
663 tp = NULL;
666 __libc_lock_unlock (tzset_lock);
668 return tp;
672 libc_freeres_fn (free_mem)
674 while (tzstring_list != NULL)
676 struct tzstring_l *old = tzstring_list;
678 tzstring_list = tzstring_list->next;
679 free (old);
681 free (old_tz);
682 old_tz = NULL;