diff options
author | Michael Teichgräber <devnull@localhost> | 2008-07-09 08:27:22 -0400 |
---|---|---|
committer | Michael Teichgräber <devnull@localhost> | 2008-07-09 08:27:22 -0400 |
commit | f35a04866f298aa4b0fa6846da0c0187751ce9b2 (patch) | |
tree | aa4b87fbc1f71b246c9c8975abb0cab936f7ef2b /src/lib9/zoneinfo.c | |
parent | 1cccddd6b3fb4a90641b8d05dc0bed618380074c (diff) | |
download | plan9port-f35a04866f298aa4b0fa6846da0c0187751ce9b2.tar.gz plan9port-f35a04866f298aa4b0fa6846da0c0187751ce9b2.tar.bz2 plan9port-f35a04866f298aa4b0fa6846da0c0187751ce9b2.zip |
lib9: rewrite date routines to use /usr/share/zoneinfo directly
Diffstat (limited to 'src/lib9/zoneinfo.c')
-rw-r--r-- | src/lib9/zoneinfo.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/lib9/zoneinfo.c b/src/lib9/zoneinfo.c new file mode 100644 index 00000000..f49d8120 --- /dev/null +++ b/src/lib9/zoneinfo.c @@ -0,0 +1,215 @@ +#include <u.h> +#include <libc.h> + +/* + * Access local time entries of zoneinfo files. + * Formats 0 and 2 are supported, and 4-byte timestamps + * + * Copyright © 2008 M. Teichgräber + * Contributed under the terms of the Lucent Public License 1.02. + */ +#include "zoneinfo.h" + +static +struct Zoneinfo +{ + int timecnt; /* # of transition times */ + int typecnt; /* # of local time types */ + int charcnt; /* # of characters of time zone abbreviation strings */ + + uchar *ptime; + uchar *ptype; + uchar *ptt; + uchar *pzone; +} z; + +static uchar *tzdata; + +static +uchar* +readtzfile(char *file) +{ + uchar *p; + int fd; + Dir *d; + + fd = open(file, OREAD); + if (fd<0) + return nil; + d = dirfstat(fd); + if (d==nil) + return nil; + p = malloc(d->length); + if (p!=nil) + readn(fd, p, d->length); + free(d); + close(fd); + return p; +} +static char *zonefile; +void +tzfile(char *f) +{ + if (tzdata!=nil) { + free(tzdata); + tzdata = nil; + } + z.timecnt = 0; + zonefile = f; +} + +static +long +get4(uchar *p) +{ + return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; +} + +enum { + TTinfosz = 4+1+1, +}; + +static +int +parsehead(void) +{ + uchar *p; + int ver; + + ver = tzdata[4]; + if (ver!=0) + if (ver!='2') + return -1; + + p = tzdata + 4 + 1 + 15; + + z.timecnt = get4(p+3*4); + z.typecnt = get4(p+4*4); + if (z.typecnt==0) + return -1; + z.charcnt = get4(p+5*4); + z.ptime = p+6*4; + z.ptype = z.ptime + z.timecnt*4; + z.ptt = z.ptype + z.timecnt; + z.pzone = z.ptt + z.typecnt*TTinfosz; + return 0; +} + +static +void +ttinfo(Tinfo *ti, int tti) +{ + uchar *p; + int i; + + i = z.ptype[tti]; + assert(i<z.typecnt); + p = z.ptt + i*TTinfosz; + ti->tzoff = get4(p); + ti->dlflag = p[4]; + assert(p[5]<z.charcnt); + ti->zone = (char*)z.pzone + p[5]; +} + +static +void +readtimezone(void) +{ + char *tmp; + + z.timecnt = 0; + switch (zonefile==nil) { + default: + if ((tmp=getenv("timezone"))!=nil) { + tzdata = readtzfile(tmp); + free(tmp); + break; + } + zonefile = "/etc/localtime"; + /* fall through */ + case 0: + tzdata = readtzfile(zonefile); + } + if (tzdata==nil) + return; + + if (strncmp("TZif", (char*)tzdata, 4)!=0) + goto errfree; + + if (parsehead()==-1) { + errfree: + free(tzdata); + tzdata = nil; + z.timecnt = 0; + return; + } +} + +static +tlong +gett4(uchar *p) +{ + long l; + + l = get4(p); + if (l<0) + return 0; + return l; +} +int +zonetinfo(Tinfo *ti, int i) +{ + if (tzdata==nil) + readtimezone(); + if (i<0 || i>=z.timecnt) + return -1; + ti->t = gett4(z.ptime + 4*i); + ttinfo(ti, i); + return i; +} + +int +zonelookuptinfo(Tinfo *ti, tlong t) +{ + uchar *p; + int i; + tlong oldtt, tt; + + if (tzdata==nil) + readtimezone(); + oldtt = 0; + p = z.ptime; + for (i=0; i<z.timecnt; i++) { + tt = gett4(p); + if (t<tt) + break; + oldtt = tt; + p += 4; + } + if (i>0) { + ttinfo(ti, i-1); + ti->t = oldtt; +// fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone); + return i-1; + } + return -1; +} + +void +zonedump(int fd) +{ + int i; + uchar *p; + tlong t; + Tinfo ti; + + if (tzdata==nil) + readtimezone(); + p = z.ptime; + for (i=0; i<z.timecnt; i++) { + t = gett4(p); + ttinfo(&ti, i); + fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone); + p += 4; + } +} |