10Sstevel@tonic-gate /*
21442Srobbin * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
61138Srobbin #pragma ident "%Z%%M% %I% %E% SMI"
71138Srobbin
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate * zdump 7.24
100Sstevel@tonic-gate * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump,
110Sstevel@tonic-gate * which was based on an earlier version of the elsie code.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * For zdump 7.24, the following changes were made to the elsie code:
140Sstevel@tonic-gate * locale/textdomain/messages to match existing Solaris style.
150Sstevel@tonic-gate * Solaris verbose mode is documented to display the current time first.
160Sstevel@tonic-gate * cstyle cleaned code.
170Sstevel@tonic-gate * removed old locale/textdomain code.
180Sstevel@tonic-gate */
190Sstevel@tonic-gate
201442Srobbin static char elsieid[] = "@(#)zdump.c 7.74";
210Sstevel@tonic-gate
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate * This code has been made independent of the rest of the time
240Sstevel@tonic-gate * conversion package to increase confidence in the verification it provides.
250Sstevel@tonic-gate * You can use this code to help in verifying other implementations.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include "stdio.h" /* for stdout, stderr, perror */
290Sstevel@tonic-gate #include "string.h" /* for strcpy */
300Sstevel@tonic-gate #include "sys/types.h" /* for time_t */
310Sstevel@tonic-gate #include "time.h" /* for struct tm */
320Sstevel@tonic-gate #include "stdlib.h" /* for exit, malloc, atoi */
330Sstevel@tonic-gate #include "locale.h" /* for setlocale, textdomain */
340Sstevel@tonic-gate #include "libintl.h"
351138Srobbin #include <ctype.h>
360Sstevel@tonic-gate #include "tzfile.h" /* for defines */
371138Srobbin #include <limits.h>
381138Srobbin
391138Srobbin #ifndef ZDUMP_LO_YEAR
401138Srobbin #define ZDUMP_LO_YEAR (-500)
411138Srobbin #endif /* !defined ZDUMP_LO_YEAR */
421138Srobbin
431138Srobbin #ifndef ZDUMP_HI_YEAR
441138Srobbin #define ZDUMP_HI_YEAR 2500
451138Srobbin #endif /* !defined ZDUMP_HI_YEAR */
460Sstevel@tonic-gate
470Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH
480Sstevel@tonic-gate #define MAX_STRING_LENGTH 1024
490Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */
500Sstevel@tonic-gate
510Sstevel@tonic-gate #ifndef TRUE
520Sstevel@tonic-gate #define TRUE 1
530Sstevel@tonic-gate #endif /* !defined TRUE */
540Sstevel@tonic-gate
550Sstevel@tonic-gate #ifndef FALSE
560Sstevel@tonic-gate #define FALSE 0
570Sstevel@tonic-gate #endif /* !defined FALSE */
580Sstevel@tonic-gate
591138Srobbin #ifndef isleap_sum
601138Srobbin /*
611138Srobbin * See tzfile.h for details on isleap_sum.
621138Srobbin */
631138Srobbin #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
641138Srobbin #endif /* !defined isleap_sum */
651138Srobbin
661138Srobbin #ifndef SECSPERDAY
671138Srobbin #define SECSPERDAY ((long)SECSPERHOUR * HOURSPERDAY)
681138Srobbin #endif
691138Srobbin #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
701138Srobbin #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
711138Srobbin
721138Srobbin #ifndef GNUC_or_lint
731138Srobbin #ifdef lint
741138Srobbin #define GNUC_or_lint
751138Srobbin #else /* !defined lint */
761138Srobbin #ifdef __GNUC__
771138Srobbin #define GNUC_or_lint
781138Srobbin #endif /* defined __GNUC__ */
791138Srobbin #endif /* !defined lint */
801138Srobbin #endif /* !defined GNUC_or_lint */
811138Srobbin
820Sstevel@tonic-gate #ifndef INITIALIZE
831138Srobbin #ifdef GNUC_or_lint
840Sstevel@tonic-gate #define INITIALIZE(x) ((x) = 0)
851138Srobbin #else /* !defined GNUC_or_lint */
860Sstevel@tonic-gate #define INITIALIZE(x)
871138Srobbin #endif /* !defined GNUC_or_lint */
880Sstevel@tonic-gate #endif /* !defined INITIALIZE */
890Sstevel@tonic-gate
901138Srobbin static time_t absolute_min_time;
911138Srobbin static time_t absolute_max_time;
921138Srobbin static size_t longest;
931138Srobbin static char *progname;
941138Srobbin static int warned;
950Sstevel@tonic-gate
961138Srobbin static char *abbr(struct tm *);
971138Srobbin static void abbrok(const char *, const char *);
980Sstevel@tonic-gate static long delta(struct tm *, struct tm *);
991138Srobbin static void dumptime(const struct tm *);
1000Sstevel@tonic-gate static time_t hunt(char *, time_t, time_t);
1011138Srobbin static void setabsolutes(void);
1020Sstevel@tonic-gate static void show(char *, time_t, int);
1031138Srobbin static void usage(void);
1041138Srobbin static const char *tformat(void);
1051138Srobbin static time_t yeartot(long y);
1061138Srobbin
1071138Srobbin #ifndef TYPECHECK
1081138Srobbin #define my_localtime localtime
1091138Srobbin #else /* !defined TYPECHECK */
1101138Srobbin static struct tm *
my_localtime(tp)1111138Srobbin my_localtime(tp)
1121138Srobbin time_t *tp;
1131138Srobbin {
1141138Srobbin register struct tm *tmp;
1151138Srobbin
1161138Srobbin tmp = localtime(tp);
1171138Srobbin if (tp != NULL && tmp != NULL) {
1181138Srobbin struct tm tm;
1191138Srobbin register time_t t;
1201138Srobbin
1211138Srobbin tm = *tmp;
1221138Srobbin t = mktime(&tm);
1231138Srobbin if (t - *tp >= 1 || *tp - t >= 1) {
1241138Srobbin (void) fflush(stdout);
1251138Srobbin (void) fprintf(stderr, "\n%s: ", progname);
1261138Srobbin (void) fprintf(stderr, tformat(), *tp);
1271138Srobbin (void) fprintf(stderr, " ->");
1281138Srobbin (void) fprintf(stderr, " year=%d", tmp->tm_year);
1291138Srobbin (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
1301138Srobbin (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
1311138Srobbin (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
1321138Srobbin (void) fprintf(stderr, " min=%d", tmp->tm_min);
1331138Srobbin (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
1341138Srobbin (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
1351138Srobbin (void) fprintf(stderr, " -> ");
1361138Srobbin (void) fprintf(stderr, tformat(), t);
1371138Srobbin (void) fprintf(stderr, "\n");
1381138Srobbin }
1391138Srobbin }
1401138Srobbin return (tmp);
1411138Srobbin }
1421138Srobbin #endif /* !defined TYPECHECK */
1431138Srobbin
1441138Srobbin static void
abbrok(abbrp,zone)1451138Srobbin abbrok(abbrp, zone)
1461138Srobbin const char * const abbrp;
1471138Srobbin const char * const zone;
1481138Srobbin {
1491138Srobbin register const char *cp;
1501138Srobbin int error = 0;
1511138Srobbin
1521138Srobbin if (warned)
1531138Srobbin return;
1541138Srobbin cp = abbrp;
1551138Srobbin while (isascii(*cp) && isalpha((unsigned char)*cp))
1561138Srobbin ++cp;
1571138Srobbin (void) fflush(stdout);
1581138Srobbin if (cp - abbrp == 0) {
1591138Srobbin /*
1601138Srobbin * TRANSLATION_NOTE
1611138Srobbin * The first %s prints for the program name (zdump),
1621138Srobbin * the second %s prints the timezone name, the third
1631138Srobbin * %s prints the timezone abbreviation (tzname[0] or
1641138Srobbin * tzname[1]).
1651138Srobbin */
1661138Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
1671138Srobbin "abbreviation \"%s\" lacks alphabetic at start\n"),
1681138Srobbin progname, zone, abbrp);
1691138Srobbin error = 1;
1701138Srobbin } else if (cp - abbrp < 3) {
1711138Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
1721138Srobbin "abbreviation \"%s\" has fewer than 3 alphabetics\n"),
1731138Srobbin progname, zone, abbrp);
1741138Srobbin error = 1;
1751138Srobbin } else if (cp - abbrp > 6) {
1761138Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" "
1771138Srobbin "abbreviation \"%s\" has more than 6 alphabetics\n"),
1781138Srobbin progname, zone, abbrp);
1791138Srobbin error = 1;
1801138Srobbin }
1811138Srobbin if (error == 0 && (*cp == '+' || *cp == '-')) {
1821138Srobbin ++cp;
1831138Srobbin if (isascii(*cp) && isdigit((unsigned char)*cp))
1841138Srobbin if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
1851138Srobbin ++cp;
1861442Srobbin if (*cp != '\0') {
1871442Srobbin (void) fprintf(stderr, gettext("%s: warning: "
1881442Srobbin "zone \"%s\" abbreviation \"%s\" differs from "
1891442Srobbin "POSIX standard\n"), progname, zone, abbrp);
1901442Srobbin error = 1;
1911442Srobbin }
1921138Srobbin }
1931138Srobbin if (error)
1941138Srobbin warned = TRUE;
1951138Srobbin }
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate int
main(argc,argv)1980Sstevel@tonic-gate main(argc, argv)
1990Sstevel@tonic-gate int argc;
2001138Srobbin char *argv[];
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate register int i;
2030Sstevel@tonic-gate register int c;
2040Sstevel@tonic-gate register int vflag;
2051138Srobbin register char *cutarg;
2061138Srobbin register long cutloyear = ZDUMP_LO_YEAR;
2071138Srobbin register long cuthiyear = ZDUMP_HI_YEAR;
2081138Srobbin register time_t cutlotime;
2091138Srobbin register time_t cuthitime;
2100Sstevel@tonic-gate time_t now;
2110Sstevel@tonic-gate time_t t;
2120Sstevel@tonic-gate time_t newt;
2130Sstevel@tonic-gate struct tm tm;
2140Sstevel@tonic-gate struct tm newtm;
2151138Srobbin register struct tm *tmp;
2161138Srobbin register struct tm *newtmp;
2170Sstevel@tonic-gate
2181138Srobbin INITIALIZE(cutlotime);
2191138Srobbin INITIALIZE(cuthitime);
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
2220Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
2230Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
2240Sstevel@tonic-gate #endif
2250Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate progname = argv[0];
2281138Srobbin for (i = 1; i < argc; ++i)
2291138Srobbin if (strcmp(argv[i], "--version") == 0) {
2301138Srobbin (void) printf("%s\n", elsieid);
2311138Srobbin exit(EXIT_SUCCESS);
2321138Srobbin }
2330Sstevel@tonic-gate vflag = 0;
2341138Srobbin cutarg = NULL;
2350Sstevel@tonic-gate while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
2360Sstevel@tonic-gate if (c == 'v')
2370Sstevel@tonic-gate vflag = 1;
2381138Srobbin else cutarg = optarg;
2390Sstevel@tonic-gate if (c != EOF ||
2400Sstevel@tonic-gate (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
2411138Srobbin usage();
2420Sstevel@tonic-gate /* NOTREACHED */
2430Sstevel@tonic-gate }
2441138Srobbin if (vflag) {
2451138Srobbin if (cutarg != NULL) {
2461138Srobbin long lo;
2471138Srobbin long hi;
2481138Srobbin char dummy;
2490Sstevel@tonic-gate
2501138Srobbin if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
2511138Srobbin cuthiyear = hi;
2521138Srobbin } else if (sscanf(cutarg, "%ld,%ld%c",
2531138Srobbin &lo, &hi, &dummy) == 2) {
2541138Srobbin cutloyear = lo;
2551138Srobbin cuthiyear = hi;
2561138Srobbin } else {
2571138Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"),
2581138Srobbin progname, cutarg);
2591138Srobbin exit(EXIT_FAILURE);
2601138Srobbin }
2611138Srobbin }
2621138Srobbin setabsolutes();
2631138Srobbin cutlotime = yeartot(cutloyear);
2641138Srobbin cuthitime = yeartot(cuthiyear);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate (void) time(&now);
2670Sstevel@tonic-gate longest = 0;
2680Sstevel@tonic-gate for (i = optind; i < argc; ++i)
2690Sstevel@tonic-gate if (strlen(argv[i]) > longest)
2700Sstevel@tonic-gate longest = strlen(argv[i]);
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate for (i = optind; i < argc; ++i) {
2730Sstevel@tonic-gate static char buf[MAX_STRING_LENGTH];
2741138Srobbin static char *tzp = NULL;
2750Sstevel@tonic-gate
2761138Srobbin (void) unsetenv("TZ");
2771138Srobbin if (tzp != NULL)
2781138Srobbin free(tzp);
2791138Srobbin if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) {
2801138Srobbin perror(progname);
2811138Srobbin exit(EXIT_FAILURE);
2821138Srobbin }
2831138Srobbin (void) strcpy(tzp, "TZ=");
2841138Srobbin (void) strcat(tzp, argv[i]);
2851138Srobbin if (putenv(tzp) != 0) {
2861138Srobbin perror(progname);
2871138Srobbin exit(EXIT_FAILURE);
2881138Srobbin }
2890Sstevel@tonic-gate if (!vflag) {
2900Sstevel@tonic-gate show(argv[i], now, FALSE);
2910Sstevel@tonic-gate continue;
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate #if defined(sun)
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate * We show the current time first, probably because we froze
2970Sstevel@tonic-gate * the behavior of zdump some time ago and then it got
2980Sstevel@tonic-gate * changed.
2990Sstevel@tonic-gate */
3000Sstevel@tonic-gate show(argv[i], now, TRUE);
3010Sstevel@tonic-gate #endif
3021138Srobbin warned = FALSE;
3031138Srobbin t = absolute_min_time;
3040Sstevel@tonic-gate show(argv[i], t, TRUE);
3050Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY;
3060Sstevel@tonic-gate show(argv[i], t, TRUE);
3071138Srobbin if (t < cutlotime)
3081138Srobbin t = cutlotime;
3091138Srobbin tmp = my_localtime(&t);
3101138Srobbin if (tmp != NULL) {
3111138Srobbin tm = *tmp;
3121138Srobbin (void) strncpy(buf, abbr(&tm), sizeof (buf) - 1);
3131138Srobbin }
3140Sstevel@tonic-gate for (;;) {
3151138Srobbin if (t >= cuthitime)
3160Sstevel@tonic-gate break;
317*3196Srobbin /* check if newt will overrun maximum time_t value */
318*3196Srobbin if (t > LONG_MAX - (SECSPERHOUR * 12))
319*3196Srobbin break;
3200Sstevel@tonic-gate newt = t + SECSPERHOUR * 12;
3211138Srobbin if (newt >= cuthitime)
3220Sstevel@tonic-gate break;
3231138Srobbin newtmp = localtime(&newt);
3241138Srobbin if (newtmp != NULL)
3251138Srobbin newtm = *newtmp;
3261138Srobbin if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
3271138Srobbin (delta(&newtm, &tm) != (newt - t) ||
3280Sstevel@tonic-gate newtm.tm_isdst != tm.tm_isdst ||
3291138Srobbin strcmp(abbr(&newtm), buf) != 0)) {
3300Sstevel@tonic-gate newt = hunt(argv[i], t, newt);
3311138Srobbin newtmp = localtime(&newt);
3321138Srobbin if (newtmp != NULL) {
3331138Srobbin newtm = *newtmp;
3341138Srobbin (void) strncpy(buf,
3351138Srobbin abbr(&newtm),
3361138Srobbin sizeof (buf) - 1);
3371138Srobbin }
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate t = newt;
3400Sstevel@tonic-gate tm = newtm;
3411138Srobbin tmp = newtmp;
3420Sstevel@tonic-gate }
3431138Srobbin t = absolute_max_time;
3440Sstevel@tonic-gate #if defined(sun)
3450Sstevel@tonic-gate show(argv[i], t, TRUE);
3460Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY;
3470Sstevel@tonic-gate show(argv[i], t, TRUE);
3480Sstevel@tonic-gate #else /* !defined(sun) */
3490Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY;
3500Sstevel@tonic-gate show(argv[i], t, TRUE);
3510Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY;
3520Sstevel@tonic-gate show(argv[i], t, TRUE);
3530Sstevel@tonic-gate #endif /* !defined(sun) */
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate if (fflush(stdout) || ferror(stdout)) {
3561138Srobbin (void) fprintf(stderr, "%s: ", progname);
3571138Srobbin (void) perror(gettext("Error writing standard output"));
3581138Srobbin exit(EXIT_FAILURE);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate return (EXIT_SUCCESS);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate
3631138Srobbin static void
setabsolutes()3641138Srobbin setabsolutes()
3651138Srobbin {
3661138Srobbin #if defined(sun)
3671138Srobbin absolute_min_time = LONG_MIN;
3681138Srobbin absolute_max_time = LONG_MAX;
3691138Srobbin #else
3701138Srobbin if (0.5 == (time_t)0.5) {
3711138Srobbin /*
3721138Srobbin * time_t is floating.
3731138Srobbin */
3741138Srobbin if (sizeof (time_t) == sizeof (float)) {
3751138Srobbin absolute_min_time = (time_t)-FLT_MAX;
3761138Srobbin absolute_max_time = (time_t)FLT_MAX;
3771138Srobbin } else if (sizeof (time_t) == sizeof (double)) {
3781138Srobbin absolute_min_time = (time_t)-DBL_MAX;
3791138Srobbin absolute_max_time = (time_t)DBL_MAX;
3801138Srobbin } else {
3811138Srobbin (void) fprintf(stderr, gettext("%s: use of -v on "
3821138Srobbin "system with floating time_t other than float "
3831138Srobbin "or double\n"), progname);
3841138Srobbin exit(EXIT_FAILURE);
3851138Srobbin }
3861138Srobbin } else
3871138Srobbin /*CONSTANTCONDITION*/
3881138Srobbin if (0 > (time_t)-1) {
3891138Srobbin /*
3901138Srobbin * time_t is signed.
3911138Srobbin */
3921138Srobbin register time_t hibit;
3931138Srobbin
3941138Srobbin for (hibit = 1; (hibit * 2) != 0; hibit *= 2)
3951138Srobbin continue;
3961138Srobbin absolute_min_time = hibit;
3971138Srobbin absolute_max_time = -(hibit + 1);
3981138Srobbin } else {
3991138Srobbin /*
4001138Srobbin * time_t is unsigned.
4011138Srobbin */
4021138Srobbin absolute_min_time = 0;
4031138Srobbin absolute_max_time = absolute_min_time - 1;
4041138Srobbin }
4051138Srobbin #endif
4061138Srobbin }
4071138Srobbin
4081138Srobbin static time_t
yeartot(y)4091138Srobbin yeartot(y)
4101138Srobbin const long y;
4111138Srobbin {
4121138Srobbin register long myy;
4131138Srobbin register long seconds;
4141138Srobbin register time_t t;
4151138Srobbin
4161138Srobbin myy = EPOCH_YEAR;
4171138Srobbin t = 0;
4181138Srobbin while (myy != y) {
4191138Srobbin if (myy < y) {
4201138Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
4211138Srobbin ++myy;
4221138Srobbin if (t > absolute_max_time - seconds) {
4231138Srobbin t = absolute_max_time;
4241138Srobbin break;
4251138Srobbin }
4261138Srobbin t += seconds;
4271138Srobbin } else {
4281138Srobbin --myy;
4291138Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
4301138Srobbin if (t < absolute_min_time + seconds) {
4311138Srobbin t = absolute_min_time;
4321138Srobbin break;
4331138Srobbin }
4341138Srobbin t -= seconds;
4351138Srobbin }
4361138Srobbin }
4371138Srobbin return (t);
4381138Srobbin }
4391138Srobbin
4400Sstevel@tonic-gate static time_t
hunt(name,lot,hit)4410Sstevel@tonic-gate hunt(name, lot, hit)
4421138Srobbin char *name;
4430Sstevel@tonic-gate time_t lot;
4440Sstevel@tonic-gate time_t hit;
4450Sstevel@tonic-gate {
4461138Srobbin time_t t;
4471138Srobbin long diff;
4481138Srobbin struct tm lotm;
4491138Srobbin register struct tm *lotmp;
4501138Srobbin struct tm tm;
4511138Srobbin register struct tm *tmp;
4521138Srobbin char loab[MAX_STRING_LENGTH];
4530Sstevel@tonic-gate
4541138Srobbin lotmp = my_localtime(&lot);
4551138Srobbin if (lotmp != NULL) {
4561138Srobbin lotm = *lotmp;
4571138Srobbin (void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1);
4581138Srobbin }
4591138Srobbin for (;;) {
4601138Srobbin diff = (long)(hit - lot);
4611138Srobbin if (diff < 2)
4621138Srobbin break;
4631138Srobbin t = lot;
4641138Srobbin t += diff / 2;
4650Sstevel@tonic-gate if (t <= lot)
4660Sstevel@tonic-gate ++t;
4670Sstevel@tonic-gate else if (t >= hit)
4680Sstevel@tonic-gate --t;
4691138Srobbin tmp = my_localtime(&t);
4701138Srobbin if (tmp != NULL)
4711138Srobbin tm = *tmp;
4721138Srobbin if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
4731138Srobbin (delta(&tm, &lotm) == (t - lot) &&
4740Sstevel@tonic-gate tm.tm_isdst == lotm.tm_isdst &&
4751138Srobbin strcmp(abbr(&tm), loab) == 0)) {
4760Sstevel@tonic-gate lot = t;
4770Sstevel@tonic-gate lotm = tm;
4781138Srobbin lotmp = tmp;
4790Sstevel@tonic-gate } else hit = t;
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate show(name, lot, TRUE);
4820Sstevel@tonic-gate show(name, hit, TRUE);
4830Sstevel@tonic-gate return (hit);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate /*
4871442Srobbin * Thanks to Paul Eggert for logic used in delta.
4880Sstevel@tonic-gate */
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate static long
delta(newp,oldp)4910Sstevel@tonic-gate delta(newp, oldp)
4921138Srobbin struct tm *newp;
4931138Srobbin struct tm *oldp;
4940Sstevel@tonic-gate {
4951138Srobbin register long result;
4961138Srobbin register int tmy;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate if (newp->tm_year < oldp->tm_year)
4990Sstevel@tonic-gate return (-delta(oldp, newp));
5000Sstevel@tonic-gate result = 0;
5010Sstevel@tonic-gate for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
5021138Srobbin result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
5030Sstevel@tonic-gate result += newp->tm_yday - oldp->tm_yday;
5040Sstevel@tonic-gate result *= HOURSPERDAY;
5050Sstevel@tonic-gate result += newp->tm_hour - oldp->tm_hour;
5060Sstevel@tonic-gate result *= MINSPERHOUR;
5070Sstevel@tonic-gate result += newp->tm_min - oldp->tm_min;
5080Sstevel@tonic-gate result *= SECSPERMIN;
5090Sstevel@tonic-gate result += newp->tm_sec - oldp->tm_sec;
5100Sstevel@tonic-gate return (result);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate static void
show(zone,t,v)5140Sstevel@tonic-gate show(zone, t, v)
5151138Srobbin char *zone;
5160Sstevel@tonic-gate time_t t;
5170Sstevel@tonic-gate int v;
5180Sstevel@tonic-gate {
5191138Srobbin register struct tm *tmp;
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate (void) printf("%-*s ", (int)longest, zone);
5220Sstevel@tonic-gate if (v) {
5231138Srobbin tmp = gmtime(&t);
5241138Srobbin if (tmp == NULL) {
5251138Srobbin (void) printf(tformat(), t);
5261138Srobbin } else {
5271138Srobbin dumptime(tmp);
5281138Srobbin (void) printf(" UTC");
5291138Srobbin }
5301138Srobbin (void) printf(" = ");
5311138Srobbin }
5321138Srobbin tmp = my_localtime(&t);
5331138Srobbin dumptime(tmp);
5341138Srobbin if (tmp != NULL) {
5351138Srobbin if (*abbr(tmp) != '\0')
5361138Srobbin (void) printf(" %s", abbr(tmp));
5371138Srobbin if (v) {
5381138Srobbin (void) printf(" isdst=%d", tmp->tm_isdst);
5391138Srobbin #ifdef TM_GMTOFF
5401138Srobbin (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
5411138Srobbin #endif /* defined TM_GMTOFF */
5421138Srobbin }
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate (void) printf("\n");
5451138Srobbin if (tmp != NULL && *abbr(tmp) != '\0')
5461138Srobbin abbrok(abbr(tmp), zone);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate static char *
abbr(tmp)5500Sstevel@tonic-gate abbr(tmp)
5511138Srobbin struct tm *tmp;
5520Sstevel@tonic-gate {
5531138Srobbin register char *result;
5540Sstevel@tonic-gate static char nada;
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
5570Sstevel@tonic-gate return (&nada);
5580Sstevel@tonic-gate result = tzname[tmp->tm_isdst];
5590Sstevel@tonic-gate return ((result == NULL) ? &nada : result);
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate
5621138Srobbin /*
5631138Srobbin * The code below can fail on certain theoretical systems;
5641138Srobbin * it works on all known real-world systems as of 2004-12-30.
5651138Srobbin */
5661138Srobbin
5671138Srobbin static const char *
tformat()5681138Srobbin tformat()
5691138Srobbin {
5701138Srobbin #if defined(sun)
5711138Srobbin /* time_t is signed long */
5721138Srobbin return ("%ld");
5731138Srobbin #else
5741138Srobbin /*CONSTANTCONDITION*/
5751138Srobbin if (0.5 == (time_t)0.5) { /* floating */
5761138Srobbin /*CONSTANTCONDITION*/
5771138Srobbin if (sizeof (time_t) > sizeof (double))
5781138Srobbin return ("%Lg");
5791138Srobbin return ("%g");
5801138Srobbin }
5811138Srobbin /*CONSTANTCONDITION*/
5821138Srobbin if (0 > (time_t)-1) { /* signed */
5831138Srobbin /*CONSTANTCONDITION*/
5841138Srobbin if (sizeof (time_t) > sizeof (long))
5851138Srobbin return ("%lld");
5861138Srobbin /*CONSTANTCONDITION*/
5871138Srobbin if (sizeof (time_t) > sizeof (int))
5881138Srobbin return ("%ld");
5891138Srobbin return ("%d");
5901138Srobbin }
5911138Srobbin /*CONSTANTCONDITION*/
5921138Srobbin if (sizeof (time_t) > sizeof (unsigned long))
5931138Srobbin return ("%llu");
5941138Srobbin /*CONSTANTCONDITION*/
5951138Srobbin if (sizeof (time_t) > sizeof (unsigned int))
5961138Srobbin return ("%lu");
5971138Srobbin return ("%u");
5981138Srobbin #endif
5991138Srobbin }
6001138Srobbin
6010Sstevel@tonic-gate static void
dumptime(timeptr)6021138Srobbin dumptime(timeptr)
6031138Srobbin register const struct tm *timeptr;
6041138Srobbin {
6051138Srobbin static const char wday_name[][3] = {
6061138Srobbin "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
6071138Srobbin };
6081138Srobbin static const char mon_name[][3] = {
6091138Srobbin "Jan", "Feb", "Mar", "Apr", "May", "Jun",
6101138Srobbin "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
6111138Srobbin };
6121138Srobbin register const char *wn;
6131138Srobbin register const char *mn;
6141138Srobbin register int lead;
6151138Srobbin register int trail;
6161138Srobbin
6171138Srobbin if (timeptr == NULL) {
6181138Srobbin (void) printf("NULL");
6191138Srobbin return;
6201138Srobbin }
6211138Srobbin /*
6221138Srobbin * The packaged versions of localtime and gmtime never put out-of-range
6231138Srobbin * values in tm_wday or tm_mon, but since this code might be compiled
6241138Srobbin * with other (perhaps experimental) versions, paranoia is in order.
6251138Srobbin */
6261138Srobbin if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
6271138Srobbin (int)(sizeof (wday_name) / sizeof (wday_name[0])))
6281138Srobbin wn = "???";
6291138Srobbin else wn = wday_name[timeptr->tm_wday];
6301138Srobbin if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
6311138Srobbin (int)(sizeof (mon_name) / sizeof (mon_name[0])))
6321138Srobbin mn = "???";
6331138Srobbin else mn = mon_name[timeptr->tm_mon];
6341138Srobbin (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
6351138Srobbin wn, mn,
6361138Srobbin timeptr->tm_mday, timeptr->tm_hour,
6371138Srobbin timeptr->tm_min, timeptr->tm_sec);
6381138Srobbin #define DIVISOR 10
6391138Srobbin trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
6401138Srobbin lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
6411138Srobbin trail / DIVISOR;
6421138Srobbin trail %= DIVISOR;
6431138Srobbin if (trail < 0 && lead > 0) {
6441138Srobbin trail += DIVISOR;
6451138Srobbin --lead;
6461138Srobbin } else if (lead < 0 && trail > 0) {
6471138Srobbin trail -= DIVISOR;
6481138Srobbin ++lead;
6491138Srobbin }
6501138Srobbin if (lead == 0)
6511138Srobbin (void) printf("%d", trail);
6521138Srobbin else
6531138Srobbin (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
6541138Srobbin }
6551138Srobbin
6561138Srobbin static void
usage()6571138Srobbin usage()
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate (void) fprintf(stderr, gettext(
6601138Srobbin "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"),
6611138Srobbin progname);
6621138Srobbin exit(EXIT_FAILURE);
6630Sstevel@tonic-gate /* NOTREACHED */
6640Sstevel@tonic-gate }
665