]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/tzfile.c
initial import
[thirdparty/glibc.git] / time / tzfile.c
CommitLineData
28f540f4
RM
1/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
2This file is part of the GNU C Library.
3
4The GNU C Library is free software; you can redistribute it and/or
5modify it under the terms of the GNU Library General Public License as
6published by the Free Software Foundation; either version 2 of the
7License, or (at your option) any later version.
8
9The GNU C Library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12Library General Public License for more details.
13
14You should have received a copy of the GNU Library General Public
15License along with the GNU C Library; see the file COPYING.LIB. If
16not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17Cambridge, 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
35int __use_tzfile = 0;
36
37struct 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
45struct leap
46 {
47 time_t transition; /* Time the transition takes effect. */
48 long int change; /* Seconds of correction to apply. */
49 };
50
51static void compute_tzname_max __P ((size_t));
52
53static size_t num_transitions;
54static time_t *transitions = NULL;
55static unsigned char *type_idxs = NULL;
56static size_t num_types;
57static struct ttinfo *types = NULL;
58static char *zone_names = NULL;
59static size_t num_leaps;
60static 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
67void
68DEFUN(__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
202void
203DEFUN(__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
249int
250DEFUN(__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
316void
317DEFUN(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}