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