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