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