]>
Commit | Line | Data |
---|---|---|
32c075e1 | 1 | static char elsieid[] = "@(#)zdump.c 7.74"; |
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 */ |
792dcd77 | 14 | #include "float.h" /* for FLT_MAX and DBL_MAX */ |
53751fd5 RM |
15 | #include "ctype.h" /* for isalpha et al. */ |
16 | #ifndef isascii | |
17 | #define isascii(x) 1 | |
32c075e1 | 18 | #endif |
792dcd77 UD |
19 | |
20 | #ifndef ZDUMP_LO_YEAR | |
21 | #define ZDUMP_LO_YEAR (-500) | |
22 | #endif /* !defined ZDUMP_LO_YEAR */ | |
23 | ||
24 | #ifndef ZDUMP_HI_YEAR | |
25 | #define ZDUMP_HI_YEAR 2500 | |
26 | #endif /* !defined ZDUMP_HI_YEAR */ | |
28f540f4 RM |
27 | |
28 | #ifndef MAX_STRING_LENGTH | |
29 | #define MAX_STRING_LENGTH 1024 | |
30 | #endif /* !defined MAX_STRING_LENGTH */ | |
31 | ||
32 | #ifndef TRUE | |
33 | #define TRUE 1 | |
34 | #endif /* !defined TRUE */ | |
35 | ||
36 | #ifndef FALSE | |
37 | #define FALSE 0 | |
38 | #endif /* !defined FALSE */ | |
39 | ||
40 | #ifndef EXIT_SUCCESS | |
41 | #define EXIT_SUCCESS 0 | |
42 | #endif /* !defined EXIT_SUCCESS */ | |
43 | ||
44 | #ifndef EXIT_FAILURE | |
45 | #define EXIT_FAILURE 1 | |
46 | #endif /* !defined EXIT_FAILURE */ | |
47 | ||
48 | #ifndef SECSPERMIN | |
49 | #define SECSPERMIN 60 | |
50 | #endif /* !defined SECSPERMIN */ | |
51 | ||
52 | #ifndef MINSPERHOUR | |
53 | #define MINSPERHOUR 60 | |
54 | #endif /* !defined MINSPERHOUR */ | |
55 | ||
56 | #ifndef SECSPERHOUR | |
57 | #define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) | |
58 | #endif /* !defined SECSPERHOUR */ | |
59 | ||
60 | #ifndef HOURSPERDAY | |
61 | #define HOURSPERDAY 24 | |
62 | #endif /* !defined HOURSPERDAY */ | |
63 | ||
64 | #ifndef EPOCH_YEAR | |
65 | #define EPOCH_YEAR 1970 | |
66 | #endif /* !defined EPOCH_YEAR */ | |
67 | ||
68 | #ifndef TM_YEAR_BASE | |
69 | #define TM_YEAR_BASE 1900 | |
70 | #endif /* !defined TM_YEAR_BASE */ | |
71 | ||
72 | #ifndef DAYSPERNYEAR | |
73 | #define DAYSPERNYEAR 365 | |
74 | #endif /* !defined DAYSPERNYEAR */ | |
75 | ||
76 | #ifndef isleap | |
792dcd77 | 77 | #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) |
28f540f4 RM |
78 | #endif /* !defined isleap */ |
79 | ||
792dcd77 UD |
80 | #ifndef isleap_sum |
81 | /* | |
82 | ** See tzfile.h for details on isleap_sum. | |
83 | */ | |
84 | #define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) | |
85 | #endif /* !defined isleap_sum */ | |
86 | ||
87 | #define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) | |
88 | #define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR) | |
89 | #define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY) | |
90 | ||
daa6fd88 | 91 | #if HAVE_GETTEXT |
92777700 RM |
92 | #include "locale.h" /* for setlocale */ |
93 | #include "libintl.h" | |
daa6fd88 | 94 | #endif /* HAVE_GETTEXT */ |
92777700 | 95 | |
28f540f4 RM |
96 | #ifndef GNUC_or_lint |
97 | #ifdef lint | |
98 | #define GNUC_or_lint | |
daa6fd88 | 99 | #else /* !defined lint */ |
28f540f4 RM |
100 | #ifdef __GNUC__ |
101 | #define GNUC_or_lint | |
102 | #endif /* defined __GNUC__ */ | |
6c2f0507 | 103 | #endif /* !defined lint */ |
28f540f4 RM |
104 | #endif /* !defined GNUC_or_lint */ |
105 | ||
106 | #ifndef INITIALIZE | |
107 | #ifdef GNUC_or_lint | |
108 | #define INITIALIZE(x) ((x) = 0) | |
daa6fd88 | 109 | #else /* !defined GNUC_or_lint */ |
28f540f4 RM |
110 | #define INITIALIZE(x) |
111 | #endif /* !defined GNUC_or_lint */ | |
112 | #endif /* !defined INITIALIZE */ | |
113 | ||
a182affd RM |
114 | /* |
115 | ** For the benefit of GNU folk... | |
92777700 RM |
116 | ** `_(MSGID)' uses the current locale's message library string for MSGID. |
117 | ** The default is to use gettext if available, and use MSGID otherwise. | |
a182affd RM |
118 | */ |
119 | ||
120 | #ifndef _ | |
daa6fd88 | 121 | #if HAVE_GETTEXT |
92777700 | 122 | #define _(msgid) gettext(msgid) |
daa6fd88 | 123 | #else /* !HAVE_GETTEXT */ |
92777700 | 124 | #define _(msgid) msgid |
daa6fd88 | 125 | #endif /* !HAVE_GETTEXT */ |
a182affd RM |
126 | #endif /* !defined _ */ |
127 | ||
92777700 RM |
128 | #ifndef TZ_DOMAIN |
129 | #define TZ_DOMAIN "tz" | |
130 | #endif /* !defined TZ_DOMAIN */ | |
131 | ||
4cca6b86 | 132 | #ifndef P |
32c075e1 | 133 | #ifdef __STDC__ |
4cca6b86 | 134 | #define P(x) x |
32c075e1 JJ |
135 | #else /* !defined __STDC__ */ |
136 | #define P(x) () | |
137 | #endif /* !defined __STDC__ */ | |
4cca6b86 UD |
138 | #endif /* !defined P */ |
139 | ||
28f540f4 | 140 | extern char ** environ; |
4cca6b86 | 141 | extern int getopt P((int argc, char * const argv[], |
792dcd77 | 142 | const char * options)); |
28f540f4 RM |
143 | extern char * optarg; |
144 | extern int optind; | |
28f540f4 RM |
145 | extern char * tzname[2]; |
146 | ||
792dcd77 UD |
147 | static time_t absolute_min_time; |
148 | static time_t absolute_max_time; | |
149 | static size_t longest; | |
150 | static char * progname; | |
c872f5cc | 151 | static int warned; |
792dcd77 | 152 | |
3ef4002b | 153 | static char * abbr P((struct tm * tmp)); |
53751fd5 | 154 | static void abbrok P((const char * abbrp, const char * zone)); |
4cca6b86 | 155 | static long delta P((struct tm * newp, struct tm * oldp)); |
792dcd77 | 156 | static void dumptime P((const struct tm * tmp)); |
4cca6b86 | 157 | static time_t hunt P((char * name, time_t lot, time_t hit)); |
792dcd77 | 158 | static void setabsolutes P((void)); |
4cca6b86 | 159 | static void show P((char * zone, time_t t, int v)); |
792dcd77 UD |
160 | static const char * tformat P((void)); |
161 | static time_t yeartot P((long y)); | |
162 | ||
163 | #ifndef TYPECHECK | |
164 | #define my_localtime localtime | |
165 | #else /* !defined TYPECHECK */ | |
166 | static struct tm * | |
167 | my_localtime(tp) | |
168 | time_t * tp; | |
169 | { | |
170 | register struct tm * tmp; | |
171 | ||
172 | tmp = localtime(tp); | |
173 | if (tp != NULL && tmp != NULL) { | |
174 | struct tm tm; | |
175 | register time_t t; | |
176 | ||
177 | tm = *tmp; | |
178 | t = mktime(&tm); | |
179 | if (t - *tp >= 1 || *tp - t >= 1) { | |
180 | (void) fflush(stdout); | |
181 | (void) fprintf(stderr, "\n%s: ", progname); | |
182 | (void) fprintf(stderr, tformat(), *tp); | |
183 | (void) fprintf(stderr, " ->"); | |
7a50b1f6 UD |
184 | (void) fprintf(stderr, " year=%d", tmp->tm_year); |
185 | (void) fprintf(stderr, " mon=%d", tmp->tm_mon); | |
186 | (void) fprintf(stderr, " mday=%d", tmp->tm_mday); | |
187 | (void) fprintf(stderr, " hour=%d", tmp->tm_hour); | |
188 | (void) fprintf(stderr, " min=%d", tmp->tm_min); | |
189 | (void) fprintf(stderr, " sec=%d", tmp->tm_sec); | |
190 | (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst); | |
792dcd77 UD |
191 | (void) fprintf(stderr, " -> "); |
192 | (void) fprintf(stderr, tformat(), t); | |
193 | (void) fprintf(stderr, "\n"); | |
194 | } | |
195 | } | |
196 | return tmp; | |
197 | } | |
198 | #endif /* !defined TYPECHECK */ | |
28f540f4 | 199 | |
c872f5cc | 200 | static void |
53751fd5 RM |
201 | abbrok(abbrp, zone) |
202 | const char * const abbrp; | |
c872f5cc UD |
203 | const char * const zone; |
204 | { | |
c872f5cc UD |
205 | register const char * cp; |
206 | register char * wp; | |
207 | ||
208 | if (warned) | |
209 | return; | |
53751fd5 | 210 | cp = abbrp; |
c872f5cc | 211 | wp = NULL; |
53751fd5 | 212 | while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp)) |
c872f5cc | 213 | ++cp; |
53751fd5 | 214 | if (cp - abbrp == 0) |
c872f5cc | 215 | wp = _("lacks alphabetic at start"); |
53751fd5 | 216 | else if (cp - abbrp < 3) |
c872f5cc | 217 | wp = _("has fewer than 3 alphabetics"); |
53751fd5 | 218 | else if (cp - abbrp > 6) |
c872f5cc UD |
219 | wp = _("has more than 6 alphabetics"); |
220 | if (wp == NULL && (*cp == '+' || *cp == '-')) { | |
221 | ++cp; | |
53751fd5 RM |
222 | if (isascii((unsigned char) *cp) && |
223 | isdigit((unsigned char) *cp)) | |
224 | if (*cp++ == '1' && *cp >= '0' && *cp <= '4') | |
225 | ++cp; | |
226 | if (*cp != '\0') | |
227 | wp = _("differs from POSIX standard"); | |
c872f5cc | 228 | } |
c872f5cc UD |
229 | if (wp == NULL) |
230 | return; | |
231 | (void) fflush(stdout); | |
232 | (void) fprintf(stderr, | |
53751fd5 RM |
233 | _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"), |
234 | progname, zone, abbrp, wp); | |
c872f5cc UD |
235 | warned = TRUE; |
236 | } | |
237 | ||
28f540f4 RM |
238 | int |
239 | main(argc, argv) | |
240 | int argc; | |
241 | char * argv[]; | |
242 | { | |
6c2f0507 RM |
243 | register int i; |
244 | register int c; | |
28f540f4 | 245 | register int vflag; |
792dcd77 UD |
246 | register char * cutarg; |
247 | register long cutloyear = ZDUMP_LO_YEAR; | |
248 | register long cuthiyear = ZDUMP_HI_YEAR; | |
249 | register time_t cutlotime; | |
250 | register time_t cuthitime; | |
251 | register char ** fakeenv; | |
28f540f4 | 252 | time_t now; |
6c2f0507 RM |
253 | time_t t; |
254 | time_t newt; | |
6c2f0507 RM |
255 | struct tm tm; |
256 | struct tm newtm; | |
792dcd77 UD |
257 | register struct tm * tmp; |
258 | register struct tm * newtmp; | |
28f540f4 | 259 | |
792dcd77 UD |
260 | INITIALIZE(cutlotime); |
261 | INITIALIZE(cuthitime); | |
daa6fd88 | 262 | #if HAVE_GETTEXT |
c872f5cc | 263 | (void) setlocale(LC_ALL, ""); |
92777700 RM |
264 | #ifdef TZ_DOMAINDIR |
265 | (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR); | |
daa6fd88 | 266 | #endif /* defined TEXTDOMAINDIR */ |
92777700 | 267 | (void) textdomain(TZ_DOMAIN); |
daa6fd88 | 268 | #endif /* HAVE_GETTEXT */ |
28f540f4 | 269 | progname = argv[0]; |
c0df57e1 UD |
270 | for (i = 1; i < argc; ++i) |
271 | if (strcmp(argv[i], "--version") == 0) { | |
272 | (void) printf("%s\n", elsieid); | |
53751fd5 | 273 | exit(EXIT_SUCCESS); |
c0df57e1 | 274 | } |
28f540f4 | 275 | vflag = 0; |
792dcd77 | 276 | cutarg = NULL; |
28f540f4 RM |
277 | while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v') |
278 | if (c == 'v') | |
279 | vflag = 1; | |
792dcd77 | 280 | else cutarg = optarg; |
1ef32c3d | 281 | if ((c != EOF && c != -1) || |
28f540f4 RM |
282 | (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) { |
283 | (void) fprintf(stderr, | |
792dcd77 UD |
284 | _("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"), |
285 | progname, progname); | |
53751fd5 | 286 | exit(EXIT_FAILURE); |
28f540f4 | 287 | } |
792dcd77 UD |
288 | if (vflag) { |
289 | if (cutarg != NULL) { | |
290 | long lo; | |
291 | long hi; | |
292 | char dummy; | |
293 | ||
294 | if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) { | |
295 | cuthiyear = hi; | |
296 | } else if (sscanf(cutarg, "%ld,%ld%c", | |
297 | &lo, &hi, &dummy) == 2) { | |
298 | cutloyear = lo; | |
299 | cuthiyear = hi; | |
300 | } else { | |
301 | (void) fprintf(stderr, _("%s: wild -c argument %s\n"), | |
302 | progname, cutarg); | |
53751fd5 | 303 | exit(EXIT_FAILURE); |
792dcd77 UD |
304 | } |
305 | } | |
306 | setabsolutes(); | |
307 | cutlotime = yeartot(cutloyear); | |
308 | cuthitime = yeartot(cuthiyear); | |
28f540f4 RM |
309 | } |
310 | (void) time(&now); | |
311 | longest = 0; | |
312 | for (i = optind; i < argc; ++i) | |
313 | if (strlen(argv[i]) > longest) | |
314 | longest = strlen(argv[i]); | |
28f540f4 | 315 | { |
6c2f0507 RM |
316 | register int from; |
317 | register int to; | |
28f540f4 | 318 | |
792dcd77 | 319 | for (i = 0; environ[i] != NULL; ++i) |
28f540f4 | 320 | continue; |
6c2f0507 RM |
321 | fakeenv = (char **) malloc((size_t) ((i + 2) * |
322 | sizeof *fakeenv)); | |
28f540f4 | 323 | if (fakeenv == NULL || |
4cca6b86 | 324 | (fakeenv[0] = (char *) malloc(longest + 4)) == NULL) { |
6c2f0507 | 325 | (void) perror(progname); |
53751fd5 | 326 | exit(EXIT_FAILURE); |
28f540f4 RM |
327 | } |
328 | to = 0; | |
329 | (void) strcpy(fakeenv[to++], "TZ="); | |
330 | for (from = 0; environ[from] != NULL; ++from) | |
331 | if (strncmp(environ[from], "TZ=", 3) != 0) | |
332 | fakeenv[to++] = environ[from]; | |
333 | fakeenv[to] = NULL; | |
334 | environ = fakeenv; | |
335 | } | |
336 | for (i = optind; i < argc; ++i) { | |
337 | static char buf[MAX_STRING_LENGTH]; | |
338 | ||
339 | (void) strcpy(&fakeenv[0][3], argv[i]); | |
dfe1754a RM |
340 | if (!vflag) { |
341 | show(argv[i], now, FALSE); | |
28f540f4 | 342 | continue; |
dfe1754a | 343 | } |
c872f5cc | 344 | warned = FALSE; |
792dcd77 | 345 | t = absolute_min_time; |
28f540f4 RM |
346 | show(argv[i], t, TRUE); |
347 | t += SECSPERHOUR * HOURSPERDAY; | |
348 | show(argv[i], t, TRUE); | |
792dcd77 UD |
349 | if (t < cutlotime) |
350 | t = cutlotime; | |
351 | tmp = my_localtime(&t); | |
352 | if (tmp != NULL) { | |
353 | tm = *tmp; | |
354 | (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1); | |
355 | } | |
28f540f4 | 356 | for ( ; ; ) { |
792dcd77 | 357 | if (t >= cuthitime) |
28f540f4 RM |
358 | break; |
359 | newt = t + SECSPERHOUR * 12; | |
792dcd77 | 360 | if (newt >= cuthitime) |
28f540f4 RM |
361 | break; |
362 | if (newt <= t) | |
363 | break; | |
792dcd77 UD |
364 | newtmp = localtime(&newt); |
365 | if (newtmp != NULL) | |
366 | newtm = *newtmp; | |
7a50b1f6 | 367 | if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) : |
792dcd77 | 368 | (delta(&newtm, &tm) != (newt - t) || |
28f540f4 | 369 | newtm.tm_isdst != tm.tm_isdst || |
792dcd77 | 370 | strcmp(abbr(&newtm), buf) != 0)) { |
28f540f4 | 371 | newt = hunt(argv[i], t, newt); |
792dcd77 UD |
372 | newtmp = localtime(&newt); |
373 | if (newtmp != NULL) { | |
374 | newtm = *newtmp; | |
375 | (void) strncpy(buf, | |
376 | abbr(&newtm), | |
377 | (sizeof buf) - 1); | |
378 | } | |
28f540f4 RM |
379 | } |
380 | t = newt; | |
381 | tm = newtm; | |
792dcd77 | 382 | tmp = newtmp; |
28f540f4 | 383 | } |
792dcd77 | 384 | t = absolute_max_time; |
28f540f4 RM |
385 | t -= SECSPERHOUR * HOURSPERDAY; |
386 | show(argv[i], t, TRUE); | |
387 | t += SECSPERHOUR * HOURSPERDAY; | |
388 | show(argv[i], t, TRUE); | |
389 | } | |
390 | if (fflush(stdout) || ferror(stdout)) { | |
792dcd77 | 391 | (void) fprintf(stderr, "%s: ", progname); |
bef8927a | 392 | (void) perror(_("Error writing to standard output")); |
53751fd5 | 393 | exit(EXIT_FAILURE); |
28f540f4 RM |
394 | } |
395 | exit(EXIT_SUCCESS); | |
792dcd77 UD |
396 | /* If exit fails to exit... */ |
397 | return EXIT_FAILURE; | |
398 | } | |
399 | ||
400 | static void | |
401 | setabsolutes() | |
402 | { | |
403 | if (0.5 == (time_t) 0.5) { | |
404 | /* | |
405 | ** time_t is floating. | |
406 | */ | |
407 | if (sizeof (time_t) == sizeof (float)) { | |
408 | absolute_min_time = (time_t) -FLT_MAX; | |
409 | absolute_max_time = (time_t) FLT_MAX; | |
410 | } else if (sizeof (time_t) == sizeof (double)) { | |
411 | absolute_min_time = (time_t) -DBL_MAX; | |
412 | absolute_max_time = (time_t) DBL_MAX; | |
413 | } else { | |
414 | (void) fprintf(stderr, | |
415 | _("%s: use of -v on system with floating time_t other than float or double\n"), | |
416 | progname); | |
53751fd5 | 417 | exit(EXIT_FAILURE); |
792dcd77 UD |
418 | } |
419 | } else if (0 > (time_t) -1) { | |
420 | /* | |
32c075e1 | 421 | ** time_t is signed. |
792dcd77 | 422 | */ |
32c075e1 | 423 | register time_t hibit; |
28f540f4 | 424 | |
32c075e1 JJ |
425 | for (hibit = 1; (hibit * 2) != 0; hibit *= 2) |
426 | continue; | |
427 | absolute_min_time = hibit; | |
428 | absolute_max_time = -(hibit + 1); | |
792dcd77 UD |
429 | } else { |
430 | /* | |
431 | ** time_t is unsigned. | |
432 | */ | |
433 | absolute_min_time = 0; | |
434 | absolute_max_time = absolute_min_time - 1; | |
435 | } | |
436 | } | |
437 | ||
438 | static time_t | |
439 | yeartot(y) | |
440 | const long y; | |
441 | { | |
442 | register long myy; | |
443 | register long seconds; | |
444 | register time_t t; | |
445 | ||
446 | myy = EPOCH_YEAR; | |
447 | t = 0; | |
448 | while (myy != y) { | |
449 | if (myy < y) { | |
450 | seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; | |
451 | ++myy; | |
452 | if (t > absolute_max_time - seconds) { | |
453 | t = absolute_max_time; | |
454 | break; | |
455 | } | |
456 | t += seconds; | |
457 | } else { | |
458 | --myy; | |
459 | seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; | |
460 | if (t < absolute_min_time + seconds) { | |
461 | t = absolute_min_time; | |
462 | break; | |
463 | } | |
464 | t -= seconds; | |
465 | } | |
466 | } | |
467 | return t; | |
28f540f4 RM |
468 | } |
469 | ||
470 | static time_t | |
32c075e1 JJ |
471 | hunt(name, lot, hit) |
472 | char * name; | |
473 | time_t lot; | |
474 | time_t hit; | |
28f540f4 | 475 | { |
792dcd77 UD |
476 | time_t t; |
477 | long diff; | |
478 | struct tm lotm; | |
479 | register struct tm * lotmp; | |
480 | struct tm tm; | |
481 | register struct tm * tmp; | |
482 | char loab[MAX_STRING_LENGTH]; | |
483 | ||
484 | lotmp = my_localtime(&lot); | |
485 | if (lotmp != NULL) { | |
486 | lotm = *lotmp; | |
487 | (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1); | |
488 | } | |
489 | for ( ; ; ) { | |
490 | diff = (long) (hit - lot); | |
491 | if (diff < 2) | |
492 | break; | |
493 | t = lot; | |
494 | t += diff / 2; | |
28f540f4 RM |
495 | if (t <= lot) |
496 | ++t; | |
497 | else if (t >= hit) | |
498 | --t; | |
792dcd77 UD |
499 | tmp = my_localtime(&t); |
500 | if (tmp != NULL) | |
501 | tm = *tmp; | |
502 | if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) : | |
503 | (delta(&tm, &lotm) == (t - lot) && | |
28f540f4 | 504 | tm.tm_isdst == lotm.tm_isdst && |
792dcd77 | 505 | strcmp(abbr(&tm), loab) == 0)) { |
28f540f4 RM |
506 | lot = t; |
507 | lotm = tm; | |
792dcd77 | 508 | lotmp = tmp; |
28f540f4 RM |
509 | } else hit = t; |
510 | } | |
511 | show(name, lot, TRUE); | |
512 | show(name, hit, TRUE); | |
513 | return hit; | |
514 | } | |
515 | ||
516 | /* | |
53751fd5 | 517 | ** Thanks to Paul Eggert for logic used in delta. |
28f540f4 RM |
518 | */ |
519 | ||
520 | static long | |
521 | delta(newp, oldp) | |
522 | struct tm * newp; | |
523 | struct tm * oldp; | |
524 | { | |
792dcd77 UD |
525 | register long result; |
526 | register int tmy; | |
28f540f4 RM |
527 | |
528 | if (newp->tm_year < oldp->tm_year) | |
529 | return -delta(oldp, newp); | |
530 | result = 0; | |
531 | for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy) | |
792dcd77 | 532 | result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE); |
28f540f4 RM |
533 | result += newp->tm_yday - oldp->tm_yday; |
534 | result *= HOURSPERDAY; | |
535 | result += newp->tm_hour - oldp->tm_hour; | |
536 | result *= MINSPERHOUR; | |
537 | result += newp->tm_min - oldp->tm_min; | |
538 | result *= SECSPERMIN; | |
539 | result += newp->tm_sec - oldp->tm_sec; | |
540 | return result; | |
541 | } | |
542 | ||
28f540f4 | 543 | static void |
32c075e1 JJ |
544 | show(zone, t, v) |
545 | char * zone; | |
546 | time_t t; | |
547 | int v; | |
28f540f4 | 548 | { |
792dcd77 | 549 | register struct tm * tmp; |
28f540f4 | 550 | |
4cca6b86 | 551 | (void) printf("%-*s ", (int) longest, zone); |
daa6fd88 | 552 | if (v) { |
792dcd77 UD |
553 | tmp = gmtime(&t); |
554 | if (tmp == NULL) { | |
555 | (void) printf(tformat(), t); | |
556 | } else { | |
557 | dumptime(tmp); | |
558 | (void) printf(" UTC"); | |
559 | } | |
560 | (void) printf(" = "); | |
daa6fd88 | 561 | } |
792dcd77 | 562 | tmp = my_localtime(&t); |
daa6fd88 | 563 | dumptime(tmp); |
792dcd77 UD |
564 | if (tmp != NULL) { |
565 | if (*abbr(tmp) != '\0') | |
566 | (void) printf(" %s", abbr(tmp)); | |
567 | if (v) { | |
568 | (void) printf(" isdst=%d", tmp->tm_isdst); | |
28f540f4 | 569 | #ifdef TM_GMTOFF |
792dcd77 | 570 | (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF); |
28f540f4 | 571 | #endif /* defined TM_GMTOFF */ |
792dcd77 | 572 | } |
28f540f4 RM |
573 | } |
574 | (void) printf("\n"); | |
c872f5cc UD |
575 | if (tmp != NULL && *abbr(tmp) != '\0') |
576 | abbrok(abbr(tmp), zone); | |
28f540f4 RM |
577 | } |
578 | ||
3ef4002b | 579 | static char * |
28f540f4 RM |
580 | abbr(tmp) |
581 | struct tm * tmp; | |
582 | { | |
3ef4002b UD |
583 | register char * result; |
584 | static char nada; | |
28f540f4 RM |
585 | |
586 | if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1) | |
587 | return &nada; | |
588 | result = tzname[tmp->tm_isdst]; | |
589 | return (result == NULL) ? &nada : result; | |
590 | } | |
daa6fd88 | 591 | |
792dcd77 UD |
592 | /* |
593 | ** The code below can fail on certain theoretical systems; | |
594 | ** it works on all known real-world systems as of 2004-12-30. | |
595 | */ | |
596 | ||
597 | static const char * | |
598 | tformat() | |
599 | { | |
600 | if (0.5 == (time_t) 0.5) { /* floating */ | |
601 | if (sizeof (time_t) > sizeof (double)) | |
602 | return "%Lg"; | |
603 | return "%g"; | |
604 | } | |
605 | if (0 > (time_t) -1) { /* signed */ | |
606 | if (sizeof (time_t) > sizeof (long)) | |
607 | return "%lld"; | |
608 | if (sizeof (time_t) > sizeof (int)) | |
609 | return "%ld"; | |
610 | return "%d"; | |
611 | } | |
612 | if (sizeof (time_t) > sizeof (unsigned long)) | |
613 | return "%llu"; | |
614 | if (sizeof (time_t) > sizeof (unsigned int)) | |
615 | return "%lu"; | |
616 | return "%u"; | |
617 | } | |
618 | ||
daa6fd88 UD |
619 | static void |
620 | dumptime(timeptr) | |
621 | register const struct tm * timeptr; | |
622 | { | |
623 | static const char wday_name[][3] = { | |
624 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | |
625 | }; | |
626 | static const char mon_name[][3] = { | |
627 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
628 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | |
629 | }; | |
630 | register const char * wn; | |
631 | register const char * mn; | |
792dcd77 UD |
632 | register int lead; |
633 | register int trail; | |
daa6fd88 | 634 | |
792dcd77 UD |
635 | if (timeptr == NULL) { |
636 | (void) printf("NULL"); | |
637 | return; | |
638 | } | |
daa6fd88 UD |
639 | /* |
640 | ** The packaged versions of localtime and gmtime never put out-of-range | |
641 | ** values in tm_wday or tm_mon, but since this code might be compiled | |
642 | ** with other (perhaps experimental) versions, paranoia is in order. | |
643 | */ | |
644 | if (timeptr->tm_wday < 0 || timeptr->tm_wday >= | |
645 | (int) (sizeof wday_name / sizeof wday_name[0])) | |
646 | wn = "???"; | |
647 | else wn = wday_name[timeptr->tm_wday]; | |
648 | if (timeptr->tm_mon < 0 || timeptr->tm_mon >= | |
649 | (int) (sizeof mon_name / sizeof mon_name[0])) | |
650 | mn = "???"; | |
651 | else mn = mon_name[timeptr->tm_mon]; | |
792dcd77 | 652 | (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ", |
daa6fd88 UD |
653 | wn, mn, |
654 | timeptr->tm_mday, timeptr->tm_hour, | |
792dcd77 UD |
655 | timeptr->tm_min, timeptr->tm_sec); |
656 | #define DIVISOR 10 | |
657 | trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR; | |
658 | lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + | |
659 | trail / DIVISOR; | |
660 | trail %= DIVISOR; | |
661 | if (trail < 0 && lead > 0) { | |
662 | trail += DIVISOR; | |
663 | --lead; | |
664 | } else if (lead < 0 && trail > 0) { | |
665 | trail -= DIVISOR; | |
666 | ++lead; | |
667 | } | |
668 | if (lead == 0) | |
669 | (void) printf("%d", trail); | |
670 | else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail)); | |
daa6fd88 | 671 | } |