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