1 #ifndef lint 2 #ifndef NOID 3 static char elsieid[] = "@(#)zdump.c 7.28"; 4 #endif /* !defined NOID */ 5 #endif /* !defined lint */ 6 7 /* 8 * @(#)zdump.c 7.28 9 * $FreeBSD: src/usr.sbin/zic/zdump.c,v 1.7 1999/08/28 01:21:19 peter Exp $ 10 * $DragonFly: src/usr.sbin/zic/zdump.c,v 1.4 2004/12/18 22:48:15 swildner Exp $ 11 */ 12 /* 13 ** This code has been made independent of the rest of the time 14 ** conversion package to increase confidence in the verification it provides. 15 ** You can use this code to help in verifying other implementations. 16 */ 17 18 #include <err.h> 19 #include <stdio.h> /* for stdout, stderr */ 20 #include <stdlib.h> /* for exit, malloc, atoi */ 21 #include <string.h> /* for strcpy */ 22 #include <sys/types.h> /* for time_t */ 23 #include <time.h> /* for struct tm */ 24 #include <unistd.h> 25 26 #ifndef MAX_STRING_LENGTH 27 #define MAX_STRING_LENGTH 1024 28 #endif /* !defined MAX_STRING_LENGTH */ 29 30 #ifndef TRUE 31 #define TRUE 1 32 #endif /* !defined TRUE */ 33 34 #ifndef FALSE 35 #define FALSE 0 36 #endif /* !defined FALSE */ 37 38 #ifndef EXIT_SUCCESS 39 #define EXIT_SUCCESS 0 40 #endif /* !defined EXIT_SUCCESS */ 41 42 #ifndef EXIT_FAILURE 43 #define EXIT_FAILURE 1 44 #endif /* !defined EXIT_FAILURE */ 45 46 #ifndef SECSPERMIN 47 #define SECSPERMIN 60 48 #endif /* !defined SECSPERMIN */ 49 50 #ifndef MINSPERHOUR 51 #define MINSPERHOUR 60 52 #endif /* !defined MINSPERHOUR */ 53 54 #ifndef SECSPERHOUR 55 #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) 56 #endif /* !defined SECSPERHOUR */ 57 58 #ifndef HOURSPERDAY 59 #define HOURSPERDAY 24 60 #endif /* !defined HOURSPERDAY */ 61 62 #ifndef EPOCH_YEAR 63 #define EPOCH_YEAR 1970 64 #endif /* !defined EPOCH_YEAR */ 65 66 #ifndef TM_YEAR_BASE 67 #define TM_YEAR_BASE 1900 68 #endif /* !defined TM_YEAR_BASE */ 69 70 #ifndef DAYSPERNYEAR 71 #define DAYSPERNYEAR 365 72 #endif /* !defined DAYSPERNYEAR */ 73 74 #ifndef isleap 75 #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 76 #endif /* !defined isleap */ 77 78 #if HAVE_GETTEXT - 0 79 #include "locale.h" /* for setlocale */ 80 #include "libintl.h" 81 #endif /* HAVE_GETTEXT - 0 */ 82 83 #ifndef GNUC_or_lint 84 #ifdef lint 85 #define GNUC_or_lint 86 #endif /* defined lint */ 87 #ifndef lint 88 #ifdef __GNUC__ 89 #define GNUC_or_lint 90 #endif /* defined __GNUC__ */ 91 #endif /* !defined lint */ 92 #endif /* !defined GNUC_or_lint */ 93 94 #ifndef INITIALIZE 95 #ifdef GNUC_or_lint 96 #define INITIALIZE(x) ((x) = 0) 97 #endif /* defined GNUC_or_lint */ 98 #ifndef GNUC_or_lint 99 #define INITIALIZE(x) 100 #endif /* !defined GNUC_or_lint */ 101 #endif /* !defined INITIALIZE */ 102 103 /* 104 ** For the benefit of GNU folk... 105 ** `_(MSGID)' uses the current locale's message library string for MSGID. 106 ** The default is to use gettext if available, and use MSGID otherwise. 107 */ 108 109 #ifndef _ 110 #if HAVE_GETTEXT - 0 111 #define _(msgid) gettext(msgid) 112 #else /* !(HAVE_GETTEXT - 0) */ 113 #define _(msgid) msgid 114 #endif /* !(HAVE_GETTEXT - 0) */ 115 #endif /* !defined _ */ 116 117 #ifndef TZ_DOMAIN 118 #define TZ_DOMAIN "tz" 119 #endif /* !defined TZ_DOMAIN */ 120 121 extern char ** environ; 122 extern char * tzname[2]; 123 124 static char *abbr(struct tm *tmp); 125 static long delta(struct tm *newp, struct tm *oldp); 126 static time_t hunt(char *name, time_t lot, time_t hit); 127 static size_t longest; 128 static char *progname; 129 static void show(char *zone, time_t t, int v); 130 static void usage(void); 131 132 int 133 main(int argc, char *argv[]) 134 { 135 int i; 136 int c; 137 int vflag; 138 char *cutoff; 139 int cutyear; 140 long cuttime; 141 char **fakeenv; 142 time_t now; 143 time_t t; 144 time_t newt; 145 time_t hibit; 146 struct tm tm; 147 struct tm newtm; 148 149 INITIALIZE(cuttime); 150 #if HAVE_GETTEXT - 0 151 setlocale(LC_MESSAGES, ""); 152 #ifdef TZ_DOMAINDIR 153 bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); 154 #endif /* defined(TEXTDOMAINDIR) */ 155 textdomain(TZ_DOMAIN); 156 #endif /* HAVE_GETTEXT - 0 */ 157 vflag = 0; 158 cutoff = NULL; 159 while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') 160 if (c == 'v') 161 vflag = 1; 162 else cutoff = optarg; 163 if ((c != EOF && c != -1) || 164 (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { 165 usage(); 166 } 167 if (cutoff != NULL) { 168 int y; 169 170 cutyear = atoi(cutoff); 171 cuttime = 0; 172 for (y = EPOCH_YEAR; y < cutyear; ++y) 173 cuttime += DAYSPERNYEAR + isleap(y); 174 cuttime *= SECSPERHOUR * HOURSPERDAY; 175 } 176 time(&now); 177 longest = 0; 178 for (i = optind; i < argc; ++i) 179 if (strlen(argv[i]) > longest) 180 longest = strlen(argv[i]); 181 for (hibit = 1; (hibit << 1) != 0; hibit <<= 1) 182 continue; 183 { 184 int from; 185 int to; 186 187 for (i = 0; environ[i] != NULL; ++i) 188 continue; 189 fakeenv = (char **) malloc((size_t) ((i + 2) * 190 sizeof *fakeenv)); 191 if (fakeenv == NULL || 192 (fakeenv[0] = (char *) malloc((size_t) (longest + 193 4))) == NULL) 194 errx(EXIT_FAILURE, 195 _("malloc() failed")); 196 to = 0; 197 strcpy(fakeenv[to++], "TZ="); 198 for (from = 0; environ[from] != NULL; ++from) 199 if (strncmp(environ[from], "TZ=", 3) != 0) 200 fakeenv[to++] = environ[from]; 201 fakeenv[to] = NULL; 202 environ = fakeenv; 203 } 204 for (i = optind; i < argc; ++i) { 205 static char buf[MAX_STRING_LENGTH]; 206 207 strcpy(&fakeenv[0][3], argv[i]); 208 if (!vflag) { 209 show(argv[i], now, FALSE); 210 continue; 211 } 212 /* 213 ** Get lowest value of t. 214 */ 215 t = hibit; 216 if (t > 0) /* time_t is unsigned */ 217 t = 0; 218 show(argv[i], t, TRUE); 219 t += SECSPERHOUR * HOURSPERDAY; 220 show(argv[i], t, TRUE); 221 tm = *localtime(&t); 222 strncpy(buf, abbr(&tm), (sizeof buf) - 1); 223 for ( ; ; ) { 224 if (cutoff != NULL && t >= cuttime) 225 break; 226 newt = t + SECSPERHOUR * 12; 227 if (cutoff != NULL && newt >= cuttime) 228 break; 229 if (newt <= t) 230 break; 231 newtm = *localtime(&newt); 232 if (delta(&newtm, &tm) != (newt - t) || 233 newtm.tm_isdst != tm.tm_isdst || 234 strcmp(abbr(&newtm), buf) != 0) { 235 newt = hunt(argv[i], t, newt); 236 newtm = *localtime(&newt); 237 strncpy(buf, abbr(&newtm), 238 (sizeof buf) - 1); 239 } 240 t = newt; 241 tm = newtm; 242 } 243 /* 244 ** Get highest value of t. 245 */ 246 t = ~((time_t) 0); 247 if (t < 0) /* time_t is signed */ 248 t &= ~hibit; 249 t -= SECSPERHOUR * HOURSPERDAY; 250 show(argv[i], t, TRUE); 251 t += SECSPERHOUR * HOURSPERDAY; 252 show(argv[i], t, TRUE); 253 } 254 if (fflush(stdout) || ferror(stdout)) 255 errx(EXIT_FAILURE, _("error writing standard output")); 256 exit(EXIT_SUCCESS); 257 258 /* gcc -Wall pacifier */ 259 for ( ; ; ) 260 continue; 261 } 262 263 static void 264 usage(void) 265 { 266 fprintf(stderr, _("usage: zdump [-v] [-c cutoff] zonename ...\n")); 267 exit(EXIT_FAILURE); 268 } 269 270 static time_t 271 hunt(char *name, time_t lot, time_t hit) 272 { 273 time_t t; 274 struct tm lotm; 275 struct tm tm; 276 static char loab[MAX_STRING_LENGTH]; 277 278 lotm = *localtime(&lot); 279 strncpy(loab, abbr(&lotm), (sizeof loab) - 1); 280 while ((hit - lot) >= 2) { 281 t = lot / 2 + hit / 2; 282 if (t <= lot) 283 ++t; 284 else if (t >= hit) 285 --t; 286 tm = *localtime(&t); 287 if (delta(&tm, &lotm) == (t - lot) && 288 tm.tm_isdst == lotm.tm_isdst && 289 strcmp(abbr(&tm), loab) == 0) { 290 lot = t; 291 lotm = tm; 292 } else hit = t; 293 } 294 show(name, lot, TRUE); 295 show(name, hit, TRUE); 296 return hit; 297 } 298 299 /* 300 ** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta. 301 */ 302 303 static long 304 delta(struct tm *newp, struct tm *oldp) 305 { 306 long result; 307 int tmy; 308 309 if (newp->tm_year < oldp->tm_year) 310 return -delta(oldp, newp); 311 result = 0; 312 for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) 313 result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE); 314 result += newp->tm_yday - oldp->tm_yday; 315 result *= HOURSPERDAY; 316 result += newp->tm_hour - oldp->tm_hour; 317 result *= MINSPERHOUR; 318 result += newp->tm_min - oldp->tm_min; 319 result *= SECSPERMIN; 320 result += newp->tm_sec - oldp->tm_sec; 321 return result; 322 } 323 324 static void 325 show(char *zone, time_t t, int v) 326 { 327 struct tm * tmp; 328 329 printf("%-*s ", (int) longest, zone); 330 if (v) 331 printf("%.24s UTC = ", asctime(gmtime(&t))); 332 tmp = localtime(&t); 333 printf("%.24s", asctime(tmp)); 334 if (*abbr(tmp) != '\0') 335 printf(" %s", abbr(tmp)); 336 if (v) { 337 printf(" isdst=%d", tmp->tm_isdst); 338 #ifdef TM_GMTOFF 339 printf(" gmtoff=%ld", tmp->TM_GMTOFF); 340 #endif /* defined TM_GMTOFF */ 341 } 342 printf("\n"); 343 } 344 345 static char * 346 abbr(struct tm *tmp) 347 { 348 char * result; 349 static char nada; 350 351 if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) 352 return &nada; 353 result = tzname[tmp->tm_isdst]; 354 return (result == NULL) ? &nada : result; 355 } 356