scc

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

_tzone.c (3902B)


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