source: trunk/minix/lib/ansi/misc.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 9.0 KB
Line 
1/*
2 * misc - data and miscellaneous routines
3 */
4/* $Header: /cvsup/minix/src/lib/ansi/misc.c,v 1.2 2005/06/17 13:00:04 jnherder Exp $ */
5
6#include <ctype.h>
7#include <time.h>
8#include <stdlib.h>
9#include <string.h>
10
11#if defined(__BSD4_2)
12
13struct timeval {
14 long tv_sec; /* seconds */
15 long tv_usec; /* and microseconds */
16};
17
18struct timezone {
19 int tz_minuteswest; /* minutes west of Greenwich */
20 int tz_dsttime; /* type of dst correction */
21};
22
23int _gettimeofday(struct timeval *tp, struct timezone *tzp);
24
25#elif !defined(_POSIX_SOURCE) && !defined(__USG)
26#if !defined(_MINIX) /* MINIX has no ftime() */
27struct timeb {
28 long time;
29 unsigned short millitm;
30 short timezone;
31 short dstflag;
32};
33void _ftime(struct timeb *bp);
34#endif
35#endif
36
37#include "loc_time.h"
38
39#define RULE_LEN 120
40#define TZ_LEN 10
41
42/* Make sure that the strings do not end up in ROM.
43 * These strings probably contain the wrong value, and we cannot obtain the
44 * right value from the system. TZ is the only help.
45 */
46static char ntstr[TZ_LEN + 1] = "GMT"; /* string for normal time */
47static char dststr[TZ_LEN + 1] = "GDT"; /* string for daylight saving */
48
49long _timezone = 0;
50long _dst_off = 60 * 60;
51int _daylight = 0;
52char *_tzname[2] = {ntstr, dststr};
53
54#if defined(__USG) || defined(_POSIX_SOURCE)
55char *tzname[2] = {ntstr, dststr};
56
57#if defined(__USG)
58long timezone = 0;
59int daylight = 0;
60#endif
61#endif
62
63static struct dsttype {
64 char ds_type; /* Unknown, Julian, Zero-based or M */
65 int ds_date[3]; /* months, weeks, days */
66 long ds_sec; /* usually 02:00:00 */
67} dststart = { 'U', { 0, 0, 0 }, 2 * 60 * 60 }
68 , dstend = { 'U', { 0, 0, 0 }, 2 * 60 * 60 };
69
70const char *_days[] = {
71 "Sunday", "Monday", "Tuesday", "Wednesday",
72 "Thursday", "Friday", "Saturday"
73 };
74
75const char *_months[] = {
76 "January", "February", "March",
77 "April", "May", "June",
78 "July", "August", "September",
79 "October", "November", "December"
80 };
81
82const int _ytab[2][12] = {
83 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
84 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
85 };
86
87static const char *
88parseZoneName(register char *buf, register const char *p)
89{
90 register int n = 0;
91
92 if (*p == ':') return NULL;
93 while (*p && !isdigit(*p) && *p != ',' && *p != '-' && *p != '+') {
94 if (n < TZ_LEN)
95 *buf++ = *p;
96 p++;
97 n++;
98 }
99 if (n < 3) return NULL; /* error */
100 *buf = '\0';
101 return p;
102}
103
104static const char *
105parseTime(register long *tm, const char *p, register struct dsttype *dst)
106{
107 register int n = 0;
108 register const char *q = p;
109 char ds_type = (dst ? dst->ds_type : '\0');
110
111 if (dst) dst->ds_type = 'U';
112
113 *tm = 0;
114 while(*p >= '0' && *p <= '9') {
115 n = 10 * n + (*p++ - '0');
116 }
117 if (q == p) return NULL; /* "The hour shall be required" */
118 if (n < 0 || n >= 24) return NULL;
119 *tm = n * 60 * 60;
120 if (*p == ':') {
121 p++;
122 n = 0;
123 while(*p >= '0' && *p <= '9') {
124 n = 10 * n + (*p++ - '0');
125 }
126 if (q == p) return NULL; /* format error */
127 if (n < 0 || n >= 60) return NULL;
128 *tm += n * 60;
129 if (*p == ':') {
130 p++;
131 n = 0;
132 while(*p >= '0' && *p <= '9') {
133 n = 10 * n + (*p++ - '0');
134 }
135 if (q == p) return NULL; /* format error */
136 if (n < 0 || n >= 60) return NULL;
137 *tm += n;
138 }
139 }
140 if (dst) {
141 dst->ds_type = ds_type;
142 dst->ds_sec = *tm;
143 }
144 return p;
145}
146
147static const char *
148parseDate(register char *buf, register const char *p, struct dsttype *dstinfo)
149{
150 register const char *q;
151 register int n = 0;
152 int cnt = 0;
153 const int bnds[3][2] = { { 1, 12 },
154 { 1, 5 },
155 { 0, 6}
156 };
157 char ds_type;
158
159 if (*p != 'M') {
160 if (*p == 'J') {
161 *buf++ = *p++;
162 ds_type = 'J';
163 }
164 else ds_type = 'Z';
165 q = p;
166 while(*p >= '0' && *p <= '9') {
167 n = 10 * n + (*p - '0');
168 *buf++ = *p++;
169 }
170 if (q == p) return NULL; /* format error */
171 if (n < (ds_type == 'J') || n > 365) return NULL;
172 dstinfo->ds_type = ds_type;
173 dstinfo->ds_date[0] = n;
174 return p;
175 }
176 ds_type = 'M';
177 do {
178 *buf++ = *p++;
179 q = p;
180 n = 0;
181 while(*p >= '0' && *p <= '9') {
182 n = 10 * n + (*p - '0');
183 *buf++ = *p++;
184 }
185 if (q == p) return NULL; /* format error */
186 if (n < bnds[cnt][0] || n > bnds[cnt][1]) return NULL;
187 dstinfo->ds_date[cnt] = n;
188 cnt++;
189 } while (cnt < 3 && *p == '.');
190 if (cnt != 3) return NULL;
191 *buf = '\0';
192 dstinfo->ds_type = ds_type;
193 return p;
194}
195
196static const char *
197parseRule(register char *buf, register const char *p)
198{
199 long time;
200 register const char *q;
201
202 if (!(p = parseDate(buf, p, &dststart))) return NULL;
203 buf += strlen(buf);
204 if (*p == '/') {
205 q = ++p;
206 if (!(p = parseTime(&time, p, &dststart))) return NULL;
207 while( p != q) *buf++ = *q++;
208 }
209 if (*p != ',') return NULL;
210 p++;
211 if (!(p = parseDate(buf, p, &dstend))) return NULL;
212 buf += strlen(buf);
213 if (*p == '/') {
214 q = ++p;
215 if (!(p = parseTime(&time, p, &dstend))) return NULL;
216 while(*buf++ = *q++);
217 }
218 if (*p) return NULL;
219 return p;
220}
221
222/* The following routine parses timezone information in POSIX-format. For
223 * the requirements, see IEEE Std 1003.1-1988 section 8.1.1.
224 * The function returns as soon as it spots an error.
225 */
226static void
227parseTZ(const char *p)
228{
229 long tz, dst = 60 * 60, sign = 1;
230 static char lastTZ[2 * RULE_LEN];
231 static char buffer[RULE_LEN];
232
233 if (!p) return;
234
235 if (*p == ':') {
236 /*
237 * According to POSIX, this is implementation defined.
238 * Since it depends on the particular operating system, we
239 * can do nothing.
240 */
241 return;
242 }
243
244 if (!strcmp(lastTZ, p)) return; /* nothing changed */
245
246 *_tzname[0] = '\0';
247 *_tzname[1] = '\0';
248 dststart.ds_type = 'U';
249 dststart.ds_sec = 2 * 60 * 60;
250 dstend.ds_type = 'U';
251 dstend.ds_sec = 2 * 60 * 60;
252
253 if (strlen(p) > 2 * RULE_LEN) return;
254 strcpy(lastTZ, p);
255
256 if (!(p = parseZoneName(buffer, p))) return;
257
258 if (*p == '-') {
259 sign = -1;
260 p++;
261 } else if (*p == '+') p++;
262
263 if (!(p = parseTime(&tz, p, NULL))) return;
264 tz *= sign;
265 _timezone = tz;
266 strncpy(_tzname[0], buffer, TZ_LEN);
267
268 if (!(_daylight = (*p != '\0'))) return;
269
270 buffer[0] = '\0';
271 if (!(p = parseZoneName(buffer, p))) return;
272 strncpy(_tzname[1], buffer, TZ_LEN);
273
274 buffer[0] = '\0';
275 if (*p && (*p != ','))
276 if (!(p = parseTime(&dst, p, NULL))) return;
277 _dst_off = dst; /* dst was initialized to 1 hour */
278 if (*p) {
279 if (*p != ',') return;
280 p++;
281 if (strlen(p) > RULE_LEN) return;
282 if (!(p = parseRule(buffer, p))) return;
283 }
284}
285
286void
287_tzset(void)
288{
289#if defined(__BSD4_2)
290
291 struct timeval tv;
292 struct timezone tz;
293
294 _gettimeofday(&tv, &tz);
295 _daylight = tz.tz_dsttime;
296 _timezone = tz.tz_minuteswest * 60L;
297
298#elif !defined(_POSIX_SOURCE) && !defined(__USG)
299
300#if !defined(_MINIX) /* MINIX has no ftime() */
301 struct timeb time;
302
303 _ftime(&time);
304 _timezone = time.timezone * 60L;
305 _daylight = time.dstflag;
306#endif
307
308#endif /* !_POSIX_SOURCE && !__USG */
309
310 parseTZ(getenv("TZ")); /* should go inside #if */
311
312#if defined(__USG) || defined(_POSIX_SOURCE)
313 tzname[0] = _tzname[0];
314 tzname[1] = _tzname[1];
315#if defined(__USG)
316 timezone = _timezone;
317 daylight = _daylight;
318#endif
319#endif /* __USG || _POSIX_SOURCE */
320}
321
322static int
323last_sunday(register int day, register struct tm *timep)
324{
325 int first = FIRSTSUNDAY(timep);
326
327 if (day >= 58 && LEAPYEAR(YEAR0 + timep->tm_year)) day++;
328 if (day < first) return first;
329 return day - (day - first) % 7;
330}
331
332static int
333date_of(register struct dsttype *dst, struct tm *timep)
334{
335 int leap = LEAPYEAR(YEAR0 + timep->tm_year);
336 int firstday, tmpday;
337 register int day, month;
338
339 if (dst->ds_type != 'M') {
340 return dst->ds_date[0] -
341 (dst->ds_type == 'J'
342 && leap
343 && dst->ds_date[0] < 58);
344 }
345 day = 0;
346 month = 1;
347 while (month < dst->ds_date[0]) {
348 day += _ytab[leap][month - 1];
349 month++;
350 }
351 firstday = (day + FIRSTDAYOF(timep)) % 7;
352 tmpday = day;
353 day += (dst->ds_date[2] - firstday + 7) % 7
354 + 7 * (dst->ds_date[1] - 1);
355 if (day >= tmpday + _ytab[leap][month-1]) day -= 7;
356 return day;
357}
358
359/*
360 * The default dst transitions are those for Western Europe (except Great
361 * Britain).
362 */
363unsigned
364_dstget(register struct tm *timep)
365{
366 int begindst, enddst;
367 register struct dsttype *dsts = &dststart, *dste = &dstend;
368 int do_dst = 0;
369
370 if (_daylight == -1)
371 _tzset();
372
373 timep->tm_isdst = _daylight;
374 if (!_daylight) return 0;
375
376 if (dsts->ds_type != 'U')
377 begindst = date_of(dsts, timep);
378 else begindst = last_sunday(89, timep); /* last Sun before Apr */
379 if (dste->ds_type != 'U')
380 enddst = date_of(dste, timep);
381 else enddst = last_sunday(272, timep); /* last Sun in Sep */
382
383 /* assume begindst != enddst (otherwise it would be no use) */
384 if (begindst < enddst) { /* northern hemisphere */
385 if (timep->tm_yday > begindst && timep->tm_yday < enddst)
386 do_dst = 1;
387 } else { /* southern hemisphere */
388 if (timep->tm_yday > begindst || timep->tm_yday < enddst)
389 do_dst = 1;
390 }
391
392 if (!do_dst
393 && (timep->tm_yday == begindst || timep->tm_yday == enddst)) {
394 long dsttranssec; /* transition when day is this old */
395 long cursec;
396
397 if (timep->tm_yday == begindst)
398 dsttranssec = dsts->ds_sec;
399 else dsttranssec = dste->ds_sec;
400 cursec = ((timep->tm_hour * 60) + timep->tm_min) * 60L
401 + timep->tm_sec;
402
403 if ((timep->tm_yday == begindst && cursec >= dsttranssec)
404 || (timep->tm_yday == enddst && cursec < dsttranssec))
405 do_dst = 1;
406 }
407 if (do_dst) return _dst_off;
408 timep->tm_isdst = 0;
409 return 0;
410}
Note: See TracBrowser for help on using the repository browser.