9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

zoneinfo.c (3092B)


      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 terms of the Lucent Public License 1.02.
     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 	switch (zonefile==nil) {
    122 	default:
    123 		if ((tmp=getenv("timezone"))!=nil) {
    124 			tzdata = readtzfile(tmp);
    125 			free(tmp);
    126 			break;
    127 		}
    128 		zonefile = "/etc/localtime";
    129 		/* fall through */
    130 	case 0:
    131 		tzdata = readtzfile(zonefile);
    132 	}
    133 	if (tzdata==nil)
    134 		return;
    135 
    136 	if (strncmp("TZif", (char*)tzdata, 4)!=0)
    137 		goto errfree;
    138 
    139 	if (parsehead()==-1) {
    140 	errfree:
    141 		free(tzdata);
    142 		tzdata = nil;
    143 		z.timecnt = 0;
    144 		return;
    145 	}
    146 }
    147 
    148 static
    149 tlong
    150 gett4(uchar *p)
    151 {
    152 	long l;
    153 
    154 	l = get4(p);
    155 	if (l<0)
    156 		return 0;
    157 	return l;
    158 }
    159 int
    160 zonetinfo(Tinfo *ti, int i)
    161 {
    162 	if (tzdata==nil)
    163 		readtimezone();
    164 	if (i<0 || i>=z.timecnt)
    165 		return -1;
    166 	ti->t = gett4(z.ptime + 4*i);
    167 	ttinfo(ti, i);
    168 	return i;
    169 }
    170 
    171 int
    172 zonelookuptinfo(Tinfo *ti, tlong t)
    173 {
    174 	uchar *p;
    175 	int	i;
    176 	tlong	oldtt, tt;
    177 
    178 	if (tzdata==nil)
    179 		readtimezone();
    180 	oldtt = 0;
    181 	p = z.ptime;
    182 	for (i=0; i<z.timecnt; i++) {
    183 		tt = gett4(p);
    184 		if (t<tt)
    185 			break;
    186 		oldtt = tt;
    187 		p += 4;
    188 	}
    189 	if (i>0) {
    190 		ttinfo(ti, i-1);
    191 		ti->t = oldtt;
    192 //		fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
    193 		return i-1;
    194 	}
    195 	return -1;
    196 }
    197 
    198 void
    199 zonedump(int fd)
    200 {
    201 	int	i;
    202 	uchar *p;
    203 	tlong t;
    204 	Tinfo ti;
    205 
    206 	if (tzdata==nil)
    207 		readtimezone();
    208 	p = z.ptime;
    209 	for (i=0; i<z.timecnt; i++) {
    210 		t = gett4(p);
    211 		ttinfo(&ti, i);
    212 		fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
    213 		p += 4;
    214 	}
    215 }