_tzone.c (2869B)
1 #include <stdlib.h> 2 #include <string.h> 3 #include <time.h> 4 5 #include "../../libc.h" 6 7 #define TOKENSIZ 10 8 9 enum { 10 EOS, 11 NUM, 12 STR, 13 }; 14 15 enum { 16 GREGORIAN, 17 JULIAN, 18 }; 19 20 static char st[TOKENSIZ], ds[TOKENSIZ], tokstr[TOKENSIZ]; 21 static int tok; 22 23 char *_tzname[2] = { st, ds }; 24 time_t _tzstdoff, _tzdstoff; 25 time_t _tzstart, _tzend; 26 int _tzjulian; 27 28 static int 29 next(char *str) 30 { 31 int n, t; 32 static char *s; 33 34 if (str) 35 s = str; 36 37 switch (*s) { 38 case '0': 39 case '1': 40 case '2': 41 case '3': 42 case '4': 43 case '5': 44 case '6': 45 case '7': 46 case '8': 47 case '9': 48 n = strspn(s, "0123456789"); 49 t = NUM; 50 break; 51 case '+': 52 case '-': 53 case ':': 54 case ',': 55 n = 1; 56 t = *s; 57 break; 58 case '\0': 59 n = 0; 60 t = EOS; 61 break; 62 default: 63 n = strcspn(s, "+-0123456789"); 64 t = STR; 65 break; 66 } 67 68 if (n >= TOKENSIZ-1) 69 return -1; 70 memcpy(tokstr, s, n); 71 tokstr[n] = '\0'; 72 s += n; 73 74 return tok = t; 75 } 76 77 static int 78 accept(int c) 79 { 80 if (tok != c) 81 return 0; 82 return next(NULL); 83 } 84 85 static int 86 num(int max) 87 { 88 int n; 89 90 if (tok == EOS) 91 return 0; 92 if (tok != NUM) 93 return -1; 94 n = atoi(tokstr); 95 if (n < 0 || n > max) 96 return -1; 97 return n; 98 } 99 100 static long 101 offset(void) 102 { 103 int sign = 1; 104 int n; 105 long off; 106 107 if (tok == EOS) 108 return -1; 109 110 switch (tok) { 111 case '+': 112 sign = -1; 113 case '-': 114 next(NULL); 115 break; 116 default: 117 return -1; 118 } 119 120 if ((n = num(24)) < 0) 121 return -1; 122 off = n * SECHOUR; 123 next(NULL); 124 if (tok == EOS) 125 goto ret; 126 127 if (!accept(':')) 128 return -1; 129 if ((n = num(60)) < 0) 130 return -1; 131 off += n * SECMIN; 132 next(NULL); 133 if (tok == EOS) 134 goto ret; 135 136 if (!accept(':')) 137 return -1; 138 if ((n = num(60)) < 0) 139 return -1; 140 off += n; 141 next(NULL); 142 143 ret: 144 return sign * off; 145 } 146 147 static int 148 std(void) 149 { 150 time_t off; 151 152 if (tok != STR) 153 return 0; 154 strcpy(st, tokstr); 155 next(NULL); 156 157 if ((off = offset()) == -1) 158 return 0; 159 _tzstdoff = off; 160 161 return 1; 162 } 163 164 static int 165 dst(void) 166 { 167 time_t off; 168 169 if (tok != STR) 170 return 0; 171 strcpy(ds, tokstr); 172 next(NULL); 173 174 if ((off = offset()) == -1) 175 _tzdstoff = off; 176 else 177 _tzdstoff = _tzstdoff + SECHOUR; 178 179 return 1; 180 } 181 182 static int 183 yday(void) 184 { 185 int type, n; 186 187 if (tok == STR && !strcmp(tokstr, "J")) 188 type = JULIAN; 189 else if (tok == NUM) 190 type = GREGORIAN; 191 else 192 return -1; 193 194 switch (type) { 195 case JULIAN: 196 next(NULL); 197 n = num(365); 198 next(NULL); 199 if (n == 0) 200 return -1; 201 _tzjulian = 1; 202 break; 203 case GREGORIAN: 204 n = num(365); 205 next(NULL); 206 break; 207 } 208 209 return n; 210 } 211 212 static int 213 rule(void) 214 { 215 if (tok == EOS) 216 return 0; 217 if (!accept(',')) 218 return 0; 219 if ((_tzstart = yday()) == -1) 220 return 0; 221 if (!accept(',')) 222 return 0; 223 if ((_tzend = yday()) == -1) 224 return 0; 225 } 226 227 void 228 _tzset(void) 229 { 230 char *tz = getenv("TZ"); 231 int i; 232 233 _tzstdoff = _tzdstoff = (time_t) -1; 234 _tzstart = _tzend = (time_t) -1; 235 _tzjulian = 0; 236 237 if (!tz) 238 return; 239 next(tz); 240 241 if (!std()) 242 return; 243 if (!dst()) 244 return; 245 if (!rule()) 246 return; 247 }