Blob


1 #include <u.h>
2 #include <libc.h>
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"
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 */
20 uchar *ptime;
21 uchar *ptype;
22 uchar *ptt;
23 uchar *pzone;
24 } z;
26 static uchar *tzdata;
28 static
29 uchar*
30 readtzfile(char *file)
31 {
32 uchar *p;
33 int fd;
34 Dir *d;
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 }
61 static
62 long
63 get4(uchar *p)
64 {
65 return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
66 }
68 enum {
69 TTinfosz = 4+1+1,
70 };
72 static
73 int
74 parsehead(void)
75 {
76 uchar *p;
77 int ver;
79 ver = tzdata[4];
80 if (ver!=0)
81 if (ver!='2')
82 return -1;
84 p = tzdata + 4 + 1 + 15;
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 }
98 static
99 void
100 ttinfo(Tinfo *ti, int tti)
102 uchar *p;
103 int i;
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];
114 static
115 void
116 readtimezone(void)
118 char *tmp;
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;
128 zonefile = "/etc/localtime";
129 /* fall through */
130 case 0:
131 tzdata = readtzfile(zonefile);
133 if (tzdata==nil)
134 return;
136 if (strncmp("TZif", (char*)tzdata, 4)!=0)
137 goto errfree;
139 if (parsehead()==-1) {
140 errfree:
141 free(tzdata);
142 tzdata = nil;
143 z.timecnt = 0;
144 return;
148 static
149 tlong
150 gett4(uchar *p)
152 long l;
154 l = get4(p);
155 if (l<0)
156 return 0;
157 return l;
159 int
160 zonetinfo(Tinfo *ti, int i)
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;
171 int
172 zonelookuptinfo(Tinfo *ti, tlong t)
174 uchar *p;
175 int i;
176 tlong oldtt, tt;
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;
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;
195 return -1;
198 void
199 zonedump(int fd)
201 int i;
202 uchar *p;
203 tlong t;
204 Tinfo ti;
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;