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