scc

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

mktime.c (2466B)


      1 #include <limits.h>
      2 #include <time.h>
      3 
      4 #include "../libc.h"
      5 
      6 #undef mktime
      7 
      8 static int
      9 norm(int *val, int *next, int max)
     10 {
     11 	int v = *val, n = *next, d;
     12 
     13 	if (v < 0) {
     14 		d = -v / max + 1;
     15 		v += d * max;
     16 		if (n > INT_MAX - d)
     17 			return 0;
     18 		n -= d;
     19 	}
     20 	if (v >= max) {
     21 		d = v / max;
     22 		v -= d * max;
     23 		if (n < INT_MIN + d)
     24 			return 0;
     25 		n += d;
     26 	}
     27 
     28 	*val = v;
     29 	*next = n;
     30 	return 1;
     31 }
     32 
     33 static int
     34 normalize(struct tm *tm)
     35 {
     36 	int mon, day, year, yday;
     37 
     38 	/*
     39 	 * Normalize sec so that it doesn't over/underflow min
     40 	 * Normalize min so that it doesn't over/underflow hour
     41 	 * Normalize hour so that it doesn't over/underflow mday
     42 	 * Normalize month so that it doesn't over/underflow year
     43 	 */
     44 	if (!norm(&tm->tm_sec, &tm->tm_min, 60)
     45 	|| !norm(&tm->tm_min, &tm->tm_hour, 60)
     46 	|| !norm(&tm->tm_hour, &tm->tm_mday, 24)
     47 	|| !norm(&tm->tm_mon, &tm->tm_year, 12))
     48 		return 0;
     49 
     50 	day = tm->tm_mday;
     51 	yday = 0;
     52 	year = BASEYEAR + tm->tm_year;
     53 
     54 	_daysmon[FEB] = FEBDAYS(year);
     55 
     56 	/*
     57 	 * Normalize mday so that it doesn't over/underflow month
     58 	 * Normalize month so that it doesn't over/underflow year
     59 	 */
     60 	for (mon = tm->tm_mon; day < 1; --mon) {
     61 		if (mon == JAN) {
     62 			if (year == INT_MIN)
     63 				return 0;
     64 			year--;
     65 			_daysmon[FEB] = FEBDAYS(year);
     66 			mon = DEC+1;
     67 		}
     68 		day += _daysmon[mon-1];
     69 	}
     70 
     71 	for (; day > _daysmon[mon]; ++mon) {
     72 		day -= _daysmon[mon];
     73 		if (mon == DEC) {
     74 			if (year == INT_MAX)
     75 				return 0;
     76 			year++;
     77 			_daysmon[FEB] = FEBDAYS(year);
     78 			mon = JAN-1;
     79 		}
     80 	}
     81 
     82 	if (year < INT_MIN + BASEYEAR)
     83 		return 0;
     84 	year -= BASEYEAR;
     85 
     86 	if (year > _MAXYEAR || year < _MINYEAR)
     87 		return 0;
     88 
     89 	for (int i = 0; i < mon; ++i)
     90 		yday += _daysmon[i];
     91 
     92 	tm->tm_mon = mon;
     93 	tm->tm_year = year;
     94 	tm->tm_mday = day;
     95 	tm->tm_yday = yday + day - 1;
     96 	tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7;
     97 
     98 	return 1;
     99 }
    100 
    101 time_t
    102 mktime(struct tm *tm)
    103 {
    104 	time_t t;
    105 	int i, year;
    106 	struct tm *aux;
    107 
    108 	if (!normalize(tm))
    109 		return -1;
    110 
    111 	t = 0;
    112 	year = tm->tm_year + BASEYEAR;
    113 	for (i = EPOCH; i < year; ++i)
    114 		t += _daysyear(i) * SECDAY;
    115 	for (i = 0; i < tm->tm_mon; ++i)
    116 		t += _daysmon[i] * SECDAY;
    117 
    118 	t += tm->tm_sec;
    119 	t += tm->tm_min * SECMIN;
    120 	t += tm->tm_hour * SECHOUR;
    121 	t += (tm->tm_mday-1) * SECDAY;
    122 	aux = localtime(&t);
    123 
    124 	if (tm->tm_isdst == -1)
    125 		tm->tm_isdst = aux->tm_isdst;
    126 
    127 	if (tm->tm_isdst == 1) {
    128 		tm->tm_zone = _tzname[1];
    129 		tm->tm_gmtoff = _dstzone;
    130 	} else {
    131 		tm->tm_zone = _tzname[0];
    132 		tm->tm_gmtoff = _timezone;
    133 	}
    134 	t += tm->tm_gmtoff;
    135 
    136 	return t;
    137 }