scc

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

mktime.c (2572B)


      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 *ptm)
    103 {
    104 	time_t t;
    105 	long off;
    106 	char *name;
    107 	int i, year;
    108 	struct tm tm;
    109 
    110 	tm = *ptm;
    111 	if (!normalize(&tm))
    112 		return -1;
    113 
    114 	t = 0;
    115 	i = EPOCH;
    116 	year = tm.tm_year + BASEYEAR;
    117 	if (year >= EPOCH) {
    118 		while (i < year)
    119 			t += _daysyear(i++) * SECDAY;
    120 	} else {
    121 		while (i > year)
    122 			t -= _daysyear(--i) * SECDAY;
    123 	}
    124 
    125 	for (i = 0; i < tm.tm_mon; ++i)
    126 		t += _daysmon[i] * SECDAY;
    127 
    128 	t += tm.tm_sec;
    129 	t += tm.tm_min * SECMIN;
    130 	t += tm.tm_hour * SECHOUR;
    131 	t += (tm.tm_mday-1) * SECDAY;
    132 
    133 	_tzset();
    134 	if (tm.tm_isdst == 0 || tm.tm_isdst < 0 && !_isdst(&tm))
    135 		off = _timezone;
    136 	else
    137 		off = _dstzone;
    138 
    139 	if (off > 0 && t > _TIME_MAX - off
    140 	||  off < 0 && t < _TIME_MIN - off) {
    141 		return -1;
    142 	}
    143 	t += off;
    144 	*ptm = *localtime(&t);
    145 
    146 	return t;
    147 }