.
[kopensolaris-gnu/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   free (old_tz);
418   old_tz = tz ? __strdup (tz) : NULL;
419
420   /* Try to read a data file.  */
421   __tzfile_read (tz, 0, NULL);
422   if (__use_tzfile)
423     return;
424
425   /* No data file found.  Default to UTC if nothing specified.  */
426
427   if (tz == NULL || *tz == '\0'
428       || (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
429     {
430       tz_rules[0].name = tz_rules[1].name = "UTC";
431       tz_rules[0].type = tz_rules[1].type = J0;
432       tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
433       tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
434       tz_rules[0].secs = tz_rules[1].secs = 0;
435       tz_rules[0].offset = tz_rules[1].offset = 0L;
436       tz_rules[0].change = tz_rules[1].change = (time_t) -1;
437       tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
438       update_vars ();
439       return;
440     }
441
442   __tzset_parse_tz (tz);
443 }
444 \f
445 /* Figure out the exact time (as a time_t) in YEAR
446    when the change described by RULE will occur and
447    put it in RULE->change, saving YEAR in RULE->computed_for.  */
448 static void
449 internal_function
450 compute_change (rule, year)
451      tz_rule *rule;
452      int year;
453 {
454   register time_t t;
455
456   if (year != -1 && rule->computed_for == year)
457     /* Operations on times in 2 BC will be slower.  Oh well.  */
458     return;
459
460   /* First set T to January 1st, 0:00:00 GMT in YEAR.  */
461   if (year > 1970)
462     t = ((year - 1970) * 365
463          + /* Compute the number of leapdays between 1970 and YEAR
464               (exclusive).  There is a leapday every 4th year ...  */
465          + ((year - 1) / 4 - 1970 / 4)
466          /* ... except every 100th year ... */
467          - ((year - 1) / 100 - 1970 / 100)
468          /* ... but still every 400th year.  */
469          + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
470   else
471     t = 0;
472
473   switch (rule->type)
474     {
475     case J1:
476       /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
477          In non-leap years, or if the day number is 59 or less, just
478          add SECSPERDAY times the day number-1 to the time of
479          January 1, midnight, to get the day.  */
480       t += (rule->d - 1) * SECSPERDAY;
481       if (rule->d >= 60 && __isleap (year))
482         t += SECSPERDAY;
483       break;
484
485     case J0:
486       /* n - Day of year.
487          Just add SECSPERDAY times the day number to the time of Jan 1st.  */
488       t += rule->d * SECSPERDAY;
489       break;
490
491     case M:
492       /* Mm.n.d - Nth "Dth day" of month M.  */
493       {
494         unsigned int i;
495         int d, m1, yy0, yy1, yy2, dow;
496         const unsigned short int *myday =
497           &__mon_yday[__isleap (year)][rule->m];
498
499         /* First add SECSPERDAY for each day in months before M.  */
500         t += myday[-1] * SECSPERDAY;
501
502         /* Use Zeller's Congruence to get day-of-week of first day of month. */
503         m1 = (rule->m + 9) % 12 + 1;
504         yy0 = (rule->m <= 2) ? (year - 1) : year;
505         yy1 = yy0 / 100;
506         yy2 = yy0 % 100;
507         dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
508         if (dow < 0)
509           dow += 7;
510
511         /* DOW is the day-of-week of the first day of the month.  Get the
512            day-of-month (zero-origin) of the first DOW day of the month.  */
513         d = rule->d - dow;
514         if (d < 0)
515           d += 7;
516         for (i = 1; i < rule->n; ++i)
517           {
518             if (d + 7 >= (int) myday[0] - myday[-1])
519               break;
520             d += 7;
521           }
522
523         /* D is the day-of-month (zero-origin) of the day we want.  */
524         t += d * SECSPERDAY;
525       }
526       break;
527     }
528
529   /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
530      Just add the time of day and local offset from GMT, and we're done.  */
531
532   rule->change = t - rule->offset + rule->secs;
533   rule->computed_for = year;
534 }
535
536
537 /* Figure out the correct timezone for TM and set `__tzname',
538    `__timezone', and `__daylight' accordingly.  */
539 void
540 internal_function
541 __tz_compute (timer, tm, use_localtime)
542      time_t timer;
543      struct tm *tm;
544      int use_localtime;
545 {
546   compute_change (&tz_rules[0], 1900 + tm->tm_year);
547   compute_change (&tz_rules[1], 1900 + tm->tm_year);
548
549   if (use_localtime)
550     {
551       int isdst;
552
553       /* We have to distinguish between northern and southern
554          hemisphere.  For the latter the daylight saving time
555          ends in the next year.  */
556       if (__builtin_expect (tz_rules[0].change
557                             > tz_rules[1].change, 0))
558         isdst = (timer < tz_rules[1].change
559                  || timer >= tz_rules[0].change);
560       else
561         isdst = (timer >= tz_rules[0].change
562                  && timer < tz_rules[1].change);
563       tm->tm_isdst = isdst;
564       tm->tm_zone = __tzname[isdst];
565       tm->tm_gmtoff = tz_rules[isdst].offset;
566     }
567 }
568 \f
569 /* Reinterpret the TZ environment variable and set `tzname'.  */
570 #undef tzset
571
572 void
573 __tzset (void)
574 {
575   __libc_lock_lock (tzset_lock);
576
577   tzset_internal (1, 1);
578
579   if (!__use_tzfile)
580     {
581       /* Set `tzname'.  */
582       __tzname[0] = (char *) tz_rules[0].name;
583       __tzname[1] = (char *) tz_rules[1].name;
584     }
585
586   __libc_lock_unlock (tzset_lock);
587 }
588 weak_alias (__tzset, tzset)
589 \f
590 /* Return the `struct tm' representation of *TIMER in the local timezone.
591    Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
592 struct tm *
593 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
594 {
595   long int leap_correction;
596   int leap_extra_secs;
597
598   if (timer == NULL)
599     {
600       __set_errno (EINVAL);
601       return NULL;
602     }
603
604   __libc_lock_lock (tzset_lock);
605
606   /* Update internal database according to current TZ setting.
607      POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
608      This is a good idea since this allows at least a bit more parallelism.  */
609   tzset_internal (tp == &_tmbuf && use_localtime, 1);
610
611   if (__use_tzfile)
612     __tzfile_compute (*timer, use_localtime, &leap_correction,
613                       &leap_extra_secs, tp);
614   else
615     {
616       if (! __offtime (timer, 0, tp))
617         tp = NULL;
618       else
619         __tz_compute (*timer, tp, use_localtime);
620       leap_correction = 0L;
621       leap_extra_secs = 0;
622     }
623
624   if (tp)
625     {
626       if (! use_localtime)
627         {
628           tp->tm_isdst = 0;
629           tp->tm_zone = "GMT";
630           tp->tm_gmtoff = 0L;
631         }
632
633       if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
634         tp->tm_sec += leap_extra_secs;
635       else
636         tp = NULL;
637     }
638
639   __libc_lock_unlock (tzset_lock);
640
641   return tp;
642 }
643
644
645 libc_freeres_fn (free_mem)
646 {
647   while (tzstring_list != NULL)
648     {
649       struct tzstring_l *old = tzstring_list;
650
651       tzstring_list = tzstring_list->next;
652       free (old);
653     }
654   free (old_tz);
655   old_tz = NULL;
656 }