Annotation of src/lib/libc/time/zdump.c, Revision 1.34
1.34 ! christos 1: /* $NetBSD: zdump.c,v 1.33 2014/05/13 16:33:56 christos Exp $ */
1.17 mlelstv 2: /*
3: ** This file is in the public domain, so clarified as of
4: ** 2009-05-17 by Arthur David Olson.
5: */
1.2 jtc 6:
1.6 christos 7: #include <sys/cdefs.h>
1.1 jtc 8: #ifndef lint
1.34 ! christos 9: __RCSID("$NetBSD: zdump.c,v 1.33 2014/05/13 16:33:56 christos Exp $");
1.1 jtc 10: #endif /* !defined lint */
11:
1.25 christos 12: #include "version.h"
1.1 jtc 13: /*
14: ** This code has been made independent of the rest of the time
15: ** conversion package to increase confidence in the verification it provides.
16: ** You can use this code to help in verifying other implementations.
1.29 christos 17: **
18: ** However, include private.h when debugging, so that it overrides
19: ** time_t consistently with the rest of the package.
1.1 jtc 20: */
21:
1.29 christos 22: #include "private.h"
23:
1.15 christos 24: #include "stdio.h" /* for stdout, stderr */
1.1 jtc 25: #include "string.h" /* for strcpy */
26: #include "sys/types.h" /* for time_t */
27: #include "time.h" /* for struct tm */
28: #include "stdlib.h" /* for exit, malloc, atoi */
1.15 christos 29: #include <err.h>
1.17 mlelstv 30:
1.29 christos 31: /*
32: ** Substitutes for pre-C99 compilers.
33: ** Much of this section of code is stolen from private.h.
34: */
35:
36: #ifndef HAVE_STDINT_H
37: # define HAVE_STDINT_H \
1.33 christos 38: (199901 <= __STDC_VERSION__ \
39: || 2 < __GLIBC__ + (1 <= __GLIBC_MINOR__) \
40: || __CYGWIN__)
1.29 christos 41: #endif
42: #if HAVE_STDINT_H
43: # include "stdint.h"
44: #endif
45: #ifndef HAVE_INTTYPES_H
46: # define HAVE_INTTYPES_H HAVE_STDINT_H
47: #endif
48: #if HAVE_INTTYPES_H
49: # include <inttypes.h>
50: #endif
51:
52: #ifndef INT_FAST32_MAX
53: # if INT_MAX >> 31 == 0
54: typedef long int_fast32_t;
55: # else
56: typedef int int_fast32_t;
57: # endif
58: #endif
59:
60: #ifndef INTMAX_MAX
61: # if defined LLONG_MAX || defined __LONG_LONG_MAX__
62: typedef long long intmax_t;
1.32 christos 63: # define strtoimax strtoll
1.29 christos 64: # define PRIdMAX "lld"
1.31 christos 65: # ifdef LLONG_MAX
66: # define INTMAX_MAX LLONG_MAX
67: # else
68: # define INTMAX_MAX __LONG_LONG_MAX__
69: # endif
1.29 christos 70: # else
71: typedef long intmax_t;
1.32 christos 72: # define strtoimax strtol
1.29 christos 73: # define PRIdMAX "ld"
1.31 christos 74: # define INTMAX_MAX LONG_MAX
1.29 christos 75: # endif
76: #endif
77:
1.27 christos 78:
1.17 mlelstv 79: #ifndef ZDUMP_LO_YEAR
80: #define ZDUMP_LO_YEAR (-500)
81: #endif /* !defined ZDUMP_LO_YEAR */
82:
83: #ifndef ZDUMP_HI_YEAR
84: #define ZDUMP_HI_YEAR 2500
85: #endif /* !defined ZDUMP_HI_YEAR */
1.1 jtc 86:
87: #ifndef MAX_STRING_LENGTH
88: #define MAX_STRING_LENGTH 1024
89: #endif /* !defined MAX_STRING_LENGTH */
90:
91: #ifndef TRUE
92: #define TRUE 1
93: #endif /* !defined TRUE */
94:
95: #ifndef FALSE
96: #define FALSE 0
97: #endif /* !defined FALSE */
98:
99: #ifndef EXIT_SUCCESS
100: #define EXIT_SUCCESS 0
101: #endif /* !defined EXIT_SUCCESS */
102:
103: #ifndef EXIT_FAILURE
104: #define EXIT_FAILURE 1
105: #endif /* !defined EXIT_FAILURE */
106:
107: #ifndef SECSPERMIN
108: #define SECSPERMIN 60
109: #endif /* !defined SECSPERMIN */
110:
111: #ifndef MINSPERHOUR
112: #define MINSPERHOUR 60
113: #endif /* !defined MINSPERHOUR */
114:
115: #ifndef SECSPERHOUR
116: #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
117: #endif /* !defined SECSPERHOUR */
118:
119: #ifndef HOURSPERDAY
120: #define HOURSPERDAY 24
121: #endif /* !defined HOURSPERDAY */
122:
123: #ifndef EPOCH_YEAR
124: #define EPOCH_YEAR 1970
125: #endif /* !defined EPOCH_YEAR */
126:
127: #ifndef TM_YEAR_BASE
128: #define TM_YEAR_BASE 1900
129: #endif /* !defined TM_YEAR_BASE */
130:
131: #ifndef DAYSPERNYEAR
132: #define DAYSPERNYEAR 365
133: #endif /* !defined DAYSPERNYEAR */
134:
135: #ifndef isleap
1.17 mlelstv 136: #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
1.1 jtc 137: #endif /* !defined isleap */
138:
1.17 mlelstv 139: #ifndef isleap_sum
140: /*
141: ** See tzfile.h for details on isleap_sum.
142: */
143: #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
144: #endif /* !defined isleap_sum */
145:
1.29 christos 146: #define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
1.17 mlelstv 147: #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
148: #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
1.31 christos 149: #define SECSPER400YEARS (SECSPERNYEAR * (intmax_t) (300 + 3) \
150: + SECSPERLYEAR * (intmax_t) (100 - 3))
151:
152: /*
153: ** True if SECSPER400YEARS is known to be representable as an
154: ** intmax_t. It's OK that SECSPER400YEARS_FITS can in theory be false
155: ** even if SECSPER400YEARS is representable, because when that happens
156: ** the code merely runs a bit more slowly, and this slowness doesn't
157: ** occur on any practical platform.
158: */
159: enum { SECSPER400YEARS_FITS = SECSPERLYEAR <= INTMAX_MAX / 400 };
1.17 mlelstv 160:
161: #ifndef HAVE_GETTEXT
162: #define HAVE_GETTEXT 0
163: #endif
164: #if HAVE_GETTEXT
1.3 jtc 165: #include "locale.h" /* for setlocale */
166: #include "libintl.h"
1.17 mlelstv 167: #endif /* HAVE_GETTEXT */
1.3 jtc 168:
1.29 christos 169: #ifndef ATTRIBUTE_PURE
1.26 christos 170: #if 2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)
1.29 christos 171: # define ATTRIBUTE_PURE __attribute__ ((ATTRIBUTE_PURE__))
1.26 christos 172: #else
1.29 christos 173: # define ATTRIBUTE_PURE /* empty */
1.26 christos 174: #endif
175: #endif
176:
1.1 jtc 177: #ifndef INITIALIZE
178: #ifdef GNUC_or_lint
179: #define INITIALIZE(x) ((x) = 0)
1.17 mlelstv 180: #else /* !defined GNUC_or_lint */
1.1 jtc 181: #define INITIALIZE(x)
182: #endif /* !defined GNUC_or_lint */
183: #endif /* !defined INITIALIZE */
184:
1.3 jtc 185: /*
186: ** For the benefit of GNU folk...
1.34 ! christos 187: ** '_(MSGID)' uses the current locale's message library string for MSGID.
1.3 jtc 188: ** The default is to use gettext if available, and use MSGID otherwise.
189: */
190:
191: #ifndef _
1.17 mlelstv 192: #if HAVE_GETTEXT
1.3 jtc 193: #define _(msgid) gettext(msgid)
1.17 mlelstv 194: #else /* !HAVE_GETTEXT */
1.21 christos 195: #define _(msgid) msgid
1.17 mlelstv 196: #endif /* !HAVE_GETTEXT */
1.3 jtc 197: #endif /* !defined _ */
198:
1.34 ! christos 199: #if !defined TZ_DOMAIN && defined HAVE_GETTEXT
! 200: # define TZ_DOMAIN "tz"
! 201: #endif
1.3 jtc 202:
1.1 jtc 203: extern char ** environ;
1.17 mlelstv 204: extern int getopt(int argc, char * const argv[],
205: const char * options);
1.1 jtc 206: extern char * optarg;
207: extern int optind;
208:
1.29 christos 209: /* The minimum and maximum finite time values. */
210: static time_t absolute_min_time =
1.31 christos 211: ((time_t) -1 < 0
1.29 christos 212: ? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
213: : 0);
214: static time_t absolute_max_time =
1.31 christos 215: ((time_t) -1 < 0
216: ? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
1.29 christos 217: : -1);
1.5 jtc 218: static size_t longest;
1.1 jtc 219: static char * progname;
1.17 mlelstv 220: static int warned;
221:
222: static const char * abbr(struct tm * tmp);
223: static void abbrok(const char * abbrp, const char * zone);
1.29 christos 224: static intmax_t delta(struct tm * newp, struct tm * oldp) ATTRIBUTE_PURE;
1.17 mlelstv 225: static void dumptime(const struct tm * tmp);
226: static time_t hunt(char * name, time_t lot, time_t hit);
227: static void show(char * zone, time_t t, int v);
228: static const char * tformat(void);
1.29 christos 229: static time_t yeartot(long y) ATTRIBUTE_PURE;
1.17 mlelstv 230:
1.34 ! christos 231: /* Is A an alphabetic character in the C locale? */
! 232: static int
! 233: is_alpha(char a)
! 234: {
! 235: switch (a) {
! 236: default:
! 237: return 0;
! 238: case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
! 239: case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
! 240: case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
! 241: case 'V': case 'W': case 'X': case 'Y': case 'Z':
! 242: case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
! 243: case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
! 244: case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
! 245: case 'v': case 'w': case 'x': case 'y': case 'z':
! 246: return 1;
! 247: }
! 248: }
! 249:
1.17 mlelstv 250: #ifndef TYPECHECK
251: #define my_localtime localtime
252: #else /* !defined TYPECHECK */
253: static struct tm *
1.26 christos 254: my_localtime(time_t *tp)
1.17 mlelstv 255: {
1.26 christos 256: struct tm *tmp;
1.17 mlelstv 257:
258: tmp = localtime(tp);
259: if (tp != NULL && tmp != NULL) {
260: struct tm tm;
1.26 christos 261: time_t t;
1.17 mlelstv 262:
263: tm = *tmp;
264: t = mktime(&tm);
1.31 christos 265: if (t != *tp) {
1.17 mlelstv 266: (void) fflush(stdout);
267: (void) fprintf(stderr, "\n%s: ", progname);
268: (void) fprintf(stderr, tformat(), *tp);
269: (void) fprintf(stderr, " ->");
270: (void) fprintf(stderr, " year=%d", tmp->tm_year);
271: (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
272: (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
273: (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
274: (void) fprintf(stderr, " min=%d", tmp->tm_min);
275: (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
276: (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
277: (void) fprintf(stderr, " -> ");
278: (void) fprintf(stderr, tformat(), t);
279: (void) fprintf(stderr, "\n");
280: }
281: }
282: return tmp;
283: }
284: #endif /* !defined TYPECHECK */
285:
286: static void
1.26 christos 287: abbrok(const char *const abbrp, const char *const zone)
1.17 mlelstv 288: {
1.26 christos 289: const char *cp;
290: const char *wp;
1.17 mlelstv 291:
292: if (warned)
293: return;
294: cp = abbrp;
295: wp = NULL;
1.34 ! christos 296: while (is_alpha(*cp))
1.17 mlelstv 297: ++cp;
298: if (cp - abbrp == 0)
299: wp = _("lacks alphabetic at start");
300: else if (cp - abbrp < 3)
301: wp = _("has fewer than 3 alphabetics");
302: else if (cp - abbrp > 6)
303: wp = _("has more than 6 alphabetics");
304: if (wp == NULL && (*cp == '+' || *cp == '-')) {
305: ++cp;
1.34 ! christos 306: if ('0' <= *cp && *cp <= '9')
! 307: if (*cp++ == '1' && '0' <= *cp && *cp <= '4')
! 308: cp++;
1.17 mlelstv 309: if (*cp != '\0')
310: wp = _("differs from POSIX standard");
311: }
312: if (wp == NULL)
313: return;
314: (void) fflush(stdout);
315: (void) fprintf(stderr,
316: _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"),
317: progname, zone, abbrp, wp);
318: warned = TRUE;
319: }
320:
1.24 joerg 321: __dead static void
1.26 christos 322: usage(FILE *const stream, const int status)
1.17 mlelstv 323: {
324: (void) fprintf(stream,
1.29 christos 325: _("%s: usage: %s [--version] [--help] [-{vV}] [-{ct} [lo,]hi] zonename ...\n"
326: "\n"
327: "Report bugs to %s.\n"),
1.28 christos 328: progname, progname, REPORT_BUGS_TO);
1.17 mlelstv 329: exit(status);
330: }
1.1 jtc 331:
332: int
1.26 christos 333: main(int argc, char *argv[])
334: {
335: int i;
336: int vflag;
1.29 christos 337: int Vflag;
1.26 christos 338: char * cutarg;
1.29 christos 339: char * cuttimes;
1.26 christos 340: time_t cutlotime;
341: time_t cuthitime;
342: char ** fakeenv;
343: time_t now;
344: time_t t;
345: time_t newt;
346: struct tm tm;
347: struct tm newtm;
348: struct tm * tmp;
349: struct tm * newtmp;
1.1 jtc 350:
1.29 christos 351: cutlotime = absolute_min_time;
352: cuthitime = absolute_max_time;
1.17 mlelstv 353: #if HAVE_GETTEXT
354: (void) setlocale(LC_ALL, "");
1.3 jtc 355: #ifdef TZ_DOMAINDIR
356: (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
1.17 mlelstv 357: #endif /* defined TEXTDOMAINDIR */
1.3 jtc 358: (void) textdomain(TZ_DOMAIN);
1.17 mlelstv 359: #endif /* HAVE_GETTEXT */
1.1 jtc 360: progname = argv[0];
1.14 kleink 361: for (i = 1; i < argc; ++i)
362: if (strcmp(argv[i], "--version") == 0) {
1.28 christos 363: (void) printf("zdump %s%s\n", PKGVERSION, TZVERSION);
1.17 mlelstv 364: exit(EXIT_SUCCESS);
365: } else if (strcmp(argv[i], "--help") == 0) {
1.22 christos 366: usage(stdout, EXIT_SUCCESS);
1.14 kleink 367: }
1.29 christos 368: vflag = Vflag = 0;
369: cutarg = cuttimes = NULL;
370: for (;;)
371: switch (getopt(argc, argv, "c:t:vV")) {
372: case 'c': cutarg = optarg; break;
373: case 't': cuttimes = optarg; break;
374: case 'v': vflag = 1; break;
375: case 'V': Vflag = 1; break;
376: case -1:
377: if (! (optind == argc - 1 && strcmp(argv[optind], "=") == 0))
378: goto arg_processing_done;
379: /* Fall through. */
380: default:
381: usage(stderr, EXIT_FAILURE);
382: }
383: arg_processing_done:;
384:
385: if (vflag | Vflag) {
386: intmax_t lo;
387: intmax_t hi;
1.32 christos 388: char *loend, *hiend;
1.30 christos 389: intmax_t cutloyear = ZDUMP_LO_YEAR;
390: intmax_t cuthiyear = ZDUMP_HI_YEAR;
1.17 mlelstv 391: if (cutarg != NULL) {
1.32 christos 392: lo = strtoimax(cutarg, &loend, 10);
393: if (cutarg != loend && !*loend) {
394: hi = lo;
395: cuthiyear = hi;
396: } else if (cutarg != loend && *loend == ','
397: && (hi = strtoimax(loend + 1, &hiend, 10),
398: loend + 1 != hiend && !*hiend)) {
399: cutloyear = lo;
1.17 mlelstv 400: cuthiyear = hi;
401: } else {
402: (void) fprintf(stderr, _("%s: wild -c argument %s\n"),
403: progname, cutarg);
404: exit(EXIT_FAILURE);
405: }
406: }
1.29 christos 407: if (cutarg != NULL || cuttimes == NULL) {
408: cutlotime = yeartot(cutloyear);
409: cuthitime = yeartot(cuthiyear);
410: }
411: if (cuttimes != NULL) {
1.32 christos 412: lo = strtoimax(cuttimes, &loend, 10);
413: if (cuttimes != loend && !*loend) {
414: hi = lo;
1.29 christos 415: if (hi < cuthitime) {
416: if (hi < absolute_min_time)
417: hi = absolute_min_time;
418: cuthitime = hi;
419: }
1.32 christos 420: } else if (cuttimes != loend && *loend == ','
421: && (hi = strtoimax(loend + 1, &hiend, 10),
422: loend + 1 != hiend && !*hiend)) {
1.29 christos 423: if (cutlotime < lo) {
424: if (absolute_max_time < lo)
425: lo = absolute_max_time;
426: cutlotime = lo;
427: }
428: if (hi < cuthitime) {
429: if (hi < absolute_min_time)
430: hi = absolute_min_time;
431: cuthitime = hi;
432: }
433: } else {
434: (void) fprintf(stderr,
435: _("%s: wild -t argument %s\n"),
436: progname, cuttimes);
437: exit(EXIT_FAILURE);
438: }
439: }
1.1 jtc 440: }
441: (void) time(&now);
442: longest = 0;
443: for (i = optind; i < argc; ++i)
444: if (strlen(argv[i]) > longest)
445: longest = strlen(argv[i]);
446: {
1.26 christos 447: int from;
448: int to;
1.1 jtc 449:
1.17 mlelstv 450: for (i = 0; environ[i] != NULL; ++i)
1.1 jtc 451: continue;
1.26 christos 452: fakeenv = malloc((i + 2) * sizeof *fakeenv);
1.1 jtc 453: if (fakeenv == NULL ||
1.26 christos 454: (fakeenv[0] = malloc(longest + 4)) == NULL) {
1.15 christos 455: err(EXIT_FAILURE, "Can't allocated %zu bytes",
456: longest + 4);
1.1 jtc 457: }
458: to = 0;
1.4 mrg 459: (void)strcpy(fakeenv[to++], "TZ="); /* XXX strcpy is safe */
1.1 jtc 460: for (from = 0; environ[from] != NULL; ++from)
461: if (strncmp(environ[from], "TZ=", 3) != 0)
462: fakeenv[to++] = environ[from];
463: fakeenv[to] = NULL;
464: environ = fakeenv;
465: }
466: for (i = optind; i < argc; ++i) {
467: static char buf[MAX_STRING_LENGTH];
468:
1.4 mrg 469: (void) strcpy(&fakeenv[0][3], argv[i]); /* XXX strcpy is safe */
1.29 christos 470: if (! (vflag | Vflag)) {
1.3 jtc 471: show(argv[i], now, FALSE);
1.1 jtc 472: continue;
1.3 jtc 473: }
1.17 mlelstv 474: warned = FALSE;
475: t = absolute_min_time;
1.29 christos 476: if (!Vflag) {
477: show(argv[i], t, TRUE);
1.31 christos 478: t += SECSPERDAY;
1.29 christos 479: show(argv[i], t, TRUE);
480: }
1.17 mlelstv 481: if (t < cutlotime)
482: t = cutlotime;
483: tmp = my_localtime(&t);
484: if (tmp != NULL) {
485: tm = *tmp;
486: (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
487: }
1.1 jtc 488: for ( ; ; ) {
1.31 christos 489: newt = (t < absolute_max_time - SECSPERDAY / 2
490: ? t + SECSPERDAY / 2
491: : absolute_max_time);
492: if (cuthitime <= newt)
1.1 jtc 493: break;
1.17 mlelstv 494: newtmp = localtime(&newt);
495: if (newtmp != NULL)
496: newtm = *newtmp;
497: if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
498: (delta(&newtm, &tm) != (newt - t) ||
1.1 jtc 499: newtm.tm_isdst != tm.tm_isdst ||
1.17 mlelstv 500: strcmp(abbr(&newtm), buf) != 0)) {
1.1 jtc 501: newt = hunt(argv[i], t, newt);
1.17 mlelstv 502: newtmp = localtime(&newt);
503: if (newtmp != NULL) {
504: newtm = *newtmp;
505: (void) strncpy(buf,
506: abbr(&newtm),
507: (sizeof buf) - 1);
508: }
1.1 jtc 509: }
510: t = newt;
511: tm = newtm;
1.17 mlelstv 512: tmp = newtmp;
1.1 jtc 513: }
1.29 christos 514: if (!Vflag) {
515: t = absolute_max_time;
1.31 christos 516: t -= SECSPERDAY;
1.29 christos 517: show(argv[i], t, TRUE);
1.31 christos 518: t += SECSPERDAY;
1.29 christos 519: show(argv[i], t, TRUE);
520: }
1.1 jtc 521: }
522: if (fflush(stdout) || ferror(stdout)) {
1.16 kleink 523: err(EXIT_FAILURE, _("Error writing standard output"));
1.1 jtc 524: }
525: exit(EXIT_SUCCESS);
1.17 mlelstv 526: /* If exit fails to exit... */
527: return EXIT_FAILURE;
528: }
1.1 jtc 529:
530: static time_t
1.26 christos 531: yeartot(const long y)
1.17 mlelstv 532: {
1.31 christos 533: intmax_t myy, seconds, years;
1.29 christos 534: time_t t;
1.17 mlelstv 535:
536: myy = EPOCH_YEAR;
537: t = 0;
1.31 christos 538: while (myy < y) {
539: if (SECSPER400YEARS_FITS && 400 <= y - myy) {
540: intmax_t diff400 = (y - myy) / 400;
541: if (INTMAX_MAX / SECSPER400YEARS < diff400)
542: return absolute_max_time;
543: seconds = diff400 * SECSPER400YEARS;
544: years = diff400 * 400;
545: } else {
1.17 mlelstv 546: seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
1.31 christos 547: years = 1;
548: }
549: myy += years;
550: if (t > absolute_max_time - seconds)
551: return absolute_max_time;
552: t += seconds;
553: }
554: while (y < myy) {
555: if (SECSPER400YEARS_FITS && y + 400 <= myy && myy < 0) {
556: intmax_t diff400 = (myy - y) / 400;
557: if (INTMAX_MAX / SECSPER400YEARS < diff400)
558: return absolute_min_time;
559: seconds = diff400 * SECSPER400YEARS;
560: years = diff400 * 400;
1.17 mlelstv 561: } else {
1.31 christos 562: seconds = isleap(myy - 1) ? SECSPERLYEAR : SECSPERNYEAR;
563: years = 1;
1.17 mlelstv 564: }
1.31 christos 565: myy -= years;
566: if (t < absolute_min_time + seconds)
567: return absolute_min_time;
568: t -= seconds;
1.17 mlelstv 569: }
570: return t;
571: }
572:
573: static time_t
574: hunt(char *name, time_t lot, time_t hit)
575: {
576: time_t t;
577: struct tm lotm;
1.26 christos 578: struct tm * lotmp;
1.17 mlelstv 579: struct tm tm;
1.26 christos 580: struct tm * tmp;
1.17 mlelstv 581: char loab[MAX_STRING_LENGTH];
582:
583: lotmp = my_localtime(&lot);
584: if (lotmp != NULL) {
585: lotm = *lotmp;
586: (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
587: }
588: for ( ; ; ) {
1.29 christos 589: time_t diff = hit - lot;
1.17 mlelstv 590: if (diff < 2)
591: break;
592: t = lot;
593: t += diff / 2;
1.1 jtc 594: if (t <= lot)
595: ++t;
596: else if (t >= hit)
597: --t;
1.17 mlelstv 598: tmp = my_localtime(&t);
599: if (tmp != NULL)
600: tm = *tmp;
601: if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
602: (delta(&tm, &lotm) == (t - lot) &&
1.1 jtc 603: tm.tm_isdst == lotm.tm_isdst &&
1.17 mlelstv 604: strcmp(abbr(&tm), loab) == 0)) {
1.1 jtc 605: lot = t;
606: lotm = tm;
1.17 mlelstv 607: lotmp = tmp;
1.1 jtc 608: } else hit = t;
609: }
610: show(name, lot, TRUE);
611: show(name, hit, TRUE);
612: return hit;
613: }
614:
615: /*
1.17 mlelstv 616: ** Thanks to Paul Eggert for logic used in delta.
1.1 jtc 617: */
618:
1.29 christos 619: static intmax_t
1.26 christos 620: delta(struct tm *newp, struct tm *oldp)
1.1 jtc 621: {
1.29 christos 622: intmax_t result;
623: int tmy;
1.1 jtc 624:
625: if (newp->tm_year < oldp->tm_year)
626: return -delta(oldp, newp);
627: result = 0;
628: for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
1.17 mlelstv 629: result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
1.1 jtc 630: result += newp->tm_yday - oldp->tm_yday;
631: result *= HOURSPERDAY;
632: result += newp->tm_hour - oldp->tm_hour;
633: result *= MINSPERHOUR;
634: result += newp->tm_min - oldp->tm_min;
635: result *= SECSPERMIN;
636: result += newp->tm_sec - oldp->tm_sec;
637: return result;
638: }
639:
640: static void
1.17 mlelstv 641: show(char *zone, time_t t, int v)
1.1 jtc 642: {
1.26 christos 643: struct tm * tmp;
1.1 jtc 644:
1.5 jtc 645: (void) printf("%-*s ", (int) longest, zone);
1.1 jtc 646: if (v) {
1.17 mlelstv 647: tmp = gmtime(&t);
648: if (tmp == NULL) {
649: (void) printf(tformat(), t);
650: } else {
651: dumptime(tmp);
1.31 christos 652: (void) printf(" UT");
1.17 mlelstv 653: }
654: (void) printf(" = ");
655: }
656: tmp = my_localtime(&t);
657: dumptime(tmp);
658: if (tmp != NULL) {
659: if (*abbr(tmp) != '\0')
660: (void) printf(" %s", abbr(tmp));
661: if (v) {
662: (void) printf(" isdst=%d", tmp->tm_isdst);
1.1 jtc 663: #ifdef TM_GMTOFF
1.17 mlelstv 664: (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
1.1 jtc 665: #endif /* defined TM_GMTOFF */
1.17 mlelstv 666: }
1.1 jtc 667: }
668: (void) printf("\n");
1.17 mlelstv 669: if (tmp != NULL && *abbr(tmp) != '\0')
670: abbrok(abbr(tmp), zone);
1.1 jtc 671: }
672:
1.9 mycroft 673: static const char *
1.26 christos 674: abbr(struct tm *tmp)
1.1 jtc 675: {
1.26 christos 676: const char * result;
1.9 mycroft 677: static const char nada;
1.1 jtc 678:
679: if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
680: return &nada;
681: result = tzname[tmp->tm_isdst];
682: return (result == NULL) ? &nada : result;
683: }
1.17 mlelstv 684:
685: /*
686: ** The code below can fail on certain theoretical systems;
687: ** it works on all known real-world systems as of 2004-12-30.
688: */
689:
690: static const char *
691: tformat(void)
692: {
693: if (0 > (time_t) -1) { /* signed */
1.29 christos 694: if (sizeof (time_t) == sizeof (intmax_t))
695: return "%"PRIdMAX;
1.17 mlelstv 696: if (sizeof (time_t) > sizeof (long))
697: return "%lld";
698: if (sizeof (time_t) > sizeof (int))
699: return "%ld";
700: return "%d";
701: }
1.29 christos 702: #ifdef PRIuMAX
703: if (sizeof (time_t) == sizeof (uintmax_t))
704: return "%"PRIuMAX;
705: #endif
1.17 mlelstv 706: if (sizeof (time_t) > sizeof (unsigned long))
707: return "%llu";
708: if (sizeof (time_t) > sizeof (unsigned int))
709: return "%lu";
710: return "%u";
711: }
712:
713: static void
1.26 christos 714: dumptime(const struct tm *timeptr)
1.17 mlelstv 715: {
716: static const char wday_name[][3] = {
717: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
718: };
719: static const char mon_name[][3] = {
720: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
721: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
722: };
1.26 christos 723: const char * wn;
724: const char * mn;
725: int lead;
726: int trail;
1.17 mlelstv 727:
728: if (timeptr == NULL) {
729: (void) printf("NULL");
730: return;
731: }
732: /*
733: ** The packaged versions of localtime and gmtime never put out-of-range
734: ** values in tm_wday or tm_mon, but since this code might be compiled
735: ** with other (perhaps experimental) versions, paranoia is in order.
736: */
737: if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
738: (int) (sizeof wday_name / sizeof wday_name[0]))
739: wn = "???";
740: else wn = wday_name[timeptr->tm_wday];
741: if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
742: (int) (sizeof mon_name / sizeof mon_name[0]))
743: mn = "???";
744: else mn = mon_name[timeptr->tm_mon];
745: (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
746: wn, mn,
747: timeptr->tm_mday, timeptr->tm_hour,
748: timeptr->tm_min, timeptr->tm_sec);
749: #define DIVISOR 10
750: trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
751: lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
752: trail / DIVISOR;
753: trail %= DIVISOR;
754: if (trail < 0 && lead > 0) {
755: trail += DIVISOR;
756: --lead;
757: } else if (lead < 0 && trail > 0) {
758: trail -= DIVISOR;
759: ++lead;
760: }
761: if (lead == 0)
762: (void) printf("%d", trail);
763: else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
764: }
CVSweb <webmaster@jp.NetBSD.org>