(__tzfile_default): Initialize RULE_STDOFF to zero.
[kopensolaris-gnu/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991, 1992, 1993, 1995 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 <stdlib.h>
21 #include <stdio.h>
22 #include <time.h>
23 #include <string.h>
24 #include <limits.h>
25
26 #define NOID
27 #include <tzfile.h>
28
29 int __use_tzfile = 0;
30
31 struct ttinfo
32   {
33     long int offset;            /* Seconds east of GMT.  */
34     unsigned char isdst;        /* Used to set tm_isdst.  */
35     unsigned char idx;          /* Index into `zone_names'.  */
36     unsigned char isstd;        /* Transition times are in standard time.  */
37     unsigned char isgmt;        /* Transition times are in GMT.  */
38   };
39
40 struct leap
41   {
42     time_t transition;          /* Time the transition takes effect.  */
43     long int change;            /* Seconds of correction to apply.  */
44   };
45
46 static void compute_tzname_max __P ((size_t));
47
48 static size_t num_transitions;
49 static time_t *transitions = NULL;
50 static unsigned char *type_idxs = NULL;
51 static size_t num_types;
52 static struct ttinfo *types = NULL;
53 static char *zone_names = NULL;
54 static size_t num_leaps;
55 static struct leap *leaps = NULL;
56
57 #include <endian.h>
58
59 /* Decode the four bytes at PTR as a signed integer in network byte order.  */
60 static inline int
61 decode (const void *ptr)
62 {
63 #if BYTE_ORDER == BIG_ENDIAN
64   return *(const int *) ptr;
65 #else
66   const unsigned char *p = ptr;
67   int result = 0;
68
69   result = (result << 8) | *p++;
70   result = (result << 8) | *p++;
71   result = (result << 8) | *p++;
72   result = (result << 8) | *p++;
73
74   return result;
75 #endif
76 }
77
78 void
79 DEFUN(__tzfile_read, (file), CONST char *file)
80 {
81   size_t num_isstd, num_isgmt;
82   register FILE *f;
83   struct tzhead tzhead;
84   size_t chars;
85   register size_t i;
86
87   __use_tzfile = 0;
88
89   if (transitions != NULL)
90     free((PTR) transitions);
91   transitions = NULL;
92   if (type_idxs != NULL)
93     free((PTR) type_idxs);
94   type_idxs = NULL;
95   if (types != NULL)
96     free((PTR) types);
97   types = NULL;
98   if (zone_names != NULL)
99     free((PTR) zone_names);
100   zone_names = NULL;
101   if (leaps != NULL)
102     free((PTR) leaps);
103   leaps = NULL;
104
105   if (file == NULL || *file == '\0')
106     file = TZDEFAULT;
107
108   if (*file != '/')
109     {
110       static CONST char tzdir[] = TZDIR;
111       register CONST unsigned int len = strlen(file) + 1;
112       char *new = (char *) __alloca(sizeof(tzdir) + len);
113       memcpy(new, tzdir, sizeof(tzdir) - 1);
114       new[sizeof(tzdir) - 1] = '/';
115       memcpy(&new[sizeof(tzdir)], file, len);
116       file = new;
117     }
118
119   f = fopen(file, "r");
120   if (f == NULL)
121     return;
122
123   if (fread((PTR) &tzhead, sizeof(tzhead), 1, f) != 1)
124     goto lose;
125
126   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
127   num_types = (size_t) decode (tzhead.tzh_typecnt);
128   chars = (size_t) decode (tzhead.tzh_charcnt);
129   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
130   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
131   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
132
133   if (num_transitions > 0)
134     {
135       transitions = (time_t *) malloc (num_transitions * sizeof(time_t));
136       if (transitions == NULL)
137         goto lose;
138       type_idxs = (unsigned char *) malloc (num_transitions);
139       if (type_idxs == NULL)
140         goto lose;
141     }
142   if (num_types > 0)
143     {
144       types = (struct ttinfo *) malloc (num_types * sizeof (struct ttinfo));
145       if (types == NULL)
146         goto lose;
147     }
148   if (chars > 0)
149     {
150       zone_names = (char *) malloc (chars);
151       if (zone_names == NULL)
152         goto lose;
153     }
154   if (num_leaps > 0)
155     {
156       leaps = (struct leap *) malloc (num_leaps * sizeof (struct leap));
157       if (leaps == NULL)
158         goto lose;
159     }
160
161   if (fread((PTR) transitions, 4, num_transitions, f) != num_transitions ||
162       fread((PTR) type_idxs, 1, num_transitions, f) != num_transitions)
163     goto lose;
164
165   if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
166     {
167       /* Decode the transition times, stored as 4-byte integers in
168          network (big-endian) byte order.  We work from the end of
169          the array so as not to clobber the next element to be
170          processed when sizeof (time_t) > 4.  */
171       i = num_transitions;
172       while (num_transitions-- > 0)
173         transitions[i] = decode ((char *) transitions + i*4);
174     }
175
176   for (i = 0; i < num_types; ++i)
177     {
178       unsigned char x[4];
179       if (fread((PTR) x, 1, 4, f) != 4 ||
180           fread((PTR) &types[i].isdst, 1, 1, f) != 1 ||
181           fread((PTR) &types[i].idx, 1, 1, f) != 1)
182         goto lose;
183       types[i].offset = (long int) decode (x);
184     }
185
186   if (fread((PTR) zone_names, 1, chars, f) != chars)
187     goto lose;
188
189   for (i = 0; i < num_leaps; ++i)
190     {
191       unsigned char x[4];
192       if (fread((PTR) x, 1, sizeof(x), f) != sizeof(x))
193         goto lose;
194       leaps[i].transition = (time_t) decode (x);
195       if (fread((PTR) x, 1, sizeof(x), f) != sizeof(x))
196         goto lose;
197       leaps[i].change = (long int) decode (x);
198     }
199
200   for (i = 0; i < num_isstd; ++i)
201     {
202       char c = getc(f);
203       if (c == EOF)
204         goto lose;
205       types[i].isstd = c != 0;
206     }
207   while (i < num_types)
208     types[i++].isstd = 0;
209
210   for (i = 0; i < num_isgmt; ++i)
211     {
212       char c = getc(f);
213       if (c == EOF)
214         goto lose;
215       types[i].isgmt = c != 0;
216     }
217   while (i < num_types)
218     types[i++].isgmt = 0;
219
220   (void) fclose(f);
221
222   compute_tzname_max (chars);
223   
224   __use_tzfile = 1;
225   return;
226
227  lose:;
228   (void) fclose(f);
229 }
230 \f
231 /* The user specified a hand-made timezone, but not its DST rules.
232    We will use the names and offsets from the user, and the rules
233    from the TZDEFRULES file.  */
234
235 void
236 DEFUN(__tzfile_default, (std, dst, stdoff, dstoff),
237       char *std AND char *dst AND
238       long int stdoff AND long int dstoff)
239 {
240   size_t stdlen, dstlen, i;
241   long int rule_offset, rule_stdoff, rule_dstoff;
242   int isdst;
243
244   __tzfile_read (TZDEFRULES);
245   if (!__use_tzfile)
246     return;
247
248   if (num_types < 2)
249     {
250       __use_tzfile = 0;
251       return;
252     }
253
254   /* Ignore the zone names read from the file.  */
255   free (zone_names);
256
257   /* Use the names the user specified.  */
258   stdlen = strlen (std) + 1;
259   dstlen = strlen (dst) + 1;
260   zone_names = malloc (stdlen + dstlen);
261   if (zone_names == NULL)
262     {
263       __use_tzfile = 0;
264       return;
265     }
266   memcpy (zone_names, std, stdlen);
267   memcpy (&zone_names[stdlen], dst, dstlen);
268
269   /* Find the standard and daylight time offsets used by the rule file.
270      We choose the offsets in the types of each flavor that are
271      transitioned to earliest in time.  */
272   rule_stdoff = rule_dstoff = 0;
273   for (i = 0; i < num_transitions; ++i)
274     {
275       if (!rule_stdoff && !types[type_idxs[i]].isdst)
276         rule_stdoff = types[type_idxs[i]].offset;
277       if (!rule_dstoff && types[type_idxs[i]].isdst)
278         rule_dstoff = types[type_idxs[i]].offset;
279       if (rule_stdoff && rule_dstoff)
280         break;
281     }
282
283   /* Now correct the transition times for the user-specified standard and
284      daylight offsets from GMT.  */
285   isdst = 0;
286   rule_offset = rule_offset;
287   for (i = 0; i < num_transitions; ++i)
288     {
289       struct ttinfo *trans_type = &types[type_idxs[i]];
290
291       /* We will use only types 0 (standard) and 1 (daylight).
292          Fix up this transition to point to whichever matches
293          the flavor of its original type.  */
294       type_idxs[i] = trans_type->isdst;
295
296       if (trans_type->isgmt)
297         /* The transition time is in GMT.  No correction to apply.  */ ;
298       else if (isdst && !trans_type->isstd)
299         /* The type says this transition is in "local wall clock time", and
300            wall clock time as of the previous transition was DST.  Correct
301            for the difference between the rule's DST offset and the user's
302            DST offset.  */
303         transitions[i] += dstoff - rule_dstoff;
304       else
305         /* This transition is in "local wall clock time", and wall clock
306            time as of this iteration is non-DST.  Correct for the
307            difference between the rule's standard offset and the user's
308            standard offset.  */
309         transitions[i] += stdoff - rule_stdoff;
310
311       /* The DST state of "local wall clock time" for the next iteration is
312          as specified by this transition.  */
313       isdst = trans_type->isdst;
314     }
315
316   /* Reset types 0 and 1 to describe the user's settings.  */
317   types[0].idx = 0;
318   types[0].offset = stdoff;
319   types[0].isdst = 0;
320   types[1].idx = stdlen;
321   types[1].offset = dstoff;
322   types[1].isdst = 1;
323
324   compute_tzname_max (stdlen + dstlen);
325 }
326 \f
327 int
328 DEFUN(__tzfile_compute, (timer, leap_correct, leap_hit),
329       time_t timer AND long int *leap_correct AND int *leap_hit)
330 {
331   struct ttinfo *info;
332   register size_t i;
333
334   if (num_transitions == 0 || timer < transitions[0])
335     {
336       /* TIMER is before any transition (or there are no transitions).
337          Choose the first non-DST type
338          (or the first if they're all DST types).  */
339       i = 0;
340       while (i < num_types && types[i].isdst)
341         ++i;
342       if (i == num_types)
343         i = 0;
344     }
345   else
346     {
347       /* Find the first transition after TIMER, and
348          then pick the type of the transition before it.  */
349       for (i = 1; i < num_transitions; ++i)
350         if (timer < transitions[i])
351           break;
352       i = type_idxs[i - 1];
353     }
354
355   info = &types[i];
356   __daylight = info->isdst;
357   __timezone = info->offset;
358   for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
359        ++i)
360     __tzname[types[i].isdst] = &zone_names[types[i].idx];
361   if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
362     __tzname[info->isdst] = &zone_names[info->idx];
363
364   *leap_correct = 0L;
365   *leap_hit = 0;
366
367   /* Find the last leap second correction transition time before TIMER.  */
368   i = num_leaps;
369   do
370     if (i-- == 0)
371       return 1;
372   while (timer < leaps[i].transition);
373
374   /* Apply its correction.  */
375   *leap_correct = leaps[i].change;
376
377   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
378       ((i == 0 && leaps[i].change > 0) ||
379        leaps[i].change > leaps[i - 1].change))
380     {
381       *leap_hit = 1;
382       while (i > 0 &&
383              leaps[i].transition == leaps[i - 1].transition + 1 &&
384              leaps[i].change == leaps[i - 1].change + 1)
385         {
386           ++*leap_hit;
387           --i;
388         }
389     }
390
391   return 1;
392 }
393 \f
394 void
395 DEFUN(compute_tzname_max, (chars), size_t chars)
396 {
397   extern long int __tzname_cur_max; /* Defined in __tzset.c. */
398
399   const char *p;
400
401   p = zone_names;
402   do
403     {
404       const char *start = p;
405       while (*p != '\0')
406         ++p;
407       if (p - start > __tzname_cur_max)
408         __tzname_cur_max = p - start;
409     } while (++p < &zone_names[chars]);
410 }