(__strptime_internal): Add braces to avoid warning.
[kopensolaris-gnu/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       tz_rules[0].offset = 0;
244       goto out;
245     case 1:
246       mm = 0;
247     case 2:
248       ss = 0;
249     case 3:
250       break;
251     }
252   tz_rules[0].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
253                          (min (hh, 24) * 60 * 60));
254
255   for (l = 0; l < 3; ++l)
256     {
257       while (isdigit(*tz))
258         ++tz;
259       if (l < 2 && *tz == ':')
260         ++tz;
261     }
262
263   /* Get the DST timezone name (if any).  */
264   if (*tz != '\0')
265     {
266       char *n = tzbuf + strlen (tzbuf) + 1;
267       if (sscanf (tz, "%[^0-9,+-]", n) != 1 ||
268           (l = strlen (n)) < 3)
269         goto done_names;        /* Punt on name, set up the offsets.  */
270
271       tz_rules[1].name = __tzstring (n);
272
273       tz += l;
274
275       /* Figure out the DST offset from GMT.  */
276       if (*tz == '-' || *tz == '+')
277         tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
278       else
279         tz_rules[1].offset = -1L;
280
281       switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
282         {
283         default:
284           /* Default to one hour later than standard time.  */
285           tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
286           break;
287
288         case 1:
289           mm = 0;
290         case 2:
291           ss = 0;
292         case 3:
293           tz_rules[1].offset *= (min (ss, 59) + (min (mm, 59) * 60) +
294                                  (min (hh, 23) * (60 * 60)));
295           break;
296         }
297       for (l = 0; l < 3; ++l)
298         {
299           while (isdigit (*tz))
300             ++tz;
301           if (l < 2 && *tz == ':')
302             ++tz;
303         }
304       if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
305         {
306           /* There is no rule.  See if there is a default rule file.  */
307           __tzfile_default (tz_rules[0].name, tz_rules[1].name,
308                             tz_rules[0].offset, tz_rules[1].offset);
309           if (__use_tzfile)
310             {
311               free (old_tz);
312               old_tz = NULL;
313               return;
314             }
315         }
316     }
317   else
318     {
319       /* There is no DST.  */
320       tz_rules[1].name = tz_rules[0].name;
321       tz_rules[1].offset = tz_rules[0].offset;
322       goto out;
323     }
324
325  done_names:
326   /* Figure out the standard <-> DST rules.  */
327   for (whichrule = 0; whichrule < 2; ++whichrule)
328     {
329       register tz_rule *tzr = &tz_rules[whichrule];
330
331       /* Ignore comma to support string following the incorrect
332          specification in early POSIX.1 printings.  */
333       tz += *tz == ',';
334
335       /* Get the date of the change.  */
336       if (*tz == 'J' || isdigit (*tz))
337         {
338           char *end;
339           tzr->type = *tz == 'J' ? J1 : J0;
340           if (tzr->type == J1 && !isdigit (*++tz))
341             goto out;
342           tzr->d = (unsigned short int) strtoul (tz, &end, 10);
343           if (end == tz || tzr->d > 365)
344             goto out;
345           else if (tzr->type == J1 && tzr->d == 0)
346             goto out;
347           tz = end;
348         }
349       else if (*tz == 'M')
350         {
351           int n;
352           tzr->type = M;
353           if (sscanf (tz, "M%hu.%hu.%hu%n",
354                       &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
355               tzr->m < 1 || tzr->m > 12 ||
356               tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
357             goto out;
358           tz += n;
359         }
360       else if (*tz == '\0')
361         {
362           /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0".  */
363           tzr->type = M;
364           if (tzr == &tz_rules[0])
365             {
366               tzr->m = 4;
367               tzr->n = 1;
368               tzr->d = 0;
369             }
370           else
371             {
372               tzr->m = 10;
373               tzr->n = 5;
374               tzr->d = 0;
375             }
376         }
377       else
378         goto out;
379
380       if (*tz != '\0' && *tz != '/' && *tz != ',')
381         goto out;
382       else if (*tz == '/')
383         {
384           /* Get the time of day of the change.  */
385           ++tz;
386           if (*tz == '\0')
387             goto out;
388           switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
389             {
390             default:
391               hh = 2;           /* Default to 2:00 AM.  */
392             case 1:
393               mm = 0;
394             case 2:
395               ss = 0;
396             case 3:
397               break;
398             }
399           for (l = 0; l < 3; ++l)
400             {
401               while (isdigit (*tz))
402                 ++tz;
403               if (l < 2 && *tz == ':')
404                 ++tz;
405             }
406           tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
407         }
408       else
409         /* Default to 2:00 AM.  */
410         tzr->secs = 2 * 60 * 60;
411
412       tzr->computed_for = -1;
413     }
414
415  out:
416   __daylight = tz_rules[0].offset != tz_rules[1].offset;
417   __timezone = -tz_rules[0].offset;
418   __tzname[0] = (char *) tz_rules[0].name;
419   __tzname[1] = (char *) tz_rules[1].name;
420
421   {
422     /* Keep __tzname_cur_max up to date.  */
423     size_t len0 = strlen (__tzname[0]);
424     size_t len1 = strlen (__tzname[1]);
425     if (len0 > __tzname_cur_max)
426       __tzname_cur_max = len0;
427     if (len1 > __tzname_cur_max)
428       __tzname_cur_max = len1;
429   }
430 }
431 \f
432 /* Figure out the exact time (as a time_t) in YEAR
433    when the change described by RULE will occur and
434    put it in RULE->change, saving YEAR in RULE->computed_for.  */
435 static void
436 internal_function
437 compute_change (rule, year)
438      tz_rule *rule;
439      int year;
440 {
441   register time_t t;
442
443   if (year != -1 && rule->computed_for == year)
444     /* Operations on times in 2 BC will be slower.  Oh well.  */
445     return;
446
447   /* First set T to January 1st, 0:00:00 GMT in YEAR.  */
448   if (year > 1970)
449     t = ((year - 1970) * 365
450          + /* Compute the number of leapdays between 1970 and YEAR
451               (exclusive).  There is a leapday every 4th year ...  */
452          + ((year - 1) / 4 - 1970 / 4)
453          /* ... except every 100th year ... */
454          - ((year - 1) / 100 - 1970 / 100)
455          /* ... but still every 400th year.  */
456          + ((year - 1) / 400 - 1970 / 400)) * SECSPERDAY;
457   else
458     t = 0;
459
460   switch (rule->type)
461     {
462     case J1:
463       /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
464          In non-leap years, or if the day number is 59 or less, just
465          add SECSPERDAY times the day number-1 to the time of
466          January 1, midnight, to get the day.  */
467       t += (rule->d - 1) * SECSPERDAY;
468       if (rule->d >= 60 && __isleap (year))
469         t += SECSPERDAY;
470       break;
471
472     case J0:
473       /* n - Day of year.
474          Just add SECSPERDAY times the day number to the time of Jan 1st.  */
475       t += rule->d * SECSPERDAY;
476       break;
477
478     case M:
479       /* Mm.n.d - Nth "Dth day" of month M.  */
480       {
481         unsigned int i;
482         int d, m1, yy0, yy1, yy2, dow;
483         const unsigned short int *myday =
484           &__mon_yday[__isleap (year)][rule->m];
485
486         /* First add SECSPERDAY for each day in months before M.  */
487         t += myday[-1] * SECSPERDAY;
488
489         /* Use Zeller's Congruence to get day-of-week of first day of month. */
490         m1 = (rule->m + 9) % 12 + 1;
491         yy0 = (rule->m <= 2) ? (year - 1) : year;
492         yy1 = yy0 / 100;
493         yy2 = yy0 % 100;
494         dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
495         if (dow < 0)
496           dow += 7;
497
498         /* DOW is the day-of-week of the first day of the month.  Get the
499            day-of-month (zero-origin) of the first DOW day of the month.  */
500         d = rule->d - dow;
501         if (d < 0)
502           d += 7;
503         for (i = 1; i < rule->n; ++i)
504           {
505             if (d + 7 >= (int) myday[0] - myday[-1])
506               break;
507             d += 7;
508           }
509
510         /* D is the day-of-month (zero-origin) of the day we want.  */
511         t += d * SECSPERDAY;
512       }
513       break;
514     }
515
516   /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
517      Just add the time of day and local offset from GMT, and we're done.  */
518
519   rule->change = t - rule->offset + rule->secs;
520   rule->computed_for = year;
521 }
522
523
524 /* Figure out the correct timezone for TM and set `__tzname',
525    `__timezone', and `__daylight' accordingly.  */
526 static void
527 internal_function
528 tz_compute (tm)
529      const struct tm *tm;
530 {
531   compute_change (&tz_rules[0], 1900 + tm->tm_year);
532   compute_change (&tz_rules[1], 1900 + tm->tm_year);
533 }
534 \f
535 /* Reinterpret the TZ environment variable and set `tzname'.  */
536 #undef tzset
537
538 void
539 __tzset (void)
540 {
541   __libc_lock_lock (tzset_lock);
542
543   tzset_internal (1, 1);
544
545   if (!__use_tzfile)
546     {
547       /* Set `tzname'.  */
548       __tzname[0] = (char *) tz_rules[0].name;
549       __tzname[1] = (char *) tz_rules[1].name;
550     }
551
552   __libc_lock_unlock (tzset_lock);
553 }
554 weak_alias (__tzset, tzset)
555 \f
556 /* Return the `struct tm' representation of *TIMER in the local timezone.
557    Use local time if USE_LOCALTIME is nonzero, UTC otherwise.  */
558 struct tm *
559 __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
560 {
561   long int leap_correction;
562   int leap_extra_secs;
563
564   if (timer == NULL)
565     {
566       __set_errno (EINVAL);
567       return NULL;
568     }
569
570   __libc_lock_lock (tzset_lock);
571
572   /* Update internal database according to current TZ setting.
573      POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
574      This is a good idea since this allows at least a bit more parallelism.
575      By analogy we apply the same rule to gmtime_r.  */
576   tzset_internal (tp == &_tmbuf, 0);
577
578   if (__use_tzfile)
579     __tzfile_compute (*timer, use_localtime, &leap_correction,
580                       &leap_extra_secs, tp);
581   else
582     {
583       if (! __offtime (timer, 0, tp))
584         tp = NULL;
585       else
586         tz_compute (tp);
587       leap_correction = 0L;
588       leap_extra_secs = 0;
589     }
590
591   if (tp)
592     {
593       if (use_localtime)
594         {
595           if (!__use_tzfile)
596             {
597               int isdst;
598
599               /* We have to distinguish between northern and southern
600                  hemisphere.  For the latter the daylight saving time
601                  ends in the next year.  */
602               if (__builtin_expect (tz_rules[0].change
603                                     > tz_rules[1].change, 0))
604                 isdst = (*timer < tz_rules[1].change
605                          || *timer >= tz_rules[0].change);
606               else
607                 isdst = (*timer >= tz_rules[0].change
608                          && *timer < tz_rules[1].change);
609               tp->tm_isdst = isdst;
610               tp->tm_zone = __tzname[isdst];
611               tp->tm_gmtoff = tz_rules[isdst].offset;
612             }
613         }
614       else
615         {
616           tp->tm_isdst = 0;
617           tp->tm_zone = "GMT";
618           tp->tm_gmtoff = 0L;
619         }
620
621       if (__offtime (timer, tp->tm_gmtoff - leap_correction, tp))
622         tp->tm_sec += leap_extra_secs;
623       else
624         tp = NULL;
625     }
626
627   __libc_lock_unlock (tzset_lock);
628
629   return tp;
630 }
631
632
633 libc_freeres_fn (free_mem)
634 {
635   while (tzstring_list != NULL)
636     {
637       struct tzstring_l *old = tzstring_list;
638
639       tzstring_list = tzstring_list->next;
640       free (old);
641     }
642   free (old_tz);
643   old_tz = NULL;
644 }