[BZ #5186]
[platform/upstream/glibc.git] / time / tzset.c
1 /* Copyright (C) 1991-2002,2003,2004,2007 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, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
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>
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     unsigned 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 \f
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 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)
91 {
92   char *p;
93   struct tzstring_l *t, *u, *new;
94   size_t len = strlen (s);
95
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)
100       {
101         p = &t->data[t->len - len];
102         if (strcmp (s, p) == 0)
103           return p;
104       }
105
106   /* Not found; allocate a new buffer. */
107   new = malloc (sizeof (struct tzstring_l) + len + 1);
108   if (!new)
109     return NULL;
110
111   new->next = NULL;
112   new->len = len;
113   strcpy (new->data, s);
114
115   if (u)
116     u->next = new;
117   else
118     tzstring_list = new;
119
120   return new->data;
121 }
122 \f
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;
127
128 long int
129 __tzname_max ()
130 {
131   __libc_lock_lock (tzset_lock);
132
133   tzset_internal (0, 0);
134
135   __libc_lock_unlock (tzset_lock);
136
137   return __tzname_cur_max;
138 }
139 \f
140 static char *old_tz;
141
142 static void
143 internal_function
144 update_vars (void)
145 {
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;
150
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;
158 }
159
160 /* Parse the POSIX TZ-style string.  */
161 void
162 __tzset_parse_tz (tz)
163      const char *tz;
164 {
165   register size_t l;
166   char *tzbuf;
167   unsigned short int hh, mm, ss;
168   unsigned short int whichrule;
169
170   /* Clear out old state and reset to unnamed UTC.  */
171   memset (tz_rules, 0, sizeof tz_rules);
172   tz_rules[0].name = tz_rules[1].name = "";
173
174   /* Get the standard timezone name.  */
175   tzbuf = strdupa (tz);
176
177   if (sscanf (tz, "%[^0-9,+-]", tzbuf) != 1 ||
178       (l = strlen (tzbuf)) < 3)
179     goto out;
180
181   tz_rules[0].name = __tzstring (tzbuf);
182
183   tz += l;
184
185   /* Figure out the standard offset from UTC.  */
186   if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit (*tz)))
187     goto out;
188
189   if (*tz == '-' || *tz == '+')
190     tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
191   else
192     tz_rules[0].offset = -1L;
193   switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
194     {
195     default:
196       tz_rules[0].offset = 0;
197       goto out;
198     case 1:
199       mm = 0;
200     case 2:
201       ss = 0;
202     case 3:
203       break;
204     }
205   tz_rules[0].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
206                          (min (hh, 24) * 60 * 60));
207
208   for (l = 0; l < 3; ++l)
209     {
210       while (isdigit(*tz))
211         ++tz;
212       if (l < 2 && *tz == ':')
213         ++tz;
214     }
215
216   /* Get the DST timezone name (if any).  */
217   if (*tz != '\0')
218     {
219       char *n = tzbuf + strlen (tzbuf) + 1;
220       if (sscanf (tz, "%[^0-9,+-]", n) != 1 ||
221           (l = strlen (n)) < 3)
222         goto done_names;        /* Punt on name, set up the offsets.  */
223
224       tz_rules[1].name = __tzstring (n);
225
226       tz += l;
227
228       /* Figure out the DST offset from GMT.  */
229       if (*tz == '-' || *tz == '+')
230         tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
231       else
232         tz_rules[1].offset = -1L;
233
234       switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
235         {
236         default:
237           /* Default to one hour later than standard time.  */
238           tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
239           break;
240
241         case 1:
242           mm = 0;
243         case 2:
244           ss = 0;
245         case 3:
246           tz_rules[1].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
247                                  (min (hh, 23) * (60 * 60)));
248           break;
249         }
250       for (l = 0; l < 3; ++l)
251         {
252           while (isdigit (*tz))
253             ++tz;
254           if (l < 2 && *tz == ':')
255             ++tz;
256         }
257       if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
258         {
259           /* There is no rule.  See if there is a default rule file.  */
260           __tzfile_default (tz_rules[0].name, tz_rules[1].name,
261                             tz_rules[0].offset, tz_rules[1].offset);
262           if (__use_tzfile)
263             {
264               free (old_tz);
265               old_tz = NULL;
266               return;
267             }
268         }
269     }
270   else
271     {
272       /* There is no DST.  */
273       tz_rules[1].name = tz_rules[0].name;
274       tz_rules[1].offset = tz_rules[0].offset;
275       goto out;
276     }
277
278  done_names:
279   /* Figure out the standard <-> DST rules.  */
280   for (whichrule = 0; whichrule < 2; ++whichrule)
281     {
282       register tz_rule *tzr = &tz_rules[whichrule];
283
284       /* Ignore comma to support string following the incorrect
285          specification in early POSIX.1 printings.  */
286       tz += *tz == ',';
287
288       /* Get the date of the change.  */
289       if (*tz == 'J' || isdigit (*tz))
290         {
291           char *end;
292           tzr->type = *tz == 'J' ? J1 : J0;
293           if (tzr->type == J1 && !isdigit (*++tz))
294             goto out;
295           tzr->d = (unsigned short int) strtoul (tz, &end, 10);
296           if (end == tz || tzr->d > 365)
297             goto out;
298           else if (tzr->type == J1 && tzr->d == 0)
299             goto out;
300           tz = end;
301         }
302       else if (*tz == 'M')
303         {
304           int n;
305           tzr->type = M;
306           if (sscanf (tz, "M%hu.%hu.%hu%n",
307                       &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
308               tzr->m < 1 || tzr->m > 12 ||
309               tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
310             goto out;
311           tz += n;
312         }
313       else if (*tz == '\0')
314         {
315           /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0".  */
316           tzr->type = M;
317           if (tzr == &tz_rules[0])
318             {
319               tzr->m = 4;
320               tzr->n = 1;
321               tzr->d = 0;
322             }
323           else
324             {
325               tzr->m = 10;
326               tzr->n = 5;
327               tzr->d = 0;
328             }
329         }
330       else
331         goto out;
332
333       if (*tz != '\0' && *tz != '/' && *tz != ',')
334         goto out;
335       else if (*tz == '/')
336         {
337           /* Get the time of day of the change.  */
338           ++tz;
339           if (*tz == '\0')
340             goto out;
341           switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
342             {
343             default:
344               hh = 2;           /* Default to 2:00 AM.  */
345             case 1:
346               mm = 0;
347             case 2:
348               ss = 0;
349             case 3:
350               break;
351             }
352           for (l = 0; l < 3; ++l)
353             {
354               while (isdigit (*tz))
355                 ++tz;
356               if (l < 2 && *tz == ':')
357                 ++tz;
358             }
359           tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
360         }
361       else
362         /* Default to 2:00 AM.  */
363         tzr->secs = 2 * 60 * 60;
364
365       tzr->computed_for = -1;
366     }
367
368  out:
369   update_vars ();
370 }
371
372 /* Interpret the TZ envariable.  */
373 static void
374 internal_function
375 tzset_internal (always, explicit)
376      int always;
377      int explicit;
378 {
379   static int is_initialized;
380   register const char *tz;
381
382   if (is_initialized && !always)
383     return;
384   is_initialized = 1;
385
386   /* Examine the TZ environment variable.  */
387   tz = getenv ("TZ");
388   if (tz == NULL && !explicit)
389     /* Use the site-wide default.  This is a file name which means we
390        would not see changes to the file if we compare only the file
391        name for change.  We want to notice file changes if tzset() has
392        been called explicitly.  Leave TZ as NULL in this case.  */
393     tz = TZDEFAULT;
394   if (tz && *tz == '\0')
395     /* User specified the empty string; use UTC explicitly.  */
396     tz = "Universal";
397
398   /* A leading colon means "implementation defined syntax".
399      We ignore the colon and always use the same algorithm:
400      try a data file, and if none exists parse the 1003.1 syntax.  */
401   if (tz && *tz == ':')
402     ++tz;
403
404   /* Check whether the value changed since the last run.  */
405   if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
406     /* No change, simply return.  */
407     return;
408
409   if (tz == NULL)
410     /* No user specification; use the site-wide default.  */
411     tz = TZDEFAULT;
412
413   tz_rules[0].name = NULL;
414   tz_rules[1].name = NULL;
415
416   /* Save the value of `tz'.  */
417   if (old_tz != NULL)
418     free (old_tz);
419   old_tz = tz ? __strdup (tz) : NULL;
420
421   /* Try to read a data file.  */
422   __tzfile_read (tz, 0, NULL);
423   if (__use_tzfile)
424     return;
425
426   /* No data file found.  Default to UTC if nothing specified.  */
427
428   if (tz == NULL || *tz == '\0'
429       || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
430     {
431       tz_rules[0].name = tz_rules[1].name = "UTC";
432       tz_rules[0].type = tz_rules[1].type = J0;
433       tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
434       tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
435       tz_rules[0].secs = tz_rules[1].secs = 0;
436       tz_rules[0].offset = tz_rules[1].offset = 0L;
437       tz_rules[0].change = tz_rules[1].change = (time_t) -1;
438       tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
439       update_vars ();
440       return;
441     }
442
443   __tzset_parse_tz (tz);
444 }
445 \f
446 /* Figure out the exact time (as a time_t) in YEAR
447    when the change described by RULE will occur and
448    put it in RULE->change, saving YEAR in RULE->computed_for.  */
449 static void
450 internal_function
451 compute_change (rule, year)
452      tz_rule *rule;
453      int year;
454 {
455   register time_t t;
456
457   if (year != -1 && rule->computed_for == year)
458     /* Operations on times in 2 BC will be slower.  Oh well.  */
459     return;
460
461   /* First set T to January 1st, 0:00:00 GMT in YEAR.  */
462   if (year > 1970)
463     t = ((year - 1970) * 365
464          + /* Compute the number of leapdays between 1970 and YEAR
465               (exclusive).  There is a leapday every 4th year ...  */
466          + ((year - 1) / 4 - 1970 / 4)
467          /* ... except every 100th year ... */
468          - ((year - 1) / 100 - 1970 / 100)
469          /* ... but still every 400th year.  */
470          + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
471   else
472     t = 0;
473
474   switch (rule->type)
475     {
476     case J1:
477       /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
478          In non-leap years, or if the day number is 59 or less, just
479          add SECSPERDAY times the day number-1 to the time of
480          January 1, midnight, to get the day.  */
481       t += (rule->d - 1) * SECSPERDAY;
482       if (rule->d >= 60 && __isleap (year))
483         t += SECSPERDAY;
484       break;
485
486     case J0:
487       /* n - Day of year.
488          Just add SECSPERDAY times the day number to the time of Jan 1st.  */
489       t += rule->d * SECSPERDAY;
490       break;
491
492     case M:
493       /* Mm.n.d - Nth "Dth day" of month M.  */
494       {
495         unsigned int i;
496         int d, m1, yy0, yy1, yy2, dow;
497         const unsigned short int *myday =
498           &__mon_yday[__isleap (year)][rule->m];
499
500         /* First add SECSPERDAY for each day in months before M.  */
501         t += myday[-1] * SECSPERDAY;
502
503         /* Use Zeller's Congruence to get day-of-week of first day of month. */
504         m1 = (rule->m + 9) % 12 + 1;
505         yy0 = (rule->m <= 2) ? (year - 1) : year;
506         yy1 = yy0 / 100;
507         yy2 = yy0 % 100;
508         dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
509         if (dow < 0)
510           dow += 7;
511
512         /* DOW is the day-of-week of the first day of the month.  Get the
513            day-of-month (zero-origin) of the first DOW day of the month.  */
514         d = rule->d - dow;
515         if (d < 0)
516           d += 7;
517         for (i = 1; i < rule->n; ++i)
518           {
519             if (d + 7 >= (int) myday[0] - myday[-1])
520               break;
521             d += 7;
522           }
523
524         /* D is the day-of-month (zero-origin) of the day we want.  */
525         t += d * SECSPERDAY;
526       }
527       break;
528     }
529
530   /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
531      Just add the time of day and local offset from GMT, and we're done.  */
532
533   rule->change = t - rule->offset + rule->secs;
534   rule->computed_for = year;
535 }
536
537
538 /* Figure out the correct timezone for TM and set `__tzname',
539    `__timezone', and `__daylight' accordingly.  */
540 void
541 internal_function
542 __tz_compute (timer, tm, use_localtime)
543      time_t timer;
544      struct tm *tm;
545      int use_localtime;
546 {
547   compute_change (&tz_rules[0], 1900 + tm->tm_year);
548   compute_change (&tz_rules[1], 1900 + tm->tm_year);
549
550   if (use_localtime)
551     {
552       int isdst;
553
554       /* We have to distinguish between northern and southern
555          hemisphere.  For the latter the daylight saving time
556          ends in the next year.  */
557       if (__builtin_expect (tz_rules[0].change
558                             > tz_rules[1].change, 0))
559         isdst = (timer < tz_rules[1].change
560                  || timer >= tz_rules[0].change);
561       else
562         isdst = (timer >= tz_rules[0].change
563                  && timer < tz_rules[1].change);
564       tm->tm_isdst = isdst;
565       tm->tm_zone = __tzname[isdst];
566       tm->tm_gmtoff = tz_rules[isdst].offset;
567     }
568 }
569 \f
570 /* Reinterpret the TZ environment variable and set `tzname'.  */
571 #undef tzset
572
573 void
574 __tzset (void)
575 {
576   __libc_lock_lock (tzset_lock);
577
578   tzset_internal (1, 1);
579
580   if (!__use_tzfile)
581     {
582       /* Set `tzname'.  */
583       __tzname[0] = (char *) tz_rules[0].name;
584       __tzname[1] = (char *) tz_rules[1].name;
585     }
586
587   __libc_lock_unlock (tzset_lock);
588 }
589 weak_alias (__tzset, tzset)
590 \f
591 /* Return the `struct tm' representation of *TIMER in the local timezone.
592    Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
593 struct tm *
594 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
595 {
596   long int leap_correction;
597   int leap_extra_secs;
598
599   if (timer == NULL)
600     {
601       __set_errno (EINVAL);
602       return NULL;
603     }
604
605   __libc_lock_lock (tzset_lock);
606
607   /* Update internal database according to current TZ setting.
608      POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
609      This is a good idea since this allows at least a bit more parallelism.  */
610   tzset_internal (tp == &_tmbuf && use_localtime, 1);
611
612   if (__use_tzfile)
613     __tzfile_compute (*timer, use_localtime, &leap_correction,
614                       &leap_extra_secs, tp);
615   else
616     {
617       if (! __offtime (timer, 0, tp))
618         tp = NULL;
619       else
620         __tz_compute (*timer, tp, use_localtime);
621       leap_correction = 0L;
622       leap_extra_secs = 0;
623     }
624
625   if (tp)
626     {
627       if (! use_localtime)
628         {
629           tp->tm_isdst = 0;
630           tp->tm_zone = "GMT";
631           tp->tm_gmtoff = 0L;
632         }
633
634       if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
635         tp->tm_sec += leap_extra_secs;
636       else
637         tp = NULL;
638     }
639
640   __libc_lock_unlock (tzset_lock);
641
642   return tp;
643 }
644
645
646 libc_freeres_fn (free_mem)
647 {
648   while (tzstring_list != NULL)
649     {
650       struct tzstring_l *old = tzstring_list;
651
652       tzstring_list = tzstring_list->next;
653       free (old);
654     }
655   free (old_tz);
656   old_tz = NULL;
657 }