Formerly ../time/sys/time.h.~16~
[kopensolaris-gnu/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991, 1992, 1993 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 #ifndef HAVE_GNU_LD
30 #define __tzname        tzname
31 #define __daylight      daylight
32 #define __timezone      timezone
33 #endif
34
35 int __use_tzfile = 0;
36
37 struct ttinfo
38   {
39     long int offset;            /* Seconds east of GMT.  */
40     unsigned char isdst;        /* Used to set tm_isdst.  */
41     unsigned char idx;          /* Index into `zone_names'.  */
42     unsigned char isstd;        /* Transition times are standard time.  */
43   };
44
45 struct leap
46   {
47     time_t transition;          /* Time the transition takes effect.  */
48     long int change;            /* Seconds of correction to apply.  */
49   };
50
51 static void compute_tzname_max __P ((size_t));
52
53 static size_t num_transitions;
54 static time_t *transitions = NULL;
55 static unsigned char *type_idxs = NULL;
56 static size_t num_types;
57 static struct ttinfo *types = NULL;
58 static char *zone_names = NULL;
59 static size_t num_leaps;
60 static struct leap *leaps = NULL;
61
62 #define uc2ul(x)        _uc2ul((unsigned char *) (x))
63 #define _uc2ul(x)                                                             \
64   ((x)[3] + ((x)[2] << CHAR_BIT) + ((x)[1] << (2 * CHAR_BIT)) +               \
65    ((x)[0] << (3 * CHAR_BIT)))
66
67 void
68 DEFUN(__tzfile_read, (file), CONST char *file)
69 {
70   size_t num_isstd;
71   register FILE *f;
72   struct tzhead tzhead;
73   size_t chars;
74   register size_t i;
75
76   __use_tzfile = 0;
77
78   if (transitions != NULL)
79     free((PTR) transitions);
80   transitions = NULL;
81   if (type_idxs != NULL)
82     free((PTR) type_idxs);
83   type_idxs = NULL;
84   if (types != NULL)
85     free((PTR) types);
86   types = NULL;
87   if (zone_names != NULL)
88     free((PTR) zone_names);
89   zone_names = NULL;
90   if (leaps != NULL)
91     free((PTR) leaps);
92   leaps = NULL;
93
94   if (file == NULL || *file == '\0')
95     file = TZDEFAULT;
96
97   if (*file != '/')
98     {
99       static CONST char tzdir[] = TZDIR;
100       register CONST unsigned int len = strlen(file) + 1;
101       char *new = (char *) __alloca(sizeof(tzdir) + len);
102       memcpy(new, tzdir, sizeof(tzdir) - 1);
103       new[sizeof(tzdir) - 1] = '/';
104       memcpy(&new[sizeof(tzdir)], file, len);
105       file = new;
106     }
107
108   f = fopen(file, "r");
109   if (f == NULL)
110     return;
111
112   if (fread((PTR) &tzhead, sizeof(tzhead), 1, f) != 1)
113     goto lose;
114
115   num_transitions = (size_t) uc2ul(tzhead.tzh_timecnt);
116   num_types = (size_t) uc2ul(tzhead.tzh_typecnt);
117   chars = (size_t) uc2ul(tzhead.tzh_charcnt);
118   num_leaps = (size_t) uc2ul(tzhead.tzh_leapcnt);
119   num_isstd = (size_t) uc2ul(tzhead.tzh_ttisstdcnt);
120
121   if (num_transitions > 0)
122     {
123       transitions = (time_t *) malloc (num_transitions * sizeof(time_t));
124       if (transitions == NULL)
125         goto lose;
126       type_idxs = (unsigned char *) malloc (num_transitions);
127       if (type_idxs == NULL)
128         goto lose;
129     }
130   if (num_types > 0)
131     {
132       types = (struct ttinfo *) malloc (num_types * sizeof (struct ttinfo));
133       if (types == NULL)
134         goto lose;
135     }
136   if (chars > 0)
137     {
138       zone_names = (char *) malloc (chars);
139       if (zone_names == NULL)
140         goto lose;
141     }
142   if (num_leaps > 0)
143     {
144       leaps = (struct leap *) malloc (num_leaps * sizeof (struct leap));
145       if (leaps == NULL)
146         goto lose;
147     }
148
149   if (fread((PTR) transitions, sizeof(time_t),
150             num_transitions, f) != num_transitions ||
151       fread((PTR) type_idxs, 1, num_transitions, f) != num_transitions)
152     goto lose;
153
154   for (i = 0; i < num_transitions; ++i)
155     transitions[i] = uc2ul (&transitions[i]);
156
157   for (i = 0; i < num_types; ++i)
158     {
159       unsigned char x[4];
160       if (fread((PTR) x, 1, 4, f) != 4 ||
161           fread((PTR) &types[i].isdst, 1, 1, f) != 1 ||
162           fread((PTR) &types[i].idx, 1, 1, f) != 1)
163         goto lose;
164       types[i].offset = (long int) uc2ul(x);
165     }
166
167   if (fread((PTR) zone_names, 1, chars, f) != chars)
168     goto lose;
169
170   for (i = 0; i < num_leaps; ++i)
171     {
172       unsigned char x[4];
173       if (fread((PTR) x, 1, sizeof(x), f) != sizeof(x))
174         goto lose;
175       leaps[i].transition = (time_t) uc2ul(x);
176       if (fread((PTR) x, 1, sizeof(x), f) != sizeof(x))
177         goto lose;
178       leaps[i].change = (long int) uc2ul(x);
179     }
180
181   for (i = 0; i < num_isstd; ++i)
182     {
183       char c = getc(f);
184       if (c == EOF)
185         goto lose;
186       types[i].isstd = c != 0;
187     }
188   while (i < num_types)
189     types[i++].isstd = 0;
190
191   (void) fclose(f);
192
193   compute_tzname_max (chars);
194   
195   __use_tzfile = 1;
196   return;
197
198  lose:;
199   (void) fclose(f);
200 }
201 \f
202 void
203 DEFUN(__tzfile_default, (std, dst, stdoff, dstoff),
204       char *std AND char *dst AND
205       long int stdoff AND long int dstoff)
206 {
207   size_t stdlen, dstlen, i;
208
209   __tzfile_read (TZDEFRULES);
210   if (!__use_tzfile)
211     return;
212
213   if (num_types < 2)
214     {
215       __use_tzfile = 0;
216       return;
217     }
218
219   free (zone_names);
220
221   stdlen = strlen (std) + 1;
222   dstlen = strlen (dst) + 1;
223   zone_names = malloc (stdlen + dstlen);
224   if (zone_names == NULL)
225     {
226       __use_tzfile = 0;
227       return;
228     }
229   memcpy (zone_names, std, stdlen);
230   memcpy (&zone_names[stdlen], dst, dstlen);
231
232   for (i = 0; i < num_types; ++i)
233     if (types[i].isdst)
234       {
235         types[i].idx = stdlen;
236         if (dst[0] != '\0')
237           types[i].offset = dstoff;
238       }
239     else
240       {
241         types[i].idx = 0;
242         if (dst[0] != '\0')
243           types[i].offset = stdoff;
244       }
245
246   compute_tzname_max (stdlen + dstlen);
247 }
248 \f
249 int
250 DEFUN(__tzfile_compute, (timer, leap_correct, leap_hit),
251       time_t timer AND long int *leap_correct AND int *leap_hit)
252 {
253   struct ttinfo *info;
254   register size_t i;
255
256   if (num_transitions == 0 || timer < transitions[0])
257     {
258       /* TIMER is before any transition (or there are no transitions).
259          Choose the first non-DST type
260          (or the first if they're all DST types).  */
261       i = 0;
262       while (i < num_types && types[i].isdst)
263         ++i;
264       if (i == num_types)
265         i = 0;
266     }
267   else
268     {
269       /* Find the first transition after TIMER, and
270          then pick the type of the transition before it.  */
271       for (i = 1; i < num_transitions; ++i)
272         if (timer < transitions[i])
273           break;
274       i = type_idxs[i - 1];
275     }
276
277   info = &types[i];
278   __daylight = info->isdst;
279   __timezone = info->offset;
280   for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
281        ++i)
282     __tzname[types[i].isdst] = &zone_names[types[i].idx];
283   if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
284     __tzname[info->isdst] = &zone_names[info->idx];
285
286   *leap_correct = 0L;
287   *leap_hit = 0;
288
289   /* Find the last leap second correction transition time before TIMER.  */
290   i = num_leaps;
291   do
292     if (i-- == 0)
293       return 1;
294   while (timer < leaps[i].transition);
295
296   /* Apply its correction.  */
297   *leap_correct = leaps[i].change;
298
299   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
300       ((i == 0 && leaps[i].change > 0) ||
301        leaps[i].change > leaps[i - 1].change))
302     {
303       *leap_hit = 1;
304       while (i > 0 &&
305              leaps[i].transition == leaps[i - 1].transition + 1 &&
306              leaps[i].change == leaps[i - 1].change + 1)
307         {
308           ++*leap_hit;
309           --i;
310         }
311     }
312
313   return 1;
314 }
315 \f
316 void
317 DEFUN(compute_tzname_max, (chars), size_t chars)
318 {
319   extern long int __tzname_cur_max; /* Defined in __tzset.c. */
320
321   const char *p;
322
323   p = zone_names;
324   do
325     {
326       const char *start = p;
327       while (*p != '\0')
328         ++p;
329       if (p - start > __tzname_cur_max)
330         __tzname_cur_max = p - start;
331     } while (++p < &zone_names[chars]);
332 }