1 #include <u.h>
2 #include <libc.h>
3
4 #define TZSIZE 150
5 static void readtimezone(void);
6 static int rd_name(char**, char*);
7 static int rd_long(char**, long*);
8 static
9 struct
10 {
11 char stname[4];
12 char dlname[4];
13 long stdiff;
14 long dldiff;
15 long dlpairs[TZSIZE];
16 } timezone;
17
18 #define SEC2MIN 60L
19 #define SEC2HOUR (60L*SEC2MIN)
20 #define SEC2DAY (24L*SEC2HOUR)
21
22 /*
23 * days per month plus days/year
24 */
25 static int dmsize[] =
26 {
27 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
28 };
29 static int ldmsize[] =
30 {
31 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
32 };
33
34 /*
35 * return the days/month for the given year
36 */
37 static int *
yrsize(int y)38 yrsize(int y)
39 {
40 if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
41 return ldmsize;
42 else
43 return dmsize;
44 }
45
46 /*
47 * compute seconds since Jan 1 1970 GMT
48 * and convert to our timezone.
49 */
50 long
tm2sec(Tm * tm)51 tm2sec(Tm *tm)
52 {
53 long secs;
54 int i, yday, year, *d2m;
55
56 if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0)
57 readtimezone();
58 secs = 0;
59
60 /*
61 * seconds per year
62 */
63 year = tm->year + 1900;
64 for(i = 1970; i < year; i++){
65 d2m = yrsize(i);
66 secs += d2m[0] * SEC2DAY;
67 }
68
69 /*
70 * if mday is set, use mon and mday to compute yday
71 */
72 if(tm->mday){
73 yday = 0;
74 d2m = yrsize(year);
75 for(i=0; i<tm->mon; i++)
76 yday += d2m[i+1];
77 yday += tm->mday-1;
78 }else{
79 yday = tm->yday;
80 }
81 secs += yday * SEC2DAY;
82
83 /*
84 * hours, minutes, seconds
85 */
86 secs += tm->hour * SEC2HOUR;
87 secs += tm->min * SEC2MIN;
88 secs += tm->sec;
89
90 /*
91 * Only handles zones mentioned in /env/timezone,
92 * but things get too ambiguous otherwise.
93 */
94 if(strcmp(tm->zone, timezone.stname) == 0)
95 secs -= timezone.stdiff;
96 else if(strcmp(tm->zone, timezone.dlname) == 0)
97 secs -= timezone.dldiff;
98 if(secs < 0)
99 secs = 0;
100 return secs;
101 }
102
103 static
104 void
readtimezone(void)105 readtimezone(void)
106 {
107 char buf[TZSIZE*11+30], *p;
108 int i;
109
110 memset(buf, 0, sizeof(buf));
111 i = open("/env/timezone", 0);
112 if(i < 0)
113 goto error;
114 if(read(i, buf, sizeof(buf)) >= sizeof(buf))
115 goto error;
116 close(i);
117 p = buf;
118 if(rd_name(&p, timezone.stname))
119 goto error;
120 if(rd_long(&p, &timezone.stdiff))
121 goto error;
122 if(rd_name(&p, timezone.dlname))
123 goto error;
124 if(rd_long(&p, &timezone.dldiff))
125 goto error;
126 for(i=0; i<TZSIZE; i++) {
127 if(rd_long(&p, &timezone.dlpairs[i]))
128 goto error;
129 if(timezone.dlpairs[i] == 0)
130 return;
131 }
132
133 error:
134 timezone.stdiff = 0;
135 strcpy(timezone.stname, "GMT");
136 timezone.dlpairs[0] = 0;
137 }
138
139 static int
rd_name(char ** f,char * p)140 rd_name(char **f, char *p)
141 {
142 int c, i;
143
144 for(;;) {
145 c = *(*f)++;
146 if(c != ' ' && c != '\n')
147 break;
148 }
149 for(i=0; i<3; i++) {
150 if(c == ' ' || c == '\n')
151 return 1;
152 *p++ = c;
153 c = *(*f)++;
154 }
155 if(c != ' ' && c != '\n')
156 return 1;
157 *p = 0;
158 return 0;
159 }
160
161 static int
rd_long(char ** f,long * p)162 rd_long(char **f, long *p)
163 {
164 int c, s;
165 long l;
166
167 s = 0;
168 for(;;) {
169 c = *(*f)++;
170 if(c == '-') {
171 s++;
172 continue;
173 }
174 if(c != ' ' && c != '\n')
175 break;
176 }
177 if(c == 0) {
178 *p = 0;
179 return 0;
180 }
181 l = 0;
182 for(;;) {
183 if(c == ' ' || c == '\n')
184 break;
185 if(c < '0' || c > '9')
186 return 1;
187 l = l*10 + c-'0';
188 c = *(*f)++;
189 }
190 if(s)
191 l = -l;
192 *p = l;
193 return 0;
194 }
195