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