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 MIT license used in the rest of the distribution.
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 if(zonefile==nil) {
122 if ((tmp=getenv("timezone"))!=nil) {
123 tzdata = readtzfile(tmp);
124 free(tmp);
125 goto havedata;
127 zonefile = "/etc/localtime";
129 tzdata = readtzfile(zonefile);
130 if (tzdata==nil)
131 return;
133 havedata:
134 if (strncmp("TZif", (char*)tzdata, 4)!=0)
135 goto errfree;
137 if (parsehead()==-1) {
138 errfree:
139 free(tzdata);
140 tzdata = nil;
141 z.timecnt = 0;
142 return;
146 static
147 tlong
148 gett4(uchar *p)
150 long l;
152 l = get4(p);
153 if (l<0)
154 return 0;
155 return l;
157 int
158 zonetinfo(Tinfo *ti, int i)
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;
169 int
170 zonelookuptinfo(Tinfo *ti, tlong t)
172 uchar *p;
173 int i;
174 tlong oldtt, tt;
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;
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;
193 return -1;
196 void
197 zonedump(int fd)
199 int i;
200 uchar *p;
201 tlong t;
202 Tinfo ti;
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;