File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / libntp / mktime.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 5 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * Copyright (c) 1987, 1989 Regents of the University of California.
    3:  * All rights reserved.
    4:  *
    5:  * This code is derived from software contributed to Berkeley by
    6:  * Arthur David Olson of the National Cancer Institute.
    7:  *
    8:  * Redistribution and use in source and binary forms, with or without
    9:  * modification, are permitted provided that the following conditions
   10:  * are met:
   11:  * 1. Redistributions of source code must retain the above copyright
   12:  *    notice, this list of conditions and the following disclaimer.
   13:  * 2. Redistributions in binary form must reproduce the above copyright
   14:  *    notice, this list of conditions and the following disclaimer in the
   15:  *    documentation and/or other materials provided with the distribution.
   16:  * 3. All advertising materials mentioning features or use of this software
   17:  *    must display the following acknowledgement:
   18:  *	This product includes software developed by the University of
   19:  *	California, Berkeley and its contributors.
   20:  * 4. Neither the name of the University nor the names of its contributors
   21:  *    may be used to endorse or promote products derived from this software
   22:  *    without specific prior written permission.
   23:  *
   24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34:  * SUCH DAMAGE.  */
   35: 
   36: /*static char *sccsid = "from: @(#)ctime.c	5.26 (Berkeley) 2/23/91";*/
   37: 
   38: /*
   39:  * This implementation of mktime is lifted straight from the NetBSD (BSD 4.4)
   40:  * version.  I modified it slightly to divorce it from the internals of the
   41:  * ctime library.  Thus this version can't use details of the internal
   42:  * timezone state file to figure out strange unnormalized struct tm values,
   43:  * as might result from someone doing date math on the tm struct then passing
   44:  * it to mktime.
   45:  *
   46:  * It just does as well as it can at normalizing the tm input, then does a
   47:  * binary search of the time space using the system's localtime() function.
   48:  *
   49:  * The original binary search was defective in that it didn't consider the
   50:  * setting of tm_isdst when comparing tm values, causing the search to be
   51:  * flubbed for times near the dst/standard time changeover.  The original
   52:  * code seems to make up for this by grubbing through the timezone info
   53:  * whenever the binary search barfed.  Since I don't have that luxury in
   54:  * portable code, I have to take care of tm_isdst in the comparison routine.
   55:  * This requires knowing how many minutes offset dst is from standard time.
   56:  *
   57:  * So, if you live somewhere in the world where dst is not 60 minutes offset,
   58:  * and your vendor doesn't supply mktime(), you'll have to edit this variable
   59:  * by hand.  Sorry about that.
   60:  */
   61: 
   62: #include "ntp_machine.h"
   63: 
   64: #if !defined(HAVE_MKTIME) || !defined(HAVE_TIMEGM)
   65: 
   66: #if SIZEOF_TIME_T >= 8
   67: #error libntp supplied mktime()/timegm() do not support 64-bit time_t
   68: #endif
   69: 
   70: #ifndef DSTMINUTES
   71: #define DSTMINUTES 60
   72: #endif
   73: 
   74: #define FALSE 0
   75: #define TRUE 1
   76: 
   77: /* some constants from tzfile.h */
   78: #define SECSPERMIN      60
   79: #define MINSPERHOUR     60
   80: #define HOURSPERDAY     24
   81: #define DAYSPERWEEK     7
   82: #define DAYSPERNYEAR    365
   83: #define DAYSPERLYEAR    366
   84: #define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
   85: #define SECSPERDAY      ((long) SECSPERHOUR * HOURSPERDAY)
   86: #define MONSPERYEAR     12
   87: #define TM_YEAR_BASE    1900
   88: #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
   89: 
   90: static int	mon_lengths[2][MONSPERYEAR] = {
   91: 	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
   92: 	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
   93: };
   94: 
   95: static int	year_lengths[2] = {
   96: 	DAYSPERNYEAR, DAYSPERLYEAR
   97: };
   98: 
   99: /*
  100: ** Adapted from code provided by Robert Elz, who writes:
  101: **	The "best" way to do mktime I think is based on an idea of Bob
  102: **	Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  103: **	It does a binary search of the time_t space.  Since time_t's are
  104: **	just 32 bits, its a max of 32 iterations (even at 64 bits it
  105: **	would still be very reasonable).
  106: */
  107: 
  108: #ifndef WRONG
  109: #define WRONG	(-1)
  110: #endif /* !defined WRONG */
  111: 
  112: static void
  113: normalize(
  114: 	int * tensptr,
  115: 	int * unitsptr,
  116: 	int	base
  117: 	)
  118: {
  119: 	if (*unitsptr >= base) {
  120: 		*tensptr += *unitsptr / base;
  121: 		*unitsptr %= base;
  122: 	} else if (*unitsptr < 0) {
  123: 		--*tensptr;
  124: 		*unitsptr += base;
  125: 		if (*unitsptr < 0) {
  126: 			*tensptr -= 1 + (-*unitsptr) / base;
  127: 			*unitsptr = base - (-*unitsptr) % base;
  128: 		}
  129: 	}
  130: }
  131: 
  132: static struct tm *
  133: mkdst(
  134: 	struct tm *	tmp
  135: 	)
  136: {
  137:     /* jds */
  138:     static struct tm tmbuf;
  139: 
  140:     tmbuf = *tmp;
  141:     tmbuf.tm_isdst = 1;
  142:     tmbuf.tm_min += DSTMINUTES;
  143:     normalize(&tmbuf.tm_hour, &tmbuf.tm_min, MINSPERHOUR);
  144:     return &tmbuf;
  145: }
  146: 
  147: static int
  148: tmcomp(
  149: 	register struct tm * atmp,
  150: 	register struct tm * btmp
  151: 	)
  152: {
  153: 	register int	result;
  154: 
  155: 	/* compare down to the same day */
  156: 
  157: 	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  158: 	    (result = (atmp->tm_mon - btmp->tm_mon)) == 0)
  159: 	    result = (atmp->tm_mday - btmp->tm_mday);
  160: 
  161: 	if(result != 0)
  162: 	    return result;
  163: 
  164: 	/* get rid of one-sided dst bias */
  165: 
  166: 	if(atmp->tm_isdst == 1 && !btmp->tm_isdst)
  167: 	    btmp = mkdst(btmp);
  168: 	else if(btmp->tm_isdst == 1 && !atmp->tm_isdst)
  169: 	    atmp = mkdst(atmp);
  170: 
  171: 	/* compare the rest of the way */
  172: 
  173: 	if ((result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  174: 	    (result = (atmp->tm_min - btmp->tm_min)) == 0)
  175: 	    result = atmp->tm_sec - btmp->tm_sec;
  176: 	return result;
  177: }
  178: 
  179: 
  180: static time_t
  181: time2(
  182: 	struct tm *	tmp,
  183: 	int * 		okayp,
  184: 	int		usezn
  185: 	)
  186: {
  187: 	register int			dir;
  188: 	register int			bits;
  189: 	register int			i;
  190: 	register int			saved_seconds;
  191: 	time_t				t;
  192: 	struct tm			yourtm, mytm;
  193: 
  194: 	*okayp = FALSE;
  195: 	yourtm = *tmp;
  196: 	if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
  197: 		normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
  198: 	normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
  199: 	normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
  200: 	normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
  201: 	while (yourtm.tm_mday <= 0) {
  202: 		--yourtm.tm_year;
  203: 		yourtm.tm_mday +=
  204: 			year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
  205: 	}
  206: 	for ( ; ; ) {
  207: 		i = mon_lengths[isleap(yourtm.tm_year +
  208: 			TM_YEAR_BASE)][yourtm.tm_mon];
  209: 		if (yourtm.tm_mday <= i)
  210: 			break;
  211: 		yourtm.tm_mday -= i;
  212: 		if (++yourtm.tm_mon >= MONSPERYEAR) {
  213: 			yourtm.tm_mon = 0;
  214: 			++yourtm.tm_year;
  215: 		}
  216: 	}
  217: 	saved_seconds = yourtm.tm_sec;
  218: 	yourtm.tm_sec = 0;
  219: 	/*
  220: 	** Calculate the number of magnitude bits in a time_t
  221: 	** (this works regardless of whether time_t is
  222: 	** signed or unsigned, though lint complains if unsigned).
  223: 	*/
  224: 	for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  225: 		;
  226: 	/*
  227: 	** If time_t is signed, then 0 is the median value,
  228: 	** if time_t is unsigned, then 1 << bits is median.
  229: 	*/
  230: 	t = (t < 0) ? 0 : ((time_t) 1 << bits);
  231: 	for ( ; ; ) {
  232: 		if (usezn)
  233: 			mytm = *localtime(&t);
  234: 		else
  235: 			mytm = *gmtime(&t);
  236: 		dir = tmcomp(&mytm, &yourtm);
  237: 		if (dir != 0) {
  238: 			if (bits-- < 0)
  239: 				return WRONG;
  240: 			if (bits < 0)
  241: 				--t;
  242: 			else if (dir > 0)
  243: 				t -= (time_t) 1 << bits;
  244: 			else	t += (time_t) 1 << bits;
  245: 			continue;
  246: 		}
  247: 		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  248: 			break;
  249: 
  250: 		return WRONG;
  251: 	}
  252: 	t += saved_seconds;
  253: 	if (usezn)
  254: 		*tmp = *localtime(&t);
  255: 	else
  256: 		*tmp = *gmtime(&t);
  257: 	*okayp = TRUE;
  258: 	return t;
  259: }
  260: #else
  261: int mktime_bs;
  262: #endif /* !HAVE_MKTIME || !HAVE_TIMEGM */
  263: 
  264: #ifndef HAVE_MKTIME
  265: static time_t
  266: time1(
  267: 	struct tm * tmp
  268: 	)
  269: {
  270: 	register time_t			t;
  271: 	int				okay;
  272: 
  273: 	if (tmp->tm_isdst > 1)
  274: 		tmp->tm_isdst = 1;
  275: 	t = time2(tmp, &okay, 1);
  276: 	if (okay || tmp->tm_isdst < 0)
  277: 		return t;
  278: 
  279: 	return WRONG;
  280: }
  281: 
  282: time_t
  283: mktime(
  284: 	struct tm * tmp
  285: 	)
  286: {
  287: 	return time1(tmp);
  288: }
  289: #endif /* !HAVE_MKTIME */
  290: 
  291: #ifndef HAVE_TIMEGM
  292: time_t
  293: timegm(
  294: 	struct tm * tmp
  295: 	)
  296: {
  297: 	register time_t			t;
  298: 	int				okay;
  299: 
  300: 	tmp->tm_isdst = 0;
  301: 	t = time2(tmp, &okay, 0);
  302: 	if (okay || tmp->tm_isdst < 0)
  303: 		return t;
  304: 
  305: 	return WRONG;
  306: }
  307: #endif /* !HAVE_TIMEGM */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>