Annotation of embedaddon/ntp/libntp/prettydate.c, revision 1.1.1.1

1.1       misho       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>