File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / libntp / prettydate.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, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * prettydate - convert a time stamp to something readable
    3:  */
    4: #include <stdio.h>
    5: 
    6: #include "ntp_fp.h"
    7: #include "ntp_unixtime.h"	/* includes <sys/time.h> */
    8: #include "lib_strbuf.h"
    9: #include "ntp_stdlib.h"
   10: #include "ntp_assert.h"
   11: 
   12: static char *common_prettydate(l_fp *, int);
   13: 
   14: const char *months[] = {
   15:   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   16:   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
   17: };
   18: 
   19: static const char *days[] = {
   20:   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
   21: };
   22: 
   23: /* Helper function to handle possible wraparound of the ntp epoch.
   24: 
   25:    Works by periodic extension of the ntp time stamp in the NTP epoch.  If the
   26:    'time_t' is 32 bit, use solar cycle warping to get the value in a suitable
   27:    range. Also uses solar cycle warping to work around really buggy
   28:    implementations of 'gmtime()' / 'localtime()' that cannot work with a
   29:    negative time value, that is, times before 1970-01-01. (MSVCRT...)
   30: 
   31:    Apart from that we're assuming that the localtime/gmtime library functions
   32:    have been updated so that they work...
   33: */
   34: 
   35: 
   36: /* solar cycle in secs, unsigned secs and years. And the cycle limits.
   37: **
   38: ** And an explanation. The julian calendar repeats ever 28 years, because it's
   39: ** the LCM of 7 and 4, the week and leap year cycles. This is called a 'solar
   40: ** cycle'. The gregorian calendar does the same as long as no centennial year
   41: ** (divisible by 100, but not 400) goes in the way. So between 1901 and 2099
   42: ** (inclusive) we can warp time stamps by 28 years to make them suitable for
   43: ** localtime() and gmtime() if we have trouble. Of course this will play
   44: ** hubbubb with the DST zone switches, so we should do it only if necessary;
   45: ** but as we NEED a proper conversion to dates via gmtime() we should try to
   46: ** cope with as many idiosyncrasies as possible.
   47: */
   48: #define SOLAR_CYCLE_SECS   0x34AADC80UL	/* 7*1461*86400*/
   49: #define SOLAR_CYCLE_YEARS  28
   50: #define MINFOLD -3
   51: #define MAXFOLD  3
   52: 
   53: struct tm *
   54: ntp2unix_tm(
   55: 	u_long ntp, int local
   56: 	)
   57: {
   58: 	struct tm *tm;
   59: 	int32      folds = 0;
   60: 	time_t     t     = time(NULL);
   61: 	u_int32    dwlo  = (int32)t; /* might expand for SIZEOF_TIME_T < 4 */
   62: #if ( SIZEOF_TIME_T > 4 )
   63: 	int32      dwhi  = (int32)(t >> 16 >> 16);/* double shift: avoid warnings */
   64: #else
   65: 	/*
   66: 	 * Get the correct sign extension in the high part. 
   67: 	 * (now >> 32) may not work correctly on every 32 bit 
   68: 	 * system, e.g. it yields garbage under Win32/VC6.
   69: 	 */
   70:     int32		dwhi = (int32)(t >> 31);
   71: #endif
   72: 	
   73: 	/* Shift NTP to UN*X epoch, then unfold around currrent time. It's
   74: 	 * important to use a 32 bit max signed value -- LONG_MAX is 64 bit on
   75: 	 * a 64-bit system, and it will give wrong results.
   76: 	 */
   77: 	M_ADD(dwhi, dwlo, 0, ((1UL << 31)-1)); /* 32-bit max signed */
   78: 	if ((ntp -= JAN_1970) > dwlo)
   79: 		--dwhi;
   80: 	dwlo = ntp;
   81:  
   82: #   if SIZEOF_TIME_T < 4
   83: #	error sizeof(time_t) < 4 -- this will not work!
   84: #   elif SIZEOF_TIME_T == 4
   85: 
   86: 	/*
   87: 	** If the result will not fit into a 'time_t' we have to warp solar
   88: 	** cycles. That's implemented by looped addition / subtraction with
   89: 	** M_ADD and M_SUB to avoid implicit 64 bit operations, especially
   90: 	** division. As he number of warps is rather limited there's no big
   91: 	** performance loss here.
   92: 	**
   93: 	** note: unless the high word doesn't match the sign-extended low word,
   94: 	** the combination will not fit into time_t. That's what we use for
   95: 	** loop control here...
   96: 	*/
   97: 	while (dwhi != ((int32)dwlo >> 31)) {
   98: 		if (dwhi < 0 && --folds >= MINFOLD)
   99: 			M_ADD(dwhi, dwlo, 0, SOLAR_CYCLE_SECS);
  100: 		else if (dwhi >= 0 && ++folds <= MAXFOLD)
  101: 			M_SUB(dwhi, dwlo, 0, SOLAR_CYCLE_SECS);
  102: 		else
  103: 			return NULL;
  104: 	}
  105: 
  106: #   else
  107: 
  108: 	/* everything fine -- no reduction needed for the next thousand years */
  109: 
  110: #   endif
  111: 
  112: 	/* combine hi/lo to make time stamp */
  113: 	t = ((time_t)dwhi << 16 << 16) | dwlo;	/* double shift: avoid warnings */
  114: 
  115: #   ifdef _MSC_VER	/* make this an autoconf option? */
  116: 
  117: 	/*
  118: 	** The MSDN says that the (Microsoft) Windoze versions of 'gmtime()'
  119: 	** and 'localtime()' will bark on time stamps < 0. Better to fix it
  120: 	** immediately.
  121: 	*/
  122: 	while (t < 0) { 
  123: 		if (--folds < MINFOLD)
  124: 			return NULL;
  125: 		t += SOLAR_CYCLE_SECS;
  126: 	}
  127: 			
  128: #   endif /* Microsoft specific */
  129: 
  130: 	/* 't' should be a suitable value by now. Just go ahead. */
  131: 	while ( (tm = (*(local ? localtime : gmtime))(&t)) == 0)
  132: 		/* seems there are some other pathological implementations of
  133: 		** 'gmtime()' and 'localtime()' somewhere out there. No matter
  134: 		** if we have 32-bit or 64-bit 'time_t', try to fix this by
  135: 		** solar cycle warping again...
  136: 		*/
  137: 		if (t < 0) {
  138: 			if (--folds < MINFOLD)
  139: 				return NULL;
  140: 			t += SOLAR_CYCLE_SECS;
  141: 		} else {
  142: 			if ((++folds > MAXFOLD) || ((t -= SOLAR_CYCLE_SECS) < 0))
  143: 				return NULL; /* That's truely pathological! */
  144: 		}
  145: 	/* 'tm' surely not NULL here... */
  146: 	NTP_INSIST(tm != NULL);
  147: 	if (folds != 0) {
  148: 		tm->tm_year += folds * SOLAR_CYCLE_YEARS;
  149: 		if (tm->tm_year <= 0 || tm->tm_year >= 200)
  150: 			return NULL;	/* left warp range... can't help here! */
  151: 	}
  152: 	return tm;
  153: }
  154: 
  155: 
  156: static char *
  157: common_prettydate(
  158: 	l_fp *ts,
  159: 	int local
  160: 	)
  161: {
  162: 	char *bp;
  163: 	struct tm *tm;
  164: 	u_long sec;
  165: 	u_long msec;
  166: 
  167: 	LIB_GETBUF(bp);
  168: 	
  169: 	sec = ts->l_ui;
  170: 	msec = ts->l_uf / 4294967;	/* fract / (2 ** 32 / 1000) */
  171: 
  172: 	tm = ntp2unix_tm(sec, local);
  173: 	if (!tm)
  174: 		snprintf(bp, LIB_BUFLENGTH,
  175: 			 "%08lx.%08lx  --- --- -- ---- --:--:--",
  176: 			 (u_long)ts->l_ui, (u_long)ts->l_uf);
  177: 	else
  178: 		snprintf(bp, LIB_BUFLENGTH,
  179: 			 "%08lx.%08lx  %s, %s %2d %4d %2d:%02d:%02d.%03lu",
  180: 			 (u_long)ts->l_ui, (u_long)ts->l_uf,
  181: 			 days[tm->tm_wday], months[tm->tm_mon],
  182: 			 tm->tm_mday, 1900 + tm->tm_year, tm->tm_hour,
  183: 			 tm->tm_min, tm->tm_sec, msec);
  184: 	
  185: 	return bp;
  186: }
  187: 
  188: 
  189: char *
  190: prettydate(
  191: 	l_fp *ts
  192: 	)
  193: {
  194: 	return common_prettydate(ts, 1);
  195: }
  196: 
  197: 
  198: char *
  199: gmprettydate(
  200: 	l_fp *ts
  201: 	)
  202: {
  203: 	return common_prettydate(ts, 0);
  204: }

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