zoneinfo.c - 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 zo… | |
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, t… | |
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.dl… | |
213 p += 4; | |
214 } | |
215 } |