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