1 #include <u.h>
2 #include <libc.h>
3
4 #define TZSIZE ((136*2)+10) /* 1970-2106; match tm2sec.c */
5
6 static void readtimezone(void);
7 static int rd_name(char**, char*);
8 static int rd_long(char**, long*);
9
10 static
11 struct
12 {
13 char stname[4];
14 char dlname[4];
15 long stdiff;
16 long dldiff;
17 ulong dlpairs[TZSIZE];
18 } timezone;
19
20 #define SEC2MIN 60UL
21 #define SEC2HOUR (60UL*SEC2MIN)
22 #define SEC2DAY (24UL*SEC2HOUR)
23
24 /*
25 * days per month plus days/year
26 */
27 static int dmsize[] =
28 {
29 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
30 };
31 static int ldmsize[] =
32 {
33 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
34 };
35
36 /*
37 * return the days/month for the given year
38 */
39 static int *
yrsize(int y)40 yrsize(int y)
41 {
42 if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
43 return ldmsize;
44 else
45 return dmsize;
46 }
47
48 /*
49 * compute seconds since Jan 1 1970 GMT
50 * and convert to our timezone.
51 */
52 long
tm2sec(Tm * tm)53 tm2sec(Tm *tm)
54 {
55 ulong secs;
56 int i, yday, year, *d2m;
57
58 if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0)
59 readtimezone();
60 secs = 0;
61
62 /*
63 * seconds per year
64 */
65 year = tm->year + 1900;
66 for(i = 1970; i < year; i++){
67 d2m = yrsize(i);
68 secs += d2m[0] * SEC2DAY;
69 }
70
71 /*
72 * if mday is set, use mon and mday to compute yday
73 */
74 if(tm->mday){
75 yday = 0;
76 d2m = yrsize(year);
77 for(i=0; i<tm->mon; i++)
78 yday += d2m[i+1];
79 yday += tm->mday-1;
80 }else{
81 yday = tm->yday;
82 }
83 secs += yday * SEC2DAY;
84
85 /*
86 * hours, minutes, seconds
87 */
88 secs += tm->hour * SEC2HOUR;
89 secs += tm->min * SEC2MIN;
90 secs += tm->sec;
91
92 /*
93 * Only handles zones mentioned in /env/timezone,
94 * but things get too ambiguous otherwise.
95 */
96 if(strcmp(tm->zone, timezone.stname) == 0)
97 secs -= timezone.stdiff;
98 else if(strcmp(tm->zone, timezone.dlname) == 0)
99 secs -= timezone.dldiff;
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, (long *)&timezone.dlpairs[i]))
128 goto error;
129 if(timezone.dlpairs[i] == 0)
130 return;
131 }
132 /* array too small for input */
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