10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*1138Srobbin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 27*1138Srobbin #pragma ident "%Z%%M% %I% %E% SMI" 28*1138Srobbin 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * zdump 7.24 310Sstevel@tonic-gate * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump, 320Sstevel@tonic-gate * which was based on an earlier version of the elsie code. 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * For zdump 7.24, the following changes were made to the elsie code: 350Sstevel@tonic-gate * locale/textdomain/messages to match existing Solaris style. 360Sstevel@tonic-gate * Solaris verbose mode is documented to display the current time first. 370Sstevel@tonic-gate * cstyle cleaned code. 380Sstevel@tonic-gate * removed old locale/textdomain code. 390Sstevel@tonic-gate */ 400Sstevel@tonic-gate 41*1138Srobbin static char elsieid[] = "@(#)zdump.c 7.68"; 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * This code has been made independent of the rest of the time 450Sstevel@tonic-gate * conversion package to increase confidence in the verification it provides. 460Sstevel@tonic-gate * You can use this code to help in verifying other implementations. 470Sstevel@tonic-gate */ 480Sstevel@tonic-gate 490Sstevel@tonic-gate #include "stdio.h" /* for stdout, stderr, perror */ 500Sstevel@tonic-gate #include "string.h" /* for strcpy */ 510Sstevel@tonic-gate #include "sys/types.h" /* for time_t */ 520Sstevel@tonic-gate #include "time.h" /* for struct tm */ 530Sstevel@tonic-gate #include "stdlib.h" /* for exit, malloc, atoi */ 540Sstevel@tonic-gate #include "locale.h" /* for setlocale, textdomain */ 550Sstevel@tonic-gate #include "libintl.h" 56*1138Srobbin #include <ctype.h> 570Sstevel@tonic-gate #include "tzfile.h" /* for defines */ 58*1138Srobbin #include <limits.h> 59*1138Srobbin 60*1138Srobbin #ifndef ZDUMP_LO_YEAR 61*1138Srobbin #define ZDUMP_LO_YEAR (-500) 62*1138Srobbin #endif /* !defined ZDUMP_LO_YEAR */ 63*1138Srobbin 64*1138Srobbin #ifndef ZDUMP_HI_YEAR 65*1138Srobbin #define ZDUMP_HI_YEAR 2500 66*1138Srobbin #endif /* !defined ZDUMP_HI_YEAR */ 670Sstevel@tonic-gate 680Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH 690Sstevel@tonic-gate #define MAX_STRING_LENGTH 1024 700Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */ 710Sstevel@tonic-gate 720Sstevel@tonic-gate #ifndef TRUE 730Sstevel@tonic-gate #define TRUE 1 740Sstevel@tonic-gate #endif /* !defined TRUE */ 750Sstevel@tonic-gate 760Sstevel@tonic-gate #ifndef FALSE 770Sstevel@tonic-gate #define FALSE 0 780Sstevel@tonic-gate #endif /* !defined FALSE */ 790Sstevel@tonic-gate 80*1138Srobbin #ifndef isleap_sum 81*1138Srobbin /* 82*1138Srobbin * See tzfile.h for details on isleap_sum. 83*1138Srobbin */ 84*1138Srobbin #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 85*1138Srobbin #endif /* !defined isleap_sum */ 86*1138Srobbin 87*1138Srobbin #ifndef SECSPERDAY 88*1138Srobbin #define SECSPERDAY ((long)SECSPERHOUR * HOURSPERDAY) 89*1138Srobbin #endif 90*1138Srobbin #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 91*1138Srobbin #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 92*1138Srobbin 93*1138Srobbin #ifndef GNUC_or_lint 94*1138Srobbin #ifdef lint 95*1138Srobbin #define GNUC_or_lint 96*1138Srobbin #else /* !defined lint */ 97*1138Srobbin #ifdef __GNUC__ 98*1138Srobbin #define GNUC_or_lint 99*1138Srobbin #endif /* defined __GNUC__ */ 100*1138Srobbin #endif /* !defined lint */ 101*1138Srobbin #endif /* !defined GNUC_or_lint */ 102*1138Srobbin 1030Sstevel@tonic-gate #ifndef INITIALIZE 104*1138Srobbin #ifdef GNUC_or_lint 1050Sstevel@tonic-gate #define INITIALIZE(x) ((x) = 0) 106*1138Srobbin #else /* !defined GNUC_or_lint */ 1070Sstevel@tonic-gate #define INITIALIZE(x) 108*1138Srobbin #endif /* !defined GNUC_or_lint */ 1090Sstevel@tonic-gate #endif /* !defined INITIALIZE */ 1100Sstevel@tonic-gate 111*1138Srobbin static time_t absolute_min_time; 112*1138Srobbin static time_t absolute_max_time; 113*1138Srobbin static size_t longest; 114*1138Srobbin static char *progname; 115*1138Srobbin static int warned; 1160Sstevel@tonic-gate 117*1138Srobbin static char *abbr(struct tm *); 118*1138Srobbin static void abbrok(const char *, const char *); 1190Sstevel@tonic-gate static long delta(struct tm *, struct tm *); 120*1138Srobbin static void dumptime(const struct tm *); 1210Sstevel@tonic-gate static time_t hunt(char *, time_t, time_t); 122*1138Srobbin static void setabsolutes(void); 1230Sstevel@tonic-gate static void show(char *, time_t, int); 124*1138Srobbin static void usage(void); 125*1138Srobbin static const char *tformat(void); 126*1138Srobbin static time_t yeartot(long y); 127*1138Srobbin 128*1138Srobbin #ifndef TYPECHECK 129*1138Srobbin #define my_localtime localtime 130*1138Srobbin #else /* !defined TYPECHECK */ 131*1138Srobbin static struct tm * 132*1138Srobbin my_localtime(tp) 133*1138Srobbin time_t *tp; 134*1138Srobbin { 135*1138Srobbin register struct tm *tmp; 136*1138Srobbin 137*1138Srobbin tmp = localtime(tp); 138*1138Srobbin if (tp != NULL && tmp != NULL) { 139*1138Srobbin struct tm tm; 140*1138Srobbin register time_t t; 141*1138Srobbin 142*1138Srobbin tm = *tmp; 143*1138Srobbin t = mktime(&tm); 144*1138Srobbin if (t - *tp >= 1 || *tp - t >= 1) { 145*1138Srobbin (void) fflush(stdout); 146*1138Srobbin (void) fprintf(stderr, "\n%s: ", progname); 147*1138Srobbin (void) fprintf(stderr, tformat(), *tp); 148*1138Srobbin (void) fprintf(stderr, " ->"); 149*1138Srobbin (void) fprintf(stderr, " year=%d", tmp->tm_year); 150*1138Srobbin (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 151*1138Srobbin (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 152*1138Srobbin (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 153*1138Srobbin (void) fprintf(stderr, " min=%d", tmp->tm_min); 154*1138Srobbin (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 155*1138Srobbin (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 156*1138Srobbin (void) fprintf(stderr, " -> "); 157*1138Srobbin (void) fprintf(stderr, tformat(), t); 158*1138Srobbin (void) fprintf(stderr, "\n"); 159*1138Srobbin } 160*1138Srobbin } 161*1138Srobbin return (tmp); 162*1138Srobbin } 163*1138Srobbin #endif /* !defined TYPECHECK */ 164*1138Srobbin 165*1138Srobbin static void 166*1138Srobbin abbrok(abbrp, zone) 167*1138Srobbin const char * const abbrp; 168*1138Srobbin const char * const zone; 169*1138Srobbin { 170*1138Srobbin register const char *cp; 171*1138Srobbin int error = 0; 172*1138Srobbin 173*1138Srobbin if (warned) 174*1138Srobbin return; 175*1138Srobbin cp = abbrp; 176*1138Srobbin while (isascii(*cp) && isalpha((unsigned char)*cp)) 177*1138Srobbin ++cp; 178*1138Srobbin (void) fflush(stdout); 179*1138Srobbin if (cp - abbrp == 0) { 180*1138Srobbin /* 181*1138Srobbin * TRANSLATION_NOTE 182*1138Srobbin * The first %s prints for the program name (zdump), 183*1138Srobbin * the second %s prints the timezone name, the third 184*1138Srobbin * %s prints the timezone abbreviation (tzname[0] or 185*1138Srobbin * tzname[1]). 186*1138Srobbin */ 187*1138Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 188*1138Srobbin "abbreviation \"%s\" lacks alphabetic at start\n"), 189*1138Srobbin progname, zone, abbrp); 190*1138Srobbin error = 1; 191*1138Srobbin } else if (cp - abbrp < 3) { 192*1138Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 193*1138Srobbin "abbreviation \"%s\" has fewer than 3 alphabetics\n"), 194*1138Srobbin progname, zone, abbrp); 195*1138Srobbin error = 1; 196*1138Srobbin } else if (cp - abbrp > 6) { 197*1138Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 198*1138Srobbin "abbreviation \"%s\" has more than 6 alphabetics\n"), 199*1138Srobbin progname, zone, abbrp); 200*1138Srobbin error = 1; 201*1138Srobbin } 202*1138Srobbin if (error == 0 && (*cp == '+' || *cp == '-')) { 203*1138Srobbin ++cp; 204*1138Srobbin if (isascii(*cp) && isdigit((unsigned char)*cp)) 205*1138Srobbin if (*cp++ == '1' && *cp >= '0' && *cp <= '4') 206*1138Srobbin ++cp; 207*1138Srobbin } 208*1138Srobbin if (error == 0 && *cp != '\0') { 209*1138Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 210*1138Srobbin "abbreviation \"%s\" differs from POSIX standard\n"), 211*1138Srobbin progname, zone, abbrp); 212*1138Srobbin error = 1; 213*1138Srobbin } 214*1138Srobbin if (error) 215*1138Srobbin warned = TRUE; 216*1138Srobbin } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate int 2190Sstevel@tonic-gate main(argc, argv) 2200Sstevel@tonic-gate int argc; 221*1138Srobbin char *argv[]; 2220Sstevel@tonic-gate { 2230Sstevel@tonic-gate register int i; 2240Sstevel@tonic-gate register int c; 2250Sstevel@tonic-gate register int vflag; 226*1138Srobbin register char *cutarg; 227*1138Srobbin register long cutloyear = ZDUMP_LO_YEAR; 228*1138Srobbin register long cuthiyear = ZDUMP_HI_YEAR; 229*1138Srobbin register time_t cutlotime; 230*1138Srobbin register time_t cuthitime; 2310Sstevel@tonic-gate time_t now; 2320Sstevel@tonic-gate time_t t; 2330Sstevel@tonic-gate time_t newt; 2340Sstevel@tonic-gate struct tm tm; 2350Sstevel@tonic-gate struct tm newtm; 236*1138Srobbin register struct tm *tmp; 237*1138Srobbin register struct tm *newtmp; 2380Sstevel@tonic-gate 239*1138Srobbin INITIALIZE(cutlotime); 240*1138Srobbin INITIALIZE(cuthitime); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2430Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 2440Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 2450Sstevel@tonic-gate #endif 2460Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate progname = argv[0]; 249*1138Srobbin for (i = 1; i < argc; ++i) 250*1138Srobbin if (strcmp(argv[i], "--version") == 0) { 251*1138Srobbin (void) printf("%s\n", elsieid); 252*1138Srobbin exit(EXIT_SUCCESS); 253*1138Srobbin } 2540Sstevel@tonic-gate vflag = 0; 255*1138Srobbin cutarg = NULL; 2560Sstevel@tonic-gate while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 2570Sstevel@tonic-gate if (c == 'v') 2580Sstevel@tonic-gate vflag = 1; 259*1138Srobbin else cutarg = optarg; 2600Sstevel@tonic-gate if (c != EOF || 2610Sstevel@tonic-gate (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 262*1138Srobbin usage(); 2630Sstevel@tonic-gate /* NOTREACHED */ 2640Sstevel@tonic-gate } 265*1138Srobbin if (vflag) { 266*1138Srobbin if (cutarg != NULL) { 267*1138Srobbin long lo; 268*1138Srobbin long hi; 269*1138Srobbin char dummy; 2700Sstevel@tonic-gate 271*1138Srobbin if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { 272*1138Srobbin cuthiyear = hi; 273*1138Srobbin } else if (sscanf(cutarg, "%ld,%ld%c", 274*1138Srobbin &lo, &hi, &dummy) == 2) { 275*1138Srobbin cutloyear = lo; 276*1138Srobbin cuthiyear = hi; 277*1138Srobbin } else { 278*1138Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"), 279*1138Srobbin progname, cutarg); 280*1138Srobbin exit(EXIT_FAILURE); 281*1138Srobbin } 282*1138Srobbin } 283*1138Srobbin setabsolutes(); 284*1138Srobbin cutlotime = yeartot(cutloyear); 285*1138Srobbin cuthitime = yeartot(cuthiyear); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate (void) time(&now); 2880Sstevel@tonic-gate longest = 0; 2890Sstevel@tonic-gate for (i = optind; i < argc; ++i) 2900Sstevel@tonic-gate if (strlen(argv[i]) > longest) 2910Sstevel@tonic-gate longest = strlen(argv[i]); 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate for (i = optind; i < argc; ++i) { 2940Sstevel@tonic-gate static char buf[MAX_STRING_LENGTH]; 295*1138Srobbin static char *tzp = NULL; 2960Sstevel@tonic-gate 297*1138Srobbin (void) unsetenv("TZ"); 298*1138Srobbin if (tzp != NULL) 299*1138Srobbin free(tzp); 300*1138Srobbin if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) { 301*1138Srobbin perror(progname); 302*1138Srobbin exit(EXIT_FAILURE); 303*1138Srobbin } 304*1138Srobbin (void) strcpy(tzp, "TZ="); 305*1138Srobbin (void) strcat(tzp, argv[i]); 306*1138Srobbin if (putenv(tzp) != 0) { 307*1138Srobbin perror(progname); 308*1138Srobbin exit(EXIT_FAILURE); 309*1138Srobbin } 3100Sstevel@tonic-gate if (!vflag) { 3110Sstevel@tonic-gate show(argv[i], now, FALSE); 3120Sstevel@tonic-gate continue; 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate #if defined(sun) 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * We show the current time first, probably because we froze 3180Sstevel@tonic-gate * the behavior of zdump some time ago and then it got 3190Sstevel@tonic-gate * changed. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate show(argv[i], now, TRUE); 3220Sstevel@tonic-gate #endif 323*1138Srobbin warned = FALSE; 324*1138Srobbin t = absolute_min_time; 3250Sstevel@tonic-gate show(argv[i], t, TRUE); 3260Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 3270Sstevel@tonic-gate show(argv[i], t, TRUE); 328*1138Srobbin if (t < cutlotime) 329*1138Srobbin t = cutlotime; 330*1138Srobbin tmp = my_localtime(&t); 331*1138Srobbin if (tmp != NULL) { 332*1138Srobbin tm = *tmp; 333*1138Srobbin (void) strncpy(buf, abbr(&tm), sizeof (buf) - 1); 334*1138Srobbin } 3350Sstevel@tonic-gate for (;;) { 336*1138Srobbin if (t >= cuthitime) 3370Sstevel@tonic-gate break; 3380Sstevel@tonic-gate newt = t + SECSPERHOUR * 12; 339*1138Srobbin if (newt >= cuthitime) 3400Sstevel@tonic-gate break; 3410Sstevel@tonic-gate if (newt <= t) 3420Sstevel@tonic-gate break; 343*1138Srobbin newtmp = localtime(&newt); 344*1138Srobbin if (newtmp != NULL) 345*1138Srobbin newtm = *newtmp; 346*1138Srobbin if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 347*1138Srobbin (delta(&newtm, &tm) != (newt - t) || 3480Sstevel@tonic-gate newtm.tm_isdst != tm.tm_isdst || 349*1138Srobbin strcmp(abbr(&newtm), buf) != 0)) { 3500Sstevel@tonic-gate newt = hunt(argv[i], t, newt); 351*1138Srobbin newtmp = localtime(&newt); 352*1138Srobbin if (newtmp != NULL) { 353*1138Srobbin newtm = *newtmp; 354*1138Srobbin (void) strncpy(buf, 355*1138Srobbin abbr(&newtm), 356*1138Srobbin sizeof (buf) - 1); 357*1138Srobbin } 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate t = newt; 3600Sstevel@tonic-gate tm = newtm; 361*1138Srobbin tmp = newtmp; 3620Sstevel@tonic-gate } 363*1138Srobbin t = absolute_max_time; 3640Sstevel@tonic-gate #if defined(sun) 3650Sstevel@tonic-gate show(argv[i], t, TRUE); 3660Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3670Sstevel@tonic-gate show(argv[i], t, TRUE); 3680Sstevel@tonic-gate #else /* !defined(sun) */ 3690Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3700Sstevel@tonic-gate show(argv[i], t, TRUE); 3710Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 3720Sstevel@tonic-gate show(argv[i], t, TRUE); 3730Sstevel@tonic-gate #endif /* !defined(sun) */ 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate if (fflush(stdout) || ferror(stdout)) { 376*1138Srobbin (void) fprintf(stderr, "%s: ", progname); 377*1138Srobbin (void) perror(gettext("Error writing standard output")); 378*1138Srobbin exit(EXIT_FAILURE); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate return (EXIT_SUCCESS); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 383*1138Srobbin static void 384*1138Srobbin setabsolutes() 385*1138Srobbin { 386*1138Srobbin #if defined(sun) 387*1138Srobbin absolute_min_time = LONG_MIN; 388*1138Srobbin absolute_max_time = LONG_MAX; 389*1138Srobbin #else 390*1138Srobbin if (0.5 == (time_t)0.5) { 391*1138Srobbin /* 392*1138Srobbin * time_t is floating. 393*1138Srobbin */ 394*1138Srobbin if (sizeof (time_t) == sizeof (float)) { 395*1138Srobbin absolute_min_time = (time_t)-FLT_MAX; 396*1138Srobbin absolute_max_time = (time_t)FLT_MAX; 397*1138Srobbin } else if (sizeof (time_t) == sizeof (double)) { 398*1138Srobbin absolute_min_time = (time_t)-DBL_MAX; 399*1138Srobbin absolute_max_time = (time_t)DBL_MAX; 400*1138Srobbin } else { 401*1138Srobbin (void) fprintf(stderr, gettext("%s: use of -v on " 402*1138Srobbin "system with floating time_t other than float " 403*1138Srobbin "or double\n"), progname); 404*1138Srobbin exit(EXIT_FAILURE); 405*1138Srobbin } 406*1138Srobbin } else 407*1138Srobbin /*CONSTANTCONDITION*/ 408*1138Srobbin if (0 > (time_t)-1) { 409*1138Srobbin /* 410*1138Srobbin * time_t is signed. 411*1138Srobbin */ 412*1138Srobbin register time_t hibit; 413*1138Srobbin 414*1138Srobbin for (hibit = 1; (hibit * 2) != 0; hibit *= 2) 415*1138Srobbin continue; 416*1138Srobbin absolute_min_time = hibit; 417*1138Srobbin absolute_max_time = -(hibit + 1); 418*1138Srobbin } else { 419*1138Srobbin /* 420*1138Srobbin * time_t is unsigned. 421*1138Srobbin */ 422*1138Srobbin absolute_min_time = 0; 423*1138Srobbin absolute_max_time = absolute_min_time - 1; 424*1138Srobbin } 425*1138Srobbin #endif 426*1138Srobbin } 427*1138Srobbin 428*1138Srobbin static time_t 429*1138Srobbin yeartot(y) 430*1138Srobbin const long y; 431*1138Srobbin { 432*1138Srobbin register long myy; 433*1138Srobbin register long seconds; 434*1138Srobbin register time_t t; 435*1138Srobbin 436*1138Srobbin myy = EPOCH_YEAR; 437*1138Srobbin t = 0; 438*1138Srobbin while (myy != y) { 439*1138Srobbin if (myy < y) { 440*1138Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 441*1138Srobbin ++myy; 442*1138Srobbin if (t > absolute_max_time - seconds) { 443*1138Srobbin t = absolute_max_time; 444*1138Srobbin break; 445*1138Srobbin } 446*1138Srobbin t += seconds; 447*1138Srobbin } else { 448*1138Srobbin --myy; 449*1138Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 450*1138Srobbin if (t < absolute_min_time + seconds) { 451*1138Srobbin t = absolute_min_time; 452*1138Srobbin break; 453*1138Srobbin } 454*1138Srobbin t -= seconds; 455*1138Srobbin } 456*1138Srobbin } 457*1138Srobbin return (t); 458*1138Srobbin } 459*1138Srobbin 4600Sstevel@tonic-gate static time_t 4610Sstevel@tonic-gate hunt(name, lot, hit) 462*1138Srobbin char *name; 4630Sstevel@tonic-gate time_t lot; 4640Sstevel@tonic-gate time_t hit; 4650Sstevel@tonic-gate { 466*1138Srobbin time_t t; 467*1138Srobbin long diff; 468*1138Srobbin struct tm lotm; 469*1138Srobbin register struct tm *lotmp; 470*1138Srobbin struct tm tm; 471*1138Srobbin register struct tm *tmp; 472*1138Srobbin char loab[MAX_STRING_LENGTH]; 4730Sstevel@tonic-gate 474*1138Srobbin lotmp = my_localtime(&lot); 475*1138Srobbin if (lotmp != NULL) { 476*1138Srobbin lotm = *lotmp; 477*1138Srobbin (void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1); 478*1138Srobbin } 479*1138Srobbin for (;;) { 480*1138Srobbin diff = (long)(hit - lot); 481*1138Srobbin if (diff < 2) 482*1138Srobbin break; 483*1138Srobbin t = lot; 484*1138Srobbin t += diff / 2; 4850Sstevel@tonic-gate if (t <= lot) 4860Sstevel@tonic-gate ++t; 4870Sstevel@tonic-gate else if (t >= hit) 4880Sstevel@tonic-gate --t; 489*1138Srobbin tmp = my_localtime(&t); 490*1138Srobbin if (tmp != NULL) 491*1138Srobbin tm = *tmp; 492*1138Srobbin if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : 493*1138Srobbin (delta(&tm, &lotm) == (t - lot) && 4940Sstevel@tonic-gate tm.tm_isdst == lotm.tm_isdst && 495*1138Srobbin strcmp(abbr(&tm), loab) == 0)) { 4960Sstevel@tonic-gate lot = t; 4970Sstevel@tonic-gate lotm = tm; 498*1138Srobbin lotmp = tmp; 4990Sstevel@tonic-gate } else hit = t; 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate show(name, lot, TRUE); 5020Sstevel@tonic-gate show(name, hit, TRUE); 5030Sstevel@tonic-gate return (hit); 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta. 5080Sstevel@tonic-gate */ 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate static long 5110Sstevel@tonic-gate delta(newp, oldp) 512*1138Srobbin struct tm *newp; 513*1138Srobbin struct tm *oldp; 5140Sstevel@tonic-gate { 515*1138Srobbin register long result; 516*1138Srobbin register int tmy; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate if (newp->tm_year < oldp->tm_year) 5190Sstevel@tonic-gate return (-delta(oldp, newp)); 5200Sstevel@tonic-gate result = 0; 5210Sstevel@tonic-gate for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 522*1138Srobbin result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); 5230Sstevel@tonic-gate result += newp->tm_yday - oldp->tm_yday; 5240Sstevel@tonic-gate result *= HOURSPERDAY; 5250Sstevel@tonic-gate result += newp->tm_hour - oldp->tm_hour; 5260Sstevel@tonic-gate result *= MINSPERHOUR; 5270Sstevel@tonic-gate result += newp->tm_min - oldp->tm_min; 5280Sstevel@tonic-gate result *= SECSPERMIN; 5290Sstevel@tonic-gate result += newp->tm_sec - oldp->tm_sec; 5300Sstevel@tonic-gate return (result); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate static void 5340Sstevel@tonic-gate show(zone, t, v) 535*1138Srobbin char *zone; 5360Sstevel@tonic-gate time_t t; 5370Sstevel@tonic-gate int v; 5380Sstevel@tonic-gate { 539*1138Srobbin register struct tm *tmp; 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate (void) printf("%-*s ", (int)longest, zone); 5420Sstevel@tonic-gate if (v) { 543*1138Srobbin tmp = gmtime(&t); 544*1138Srobbin if (tmp == NULL) { 545*1138Srobbin (void) printf(tformat(), t); 546*1138Srobbin } else { 547*1138Srobbin dumptime(tmp); 548*1138Srobbin (void) printf(" UTC"); 549*1138Srobbin } 550*1138Srobbin (void) printf(" = "); 551*1138Srobbin } 552*1138Srobbin tmp = my_localtime(&t); 553*1138Srobbin dumptime(tmp); 554*1138Srobbin if (tmp != NULL) { 555*1138Srobbin if (*abbr(tmp) != '\0') 556*1138Srobbin (void) printf(" %s", abbr(tmp)); 557*1138Srobbin if (v) { 558*1138Srobbin (void) printf(" isdst=%d", tmp->tm_isdst); 559*1138Srobbin #ifdef TM_GMTOFF 560*1138Srobbin (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 561*1138Srobbin #endif /* defined TM_GMTOFF */ 562*1138Srobbin } 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate (void) printf("\n"); 565*1138Srobbin if (tmp != NULL && *abbr(tmp) != '\0') 566*1138Srobbin abbrok(abbr(tmp), zone); 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate static char * 5700Sstevel@tonic-gate abbr(tmp) 571*1138Srobbin struct tm *tmp; 5720Sstevel@tonic-gate { 573*1138Srobbin register char *result; 5740Sstevel@tonic-gate static char nada; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 5770Sstevel@tonic-gate return (&nada); 5780Sstevel@tonic-gate result = tzname[tmp->tm_isdst]; 5790Sstevel@tonic-gate return ((result == NULL) ? &nada : result); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 582*1138Srobbin /* 583*1138Srobbin * The code below can fail on certain theoretical systems; 584*1138Srobbin * it works on all known real-world systems as of 2004-12-30. 585*1138Srobbin */ 586*1138Srobbin 587*1138Srobbin static const char * 588*1138Srobbin tformat() 589*1138Srobbin { 590*1138Srobbin #if defined(sun) 591*1138Srobbin /* time_t is signed long */ 592*1138Srobbin return ("%ld"); 593*1138Srobbin #else 594*1138Srobbin /*CONSTANTCONDITION*/ 595*1138Srobbin if (0.5 == (time_t)0.5) { /* floating */ 596*1138Srobbin /*CONSTANTCONDITION*/ 597*1138Srobbin if (sizeof (time_t) > sizeof (double)) 598*1138Srobbin return ("%Lg"); 599*1138Srobbin return ("%g"); 600*1138Srobbin } 601*1138Srobbin /*CONSTANTCONDITION*/ 602*1138Srobbin if (0 > (time_t)-1) { /* signed */ 603*1138Srobbin /*CONSTANTCONDITION*/ 604*1138Srobbin if (sizeof (time_t) > sizeof (long)) 605*1138Srobbin return ("%lld"); 606*1138Srobbin /*CONSTANTCONDITION*/ 607*1138Srobbin if (sizeof (time_t) > sizeof (int)) 608*1138Srobbin return ("%ld"); 609*1138Srobbin return ("%d"); 610*1138Srobbin } 611*1138Srobbin /*CONSTANTCONDITION*/ 612*1138Srobbin if (sizeof (time_t) > sizeof (unsigned long)) 613*1138Srobbin return ("%llu"); 614*1138Srobbin /*CONSTANTCONDITION*/ 615*1138Srobbin if (sizeof (time_t) > sizeof (unsigned int)) 616*1138Srobbin return ("%lu"); 617*1138Srobbin return ("%u"); 618*1138Srobbin #endif 619*1138Srobbin } 620*1138Srobbin 6210Sstevel@tonic-gate static void 622*1138Srobbin dumptime(timeptr) 623*1138Srobbin register const struct tm *timeptr; 624*1138Srobbin { 625*1138Srobbin static const char wday_name[][3] = { 626*1138Srobbin "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 627*1138Srobbin }; 628*1138Srobbin static const char mon_name[][3] = { 629*1138Srobbin "Jan", "Feb", "Mar", "Apr", "May", "Jun", 630*1138Srobbin "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 631*1138Srobbin }; 632*1138Srobbin register const char *wn; 633*1138Srobbin register const char *mn; 634*1138Srobbin register int lead; 635*1138Srobbin register int trail; 636*1138Srobbin 637*1138Srobbin if (timeptr == NULL) { 638*1138Srobbin (void) printf("NULL"); 639*1138Srobbin return; 640*1138Srobbin } 641*1138Srobbin /* 642*1138Srobbin * The packaged versions of localtime and gmtime never put out-of-range 643*1138Srobbin * values in tm_wday or tm_mon, but since this code might be compiled 644*1138Srobbin * with other (perhaps experimental) versions, paranoia is in order. 645*1138Srobbin */ 646*1138Srobbin if (timeptr->tm_wday < 0 || timeptr->tm_wday >= 647*1138Srobbin (int)(sizeof (wday_name) / sizeof (wday_name[0]))) 648*1138Srobbin wn = "???"; 649*1138Srobbin else wn = wday_name[timeptr->tm_wday]; 650*1138Srobbin if (timeptr->tm_mon < 0 || timeptr->tm_mon >= 651*1138Srobbin (int)(sizeof (mon_name) / sizeof (mon_name[0]))) 652*1138Srobbin mn = "???"; 653*1138Srobbin else mn = mon_name[timeptr->tm_mon]; 654*1138Srobbin (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", 655*1138Srobbin wn, mn, 656*1138Srobbin timeptr->tm_mday, timeptr->tm_hour, 657*1138Srobbin timeptr->tm_min, timeptr->tm_sec); 658*1138Srobbin #define DIVISOR 10 659*1138Srobbin trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; 660*1138Srobbin lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + 661*1138Srobbin trail / DIVISOR; 662*1138Srobbin trail %= DIVISOR; 663*1138Srobbin if (trail < 0 && lead > 0) { 664*1138Srobbin trail += DIVISOR; 665*1138Srobbin --lead; 666*1138Srobbin } else if (lead < 0 && trail > 0) { 667*1138Srobbin trail -= DIVISOR; 668*1138Srobbin ++lead; 669*1138Srobbin } 670*1138Srobbin if (lead == 0) 671*1138Srobbin (void) printf("%d", trail); 672*1138Srobbin else 673*1138Srobbin (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); 674*1138Srobbin } 675*1138Srobbin 676*1138Srobbin static void 677*1138Srobbin usage() 6780Sstevel@tonic-gate { 6790Sstevel@tonic-gate (void) fprintf(stderr, gettext( 680*1138Srobbin "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), 681*1138Srobbin progname); 682*1138Srobbin exit(EXIT_FAILURE); 6830Sstevel@tonic-gate /* NOTREACHED */ 6840Sstevel@tonic-gate } 685