[BACK]Return to zdump.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / time

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>