17c478bd9Sstevel@tonic-gate /* 2f430f59aSrobbin * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate * zdump 7.24 87c478bd9Sstevel@tonic-gate * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump, 97c478bd9Sstevel@tonic-gate * which was based on an earlier version of the elsie code. 107c478bd9Sstevel@tonic-gate * 117c478bd9Sstevel@tonic-gate * For zdump 7.24, the following changes were made to the elsie code: 127c478bd9Sstevel@tonic-gate * locale/textdomain/messages to match existing Solaris style. 137c478bd9Sstevel@tonic-gate * Solaris verbose mode is documented to display the current time first. 147c478bd9Sstevel@tonic-gate * cstyle cleaned code. 157c478bd9Sstevel@tonic-gate * removed old locale/textdomain code. 167c478bd9Sstevel@tonic-gate */ 177c478bd9Sstevel@tonic-gate 18f430f59aSrobbin static char elsieid[] = "@(#)zdump.c 7.74"; 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate /* 217c478bd9Sstevel@tonic-gate * This code has been made independent of the rest of the time 227c478bd9Sstevel@tonic-gate * conversion package to increase confidence in the verification it provides. 237c478bd9Sstevel@tonic-gate * You can use this code to help in verifying other implementations. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include "stdio.h" /* for stdout, stderr, perror */ 277c478bd9Sstevel@tonic-gate #include "string.h" /* for strcpy */ 287c478bd9Sstevel@tonic-gate #include "sys/types.h" /* for time_t */ 297c478bd9Sstevel@tonic-gate #include "time.h" /* for struct tm */ 307c478bd9Sstevel@tonic-gate #include "stdlib.h" /* for exit, malloc, atoi */ 317c478bd9Sstevel@tonic-gate #include "locale.h" /* for setlocale, textdomain */ 327c478bd9Sstevel@tonic-gate #include "libintl.h" 3380868c53Srobbin #include <ctype.h> 347c478bd9Sstevel@tonic-gate #include "tzfile.h" /* for defines */ 3580868c53Srobbin #include <limits.h> 3680868c53Srobbin 3780868c53Srobbin #ifndef ZDUMP_LO_YEAR 3880868c53Srobbin #define ZDUMP_LO_YEAR (-500) 3980868c53Srobbin #endif /* !defined ZDUMP_LO_YEAR */ 4080868c53Srobbin 4180868c53Srobbin #ifndef ZDUMP_HI_YEAR 4280868c53Srobbin #define ZDUMP_HI_YEAR 2500 4380868c53Srobbin #endif /* !defined ZDUMP_HI_YEAR */ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH 467c478bd9Sstevel@tonic-gate #define MAX_STRING_LENGTH 1024 477c478bd9Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #ifndef TRUE 507c478bd9Sstevel@tonic-gate #define TRUE 1 517c478bd9Sstevel@tonic-gate #endif /* !defined TRUE */ 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #ifndef FALSE 547c478bd9Sstevel@tonic-gate #define FALSE 0 557c478bd9Sstevel@tonic-gate #endif /* !defined FALSE */ 567c478bd9Sstevel@tonic-gate 5780868c53Srobbin #ifndef isleap_sum 5880868c53Srobbin /* 5980868c53Srobbin * See tzfile.h for details on isleap_sum. 6080868c53Srobbin */ 6180868c53Srobbin #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 6280868c53Srobbin #endif /* !defined isleap_sum */ 6380868c53Srobbin 6480868c53Srobbin #ifndef SECSPERDAY 6580868c53Srobbin #define SECSPERDAY ((long)SECSPERHOUR * HOURSPERDAY) 6680868c53Srobbin #endif 6780868c53Srobbin #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 6880868c53Srobbin #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 6980868c53Srobbin 7080868c53Srobbin #ifndef GNUC_or_lint 717c478bd9Sstevel@tonic-gate #ifdef lint 7280868c53Srobbin #define GNUC_or_lint 7380868c53Srobbin #else /* !defined lint */ 7480868c53Srobbin #ifdef __GNUC__ 7580868c53Srobbin #define GNUC_or_lint 7680868c53Srobbin #endif /* defined __GNUC__ */ 777c478bd9Sstevel@tonic-gate #endif /* !defined lint */ 7880868c53Srobbin #endif /* !defined GNUC_or_lint */ 7980868c53Srobbin 8080868c53Srobbin #ifndef INITIALIZE 8180868c53Srobbin #ifdef GNUC_or_lint 8280868c53Srobbin #define INITIALIZE(x) ((x) = 0) 8380868c53Srobbin #else /* !defined GNUC_or_lint */ 8480868c53Srobbin #define INITIALIZE(x) 8580868c53Srobbin #endif /* !defined GNUC_or_lint */ 867c478bd9Sstevel@tonic-gate #endif /* !defined INITIALIZE */ 877c478bd9Sstevel@tonic-gate 8880868c53Srobbin static time_t absolute_min_time; 8980868c53Srobbin static time_t absolute_max_time; 907c478bd9Sstevel@tonic-gate static size_t longest; 917c478bd9Sstevel@tonic-gate static char *progname; 9280868c53Srobbin static int warned; 9380868c53Srobbin 9480868c53Srobbin static char *abbr(struct tm *); 9580868c53Srobbin static void abbrok(const char *, const char *); 9680868c53Srobbin static long delta(struct tm *, struct tm *); 9780868c53Srobbin static void dumptime(const struct tm *); 9880868c53Srobbin static time_t hunt(char *, time_t, time_t); 9980868c53Srobbin static void setabsolutes(void); 1007c478bd9Sstevel@tonic-gate static void show(char *, time_t, int); 10180868c53Srobbin static void usage(void); 10280868c53Srobbin static const char *tformat(void); 10380868c53Srobbin static time_t yeartot(long y); 10480868c53Srobbin 10580868c53Srobbin #ifndef TYPECHECK 10680868c53Srobbin #define my_localtime localtime 10780868c53Srobbin #else /* !defined TYPECHECK */ 10880868c53Srobbin static struct tm * 10980868c53Srobbin my_localtime(tp) 11080868c53Srobbin time_t *tp; 11180868c53Srobbin { 11280868c53Srobbin register struct tm *tmp; 11380868c53Srobbin 11480868c53Srobbin tmp = localtime(tp); 11580868c53Srobbin if (tp != NULL && tmp != NULL) { 11680868c53Srobbin struct tm tm; 11780868c53Srobbin register time_t t; 11880868c53Srobbin 11980868c53Srobbin tm = *tmp; 12080868c53Srobbin t = mktime(&tm); 12180868c53Srobbin if (t - *tp >= 1 || *tp - t >= 1) { 12280868c53Srobbin (void) fflush(stdout); 12380868c53Srobbin (void) fprintf(stderr, "\n%s: ", progname); 12480868c53Srobbin (void) fprintf(stderr, tformat(), *tp); 12580868c53Srobbin (void) fprintf(stderr, " ->"); 12680868c53Srobbin (void) fprintf(stderr, " year=%d", tmp->tm_year); 12780868c53Srobbin (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 12880868c53Srobbin (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 12980868c53Srobbin (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 13080868c53Srobbin (void) fprintf(stderr, " min=%d", tmp->tm_min); 13180868c53Srobbin (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 13280868c53Srobbin (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 13380868c53Srobbin (void) fprintf(stderr, " -> "); 13480868c53Srobbin (void) fprintf(stderr, tformat(), t); 13580868c53Srobbin (void) fprintf(stderr, "\n"); 13680868c53Srobbin } 13780868c53Srobbin } 13880868c53Srobbin return (tmp); 13980868c53Srobbin } 14080868c53Srobbin #endif /* !defined TYPECHECK */ 14180868c53Srobbin 14280868c53Srobbin static void 143*84ba300aSDan McDonald abbrok(const char * const abbrp, const char * const zone) 14480868c53Srobbin { 14580868c53Srobbin register const char *cp; 14680868c53Srobbin int error = 0; 14780868c53Srobbin 14880868c53Srobbin if (warned) 14980868c53Srobbin return; 15080868c53Srobbin cp = abbrp; 151*84ba300aSDan McDonald while (isalpha(*cp) || isdigit(*cp) || *cp == '-' || *cp == '+') 15280868c53Srobbin ++cp; 15380868c53Srobbin (void) fflush(stdout); 154*84ba300aSDan McDonald if (cp - abbrp < 3) { 15580868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 15680868c53Srobbin "abbreviation \"%s\" has fewer than 3 alphabetics\n"), 15780868c53Srobbin progname, zone, abbrp); 15880868c53Srobbin error = 1; 15980868c53Srobbin } else if (cp - abbrp > 6) { 16080868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 161*84ba300aSDan McDonald "abbreviation \"%s\" has more than 6 characters\n"), 16280868c53Srobbin progname, zone, abbrp); 16380868c53Srobbin error = 1; 164*84ba300aSDan McDonald } else if (*cp != '\0') { 165*84ba300aSDan McDonald (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 166*84ba300aSDan McDonald "abbreviation \"%s\" has characters other than " 167*84ba300aSDan McDonald "alphanumerics\n"), progname, zone, abbrp); 16880868c53Srobbin error = 1; 16980868c53Srobbin } 17080868c53Srobbin if (error) 17180868c53Srobbin warned = TRUE; 17280868c53Srobbin } 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate int 1757c478bd9Sstevel@tonic-gate main(argc, argv) 1767c478bd9Sstevel@tonic-gate int argc; 1777c478bd9Sstevel@tonic-gate char *argv[]; 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate register int i; 1807c478bd9Sstevel@tonic-gate register int c; 1817c478bd9Sstevel@tonic-gate register int vflag; 18280868c53Srobbin register char *cutarg; 18380868c53Srobbin register long cutloyear = ZDUMP_LO_YEAR; 18480868c53Srobbin register long cuthiyear = ZDUMP_HI_YEAR; 18580868c53Srobbin register time_t cutlotime; 18680868c53Srobbin register time_t cuthitime; 1877c478bd9Sstevel@tonic-gate time_t now; 1887c478bd9Sstevel@tonic-gate time_t t; 1897c478bd9Sstevel@tonic-gate time_t newt; 1907c478bd9Sstevel@tonic-gate struct tm tm; 1917c478bd9Sstevel@tonic-gate struct tm newtm; 19280868c53Srobbin register struct tm *tmp; 19380868c53Srobbin register struct tm *newtmp; 1947c478bd9Sstevel@tonic-gate 19580868c53Srobbin INITIALIZE(cutlotime); 19680868c53Srobbin INITIALIZE(cuthitime); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1997c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 2007c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 2017c478bd9Sstevel@tonic-gate #endif 2027c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate progname = argv[0]; 20580868c53Srobbin for (i = 1; i < argc; ++i) 20680868c53Srobbin if (strcmp(argv[i], "--version") == 0) { 20780868c53Srobbin (void) printf("%s\n", elsieid); 20880868c53Srobbin exit(EXIT_SUCCESS); 20980868c53Srobbin } 2107c478bd9Sstevel@tonic-gate vflag = 0; 21180868c53Srobbin cutarg = NULL; 2127c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 2137c478bd9Sstevel@tonic-gate if (c == 'v') 2147c478bd9Sstevel@tonic-gate vflag = 1; 21580868c53Srobbin else cutarg = optarg; 2167c478bd9Sstevel@tonic-gate if (c != EOF || 2177c478bd9Sstevel@tonic-gate (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 21880868c53Srobbin usage(); 2197c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2207c478bd9Sstevel@tonic-gate } 22180868c53Srobbin if (vflag) { 22280868c53Srobbin if (cutarg != NULL) { 22380868c53Srobbin long lo; 22480868c53Srobbin long hi; 22580868c53Srobbin char dummy; 2267c478bd9Sstevel@tonic-gate 22780868c53Srobbin if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { 22880868c53Srobbin cuthiyear = hi; 22980868c53Srobbin } else if (sscanf(cutarg, "%ld,%ld%c", 23080868c53Srobbin &lo, &hi, &dummy) == 2) { 23180868c53Srobbin cutloyear = lo; 23280868c53Srobbin cuthiyear = hi; 23380868c53Srobbin } else { 23480868c53Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"), 23580868c53Srobbin progname, cutarg); 23680868c53Srobbin exit(EXIT_FAILURE); 23780868c53Srobbin } 23880868c53Srobbin } 23980868c53Srobbin setabsolutes(); 24080868c53Srobbin cutlotime = yeartot(cutloyear); 24180868c53Srobbin cuthitime = yeartot(cuthiyear); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate (void) time(&now); 2447c478bd9Sstevel@tonic-gate longest = 0; 2457c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) 2467c478bd9Sstevel@tonic-gate if (strlen(argv[i]) > longest) 2477c478bd9Sstevel@tonic-gate longest = strlen(argv[i]); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) { 2507c478bd9Sstevel@tonic-gate static char buf[MAX_STRING_LENGTH]; 25180868c53Srobbin static char *tzp = NULL; 2527c478bd9Sstevel@tonic-gate 25380868c53Srobbin (void) unsetenv("TZ"); 25480868c53Srobbin if (tzp != NULL) 25580868c53Srobbin free(tzp); 25680868c53Srobbin if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) { 25780868c53Srobbin perror(progname); 25880868c53Srobbin exit(EXIT_FAILURE); 25980868c53Srobbin } 26080868c53Srobbin (void) strcpy(tzp, "TZ="); 26180868c53Srobbin (void) strcat(tzp, argv[i]); 26280868c53Srobbin if (putenv(tzp) != 0) { 26380868c53Srobbin perror(progname); 26480868c53Srobbin exit(EXIT_FAILURE); 26580868c53Srobbin } 2667c478bd9Sstevel@tonic-gate if (!vflag) { 2677c478bd9Sstevel@tonic-gate show(argv[i], now, FALSE); 2687c478bd9Sstevel@tonic-gate continue; 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate #if defined(sun) 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * We show the current time first, probably because we froze 2747c478bd9Sstevel@tonic-gate * the behavior of zdump some time ago and then it got 2757c478bd9Sstevel@tonic-gate * changed. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate show(argv[i], now, TRUE); 2787c478bd9Sstevel@tonic-gate #endif 27980868c53Srobbin warned = FALSE; 28080868c53Srobbin t = absolute_min_time; 2817c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 2827c478bd9Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 2837c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 28480868c53Srobbin if (t < cutlotime) 28580868c53Srobbin t = cutlotime; 28680868c53Srobbin tmp = my_localtime(&t); 28780868c53Srobbin if (tmp != NULL) { 28880868c53Srobbin tm = *tmp; 28980868c53Srobbin (void) strncpy(buf, abbr(&tm), sizeof (buf) - 1); 29080868c53Srobbin } 2917c478bd9Sstevel@tonic-gate for (;;) { 29280868c53Srobbin if (t >= cuthitime) 2937c478bd9Sstevel@tonic-gate break; 294292f4c1cSrobbin /* check if newt will overrun maximum time_t value */ 295292f4c1cSrobbin if (t > LONG_MAX - (SECSPERHOUR * 12)) 296292f4c1cSrobbin break; 2977c478bd9Sstevel@tonic-gate newt = t + SECSPERHOUR * 12; 29880868c53Srobbin if (newt >= cuthitime) 2997c478bd9Sstevel@tonic-gate break; 30080868c53Srobbin newtmp = localtime(&newt); 30180868c53Srobbin if (newtmp != NULL) 30280868c53Srobbin newtm = *newtmp; 30380868c53Srobbin if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 30480868c53Srobbin (delta(&newtm, &tm) != (newt - t) || 3057c478bd9Sstevel@tonic-gate newtm.tm_isdst != tm.tm_isdst || 30680868c53Srobbin strcmp(abbr(&newtm), buf) != 0)) { 3077c478bd9Sstevel@tonic-gate newt = hunt(argv[i], t, newt); 30880868c53Srobbin newtmp = localtime(&newt); 30980868c53Srobbin if (newtmp != NULL) { 31080868c53Srobbin newtm = *newtmp; 31180868c53Srobbin (void) strncpy(buf, 31280868c53Srobbin abbr(&newtm), 31380868c53Srobbin sizeof (buf) - 1); 31480868c53Srobbin } 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate t = newt; 3177c478bd9Sstevel@tonic-gate tm = newtm; 31880868c53Srobbin tmp = newtmp; 3197c478bd9Sstevel@tonic-gate } 32080868c53Srobbin t = absolute_max_time; 3217c478bd9Sstevel@tonic-gate #if defined(sun) 3227c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3237c478bd9Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3247c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3257c478bd9Sstevel@tonic-gate #else /* !defined(sun) */ 3267c478bd9Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3277c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3287c478bd9Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 3297c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3307c478bd9Sstevel@tonic-gate #endif /* !defined(sun) */ 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate if (fflush(stdout) || ferror(stdout)) { 33380868c53Srobbin (void) fprintf(stderr, "%s: ", progname); 33480868c53Srobbin (void) perror(gettext("Error writing standard output")); 33580868c53Srobbin exit(EXIT_FAILURE); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate return (EXIT_SUCCESS); 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 34080868c53Srobbin static void 34180868c53Srobbin setabsolutes() 34280868c53Srobbin { 34380868c53Srobbin #if defined(sun) 34480868c53Srobbin absolute_min_time = LONG_MIN; 34580868c53Srobbin absolute_max_time = LONG_MAX; 34680868c53Srobbin #else 34780868c53Srobbin if (0.5 == (time_t)0.5) { 34880868c53Srobbin /* 34980868c53Srobbin * time_t is floating. 35080868c53Srobbin */ 35180868c53Srobbin if (sizeof (time_t) == sizeof (float)) { 35280868c53Srobbin absolute_min_time = (time_t)-FLT_MAX; 35380868c53Srobbin absolute_max_time = (time_t)FLT_MAX; 35480868c53Srobbin } else if (sizeof (time_t) == sizeof (double)) { 35580868c53Srobbin absolute_min_time = (time_t)-DBL_MAX; 35680868c53Srobbin absolute_max_time = (time_t)DBL_MAX; 35780868c53Srobbin } else { 35880868c53Srobbin (void) fprintf(stderr, gettext("%s: use of -v on " 35980868c53Srobbin "system with floating time_t other than float " 36080868c53Srobbin "or double\n"), progname); 36180868c53Srobbin exit(EXIT_FAILURE); 36280868c53Srobbin } 36380868c53Srobbin } else 36480868c53Srobbin /*CONSTANTCONDITION*/ 36580868c53Srobbin if (0 > (time_t)-1) { 36680868c53Srobbin /* 36780868c53Srobbin * time_t is signed. 36880868c53Srobbin */ 36980868c53Srobbin register time_t hibit; 37080868c53Srobbin 37180868c53Srobbin for (hibit = 1; (hibit * 2) != 0; hibit *= 2) 37280868c53Srobbin continue; 37380868c53Srobbin absolute_min_time = hibit; 37480868c53Srobbin absolute_max_time = -(hibit + 1); 37580868c53Srobbin } else { 37680868c53Srobbin /* 37780868c53Srobbin * time_t is unsigned. 37880868c53Srobbin */ 37980868c53Srobbin absolute_min_time = 0; 38080868c53Srobbin absolute_max_time = absolute_min_time - 1; 38180868c53Srobbin } 38280868c53Srobbin #endif 38380868c53Srobbin } 38480868c53Srobbin 38580868c53Srobbin static time_t 38680868c53Srobbin yeartot(y) 38780868c53Srobbin const long y; 38880868c53Srobbin { 38980868c53Srobbin register long myy; 39080868c53Srobbin register long seconds; 39180868c53Srobbin register time_t t; 39280868c53Srobbin 39380868c53Srobbin myy = EPOCH_YEAR; 39480868c53Srobbin t = 0; 39580868c53Srobbin while (myy != y) { 39680868c53Srobbin if (myy < y) { 39780868c53Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 39880868c53Srobbin ++myy; 39980868c53Srobbin if (t > absolute_max_time - seconds) { 40080868c53Srobbin t = absolute_max_time; 40180868c53Srobbin break; 40280868c53Srobbin } 40380868c53Srobbin t += seconds; 40480868c53Srobbin } else { 40580868c53Srobbin --myy; 40680868c53Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 40780868c53Srobbin if (t < absolute_min_time + seconds) { 40880868c53Srobbin t = absolute_min_time; 40980868c53Srobbin break; 41080868c53Srobbin } 41180868c53Srobbin t -= seconds; 41280868c53Srobbin } 41380868c53Srobbin } 41480868c53Srobbin return (t); 41580868c53Srobbin } 41680868c53Srobbin 4177c478bd9Sstevel@tonic-gate static time_t 4187c478bd9Sstevel@tonic-gate hunt(name, lot, hit) 4197c478bd9Sstevel@tonic-gate char *name; 4207c478bd9Sstevel@tonic-gate time_t lot; 4217c478bd9Sstevel@tonic-gate time_t hit; 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate time_t t; 42480868c53Srobbin long diff; 4257c478bd9Sstevel@tonic-gate struct tm lotm; 42680868c53Srobbin register struct tm *lotmp; 4277c478bd9Sstevel@tonic-gate struct tm tm; 42880868c53Srobbin register struct tm *tmp; 42980868c53Srobbin char loab[MAX_STRING_LENGTH]; 4307c478bd9Sstevel@tonic-gate 43180868c53Srobbin lotmp = my_localtime(&lot); 43280868c53Srobbin if (lotmp != NULL) { 43380868c53Srobbin lotm = *lotmp; 43480868c53Srobbin (void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1); 43580868c53Srobbin } 43680868c53Srobbin for (;;) { 43780868c53Srobbin diff = (long)(hit - lot); 43880868c53Srobbin if (diff < 2) 43980868c53Srobbin break; 44080868c53Srobbin t = lot; 44180868c53Srobbin t += diff / 2; 4427c478bd9Sstevel@tonic-gate if (t <= lot) 4437c478bd9Sstevel@tonic-gate ++t; 4447c478bd9Sstevel@tonic-gate else if (t >= hit) 4457c478bd9Sstevel@tonic-gate --t; 44680868c53Srobbin tmp = my_localtime(&t); 44780868c53Srobbin if (tmp != NULL) 44880868c53Srobbin tm = *tmp; 44980868c53Srobbin if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : 45080868c53Srobbin (delta(&tm, &lotm) == (t - lot) && 4517c478bd9Sstevel@tonic-gate tm.tm_isdst == lotm.tm_isdst && 45280868c53Srobbin strcmp(abbr(&tm), loab) == 0)) { 4537c478bd9Sstevel@tonic-gate lot = t; 4547c478bd9Sstevel@tonic-gate lotm = tm; 45580868c53Srobbin lotmp = tmp; 4567c478bd9Sstevel@tonic-gate } else hit = t; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate show(name, lot, TRUE); 4597c478bd9Sstevel@tonic-gate show(name, hit, TRUE); 4607c478bd9Sstevel@tonic-gate return (hit); 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 464f430f59aSrobbin * Thanks to Paul Eggert for logic used in delta. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate static long 4687c478bd9Sstevel@tonic-gate delta(newp, oldp) 4697c478bd9Sstevel@tonic-gate struct tm *newp; 4707c478bd9Sstevel@tonic-gate struct tm *oldp; 4717c478bd9Sstevel@tonic-gate { 47280868c53Srobbin register long result; 47380868c53Srobbin register int tmy; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate if (newp->tm_year < oldp->tm_year) 4767c478bd9Sstevel@tonic-gate return (-delta(oldp, newp)); 4777c478bd9Sstevel@tonic-gate result = 0; 4787c478bd9Sstevel@tonic-gate for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 47980868c53Srobbin result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); 4807c478bd9Sstevel@tonic-gate result += newp->tm_yday - oldp->tm_yday; 4817c478bd9Sstevel@tonic-gate result *= HOURSPERDAY; 4827c478bd9Sstevel@tonic-gate result += newp->tm_hour - oldp->tm_hour; 4837c478bd9Sstevel@tonic-gate result *= MINSPERHOUR; 4847c478bd9Sstevel@tonic-gate result += newp->tm_min - oldp->tm_min; 4857c478bd9Sstevel@tonic-gate result *= SECSPERMIN; 4867c478bd9Sstevel@tonic-gate result += newp->tm_sec - oldp->tm_sec; 4877c478bd9Sstevel@tonic-gate return (result); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate static void 4917c478bd9Sstevel@tonic-gate show(zone, t, v) 4927c478bd9Sstevel@tonic-gate char *zone; 4937c478bd9Sstevel@tonic-gate time_t t; 4947c478bd9Sstevel@tonic-gate int v; 4957c478bd9Sstevel@tonic-gate { 49680868c53Srobbin register struct tm *tmp; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate (void) printf("%-*s ", (int)longest, zone); 49980868c53Srobbin if (v) { 50080868c53Srobbin tmp = gmtime(&t); 50180868c53Srobbin if (tmp == NULL) { 50280868c53Srobbin (void) printf(tformat(), t); 50380868c53Srobbin } else { 50480868c53Srobbin dumptime(tmp); 50580868c53Srobbin (void) printf(" UTC"); 50680868c53Srobbin } 50780868c53Srobbin (void) printf(" = "); 50880868c53Srobbin } 50980868c53Srobbin tmp = my_localtime(&t); 51080868c53Srobbin dumptime(tmp); 51180868c53Srobbin if (tmp != NULL) { 5127c478bd9Sstevel@tonic-gate if (*abbr(tmp) != '\0') 5137c478bd9Sstevel@tonic-gate (void) printf(" %s", abbr(tmp)); 5147c478bd9Sstevel@tonic-gate if (v) { 5157c478bd9Sstevel@tonic-gate (void) printf(" isdst=%d", tmp->tm_isdst); 51680868c53Srobbin #ifdef TM_GMTOFF 51780868c53Srobbin (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 51880868c53Srobbin #endif /* defined TM_GMTOFF */ 51980868c53Srobbin } 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate (void) printf("\n"); 52280868c53Srobbin if (tmp != NULL && *abbr(tmp) != '\0') 52380868c53Srobbin abbrok(abbr(tmp), zone); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate static char * 5277c478bd9Sstevel@tonic-gate abbr(tmp) 5287c478bd9Sstevel@tonic-gate struct tm *tmp; 5297c478bd9Sstevel@tonic-gate { 5307c478bd9Sstevel@tonic-gate register char *result; 5317c478bd9Sstevel@tonic-gate static char nada; 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 5347c478bd9Sstevel@tonic-gate return (&nada); 5357c478bd9Sstevel@tonic-gate result = tzname[tmp->tm_isdst]; 5367c478bd9Sstevel@tonic-gate return ((result == NULL) ? &nada : result); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 53980868c53Srobbin /* 54080868c53Srobbin * The code below can fail on certain theoretical systems; 54180868c53Srobbin * it works on all known real-world systems as of 2004-12-30. 54280868c53Srobbin */ 54380868c53Srobbin 54480868c53Srobbin static const char * 54580868c53Srobbin tformat() 54680868c53Srobbin { 54780868c53Srobbin #if defined(sun) 54880868c53Srobbin /* time_t is signed long */ 54980868c53Srobbin return ("%ld"); 55080868c53Srobbin #else 55180868c53Srobbin /*CONSTANTCONDITION*/ 55280868c53Srobbin if (0.5 == (time_t)0.5) { /* floating */ 55380868c53Srobbin /*CONSTANTCONDITION*/ 55480868c53Srobbin if (sizeof (time_t) > sizeof (double)) 55580868c53Srobbin return ("%Lg"); 55680868c53Srobbin return ("%g"); 55780868c53Srobbin } 55880868c53Srobbin /*CONSTANTCONDITION*/ 55980868c53Srobbin if (0 > (time_t)-1) { /* signed */ 56080868c53Srobbin /*CONSTANTCONDITION*/ 56180868c53Srobbin if (sizeof (time_t) > sizeof (long)) 56280868c53Srobbin return ("%lld"); 56380868c53Srobbin /*CONSTANTCONDITION*/ 56480868c53Srobbin if (sizeof (time_t) > sizeof (int)) 56580868c53Srobbin return ("%ld"); 56680868c53Srobbin return ("%d"); 56780868c53Srobbin } 56880868c53Srobbin /*CONSTANTCONDITION*/ 56980868c53Srobbin if (sizeof (time_t) > sizeof (unsigned long)) 57080868c53Srobbin return ("%llu"); 57180868c53Srobbin /*CONSTANTCONDITION*/ 57280868c53Srobbin if (sizeof (time_t) > sizeof (unsigned int)) 57380868c53Srobbin return ("%lu"); 57480868c53Srobbin return ("%u"); 57580868c53Srobbin #endif 57680868c53Srobbin } 57780868c53Srobbin 5787c478bd9Sstevel@tonic-gate static void 57980868c53Srobbin dumptime(timeptr) 58080868c53Srobbin register const struct tm *timeptr; 58180868c53Srobbin { 58280868c53Srobbin static const char wday_name[][3] = { 58380868c53Srobbin "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 58480868c53Srobbin }; 58580868c53Srobbin static const char mon_name[][3] = { 58680868c53Srobbin "Jan", "Feb", "Mar", "Apr", "May", "Jun", 58780868c53Srobbin "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 58880868c53Srobbin }; 58980868c53Srobbin register const char *wn; 59080868c53Srobbin register const char *mn; 59180868c53Srobbin register int lead; 59280868c53Srobbin register int trail; 59380868c53Srobbin 59480868c53Srobbin if (timeptr == NULL) { 59580868c53Srobbin (void) printf("NULL"); 59680868c53Srobbin return; 59780868c53Srobbin } 59880868c53Srobbin /* 59980868c53Srobbin * The packaged versions of localtime and gmtime never put out-of-range 60080868c53Srobbin * values in tm_wday or tm_mon, but since this code might be compiled 60180868c53Srobbin * with other (perhaps experimental) versions, paranoia is in order. 60280868c53Srobbin */ 60380868c53Srobbin if (timeptr->tm_wday < 0 || timeptr->tm_wday >= 60480868c53Srobbin (int)(sizeof (wday_name) / sizeof (wday_name[0]))) 60580868c53Srobbin wn = "???"; 60680868c53Srobbin else wn = wday_name[timeptr->tm_wday]; 60780868c53Srobbin if (timeptr->tm_mon < 0 || timeptr->tm_mon >= 60880868c53Srobbin (int)(sizeof (mon_name) / sizeof (mon_name[0]))) 60980868c53Srobbin mn = "???"; 61080868c53Srobbin else mn = mon_name[timeptr->tm_mon]; 61180868c53Srobbin (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", 61280868c53Srobbin wn, mn, 61380868c53Srobbin timeptr->tm_mday, timeptr->tm_hour, 61480868c53Srobbin timeptr->tm_min, timeptr->tm_sec); 61580868c53Srobbin #define DIVISOR 10 61680868c53Srobbin trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; 61780868c53Srobbin lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + 61880868c53Srobbin trail / DIVISOR; 61980868c53Srobbin trail %= DIVISOR; 62080868c53Srobbin if (trail < 0 && lead > 0) { 62180868c53Srobbin trail += DIVISOR; 62280868c53Srobbin --lead; 62380868c53Srobbin } else if (lead < 0 && trail > 0) { 62480868c53Srobbin trail -= DIVISOR; 62580868c53Srobbin ++lead; 62680868c53Srobbin } 62780868c53Srobbin if (lead == 0) 62880868c53Srobbin (void) printf("%d", trail); 62980868c53Srobbin else 63080868c53Srobbin (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); 63180868c53Srobbin } 63280868c53Srobbin 63380868c53Srobbin static void 63480868c53Srobbin usage() 6357c478bd9Sstevel@tonic-gate { 6367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 63780868c53Srobbin "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), 63880868c53Srobbin progname); 63980868c53Srobbin exit(EXIT_FAILURE); 6407c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6417c478bd9Sstevel@tonic-gate } 642