From 64bc6412188b141c010ac3b8e813b837dd991e80 Mon Sep 17 00:00:00 2001 From: Erik Andersen Date: Sun, 14 May 2000 04:16:35 +0000 Subject: Initial revision --- libc/misc/time/Makefile | 24 ++++ libc/misc/time/README | 8 ++ libc/misc/time/asc_conv.c | 49 ++++++++ libc/misc/time/asctime.c | 15 +++ libc/misc/time/asctime_r.c | 15 +++ libc/misc/time/ctime.c | 26 +++++ libc/misc/time/ctime_r.c | 26 +++++ libc/misc/time/gmtime.c | 16 +++ libc/misc/time/gmtime_r.c | 14 +++ libc/misc/time/localtime.c | 22 ++++ libc/misc/time/localtime_r.c | 22 ++++ libc/misc/time/mktime.c | 259 +++++++++++++++++++++++++++++++++++++++++++ libc/misc/time/tm_conv.c | 138 +++++++++++++++++++++++ 13 files changed, 634 insertions(+) create mode 100644 libc/misc/time/Makefile create mode 100644 libc/misc/time/README create mode 100644 libc/misc/time/asc_conv.c create mode 100644 libc/misc/time/asctime.c create mode 100644 libc/misc/time/asctime_r.c create mode 100644 libc/misc/time/ctime.c create mode 100644 libc/misc/time/ctime_r.c create mode 100644 libc/misc/time/gmtime.c create mode 100644 libc/misc/time/gmtime_r.c create mode 100644 libc/misc/time/localtime.c create mode 100644 libc/misc/time/localtime_r.c create mode 100644 libc/misc/time/mktime.c create mode 100644 libc/misc/time/tm_conv.c (limited to 'libc/misc/time') diff --git a/libc/misc/time/Makefile b/libc/misc/time/Makefile new file mode 100644 index 000000000..ab47a7e47 --- /dev/null +++ b/libc/misc/time/Makefile @@ -0,0 +1,24 @@ +# Copyright (C) 1996 Robert de Bath +# This file is part of the Linux-8086 C library and is distributed +# under the GNU Library General Public License. + +LIBC=../libc.a + +CC=m68k-pic-coff-gcc +AR=m68k-pic-coff-ar +RANLIB=m68k-pic-coff-ranlib + +CCFLAGS= -O2 -m68000 -msoft-float -I../include + +OBJ=localtime.o gmtime.o asctime.o ctime.o asc_conv.o tm_conv.o mktime.o \ + localtime_r.o gmtime_r.o asctime_r.o ctime_r.o + +CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS) + +all: $(LIBC) + @$(RM) $(OBJ) + +$(LIBC): $(LIBC)($(OBJ)) + +clean: + rm -f *.o libc.a diff --git a/libc/misc/time/README b/libc/misc/time/README new file mode 100644 index 000000000..da4f4e67f --- /dev/null +++ b/libc/misc/time/README @@ -0,0 +1,8 @@ +Copyright (C) 1996 Robert de Bath +This file is part of the Linux-8086 C library and is distributed +under the GNU Library General Public License. + +There are two ways of converting the time_t to a struct tm, I'm not +quite sure which is better. + +-Robert diff --git a/libc/misc/time/asc_conv.c b/libc/misc/time/asc_conv.c new file mode 100644 index 000000000..78cbcdd8d --- /dev/null +++ b/libc/misc/time/asc_conv.c @@ -0,0 +1,49 @@ + +#include +#include +/* + * Internal ascii conversion routine, avoid use of printf, it's a bit big! + */ + + +static void +hit(buf, val) +char * buf; +int val; +{ + *buf = '0' + val%10; +} + +void +__asctime(buffer, ptm) +register char * buffer; +struct tm * ptm; +{ +static char days[] = "SunMonTueWedThuFriSat"; +static char mons[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + int year; + + /* 012345678901234567890123456 */ + strcpy(buffer, "Err Err .. ..:..:.. ....\n"); + if( (ptm->tm_wday >= 0) && (ptm->tm_wday <= 6) ) + memcpy(buffer, days+3*(ptm->tm_wday), 3); + + if( (ptm->tm_mon >= 0) && (ptm->tm_mon <= 11) ) + memcpy(buffer+4, mons+3*(ptm->tm_mon), 3); + + + hit(buffer+ 8, ptm->tm_mday/10); + hit(buffer+ 9, ptm->tm_mday ); + hit(buffer+11, ptm->tm_hour/10); + hit(buffer+12, ptm->tm_hour ); + hit(buffer+14, ptm->tm_min/10); + hit(buffer+15, ptm->tm_min ); + hit(buffer+17, ptm->tm_sec/10); + hit(buffer+18, ptm->tm_sec ); + + year = ptm->tm_year + 1900; + hit(buffer+20, year/1000); + hit(buffer+21, year/100); + hit(buffer+22, year/10); + hit(buffer+23, year); +} diff --git a/libc/misc/time/asctime.c b/libc/misc/time/asctime.c new file mode 100644 index 000000000..08673cbcc --- /dev/null +++ b/libc/misc/time/asctime.c @@ -0,0 +1,15 @@ + +#include + +extern void __asctime(); + +char * +asctime(timeptr) +__const struct tm * timeptr; +{ + static char timebuf[26]; + + if( timeptr == 0 ) return 0; + __asctime(timebuf, timeptr); + return timebuf; +} diff --git a/libc/misc/time/asctime_r.c b/libc/misc/time/asctime_r.c new file mode 100644 index 000000000..ff2b6bfb3 --- /dev/null +++ b/libc/misc/time/asctime_r.c @@ -0,0 +1,15 @@ + +#include + +extern void __asctime(); + +char * +asctime_r(timeptr, buf) +__const struct tm * timeptr; +char * buf; +{ + + if( timeptr == 0 ) return 0; + __asctime(buf, timeptr); + return buf; +} diff --git a/libc/misc/time/ctime.c b/libc/misc/time/ctime.c new file mode 100644 index 000000000..2f42cd3f3 --- /dev/null +++ b/libc/misc/time/ctime.c @@ -0,0 +1,26 @@ + +#include + +extern void __tm_conv(); +extern void __asctime(); + +char * +ctime(timep) +__const time_t * timep; +{ + static char cbuf[26]; + struct tm tmb; + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(&tmb, timep, offt); + + __asctime(cbuf, &tmb); + + return cbuf; +} diff --git a/libc/misc/time/ctime_r.c b/libc/misc/time/ctime_r.c new file mode 100644 index 000000000..ac267b04e --- /dev/null +++ b/libc/misc/time/ctime_r.c @@ -0,0 +1,26 @@ + +#include + +extern void __tm_conv(); +extern void __asctime(); + +char * +ctime_r(timep, buf) +__const time_t * timep; +char * buf; +{ + struct tm tmb; + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(&tmb, timep, offt); + + __asctime(buf, &tmb); + + return buf; +} diff --git a/libc/misc/time/gmtime.c b/libc/misc/time/gmtime.c new file mode 100644 index 000000000..69d539392 --- /dev/null +++ b/libc/misc/time/gmtime.c @@ -0,0 +1,16 @@ + +#include + +extern void __tm_conv(); + +struct tm * +gmtime(timep) +__const time_t * timep; +{ + static struct tm tmb; + + __tm_conv(&tmb, timep, 0L); + + return &tmb; +} + diff --git a/libc/misc/time/gmtime_r.c b/libc/misc/time/gmtime_r.c new file mode 100644 index 000000000..00c41b349 --- /dev/null +++ b/libc/misc/time/gmtime_r.c @@ -0,0 +1,14 @@ + +#include + +extern void __tm_conv(); + +struct tm * +gmtime_r(timep, tp) +__const time_t * timep; +struct tm * tp; +{ + __tm_conv(tp, timep, 0L); + return tp; +} + diff --git a/libc/misc/time/localtime.c b/libc/misc/time/localtime.c new file mode 100644 index 000000000..9d9b46d15 --- /dev/null +++ b/libc/misc/time/localtime.c @@ -0,0 +1,22 @@ + +#include + +extern void __tm_conv(); + +struct tm * +localtime(timep) +__const time_t * timep; +{ + static struct tm tmb; + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(&tmb, timep, offt); + + return &tmb; +} diff --git a/libc/misc/time/localtime_r.c b/libc/misc/time/localtime_r.c new file mode 100644 index 000000000..fe024670c --- /dev/null +++ b/libc/misc/time/localtime_r.c @@ -0,0 +1,22 @@ + +#include + +extern void __tm_conv(); + +struct tm * +localtime_r(timep, tp) +__const time_t * timep; +struct tm * tp; +{ + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(tp, timep, offt); + + return tp; +} diff --git a/libc/misc/time/mktime.c b/libc/misc/time/mktime.c new file mode 100644 index 000000000..7f7aabcd7 --- /dev/null +++ b/libc/misc/time/mktime.c @@ -0,0 +1,259 @@ + +/* This is adapted from glibc */ +/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. */ + + +/* Assume that leap seconds are possible, unless told otherwise. + If the host has a `zic' command with a -L leapsecondfilename' option, + then it supports leap seconds; otherwise it probably doesn't. */ +#ifndef LEAP_SECONDS_POSSIBLE +#define LEAP_SECONDS_POSSIBLE 1 +#endif + +#include /* Some systems define `time_t' here. */ +#include + +#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS +#include +#endif + +#if DEBUG +#include +#if __STDC__ || __GNU_LIBRARY__ || STDC_HEADERS +#include +#endif +/* Make it work even if the system's libc has its own mktime routine. */ +#define mktime my_mktime +#endif /* DEBUG */ + +#ifndef __P +#if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +#define __P(args) args +#else +#define __P(args) () +#endif /* GCC. */ +#endif /* Not __P. */ + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef INT_MIN +#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1)) +#endif +#ifndef INT_MAX +#define INT_MAX (~0 - INT_MIN) +#endif + +#ifndef TIME_T_MIN +#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \ + : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1)) +#endif +#ifndef TIME_T_MAX +#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN) +#endif + +#define TM_YEAR_BASE 1900 +#define EPOCH_YEAR 1970 + +#ifndef __isleap +/* Nonzero if YEAR is a leap year (every 4 years, + except every 100th isn't, and every 400th is). */ +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) +#endif + +/* How many days come before each month (0-12). */ +const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; + +static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *)); +time_t __mktime_internal __P ((struct tm *, + struct tm *(*) (const time_t *, struct tm *), + time_t *)); + +/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP), + measured in seconds, ignoring leap seconds. + YEAR uses the same numbering as TM->tm_year. + All values are in range, except possibly YEAR. + If overflow occurs, yield the low order bits of the correct answer. */ +static time_t +ydhms_tm_diff (year, yday, hour, min, sec, tp) + int year, yday, hour, min, sec; + const struct tm *tp; +{ + /* Compute intervening leap days correctly even if year is negative. + Take care to avoid int overflow. time_t overflow is OK, since + only the low order bits of the correct time_t answer are needed. + Don't convert to time_t until after all divisions are done, since + time_t might be unsigned. */ + int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3); + int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3); + int a100 = a4 / 25 - (a4 % 25 < 0); + int b100 = b4 / 25 - (b4 % 25 < 0); + int a400 = a100 >> 2; + int b400 = b100 >> 2; + int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); + time_t years = year - (time_t) tp->tm_year; + time_t days = (365 * years + intervening_leap_days + + (yday - tp->tm_yday)); + return (60 * (60 * (24 * days + (hour - tp->tm_hour)) + + (min - tp->tm_min)) + + (sec - tp->tm_sec)); +} + + +static time_t localtime_offset; + + +/* Convert *TP to a time_t value. */ +time_t +mktime (tp) + struct tm *tp; +{ +#ifdef _LIBC + /* POSIX.1 8.1.1 requires that whenever mktime() is called, the + time zone names contained in the external variable `tzname' shall + be set as if the tzset() function had been called. */ + __tzset (); +#endif + + return __mktime_internal (tp, localtime_r, &localtime_offset); +} + +/* Convert *TP to a time_t value, inverting + the monotonic and mostly-unit-linear conversion function CONVERT. + Use *OFFSET to keep track of a guess at the offset of the result, + compared to what the result would be for UTC without leap seconds. + If *OFFSET's guess is correct, only one CONVERT call is needed. */ +time_t +__mktime_internal (tp, convert, offset) + struct tm *tp; + struct tm *(*convert) __P ((const time_t *, struct tm *)); + time_t *offset; +{ + time_t t, dt, t0; + struct tm tm; + + /* The maximum number of probes (calls to CONVERT) should be enough + to handle any combinations of time zone rule changes, solar time, + and leap seconds. Posix.1 prohibits leap seconds, but some hosts + have them anyway. */ + int remaining_probes = 4; + + /* Time requested. Copy it in case CONVERT modifies *TP; this can + occur if TP is localtime's returned value and CONVERT is localtime. */ + int sec = tp->tm_sec; + int min = tp->tm_min; + int hour = tp->tm_hour; + int mday = tp->tm_mday; + int mon = tp->tm_mon; + int year_requested = tp->tm_year; + int isdst = tp->tm_isdst; + + /* Ensure that mon is in range, and set year accordingly. */ + int mon_remainder = mon % 12; + int negative_mon_remainder = mon_remainder < 0; + int mon_years = mon / 12 - negative_mon_remainder; + int year = year_requested + mon_years; + + /* The other values need not be in range: + the remaining code handles minor overflows correctly, + assuming int and time_t arithmetic wraps around. + Major overflows are caught at the end. */ + + /* Calculate day of year from year, month, and day of month. + The result need not be in range. */ + int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)] + [mon_remainder + 12 * negative_mon_remainder]) + + mday - 1); + +#if LEAP_SECONDS_POSSIBLE + /* Handle out-of-range seconds specially, + since ydhms_tm_diff assumes every minute has 60 seconds. */ + int sec_requested = sec; + if (sec < 0) + sec = 0; + if (59 < sec) + sec = 59; +#endif + + /* Invert CONVERT by probing. First assume the same offset as last time. + Then repeatedly use the error to improve the guess. */ + + tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE; + tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm); + + for (t = t0 + *offset; + (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm))); + t += dt) + if (--remaining_probes == 0) + return -1; + + /* Check whether tm.tm_isdst has the requested value, if any. */ + if (0 <= isdst && 0 <= tm.tm_isdst) + { + int dst_diff = (isdst != 0) - (tm.tm_isdst != 0); + if (dst_diff) + { + /* Move two hours in the direction indicated by the disagreement, + probe some more, and switch to a new time if found. + The largest known fallback due to daylight savings is two hours: + once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */ + time_t ot = t - 2 * 60 * 60 * dst_diff; + while (--remaining_probes != 0) + { + struct tm otm; + if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec, + (*convert) (&ot, &otm)))) + { + t = ot; + tm = otm; + break; + } + if ((ot += dt) == t) + break; /* Avoid a redundant probe. */ + } + } + } + + *offset = t - t0; + +#if LEAP_SECONDS_POSSIBLE + if (sec_requested != tm.tm_sec) + { + /* Adjust time to reflect the tm_sec requested, not the normalized value. + Also, repair any damage from a false match due to a leap second. */ + t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60); + (*convert) (&t, &tm); + } +#endif + +#if 0 + if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3) + { + /* time_t isn't large enough to rule out overflows in ydhms_tm_diff, + so check for major overflows. A gross check suffices, + since if t has overflowed, it is off by a multiple of + TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of + the difference that is bounded by a small value. */ + + double dyear = (double) year_requested + mon_years - tm.tm_year; + double dday = 366 * dyear + mday; + double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested; + + if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec)) + return -1; + } +#endif + + *tp = tm; + return t; +} + diff --git a/libc/misc/time/tm_conv.c b/libc/misc/time/tm_conv.c new file mode 100644 index 000000000..ffd524c4b --- /dev/null +++ b/libc/misc/time/tm_conv.c @@ -0,0 +1,138 @@ + +#if 0 +#include + +/* This is a translation from ALGOL in Collected Algorithms of CACM. */ +/* Copied from Algorithm 199, Author: Robert G. Tantzen */ + +void +__tm_conv(tmbuf, timep, offset) +struct tm *tmbuf; +time_t *timep; +time_t offset; +{ +static int moffset[] = + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + long s; + long j, d, m, y; + + offset += *timep; + + tmbuf->tm_isdst = 0; /* Someone else can set this */ + + j = offset / 86400L + 719469; + s = offset % 86400L; + + if( s < 0 ) { s += 86400L; j--; } + + tmbuf->tm_sec = s % 60; + tmbuf->tm_min = (s / 60) % 60; + tmbuf->tm_hour = s / 3600; + + tmbuf->tm_wday = (j+2) % 7; + + /* + * Julian date converter. Takes a julian date (the number of days since + * some distant epoch or other), and fills tmbuf. + */ + + y = (4L * j - 1L) / 146097L; + j = 4L * j - 1L - 146097L * y; + d = j / 4L; + j = (4L * d + 3L) / 1461L; + d = 4L * d + 3L - 1461L * j; + d = (d + 4L) / 4L; + m = (5L * d - 3L) / 153L; + d = 5L * d - 3 - 153L * m; + d = (d + 5L) / 5L; + y = 100L * y + j; + if (m < 10) + m += 2; + else + { + m -= 10; + ++y; + } + + tmbuf->tm_year = y - 1900; + tmbuf->tm_mon = m; + tmbuf->tm_mday = d; + + tmbuf->tm_yday = d + moffset[m]; + if (m > 1 && ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))) + tmbuf->tm_yday++; +} + +#else + +/* This is adapted from glibc */ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc */ + +#define SECS_PER_HOUR 3600L +#define SECS_PER_DAY 86400L + +#include + +static const unsigned short int __mon_lengths[2][12] = + { + /* Normal years. */ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + /* Leap years. */ + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + +void +__tm_conv(tmbuf, t, offset) +struct tm *tmbuf; +time_t *t; +time_t offset; +{ + long days, rem; + register int y; + register unsigned short int *ip; + + days = *t / SECS_PER_DAY; + rem = *t % SECS_PER_DAY; + rem += offset; + while (rem < 0) + { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) + { + rem -= SECS_PER_DAY; + ++days; + } + tmbuf->tm_hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + tmbuf->tm_min = rem / 60; + tmbuf->tm_sec = rem % 60; + /* January 1, 1970 was a Thursday. */ + tmbuf->tm_wday = (4 + days) % 7; + if (tmbuf->tm_wday < 0) + tmbuf->tm_wday += 7; + y = 1970; + while (days >= (rem = __isleap(y) ? 366 : 365)) + { + ++y; + days -= rem; + } + while (days < 0) + { + --y; + days += __isleap(y) ? 366 : 365; + } + tmbuf->tm_year = y - 1900; + tmbuf->tm_yday = days; + ip = __mon_lengths[__isleap(y)]; + for (y = 0; days >= ip[y]; ++y) + days -= ip[y]; + tmbuf->tm_mon = y; + tmbuf->tm_mday = days + 1; + tmbuf->tm_isdst = -1; +} + +#endif -- cgit v1.2.3