]>
Commit | Line | Data |
---|---|---|
28f540f4 RM |
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 | } |