17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*80868c53Srobbin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 27*80868c53Srobbin #pragma ident "%Z%%M% %I% %E% SMI" 28*80868c53Srobbin 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * zdump 7.24 317c478bd9Sstevel@tonic-gate * Taken from elsie.nci.nih.gov to replace the existing Solaris zdump, 327c478bd9Sstevel@tonic-gate * which was based on an earlier version of the elsie code. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * For zdump 7.24, the following changes were made to the elsie code: 357c478bd9Sstevel@tonic-gate * locale/textdomain/messages to match existing Solaris style. 367c478bd9Sstevel@tonic-gate * Solaris verbose mode is documented to display the current time first. 377c478bd9Sstevel@tonic-gate * cstyle cleaned code. 387c478bd9Sstevel@tonic-gate * removed old locale/textdomain code. 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 41*80868c53Srobbin static char elsieid[] = "@(#)zdump.c 7.68"; 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* 447c478bd9Sstevel@tonic-gate * This code has been made independent of the rest of the time 457c478bd9Sstevel@tonic-gate * conversion package to increase confidence in the verification it provides. 467c478bd9Sstevel@tonic-gate * You can use this code to help in verifying other implementations. 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #include "stdio.h" /* for stdout, stderr, perror */ 507c478bd9Sstevel@tonic-gate #include "string.h" /* for strcpy */ 517c478bd9Sstevel@tonic-gate #include "sys/types.h" /* for time_t */ 527c478bd9Sstevel@tonic-gate #include "time.h" /* for struct tm */ 537c478bd9Sstevel@tonic-gate #include "stdlib.h" /* for exit, malloc, atoi */ 547c478bd9Sstevel@tonic-gate #include "locale.h" /* for setlocale, textdomain */ 557c478bd9Sstevel@tonic-gate #include "libintl.h" 56*80868c53Srobbin #include <ctype.h> 577c478bd9Sstevel@tonic-gate #include "tzfile.h" /* for defines */ 58*80868c53Srobbin #include <limits.h> 59*80868c53Srobbin 60*80868c53Srobbin #ifndef ZDUMP_LO_YEAR 61*80868c53Srobbin #define ZDUMP_LO_YEAR (-500) 62*80868c53Srobbin #endif /* !defined ZDUMP_LO_YEAR */ 63*80868c53Srobbin 64*80868c53Srobbin #ifndef ZDUMP_HI_YEAR 65*80868c53Srobbin #define ZDUMP_HI_YEAR 2500 66*80868c53Srobbin #endif /* !defined ZDUMP_HI_YEAR */ 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #ifndef MAX_STRING_LENGTH 697c478bd9Sstevel@tonic-gate #define MAX_STRING_LENGTH 1024 707c478bd9Sstevel@tonic-gate #endif /* !defined MAX_STRING_LENGTH */ 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #ifndef TRUE 737c478bd9Sstevel@tonic-gate #define TRUE 1 747c478bd9Sstevel@tonic-gate #endif /* !defined TRUE */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #ifndef FALSE 777c478bd9Sstevel@tonic-gate #define FALSE 0 787c478bd9Sstevel@tonic-gate #endif /* !defined FALSE */ 797c478bd9Sstevel@tonic-gate 80*80868c53Srobbin #ifndef isleap_sum 81*80868c53Srobbin /* 82*80868c53Srobbin * See tzfile.h for details on isleap_sum. 83*80868c53Srobbin */ 84*80868c53Srobbin #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 85*80868c53Srobbin #endif /* !defined isleap_sum */ 86*80868c53Srobbin 87*80868c53Srobbin #ifndef SECSPERDAY 88*80868c53Srobbin #define SECSPERDAY ((long)SECSPERHOUR * HOURSPERDAY) 89*80868c53Srobbin #endif 90*80868c53Srobbin #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 91*80868c53Srobbin #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 92*80868c53Srobbin 93*80868c53Srobbin #ifndef GNUC_or_lint 947c478bd9Sstevel@tonic-gate #ifdef lint 95*80868c53Srobbin #define GNUC_or_lint 96*80868c53Srobbin #else /* !defined lint */ 97*80868c53Srobbin #ifdef __GNUC__ 98*80868c53Srobbin #define GNUC_or_lint 99*80868c53Srobbin #endif /* defined __GNUC__ */ 1007c478bd9Sstevel@tonic-gate #endif /* !defined lint */ 101*80868c53Srobbin #endif /* !defined GNUC_or_lint */ 102*80868c53Srobbin 103*80868c53Srobbin #ifndef INITIALIZE 104*80868c53Srobbin #ifdef GNUC_or_lint 105*80868c53Srobbin #define INITIALIZE(x) ((x) = 0) 106*80868c53Srobbin #else /* !defined GNUC_or_lint */ 107*80868c53Srobbin #define INITIALIZE(x) 108*80868c53Srobbin #endif /* !defined GNUC_or_lint */ 1097c478bd9Sstevel@tonic-gate #endif /* !defined INITIALIZE */ 1107c478bd9Sstevel@tonic-gate 111*80868c53Srobbin static time_t absolute_min_time; 112*80868c53Srobbin static time_t absolute_max_time; 1137c478bd9Sstevel@tonic-gate static size_t longest; 1147c478bd9Sstevel@tonic-gate static char *progname; 115*80868c53Srobbin static int warned; 116*80868c53Srobbin 117*80868c53Srobbin static char *abbr(struct tm *); 118*80868c53Srobbin static void abbrok(const char *, const char *); 119*80868c53Srobbin static long delta(struct tm *, struct tm *); 120*80868c53Srobbin static void dumptime(const struct tm *); 121*80868c53Srobbin static time_t hunt(char *, time_t, time_t); 122*80868c53Srobbin static void setabsolutes(void); 1237c478bd9Sstevel@tonic-gate static void show(char *, time_t, int); 124*80868c53Srobbin static void usage(void); 125*80868c53Srobbin static const char *tformat(void); 126*80868c53Srobbin static time_t yeartot(long y); 127*80868c53Srobbin 128*80868c53Srobbin #ifndef TYPECHECK 129*80868c53Srobbin #define my_localtime localtime 130*80868c53Srobbin #else /* !defined TYPECHECK */ 131*80868c53Srobbin static struct tm * 132*80868c53Srobbin my_localtime(tp) 133*80868c53Srobbin time_t *tp; 134*80868c53Srobbin { 135*80868c53Srobbin register struct tm *tmp; 136*80868c53Srobbin 137*80868c53Srobbin tmp = localtime(tp); 138*80868c53Srobbin if (tp != NULL && tmp != NULL) { 139*80868c53Srobbin struct tm tm; 140*80868c53Srobbin register time_t t; 141*80868c53Srobbin 142*80868c53Srobbin tm = *tmp; 143*80868c53Srobbin t = mktime(&tm); 144*80868c53Srobbin if (t - *tp >= 1 || *tp - t >= 1) { 145*80868c53Srobbin (void) fflush(stdout); 146*80868c53Srobbin (void) fprintf(stderr, "\n%s: ", progname); 147*80868c53Srobbin (void) fprintf(stderr, tformat(), *tp); 148*80868c53Srobbin (void) fprintf(stderr, " ->"); 149*80868c53Srobbin (void) fprintf(stderr, " year=%d", tmp->tm_year); 150*80868c53Srobbin (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 151*80868c53Srobbin (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 152*80868c53Srobbin (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 153*80868c53Srobbin (void) fprintf(stderr, " min=%d", tmp->tm_min); 154*80868c53Srobbin (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 155*80868c53Srobbin (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 156*80868c53Srobbin (void) fprintf(stderr, " -> "); 157*80868c53Srobbin (void) fprintf(stderr, tformat(), t); 158*80868c53Srobbin (void) fprintf(stderr, "\n"); 159*80868c53Srobbin } 160*80868c53Srobbin } 161*80868c53Srobbin return (tmp); 162*80868c53Srobbin } 163*80868c53Srobbin #endif /* !defined TYPECHECK */ 164*80868c53Srobbin 165*80868c53Srobbin static void 166*80868c53Srobbin abbrok(abbrp, zone) 167*80868c53Srobbin const char * const abbrp; 168*80868c53Srobbin const char * const zone; 169*80868c53Srobbin { 170*80868c53Srobbin register const char *cp; 171*80868c53Srobbin int error = 0; 172*80868c53Srobbin 173*80868c53Srobbin if (warned) 174*80868c53Srobbin return; 175*80868c53Srobbin cp = abbrp; 176*80868c53Srobbin while (isascii(*cp) && isalpha((unsigned char)*cp)) 177*80868c53Srobbin ++cp; 178*80868c53Srobbin (void) fflush(stdout); 179*80868c53Srobbin if (cp - abbrp == 0) { 180*80868c53Srobbin /* 181*80868c53Srobbin * TRANSLATION_NOTE 182*80868c53Srobbin * The first %s prints for the program name (zdump), 183*80868c53Srobbin * the second %s prints the timezone name, the third 184*80868c53Srobbin * %s prints the timezone abbreviation (tzname[0] or 185*80868c53Srobbin * tzname[1]). 186*80868c53Srobbin */ 187*80868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 188*80868c53Srobbin "abbreviation \"%s\" lacks alphabetic at start\n"), 189*80868c53Srobbin progname, zone, abbrp); 190*80868c53Srobbin error = 1; 191*80868c53Srobbin } else if (cp - abbrp < 3) { 192*80868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 193*80868c53Srobbin "abbreviation \"%s\" has fewer than 3 alphabetics\n"), 194*80868c53Srobbin progname, zone, abbrp); 195*80868c53Srobbin error = 1; 196*80868c53Srobbin } else if (cp - abbrp > 6) { 197*80868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 198*80868c53Srobbin "abbreviation \"%s\" has more than 6 alphabetics\n"), 199*80868c53Srobbin progname, zone, abbrp); 200*80868c53Srobbin error = 1; 201*80868c53Srobbin } 202*80868c53Srobbin if (error == 0 && (*cp == '+' || *cp == '-')) { 203*80868c53Srobbin ++cp; 204*80868c53Srobbin if (isascii(*cp) && isdigit((unsigned char)*cp)) 205*80868c53Srobbin if (*cp++ == '1' && *cp >= '0' && *cp <= '4') 206*80868c53Srobbin ++cp; 207*80868c53Srobbin } 208*80868c53Srobbin if (error == 0 && *cp != '\0') { 209*80868c53Srobbin (void) fprintf(stderr, gettext("%s: warning: zone \"%s\" " 210*80868c53Srobbin "abbreviation \"%s\" differs from POSIX standard\n"), 211*80868c53Srobbin progname, zone, abbrp); 212*80868c53Srobbin error = 1; 213*80868c53Srobbin } 214*80868c53Srobbin if (error) 215*80868c53Srobbin warned = TRUE; 216*80868c53Srobbin } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate int 2197c478bd9Sstevel@tonic-gate main(argc, argv) 2207c478bd9Sstevel@tonic-gate int argc; 2217c478bd9Sstevel@tonic-gate char *argv[]; 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate register int i; 2247c478bd9Sstevel@tonic-gate register int c; 2257c478bd9Sstevel@tonic-gate register int vflag; 226*80868c53Srobbin register char *cutarg; 227*80868c53Srobbin register long cutloyear = ZDUMP_LO_YEAR; 228*80868c53Srobbin register long cuthiyear = ZDUMP_HI_YEAR; 229*80868c53Srobbin register time_t cutlotime; 230*80868c53Srobbin register time_t cuthitime; 2317c478bd9Sstevel@tonic-gate time_t now; 2327c478bd9Sstevel@tonic-gate time_t t; 2337c478bd9Sstevel@tonic-gate time_t newt; 2347c478bd9Sstevel@tonic-gate struct tm tm; 2357c478bd9Sstevel@tonic-gate struct tm newtm; 236*80868c53Srobbin register struct tm *tmp; 237*80868c53Srobbin register struct tm *newtmp; 2387c478bd9Sstevel@tonic-gate 239*80868c53Srobbin INITIALIZE(cutlotime); 240*80868c53Srobbin INITIALIZE(cuthitime); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2437c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 2447c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 2457c478bd9Sstevel@tonic-gate #endif 2467c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate progname = argv[0]; 249*80868c53Srobbin for (i = 1; i < argc; ++i) 250*80868c53Srobbin if (strcmp(argv[i], "--version") == 0) { 251*80868c53Srobbin (void) printf("%s\n", elsieid); 252*80868c53Srobbin exit(EXIT_SUCCESS); 253*80868c53Srobbin } 2547c478bd9Sstevel@tonic-gate vflag = 0; 255*80868c53Srobbin cutarg = NULL; 2567c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 2577c478bd9Sstevel@tonic-gate if (c == 'v') 2587c478bd9Sstevel@tonic-gate vflag = 1; 259*80868c53Srobbin else cutarg = optarg; 2607c478bd9Sstevel@tonic-gate if (c != EOF || 2617c478bd9Sstevel@tonic-gate (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 262*80868c53Srobbin usage(); 2637c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2647c478bd9Sstevel@tonic-gate } 265*80868c53Srobbin if (vflag) { 266*80868c53Srobbin if (cutarg != NULL) { 267*80868c53Srobbin long lo; 268*80868c53Srobbin long hi; 269*80868c53Srobbin char dummy; 2707c478bd9Sstevel@tonic-gate 271*80868c53Srobbin if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { 272*80868c53Srobbin cuthiyear = hi; 273*80868c53Srobbin } else if (sscanf(cutarg, "%ld,%ld%c", 274*80868c53Srobbin &lo, &hi, &dummy) == 2) { 275*80868c53Srobbin cutloyear = lo; 276*80868c53Srobbin cuthiyear = hi; 277*80868c53Srobbin } else { 278*80868c53Srobbin (void) fprintf(stderr, gettext("%s: wild -c argument %s\n"), 279*80868c53Srobbin progname, cutarg); 280*80868c53Srobbin exit(EXIT_FAILURE); 281*80868c53Srobbin } 282*80868c53Srobbin } 283*80868c53Srobbin setabsolutes(); 284*80868c53Srobbin cutlotime = yeartot(cutloyear); 285*80868c53Srobbin cuthitime = yeartot(cuthiyear); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate (void) time(&now); 2887c478bd9Sstevel@tonic-gate longest = 0; 2897c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) 2907c478bd9Sstevel@tonic-gate if (strlen(argv[i]) > longest) 2917c478bd9Sstevel@tonic-gate longest = strlen(argv[i]); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate for (i = optind; i < argc; ++i) { 2947c478bd9Sstevel@tonic-gate static char buf[MAX_STRING_LENGTH]; 295*80868c53Srobbin static char *tzp = NULL; 2967c478bd9Sstevel@tonic-gate 297*80868c53Srobbin (void) unsetenv("TZ"); 298*80868c53Srobbin if (tzp != NULL) 299*80868c53Srobbin free(tzp); 300*80868c53Srobbin if ((tzp = malloc(3 + strlen(argv[i]) + 1)) == NULL) { 301*80868c53Srobbin perror(progname); 302*80868c53Srobbin exit(EXIT_FAILURE); 303*80868c53Srobbin } 304*80868c53Srobbin (void) strcpy(tzp, "TZ="); 305*80868c53Srobbin (void) strcat(tzp, argv[i]); 306*80868c53Srobbin if (putenv(tzp) != 0) { 307*80868c53Srobbin perror(progname); 308*80868c53Srobbin exit(EXIT_FAILURE); 309*80868c53Srobbin } 3107c478bd9Sstevel@tonic-gate if (!vflag) { 3117c478bd9Sstevel@tonic-gate show(argv[i], now, FALSE); 3127c478bd9Sstevel@tonic-gate continue; 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate #if defined(sun) 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * We show the current time first, probably because we froze 3187c478bd9Sstevel@tonic-gate * the behavior of zdump some time ago and then it got 3197c478bd9Sstevel@tonic-gate * changed. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate show(argv[i], now, TRUE); 3227c478bd9Sstevel@tonic-gate #endif 323*80868c53Srobbin warned = FALSE; 324*80868c53Srobbin t = absolute_min_time; 3257c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3267c478bd9Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 3277c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 328*80868c53Srobbin if (t < cutlotime) 329*80868c53Srobbin t = cutlotime; 330*80868c53Srobbin tmp = my_localtime(&t); 331*80868c53Srobbin if (tmp != NULL) { 332*80868c53Srobbin tm = *tmp; 333*80868c53Srobbin (void) strncpy(buf, abbr(&tm), sizeof (buf) - 1); 334*80868c53Srobbin } 3357c478bd9Sstevel@tonic-gate for (;;) { 336*80868c53Srobbin if (t >= cuthitime) 3377c478bd9Sstevel@tonic-gate break; 3387c478bd9Sstevel@tonic-gate newt = t + SECSPERHOUR * 12; 339*80868c53Srobbin if (newt >= cuthitime) 3407c478bd9Sstevel@tonic-gate break; 3417c478bd9Sstevel@tonic-gate if (newt <= t) 3427c478bd9Sstevel@tonic-gate break; 343*80868c53Srobbin newtmp = localtime(&newt); 344*80868c53Srobbin if (newtmp != NULL) 345*80868c53Srobbin newtm = *newtmp; 346*80868c53Srobbin if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 347*80868c53Srobbin (delta(&newtm, &tm) != (newt - t) || 3487c478bd9Sstevel@tonic-gate newtm.tm_isdst != tm.tm_isdst || 349*80868c53Srobbin strcmp(abbr(&newtm), buf) != 0)) { 3507c478bd9Sstevel@tonic-gate newt = hunt(argv[i], t, newt); 351*80868c53Srobbin newtmp = localtime(&newt); 352*80868c53Srobbin if (newtmp != NULL) { 353*80868c53Srobbin newtm = *newtmp; 354*80868c53Srobbin (void) strncpy(buf, 355*80868c53Srobbin abbr(&newtm), 356*80868c53Srobbin sizeof (buf) - 1); 357*80868c53Srobbin } 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate t = newt; 3607c478bd9Sstevel@tonic-gate tm = newtm; 361*80868c53Srobbin tmp = newtmp; 3627c478bd9Sstevel@tonic-gate } 363*80868c53Srobbin t = absolute_max_time; 3647c478bd9Sstevel@tonic-gate #if defined(sun) 3657c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3667c478bd9Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3677c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3687c478bd9Sstevel@tonic-gate #else /* !defined(sun) */ 3697c478bd9Sstevel@tonic-gate t -= SECSPERHOUR * HOURSPERDAY; 3707c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3717c478bd9Sstevel@tonic-gate t += SECSPERHOUR * HOURSPERDAY; 3727c478bd9Sstevel@tonic-gate show(argv[i], t, TRUE); 3737c478bd9Sstevel@tonic-gate #endif /* !defined(sun) */ 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate if (fflush(stdout) || ferror(stdout)) { 376*80868c53Srobbin (void) fprintf(stderr, "%s: ", progname); 377*80868c53Srobbin (void) perror(gettext("Error writing standard output")); 378*80868c53Srobbin exit(EXIT_FAILURE); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate return (EXIT_SUCCESS); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 383*80868c53Srobbin static void 384*80868c53Srobbin setabsolutes() 385*80868c53Srobbin { 386*80868c53Srobbin #if defined(sun) 387*80868c53Srobbin absolute_min_time = LONG_MIN; 388*80868c53Srobbin absolute_max_time = LONG_MAX; 389*80868c53Srobbin #else 390*80868c53Srobbin if (0.5 == (time_t)0.5) { 391*80868c53Srobbin /* 392*80868c53Srobbin * time_t is floating. 393*80868c53Srobbin */ 394*80868c53Srobbin if (sizeof (time_t) == sizeof (float)) { 395*80868c53Srobbin absolute_min_time = (time_t)-FLT_MAX; 396*80868c53Srobbin absolute_max_time = (time_t)FLT_MAX; 397*80868c53Srobbin } else if (sizeof (time_t) == sizeof (double)) { 398*80868c53Srobbin absolute_min_time = (time_t)-DBL_MAX; 399*80868c53Srobbin absolute_max_time = (time_t)DBL_MAX; 400*80868c53Srobbin } else { 401*80868c53Srobbin (void) fprintf(stderr, gettext("%s: use of -v on " 402*80868c53Srobbin "system with floating time_t other than float " 403*80868c53Srobbin "or double\n"), progname); 404*80868c53Srobbin exit(EXIT_FAILURE); 405*80868c53Srobbin } 406*80868c53Srobbin } else 407*80868c53Srobbin /*CONSTANTCONDITION*/ 408*80868c53Srobbin if (0 > (time_t)-1) { 409*80868c53Srobbin /* 410*80868c53Srobbin * time_t is signed. 411*80868c53Srobbin */ 412*80868c53Srobbin register time_t hibit; 413*80868c53Srobbin 414*80868c53Srobbin for (hibit = 1; (hibit * 2) != 0; hibit *= 2) 415*80868c53Srobbin continue; 416*80868c53Srobbin absolute_min_time = hibit; 417*80868c53Srobbin absolute_max_time = -(hibit + 1); 418*80868c53Srobbin } else { 419*80868c53Srobbin /* 420*80868c53Srobbin * time_t is unsigned. 421*80868c53Srobbin */ 422*80868c53Srobbin absolute_min_time = 0; 423*80868c53Srobbin absolute_max_time = absolute_min_time - 1; 424*80868c53Srobbin } 425*80868c53Srobbin #endif 426*80868c53Srobbin } 427*80868c53Srobbin 428*80868c53Srobbin static time_t 429*80868c53Srobbin yeartot(y) 430*80868c53Srobbin const long y; 431*80868c53Srobbin { 432*80868c53Srobbin register long myy; 433*80868c53Srobbin register long seconds; 434*80868c53Srobbin register time_t t; 435*80868c53Srobbin 436*80868c53Srobbin myy = EPOCH_YEAR; 437*80868c53Srobbin t = 0; 438*80868c53Srobbin while (myy != y) { 439*80868c53Srobbin if (myy < y) { 440*80868c53Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 441*80868c53Srobbin ++myy; 442*80868c53Srobbin if (t > absolute_max_time - seconds) { 443*80868c53Srobbin t = absolute_max_time; 444*80868c53Srobbin break; 445*80868c53Srobbin } 446*80868c53Srobbin t += seconds; 447*80868c53Srobbin } else { 448*80868c53Srobbin --myy; 449*80868c53Srobbin seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 450*80868c53Srobbin if (t < absolute_min_time + seconds) { 451*80868c53Srobbin t = absolute_min_time; 452*80868c53Srobbin break; 453*80868c53Srobbin } 454*80868c53Srobbin t -= seconds; 455*80868c53Srobbin } 456*80868c53Srobbin } 457*80868c53Srobbin return (t); 458*80868c53Srobbin } 459*80868c53Srobbin 4607c478bd9Sstevel@tonic-gate static time_t 4617c478bd9Sstevel@tonic-gate hunt(name, lot, hit) 4627c478bd9Sstevel@tonic-gate char *name; 4637c478bd9Sstevel@tonic-gate time_t lot; 4647c478bd9Sstevel@tonic-gate time_t hit; 4657c478bd9Sstevel@tonic-gate { 4667c478bd9Sstevel@tonic-gate time_t t; 467*80868c53Srobbin long diff; 4687c478bd9Sstevel@tonic-gate struct tm lotm; 469*80868c53Srobbin register struct tm *lotmp; 4707c478bd9Sstevel@tonic-gate struct tm tm; 471*80868c53Srobbin register struct tm *tmp; 472*80868c53Srobbin char loab[MAX_STRING_LENGTH]; 4737c478bd9Sstevel@tonic-gate 474*80868c53Srobbin lotmp = my_localtime(&lot); 475*80868c53Srobbin if (lotmp != NULL) { 476*80868c53Srobbin lotm = *lotmp; 477*80868c53Srobbin (void) strncpy(loab, abbr(&lotm), sizeof (loab) - 1); 478*80868c53Srobbin } 479*80868c53Srobbin for (;;) { 480*80868c53Srobbin diff = (long)(hit - lot); 481*80868c53Srobbin if (diff < 2) 482*80868c53Srobbin break; 483*80868c53Srobbin t = lot; 484*80868c53Srobbin t += diff / 2; 4857c478bd9Sstevel@tonic-gate if (t <= lot) 4867c478bd9Sstevel@tonic-gate ++t; 4877c478bd9Sstevel@tonic-gate else if (t >= hit) 4887c478bd9Sstevel@tonic-gate --t; 489*80868c53Srobbin tmp = my_localtime(&t); 490*80868c53Srobbin if (tmp != NULL) 491*80868c53Srobbin tm = *tmp; 492*80868c53Srobbin if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : 493*80868c53Srobbin (delta(&tm, &lotm) == (t - lot) && 4947c478bd9Sstevel@tonic-gate tm.tm_isdst == lotm.tm_isdst && 495*80868c53Srobbin strcmp(abbr(&tm), loab) == 0)) { 4967c478bd9Sstevel@tonic-gate lot = t; 4977c478bd9Sstevel@tonic-gate lotm = tm; 498*80868c53Srobbin lotmp = tmp; 4997c478bd9Sstevel@tonic-gate } else hit = t; 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate show(name, lot, TRUE); 5027c478bd9Sstevel@tonic-gate show(name, hit, TRUE); 5037c478bd9Sstevel@tonic-gate return (hit); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta. 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate static long 5117c478bd9Sstevel@tonic-gate delta(newp, oldp) 5127c478bd9Sstevel@tonic-gate struct tm *newp; 5137c478bd9Sstevel@tonic-gate struct tm *oldp; 5147c478bd9Sstevel@tonic-gate { 515*80868c53Srobbin register long result; 516*80868c53Srobbin register int tmy; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate if (newp->tm_year < oldp->tm_year) 5197c478bd9Sstevel@tonic-gate return (-delta(oldp, newp)); 5207c478bd9Sstevel@tonic-gate result = 0; 5217c478bd9Sstevel@tonic-gate for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 522*80868c53Srobbin result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); 5237c478bd9Sstevel@tonic-gate result += newp->tm_yday - oldp->tm_yday; 5247c478bd9Sstevel@tonic-gate result *= HOURSPERDAY; 5257c478bd9Sstevel@tonic-gate result += newp->tm_hour - oldp->tm_hour; 5267c478bd9Sstevel@tonic-gate result *= MINSPERHOUR; 5277c478bd9Sstevel@tonic-gate result += newp->tm_min - oldp->tm_min; 5287c478bd9Sstevel@tonic-gate result *= SECSPERMIN; 5297c478bd9Sstevel@tonic-gate result += newp->tm_sec - oldp->tm_sec; 5307c478bd9Sstevel@tonic-gate return (result); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate static void 5347c478bd9Sstevel@tonic-gate show(zone, t, v) 5357c478bd9Sstevel@tonic-gate char *zone; 5367c478bd9Sstevel@tonic-gate time_t t; 5377c478bd9Sstevel@tonic-gate int v; 5387c478bd9Sstevel@tonic-gate { 539*80868c53Srobbin register struct tm *tmp; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate (void) printf("%-*s ", (int)longest, zone); 542*80868c53Srobbin if (v) { 543*80868c53Srobbin tmp = gmtime(&t); 544*80868c53Srobbin if (tmp == NULL) { 545*80868c53Srobbin (void) printf(tformat(), t); 546*80868c53Srobbin } else { 547*80868c53Srobbin dumptime(tmp); 548*80868c53Srobbin (void) printf(" UTC"); 549*80868c53Srobbin } 550*80868c53Srobbin (void) printf(" = "); 551*80868c53Srobbin } 552*80868c53Srobbin tmp = my_localtime(&t); 553*80868c53Srobbin dumptime(tmp); 554*80868c53Srobbin if (tmp != NULL) { 5557c478bd9Sstevel@tonic-gate if (*abbr(tmp) != '\0') 5567c478bd9Sstevel@tonic-gate (void) printf(" %s", abbr(tmp)); 5577c478bd9Sstevel@tonic-gate if (v) { 5587c478bd9Sstevel@tonic-gate (void) printf(" isdst=%d", tmp->tm_isdst); 559*80868c53Srobbin #ifdef TM_GMTOFF 560*80868c53Srobbin (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 561*80868c53Srobbin #endif /* defined TM_GMTOFF */ 562*80868c53Srobbin } 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate (void) printf("\n"); 565*80868c53Srobbin if (tmp != NULL && *abbr(tmp) != '\0') 566*80868c53Srobbin abbrok(abbr(tmp), zone); 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate static char * 5707c478bd9Sstevel@tonic-gate abbr(tmp) 5717c478bd9Sstevel@tonic-gate struct tm *tmp; 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate register char *result; 5747c478bd9Sstevel@tonic-gate static char nada; 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 5777c478bd9Sstevel@tonic-gate return (&nada); 5787c478bd9Sstevel@tonic-gate result = tzname[tmp->tm_isdst]; 5797c478bd9Sstevel@tonic-gate return ((result == NULL) ? &nada : result); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 582*80868c53Srobbin /* 583*80868c53Srobbin * The code below can fail on certain theoretical systems; 584*80868c53Srobbin * it works on all known real-world systems as of 2004-12-30. 585*80868c53Srobbin */ 586*80868c53Srobbin 587*80868c53Srobbin static const char * 588*80868c53Srobbin tformat() 589*80868c53Srobbin { 590*80868c53Srobbin #if defined(sun) 591*80868c53Srobbin /* time_t is signed long */ 592*80868c53Srobbin return ("%ld"); 593*80868c53Srobbin #else 594*80868c53Srobbin /*CONSTANTCONDITION*/ 595*80868c53Srobbin if (0.5 == (time_t)0.5) { /* floating */ 596*80868c53Srobbin /*CONSTANTCONDITION*/ 597*80868c53Srobbin if (sizeof (time_t) > sizeof (double)) 598*80868c53Srobbin return ("%Lg"); 599*80868c53Srobbin return ("%g"); 600*80868c53Srobbin } 601*80868c53Srobbin /*CONSTANTCONDITION*/ 602*80868c53Srobbin if (0 > (time_t)-1) { /* signed */ 603*80868c53Srobbin /*CONSTANTCONDITION*/ 604*80868c53Srobbin if (sizeof (time_t) > sizeof (long)) 605*80868c53Srobbin return ("%lld"); 606*80868c53Srobbin /*CONSTANTCONDITION*/ 607*80868c53Srobbin if (sizeof (time_t) > sizeof (int)) 608*80868c53Srobbin return ("%ld"); 609*80868c53Srobbin return ("%d"); 610*80868c53Srobbin } 611*80868c53Srobbin /*CONSTANTCONDITION*/ 612*80868c53Srobbin if (sizeof (time_t) > sizeof (unsigned long)) 613*80868c53Srobbin return ("%llu"); 614*80868c53Srobbin /*CONSTANTCONDITION*/ 615*80868c53Srobbin if (sizeof (time_t) > sizeof (unsigned int)) 616*80868c53Srobbin return ("%lu"); 617*80868c53Srobbin return ("%u"); 618*80868c53Srobbin #endif 619*80868c53Srobbin } 620*80868c53Srobbin 6217c478bd9Sstevel@tonic-gate static void 622*80868c53Srobbin dumptime(timeptr) 623*80868c53Srobbin register const struct tm *timeptr; 624*80868c53Srobbin { 625*80868c53Srobbin static const char wday_name[][3] = { 626*80868c53Srobbin "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 627*80868c53Srobbin }; 628*80868c53Srobbin static const char mon_name[][3] = { 629*80868c53Srobbin "Jan", "Feb", "Mar", "Apr", "May", "Jun", 630*80868c53Srobbin "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 631*80868c53Srobbin }; 632*80868c53Srobbin register const char *wn; 633*80868c53Srobbin register const char *mn; 634*80868c53Srobbin register int lead; 635*80868c53Srobbin register int trail; 636*80868c53Srobbin 637*80868c53Srobbin if (timeptr == NULL) { 638*80868c53Srobbin (void) printf("NULL"); 639*80868c53Srobbin return; 640*80868c53Srobbin } 641*80868c53Srobbin /* 642*80868c53Srobbin * The packaged versions of localtime and gmtime never put out-of-range 643*80868c53Srobbin * values in tm_wday or tm_mon, but since this code might be compiled 644*80868c53Srobbin * with other (perhaps experimental) versions, paranoia is in order. 645*80868c53Srobbin */ 646*80868c53Srobbin if (timeptr->tm_wday < 0 || timeptr->tm_wday >= 647*80868c53Srobbin (int)(sizeof (wday_name) / sizeof (wday_name[0]))) 648*80868c53Srobbin wn = "???"; 649*80868c53Srobbin else wn = wday_name[timeptr->tm_wday]; 650*80868c53Srobbin if (timeptr->tm_mon < 0 || timeptr->tm_mon >= 651*80868c53Srobbin (int)(sizeof (mon_name) / sizeof (mon_name[0]))) 652*80868c53Srobbin mn = "???"; 653*80868c53Srobbin else mn = mon_name[timeptr->tm_mon]; 654*80868c53Srobbin (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", 655*80868c53Srobbin wn, mn, 656*80868c53Srobbin timeptr->tm_mday, timeptr->tm_hour, 657*80868c53Srobbin timeptr->tm_min, timeptr->tm_sec); 658*80868c53Srobbin #define DIVISOR 10 659*80868c53Srobbin trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; 660*80868c53Srobbin lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + 661*80868c53Srobbin trail / DIVISOR; 662*80868c53Srobbin trail %= DIVISOR; 663*80868c53Srobbin if (trail < 0 && lead > 0) { 664*80868c53Srobbin trail += DIVISOR; 665*80868c53Srobbin --lead; 666*80868c53Srobbin } else if (lead < 0 && trail > 0) { 667*80868c53Srobbin trail -= DIVISOR; 668*80868c53Srobbin ++lead; 669*80868c53Srobbin } 670*80868c53Srobbin if (lead == 0) 671*80868c53Srobbin (void) printf("%d", trail); 672*80868c53Srobbin else 673*80868c53Srobbin (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); 674*80868c53Srobbin } 675*80868c53Srobbin 676*80868c53Srobbin static void 677*80868c53Srobbin usage() 6787c478bd9Sstevel@tonic-gate { 6797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 680*80868c53Srobbin "%s: [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), 681*80868c53Srobbin progname); 682*80868c53Srobbin exit(EXIT_FAILURE); 6837c478bd9Sstevel@tonic-gate /* NOTREACHED */ 6847c478bd9Sstevel@tonic-gate } 685