Formerly time/time.h.~10~
[kopensolaris-gnu/glibc.git] / time / tzset.c
1 /* Copyright (C) 1991, 1992 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
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <localeinfo.h>
21 #include <ctype.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27
28 #ifndef HAVE_GNU_LD
29 #define __tzname        tzname
30 #define __daylight      daylight
31 #define __timezone      timezone
32 #endif
33
34 extern int __use_tzfile;
35 extern void EXFUN(__tzfile_read, (CONST char *file));
36 extern int EXFUN(__tzfile_compute, (time_t, struct tm));
37
38 char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
39 int __daylight = 0;
40 long int __timezone = 0L;
41
42
43 #define min(a, b)       ((a) < (b) ? (a) : (b))
44 #define max(a, b)       ((a) > (b) ? (a) : (b))
45 #define sign(x)         ((x) < 0 ? -1 : 1)
46
47
48 /* This structure contains all the information about a
49    timezone given in the POSIX standard TZ envariable.  */
50 typedef struct
51   {
52     CONST char *name;
53
54     /* When to change.  */
55     enum { J0, J1, M } type;    /* Interpretation of:  */
56     unsigned short int m, n, d; /* Month, week, day.  */
57     unsigned int secs:17;       /* Time of day.  */
58
59     long int offset;            /* Seconds east of GMT (west if < 0).  */
60
61     /* We cache the computed time of change for a
62        given year so we don't have to recompute it.  */
63     time_t change;      /* When to change to this zone.  */
64     int computed_for;   /* Year above is computed for.  */
65   } tz_rule;
66
67 /* tz_rules[0] is standard, tz_rules[1] is daylight.  */
68 static tz_rule tz_rules[2];
69 \f
70 static int tzset_run = 0;
71
72 /* Interpret the TZ envariable.  */
73 void
74 DEFUN_VOID(__tzset)
75 {
76   register CONST char *tz;
77   register size_t l;
78   unsigned short int hh, mm, ss;
79   unsigned short int whichrule;
80
81   /* Free old storage.  */
82   if (tz_rules[0].name != NULL && *tz_rules[0].name != '\0')
83     free((PTR) tz_rules[0].name);
84   if (tz_rules[1].name != NULL && *tz_rules[1].name != '\0' &&
85       tz_rules[1].name != tz_rules[0].name)
86     free((PTR) tz_rules[1].name);
87
88   tz = getenv("TZ");
89
90   if (tz != NULL && *tz == ':')
91     {
92       __tzfile_read(tz + 1);
93       if (__use_tzfile)
94         {
95           tzset_run = 1;
96           return;
97         }
98       else
99         tz = NULL;
100     }
101
102   if (tz == NULL || *tz == '\0')
103     tz = _time_info->tz;
104   if (tz == NULL || *tz == '\0')
105     {
106       __tzfile_read((char *) NULL);
107       if (!__use_tzfile)
108         {
109           size_t len = strlen(_time_info->ut0) + 1;
110           tz_rules[0].name = (char *) malloc(len);
111           if (tz_rules[0].name == NULL)
112             return;
113           tz_rules[1].name = (char *) malloc(len);
114           if (tz_rules[1].name == NULL)
115             return;
116           memcpy((PTR) tz_rules[0].name, _time_info->ut0, len);
117           memcpy((PTR) tz_rules[1].name, _time_info->ut0, len);
118           tz_rules[0].type = tz_rules[1].type = J0;
119           tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
120           tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
121           tz_rules[0].secs = tz_rules[1].secs = 0;
122           tz_rules[0].offset = tz_rules[1].offset = 0L;
123           tz_rules[0].change = tz_rules[1].change = (time_t) -1;
124           tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
125         }
126       tzset_run = 1;
127       return;
128     }
129
130   /* Get the standard timezone name.  */
131   tz_rules[0].name = (char *) malloc(strlen(tz) + 1);
132   if (tz_rules[0].name == NULL)
133     return;
134
135   if (sscanf(tz, "%[^0-9,+-]", tz_rules[0].name) != 1 ||
136       (l = strlen(tz_rules[0].name)) < 3)
137     return;
138
139   tz_rules[0].name = (char *) realloc((PTR) tz_rules[0].name, l + 1);
140   if (tz_rules[0].name == NULL)
141     return;
142
143   tz += l;
144
145   /* Figure out the standard offset from GMT.  */
146   if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit(*tz)))
147     return;
148
149   if (*tz == '-' || *tz == '+')
150     tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
151   else
152     tz_rules[0].offset = -1L;
153   switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
154     {
155     default:
156       return;
157     case 1:
158       mm = 0;
159     case 2:
160       ss = 0;
161     case 3:
162       break;
163     }
164   tz_rules[0].offset *= (min(ss, 59) + (min(mm, 59) * 60) +
165                          (min(hh, 12) * 60 * 60));
166
167   for (l = 0; l < 3; ++l)
168     {
169       while (isdigit(*tz))
170         ++tz;
171       if (l < 2 && *tz == ':')
172         ++tz;
173     }
174
175   /* Get the DST timezone name (if any).  */
176   if (*tz == '\0')
177     tz_rules[1].name = "";
178   else
179     {
180       tz_rules[1].name = (char *) malloc(strlen(tz) + 1);
181       if (tz_rules[1].name == NULL)
182         return;
183       if (sscanf(tz, "%[^0-9,+-]", tz_rules[1].name) != 1 ||
184           (l = strlen(tz_rules[1].name)) < 3)
185         return;
186       tz_rules[1].name = (char *) realloc((PTR) tz_rules[1].name, l + 1);
187       if (tz_rules[1].name == NULL)
188         return;
189     }
190
191   tz += l;
192
193   /* Figure out the DST offset from GMT.  */
194   if (*tz == '-' || *tz == '+')
195     tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
196   else
197     tz_rules[1].offset = -1L;
198
199   switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
200     {
201     default:
202       /* Default to one hour later than standard time.  */
203       tz_rules[1].offset *= abs (tz_rules[0].offset);
204       hh = 1;
205
206     case 1:
207       mm = 0;
208     case 2:
209       ss = 0;
210     case 3:
211       break;
212     }
213   tz_rules[1].offset *= (min(ss, 59) + (min(mm, 59) * 60) +
214                          (min(hh, 12) * (60 * 60)));
215   for (l = 0; l < 3; ++l)
216     {
217       while (isdigit(*tz))
218         ++tz;
219       if (l < 2 && *tz == ':')
220         ++tz;
221     }
222
223   /* If no standard or DST offset was given, default to GMT
224      for standard and one hour later than standard for DST.  */
225   if (*tz_rules[0].name == '\0')
226     tz_rules[0].offset = 0L;
227   if (*tz_rules[1].name == '\0')
228     tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
229
230   /* Figure out the standard <-> DST rules.  */
231   for (whichrule = 0; whichrule < 2; ++whichrule)
232     {
233       register tz_rule *tzr = &tz_rules[whichrule];
234       
235       if (*tz != '\0' && *tz == ',')
236         {
237           ++tz;
238           if (*tz == '\0')
239             return;
240         }
241       
242       /* Get the date of the change.  */
243       if (*tz == 'J' || isdigit(*tz))
244         {
245           char *end;
246           tzr->type = *tz == 'J' ? J1 : J0;
247           if (tzr->type == J1 && !isdigit(*++tz))
248             return;
249           tzr->n = (unsigned short int) strtoul(tz, &end, 10);
250           if (end == tz || tzr->n > 365)
251             return;
252           else if (tzr->type == J1 && tzr->n == 0)
253             return;
254           if (tzr->type == J1 && tzr->n == 60)
255             /* Can't do February 29.  */
256             ++tzr->n;
257           tz = end;
258         }
259       else if (*tz == 'M')
260         {
261           int n;
262           tzr->type = M;
263           if (sscanf (tz, "M%hu.%hu.%hu%n",
264                       &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
265               tzr->m < 1 || tzr->m > 12 ||
266               tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
267             return;
268           tz += n;
269         }
270       else if (*tz == '\0')
271         {
272           /* United States Federal Law, the equivalent of "M3.1.0,M8.5.0".  */
273           tzr->type = M;
274           if (tzr == &tz_rules[0])
275             {
276               tzr->m = 4;
277               tzr->n = 1;
278               tzr->d = 0;
279             }
280           else
281             {
282               tzr->m = 10;
283               tzr->n = 5;
284               tzr->d = 0;
285             }
286         }
287       else
288         return;
289       
290       if (*tz != '\0' && *tz != '/' && *tz != ',')
291         return;
292       else if (*tz == '/')
293         {
294           /* Get the time of day of the change.  */
295           ++tz;
296           if (*tz == '\0')
297             return;
298           switch (sscanf(tz, "%hu:%hu:%hu", &hh, &mm, &ss))
299             {
300             default:
301               return;
302             case 1:
303               mm = 0;
304             case 2:
305               ss = 0;
306             case 3:
307               break;
308             }
309           for (l = 0; l < 3; ++l)
310             {
311               while (isdigit(*tz))
312                 ++tz;
313               if (l < 2 && *tz == ':')
314                 ++tz;
315             }
316           tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
317         }
318       else
319         /* Default to 2:00 AM.  */
320         tzr->secs = 2 * 60 * 60;
321
322       tzr->computed_for = -1;
323     }
324
325   tzset_run = 1;
326 }
327 \f
328 /* Figure out the exact time (as a time_t) in YEAR
329    when the change described by RULE will occur and
330    put it in RULE->change, saving YEAR in RULE->computed_for.
331    Return nonzero if successful, zero on failure.  */
332 static int
333 DEFUN(compute_change, (rule, year), tz_rule *rule AND int year)
334 {
335   register unsigned short int m = rule->m, n = rule->n, d = rule->d;
336   struct tm tbuf;
337   register time_t t;
338
339   if (year != -1 && rule->computed_for == year)
340     /* Operations on times in 1969 will be slower.  Oh well.  */
341     return 1;
342
343   memset((PTR) &tbuf, 0, sizeof(tbuf));
344   tbuf.tm_year = year;
345
346   if (rule->type == M)
347     {
348       /* Defined in _offtime.c.  */
349       extern CONST unsigned short int __mon_lengths[2][12];
350       unsigned short int ml = __mon_lengths[__isleap(tbuf.tm_year)][m - 1];
351       tbuf.tm_mon = m - 1;
352       if (n == 5)
353         tbuf.tm_mday = ml;
354       else
355         tbuf.tm_mday = max((n - 1) * 7, 1);
356       tbuf.tm_sec = rule->secs;
357       t = mktime(&tbuf);
358       if (t == (time_t) -1)
359         return 0;
360       if (tbuf.tm_wday != d)
361         {
362           if (d > tbuf.tm_wday)
363             {
364               tbuf.tm_mday -= 7;
365               tbuf.tm_mday += tbuf.tm_wday - d;
366             }
367           else
368             tbuf.tm_mday -= tbuf.tm_wday - d;
369           if (tbuf.tm_mday < 1)
370             tbuf.tm_mday += 7;
371           else
372             if (tbuf.tm_mday > ml) tbuf.tm_mday -= 7;
373           t = mktime(&tbuf);
374           if (t == (time_t) -1)
375             return 0;
376         }
377     }
378   else
379     {
380       tbuf.tm_mon = 0;
381       if (rule->type == J1)
382         --n;
383       tbuf.tm_mday = n;
384       tbuf.tm_sec = rule->secs;
385       t = mktime(&tbuf);
386       if (t == (time_t) -1)
387         return 0;
388     }
389
390   rule->change = t;
391   rule->computed_for = year;
392   return 1;
393 }
394
395
396 /* Figure out the correct timezone for *TIMER and TM (which must be the same)
397    and set `__tzname', `__timezone', and `__daylight' accordingly.
398    Return nonzero on success, zero on failure.  */
399 int
400 DEFUN(__tz_compute, (timer, tm),
401       time_t timer AND struct tm tm)
402 {
403   if (!tzset_run)
404     __tzset();
405
406   if (__use_tzfile)
407     return __tzfile_compute(timer, tm);
408
409   if (!compute_change(&tz_rules[0], tm.tm_year) ||
410       !compute_change(&tz_rules[1], tm.tm_year))
411     return 0;
412
413   __daylight = timer >= tz_rules[0].change && timer < tz_rules[1].change;
414   __timezone = tz_rules[__daylight ? 1 : 0].offset;
415   __tzname[0] = (char *) tz_rules[0].name;
416   __tzname[1] = (char *) tz_rules[1].name;
417
418   return 1;
419 }
420
421
422 long int
423 DEFUN_VOID (__tzname_max)
424 {
425   size_t len0 = strlen (__tzname[0]), len1 = strlen (__tzname[1]);
426   return len0 > len1 ? len0 : len1;
427 }