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 680868c53Srobbin #pragma ident "%Z%%M% %I% %E% SMI" 780868c53Srobbin 87c478bd9Sstevel@tonic-gate /* 97c478bd9Sstevel@tonic-gate * zdump 7.24 107c478bd9Sstevel@tonic-gate * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump, 117c478bd9Sstevel@tonic-gate * which was based on an earlier version of the elsie code. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * For zdump 7.24, the following changes were made to the elsie code: 147c478bd9Sstevel@tonic-gate * locale/textdomain/messages to match existing Solaris style. 157c478bd9Sstevel@tonic-gate * Solaris verbose mode is documented to display the current time first. 167c478bd9Sstevel@tonic-gate * cstyle cleaned code. 177c478bd9Sstevel@tonic-gate * removed old locale/textdomain code. 187c478bd9Sstevel@tonic-gate */ 197c478bd9Sstevel@tonic-gate 20f430f59aSrobbin static char elsieid[] = "@(#)zdump.c 7.74"; 217c478bd9Sstevel@tonic-gate 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * This code has been made independent of the rest of the time 247c478bd9Sstevel@tonic-gate * conversion package to increase confidence in the verification it provides. 257c478bd9Sstevel@tonic-gate * You can use this code to help in verifying other implementations. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include "stdio.h" /* for stdout, stderr, perror */ 297c478bd9Sstevel@tonic-gate #include "string.h" /* for strcpy */ 307c478bd9Sstevel@tonic-gate #include "sys/types.h" /* for time_t */ 317c478bd9Sstevel@tonic-gate #include "time.h" /* for struct tm */ 327c478bd9Sstevel@tonic-gate #include "stdlib.h" /* for exit, malloc, atoi */ 337c478bd9Sstevel@tonic-gate #include "locale.h" /* for setlocale, textdomain */ 347c478bd9Sstevel@tonic-gate #include "libintl.h" 3580868c53Srobbin #include <ctype.h> 367c478bd9Sstevel@tonic-gate #include "tzfile.h" /* for defines */ 3780868c53Srobbin #include <limits.h> 3880868c53Srobbin 3980868c53Srobbin #ifndef ZDUMP_LO_YEAR 4080868c53Srobbin #define ZDUMP_LO_YEAR (-500) 4180868c53Srobbin #endif /* !defined ZDUMP_LO_YEAR */ 4280868c53Srobbin 4380868c53Srobbin #ifndef ZDUMP_HI_YEAR 4480868c53Srobbin #define ZDUMP_HI_YEAR 2500 4580868c53Srobbin #endif /* !defined ZDUMP_HI_YEAR */ 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH 487c478bd9Sstevel@tonic-gate #define MAX_STRING_LENGTH 1024 497c478bd9Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */ 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate #ifndef TRUE 527c478bd9Sstevel@tonic-gate #define TRUE 1 537c478bd9Sstevel@tonic-gate #endif /* !defined TRUE */ 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #ifndef FALSE 567c478bd9Sstevel@tonic-gate #define FALSE 0 577c478bd9Sstevel@tonic-gate #endif /* !defined FALSE */ 587c478bd9Sstevel@tonic-gate 5980868c53Srobbin #ifndef isleap_sum 6080868c53Srobbin /* 6180868c53Srobbin * See tzfile.h for details on isleap_sum. 6280868c53Srobbin */ 6380868c53Srobbin #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 6480868c53Srobbin #endif /* !defined isleap_sum */ 6580868c53Srobbin 6680868c53Srobbin #ifndef SECSPERDAY 6780868c53Srobbin #define SECSPERDAY ((long)SECSPERHOUR * HOURSPERDAY) 6880868c53Srobbin #endif 6980868c53Srobbin #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 7080868c53Srobbin #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 7180868c53Srobbin 7280868c53Srobbin #ifndef GNUC_or_lint 737c478bd9Sstevel@tonic-gate #ifdef lint 7480868c53Srobbin #define GNUC_or_lint 7580868c53Srobbin #else /* !defined lint */ 7680868c53Srobbin #ifdef __GNUC__ 7780868c53Srobbin #define GNUC_or_lint 7880868c53Srobbin #endif /* defined __GNUC__ */ 7980868c53Srobbin #endif /* !defined lint */ 8080868c53Srobbin #endif /* !defined GNUC_or_lint */ 8180868c53Srobbin 8280868c53Srobbin #ifndef INITIALIZE 8380868c53Srobbin #ifdef GNUC_or_lint 847c478bd9Sstevel@tonic-gate #define INITIALIZE(x) ((x) = 0) 8580868c53Srobbin #else /* !defined GNUC_or_lint */ 867c478bd9Sstevel@tonic-gate #define INITIALIZE(x) 8780868c53Srobbin #endif /* !defined GNUC_or_lint */ 887c478bd9Sstevel@tonic-gate #endif /* !defined INITIALIZE */ 897c478bd9Sstevel@tonic-gate 9080868c53Srobbin static time_t absolute_min_time; 9180868c53Srobbin static time_t absolute_max_time; 9280868c53Srobbin static size_t longest; 9380868c53Srobbin static char *progname; 9480868c53Srobbin static int warned; 957c478bd9Sstevel@tonic-gate 9680868c53Srobbin static char *abbr(struct tm *); 9780868c53Srobbin static void abbrok(const char *, const char *); 987c478bd9Sstevel@tonic-gate static long delta(struct tm *, struct tm *); 9980868c53Srobbin static void dumptime(const struct tm *); 1007c478bd9Sstevel@tonic-gate static time_t hunt(char *, time_t, time_t); 10180868c53Srobbin static void setabsolutes(void); 1027c478bd9Sstevel@tonic-gate static void show(char *, time_t, int); 10380868c53Srobbin static void usage(void); 10480868c53Srobbin static const char *tformat(void); 10580868c53Srobbin static time_t yeartot(long y); 10680868c53Srobbin 10780868c53Srobbin #ifndef TYPECHECK 10880868c53Srobbin #define my_localtime localtime 10980868c53Srobbin #else /* !defined TYPECHECK */ 11080868c53Srobbin static struct tm * 11180868c53Srobbin my_localtime(tp) 11280868c53Srobbin time_t *tp; 11380868c53Srobbin { 11480868c53Srobbin register struct tm *tmp; 11580868c53Srobbin 11680868c53Srobbin tmp = localtime(tp); 11780868c53Srobbin if (tp != NULL && tmp != NULL) { 11880868c53Srobbin struct tm tm; 11980868c53Srobbin register time_t t; 12080868c53Srobbin 12180868c53Srobbin tm = *tmp; 12280868c53Srobbin t = mktime(&tm); 12380868c53Srobbin if (t - *tp >= 1 || *tp - t >= 1) { 12480868c53Srobbin (void) fflush(stdout); 12580868c53Srobbin (void) fprintf(stderr, "\n%s: ", progname); 12680868c53Srobbin (void) fprintf(stderr, tformat(), *tp); 12780868c53Srobbin (void) fprintf(stderr, " ->"); 12880868c53Srobbin (void) fprintf(stderr, " year=%d", tmp->tm_year); 12980868c53Srobbin (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 13080868c53Srobbin (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 13180868c53Srobbin (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 13280868c53Srobbin (void) fprintf(stderr, " min=%d", tmp->tm_min); 13380868c53Srobbin (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 13480868c53Srobbin (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 13580868c53Srobbin (void) fprintf(stderr, " -> "); 13680868c53Srobbin (void) fprintf(stderr, tformat(), t); 13780868c53Srobbin (void) fprintf(stderr, "\n"); 13880868c53Srobbin } 13980868c53Srobbin } 14080868c53Srobbin return (tmp); 14180868c53Srobbin } 14280868c53Srobbin #endif /* !defined TYPECHECK */ 14380868c53Srobbin 14480868c53Srobbin static void 14580868c53Srobbin abbrok(abbrp, zone) 14680868c53Srobbin const char * const abbrp; 14780868c53Srobbin const char * const zone; 14880868c53Srobbin { 14980868c53Srobbin register const char *cp; 15080868c53Srobbin int error = 0; 15180868c53Srobbin 15280868c53Srobbin if (warned) 15380868c53Srobbin return; 15480868c53Srobbin cp = abbrp; 15580868c53Srobbin while (isascii(*cp) && isalpha((unsigned char)*cp)) 15680868c53Srobbin ++cp; 15780868c53Srobbin (void) fflush(stdout); 15880868c53Srobbin if (cp - abbrp == 0) { 15980868c53Srobbin /* 16080868c53Srobbin * TRANSLATION_NOTE 16180868c53Srobbin * The first %s prints for the program name (zdump), 16280868c53Srobbin * the second %s prints the timezone name, the third 16380868c53Srobbin * %s prints the timezone abbreviation (tzname[0] or 16480868c53Srobbin * tzname[1]). 16580868c53Srobbin */ 16680868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 16780868c53Srobbin "abbreviation \"%s\" lacks alphabetic at start\n"), 16880868c53Srobbin progname, zone, abbrp); 16980868c53Srobbin error = 1; 17080868c53Srobbin } else if (cp - abbrp < 3) { 17180868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 17280868c53Srobbin "abbreviation \"%s\" has fewer than 3 alphabetics\n"), 17380868c53Srobbin progname, zone, abbrp); 17480868c53Srobbin error = 1; 17580868c53Srobbin } else if (cp - abbrp > 6) { 17680868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 17780868c53Srobbin "abbreviation \"%s\" has more than 6 alphabetics\n"), 17880868c53Srobbin progname, zone, abbrp); 17980868c53Srobbin error = 1; 18080868c53Srobbin } 18180868c53Srobbin if (error == 0 && (*cp == '+' || *cp == '-')) { 18280868c53Srobbin ++cp; 18380868c53Srobbin if (isascii(*cp) && isdigit((unsigned char)*cp)) 18480868c53Srobbin if (*cp++ == '1' && *cp >= '0' && *cp <= '4') 18580868c53Srobbin ++cp; 186f430f59aSrobbin if (*cp != '\0') { 187f430f59aSrobbin (void) fprintf(stderr, gettext("%s: warning: " 188f430f59aSrobbin "zone \"%s\" abbreviation \"%s\" differs from " 189f430f59aSrobbin "POSIX standard\n"), progname, zone, abbrp); 190f430f59aSrobbin error = 1; 191f430f59aSrobbin } 19280868c53Srobbin } 19380868c53Srobbin if (error) 19480868c53Srobbin warned = TRUE; 19580868c53Srobbin } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate int 1987c478bd9Sstevel@tonic-gate main(argc, argv) 1997c478bd9Sstevel@tonic-gate int argc; 20080868c53Srobbin char *argv[]; 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate register int i; 2037c478bd9Sstevel@tonic-gate register int c; 2047c478bd9Sstevel@tonic-gate register int vflag; 20580868c53Srobbin register char *cutarg; 20680868c53Srobbin register long cutloyear = ZDUMP_LO_YEAR; 20780868c53Srobbin register long cuthiyear = ZDUMP_HI_YEAR; 20880868c53Srobbin register time_t cutlotime; 20980868c53Srobbin register time_t cuthitime; 2107c478bd9Sstevel@tonic-gate time_t now; 2117c478bd9Sstevel@tonic-gate time_t t; 2127c478bd9Sstevel@tonic-gate time_t newt; 2137c478bd9Sstevel@tonic-gate struct tm tm; 2147c478bd9Sstevel@tonic-gate struct tm newtm; 21580868c53Srobbin register struct tm *tmp; 21680868c53Srobbin register struct tm *newtmp; 2177c478bd9Sstevel@tonic-gate 21880868c53Srobbin INITIALIZE(cutlotime); 21980868c53Srobbin INITIALIZE(cuthitime); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2227c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 2237c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 2247c478bd9Sstevel@tonic-gate #endif 2257c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate progname = argv[0]; 22880868c53Srobbin for (i = 1; i < argc; ++i) 22980868c53Srobbin if (strcmp(argv[i], "--version") == 0) { 23080868c53Srobbin (void) printf("%s\n", elsieid); 23180868c53Srobbin exit(EXIT_SUCCESS); 23280868c53Srobbin } 2337c478bd9Sstevel@tonic-gate vflag = 0; 23480868c53Srobbin cutarg = NULL; 2357c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 2367c478bd9Sstevel@tonic-gate if (c == 'v') 2377c478bd9Sstevel@tonic-gate vflag = 1; 23880868c53Srobbin else cutarg = optarg; 2397c478bd9Sstevel@tonic-gate if (c != EOF || 2407c478bd9Sstevel@tonic-gate (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 24180868c53Srobbin usage(); 2427c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2437c478bd9Sstevel@tonic-gate } 24480868c53Srobbin if (vflag) { 24580868c53Srobbin if (cutarg != NULL) { 24680868c53Srobbin long lo; 24780868c53Srobbin long hi; 24880868c53Srobbin char dummy; 24980868c53Srobbin 25080868c53Srobbin if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { 25180868c53Srobbin cuthiyear = hi; 25280868c53Srobbin } else if (sscanf(cutarg, "%ld,%ld%c", 25380868c53Srobbin &lo, &hi, &dummy) == 2) { 25480868c53Srobbin cutloyear = lo; 25580868c53Srobbin cuthiyear = hi; 25680868c53Srobbin } else { 25780868c53Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"), 25880868c53Srobbin progname, cutarg); 25980868c53Srobbin exit(EXIT_FAILURE); 26080868c53Srobbin } 26180868c53Srobbin } 26280868c53Srobbin setabsolutes(); 26380868c53Srobbin cutlotime = yeartot(cutloyear); 26480868c53Srobbin cuthitime = yeartot(cuthiyear); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate (void) time(&now); 2677c478bd9Sstevel@tonic-gate longest = 0; 2687c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) 2697c478bd9Sstevel@tonic-gate if (strlen(argv[i]) > longest) 2707c478bd9Sstevel@tonic-gate longest = strlen(argv[i]); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) { 2737c478bd9Sstevel@tonic-gate static char buf[MAX_STRING_LENGTH]; 27480868c53Srobbin static char *tzp = NULL; 2757c478bd9Sstevel@tonic-gate 27680868c53Srobbin (void) unsetenv("TZ"); 27780868c53Srobbin if (tzp != NULL) 27880868c53Srobbin free(tzp); 27980868c53Srobbin if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) { 28080868c53Srobbin perror(progname); 28180868c53Srobbin exit(EXIT_FAILURE); 28280868c53Srobbin } 28380868c53Srobbin (void) strcpy(tzp, "TZ="); 28480868c53Srobbin (void) strcat(tzp, argv[i]); 28580868c53Srobbin if (putenv(tzp) != 0) { 28680868c53Srobbin perror(progname); 28780868c53Srobbin exit(EXIT_FAILURE); 28880868c53Srobbin } 2897c478bd9Sstevel@tonic-gate if (!vflag) { 2907c478bd9Sstevel@tonic-gate show(argv[i], now, FALSE); 2917c478bd9Sstevel@tonic-gate continue; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate #if defined(sun) 2957c478bd9Sstevel@tonic-gate /* 2967c478bd9Sstevel@tonic-gate * We show the current time first, probably because we froze 2977c478bd9Sstevel@tonic-gate * the behavior of zdump some time ago and then it got 2987c478bd9Sstevel@tonic-gate * changed. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate show(argv[i], now, TRUE); 3017c478bd9Sstevel@tonic-gate #endif 30280868c53Srobbin warned = FALSE; 30380868c53Srobbin t = absolute_min_time; 3047c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3057c478bd9Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 3067c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 30780868c53Srobbin if (t < cutlotime) 30880868c53Srobbin t = cutlotime; 30980868c53Srobbin tmp = my_localtime(&t); 31080868c53Srobbin if (tmp != NULL) { 31180868c53Srobbin tm = *tmp; 31280868c53Srobbin (void) strncpy(buf, abbr(&tm), sizeof (buf) - 1); 31380868c53Srobbin } 3147c478bd9Sstevel@tonic-gate for (;;) { 31580868c53Srobbin if (t >= cuthitime) 3167c478bd9Sstevel@tonic-gate break; 317*292f4c1cSrobbin /* check if newt will overrun maximum time_t value */ 318*292f4c1cSrobbin if (t > LONG_MAX - (SECSPERHOUR * 12)) 319*292f4c1cSrobbin break; 3207c478bd9Sstevel@tonic-gate newt = t + SECSPERHOUR * 12; 32180868c53Srobbin if (newt >= cuthitime) 3227c478bd9Sstevel@tonic-gate break; 32380868c53Srobbin newtmp = localtime(&newt); 32480868c53Srobbin if (newtmp != NULL) 32580868c53Srobbin newtm = *newtmp; 32680868c53Srobbin if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 32780868c53Srobbin (delta(&newtm, &tm) != (newt - t) || 3287c478bd9Sstevel@tonic-gate newtm.tm_isdst != tm.tm_isdst || 32980868c53Srobbin strcmp(abbr(&newtm), buf) != 0)) { 3307c478bd9Sstevel@tonic-gate newt = hunt(argv[i], t, newt); 33180868c53Srobbin newtmp = localtime(&newt); 33280868c53Srobbin if (newtmp != NULL) { 33380868c53Srobbin newtm = *newtmp; 33480868c53Srobbin (void) strncpy(buf, 33580868c53Srobbin abbr(&newtm), 33680868c53Srobbin sizeof (buf) - 1); 33780868c53Srobbin } 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate t = newt; 3407c478bd9Sstevel@tonic-gate tm = newtm; 34180868c53Srobbin tmp = newtmp; 3427c478bd9Sstevel@tonic-gate } 34380868c53Srobbin t = absolute_max_time; 3447c478bd9Sstevel@tonic-gate #if defined(sun) 3457c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3467c478bd9Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3477c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3487c478bd9Sstevel@tonic-gate #else /* !defined(sun) */ 3497c478bd9Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3507c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3517c478bd9Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 3527c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3537c478bd9Sstevel@tonic-gate #endif /* !defined(sun) */ 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate if (fflush(stdout) || ferror(stdout)) { 35680868c53Srobbin (void) fprintf(stderr, "%s: ", progname); 35780868c53Srobbin (void) perror(gettext("Error writing standard output")); 35880868c53Srobbin exit(EXIT_FAILURE); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate return (EXIT_SUCCESS); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 36380868c53Srobbin static void 36480868c53Srobbin setabsolutes() 36580868c53Srobbin { 36680868c53Srobbin #if defined(sun) 36780868c53Srobbin absolute_min_time = LONG_MIN; 36880868c53Srobbin absolute_max_time = LONG_MAX; 36980868c53Srobbin #else 37080868c53Srobbin if (0.5 == (time_t)0.5) { 37180868c53Srobbin /* 37280868c53Srobbin * time_t is floating. 37380868c53Srobbin */ 37480868c53Srobbin if (sizeof (time_t) == sizeof (float)) { 37580868c53Srobbin absolute_min_time = (time_t)-FLT_MAX; 37680868c53Srobbin absolute_max_time = (time_t)FLT_MAX; 37780868c53Srobbin } else if (sizeof (time_t) == sizeof (double)) { 37880868c53Srobbin absolute_min_time = (time_t)-DBL_MAX; 37980868c53Srobbin absolute_max_time = (time_t)DBL_MAX; 38080868c53Srobbin } else { 38180868c53Srobbin (void) fprintf(stderr, gettext("%s: use of -v on " 38280868c53Srobbin "system with floating time_t other than float " 38380868c53Srobbin "or double\n"), progname); 38480868c53Srobbin exit(EXIT_FAILURE); 38580868c53Srobbin } 38680868c53Srobbin } else 38780868c53Srobbin /*CONSTANTCONDITION*/ 38880868c53Srobbin if (0 > (time_t)-1) { 38980868c53Srobbin /* 39080868c53Srobbin * time_t is signed. 39180868c53Srobbin */ 39280868c53Srobbin register time_t hibit; 39380868c53Srobbin 39480868c53Srobbin for (hibit = 1; (hibit * 2) != 0; hibit *= 2) 39580868c53Srobbin continue; 39680868c53Srobbin absolute_min_time = hibit; 39780868c53Srobbin absolute_max_time = -(hibit + 1); 39880868c53Srobbin } else { 39980868c53Srobbin /* 40080868c53Srobbin * time_t is unsigned. 40180868c53Srobbin */ 40280868c53Srobbin absolute_min_time = 0; 40380868c53Srobbin absolute_max_time = absolute_min_time - 1; 40480868c53Srobbin } 40580868c53Srobbin #endif 40680868c53Srobbin } 40780868c53Srobbin 40880868c53Srobbin static time_t 40980868c53Srobbin yeartot(y) 41080868c53Srobbin const long y; 41180868c53Srobbin { 41280868c53Srobbin register long myy; 41380868c53Srobbin register long seconds; 41480868c53Srobbin register time_t t; 41580868c53Srobbin 41680868c53Srobbin myy = EPOCH_YEAR; 41780868c53Srobbin t = 0; 41880868c53Srobbin while (myy != y) { 41980868c53Srobbin if (myy < y) { 42080868c53Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 42180868c53Srobbin ++myy; 42280868c53Srobbin if (t > absolute_max_time - seconds) { 42380868c53Srobbin t = absolute_max_time; 42480868c53Srobbin break; 42580868c53Srobbin } 42680868c53Srobbin t += seconds; 42780868c53Srobbin } else { 42880868c53Srobbin --myy; 42980868c53Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 43080868c53Srobbin if (t < absolute_min_time + seconds) { 43180868c53Srobbin t = absolute_min_time; 43280868c53Srobbin break; 43380868c53Srobbin } 43480868c53Srobbin t -= seconds; 43580868c53Srobbin } 43680868c53Srobbin } 43780868c53Srobbin return (t); 43880868c53Srobbin } 43980868c53Srobbin 4407c478bd9Sstevel@tonic-gate static time_t 4417c478bd9Sstevel@tonic-gate hunt(name, lot, hit) 44280868c53Srobbin char *name; 4437c478bd9Sstevel@tonic-gate time_t lot; 4447c478bd9Sstevel@tonic-gate time_t hit; 4457c478bd9Sstevel@tonic-gate { 44680868c53Srobbin time_t t; 44780868c53Srobbin long diff; 44880868c53Srobbin struct tm lotm; 44980868c53Srobbin register struct tm *lotmp; 45080868c53Srobbin struct tm tm; 45180868c53Srobbin register struct tm *tmp; 45280868c53Srobbin char loab[MAX_STRING_LENGTH]; 45380868c53Srobbin 45480868c53Srobbin lotmp = my_localtime(&lot); 45580868c53Srobbin if (lotmp != NULL) { 45680868c53Srobbin lotm = *lotmp; 45780868c53Srobbin (void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1); 45880868c53Srobbin } 45980868c53Srobbin for (;;) { 46080868c53Srobbin diff = (long)(hit - lot); 46180868c53Srobbin if (diff < 2) 46280868c53Srobbin break; 46380868c53Srobbin t = lot; 46480868c53Srobbin t += diff / 2; 4657c478bd9Sstevel@tonic-gate if (t <= lot) 4667c478bd9Sstevel@tonic-gate ++t; 4677c478bd9Sstevel@tonic-gate else if (t >= hit) 4687c478bd9Sstevel@tonic-gate --t; 46980868c53Srobbin tmp = my_localtime(&t); 47080868c53Srobbin if (tmp != NULL) 47180868c53Srobbin tm = *tmp; 47280868c53Srobbin if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : 47380868c53Srobbin (delta(&tm, &lotm) == (t - lot) && 4747c478bd9Sstevel@tonic-gate tm.tm_isdst == lotm.tm_isdst && 47580868c53Srobbin strcmp(abbr(&tm), loab) == 0)) { 4767c478bd9Sstevel@tonic-gate lot = t; 4777c478bd9Sstevel@tonic-gate lotm = tm; 47880868c53Srobbin lotmp = tmp; 4797c478bd9Sstevel@tonic-gate } else hit = t; 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate show(name, lot, TRUE); 4827c478bd9Sstevel@tonic-gate show(name, hit, TRUE); 4837c478bd9Sstevel@tonic-gate return (hit); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 487f430f59aSrobbin * Thanks to Paul Eggert for logic used in delta. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate static long 4917c478bd9Sstevel@tonic-gate delta(newp, oldp) 49280868c53Srobbin struct tm *newp; 49380868c53Srobbin struct tm *oldp; 4947c478bd9Sstevel@tonic-gate { 49580868c53Srobbin register long result; 49680868c53Srobbin register int tmy; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate if (newp->tm_year < oldp->tm_year) 4997c478bd9Sstevel@tonic-gate return (-delta(oldp, newp)); 5007c478bd9Sstevel@tonic-gate result = 0; 5017c478bd9Sstevel@tonic-gate for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 50280868c53Srobbin result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); 5037c478bd9Sstevel@tonic-gate result += newp->tm_yday - oldp->tm_yday; 5047c478bd9Sstevel@tonic-gate result *= HOURSPERDAY; 5057c478bd9Sstevel@tonic-gate result += newp->tm_hour - oldp->tm_hour; 5067c478bd9Sstevel@tonic-gate result *= MINSPERHOUR; 5077c478bd9Sstevel@tonic-gate result += newp->tm_min - oldp->tm_min; 5087c478bd9Sstevel@tonic-gate result *= SECSPERMIN; 5097c478bd9Sstevel@tonic-gate result += newp->tm_sec - oldp->tm_sec; 5107c478bd9Sstevel@tonic-gate return (result); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate static void 5147c478bd9Sstevel@tonic-gate show(zone, t, v) 51580868c53Srobbin char *zone; 5167c478bd9Sstevel@tonic-gate time_t t; 5177c478bd9Sstevel@tonic-gate int v; 5187c478bd9Sstevel@tonic-gate { 51980868c53Srobbin register struct tm *tmp; 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate (void) printf("%-*s ", (int)longest, zone); 5227c478bd9Sstevel@tonic-gate if (v) { 52380868c53Srobbin tmp = gmtime(&t); 52480868c53Srobbin if (tmp == NULL) { 52580868c53Srobbin (void) printf(tformat(), t); 52680868c53Srobbin } else { 52780868c53Srobbin dumptime(tmp); 52880868c53Srobbin (void) printf(" UTC"); 52980868c53Srobbin } 53080868c53Srobbin (void) printf(" = "); 53180868c53Srobbin } 53280868c53Srobbin tmp = my_localtime(&t); 53380868c53Srobbin dumptime(tmp); 53480868c53Srobbin if (tmp != NULL) { 53580868c53Srobbin if (*abbr(tmp) != '\0') 53680868c53Srobbin (void) printf(" %s", abbr(tmp)); 53780868c53Srobbin if (v) { 53880868c53Srobbin (void) printf(" isdst=%d", tmp->tm_isdst); 53980868c53Srobbin #ifdef TM_GMTOFF 54080868c53Srobbin (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 54180868c53Srobbin #endif /* defined TM_GMTOFF */ 54280868c53Srobbin } 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate (void) printf("\n"); 54580868c53Srobbin if (tmp != NULL && *abbr(tmp) != '\0') 54680868c53Srobbin abbrok(abbr(tmp), zone); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate static char * 5507c478bd9Sstevel@tonic-gate abbr(tmp) 55180868c53Srobbin struct tm *tmp; 5527c478bd9Sstevel@tonic-gate { 55380868c53Srobbin register char *result; 5547c478bd9Sstevel@tonic-gate static char nada; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 5577c478bd9Sstevel@tonic-gate return (&nada); 5587c478bd9Sstevel@tonic-gate result = tzname[tmp->tm_isdst]; 5597c478bd9Sstevel@tonic-gate return ((result == NULL) ? &nada : result); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 56280868c53Srobbin /* 56380868c53Srobbin * The code below can fail on certain theoretical systems; 56480868c53Srobbin * it works on all known real-world systems as of 2004-12-30. 56580868c53Srobbin */ 56680868c53Srobbin 56780868c53Srobbin static const char * 56880868c53Srobbin tformat() 56980868c53Srobbin { 57080868c53Srobbin #if defined(sun) 57180868c53Srobbin /* time_t is signed long */ 57280868c53Srobbin return ("%ld"); 57380868c53Srobbin #else 57480868c53Srobbin /*CONSTANTCONDITION*/ 57580868c53Srobbin if (0.5 == (time_t)0.5) { /* floating */ 57680868c53Srobbin /*CONSTANTCONDITION*/ 57780868c53Srobbin if (sizeof (time_t) > sizeof (double)) 57880868c53Srobbin return ("%Lg"); 57980868c53Srobbin return ("%g"); 58080868c53Srobbin } 58180868c53Srobbin /*CONSTANTCONDITION*/ 58280868c53Srobbin if (0 > (time_t)-1) { /* signed */ 58380868c53Srobbin /*CONSTANTCONDITION*/ 58480868c53Srobbin if (sizeof (time_t) > sizeof (long)) 58580868c53Srobbin return ("%lld"); 58680868c53Srobbin /*CONSTANTCONDITION*/ 58780868c53Srobbin if (sizeof (time_t) > sizeof (int)) 58880868c53Srobbin return ("%ld"); 58980868c53Srobbin return ("%d"); 59080868c53Srobbin } 59180868c53Srobbin /*CONSTANTCONDITION*/ 59280868c53Srobbin if (sizeof (time_t) > sizeof (unsigned long)) 59380868c53Srobbin return ("%llu"); 59480868c53Srobbin /*CONSTANTCONDITION*/ 59580868c53Srobbin if (sizeof (time_t) > sizeof (unsigned int)) 59680868c53Srobbin return ("%lu"); 59780868c53Srobbin return ("%u"); 59880868c53Srobbin #endif 59980868c53Srobbin } 60080868c53Srobbin 60180868c53Srobbin static void 60280868c53Srobbin dumptime(timeptr) 60380868c53Srobbin register const struct tm *timeptr; 60480868c53Srobbin { 60580868c53Srobbin static const char wday_name[][3] = { 60680868c53Srobbin "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 60780868c53Srobbin }; 60880868c53Srobbin static const char mon_name[][3] = { 60980868c53Srobbin "Jan", "Feb", "Mar", "Apr", "May", "Jun", 61080868c53Srobbin "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 61180868c53Srobbin }; 61280868c53Srobbin register const char *wn; 61380868c53Srobbin register const char *mn; 61480868c53Srobbin register int lead; 61580868c53Srobbin register int trail; 61680868c53Srobbin 61780868c53Srobbin if (timeptr == NULL) { 61880868c53Srobbin (void) printf("NULL"); 61980868c53Srobbin return; 62080868c53Srobbin } 62180868c53Srobbin /* 62280868c53Srobbin * The packaged versions of localtime and gmtime never put out-of-range 62380868c53Srobbin * values in tm_wday or tm_mon, but since this code might be compiled 62480868c53Srobbin * with other (perhaps experimental) versions, paranoia is in order. 62580868c53Srobbin */ 62680868c53Srobbin if (timeptr->tm_wday < 0 || timeptr->tm_wday >= 62780868c53Srobbin (int)(sizeof (wday_name) / sizeof (wday_name[0]))) 62880868c53Srobbin wn = "???"; 62980868c53Srobbin else wn = wday_name[timeptr->tm_wday]; 63080868c53Srobbin if (timeptr->tm_mon < 0 || timeptr->tm_mon >= 63180868c53Srobbin (int)(sizeof (mon_name) / sizeof (mon_name[0]))) 63280868c53Srobbin mn = "???"; 63380868c53Srobbin else mn = mon_name[timeptr->tm_mon]; 63480868c53Srobbin (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", 63580868c53Srobbin wn, mn, 63680868c53Srobbin timeptr->tm_mday, timeptr->tm_hour, 63780868c53Srobbin timeptr->tm_min, timeptr->tm_sec); 63880868c53Srobbin #define DIVISOR 10 63980868c53Srobbin trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; 64080868c53Srobbin lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + 64180868c53Srobbin trail / DIVISOR; 64280868c53Srobbin trail %= DIVISOR; 64380868c53Srobbin if (trail < 0 && lead > 0) { 64480868c53Srobbin trail += DIVISOR; 64580868c53Srobbin --lead; 64680868c53Srobbin } else if (lead < 0 && trail > 0) { 64780868c53Srobbin trail -= DIVISOR; 64880868c53Srobbin ++lead; 64980868c53Srobbin } 65080868c53Srobbin if (lead == 0) 65180868c53Srobbin (void) printf("%d", trail); 65280868c53Srobbin else 65380868c53Srobbin (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); 65480868c53Srobbin } 65580868c53Srobbin 6567c478bd9Sstevel@tonic-gate static void 65780868c53Srobbin usage() 6587c478bd9Sstevel@tonic-gate { 6597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 66080868c53Srobbin "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), 66180868c53Srobbin progname); 66280868c53Srobbin exit(EXIT_FAILURE); 6637c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6647c478bd9Sstevel@tonic-gate } 665