scc

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

mktime.c (1888B)


      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 	if (tm->tm_year < 0)
     51 		return 0;
     52 
     53 	day = tm->tm_mday;
     54 	yday = 0;
     55 	year = MINYEAR + tm->tm_year;
     56 
     57 	if (year > _MAXYEAR)
     58 		return 0;
     59 
     60 	_daysmon[FEB] = FEBDAYS(year);
     61 
     62 	/*
     63 	 * Normalize mday so that it doesn't over/underflow month
     64 	 * Normalize month so that it doesn't over/underflow year
     65 	 */
     66 	for (mon = tm->tm_mon; day < 1; --mon) {
     67 		if (mon == JAN) {
     68 			if (year == MINYEAR)
     69 				return 0;
     70 			year--;
     71 			_daysmon[FEB] = _febdays(year);
     72 			mon = DEC+1;
     73 		}
     74 		day += _daysmon[mon-1];
     75 	}
     76 
     77 	for (; day > _daysmon[mon]; ++mon) {
     78 		day -= _daysmon[mon];
     79 		if (mon == DEC) {
     80 			if (year == _MAXYEAR)
     81 				return 0;
     82 			year++;
     83 			_daysmon[FEB] = _febdays(year);
     84 			mon = JAN-1;
     85 		}
     86 	}
     87 
     88 	for (int i = 0; i < mon; ++i)
     89 		yday += _daysmon[i];
     90 
     91 	tm->tm_mon = mon;
     92 	tm->tm_year = year - MINYEAR;
     93 	tm->tm_mday = day;
     94 	tm->tm_yday = yday + day - 1;
     95 	tm->tm_wday = (_newyear(tm->tm_year) + tm->tm_yday) % 7;
     96 	tm->tm_isdst = 0;
     97 	return 1;
     98 }
     99 
    100 time_t
    101 mktime(struct tm *tm)
    102 {
    103 	if (!normalize(tm))
    104 		return -1;
    105 	return _systime(tm);
    106 }