/programs/develop/libraries/menuetlibc/src/libc/ansi/time/Makefile |
---|
0,0 → 1,4 |
THIS_SRCS = ctime.c difftime.c strftime.c time.c |
include $(MENUET_LIBC_TOPDIR)/Make.rules |
/programs/develop/libraries/menuetlibc/src/libc/ansi/time/ctime.c |
---|
0,0 → 1,1197 |
#include <libc/stubs.h> |
#include <fcntl.h> |
#include <time.h> |
#include <string.h> |
#include <ctype.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <tzfile.h> |
#include <libc/unconst.h> |
#include "posixrul.h" |
#define P(s) s |
#define alloc_size_t size_t |
#define qsort_size_t size_t |
#define fread_size_t size_t |
#define fwrite_size_t size_t |
#define ACCESS_MODE O_RDONLY|O_BINARY |
#define OPEN_MODE O_RDONLY|O_BINARY |
static char WILDABBR[] = " "; |
#ifndef TRUE |
#define TRUE 1 |
#define FALSE 0 |
#endif /* !defined TRUE */ |
static const char GMT[] = "GMT"; |
struct ttinfo { /* time type information */ |
long tt_gmtoff; /* GMT offset in seconds */ |
int tt_isdst; /* used to set tm_isdst */ |
int tt_abbrind; /* abbreviation list index */ |
int tt_ttisstd; /* TRUE if transition is std time */ |
}; |
struct lsinfo { /* leap second information */ |
time_t ls_trans; /* transition time */ |
long ls_corr; /* correction to apply */ |
}; |
struct state { |
int leapcnt; |
int timecnt; |
int typecnt; |
int charcnt; |
time_t ats[TZ_MAX_TIMES]; |
unsigned char types[TZ_MAX_TIMES]; |
struct ttinfo ttis[TZ_MAX_TYPES]; |
char chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ? TZ_MAX_CHARS + 1 : sizeof GMT]; |
struct lsinfo lsis[TZ_MAX_LEAPS]; |
}; |
struct rule { |
int r_type; /* type of rule--see below */ |
int r_day; /* day number of rule */ |
int r_week; /* week number of rule */ |
int r_mon; /* month number of rule */ |
long r_time; /* transition time of rule */ |
}; |
#define JULIAN_DAY 0 /* Jn - Julian day */ |
#define DAY_OF_YEAR 1 /* n - day of year */ |
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ |
/* |
** Prototypes for static functions. |
*/ |
static long detzcode P((const char * codep)); |
static const char * getzname P((const char * strp)); |
static const char * getnum P((const char * strp, int * nump, int min, |
int max)); |
static const char * getsecs P((const char * strp, long * secsp)); |
static const char * getoffset P((const char * strp, long * offsetp)); |
static const char * getrule P((const char * strp, struct rule * rulep)); |
static void gmtload P((struct state * sp)); |
static void gmtsub P((const time_t * timep, long offset, |
struct tm * tmp)); |
static void localsub P((const time_t * timep, long offset, |
struct tm * tmp)); |
static void normalize P((int * tensptr, int * unitsptr, int base)); |
static void settzname P((void)); |
static time_t time1 P((struct tm * tmp, void (* funcp)(const time_t * const, const long, struct tm * const), |
long offset)); |
static time_t time2 P((struct tm *tmp, void (* funcp)(const time_t * const, const long, struct tm * const), |
long offset, int * okayp)); |
static void timesub P((const time_t * timep, long offset, |
const struct state * sp, struct tm * tmp)); |
static int tmcomp P((const struct tm * atmp, |
const struct tm * btmp)); |
static time_t transtime P((time_t janfirst, int year, |
const struct rule * rulep, long offset)); |
static int tzparse P((const char * name, struct state * sp, |
int lastditch)); |
//static void tzsetwall(void); |
#ifdef ALL_STATE |
static struct state *lclptr; |
static struct state *gmtptr; |
#endif /* defined ALL_STATE */ |
#ifndef ALL_STATE |
static struct state lclmem; |
static struct state gmtmem; |
#define lclptr (&lclmem) |
#define gmtptr (&gmtmem) |
#endif /* State Farm */ |
static int lcl_is_set; |
static int gmt_is_set; |
char * tzname[2] = { |
WILDABBR, |
WILDABBR |
}; |
static long |
detzcode(const char * const codep) |
{ |
long result; |
int i; |
result = 0; |
for (i = 0; i < 4; ++i) |
result = (result << 8) | (codep[i] & 0xff); |
return result; |
} |
static void |
settzname(void) |
{ |
const struct state * const sp = lclptr; |
int i; |
tzname[0] = WILDABBR; |
tzname[1] = WILDABBR; |
#ifdef ALL_STATE |
if (sp == NULL) |
{ |
tzname[0] = tzname[1] = GMT; |
return; |
} |
#endif /* defined ALL_STATE */ |
for (i = 0; i < sp->typecnt; ++i) |
{ |
register const struct ttinfo * const ttisp = &sp->ttis[i]; |
tzname[ttisp->tt_isdst] = |
unconst(&sp->chars[ttisp->tt_abbrind], char *); |
#if 0 |
if (ttisp->tt_isdst) |
_daylight = 1; |
if (i == 0 || !ttisp->tt_isdst) |
_timezone = -(ttisp->tt_gmtoff); |
if (i == 0 || ttisp->tt_isdst) |
_altzone = -(ttisp->tt_gmtoff); |
#endif |
} |
/* |
** And to get the latest zone names into tzname. . . |
*/ |
for (i = 0; i < sp->timecnt; ++i) |
{ |
const struct ttinfo * const ttisp = &sp->ttis[sp->types[i]]; |
tzname[ttisp->tt_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *); |
} |
} |
static const int mon_lengths[2][MONSPERYEAR] = { |
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, |
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } |
}; |
static const int year_lengths[2] = { |
DAYSPERNYEAR, DAYSPERLYEAR |
}; |
/* |
** Given a pointer into a time zone string, scan until a character that is not |
** a valid character in a zone name is found. Return a pointer to that |
** character. |
*/ |
static const char * |
getzname(const char *strp) |
{ |
char c; |
while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && |
c != '+') |
++strp; |
return strp; |
} |
/* |
** Given a pointer into a time zone string, extract a number from that string. |
** Check that the number is within a specified range; if it is not, return |
** NULL. |
** Otherwise, return a pointer to the first character not part of the number. |
*/ |
static const char * |
getnum(const char *strp, int * const nump, const int min, const int max) |
{ |
char c; |
int num; |
if (strp == NULL || !isdigit(*strp)) |
return NULL; |
num = 0; |
while ((c = *strp) != '\0' && isdigit(c)) |
{ |
num = num * 10 + (c - '0'); |
if (num > max) |
return NULL; |
++strp; |
} |
if (num < min) |
return NULL; |
*nump = num; |
return strp; |
} |
/* |
** Given a pointer into a time zone string, extract a number of seconds, |
** in hh[:mm[:ss]] form, from the string. |
** If any error occurs, return NULL. |
** Otherwise, return a pointer to the first character not part of the number |
** of seconds. |
*/ |
static const char * |
getsecs(const char *strp, long * const secsp) |
{ |
int num; |
strp = getnum(strp, &num, 0, HOURSPERDAY); |
if (strp == NULL) |
return NULL; |
*secsp = num * SECSPERHOUR; |
if (*strp == ':') |
{ |
++strp; |
strp = getnum(strp, &num, 0, MINSPERHOUR - 1); |
if (strp == NULL) |
return NULL; |
*secsp += num * SECSPERMIN; |
if (*strp == ':') |
{ |
++strp; |
strp = getnum(strp, &num, 0, SECSPERMIN - 1); |
if (strp == NULL) |
return NULL; |
*secsp += num; |
} |
} |
return strp; |
} |
/* |
** Given a pointer into a time zone string, extract an offset, in |
** [+-]hh[:mm[:ss]] form, from the string. |
** If any error occurs, return NULL. |
** Otherwise, return a pointer to the first character not part of the time. |
*/ |
static const char * |
getoffset(const char *strp, long * const offsetp) |
{ |
int neg; |
if (*strp == '-') |
{ |
neg = 1; |
++strp; |
} |
else if (isdigit(*strp) || *strp++ == '+') |
neg = 0; |
else |
return NULL; /* illegal offset */ |
strp = getsecs(strp, offsetp); |
if (strp == NULL) |
return NULL; /* illegal time */ |
if (neg) |
*offsetp = -*offsetp; |
return strp; |
} |
/* |
** Given a pointer into a time zone string, extract a rule in the form |
** date[/time]. See POSIX section 8 for the format of "date" and "time". |
** If a valid rule is not found, return NULL. |
** Otherwise, return a pointer to the first character not part of the rule. |
*/ |
static const char * |
getrule(const char *strp, struct rule * const rulep) |
{ |
if (*strp == 'J') |
{ |
/* |
** Julian day. |
*/ |
rulep->r_type = JULIAN_DAY; |
++strp; |
strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR); |
} |
else if (*strp == 'M') |
{ |
/* |
** Month, week, day. |
*/ |
rulep->r_type = MONTH_NTH_DAY_OF_WEEK; |
++strp; |
strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR); |
if (strp == NULL) |
return NULL; |
if (*strp++ != '.') |
return NULL; |
strp = getnum(strp, &rulep->r_week, 1, 5); |
if (strp == NULL) |
return NULL; |
if (*strp++ != '.') |
return NULL; |
strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); |
} |
else if (isdigit(*strp)) |
{ |
/* |
** Day of year. |
*/ |
rulep->r_type = DAY_OF_YEAR; |
strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1); |
} |
else |
return NULL; /* invalid format */ |
if (strp == NULL) |
return NULL; |
if (*strp == '/') |
{ |
/* |
** Time specified. |
*/ |
++strp; |
strp = getsecs(strp, &rulep->r_time); |
} |
else |
rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */ |
return strp; |
} |
/* |
** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the |
** year, a rule, and the offset from GMT at the time that rule takes effect, |
** calculate the Epoch-relative time that rule takes effect. |
*/ |
static time_t |
transtime(const time_t janfirst, const int year, const struct rule * const rulep, const long offset) |
{ |
int leapyear; |
time_t value=0; |
int i; |
int d, m1, yy0, yy1, yy2, dow; |
leapyear = isleap(year); |
switch (rulep->r_type) |
{ |
case JULIAN_DAY: |
/* |
** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap |
** years. |
** In non-leap years, or if the day number is 59 or less, just |
** add SECSPERDAY times the day number-1 to the time of |
** January 1, midnight, to get the day. |
*/ |
value = janfirst + (rulep->r_day - 1) * SECSPERDAY; |
if (leapyear && rulep->r_day >= 60) |
value += SECSPERDAY; |
break; |
case DAY_OF_YEAR: |
/* |
** n - day of year. |
** Just add SECSPERDAY times the day number to the time of |
** January 1, midnight, to get the day. |
*/ |
value = janfirst + rulep->r_day * SECSPERDAY; |
break; |
case MONTH_NTH_DAY_OF_WEEK: |
/* |
** Mm.n.d - nth "dth day" of month m. |
*/ |
value = janfirst; |
for (i = 0; i < rulep->r_mon - 1; ++i) |
value += mon_lengths[leapyear][i] * SECSPERDAY; |
/* |
** Use Zeller's Congruence to get day-of-week of first day of |
** month. |
*/ |
m1 = (rulep->r_mon + 9) % 12 + 1; |
yy0 = (rulep->r_mon <= 2) ? (year - 1) : year; |
yy1 = yy0 / 100; |
yy2 = yy0 % 100; |
dow = ((26 * m1 - 2) / 10 + |
1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; |
if (dow < 0) |
dow += DAYSPERWEEK; |
/* |
** "dow" is the day-of-week of the first day of the month. Get |
** the day-of-month (zero-origin) of the first "dow" day of the |
** month. |
*/ |
d = rulep->r_day - dow; |
if (d < 0) |
d += DAYSPERWEEK; |
for (i = 1; i < rulep->r_week; ++i) |
{ |
if (d + DAYSPERWEEK >= |
mon_lengths[leapyear][rulep->r_mon - 1]) |
break; |
d += DAYSPERWEEK; |
} |
/* |
** "d" is the day-of-month (zero-origin) of the day we want. |
*/ |
value += d * SECSPERDAY; |
break; |
} |
/* |
** "value" is the Epoch-relative time of 00:00:00 GMT on the day in |
** question. To get the Epoch-relative time of the specified local |
** time on that day, add the transition time and the current offset |
** from GMT. |
*/ |
return value + rulep->r_time + offset; |
} |
/* |
** Given a POSIX section 8-style TZ string, fill in the rule tables as |
** appropriate. |
*/ |
static int tzload (const char * name, struct state * sp) |
{ |
return -1; |
} |
static int |
tzparse(const char *name, struct state * const sp, const int lastditch) |
{ |
const char * stdname; |
const char * dstname=0; |
int stdlen; |
int dstlen; |
long stdoffset; |
long dstoffset; |
time_t * atp; |
unsigned char * typep; |
char * cp; |
int load_result; |
stdname = name; |
if (lastditch) |
{ |
stdlen = strlen(name); /* length of standard zone name */ |
name += stdlen; |
if (stdlen >= sizeof sp->chars) |
stdlen = (sizeof sp->chars) - 1; |
} |
else |
{ |
name = getzname(name); |
stdlen = name - stdname; |
if (stdlen < 3) |
return -1; |
} |
if (*name == '\0') |
return -1; |
else |
{ |
name = getoffset(name, &stdoffset); |
if (name == NULL) |
return -1; |
} |
load_result = tzload(TZDEFRULES, sp); |
if (load_result != 0) |
sp->leapcnt = 0; /* so, we're off a little */ |
if (*name != '\0') |
{ |
dstname = name; |
name = getzname(name); |
dstlen = name - dstname; /* length of DST zone name */ |
if (dstlen < 3) |
return -1; |
if (*name != '\0' && *name != ',' && *name != ';') |
{ |
name = getoffset(name, &dstoffset); |
if (name == NULL) |
return -1; |
} |
else |
dstoffset = stdoffset - SECSPERHOUR; |
if (*name == ',' || *name == ';') |
{ |
struct rule start; |
struct rule end; |
int year; |
time_t janfirst; |
time_t starttime; |
time_t endtime; |
++name; |
if ((name = getrule(name, &start)) == NULL) |
return -1; |
if (*name++ != ',') |
return -1; |
if ((name = getrule(name, &end)) == NULL) |
return -1; |
if (*name != '\0') |
return -1; |
sp->typecnt = 2; /* standard time and DST */ |
/* |
** Two transitions per year, from EPOCH_YEAR to 2037. |
*/ |
sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1); |
if (sp->timecnt > TZ_MAX_TIMES) |
return -1; |
sp->ttis[0].tt_gmtoff = -dstoffset; |
sp->ttis[0].tt_isdst = 1; |
sp->ttis[0].tt_abbrind = stdlen + 1; |
sp->ttis[1].tt_gmtoff = -stdoffset; |
sp->ttis[1].tt_isdst = 0; |
sp->ttis[1].tt_abbrind = 0; |
atp = sp->ats; |
typep = sp->types; |
janfirst = 0; |
for (year = EPOCH_YEAR; year <= 2037; ++year) |
{ |
starttime = transtime(janfirst, year, &start, |
stdoffset); |
endtime = transtime(janfirst, year, &end, |
dstoffset); |
if (starttime > endtime) |
{ |
*atp++ = endtime; |
*typep++ = 1; /* DST ends */ |
*atp++ = starttime; |
*typep++ = 0; /* DST begins */ |
} |
else |
{ |
*atp++ = starttime; |
*typep++ = 0; /* DST begins */ |
*atp++ = endtime; |
*typep++ = 1; /* DST ends */ |
} |
janfirst += |
year_lengths[isleap(year)] * SECSPERDAY; |
} |
} |
else |
{ |
int sawstd; |
int sawdst; |
long stdfix; |
long dstfix; |
long oldfix; |
int isdst; |
int i; |
if (*name != '\0') |
return -1; |
if (load_result != 0) |
return -1; |
/* |
** Compute the difference between the real and |
** prototype standard and summer time offsets |
** from GMT, and put the real standard and summer |
** time offsets into the rules in place of the |
** prototype offsets. |
*/ |
sawstd = FALSE; |
sawdst = FALSE; |
stdfix = 0; |
dstfix = 0; |
for (i = 0; i < sp->typecnt; ++i) |
{ |
if (sp->ttis[i].tt_isdst) |
{ |
oldfix = dstfix; |
dstfix = |
sp->ttis[i].tt_gmtoff + dstoffset; |
if (sawdst && (oldfix != dstfix)) |
return -1; |
sp->ttis[i].tt_gmtoff = -dstoffset; |
sp->ttis[i].tt_abbrind = stdlen + 1; |
sawdst = TRUE; |
} |
else |
{ |
oldfix = stdfix; |
stdfix = |
sp->ttis[i].tt_gmtoff + stdoffset; |
if (sawstd && (oldfix != stdfix)) |
return -1; |
sp->ttis[i].tt_gmtoff = -stdoffset; |
sp->ttis[i].tt_abbrind = 0; |
sawstd = TRUE; |
} |
} |
/* |
** Make sure we have both standard and summer time. |
*/ |
if (!sawdst || !sawstd) |
return -1; |
/* |
** Now correct the transition times by shifting |
** them by the difference between the real and |
** prototype offsets. Note that this difference |
** can be different in standard and summer time; |
** the prototype probably has a 1-hour difference |
** between standard and summer time, but a different |
** difference can be specified in TZ. |
*/ |
isdst = FALSE; /* we start in standard time */ |
for (i = 0; i < sp->timecnt; ++i) |
{ |
const struct ttinfo * ttisp; |
/* |
** If summer time is in effect, and the |
** transition time was not specified as |
** standard time, add the summer time |
** offset to the transition time; |
** otherwise, add the standard time offset |
** to the transition time. |
*/ |
ttisp = &sp->ttis[sp->types[i]]; |
sp->ats[i] += |
(isdst && !ttisp->tt_ttisstd) ? |
dstfix : stdfix; |
isdst = ttisp->tt_isdst; |
} |
} |
} |
else |
{ |
dstlen = 0; |
sp->typecnt = 1; /* only standard time */ |
sp->timecnt = 0; |
sp->ttis[0].tt_gmtoff = -stdoffset; |
sp->ttis[0].tt_isdst = 0; |
sp->ttis[0].tt_abbrind = 0; |
} |
sp->charcnt = stdlen + 1; |
if (dstlen != 0) |
sp->charcnt += dstlen + 1; |
if (sp->charcnt > sizeof sp->chars) |
return -1; |
cp = sp->chars; |
(void) strncpy(cp, stdname, stdlen); |
cp += stdlen; |
*cp++ = '\0'; |
if (dstlen != 0) |
{ |
(void) strncpy(cp, dstname, dstlen); |
*(cp + dstlen) = '\0'; |
} |
return 0; |
} |
static void |
gmtload(struct state * const sp) |
{ |
if (tzload(GMT, sp) != 0) |
(void) tzparse(GMT, sp, TRUE); |
} |
void |
tzset(void) |
{ |
const char * name; |
name = getenv("TZ"); |
if (name == NULL) |
{ |
tzsetwall(); |
return; |
} |
lcl_is_set = TRUE; |
#ifdef ALL_STATE |
if (lclptr == NULL) |
{ |
lclptr = (struct state *) malloc(sizeof *lclptr); |
if (lclptr == NULL) |
{ |
settzname(); /* all we can do */ |
return; |
} |
} |
#endif /* defined ALL_STATE */ |
if (*name == '\0') |
{ |
/* |
** User wants it fast rather than right. |
*/ |
lclptr->leapcnt = 0; /* so, we're off a little */ |
lclptr->timecnt = 0; |
lclptr->ttis[0].tt_gmtoff = 0; |
lclptr->ttis[0].tt_abbrind = 0; |
(void) strcpy(lclptr->chars, GMT); |
} |
else if (tzload(name, lclptr) != 0) |
if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) |
gmtload(lclptr); |
settzname(); |
} |
void |
tzsetwall(void) |
{ |
lcl_is_set = TRUE; |
#ifdef ALL_STATE |
if (lclptr == NULL) |
{ |
lclptr = (struct state *) malloc(sizeof *lclptr); |
if (lclptr == NULL) |
{ |
settzname(); /* all we can do */ |
return; |
} |
} |
#endif /* defined ALL_STATE */ |
if (tzload((char *) NULL, lclptr) != 0) |
gmtload(lclptr); |
settzname(); |
} |
/* |
** The easy way to behave "as if no library function calls" localtime |
** is to not call it--so we drop its guts into "localsub", which can be |
** freely called. (And no, the PANS doesn't require the above behavior-- |
** but it *is* desirable.) |
** |
** The unused offset argument is for the benefit of mktime variants. |
*/ |
/*ARGSUSED*/ |
static void |
localsub(const time_t * const timep, const long offset, struct tm * const tmp) |
{ |
const struct state * sp; |
const struct ttinfo * ttisp; |
int i; |
const time_t t = *timep; |
if (!lcl_is_set) |
tzset(); |
sp = lclptr; |
#ifdef ALL_STATE |
if (sp == NULL) |
{ |
gmtsub(timep, offset, tmp); |
return; |
} |
#endif /* defined ALL_STATE */ |
if (sp->timecnt == 0 || t < sp->ats[0]) |
{ |
i = 0; |
while (sp->ttis[i].tt_isdst) |
if (++i >= sp->typecnt) |
{ |
i = 0; |
break; |
} |
} |
else |
{ |
for (i = 1; i < sp->timecnt; ++i) |
if (t < sp->ats[i]) |
break; |
i = sp->types[i - 1]; |
} |
ttisp = &sp->ttis[i]; |
/* |
** To get (wrong) behavior that's compatible with System V Release 2.0 |
** you'd replace the statement below with |
** t += ttisp->tt_gmtoff; |
** timesub(&t, 0L, sp, tmp); |
*/ |
timesub(&t, ttisp->tt_gmtoff, sp, tmp); |
tmp->tm_isdst = ttisp->tt_isdst; |
tzname[tmp->tm_isdst] = unconst(&sp->chars[ttisp->tt_abbrind], char *); |
tmp->tm_zone = unconst(&sp->chars[ttisp->tt_abbrind], char *); |
} |
struct tm * |
localtime(const time_t * const timep) |
{ |
static struct tm tm; |
localsub(timep, 0L, &tm); |
return &tm; |
} |
/* |
** gmtsub is to gmtime as localsub is to localtime. |
*/ |
static void |
gmtsub(const time_t * const timep, const long offset, struct tm * const tmp) |
{ |
if (!gmt_is_set) |
{ |
gmt_is_set = TRUE; |
#ifdef ALL_STATE |
gmtptr = (struct state *) malloc(sizeof *gmtptr); |
if (gmtptr != NULL) |
#endif /* defined ALL_STATE */ |
gmtload(gmtptr); |
} |
timesub(timep, offset, gmtptr, tmp); |
/* |
** Could get fancy here and deliver something such as |
** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero, |
** but this is no time for a treasure hunt. |
*/ |
if (offset != 0) |
tmp->tm_zone = WILDABBR; |
else |
{ |
#ifdef ALL_STATE |
if (gmtptr == NULL) |
tmp->TM_ZONE = GMT; |
else |
tmp->TM_ZONE = gmtptr->chars; |
#endif /* defined ALL_STATE */ |
#ifndef ALL_STATE |
tmp->tm_zone = gmtptr->chars; |
#endif /* State Farm */ |
} |
} |
struct tm * |
gmtime(const time_t * const timep) |
{ |
static struct tm tm; |
gmtsub(timep, 0L, &tm); |
return &tm; |
} |
static void |
timesub(const time_t * const timep, const long offset, const struct state * const sp, struct tm * const tmp) |
{ |
const struct lsinfo * lp; |
long days; |
long rem; |
int y; |
int yleap; |
const int * ip; |
long corr; |
int hit; |
int i; |
corr = 0; |
hit = FALSE; |
#ifdef ALL_STATE |
i = (sp == NULL) ? 0 : sp->leapcnt; |
#endif /* defined ALL_STATE */ |
#ifndef ALL_STATE |
i = sp->leapcnt; |
#endif /* State Farm */ |
while (--i >= 0) |
{ |
lp = &sp->lsis[i]; |
if (*timep >= lp->ls_trans) |
{ |
if (*timep == lp->ls_trans) |
hit = ((i == 0 && lp->ls_corr > 0) || |
lp->ls_corr > sp->lsis[i - 1].ls_corr); |
corr = lp->ls_corr; |
break; |
} |
} |
days = *timep / SECSPERDAY; |
rem = *timep % SECSPERDAY; |
#ifdef mc68k |
if (*timep == 0x80000000) |
{ |
/* |
** A 3B1 muffs the division on the most negative number. |
*/ |
days = -24855; |
rem = -11648; |
} |
#endif /* mc68k */ |
rem += (offset - corr); |
while (rem < 0) |
{ |
rem += SECSPERDAY; |
--days; |
} |
while (rem >= SECSPERDAY) |
{ |
rem -= SECSPERDAY; |
++days; |
} |
tmp->tm_hour = (int) (rem / SECSPERHOUR); |
rem = rem % SECSPERHOUR; |
tmp->tm_min = (int) (rem / SECSPERMIN); |
tmp->tm_sec = (int) (rem % SECSPERMIN); |
if (hit) |
/* |
** A positive leap second requires a special |
** representation. This uses "... ??:59:60". |
*/ |
++(tmp->tm_sec); |
tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); |
if (tmp->tm_wday < 0) |
tmp->tm_wday += DAYSPERWEEK; |
y = EPOCH_YEAR; |
if (days >= 0) |
for ( ; ; ) |
{ |
yleap = isleap(y); |
if (days < (long) year_lengths[yleap]) |
break; |
++y; |
days = days - (long) year_lengths[yleap]; |
} |
else |
do { |
--y; |
yleap = isleap(y); |
days = days + (long) year_lengths[yleap]; |
} while (days < 0); |
tmp->tm_year = y - TM_YEAR_BASE; |
tmp->tm_yday = (int) days; |
ip = mon_lengths[yleap]; |
for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) |
days = days - (long) ip[tmp->tm_mon]; |
tmp->tm_mday = (int) (days + 1); |
tmp->tm_isdst = 0; |
tmp->tm_gmtoff = offset; |
} |
/* |
** A la X3J11 |
*/ |
char * |
asctime(const struct tm *timeptr) |
{ |
static const char wday_name[DAYSPERWEEK][3] = { |
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
}; |
static const char mon_name[MONSPERYEAR][3] = { |
"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
}; |
static char result[26]; |
(void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n", |
wday_name[timeptr->tm_wday], |
mon_name[timeptr->tm_mon], |
timeptr->tm_mday, timeptr->tm_hour, |
timeptr->tm_min, timeptr->tm_sec, |
TM_YEAR_BASE + timeptr->tm_year); |
return result; |
} |
char * |
ctime(const time_t * const timep) |
{ |
return asctime(localtime(timep)); |
} |
/* |
** Adapted from code provided by Robert Elz, who writes: |
** The "best" way to do mktime I think is based on an idea of Bob |
** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). |
** It does a binary search of the time_t space. Since time_t's are |
** just 32 bits, its a max of 32 iterations (even at 64 bits it |
** would still be very reasonable). |
*/ |
#ifndef WRONG |
#define WRONG (-1) |
#endif /* !defined WRONG */ |
static void |
normalize(int * const tensptr, int * const unitsptr, const int base) |
{ |
if (*unitsptr >= base) |
{ |
*tensptr += *unitsptr / base; |
*unitsptr %= base; |
} |
else if (*unitsptr < 0) |
{ |
--*tensptr; |
*unitsptr += base; |
if (*unitsptr < 0) |
{ |
*tensptr -= 1 + (-*unitsptr) / base; |
*unitsptr = base - (-*unitsptr) % base; |
} |
} |
} |
static int |
tmcomp(const struct tm * const atmp, const struct tm * const btmp) |
{ |
int result; |
if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && |
(result = (atmp->tm_mon - btmp->tm_mon)) == 0 && |
(result = (atmp->tm_mday - btmp->tm_mday)) == 0 && |
(result = (atmp->tm_hour - btmp->tm_hour)) == 0 && |
(result = (atmp->tm_min - btmp->tm_min)) == 0) |
result = atmp->tm_sec - btmp->tm_sec; |
return result; |
} |
static time_t |
time2(struct tm *tmp, void (*const funcp)(const time_t *const,const long,struct tm *), const long offset, int * const okayp) |
{ |
const struct state * sp; |
int dir; |
int bits; |
int i, j ; |
int saved_seconds; |
time_t newt; |
time_t t; |
struct tm yourtm, mytm; |
*okayp = FALSE; |
yourtm = *tmp; |
if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0) |
normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN); |
normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR); |
normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY); |
normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR); |
while (yourtm.tm_mday <= 0) |
{ |
--yourtm.tm_year; |
yourtm.tm_mday += |
year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)]; |
} |
for ( ; ; ) |
{ |
i = mon_lengths[isleap(yourtm.tm_year + |
TM_YEAR_BASE)][yourtm.tm_mon]; |
if (yourtm.tm_mday <= i) |
break; |
yourtm.tm_mday -= i; |
if (++yourtm.tm_mon >= MONSPERYEAR) |
{ |
yourtm.tm_mon = 0; |
++yourtm.tm_year; |
} |
} |
saved_seconds = yourtm.tm_sec; |
yourtm.tm_sec = 0; |
/* |
** Calculate the number of magnitude bits in a time_t |
** (this works regardless of whether time_t is |
** signed or unsigned, though lint complains if unsigned). |
*/ |
for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) |
; |
/* |
** If time_t is signed, then 0 is the median value, |
** if time_t is unsigned, then 1 << bits is median. |
*/ |
t = (time_t) 1 << bits; |
for ( ; ; ) |
{ |
(*funcp)(&t, offset, &mytm); |
dir = tmcomp(&mytm, &yourtm); |
if (dir != 0) |
{ |
if (bits-- < 0) |
return WRONG; |
if (bits < 0) |
--t; |
else if (dir > 0) |
t -= (time_t) 1 << bits; |
else t += (time_t) 1 << bits; |
continue; |
} |
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) |
break; |
/* |
** Right time, wrong type. |
** Hunt for right time, right type. |
** It's okay to guess wrong since the guess |
** gets checked. |
*/ |
sp = (const struct state *) |
((funcp == localsub) ? lclptr : gmtptr); |
#ifdef ALL_STATE |
if (sp == NULL) |
return WRONG; |
#endif /* defined ALL_STATE */ |
for (i = 0; i < sp->typecnt; ++i) |
{ |
if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) |
continue; |
for (j = 0; j < sp->typecnt; ++j) |
{ |
if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) |
continue; |
newt = t + sp->ttis[j].tt_gmtoff - |
sp->ttis[i].tt_gmtoff; |
(*funcp)(&newt, offset, &mytm); |
if (tmcomp(&mytm, &yourtm) != 0) |
continue; |
if (mytm.tm_isdst != yourtm.tm_isdst) |
continue; |
/* |
** We have a match. |
*/ |
t = newt; |
goto label; |
} |
} |
return WRONG; |
} |
label: |
t += saved_seconds; |
(*funcp)(&t, offset, tmp); |
*okayp = TRUE; |
return t; |
} |
static time_t |
time1(struct tm * const tmp, void (*const funcp)(const time_t * const, const long, struct tm *), const long offset) |
{ |
time_t t; |
const struct state * sp; |
int samei, otheri; |
int okay; |
if (tmp->tm_isdst > 1) |
tmp->tm_isdst = 1; |
t = time2(tmp, funcp, offset, &okay); |
if (okay || tmp->tm_isdst < 0) |
return t; |
/* |
** We're supposed to assume that somebody took a time of one type |
** and did some math on it that yielded a "struct tm" that's bad. |
** We try to divine the type they started from and adjust to the |
** type they need. |
*/ |
sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); |
#ifdef ALL_STATE |
if (sp == NULL) |
return WRONG; |
#endif /* defined ALL_STATE */ |
for (samei = 0; samei < sp->typecnt; ++samei) |
{ |
if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) |
continue; |
for (otheri = 0; otheri < sp->typecnt; ++otheri) |
{ |
if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) |
continue; |
tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - |
sp->ttis[samei].tt_gmtoff; |
tmp->tm_isdst = !tmp->tm_isdst; |
t = time2(tmp, funcp, offset, &okay); |
if (okay) |
return t; |
tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - |
sp->ttis[samei].tt_gmtoff; |
tmp->tm_isdst = !tmp->tm_isdst; |
} |
} |
return WRONG; |
} |
time_t |
mktime(struct tm * tmp) |
{ |
return time1(tmp, localsub, 0L); |
} |
/programs/develop/libraries/menuetlibc/src/libc/ansi/time/difftime.c |
---|
0,0 → 1,7 |
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ |
#include <time.h> |
double difftime(time_t time1, time_t time0) |
{ |
return time1-time0; |
} |
/programs/develop/libraries/menuetlibc/src/libc/ansi/time/posixrul.h |
---|
0,0 → 1,49 |
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
/* generated with bin2h from DJGPP/zoneinfo/posixrules */ |
unsigned char _posixrules_data[] = { |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, |
0,1,16,0,0,0,2,0,0,0,8,0,151,254,240,1,135,225,224,2,119,224,240,3,112,254,96,4,96,253,112,5,80, |
224,96,6,64,223,112,7,48,194,96,7,141,25,112,9,16,164,96,9,173,148,240,10,240,134,96,11,224,133,112,12,217,162, |
224,13,192,103,112,14,185,132,224,15,169,131,240,16,153,102,224,17,137,101,240,18,121,72,224,19,105,71,240,20,89,42,224, |
21,73,41,240,22,57,12,224,23,41,11,240,24,34,41,96,25,8,237,240,26,2,11,96,26,242,10,112,27,225,237,96,28, |
209,236,112,29,193,207,96,30,177,206,112,31,161,177,96,32,118,0,240,33,129,147,96,34,85,226,240,35,106,175,224,36,53, |
196,240,37,74,145,224,38,21,166,240,39,42,115,224,39,254,195,112,41,10,85,224,41,222,165,112,42,234,55,224,43,190,135, |
112,44,211,84,96,45,158,105,112,46,179,54,96,47,126,75,112,48,147,24,96,49,103,103,240,50,114,250,96,51,71,73,240, |
52,82,220,96,53,39,43,240,54,50,190,96,55,7,13,240,56,27,218,224,56,230,239,240,57,251,188,224,58,198,209,240,59, |
219,158,224,60,175,238,112,61,187,128,224,62,143,208,112,63,155,98,224,64,111,178,112,65,132,127,96,66,79,148,112,67,100, |
97,96,68,47,118,112,69,68,67,96,70,15,88,112,71,36,37,96,71,248,116,240,73,4,7,96,73,216,86,240,74,227,233, |
96,75,184,56,240,76,205,5,224,77,152,26,240,78,172,231,224,79,119,252,240,80,140,201,224,81,97,25,112,82,108,171,224, |
83,64,251,112,84,76,141,224,85,32,221,112,86,44,111,224,87,0,191,112,88,21,140,96,88,224,161,112,89,245,110,96,90, |
192,131,112,91,213,80,96,92,169,159,240,93,181,50,96,94,137,129,240,95,149,20,96,96,105,99,240,97,126,48,224,98,73, |
69,240,99,94,18,224,100,41,39,240,101,61,244,224,102,18,68,112,103,29,214,224,103,242,38,112,104,253,184,224,105,210,8, |
112,106,221,154,224,107,177,234,112,108,198,183,96,109,145,204,112,110,166,153,96,111,113,174,112,112,134,123,96,113,90,202,240, |
114,102,93,96,115,58,172,240,116,70,63,96,117,26,142,240,118,47,91,224,118,250,112,240,120,15,61,224,120,218,82,240,121, |
239,31,224,122,186,52,240,123,207,1,224,124,163,81,112,125,174,227,224,126,131,51,112,127,142,197,224,128,99,21,112,129,119, |
226,96,130,66,247,112,131,87,196,96,132,34,217,112,133,55,166,96,134,11,245,240,135,23,136,96,135,235,215,240,136,247,106, |
96,137,203,185,240,138,215,76,96,139,171,155,240,140,192,104,224,141,139,125,240,142,160,74,224,143,107,95,240,144,128,44,224, |
145,84,124,112,146,96,14,224,147,52,94,112,148,63,240,224,149,20,64,112,150,41,13,96,150,244,34,112,152,8,239,96,152, |
212,4,112,153,232,209,96,154,189,32,240,155,200,179,96,156,157,2,240,157,168,149,96,158,124,228,240,159,136,119,96,160,92, |
198,240,161,113,147,224,162,60,168,240,163,81,117,224,164,28,138,240,165,49,87,224,166,5,167,112,167,17,57,224,167,229,137, |
112,168,241,27,224,169,197,107,112,170,218,56,96,171,165,77,112,172,186,26,96,173,133,47,112,174,153,252,96,175,101,17,112, |
176,121,222,96,177,78,45,240,178,89,192,96,179,46,15,240,180,57,162,96,181,13,241,240,182,34,190,224,182,237,211,240,184, |
2,160,224,184,205,181,240,185,226,130,224,186,182,210,112,187,194,100,224,188,150,180,112,189,162,70,224,190,118,150,112,191,130, |
40,224,192,86,120,112,193,107,69,96,194,54,90,112,195,75,39,96,196,22,60,112,197,43,9,96,197,255,88,240,199,10,235, |
96,199,223,58,240,200,234,205,96,201,191,28,240,202,211,233,224,203,158,254,240,204,179,203,224,205,126,224,240,206,147,173,224, |
207,103,253,112,208,115,143,224,209,71,223,112,210,83,113,224,211,39,193,112,212,51,83,224,213,7,163,112,214,28,112,96,214, |
231,133,112,215,252,82,96,216,199,103,112,217,220,52,96,218,176,131,240,219,188,22,96,220,144,101,240,221,155,248,96,222,112, |
71,240,223,133,20,224,224,80,41,240,225,100,246,224,226,48,11,240,227,68,216,224,228,15,237,240,229,36,186,224,229,249,10, |
112,231,4,156,224,231,216,236,112,232,228,126,224,233,184,206,112,234,205,155,96,235,152,176,112,236,173,125,96,237,120,146,112, |
238,141,95,96,239,97,174,240,240,109,65,96,241,65,144,240,242,77,35,96,243,33,114,240,244,45,5,96,245,1,84,240,246, |
22,33,224,246,225,54,240,247,246,3,224,248,193,24,240,249,213,229,224,250,160,250,240,251,181,199,224,252,138,23,112,253,149, |
169,224,254,105,249,112,255,117,139,224,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, |
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, |
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, |
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, |
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, |
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, |
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, |
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, |
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,255,255,199,192,1,0,255,255,185,176,0,4,69,68,84, |
0,69,83,84,0,0,0 |
}; |
/programs/develop/libraries/menuetlibc/src/libc/ansi/time/strftime.c |
---|
0,0 → 1,226 |
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ |
#include <string.h> |
#include <time.h> |
#define TM_YEAR_BASE 1900 |
static const char *afmt[] = { |
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", |
}; |
static const char *Afmt[] = { |
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", |
"Saturday", |
}; |
static const char *bfmt[] = { |
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", |
"Oct", "Nov", "Dec", |
}; |
static const char *Bfmt[] = { |
"January", "February", "March", "April", "May", "June", "July", |
"August", "September", "October", "November", "December", |
}; |
static size_t gsize; |
static char *pt; |
static int |
_add(const char *str) |
{ |
for (;; ++pt, --gsize) |
{ |
if (!gsize) |
return 0; |
if (!(*pt = *str++)) |
return 1; |
} |
} |
static int |
_conv(int n, int digits, char pad) |
{ |
static char buf[10]; |
char *p; |
for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits) |
*p-- = n % 10 + '0'; |
while (p > buf && digits-- > 0) |
*p-- = pad; |
return _add(++p); |
} |
static size_t |
_fmt(const char *format, const struct tm *t) |
{ |
for (; *format; ++format) |
{ |
if (*format == '%') |
switch(*++format) |
{ |
case '\0': |
--format; |
break; |
case 'A': |
if (t->tm_wday < 0 || t->tm_wday > 6) |
return 0; |
if (!_add(Afmt[t->tm_wday])) |
return 0; |
continue; |
case 'a': |
if (t->tm_wday < 0 || t->tm_wday > 6) |
return 0; |
if (!_add(afmt[t->tm_wday])) |
return 0; |
continue; |
case 'B': |
if (t->tm_mon < 0 || t->tm_mon > 11) |
return 0; |
if (!_add(Bfmt[t->tm_mon])) |
return 0; |
continue; |
case 'b': |
case 'h': |
if (t->tm_mon < 0 || t->tm_mon > 11) |
return 0; |
if (!_add(bfmt[t->tm_mon])) |
return 0; |
continue; |
case 'C': |
if (!_fmt("%a %b %e %H:%M:%S %Y", t)) |
return 0; |
continue; |
case 'c': |
if (!_fmt("%m/%d/%y %H:%M:%S", t)) |
return 0; |
continue; |
case 'e': |
if (!_conv(t->tm_mday, 2, ' ')) |
return 0; |
continue; |
case 'D': |
if (!_fmt("%m/%d/%y", t)) |
return 0; |
continue; |
case 'd': |
if (!_conv(t->tm_mday, 2, '0')) |
return 0; |
continue; |
case 'H': |
if (!_conv(t->tm_hour, 2, '0')) |
return 0; |
continue; |
case 'I': |
if (!_conv(t->tm_hour % 12 ? |
t->tm_hour % 12 : 12, 2, '0')) |
return 0; |
continue; |
case 'j': |
if (!_conv(t->tm_yday + 1, 3, '0')) |
return 0; |
continue; |
case 'k': |
if (!_conv(t->tm_hour, 2, ' ')) |
return 0; |
continue; |
case 'l': |
if (!_conv(t->tm_hour % 12 ? |
t->tm_hour % 12 : 12, 2, ' ')) |
return 0; |
continue; |
case 'M': |
if (!_conv(t->tm_min, 2, '0')) |
return 0; |
continue; |
case 'm': |
if (!_conv(t->tm_mon + 1, 2, '0')) |
return 0; |
continue; |
case 'n': |
if (!_add("\n")) |
return 0; |
continue; |
case 'p': |
if (!_add(t->tm_hour >= 12 ? "PM" : "AM")) |
return 0; |
continue; |
case 'R': |
if (!_fmt("%H:%M", t)) |
return 0; |
continue; |
case 'r': |
if (!_fmt("%I:%M:%S %p", t)) |
return 0; |
continue; |
case 'S': |
if (!_conv(t->tm_sec, 2, '0')) |
return 0; |
continue; |
case 'T': |
case 'X': |
if (!_fmt("%H:%M:%S", t)) |
return 0; |
continue; |
case 't': |
if (!_add("\t")) |
return 0; |
continue; |
case 'U': |
if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7, |
2, '0')) |
return 0; |
continue; |
case 'W': |
if (!_conv((t->tm_yday + 7 - |
(t->tm_wday ? (t->tm_wday - 1) : 6)) |
/ 7, 2, '0')) |
return 0; |
continue; |
case 'w': |
if (!_conv(t->tm_wday, 1, '0')) |
return 0; |
continue; |
case 'x': |
if (!_fmt("%m/%d/%y", t)) |
return 0; |
continue; |
case 'y': |
if (!_conv((t->tm_year + TM_YEAR_BASE) |
% 100, 2, '0')) |
return 0; |
continue; |
case 'Y': |
if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0')) |
return 0; |
continue; |
case 'Z': |
if (!t->tm_zone || !_add(t->tm_zone)) |
return 0; |
continue; |
case '%': |
/* |
* X311J/88-090 (4.12.3.5): if conversion char is |
* undefined, behavior is undefined. Print out the |
* character itself as printf(3) does. |
*/ |
default: |
break; |
} |
if (!gsize--) |
return 0; |
*pt++ = *format; |
} |
return gsize; |
} |
size_t |
strftime(char *s, size_t maxsize, const char *format, const struct tm *t) |
{ |
pt = s; |
if ((gsize = maxsize) < 1) |
return 0; |
if (_fmt(format, t)) |
{ |
*pt = '\0'; |
return maxsize - gsize; |
} |
return 0; |
} |
/programs/develop/libraries/menuetlibc/src/libc/ansi/time/time.c |
---|
0,0 → 1,13 |
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
#include <time.h> |
time_t time(time_t *t) |
{ |
struct timeval tt; |
if (gettimeofday(&tt, 0) < 0) |
return(-1); |
if (t) |
*t = tt.tv_sec; |
return tt.tv_sec; |
} |