1*66e58127Stedu /* $OpenBSD: zdump.c,v 1.3 2015/02/09 12:52:45 tedu Exp $ */ 22059035fStedu /* 32059035fStedu ** This file is in the public domain, so clarified as of 42059035fStedu ** 2009-05-17 by Arthur David Olson. 52059035fStedu */ 62059035fStedu 72059035fStedu /* 82059035fStedu ** This code has been made independent of the rest of the time 92059035fStedu ** conversion package to increase confidence in the verification it provides. 102059035fStedu ** You can use this code to help in verifying other implementations. 112059035fStedu */ 122059035fStedu 13784122ecStedu #include <ctype.h> /* for isalpha et al. */ 14784122ecStedu #include <float.h> /* for FLT_MAX and DBL_MAX */ 15784122ecStedu #include <stdio.h> /* for stdout, stderr, perror */ 16784122ecStedu #include <string.h> /* for strlcpy */ 17784122ecStedu #include <stdlib.h> /* for exit, malloc, atoi */ 18784122ecStedu #include <time.h> /* for struct tm */ 192059035fStedu 202059035fStedu #ifndef ZDUMP_LO_YEAR 212059035fStedu #define ZDUMP_LO_YEAR (-500) 222059035fStedu #endif /* !defined ZDUMP_LO_YEAR */ 232059035fStedu 242059035fStedu #ifndef ZDUMP_HI_YEAR 252059035fStedu #define ZDUMP_HI_YEAR 2500 262059035fStedu #endif /* !defined ZDUMP_HI_YEAR */ 272059035fStedu 282059035fStedu #ifndef MAX_STRING_LENGTH 292059035fStedu #define MAX_STRING_LENGTH 1024 302059035fStedu #endif /* !defined MAX_STRING_LENGTH */ 312059035fStedu 322059035fStedu #ifndef TRUE 332059035fStedu #define TRUE 1 342059035fStedu #endif /* !defined TRUE */ 352059035fStedu 362059035fStedu #ifndef FALSE 372059035fStedu #define FALSE 0 382059035fStedu #endif /* !defined FALSE */ 392059035fStedu 402059035fStedu #ifndef SECSPERMIN 412059035fStedu #define SECSPERMIN 60 422059035fStedu #endif /* !defined SECSPERMIN */ 432059035fStedu 442059035fStedu #ifndef MINSPERHOUR 452059035fStedu #define MINSPERHOUR 60 462059035fStedu #endif /* !defined MINSPERHOUR */ 472059035fStedu 482059035fStedu #ifndef SECSPERHOUR 492059035fStedu #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 502059035fStedu #endif /* !defined SECSPERHOUR */ 512059035fStedu 522059035fStedu #ifndef HOURSPERDAY 532059035fStedu #define HOURSPERDAY 24 542059035fStedu #endif /* !defined HOURSPERDAY */ 552059035fStedu 562059035fStedu #ifndef EPOCH_YEAR 572059035fStedu #define EPOCH_YEAR 1970 582059035fStedu #endif /* !defined EPOCH_YEAR */ 592059035fStedu 602059035fStedu #ifndef TM_YEAR_BASE 612059035fStedu #define TM_YEAR_BASE 1900 622059035fStedu #endif /* !defined TM_YEAR_BASE */ 632059035fStedu 642059035fStedu #ifndef DAYSPERNYEAR 652059035fStedu #define DAYSPERNYEAR 365 662059035fStedu #endif /* !defined DAYSPERNYEAR */ 672059035fStedu 682059035fStedu #ifndef isleap 692059035fStedu #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) 702059035fStedu #endif /* !defined isleap */ 712059035fStedu 722059035fStedu #ifndef isleap_sum 732059035fStedu /* 742059035fStedu ** See tzfile.h for details on isleap_sum. 752059035fStedu */ 762059035fStedu #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) 772059035fStedu #endif /* !defined isleap_sum */ 782059035fStedu 792059035fStedu #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) 802059035fStedu #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) 812059035fStedu #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) 822059035fStedu 832059035fStedu #ifndef HAVE_GETTEXT 842059035fStedu #define HAVE_GETTEXT 0 852059035fStedu #endif 862059035fStedu #if HAVE_GETTEXT 872059035fStedu #include "locale.h" /* for setlocale */ 882059035fStedu #include "libintl.h" 892059035fStedu #endif /* HAVE_GETTEXT */ 902059035fStedu 912059035fStedu #ifndef GNUC_or_lint 922059035fStedu #ifdef lint 932059035fStedu #define GNUC_or_lint 942059035fStedu #else /* !defined lint */ 952059035fStedu #ifdef __GNUC__ 962059035fStedu #define GNUC_or_lint 972059035fStedu #endif /* defined __GNUC__ */ 982059035fStedu #endif /* !defined lint */ 992059035fStedu #endif /* !defined GNUC_or_lint */ 1002059035fStedu 1012059035fStedu #ifndef INITIALIZE 1022059035fStedu #ifdef GNUC_or_lint 1032059035fStedu #define INITIALIZE(x) ((x) = 0) 1042059035fStedu #else /* !defined GNUC_or_lint */ 1052059035fStedu #define INITIALIZE(x) 1062059035fStedu #endif /* !defined GNUC_or_lint */ 1072059035fStedu #endif /* !defined INITIALIZE */ 1082059035fStedu 1092059035fStedu /* 1102059035fStedu ** For the benefit of GNU folk... 1112059035fStedu ** `_(MSGID)' uses the current locale's message library string for MSGID. 1122059035fStedu ** The default is to use gettext if available, and use MSGID otherwise. 1132059035fStedu */ 1142059035fStedu 1152059035fStedu #ifndef _ 1162059035fStedu #if HAVE_GETTEXT 1172059035fStedu #define _(msgid) gettext(msgid) 1182059035fStedu #else /* !HAVE_GETTEXT */ 1192059035fStedu #define _(msgid) msgid 1202059035fStedu #endif /* !HAVE_GETTEXT */ 1212059035fStedu #endif /* !defined _ */ 1222059035fStedu 1232059035fStedu #ifndef TZ_DOMAIN 1242059035fStedu #define TZ_DOMAIN "tz" 1252059035fStedu #endif /* !defined TZ_DOMAIN */ 1262059035fStedu 1272059035fStedu extern char ** environ; 1282059035fStedu extern int getopt(int argc, char * const argv[], 1292059035fStedu const char * options); 1302059035fStedu extern char * optarg; 1312059035fStedu extern int optind; 1322059035fStedu extern char * tzname[2]; 1332059035fStedu 1342059035fStedu static time_t absolute_min_time; 1352059035fStedu static time_t absolute_max_time; 1362059035fStedu static size_t longest; 1372059035fStedu static char * progname; 1382059035fStedu static int warned; 1392059035fStedu 1402059035fStedu static char * abbr(struct tm * tmp); 1412059035fStedu static void abbrok(const char * abbrp, const char * zone); 1422059035fStedu static long delta(struct tm * newp, struct tm * oldp); 1432059035fStedu static void dumptime(const struct tm * tmp); 1442059035fStedu static time_t hunt(char * name, time_t lot, time_t hit); 1452059035fStedu static void setabsolutes(void); 1462059035fStedu static void show(char * zone, time_t t, int v); 1472059035fStedu static const char * tformat(void); 1482059035fStedu static time_t yeartot(long y); 1492059035fStedu 1502059035fStedu #ifndef TYPECHECK 1512059035fStedu #define my_localtime localtime 1522059035fStedu #else /* !defined TYPECHECK */ 1532059035fStedu static struct tm * 1542059035fStedu my_localtime(tp) 1552059035fStedu time_t * tp; 1562059035fStedu { 157*66e58127Stedu struct tm * tmp; 1582059035fStedu 1592059035fStedu tmp = localtime(tp); 1602059035fStedu if (tp != NULL && tmp != NULL) { 1612059035fStedu struct tm tm; 162*66e58127Stedu time_t t; 1632059035fStedu 1642059035fStedu tm = *tmp; 1652059035fStedu t = mktime(&tm); 1662059035fStedu if (t - *tp >= 1 || *tp - t >= 1) { 1672059035fStedu (void) fflush(stdout); 1682059035fStedu (void) fprintf(stderr, "\n%s: ", progname); 1692059035fStedu (void) fprintf(stderr, tformat(), *tp); 1702059035fStedu (void) fprintf(stderr, " ->"); 1712059035fStedu (void) fprintf(stderr, " year=%d", tmp->tm_year); 1722059035fStedu (void) fprintf(stderr, " mon=%d", tmp->tm_mon); 1732059035fStedu (void) fprintf(stderr, " mday=%d", tmp->tm_mday); 1742059035fStedu (void) fprintf(stderr, " hour=%d", tmp->tm_hour); 1752059035fStedu (void) fprintf(stderr, " min=%d", tmp->tm_min); 1762059035fStedu (void) fprintf(stderr, " sec=%d", tmp->tm_sec); 1772059035fStedu (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); 1782059035fStedu (void) fprintf(stderr, " -> "); 1792059035fStedu (void) fprintf(stderr, tformat(), t); 1802059035fStedu (void) fprintf(stderr, "\n"); 1812059035fStedu } 1822059035fStedu } 1832059035fStedu return tmp; 1842059035fStedu } 1852059035fStedu #endif /* !defined TYPECHECK */ 1862059035fStedu 1872059035fStedu static void 1882059035fStedu abbrok(abbrp, zone) 1892059035fStedu const char * const abbrp; 1902059035fStedu const char * const zone; 1912059035fStedu { 192*66e58127Stedu const char * cp; 193*66e58127Stedu char * wp; 1942059035fStedu 1952059035fStedu if (warned) 1962059035fStedu return; 1972059035fStedu cp = abbrp; 1982059035fStedu wp = NULL; 1992059035fStedu while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp)) 2002059035fStedu ++cp; 2012059035fStedu if (cp - abbrp == 0) 2022059035fStedu wp = _("lacks alphabetic at start"); 2032059035fStedu else if (cp - abbrp < 3) 2042059035fStedu wp = _("has fewer than 3 alphabetics"); 2052059035fStedu else if (cp - abbrp > 6) 2062059035fStedu wp = _("has more than 6 alphabetics"); 2072059035fStedu if (wp == NULL && (*cp == '+' || *cp == '-')) { 2082059035fStedu ++cp; 2092059035fStedu if (isascii((unsigned char) *cp) && 2102059035fStedu isdigit((unsigned char) *cp)) 2112059035fStedu if (*cp++ == '1' && *cp >= '0' && *cp <= '4') 2122059035fStedu ++cp; 2132059035fStedu if (*cp != '\0') 2142059035fStedu wp = _("differs from POSIX standard"); 2152059035fStedu } 2162059035fStedu if (wp == NULL) 2172059035fStedu return; 2182059035fStedu (void) fflush(stdout); 2192059035fStedu (void) fprintf(stderr, 2202059035fStedu _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"), 2212059035fStedu progname, zone, abbrp, wp); 2222059035fStedu warned = TRUE; 2232059035fStedu } 2242059035fStedu 2252059035fStedu static void 2262059035fStedu usage(stream, status) 2272059035fStedu FILE * const stream; 2282059035fStedu const int status; 2292059035fStedu { 2302059035fStedu (void) fprintf(stream, 2312059035fStedu _("usage: %s [-v] [-c [loyear,]hiyear] zonename ...\n"), progname); 2322059035fStedu exit(status); 2332059035fStedu } 2342059035fStedu 2352059035fStedu int 2362059035fStedu main(argc, argv) 2372059035fStedu int argc; 2382059035fStedu char * argv[]; 2392059035fStedu { 240*66e58127Stedu int i; 241*66e58127Stedu int c; 242*66e58127Stedu int vflag; 243*66e58127Stedu char * cutarg; 244*66e58127Stedu long cutloyear = ZDUMP_LO_YEAR; 245*66e58127Stedu long cuthiyear = ZDUMP_HI_YEAR; 246*66e58127Stedu time_t cutlotime; 247*66e58127Stedu time_t cuthitime; 248*66e58127Stedu char ** fakeenv; 2492059035fStedu time_t now; 2502059035fStedu time_t t; 2512059035fStedu time_t newt; 2522059035fStedu struct tm tm; 2532059035fStedu struct tm newtm; 254*66e58127Stedu struct tm * tmp; 255*66e58127Stedu struct tm * newtmp; 2562059035fStedu 2572059035fStedu INITIALIZE(cutlotime); 2582059035fStedu INITIALIZE(cuthitime); 2592059035fStedu #if HAVE_GETTEXT 2602059035fStedu (void) setlocale(LC_ALL, ""); 2612059035fStedu #ifdef TZ_DOMAINDIR 2622059035fStedu (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 2632059035fStedu #endif /* defined TEXTDOMAINDIR */ 2642059035fStedu (void) textdomain(TZ_DOMAIN); 2652059035fStedu #endif /* HAVE_GETTEXT */ 2662059035fStedu progname = argv[0]; 2672059035fStedu vflag = 0; 2682059035fStedu cutarg = NULL; 2692059035fStedu while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 2702059035fStedu if (c == 'v') 2712059035fStedu vflag = 1; 2722059035fStedu else cutarg = optarg; 2732059035fStedu if ((c != EOF && c != -1) || 2742059035fStedu (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 2752059035fStedu usage(stderr, EXIT_FAILURE); 2762059035fStedu } 2772059035fStedu if (vflag) { 2782059035fStedu if (cutarg != NULL) { 2792059035fStedu long lo; 2802059035fStedu long hi; 2812059035fStedu char dummy; 2822059035fStedu 2832059035fStedu if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { 2842059035fStedu cuthiyear = hi; 2852059035fStedu } else if (sscanf(cutarg, "%ld,%ld%c", 2862059035fStedu &lo, &hi, &dummy) == 2) { 2872059035fStedu cutloyear = lo; 2882059035fStedu cuthiyear = hi; 2892059035fStedu } else { 2902059035fStedu (void) fprintf(stderr, _("%s: wild -c argument %s\n"), 2912059035fStedu progname, cutarg); 2922059035fStedu exit(EXIT_FAILURE); 2932059035fStedu } 2942059035fStedu } 2952059035fStedu setabsolutes(); 2962059035fStedu cutlotime = yeartot(cutloyear); 2972059035fStedu cuthitime = yeartot(cuthiyear); 2982059035fStedu } 2992059035fStedu (void) time(&now); 3002059035fStedu longest = 0; 3012059035fStedu for (i = optind; i < argc; ++i) 3022059035fStedu if (strlen(argv[i]) > longest) 3032059035fStedu longest = strlen(argv[i]); 3042059035fStedu { 305*66e58127Stedu int from; 306*66e58127Stedu int to; 3072059035fStedu 3082059035fStedu for (i = 0; environ[i] != NULL; ++i) 3092059035fStedu continue; 3102059035fStedu fakeenv = (char **) malloc((size_t) ((i + 2) * 3112059035fStedu sizeof *fakeenv)); 3122059035fStedu if (fakeenv == NULL || 3132059035fStedu (fakeenv[0] = (char *) malloc(longest + 4)) == NULL) { 3142059035fStedu (void) perror(progname); 3152059035fStedu exit(EXIT_FAILURE); 3162059035fStedu } 3172059035fStedu to = 0; 3182059035fStedu strlcpy(fakeenv[to++], "TZ=", longest + 4); 3192059035fStedu for (from = 0; environ[from] != NULL; ++from) 3202059035fStedu if (strncmp(environ[from], "TZ=", 3) != 0) 3212059035fStedu fakeenv[to++] = environ[from]; 3222059035fStedu fakeenv[to] = NULL; 3232059035fStedu environ = fakeenv; 3242059035fStedu } 3252059035fStedu for (i = optind; i < argc; ++i) { 3262059035fStedu static char buf[MAX_STRING_LENGTH]; 3272059035fStedu 3282059035fStedu strlcpy(&fakeenv[0][3], argv[i], longest + 1); 3292059035fStedu if (!vflag) { 3302059035fStedu show(argv[i], now, FALSE); 3312059035fStedu continue; 3322059035fStedu } 3332059035fStedu warned = FALSE; 3342059035fStedu t = absolute_min_time; 3352059035fStedu show(argv[i], t, TRUE); 3362059035fStedu t += SECSPERHOUR * HOURSPERDAY; 3372059035fStedu show(argv[i], t, TRUE); 3382059035fStedu if (t < cutlotime) 3392059035fStedu t = cutlotime; 3402059035fStedu tmp = my_localtime(&t); 3412059035fStedu if (tmp != NULL) { 3422059035fStedu tm = *tmp; 3432059035fStedu strlcpy(buf, abbr(&tm), sizeof buf); 3442059035fStedu } 3452059035fStedu for ( ; ; ) { 3462059035fStedu if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12) 3472059035fStedu break; 3482059035fStedu newt = t + SECSPERHOUR * 12; 3492059035fStedu newtmp = localtime(&newt); 3502059035fStedu if (newtmp != NULL) 3512059035fStedu newtm = *newtmp; 3522059035fStedu if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : 3532059035fStedu (delta(&newtm, &tm) != (newt - t) || 3542059035fStedu newtm.tm_isdst != tm.tm_isdst || 3552059035fStedu strcmp(abbr(&newtm), buf) != 0)) { 3562059035fStedu newt = hunt(argv[i], t, newt); 3572059035fStedu newtmp = localtime(&newt); 3582059035fStedu if (newtmp != NULL) { 3592059035fStedu newtm = *newtmp; 3602059035fStedu strlcpy(buf, abbr(&newtm), 3612059035fStedu sizeof buf); 3622059035fStedu } 3632059035fStedu } 3642059035fStedu t = newt; 3652059035fStedu tm = newtm; 3662059035fStedu tmp = newtmp; 3672059035fStedu } 3682059035fStedu t = absolute_max_time; 3692059035fStedu t -= SECSPERHOUR * HOURSPERDAY; 3702059035fStedu show(argv[i], t, TRUE); 3712059035fStedu t += SECSPERHOUR * HOURSPERDAY; 3722059035fStedu show(argv[i], t, TRUE); 3732059035fStedu } 3742059035fStedu if (fflush(stdout) || ferror(stdout)) { 3752059035fStedu (void) fprintf(stderr, "%s: ", progname); 3762059035fStedu (void) perror(_("Error writing to standard output")); 3772059035fStedu exit(EXIT_FAILURE); 3782059035fStedu } 3792059035fStedu exit(EXIT_SUCCESS); 3802059035fStedu /* If exit fails to exit... */ 3812059035fStedu return EXIT_FAILURE; 3822059035fStedu } 3832059035fStedu 3842059035fStedu static void 3852059035fStedu setabsolutes(void) 3862059035fStedu { 3872059035fStedu if (0.5 == (time_t) 0.5) { 3882059035fStedu /* 3892059035fStedu ** time_t is floating. 3902059035fStedu */ 3912059035fStedu if (sizeof (time_t) == sizeof (float)) { 3922059035fStedu absolute_min_time = (time_t) -FLT_MAX; 3932059035fStedu absolute_max_time = (time_t) FLT_MAX; 3942059035fStedu } else if (sizeof (time_t) == sizeof (double)) { 3952059035fStedu absolute_min_time = (time_t) -DBL_MAX; 3962059035fStedu absolute_max_time = (time_t) DBL_MAX; 3972059035fStedu } else { 3982059035fStedu (void) fprintf(stderr, 3992059035fStedu _("%s: use of -v on system with floating time_t other than float or double\n"), 4002059035fStedu progname); 4012059035fStedu exit(EXIT_FAILURE); 4022059035fStedu } 4032059035fStedu } else if (0 > (time_t) -1) { 4042059035fStedu /* 4052059035fStedu ** time_t is signed. Assume overflow wraps around. 4062059035fStedu */ 4072059035fStedu time_t t = 0; 4082059035fStedu time_t t1 = 1; 4092059035fStedu 4102059035fStedu while (t < t1) { 4112059035fStedu t = t1; 4122059035fStedu t1 = 2 * t1 + 1; 4132059035fStedu } 4142059035fStedu 4152059035fStedu absolute_max_time = t; 4162059035fStedu t = -t; 4172059035fStedu absolute_min_time = t - 1; 4182059035fStedu if (t < absolute_min_time) 4192059035fStedu absolute_min_time = t; 4202059035fStedu } else { 4212059035fStedu /* 4222059035fStedu ** time_t is unsigned. 4232059035fStedu */ 4242059035fStedu absolute_min_time = 0; 4252059035fStedu absolute_max_time = absolute_min_time - 1; 4262059035fStedu } 4272059035fStedu } 4282059035fStedu 4292059035fStedu static time_t 4302059035fStedu yeartot(y) 4312059035fStedu const long y; 4322059035fStedu { 433*66e58127Stedu long myy; 434*66e58127Stedu long seconds; 435*66e58127Stedu time_t t; 4362059035fStedu 4372059035fStedu myy = EPOCH_YEAR; 4382059035fStedu t = 0; 4392059035fStedu while (myy != y) { 4402059035fStedu if (myy < y) { 4412059035fStedu seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 4422059035fStedu ++myy; 4432059035fStedu if (t > absolute_max_time - seconds) { 4442059035fStedu t = absolute_max_time; 4452059035fStedu break; 4462059035fStedu } 4472059035fStedu t += seconds; 4482059035fStedu } else { 4492059035fStedu --myy; 4502059035fStedu seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; 4512059035fStedu if (t < absolute_min_time + seconds) { 4522059035fStedu t = absolute_min_time; 4532059035fStedu break; 4542059035fStedu } 4552059035fStedu t -= seconds; 4562059035fStedu } 4572059035fStedu } 4582059035fStedu return t; 4592059035fStedu } 4602059035fStedu 4612059035fStedu static time_t 4622059035fStedu hunt(char *name, time_t lot, time_t hit) 4632059035fStedu { 4642059035fStedu time_t t; 4652059035fStedu long diff; 4662059035fStedu struct tm lotm; 467*66e58127Stedu struct tm * lotmp; 4682059035fStedu struct tm tm; 469*66e58127Stedu struct tm * tmp; 4702059035fStedu char loab[MAX_STRING_LENGTH]; 4712059035fStedu 4722059035fStedu lotmp = my_localtime(&lot); 4732059035fStedu if (lotmp != NULL) { 4742059035fStedu lotm = *lotmp; 4752059035fStedu (void) strlcpy(loab, abbr(&lotm), sizeof loab); 4762059035fStedu } 4772059035fStedu for ( ; ; ) { 4782059035fStedu diff = (long) (hit - lot); 4792059035fStedu if (diff < 2) 4802059035fStedu break; 4812059035fStedu t = lot; 4822059035fStedu t += diff / 2; 4832059035fStedu if (t <= lot) 4842059035fStedu ++t; 4852059035fStedu else if (t >= hit) 4862059035fStedu --t; 4872059035fStedu tmp = my_localtime(&t); 4882059035fStedu if (tmp != NULL) 4892059035fStedu tm = *tmp; 4902059035fStedu if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : 4912059035fStedu (delta(&tm, &lotm) == (t - lot) && 4922059035fStedu tm.tm_isdst == lotm.tm_isdst && 4932059035fStedu strcmp(abbr(&tm), loab) == 0)) { 4942059035fStedu lot = t; 4952059035fStedu lotm = tm; 4962059035fStedu lotmp = tmp; 4972059035fStedu } else hit = t; 4982059035fStedu } 4992059035fStedu show(name, lot, TRUE); 5002059035fStedu show(name, hit, TRUE); 5012059035fStedu return hit; 5022059035fStedu } 5032059035fStedu 5042059035fStedu /* 5052059035fStedu ** Thanks to Paul Eggert for logic used in delta. 5062059035fStedu */ 5072059035fStedu 5082059035fStedu static long 5092059035fStedu delta(newp, oldp) 5102059035fStedu struct tm * newp; 5112059035fStedu struct tm * oldp; 5122059035fStedu { 513*66e58127Stedu long result; 514*66e58127Stedu int tmy; 5152059035fStedu 5162059035fStedu if (newp->tm_year < oldp->tm_year) 5172059035fStedu return -delta(oldp, newp); 5182059035fStedu result = 0; 5192059035fStedu for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 5202059035fStedu result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); 5212059035fStedu result += newp->tm_yday - oldp->tm_yday; 5222059035fStedu result *= HOURSPERDAY; 5232059035fStedu result += newp->tm_hour - oldp->tm_hour; 5242059035fStedu result *= MINSPERHOUR; 5252059035fStedu result += newp->tm_min - oldp->tm_min; 5262059035fStedu result *= SECSPERMIN; 5272059035fStedu result += newp->tm_sec - oldp->tm_sec; 5282059035fStedu return result; 5292059035fStedu } 5302059035fStedu 5312059035fStedu static void 5322059035fStedu show(char *zone, time_t t, int v) 5332059035fStedu { 534*66e58127Stedu struct tm * tmp; 5352059035fStedu 5362059035fStedu (void) printf("%-*s ", (int) longest, zone); 5372059035fStedu if (v) { 5382059035fStedu tmp = gmtime(&t); 5392059035fStedu if (tmp == NULL) { 5402059035fStedu (void) printf(tformat(), t); 5412059035fStedu } else { 5422059035fStedu dumptime(tmp); 5432059035fStedu (void) printf(" UTC"); 5442059035fStedu } 5452059035fStedu (void) printf(" = "); 5462059035fStedu } 5472059035fStedu tmp = my_localtime(&t); 5482059035fStedu dumptime(tmp); 5492059035fStedu if (tmp != NULL) { 5502059035fStedu if (*abbr(tmp) != '\0') 5512059035fStedu (void) printf(" %s", abbr(tmp)); 5522059035fStedu if (v) { 5532059035fStedu (void) printf(" isdst=%d", tmp->tm_isdst); 5542059035fStedu #ifdef TM_GMTOFF 5552059035fStedu (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); 5562059035fStedu #endif /* defined TM_GMTOFF */ 5572059035fStedu } 5582059035fStedu } 5592059035fStedu (void) printf("\n"); 5602059035fStedu if (tmp != NULL && *abbr(tmp) != '\0') 5612059035fStedu abbrok(abbr(tmp), zone); 5622059035fStedu } 5632059035fStedu 5642059035fStedu static char * 5652059035fStedu abbr(tmp) 5662059035fStedu struct tm * tmp; 5672059035fStedu { 568*66e58127Stedu char * result; 5692059035fStedu static char nada; 5702059035fStedu 5712059035fStedu if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 5722059035fStedu return &nada; 5732059035fStedu result = tzname[tmp->tm_isdst]; 5742059035fStedu return (result == NULL) ? &nada : result; 5752059035fStedu } 5762059035fStedu 5772059035fStedu /* 5782059035fStedu ** The code below can fail on certain theoretical systems; 5792059035fStedu ** it works on all known real-world systems as of 2004-12-30. 5802059035fStedu */ 5812059035fStedu 5822059035fStedu static const char * 5832059035fStedu tformat(void) 5842059035fStedu { 5852059035fStedu if (0.5 == (time_t) 0.5) { /* floating */ 5862059035fStedu if (sizeof (time_t) > sizeof (double)) 5872059035fStedu return "%Lg"; 5882059035fStedu return "%g"; 5892059035fStedu } 5902059035fStedu if (0 > (time_t) -1) { /* signed */ 5912059035fStedu if (sizeof (time_t) > sizeof (long)) 5922059035fStedu return "%lld"; 5932059035fStedu if (sizeof (time_t) > sizeof (int)) 5942059035fStedu return "%ld"; 5952059035fStedu return "%d"; 5962059035fStedu } 5972059035fStedu if (sizeof (time_t) > sizeof (unsigned long)) 5982059035fStedu return "%llu"; 5992059035fStedu if (sizeof (time_t) > sizeof (unsigned int)) 6002059035fStedu return "%lu"; 6012059035fStedu return "%u"; 6022059035fStedu } 6032059035fStedu 6042059035fStedu static void 6052059035fStedu dumptime(timeptr) 606*66e58127Stedu const struct tm * timeptr; 6072059035fStedu { 6082059035fStedu static const char wday_name[][3] = { 6092059035fStedu "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 6102059035fStedu }; 6112059035fStedu static const char mon_name[][3] = { 6122059035fStedu "Jan", "Feb", "Mar", "Apr", "May", "Jun", 6132059035fStedu "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 6142059035fStedu }; 615*66e58127Stedu const char * wn; 616*66e58127Stedu const char * mn; 617*66e58127Stedu int lead; 618*66e58127Stedu int trail; 6192059035fStedu 6202059035fStedu if (timeptr == NULL) { 6212059035fStedu (void) printf("NULL"); 6222059035fStedu return; 6232059035fStedu } 6242059035fStedu /* 6252059035fStedu ** The packaged versions of localtime and gmtime never put out-of-range 6262059035fStedu ** values in tm_wday or tm_mon, but since this code might be compiled 6272059035fStedu ** with other (perhaps experimental) versions, paranoia is in order. 6282059035fStedu */ 6292059035fStedu if (timeptr->tm_wday < 0 || timeptr->tm_wday >= 6302059035fStedu (int) (sizeof wday_name / sizeof wday_name[0])) 6312059035fStedu wn = "???"; 6322059035fStedu else wn = wday_name[timeptr->tm_wday]; 6332059035fStedu if (timeptr->tm_mon < 0 || timeptr->tm_mon >= 6342059035fStedu (int) (sizeof mon_name / sizeof mon_name[0])) 6352059035fStedu mn = "???"; 6362059035fStedu else mn = mon_name[timeptr->tm_mon]; 6372059035fStedu (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", 6382059035fStedu wn, mn, 6392059035fStedu timeptr->tm_mday, timeptr->tm_hour, 6402059035fStedu timeptr->tm_min, timeptr->tm_sec); 6412059035fStedu #define DIVISOR 10 6422059035fStedu trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; 6432059035fStedu lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + 6442059035fStedu trail / DIVISOR; 6452059035fStedu trail %= DIVISOR; 6462059035fStedu if (trail < 0 && lead > 0) { 6472059035fStedu trail += DIVISOR; 6482059035fStedu --lead; 6492059035fStedu } else if (lead < 0 && trail > 0) { 6502059035fStedu trail -= DIVISOR; 6512059035fStedu ++lead; 6522059035fStedu } 6532059035fStedu if (lead == 0) 6542059035fStedu (void) printf("%d", trail); 6552059035fStedu else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); 6562059035fStedu } 657