scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

_tzone.c (3434B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 #include <time.h>
      5 
      6 #include "../../libc.h"
      7 
      8 #define TOKENSIZ 10
      9 
     10 enum {
     11 	EOS,
     12 	NUM,
     13 	STR,
     14 };
     15 
     16 enum {
     17 	GREGORIAN,
     18 	JULIAN,
     19 };
     20 
     21 int _daylight;
     22 char *_tzname[2];
     23 long _timezone, _dstzone;
     24 
     25 static int tok;
     26 static char tokstr[TOKENSIZ];
     27 
     28 static int julian, start, end;
     29 
     30 static int
     31 next(char *str)
     32 {
     33 	int n, t;
     34 	static char *s;
     35 
     36 	if (str)
     37 		s = str;
     38 
     39 	switch (*s) {
     40 	case '0':
     41 	case '1':
     42 	case '2':
     43 	case '3':
     44 	case '4':
     45 	case '5':
     46 	case '6':
     47 	case '7':
     48 	case '8':
     49 	case '9':
     50 		n = strspn(s, "0123456789");
     51 		t = NUM;
     52 		break;
     53 	case '+':
     54 	case '-':
     55 	case ':':
     56 	case ',':
     57 		n = 1;
     58 		t = *s;
     59 		break;
     60 	case '\0':
     61 		n = 0;
     62 		t = EOS;
     63 		break;
     64 	default:
     65 		n = strcspn(s, "+-0123456789");
     66 		t = STR;
     67 		break;
     68 	}
     69 
     70 	if (n >= TOKENSIZ-1)
     71 		return -1;
     72 	memcpy(tokstr, s, n);
     73 	tokstr[n] = '\0';
     74 	s += n;
     75 
     76 	return tok = t;
     77 }
     78 
     79 static int
     80 accept(int c)
     81 {
     82 	if (tok != c)
     83 		return 0;
     84 	return next(NULL);
     85 }
     86 
     87 static int
     88 num(int max)
     89 {
     90 	int n;
     91 
     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 	long off;
    104 	int n, sign = 1;
    105 
    106 	if (tok == EOS)
    107 		return -1;
    108 
    109 	switch (tok) {
    110 	case '-':
    111 		sign = -1;
    112 	case '+':
    113 		next(NULL);
    114 		break;
    115 	}
    116 
    117 	if ((n = num(24)) < 0)
    118 		return -1;
    119 	off = n * SECHOUR;
    120 	next(NULL);
    121 	if (tok == EOS)
    122 		goto ret;
    123 
    124 	if (!accept(':'))
    125 		goto ret;
    126 	if ((n = num(60)) < 0)
    127 		return -1;
    128 	off += n * SECMIN;
    129 	next(NULL);
    130 
    131 	if (!accept(':'))
    132 		goto ret;
    133 	if ((n = num(60)) < 0)
    134 		return -1;
    135 	off += n;
    136 	next(NULL);
    137 
    138  ret:
    139 	return sign * off;
    140 }
    141 
    142 static int
    143 std(void)
    144 {
    145 	long off;
    146 	char *name;
    147 
    148 	if ((name = _gmtoff(tokstr)) == NULL)
    149 		return 0;
    150 
    151 	next(NULL);
    152 	if ((off = offset()) == -1)
    153 		return 0;
    154 
    155 	_tzname[0] = name;
    156 	_timezone = off;
    157 
    158 	return 1;
    159 }
    160 
    161 static int
    162 dst(void)
    163 {
    164 	long off;
    165 	char *name;
    166 
    167 	if ((name = _gmtoff(tokstr)) == NULL)
    168 		return 0;
    169 	_tzname[1] = name;
    170 
    171 	next(NULL);
    172 	if ((off = offset()) == -1)
    173 		_dstzone = _timezone + SECHOUR;
    174 	else
    175 		_dstzone = off;
    176 
    177 	return _daylight = 1;
    178 }
    179 
    180 static int
    181 yday(void)
    182 {
    183 	int type, n;
    184 
    185 	if (tok == STR && !strcmp(tokstr, "J"))
    186 		type = JULIAN;
    187 	else if (tok == NUM)
    188 		type = GREGORIAN;
    189 	else
    190 		return -1;
    191 
    192 	switch (type) {
    193 	case JULIAN:
    194 		next(NULL);
    195 		n = num(365);
    196 		next(NULL);
    197 		if (n == 0)
    198 			return -1;
    199 		julian = 1;
    200 		break;
    201 	case GREGORIAN:
    202 		n = num(365);
    203 		next(NULL);
    204 		break;
    205 	}
    206 
    207 	return n;
    208 }
    209 
    210 static int
    211 rule(void)
    212 {
    213 	if (!accept(','))
    214 		return 0;
    215 	if ((start = yday()) == -1)
    216 		return 0;
    217 	if (!accept(','))
    218 		return 0;
    219 	if ((end = yday()) == -1)
    220 		return 0;
    221 }
    222 
    223 void
    224 _tzset(void)
    225 {
    226 	static char *tz;
    227 	static char cache[80];
    228 	char *s = getenv("TZ");
    229 
    230 	if (s) {
    231 		if (tz && strcmp(s, tz) == 0)
    232 			return;
    233 		snprintf(cache, sizeof(cache), "%s", s);
    234 		tz = cache;
    235 	}
    236 
    237 	start = end = -1;
    238 
    239 	if (!s)
    240 		goto adjust;
    241 
    242 	if (next(s) == EOS)
    243 		goto error;
    244 
    245 	if (!std())
    246 		goto error;
    247 	if (tok == EOS)
    248 		goto adjust;
    249 
    250 	if (!dst())
    251 		goto error;
    252 	if (tok == EOS)
    253 		goto adjust;
    254 
    255 	if (!rule())
    256 		goto error;
    257 
    258 adjust:
    259 	if (!_daylight) {
    260 		_tzname[1] = _tzname[0];
    261 		_dstzone = _timezone;
    262 	}
    263 
    264 	return;
    265 
    266 error:
    267 	_daylight = 0;
    268 	_tzname[1] = _tzname[0] = "UTC";
    269 	_timezone = _dstzone = 0;
    270 	start = end = -1;
    271 	julian = 0;
    272 }
    273 
    274 int
    275 _isdst(struct tm *tm)
    276 {
    277 	int yday;
    278 
    279 	if (!_daylight)
    280 		return 0;
    281 
    282 	yday = tm->tm_yday;
    283 
    284 	if (julian && yday+1 < 60 || FEBDAYS(tm->tm_year) < 29)
    285 		yday++;
    286 	if (yday >= start && yday <= end && tm->tm_hour >= 2)
    287 		return 1;
    288 	return 0;
    289 }