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