plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

zoneinfo.c (3065B)


      1 #include <u.h>
      2 #include <libc.h>
      3 
      4 /*
      5  * Access local time entries of zoneinfo files.
      6  * Formats 0 and 2 are supported, and 4-byte timestamps
      7  *
      8  * Copyright © 2008 M. Teichgräber
      9  * Contributed under the MIT license used in the rest of the distribution.
     10  */
     11 #include "zoneinfo.h"
     12 
     13 static
     14 struct Zoneinfo
     15 {
     16 	int	timecnt;		/* # of transition times */
     17 	int	typecnt;		/* # of local time types */
     18 	int	charcnt;		/* # of characters of time zone abbreviation strings */
     19 
     20 	uchar *ptime;
     21 	uchar *ptype;
     22 	uchar *ptt;
     23 	uchar *pzone;
     24 } z;
     25 
     26 static uchar *tzdata;
     27 
     28 static
     29 uchar*
     30 readtzfile(char *file)
     31 {
     32 	uchar *p;
     33 	int fd;
     34 	Dir *d;
     35 
     36 	fd = open(file, OREAD);
     37 	if (fd<0)
     38 		return nil;
     39 	d = dirfstat(fd);
     40 	if (d==nil)
     41 		return nil;
     42 	p = malloc(d->length);
     43 	if (p!=nil)
     44 		readn(fd, p, d->length);
     45 	free(d);
     46 	close(fd);
     47 	return p;
     48 }
     49 static char *zonefile;
     50 void
     51 tzfile(char *f)
     52 {
     53 	if (tzdata!=nil) {
     54 		free(tzdata);
     55 		tzdata = nil;
     56 	}
     57 	z.timecnt = 0;
     58 	zonefile = f;
     59 }
     60 
     61 static
     62 long
     63 get4(uchar *p)
     64 {
     65 	return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
     66 }
     67 
     68 enum {
     69 	TTinfosz	= 4+1+1,
     70 };
     71 
     72 static
     73 int
     74 parsehead(void)
     75 {
     76 	uchar *p;
     77 	int	ver;
     78 
     79 	ver = tzdata[4];
     80 	if (ver!=0)
     81 	if (ver!='2')
     82 		return -1;
     83 
     84 	p = tzdata + 4 + 1 + 15;
     85 
     86 	z.timecnt = get4(p+3*4);
     87 	z.typecnt = get4(p+4*4);
     88 	if (z.typecnt==0)
     89 		return -1;
     90 	z.charcnt = get4(p+5*4);
     91 	z.ptime = p+6*4;
     92 	z.ptype = z.ptime + z.timecnt*4;
     93 	z.ptt = z.ptype + z.timecnt;
     94 	z.pzone = z.ptt + z.typecnt*TTinfosz;
     95 	return 0;
     96 }
     97 
     98 static
     99 void
    100 ttinfo(Tinfo *ti, int tti)
    101 {
    102 	uchar *p;
    103 	int	i;
    104 
    105 	i = z.ptype[tti];
    106 	assert(i<z.typecnt);
    107 	p = z.ptt + i*TTinfosz;
    108 	ti->tzoff = get4(p);
    109 	ti->dlflag = p[4];
    110 	assert(p[5]<z.charcnt);
    111 	ti->zone = (char*)z.pzone + p[5];
    112 }
    113 
    114 static
    115 void
    116 readtimezone(void)
    117 {
    118 	char *tmp;
    119 
    120 	z.timecnt = 0;
    121 	if(zonefile==nil) {
    122 		if ((tmp=getenv("timezone"))!=nil) {
    123 			tzdata = readtzfile(tmp);
    124 			free(tmp);
    125 			goto havedata;
    126 		}
    127 		zonefile = "/etc/localtime";
    128 	}
    129 	tzdata = readtzfile(zonefile);
    130 	if (tzdata==nil)
    131 		return;
    132 
    133 havedata:
    134 	if (strncmp("TZif", (char*)tzdata, 4)!=0)
    135 		goto errfree;
    136 
    137 	if (parsehead()==-1) {
    138 	errfree:
    139 		free(tzdata);
    140 		tzdata = nil;
    141 		z.timecnt = 0;
    142 		return;
    143 	}
    144 }
    145 
    146 static
    147 tlong
    148 gett4(uchar *p)
    149 {
    150 	long l;
    151 
    152 	l = get4(p);
    153 	if (l<0)
    154 		return 0;
    155 	return l;
    156 }
    157 int
    158 zonetinfo(Tinfo *ti, int i)
    159 {
    160 	if (tzdata==nil)
    161 		readtimezone();
    162 	if (i<0 || i>=z.timecnt)
    163 		return -1;
    164 	ti->t = gett4(z.ptime + 4*i);
    165 	ttinfo(ti, i);
    166 	return i;
    167 }
    168 
    169 int
    170 zonelookuptinfo(Tinfo *ti, tlong t)
    171 {
    172 	uchar *p;
    173 	int	i;
    174 	tlong	oldtt, tt;
    175 
    176 	if (tzdata==nil)
    177 		readtimezone();
    178 	oldtt = 0;
    179 	p = z.ptime;
    180 	for (i=0; i<z.timecnt; i++) {
    181 		tt = gett4(p);
    182 		if (t<tt)
    183 			break;
    184 		oldtt = tt;
    185 		p += 4;
    186 	}
    187 	if (i>0) {
    188 		ttinfo(ti, i-1);
    189 		ti->t = oldtt;
    190 //		fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
    191 		return i-1;
    192 	}
    193 	return -1;
    194 }
    195 
    196 void
    197 zonedump(int fd)
    198 {
    199 	int	i;
    200 	uchar *p;
    201 	tlong t;
    202 	Tinfo ti;
    203 
    204 	if (tzdata==nil)
    205 		readtimezone();
    206 	p = z.ptime;
    207 	for (i=0; i<z.timecnt; i++) {
    208 		t = gett4(p);
    209 		ttinfo(&ti, i);
    210 		fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
    211 		p += 4;
    212 	}
    213 }