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 * 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 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 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 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 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 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 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 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 * 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 * 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 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 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