]> git.saurik.com Git - apple/libc.git/blob - gen/ctime.c
0f5753c285b358e39cf757f5397e5db99c32fd41
[apple/libc.git] / gen / ctime.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1987, 1989, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * This code is derived from software contributed to Berkeley by
30 * Arthur David Olson of the National Cancer Institute.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61
62 /*
63 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
64 ** POSIX-style TZ environment variable handling from Guy Harris
65 ** (guy@auspex.com).
66 */
67
68 /*LINTLIBRARY*/
69
70 #include <sys/param.h>
71 #include <fcntl.h>
72 #include <time.h>
73 #include <tzfile.h>
74 #include <string.h>
75 #include <ctype.h>
76 #include <stdio.h>
77 #include <unistd.h>
78
79 #ifdef __STDC__
80 #include <stdlib.h>
81
82 #define P(s) s
83 #define alloc_size_t size_t
84 #define qsort_size_t size_t
85 #define fread_size_t size_t
86 #define fwrite_size_t size_t
87
88 #else /* !defined __STDC__ */
89
90 #define P(s) ()
91
92 typedef char * genericptr_t;
93 typedef unsigned alloc_size_t;
94 typedef int qsort_size_t;
95 typedef int fread_size_t;
96 typedef int fwrite_size_t;
97
98 extern char * calloc();
99 extern char * malloc();
100 extern char * realloc();
101 extern char * getenv();
102
103 #endif /* !defined __STDC__ */
104
105 extern time_t time();
106
107 #define ACCESS_MODE O_RDONLY
108 #define OPEN_MODE O_RDONLY
109
110 #ifndef WILDABBR
111 /*
112 ** Someone might make incorrect use of a time zone abbreviation:
113 ** 1. They might reference tzname[0] before calling tzset (explicitly
114 ** or implicitly).
115 ** 2. They might reference tzname[1] before calling tzset (explicitly
116 ** or implicitly).
117 ** 3. They might reference tzname[1] after setting to a time zone
118 ** in which Daylight Saving Time is never observed.
119 ** 4. They might reference tzname[0] after setting to a time zone
120 ** in which Standard Time is never observed.
121 ** 5. They might reference tm.TM_ZONE after calling offtime.
122 ** What's best to do in the above cases is open to debate;
123 ** for now, we just set things up so that in any of the five cases
124 ** WILDABBR is used. Another possibility: initialize tzname[0] to the
125 ** string "tzname[0] used before set", and similarly for the other cases.
126 ** And another: initialize tzname[0] to "ERA", with an explanation in the
127 ** manual page of what this "time zone abbreviation" means (doing this so
128 ** that tzname[0] has the "normal" length of three characters).
129 */
130 #define WILDABBR " "
131 #endif /* !defined WILDABBR */
132
133 #ifndef TRUE
134 #define TRUE 1
135 #define FALSE 0
136 #endif /* !defined TRUE */
137
138 static const char GMT[] = "GMT";
139
140 struct ttinfo { /* time type information */
141 long tt_gmtoff; /* GMT offset in seconds */
142 int tt_isdst; /* used to set tm_isdst */
143 int tt_abbrind; /* abbreviation list index */
144 int tt_ttisstd; /* TRUE if transition is std time */
145 };
146
147 struct lsinfo { /* leap second information */
148 time_t ls_trans; /* transition time */
149 long ls_corr; /* correction to apply */
150 };
151
152 struct state {
153 int leapcnt;
154 int timecnt;
155 int typecnt;
156 int charcnt;
157 time_t ats[TZ_MAX_TIMES];
158 unsigned char types[TZ_MAX_TIMES];
159 struct ttinfo ttis[TZ_MAX_TYPES];
160 char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
161 TZ_MAX_CHARS + 1 : sizeof GMT];
162 struct lsinfo lsis[TZ_MAX_LEAPS];
163 };
164
165 struct rule {
166 int r_type; /* type of rule--see below */
167 int r_day; /* day number of rule */
168 int r_week; /* week number of rule */
169 int r_mon; /* month number of rule */
170 long r_time; /* transition time of rule */
171 };
172
173 #define JULIAN_DAY 0 /* Jn - Julian day */
174 #define DAY_OF_YEAR 1 /* n - day of year */
175 #define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
176
177 /*
178 ** Prototypes for static functions.
179 */
180
181 static long detzcode P((const char * codep));
182 static const char * getzname P((const char * strp));
183 static const char * getnum P((const char * strp, int * nump, int min,
184 int max));
185 static const char * getsecs P((const char * strp, long * secsp));
186 static const char * getoffset P((const char * strp, long * offsetp));
187 static const char * getrule P((const char * strp, struct rule * rulep));
188 static void gmtload P((struct state * sp));
189 static void gmtsub P((const time_t * timep, long offset,
190 struct tm * tmp));
191 static void localsub P((const time_t * timep, long offset,
192 struct tm * tmp));
193 static void normalize P((int * tensptr, int * unitsptr, int base));
194 static void settzname P((void));
195 static time_t time1 P((struct tm * tmp, void (* funcp)(),
196 long offset));
197 static time_t time2 P((struct tm *tmp, void (* funcp)(),
198 long offset, int * okayp));
199 static void timesub P((const time_t * timep, long offset,
200 const struct state * sp, struct tm * tmp));
201 static int tmcomp P((const struct tm * atmp,
202 const struct tm * btmp));
203 static time_t transtime P((time_t janfirst, int year,
204 const struct rule * rulep, long offset));
205 static int tzload P((const char * name, struct state * sp));
206 static int tzparse P((const char * name, struct state * sp,
207 int lastditch));
208
209 #ifdef ALL_STATE
210 static struct state * lclptr;
211 static struct state * gmtptr;
212 #endif /* defined ALL_STATE */
213
214 #ifndef ALL_STATE
215 static struct state lclmem;
216 static struct state gmtmem;
217 #define lclptr (&lclmem)
218 #define gmtptr (&gmtmem)
219 #endif /* State Farm */
220
221 static int lcl_is_set;
222 static int gmt_is_set;
223
224 char * tzname[2] = {
225 WILDABBR,
226 WILDABBR
227 };
228
229 #ifdef USG_COMPAT
230 time_t timezone = 0;
231 int daylight = 0;
232 #endif /* defined USG_COMPAT */
233
234 #ifdef ALTZONE
235 time_t altzone = 0;
236 #endif /* defined ALTZONE */
237
238 static long
239 detzcode(codep)
240 const char * const codep;
241 {
242 register long result;
243 register int i;
244
245 result = 0;
246 for (i = 0; i < 4; ++i)
247 result = (result << 8) | (codep[i] & 0xff);
248 return result;
249 }
250
251 static void
252 settzname()
253 {
254 register const struct state * const sp = lclptr;
255 register int i;
256
257 tzname[0] = WILDABBR;
258 tzname[1] = WILDABBR;
259 #ifdef USG_COMPAT
260 daylight = 0;
261 timezone = 0;
262 #endif /* defined USG_COMPAT */
263 #ifdef ALTZONE
264 altzone = 0;
265 #endif /* defined ALTZONE */
266 #ifdef ALL_STATE
267 if (sp == NULL) {
268 tzname[0] = tzname[1] = GMT;
269 return;
270 }
271 #endif /* defined ALL_STATE */
272 for (i = 0; i < sp->typecnt; ++i) {
273 register const struct ttinfo * const ttisp = &sp->ttis[i];
274
275 tzname[ttisp->tt_isdst] =
276 (char *) &sp->chars[ttisp->tt_abbrind];
277 #ifdef USG_COMPAT
278 if (ttisp->tt_isdst)
279 daylight = 1;
280 if (i == 0 || !ttisp->tt_isdst)
281 timezone = -(ttisp->tt_gmtoff);
282 #endif /* defined USG_COMPAT */
283 #ifdef ALTZONE
284 if (i == 0 || ttisp->tt_isdst)
285 altzone = -(ttisp->tt_gmtoff);
286 #endif /* defined ALTZONE */
287 }
288 /*
289 ** And to get the latest zone names into tzname. . .
290 */
291 for (i = 0; i < sp->timecnt; ++i) {
292 register const struct ttinfo * const ttisp =
293 &sp->ttis[sp->types[i]];
294
295 tzname[ttisp->tt_isdst] =
296 (char *) &sp->chars[ttisp->tt_abbrind];
297 }
298 }
299
300 static int
301 tzload(name, sp)
302 register const char * name;
303 register struct state * const sp;
304 {
305 register const char * p;
306 register int i;
307 register int fid;
308
309 if (name == NULL && (name = TZDEFAULT) == NULL)
310 return -1;
311 {
312 char fullname[FILENAME_MAX + 1];
313
314 if (name[0] == ':')
315 ++name;
316 if (name[0] != '/') {
317 if ((p = TZDIR) == NULL)
318 return -1;
319 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
320 return -1;
321 (void) strcpy(fullname, p);
322 (void) strcat(fullname, "/");
323 (void) strcat(fullname, name);
324 name = fullname;
325 }
326 if ((fid = open(name, OPEN_MODE)) == -1)
327 return -1;
328 }
329 {
330 register const struct tzhead * tzhp;
331 char buf[sizeof *sp + sizeof *tzhp];
332 int ttisstdcnt;
333
334 i = read(fid, buf, sizeof buf);
335 if (close(fid) != 0 || i < sizeof *tzhp)
336 return -1;
337 tzhp = (struct tzhead *) buf;
338 ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
339 sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
340 sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
341 sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
342 sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
343 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
344 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
345 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
346 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
347 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
348 return -1;
349 if (i < sizeof *tzhp +
350 sp->timecnt * (4 + sizeof (char)) +
351 sp->typecnt * (4 + 2 * sizeof (char)) +
352 sp->charcnt * sizeof (char) +
353 sp->leapcnt * 2 * 4 +
354 ttisstdcnt * sizeof (char))
355 return -1;
356 p = buf + sizeof *tzhp;
357 for (i = 0; i < sp->timecnt; ++i) {
358 sp->ats[i] = detzcode(p);
359 p += 4;
360 }
361 for (i = 0; i < sp->timecnt; ++i) {
362 sp->types[i] = (unsigned char) *p++;
363 if (sp->types[i] >= sp->typecnt)
364 return -1;
365 }
366 for (i = 0; i < sp->typecnt; ++i) {
367 register struct ttinfo * ttisp;
368
369 ttisp = &sp->ttis[i];
370 ttisp->tt_gmtoff = detzcode(p);
371 p += 4;
372 ttisp->tt_isdst = (unsigned char) *p++;
373 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
374 return -1;
375 ttisp->tt_abbrind = (unsigned char) *p++;
376 if (ttisp->tt_abbrind < 0 ||
377 ttisp->tt_abbrind > sp->charcnt)
378 return -1;
379 }
380 for (i = 0; i < sp->charcnt; ++i)
381 sp->chars[i] = *p++;
382 sp->chars[i] = '\0'; /* ensure '\0' at end */
383 for (i = 0; i < sp->leapcnt; ++i) {
384 register struct lsinfo * lsisp;
385
386 lsisp = &sp->lsis[i];
387 lsisp->ls_trans = detzcode(p);
388 p += 4;
389 lsisp->ls_corr = detzcode(p);
390 p += 4;
391 }
392 for (i = 0; i < sp->typecnt; ++i) {
393 register struct ttinfo * ttisp;
394
395 ttisp = &sp->ttis[i];
396 if (ttisstdcnt == 0)
397 ttisp->tt_ttisstd = FALSE;
398 else {
399 ttisp->tt_ttisstd = *p++;
400 if (ttisp->tt_ttisstd != TRUE &&
401 ttisp->tt_ttisstd != FALSE)
402 return -1;
403 }
404 }
405 }
406 return 0;
407 }
408
409 static const int mon_lengths[2][MONSPERYEAR] = {
410 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
411 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
412 };
413
414 static const int year_lengths[2] = {
415 DAYSPERNYEAR, DAYSPERLYEAR
416 };
417
418 /*
419 ** Given a pointer into a time zone string, scan until a character that is not
420 ** a valid character in a zone name is found. Return a pointer to that
421 ** character.
422 */
423
424 static const char *
425 getzname(strp)
426 register const char * strp;
427 {
428 register char c;
429
430 while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
431 c != '+')
432 ++strp;
433 return strp;
434 }
435
436 /*
437 ** Given a pointer into a time zone string, extract a number from that string.
438 ** Check that the number is within a specified range; if it is not, return
439 ** NULL.
440 ** Otherwise, return a pointer to the first character not part of the number.
441 */
442
443 static const char *
444 getnum(strp, nump, min, max)
445 register const char * strp;
446 int * const nump;
447 const int min;
448 const int max;
449 {
450 register char c;
451 register int num;
452
453 if (strp == NULL || !isdigit(*strp))
454 return NULL;
455 num = 0;
456 while ((c = *strp) != '\0' && isdigit(c)) {
457 num = num * 10 + (c - '0');
458 if (num > max)
459 return NULL; /* illegal value */
460 ++strp;
461 }
462 if (num < min)
463 return NULL; /* illegal value */
464 *nump = num;
465 return strp;
466 }
467
468 /*
469 ** Given a pointer into a time zone string, extract a number of seconds,
470 ** in hh[:mm[:ss]] form, from the string.
471 ** If any error occurs, return NULL.
472 ** Otherwise, return a pointer to the first character not part of the number
473 ** of seconds.
474 */
475
476 static const char *
477 getsecs(strp, secsp)
478 register const char * strp;
479 long * const secsp;
480 {
481 int num;
482
483 strp = getnum(strp, &num, 0, HOURSPERDAY);
484 if (strp == NULL)
485 return NULL;
486 *secsp = num * SECSPERHOUR;
487 if (*strp == ':') {
488 ++strp;
489 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
490 if (strp == NULL)
491 return NULL;
492 *secsp += num * SECSPERMIN;
493 if (*strp == ':') {
494 ++strp;
495 strp = getnum(strp, &num, 0, SECSPERMIN - 1);
496 if (strp == NULL)
497 return NULL;
498 *secsp += num;
499 }
500 }
501 return strp;
502 }
503
504 /*
505 ** Given a pointer into a time zone string, extract an offset, in
506 ** [+-]hh[:mm[:ss]] form, from the string.
507 ** If any error occurs, return NULL.
508 ** Otherwise, return a pointer to the first character not part of the time.
509 */
510
511 static const char *
512 getoffset(strp, offsetp)
513 register const char * strp;
514 long * const offsetp;
515 {
516 register int neg;
517
518 if (*strp == '-') {
519 neg = 1;
520 ++strp;
521 } else if (isdigit(*strp) || *strp++ == '+')
522 neg = 0;
523 else return NULL; /* illegal offset */
524 strp = getsecs(strp, offsetp);
525 if (strp == NULL)
526 return NULL; /* illegal time */
527 if (neg)
528 *offsetp = -*offsetp;
529 return strp;
530 }
531
532 /*
533 ** Given a pointer into a time zone string, extract a rule in the form
534 ** date[/time]. See POSIX section 8 for the format of "date" and "time".
535 ** If a valid rule is not found, return NULL.
536 ** Otherwise, return a pointer to the first character not part of the rule.
537 */
538
539 static const char *
540 getrule(strp, rulep)
541 const char * strp;
542 register struct rule * const rulep;
543 {
544 if (*strp == 'J') {
545 /*
546 ** Julian day.
547 */
548 rulep->r_type = JULIAN_DAY;
549 ++strp;
550 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
551 } else if (*strp == 'M') {
552 /*
553 ** Month, week, day.
554 */
555 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
556 ++strp;
557 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
558 if (strp == NULL)
559 return NULL;
560 if (*strp++ != '.')
561 return NULL;
562 strp = getnum(strp, &rulep->r_week, 1, 5);
563 if (strp == NULL)
564 return NULL;
565 if (*strp++ != '.')
566 return NULL;
567 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
568 } else if (isdigit(*strp)) {
569 /*
570 ** Day of year.
571 */
572 rulep->r_type = DAY_OF_YEAR;
573 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
574 } else return NULL; /* invalid format */
575 if (strp == NULL)
576 return NULL;
577 if (*strp == '/') {
578 /*
579 ** Time specified.
580 */
581 ++strp;
582 strp = getsecs(strp, &rulep->r_time);
583 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
584 return strp;
585 }
586
587 /*
588 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
589 ** year, a rule, and the offset from GMT at the time that rule takes effect,
590 ** calculate the Epoch-relative time that rule takes effect.
591 */
592
593 static time_t
594 transtime(janfirst, year, rulep, offset)
595 const time_t janfirst;
596 const int year;
597 register const struct rule * const rulep;
598 const long offset;
599 {
600 register int leapyear;
601 register time_t value;
602 register int i;
603 int d, m1, yy0, yy1, yy2, dow;
604
605 leapyear = isleap(year);
606 switch (rulep->r_type) {
607
608 case JULIAN_DAY:
609 /*
610 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
611 ** years.
612 ** In non-leap years, or if the day number is 59 or less, just
613 ** add SECSPERDAY times the day number-1 to the time of
614 ** January 1, midnight, to get the day.
615 */
616 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
617 if (leapyear && rulep->r_day >= 60)
618 value += SECSPERDAY;
619 break;
620
621 case DAY_OF_YEAR:
622 /*
623 ** n - day of year.
624 ** Just add SECSPERDAY times the day number to the time of
625 ** January 1, midnight, to get the day.
626 */
627 value = janfirst + rulep->r_day * SECSPERDAY;
628 break;
629
630 case MONTH_NTH_DAY_OF_WEEK:
631 /*
632 ** Mm.n.d - nth "dth day" of month m.
633 */
634 value = janfirst;
635 for (i = 0; i < rulep->r_mon - 1; ++i)
636 value += mon_lengths[leapyear][i] * SECSPERDAY;
637
638 /*
639 ** Use Zeller's Congruence to get day-of-week of first day of
640 ** month.
641 */
642 m1 = (rulep->r_mon + 9) % 12 + 1;
643 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
644 yy1 = yy0 / 100;
645 yy2 = yy0 % 100;
646 dow = ((26 * m1 - 2) / 10 +
647 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
648 if (dow < 0)
649 dow += DAYSPERWEEK;
650
651 /*
652 ** "dow" is the day-of-week of the first day of the month. Get
653 ** the day-of-month (zero-origin) of the first "dow" day of the
654 ** month.
655 */
656 d = rulep->r_day - dow;
657 if (d < 0)
658 d += DAYSPERWEEK;
659 for (i = 1; i < rulep->r_week; ++i) {
660 if (d + DAYSPERWEEK >=
661 mon_lengths[leapyear][rulep->r_mon - 1])
662 break;
663 d += DAYSPERWEEK;
664 }
665
666 /*
667 ** "d" is the day-of-month (zero-origin) of the day we want.
668 */
669 value += d * SECSPERDAY;
670 break;
671 }
672
673 /*
674 ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
675 ** question. To get the Epoch-relative time of the specified local
676 ** time on that day, add the transition time and the current offset
677 ** from GMT.
678 */
679 return value + rulep->r_time + offset;
680 }
681
682 /*
683 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
684 ** appropriate.
685 */
686
687 static int
688 tzparse(name, sp, lastditch)
689 const char * name;
690 register struct state * const sp;
691 const int lastditch;
692 {
693 const char * stdname;
694 const char * dstname;
695 int stdlen;
696 int dstlen;
697 long stdoffset;
698 long dstoffset;
699 register time_t * atp;
700 register unsigned char * typep;
701 register char * cp;
702 register int load_result;
703
704 stdname = name;
705 if (lastditch) {
706 stdlen = strlen(name); /* length of standard zone name */
707 name += stdlen;
708 if (stdlen >= sizeof sp->chars)
709 stdlen = (sizeof sp->chars) - 1;
710 } else {
711 name = getzname(name);
712 stdlen = name - stdname;
713 if (stdlen < 3)
714 return -1;
715 }
716 if (*name == '\0')
717 return -1;
718 else {
719 name = getoffset(name, &stdoffset);
720 if (name == NULL)
721 return -1;
722 }
723 load_result = tzload(TZDEFRULES, sp);
724 if (load_result != 0)
725 sp->leapcnt = 0; /* so, we're off a little */
726 if (*name != '\0') {
727 dstname = name;
728 name = getzname(name);
729 dstlen = name - dstname; /* length of DST zone name */
730 if (dstlen < 3)
731 return -1;
732 if (*name != '\0' && *name != ',' && *name != ';') {
733 name = getoffset(name, &dstoffset);
734 if (name == NULL)
735 return -1;
736 } else dstoffset = stdoffset - SECSPERHOUR;
737 if (*name == ',' || *name == ';') {
738 struct rule start;
739 struct rule end;
740 register int year;
741 register time_t janfirst;
742 time_t starttime;
743 time_t endtime;
744
745 ++name;
746 if ((name = getrule(name, &start)) == NULL)
747 return -1;
748 if (*name++ != ',')
749 return -1;
750 if ((name = getrule(name, &end)) == NULL)
751 return -1;
752 if (*name != '\0')
753 return -1;
754 sp->typecnt = 2; /* standard time and DST */
755 /*
756 ** Two transitions per year, from EPOCH_YEAR to 2037.
757 */
758 sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
759 if (sp->timecnt > TZ_MAX_TIMES)
760 return -1;
761 sp->ttis[0].tt_gmtoff = -dstoffset;
762 sp->ttis[0].tt_isdst = 1;
763 sp->ttis[0].tt_abbrind = stdlen + 1;
764 sp->ttis[1].tt_gmtoff = -stdoffset;
765 sp->ttis[1].tt_isdst = 0;
766 sp->ttis[1].tt_abbrind = 0;
767 atp = sp->ats;
768 typep = sp->types;
769 janfirst = 0;
770 for (year = EPOCH_YEAR; year <= 2037; ++year) {
771 starttime = transtime(janfirst, year, &start,
772 stdoffset);
773 endtime = transtime(janfirst, year, &end,
774 dstoffset);
775 if (starttime > endtime) {
776 *atp++ = endtime;
777 *typep++ = 1; /* DST ends */
778 *atp++ = starttime;
779 *typep++ = 0; /* DST begins */
780 } else {
781 *atp++ = starttime;
782 *typep++ = 0; /* DST begins */
783 *atp++ = endtime;
784 *typep++ = 1; /* DST ends */
785 }
786 janfirst +=
787 year_lengths[isleap(year)] * SECSPERDAY;
788 }
789 } else {
790 int sawstd;
791 int sawdst;
792 long stdfix;
793 long dstfix;
794 long oldfix;
795 int isdst;
796 register int i;
797
798 if (*name != '\0')
799 return -1;
800 if (load_result != 0)
801 return -1;
802 /*
803 ** Compute the difference between the real and
804 ** prototype standard and summer time offsets
805 ** from GMT, and put the real standard and summer
806 ** time offsets into the rules in place of the
807 ** prototype offsets.
808 */
809 sawstd = FALSE;
810 sawdst = FALSE;
811 stdfix = 0;
812 dstfix = 0;
813 for (i = 0; i < sp->typecnt; ++i) {
814 if (sp->ttis[i].tt_isdst) {
815 oldfix = dstfix;
816 dstfix =
817 sp->ttis[i].tt_gmtoff + dstoffset;
818 if (sawdst && (oldfix != dstfix))
819 return -1;
820 sp->ttis[i].tt_gmtoff = -dstoffset;
821 sp->ttis[i].tt_abbrind = stdlen + 1;
822 sawdst = TRUE;
823 } else {
824 oldfix = stdfix;
825 stdfix =
826 sp->ttis[i].tt_gmtoff + stdoffset;
827 if (sawstd && (oldfix != stdfix))
828 return -1;
829 sp->ttis[i].tt_gmtoff = -stdoffset;
830 sp->ttis[i].tt_abbrind = 0;
831 sawstd = TRUE;
832 }
833 }
834 /*
835 ** Make sure we have both standard and summer time.
836 */
837 if (!sawdst || !sawstd)
838 return -1;
839 /*
840 ** Now correct the transition times by shifting
841 ** them by the difference between the real and
842 ** prototype offsets. Note that this difference
843 ** can be different in standard and summer time;
844 ** the prototype probably has a 1-hour difference
845 ** between standard and summer time, but a different
846 ** difference can be specified in TZ.
847 */
848 isdst = FALSE; /* we start in standard time */
849 for (i = 0; i < sp->timecnt; ++i) {
850 register const struct ttinfo * ttisp;
851
852 /*
853 ** If summer time is in effect, and the
854 ** transition time was not specified as
855 ** standard time, add the summer time
856 ** offset to the transition time;
857 ** otherwise, add the standard time offset
858 ** to the transition time.
859 */
860 ttisp = &sp->ttis[sp->types[i]];
861 sp->ats[i] +=
862 (isdst && !ttisp->tt_ttisstd) ?
863 dstfix : stdfix;
864 isdst = ttisp->tt_isdst;
865 }
866 }
867 } else {
868 dstlen = 0;
869 sp->typecnt = 1; /* only standard time */
870 sp->timecnt = 0;
871 sp->ttis[0].tt_gmtoff = -stdoffset;
872 sp->ttis[0].tt_isdst = 0;
873 sp->ttis[0].tt_abbrind = 0;
874 }
875 sp->charcnt = stdlen + 1;
876 if (dstlen != 0)
877 sp->charcnt += dstlen + 1;
878 if (sp->charcnt > sizeof sp->chars)
879 return -1;
880 cp = sp->chars;
881 (void) strncpy(cp, stdname, stdlen);
882 cp += stdlen;
883 *cp++ = '\0';
884 if (dstlen != 0) {
885 (void) strncpy(cp, dstname, dstlen);
886 *(cp + dstlen) = '\0';
887 }
888 return 0;
889 }
890
891 static void
892 gmtload(sp)
893 struct state * const sp;
894 {
895 if (tzload(GMT, sp) != 0)
896 (void) tzparse(GMT, sp, TRUE);
897 }
898
899 void
900 tzset()
901 {
902 register const char * name;
903 void tzsetwall();
904
905 name = getenv("TZ");
906 if (name == NULL) {
907 tzsetwall();
908 return;
909 }
910 lcl_is_set = TRUE;
911 #ifdef ALL_STATE
912 if (lclptr == NULL) {
913 lclptr = (struct state *) malloc(sizeof *lclptr);
914 if (lclptr == NULL) {
915 settzname(); /* all we can do */
916 return;
917 }
918 }
919 #endif /* defined ALL_STATE */
920 if (*name == '\0') {
921 /*
922 ** User wants it fast rather than right.
923 */
924 lclptr->leapcnt = 0; /* so, we're off a little */
925 lclptr->timecnt = 0;
926 lclptr->ttis[0].tt_gmtoff = 0;
927 lclptr->ttis[0].tt_abbrind = 0;
928 (void) strcpy(lclptr->chars, GMT);
929 } else if (tzload(name, lclptr) != 0)
930 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
931 (void) gmtload(lclptr);
932 settzname();
933 }
934
935 void
936 tzsetwall()
937 {
938 lcl_is_set = TRUE;
939 #ifdef ALL_STATE
940 if (lclptr == NULL) {
941 lclptr = (struct state *) malloc(sizeof *lclptr);
942 if (lclptr == NULL) {
943 settzname(); /* all we can do */
944 return;
945 }
946 }
947 #endif /* defined ALL_STATE */
948 if (tzload((char *) NULL, lclptr) != 0)
949 gmtload(lclptr);
950 settzname();
951 }
952
953 /*
954 ** The easy way to behave "as if no library function calls" localtime
955 ** is to not call it--so we drop its guts into "localsub", which can be
956 ** freely called. (And no, the PANS doesn't require the above behavior--
957 ** but it *is* desirable.)
958 **
959 ** The unused offset argument is for the benefit of mktime variants.
960 */
961
962 /*ARGSUSED*/
963 static void
964 localsub(timep, offset, tmp)
965 const time_t * const timep;
966 const long offset;
967 struct tm * const tmp;
968 {
969 register struct state * sp;
970 register const struct ttinfo * ttisp;
971 register int i;
972 const time_t t = *timep;
973
974 if (!lcl_is_set)
975 tzset();
976 sp = lclptr;
977 #ifdef ALL_STATE
978 if (sp == NULL) {
979 gmtsub(timep, offset, tmp);
980 return;
981 }
982 #endif /* defined ALL_STATE */
983 if (sp->timecnt == 0 || t < sp->ats[0]) {
984 i = 0;
985 while (sp->ttis[i].tt_isdst)
986 if (++i >= sp->typecnt) {
987 i = 0;
988 break;
989 }
990 } else {
991 for (i = 1; i < sp->timecnt; ++i)
992 if (t < sp->ats[i])
993 break;
994 i = sp->types[i - 1];
995 }
996 ttisp = &sp->ttis[i];
997 /*
998 ** To get (wrong) behavior that's compatible with System V Release 2.0
999 ** you'd replace the statement below with
1000 ** t += ttisp->tt_gmtoff;
1001 ** timesub(&t, 0L, sp, tmp);
1002 */
1003 timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1004 tmp->tm_isdst = ttisp->tt_isdst;
1005 tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
1006 tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
1007 }
1008
1009 struct tm *
1010 localtime(timep)
1011 const time_t * const timep;
1012 {
1013 static struct tm tm;
1014
1015 localsub(timep, 0L, &tm);
1016 return &tm;
1017 }
1018
1019 /*
1020 ** gmtsub is to gmtime as localsub is to localtime.
1021 */
1022
1023 static void
1024 gmtsub(timep, offset, tmp)
1025 const time_t * const timep;
1026 const long offset;
1027 struct tm * const tmp;
1028 {
1029 if (!gmt_is_set) {
1030 gmt_is_set = TRUE;
1031 #ifdef ALL_STATE
1032 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1033 if (gmtptr != NULL)
1034 #endif /* defined ALL_STATE */
1035 gmtload(gmtptr);
1036 }
1037 timesub(timep, offset, gmtptr, tmp);
1038 /*
1039 ** Could get fancy here and deliver something such as
1040 ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
1041 ** but this is no time for a treasure hunt.
1042 */
1043 if (offset != 0)
1044 tmp->tm_zone = WILDABBR;
1045 else {
1046 #ifdef ALL_STATE
1047 if (gmtptr == NULL)
1048 tmp->TM_ZONE = GMT;
1049 else tmp->TM_ZONE = gmtptr->chars;
1050 #endif /* defined ALL_STATE */
1051 #ifndef ALL_STATE
1052 tmp->tm_zone = gmtptr->chars;
1053 #endif /* State Farm */
1054 }
1055 }
1056
1057 struct tm *
1058 gmtime(timep)
1059 const time_t * const timep;
1060 {
1061 static struct tm tm;
1062
1063 gmtsub(timep, 0L, &tm);
1064 return &tm;
1065 }
1066
1067 static void
1068 timesub(timep, offset, sp, tmp)
1069 const time_t * const timep;
1070 const long offset;
1071 register const struct state * const sp;
1072 register struct tm * const tmp;
1073 {
1074 register const struct lsinfo * lp;
1075 register long days;
1076 register long rem;
1077 register int y;
1078 register int yleap;
1079 register const int * ip;
1080 register long corr;
1081 register int hit;
1082 register int i;
1083
1084 corr = 0;
1085 hit = FALSE;
1086 #ifdef ALL_STATE
1087 i = (sp == NULL) ? 0 : sp->leapcnt;
1088 #endif /* defined ALL_STATE */
1089 #ifndef ALL_STATE
1090 i = sp->leapcnt;
1091 #endif /* State Farm */
1092 while (--i >= 0) {
1093 lp = &sp->lsis[i];
1094 if (*timep >= lp->ls_trans) {
1095 if (*timep == lp->ls_trans)
1096 hit = ((i == 0 && lp->ls_corr > 0) ||
1097 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1098 corr = lp->ls_corr;
1099 break;
1100 }
1101 }
1102 days = *timep / SECSPERDAY;
1103 rem = *timep % SECSPERDAY;
1104 #ifdef mc68k
1105 if (*timep == 0x80000000) {
1106 /*
1107 ** A 3B1 muffs the division on the most negative number.
1108 */
1109 days = -24855;
1110 rem = -11648;
1111 }
1112 #endif /* mc68k */
1113 rem += (offset - corr);
1114 while (rem < 0) {
1115 rem += SECSPERDAY;
1116 --days;
1117 }
1118 while (rem >= SECSPERDAY) {
1119 rem -= SECSPERDAY;
1120 ++days;
1121 }
1122 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1123 rem = rem % SECSPERHOUR;
1124 tmp->tm_min = (int) (rem / SECSPERMIN);
1125 tmp->tm_sec = (int) (rem % SECSPERMIN);
1126 if (hit)
1127 /*
1128 ** A positive leap second requires a special
1129 ** representation. This uses "... ??:59:60".
1130 */
1131 ++(tmp->tm_sec);
1132 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1133 if (tmp->tm_wday < 0)
1134 tmp->tm_wday += DAYSPERWEEK;
1135 y = EPOCH_YEAR;
1136 if (days >= 0)
1137 for ( ; ; ) {
1138 yleap = isleap(y);
1139 if (days < (long) year_lengths[yleap])
1140 break;
1141 ++y;
1142 days = days - (long) year_lengths[yleap];
1143 }
1144 else do {
1145 --y;
1146 yleap = isleap(y);
1147 days = days + (long) year_lengths[yleap];
1148 } while (days < 0);
1149 tmp->tm_year = y - TM_YEAR_BASE;
1150 tmp->tm_yday = (int) days;
1151 ip = mon_lengths[yleap];
1152 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1153 days = days - (long) ip[tmp->tm_mon];
1154 tmp->tm_mday = (int) (days + 1);
1155 tmp->tm_isdst = 0;
1156 tmp->tm_gmtoff = offset;
1157 }
1158
1159 /*
1160 ** A la X3J11
1161 */
1162
1163 char *
1164 asctime(timeptr)
1165 register const struct tm * timeptr;
1166 {
1167 static const char wday_name[DAYSPERWEEK][3] = {
1168 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1169 };
1170 static const char mon_name[MONSPERYEAR][3] = {
1171 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1172 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1173 };
1174 static char result[26];
1175
1176 (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
1177 wday_name[timeptr->tm_wday],
1178 mon_name[timeptr->tm_mon],
1179 timeptr->tm_mday, timeptr->tm_hour,
1180 timeptr->tm_min, timeptr->tm_sec,
1181 TM_YEAR_BASE + timeptr->tm_year);
1182 return result;
1183 }
1184
1185 char *
1186 ctime(timep)
1187 const time_t * const timep;
1188 {
1189 return asctime(localtime(timep));
1190 }
1191
1192 /*
1193 ** Adapted from code provided by Robert Elz, who writes:
1194 ** The "best" way to do mktime I think is based on an idea of Bob
1195 ** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1196 ** It does a binary search of the time_t space. Since time_t's are
1197 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
1198 ** would still be very reasonable).
1199 */
1200
1201 #ifndef WRONG
1202 #define WRONG (-1)
1203 #endif /* !defined WRONG */
1204
1205 static void
1206 normalize(tensptr, unitsptr, base)
1207 int * const tensptr;
1208 int * const unitsptr;
1209 const int base;
1210 {
1211 if (*unitsptr >= base) {
1212 *tensptr += *unitsptr / base;
1213 *unitsptr %= base;
1214 } else if (*unitsptr < 0) {
1215 *tensptr -= 1 + (-(*unitsptr + 1)) / base;
1216 *unitsptr = base - 1 - (-(*unitsptr + 1)) % base;
1217 }
1218 }
1219
1220 static int
1221 tmcomp(atmp, btmp)
1222 register const struct tm * const atmp;
1223 register const struct tm * const btmp;
1224 {
1225 register int result;
1226
1227 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1228 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1229 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1230 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1231 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1232 result = atmp->tm_sec - btmp->tm_sec;
1233 return result;
1234 }
1235
1236 static time_t
1237 time2(tmp, funcp, offset, okayp)
1238 struct tm * const tmp;
1239 void (* const funcp)();
1240 const long offset;
1241 int * const okayp;
1242 {
1243 register const struct state * sp;
1244 register int dir;
1245 register int bits;
1246 register int i, j ;
1247 register int saved_seconds;
1248 time_t newt;
1249 time_t t;
1250 struct tm yourtm, mytm;
1251
1252 *okayp = FALSE;
1253 yourtm = *tmp;
1254 if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
1255 normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
1256 normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
1257 normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
1258 normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
1259 while (yourtm.tm_mday <= 0) {
1260 --yourtm.tm_year;
1261 yourtm.tm_mday +=
1262 year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1263 }
1264 while (yourtm.tm_mday > DAYSPERLYEAR) {
1265 yourtm.tm_mday -=
1266 year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1267 ++yourtm.tm_year;
1268 }
1269 for ( ; ; ) {
1270 i = mon_lengths[isleap(yourtm.tm_year +
1271 TM_YEAR_BASE)][yourtm.tm_mon];
1272 if (yourtm.tm_mday <= i)
1273 break;
1274 yourtm.tm_mday -= i;
1275 if (++yourtm.tm_mon >= MONSPERYEAR) {
1276 yourtm.tm_mon = 0;
1277 ++yourtm.tm_year;
1278 }
1279 }
1280 saved_seconds = yourtm.tm_sec;
1281 yourtm.tm_sec = 0;
1282 /*
1283 ** Calculate the number of magnitude bits in a time_t
1284 ** (this works regardless of whether time_t is
1285 ** signed or unsigned, though lint complains if unsigned).
1286 */
1287 for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1288 ;
1289 /*
1290 ** If time_t is signed, then 0 is the median value,
1291 ** if time_t is unsigned, then 1 << bits is median.
1292 */
1293 t = (t < 0) ? 0 : ((time_t) 1 << bits);
1294 for ( ; ; ) {
1295 (*funcp)(&t, offset, &mytm);
1296 dir = tmcomp(&mytm, &yourtm);
1297 if (dir != 0) {
1298 if (bits-- < 0)
1299 return WRONG;
1300 if (bits < 0)
1301 --t;
1302 else if (dir > 0)
1303 t -= (time_t) 1 << bits;
1304 else t += (time_t) 1 << bits;
1305 continue;
1306 }
1307 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1308 break;
1309 /*
1310 ** Right time, wrong type.
1311 ** Hunt for right time, right type.
1312 ** It's okay to guess wrong since the guess
1313 ** gets checked.
1314 */
1315 sp = (const struct state *)
1316 ((funcp == localsub) ? lclptr : gmtptr);
1317 #ifdef ALL_STATE
1318 if (sp == NULL)
1319 return WRONG;
1320 #endif /* defined ALL_STATE */
1321 for (i = 0; i < sp->typecnt; ++i) {
1322 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1323 continue;
1324 for (j = 0; j < sp->typecnt; ++j) {
1325 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1326 continue;
1327 newt = t + sp->ttis[j].tt_gmtoff -
1328 sp->ttis[i].tt_gmtoff;
1329 (*funcp)(&newt, offset, &mytm);
1330 if (tmcomp(&mytm, &yourtm) != 0)
1331 continue;
1332 if (mytm.tm_isdst != yourtm.tm_isdst)
1333 continue;
1334 /*
1335 ** We have a match.
1336 */
1337 t = newt;
1338 goto label;
1339 }
1340 }
1341 return WRONG;
1342 }
1343 label:
1344 t += saved_seconds;
1345 (*funcp)(&t, offset, tmp);
1346 *okayp = TRUE;
1347 return t;
1348 }
1349
1350 static time_t
1351 time1(tmp, funcp, offset)
1352 struct tm * const tmp;
1353 void (* const funcp)();
1354 const long offset;
1355 {
1356 register time_t t;
1357 register const struct state * sp;
1358 register int samei, otheri;
1359 int okay;
1360
1361 if (tmp->tm_isdst > 1)
1362 tmp->tm_isdst = 1;
1363 t = time2(tmp, funcp, offset, &okay);
1364 if (okay || tmp->tm_isdst < 0)
1365 return t;
1366 /*
1367 ** We're supposed to assume that somebody took a time of one type
1368 ** and did some math on it that yielded a "struct tm" that's bad.
1369 ** We try to divine the type they started from and adjust to the
1370 ** type they need.
1371 */
1372 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
1373 #ifdef ALL_STATE
1374 if (sp == NULL)
1375 return WRONG;
1376 #endif /* defined ALL_STATE */
1377 for (samei = 0; samei < sp->typecnt; ++samei) {
1378 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1379 continue;
1380 for (otheri = 0; otheri < sp->typecnt; ++otheri) {
1381 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1382 continue;
1383 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1384 sp->ttis[samei].tt_gmtoff;
1385 tmp->tm_isdst = !tmp->tm_isdst;
1386 t = time2(tmp, funcp, offset, &okay);
1387 if (okay)
1388 return t;
1389 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1390 sp->ttis[samei].tt_gmtoff;
1391 tmp->tm_isdst = !tmp->tm_isdst;
1392 }
1393 }
1394 return WRONG;
1395 }
1396
1397 time_t
1398 mktime(tmp)
1399 struct tm * const tmp;
1400 {
1401 return time1(tmp, localsub, 0L);
1402 }