The zrd zone file reader
I am submitting the following short program for possible inclusion in the next release of tzcode. Zrd (zone reader) is a program that dumps the contents of a binary zoneinfo file. It does not depend on the existing library in any way (except that it calls gmtime, but any gmtime will do), and provides a direct view into the contents of zoneinfo files. I have dedicated the program to the public domain. ===== cut here ==== /* zrd - a routine to dump the contents of a binary timezone file * Define ZONEINFO to be the directory where the timezone files are, * typically "/usr/share/zoneinfo/". * This program requires only stdio and "gmtime". * Public domain source by John Cowan <cowan@ccil.org> */ # define ZONEINFO "/usr/share/zoneinfo/" # include <stdio.h> # include <time.h> /* A handy routine that converts from network order * (big-endian) 32-bit values to local order. * It tests what local order is, and is not the most * efficient conceivable routine, but works OK * for this application. */ long my_ntohl(long s) { long r; char *ps; char *pr; long test = 0x01020304; if ((char *)&test == "\0x01\0x02\0x03\0x04") return s; ps = (char *) &s; pr = (char *) &r; pr[0] = ps[3]; pr[1] = ps[2]; pr[2] = ps[1]; pr[3] = ps[0]; return r; } /* The header of a timezone file. * It is followed by: * tzh_timecnt 32-bit values representing time transitions; * tzh_timecnt 1-byte indexes into the time type table; * the time type table, containing tzh_typecnt "struct ttinfo" elements; * the leap-second table, containing tzh_leapcnt "struct ttleap" elements; * tzh.isstdcnt 1-byte flags indicating if transitions are * based on local standard time or local current ("wall") time * tz.isgmtcnt 1-byte flags indicating if transitions are * based on UTC or local time */ struct tzhead { char tzh_magic[4]; /* magic number */ char tzh_reserved[16]; /* reserved for future use */ long tzh_ttisgmtcnt; /* coded number of trans. time flags */ long tzh_ttisstdcnt; /* coded number of trans. time flags */ long tzh_leapcnt; /* coded number of leap seconds */ long tzh_timecnt; /* coded number of transition times */ long tzh_typecnt; /* coded number of local time types */ long tzh_charcnt; /* coded number of abbr. chars */ }; /* A time type object */ struct ttinfo { long tt_gmtoff; /* offset of this time type from UTC */ char tt_isdst; /* whether this is a DST time type */ char tt_abbrind; /* index into the timezone name abbreviations */ }; /* A leap second object */ struct ttleap { long tt_time; /* The leap second */ long tt_seconds; /* New value of TAI - UTC - 10 */ }; char tzfilename[1024]; /* Filename of the timezone file */ FILE *tz; /* File stream for reading the file */ struct tzhead t; /* The file's header */ char tzdata[4096]; /* The rest of the file */ long tzsize; /* Size of tzdata in use */ /* Pointers to different parts of tzdata */ long *timep; char *timetypep; char *xtypep; struct ttinfo *typep; char *charp; struct ttleap *leapp; char *stdp; char *gmtp; main(argc, argv) int argc; char *argv[]; { int i; long gmtoff; int gmtsign; long clock; struct tm *d; char magic[5]; /* Validate command line and load header */ if (argc != 2) { fprintf(stderr, "usage: %s continent/location\n", argv[0]); exit(1); } strcpy(tzfilename, ZONEINFO); strcat(tzfilename, argv[1]); tz = fopen(tzfilename, "rb"); if (!tz) { fprintf(stderr, "%s: %s unknown\n", argv[0], argv[1]); exit(1); } fread(&t, sizeof(t), 1, tz); /* Localize values in the header */ strncpy(magic, t.tzh_magic, 4); magic[4] = 0; t.tzh_ttisgmtcnt = my_ntohl(t.tzh_ttisgmtcnt); t.tzh_ttisstdcnt = my_ntohl(t.tzh_ttisstdcnt); t.tzh_leapcnt = my_ntohl(t.tzh_leapcnt); t.tzh_typecnt = my_ntohl(t.tzh_typecnt); t.tzh_timecnt = my_ntohl(t.tzh_timecnt); t.tzh_charcnt = my_ntohl(t.tzh_charcnt); /* Read the rest of the file */ tzsize = fread(&tzdata, 1, sizeof(tzdata), tz); fclose(tz); /* Set up pointers to various sections */ timep = (long *)tzdata; timetypep = (char *)(timep + t.tzh_timecnt); xtypep = timetypep + t.tzh_timecnt; charp = xtypep + 6 * t.tzh_typecnt; /* alignment problem */ leapp = (struct ttleap *)(charp + t.tzh_charcnt); stdp = (char *)(leapp + t.tzh_leapcnt); gmtp = stdp + t.tzh_ttisstdcnt; /* Check for invalid file size */ if (tzdata + tzsize != gmtp + t.tzh_ttisgmtcnt) fprintf(stderr, "Warning: file is %ld bytes, expected %ld\n", tzsize + sizeof(t), (gmtp + t.tzh_ttisgmtcnt) - tzdata); /* Print magic number */ if (magic[0]) printf("TZ magic number is \"%s\" (normally \"TZif\")\n", magic); /* Print transition time table */ printf("%ld transition times:\n", t.tzh_timecnt); for (i = 0; i < t.tzh_timecnt; i++) { clock = my_ntohl(timep[i]); /* printf("\tat %ld use type %d\n", clock, timetypep[i]); */ d = gmtime(&clock); printf("\tat %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d UTC (%ld) use type %d\n", d->tm_year + 1900, d->tm_mon+1, d->tm_mday, d->tm_hour, d->tm_min, d->tm_sec, clock, timetypep[i]); } /* Print time types table */ printf("%ld local time types:\n", t.tzh_typecnt); for (i = 0; i < t.tzh_typecnt; i++) { typep = (struct ttinfo *)(xtypep + i * 6); gmtoff = my_ntohl(typep->tt_gmtoff); if (gmtoff < 0) { gmtsign = -1; gmtoff = -gmtoff; } else if (gmtoff > 0) gmtsign = 1; else gmtsign = 0; printf("\ttype %d offset %2.2ld:%2.2ld:%2.2ld %s name (%d) %s", i, gmtsign*(gmtoff/3600), (gmtoff%3600)/60, gmtoff%60, typep->tt_isdst ? "isdst " : "notdst", typep->tt_abbrind, charp + typep->tt_abbrind); if (i < t.tzh_ttisstdcnt) printf(" %s", stdp[i] ? "std" : "wall"); if (i < t.tzh_ttisgmtcnt) printf(" %s", gmtp[i] ? "gmt" : "local"); printf("\n"); } /* Print time zone abbreviations */ printf("%ld bytes of abbreviations: [", t.tzh_charcnt); for (i = 0; i < t.tzh_charcnt; i++) if (charp[i]) putchar(charp[i]); else if (i != t.tzh_charcnt - 1) putchar('|'); printf("]\n"); /* Print leap second table */ printf("%ld leap second entries:\n", t.tzh_leapcnt); for (i = 0; i < t.tzh_leapcnt; i++) { clock = my_ntohl(leapp[i].tt_time); d = gmtime(&clock); printf("\tat %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d UTC (%ld), TAI - UTC = %ld seconds\n", d->tm_year + 1900, d->tm_mon+1, d->tm_mday, d->tm_hour, d->tm_min, d->tm_sec, clock, my_ntohl(leapp[i].tt_seconds) + 10); } /* Print counts of gmt/local and std/wall flags (contents * have already been printed) */ printf("%ld std/wall flags\n", t.tzh_ttisstdcnt); printf("%ld gmt/local flags\n", t.tzh_ttisgmtcnt); exit(0); } ===== cut here ===== -- He made the Legislature meet at one-horse John Cowan tank-towns out in the alfalfa belt, so that jcowan@reutershealth.com hardly nobody could get there and most of http://www.reutershealth.com the leaders would stay home and let him go http://www.ccil.org/~cowan to work and do things as he pleased. --Mencken, _Declaration of Independence_
participants (1)
-
John Cowan