2002-04-17 Jeff Johnston <jjohnstn@redhat.com>

*  libc/include/time.h (tzset, _tzset_r): Added prototypes.
        (strptime): Moved prototype to be within !__STRICT_ANSI__.
        (_tzname, _daylight, _timezone): No long __CYGWIN__ only.
        (tzname): Defined for all platforms.
        (daylight, timezone): Defined only for CYGWIN.
        *  libc/sys/linux/machine/i386/crt0.c: Add call to tzset() after
        environment set up.
        * libc/stdlib/setenv_r.c (_setenv_r): Call tzset() if the TZ
        environment variable is set.
        *  libc/time/Makefile.am: Add support for tzset.c, tzlock.c, and
        tzset_r.c.
        *  libc/time/Makefile.in: Regenerated.
        *  libc/time/gmtime.c (gmtime): Changed to call gmtime_r.
        *  libc/time/gmtime_r.c (gmtime_r): Changed to call _mktm_r.
        *  libc/time/lcltime_r.c (lcltime_r): Ditto.
        *  libc/time/local.h: New local header file.
        *  libc/time/mktime.c (mktime): Add timezone support.
        *  libc/time/mktm_r.c: New file which is the common engine
        for gmtime_r and lcltime_r.  This code has timezone support.
        *  libc/time/strftime.c (strftime): Add %Z timezone support.
        *  libc/time/tzlock.c: New file containing timezone lock stubs.
        *  libc/time/tzset.c: New file containing tzset() routine.
        *  libc/time/tzset_r.c: New file containing _tzset_r and
        internal routine for calculating timezone changes for specified year.
This commit is contained in:
Jeff Johnston 2002-04-17 21:23:31 +00:00
parent a26c50352b
commit 10d0021609
16 changed files with 770 additions and 118 deletions

View File

@ -1,3 +1,30 @@
2002-04-17 Jeff Johnston <jjohnstn@redhat.com>
* libc/include/time.h (tzset, _tzset_r): Added prototypes.
(strptime): Moved prototype to be within !__STRICT_ANSI__.
(_tzname, _daylight, _timezone): No long __CYGWIN__ only.
(tzname): Defined for all platforms.
(daylight, timezone): Defined only for CYGWIN.
* libc/sys/linux/machine/i386/crt0.c: Add call to tzset() after
environment set up.
* libc/stdlib/setenv_r.c (_setenv_r): Call tzset() if the TZ
environment variable is set.
* libc/time/Makefile.am: Add support for tzset.c, tzlock.c, and
tzset_r.c.
* libc/time/Makefile.in: Regenerated.
* libc/time/gmtime.c (gmtime): Changed to call gmtime_r.
* libc/time/gmtime_r.c (gmtime_r): Changed to call _mktm_r.
* libc/time/lcltime_r.c (lcltime_r): Ditto.
* libc/time/local.h: New local header file.
* libc/time/mktime.c (mktime): Add timezone support.
* libc/time/mktm_r.c: New file which is the common engine
for gmtime_r and lcltime_r. This code has timezone support.
* libc/time/strftime.c (strftime): Add %Z timezone support.
* libc/time/tzlock.c: New file containing timezone lock stubs.
* libc/time/tzset.c: New file containing tzset() routine.
* libc/time/tzset_r.c: New file containing _tzset_r and
internal routine for calculating timezone changes for specified year.
2002-04-17 Thomas Fitzsimmons <fitzsim@redhat.com> 2002-04-17 Thomas Fitzsimmons <fitzsim@redhat.com>
* configure.in (CRT0_DIR): Set to libc/. * configure.in (CRT0_DIR): Set to libc/.

View File

@ -8,6 +8,7 @@
#define _TIME_H_ #define _TIME_H_
#include "_ansi.h" #include "_ansi.h"
#include <sys/reent.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -55,22 +56,29 @@ struct tm *_EXFUN(gmtime, (const time_t *_timer));
struct tm *_EXFUN(localtime,(const time_t *_timer)); struct tm *_EXFUN(localtime,(const time_t *_timer));
#endif #endif
size_t _EXFUN(strftime, (char *_s, size_t _maxsize, const char *_fmt, const struct tm *_t)); size_t _EXFUN(strftime, (char *_s, size_t _maxsize, const char *_fmt, const struct tm *_t));
char *_EXFUN(strptime, (const char *, const char *, struct tm *));
char *_EXFUN(asctime_r, (const struct tm *, char *)); char *_EXFUN(asctime_r, (const struct tm *, char *));
char *_EXFUN(ctime_r, (const time_t *, char *)); char *_EXFUN(ctime_r, (const time_t *, char *));
struct tm *_EXFUN(gmtime_r, (const time_t *, struct tm *)); struct tm *_EXFUN(gmtime_r, (const time_t *, struct tm *));
struct tm *_EXFUN(localtime_r, (const time_t *, struct tm *)); struct tm *_EXFUN(localtime_r, (const time_t *, struct tm *));
#ifdef __CYGWIN__
#ifndef __STRICT_ANSI__ #ifndef __STRICT_ANSI__
char *_EXFUN(strptime, (const char *, const char *, struct tm *));
_VOID _EXFUN(tzset, (_VOID));
_VOID _EXFUN(_tzset_r, (struct _reent *));
/* defines for the opengroup specifications Derived from Issue 1 of the SVID. */
extern __IMPORT time_t _timezone; extern __IMPORT time_t _timezone;
extern __IMPORT int _daylight; extern __IMPORT int _daylight;
extern __IMPORT char *_tzname[2]; extern __IMPORT char *_tzname[2];
/* defines for the opengroup specifications Derived from Issue 1 of the SVID. */
/* POSIX defines the external tzname being defined in time.h */
#ifndef tzname #ifndef tzname
#define tzname _tzname #define tzname _tzname
#endif #endif
/* CYGWIN also exposes daylight and timezone in the name space */
#ifdef __CYGWIN__
#ifndef daylight #ifndef daylight
#define daylight _daylight #define daylight _daylight
#endif #endif
@ -81,13 +89,11 @@ extern __IMPORT char *_tzname[2];
#else #else
char *_EXFUN(timezone, (void)); char *_EXFUN(timezone, (void));
#endif #endif
void _EXFUN(tzset, (void));
#endif
#endif /* __CYGWIN__ */ #endif /* __CYGWIN__ */
#endif /* !__STRICT_ANSI__ */
#include <sys/features.h> #include <sys/features.h>
#if defined(_POSIX_TIMERS) #if defined(_POSIX_TIMERS)
#include <signal.h> #include <signal.h>

View File

@ -1,5 +1,5 @@
/* This file may have been modified by DJ Delorie (Jan 1991). If so, /* This file may have been modified by DJ Delorie (Jan 1991). If so,
** these modifications are Copyright (C) 1991 DJ Delorie ** these modifications are Copyright (C) 1991 DJ Delorie.
*/ */
/* /*
@ -26,6 +26,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include "envlock.h" #include "envlock.h"
extern char **environ; extern char **environ;
@ -69,8 +70,11 @@ _DEFUN (_setenv_r, (reent_ptr, name, value, rewrite),
} }
if (strlen (C) >= l_value) if (strlen (C) >= l_value)
{ /* old larger; copy over */ { /* old larger; copy over */
while ((*C++ = *value++) != 0); while ((*C++ = *value++) != 0);
ENV_UNLOCK; ENV_UNLOCK;
/* if we are changing the TZ environment variable, update timezone info */
if (strcmp (name, "TZ") == 0)
tzset ();
return 0; return 0;
} }
} }
@ -117,6 +121,10 @@ _DEFUN (_setenv_r, (reent_ptr, name, value, rewrite),
ENV_UNLOCK; ENV_UNLOCK;
/* if we are setting the TZ environment variable, update timezone info */
if (strcmp (name, "TZ") == 0)
tzset ();
return 0; return 0;
} }

View File

@ -8,6 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
extern char **environ; extern char **environ;
@ -28,5 +29,6 @@ void _start(int args)
char **argv = (char **) (params+1); char **argv = (char **) (params+1);
environ = argv+argc+1; environ = argv+argc+1;
tzset(); /* initialize timezone info */
exit(main(argc,argv,environ)); exit(main(argc,argv,environ));
} }

View File

@ -16,9 +16,13 @@ LIB_SOURCES = \
lcltime.c \ lcltime.c \
lcltime_r.c \ lcltime_r.c \
mktime.c \ mktime.c \
mktm_r.c \
strftime.c \ strftime.c \
strptime.c \ strptime.c \
time.c time.c \
tzlock.c \
tzset.c \
tzset_r.c
libtime_la_LDFLAGS = -Xcompiler -nostdlib libtime_la_LDFLAGS = -Xcompiler -nostdlib
@ -43,7 +47,9 @@ CHEWOUT_FILES = \
lcltime.def \ lcltime.def \
mktime.def \ mktime.def \
strftime.def \ strftime.def \
time.def time.def \
tzlock.def \
tzset.def
SUFFIXES = .def SUFFIXES = .def

View File

@ -107,9 +107,13 @@ LIB_SOURCES = \
lcltime.c \ lcltime.c \
lcltime_r.c \ lcltime_r.c \
mktime.c \ mktime.c \
mktm_r.c \
strftime.c \ strftime.c \
strptime.c \ strptime.c \
time.c time.c \
tzlock.c \
tzset.c \
tzset_r.c
libtime_la_LDFLAGS = -Xcompiler -nostdlib libtime_la_LDFLAGS = -Xcompiler -nostdlib
@ -130,7 +134,9 @@ CHEWOUT_FILES = \
lcltime.def \ lcltime.def \
mktime.def \ mktime.def \
strftime.def \ strftime.def \
time.def time.def \
tzlock.def \
tzset.def
SUFFIXES = .def SUFFIXES = .def
@ -151,15 +157,16 @@ LIBS = @LIBS@
lib_a_LIBADD = lib_a_LIBADD =
@USE_LIBTOOL_FALSE@lib_a_OBJECTS = asctime.o asctime_r.o clock.o \ @USE_LIBTOOL_FALSE@lib_a_OBJECTS = asctime.o asctime_r.o clock.o \
@USE_LIBTOOL_FALSE@ctime.o ctime_r.o difftime.o gmtime.o gmtime_r.o \ @USE_LIBTOOL_FALSE@ctime.o ctime_r.o difftime.o gmtime.o gmtime_r.o \
@USE_LIBTOOL_FALSE@lcltime.o lcltime_r.o mktime.o strftime.o strptime.o \ @USE_LIBTOOL_FALSE@lcltime.o lcltime_r.o mktime.o mktm_r.o strftime.o \
@USE_LIBTOOL_FALSE@time.o @USE_LIBTOOL_FALSE@strptime.o time.o tzlock.o tzset.o tzset_r.o
LTLIBRARIES = $(noinst_LTLIBRARIES) LTLIBRARIES = $(noinst_LTLIBRARIES)
libtime_la_LIBADD = libtime_la_LIBADD =
@USE_LIBTOOL_TRUE@libtime_la_OBJECTS = asctime.lo asctime_r.lo clock.lo \ @USE_LIBTOOL_TRUE@libtime_la_OBJECTS = asctime.lo asctime_r.lo clock.lo \
@USE_LIBTOOL_TRUE@ctime.lo ctime_r.lo difftime.lo gmtime.lo gmtime_r.lo \ @USE_LIBTOOL_TRUE@ctime.lo ctime_r.lo difftime.lo gmtime.lo gmtime_r.lo \
@USE_LIBTOOL_TRUE@lcltime.lo lcltime_r.lo mktime.lo strftime.lo \ @USE_LIBTOOL_TRUE@lcltime.lo lcltime_r.lo mktime.lo mktm_r.lo \
@USE_LIBTOOL_TRUE@strptime.lo time.lo @USE_LIBTOOL_TRUE@strftime.lo strptime.lo time.lo tzlock.lo tzset.lo \
@USE_LIBTOOL_TRUE@tzset_r.lo
CFLAGS = @CFLAGS@ CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)

View File

@ -59,9 +59,8 @@ struct tm *
_DEFUN (gmtime, (tim_p), _DEFUN (gmtime, (tim_p),
_CONST time_t * tim_p) _CONST time_t * tim_p)
{ {
time_t tim = *tim_p + _GMT_OFFSET; _REENT_CHECK_TM(_REENT);
return gmtime_r (tim_p, (struct tm *)_REENT_TM(_REENT));
return (localtime (&tim));
} }
#endif #endif

View File

@ -3,15 +3,12 @@
*/ */
#include <time.h> #include <time.h>
#include "local.h"
#define _GMT_OFFSET 0
struct tm * struct tm *
_DEFUN (gmtime_r, (tim_p, res), _DEFUN (gmtime_r, (tim_p, res),
_CONST time_t * tim_p _AND _CONST time_t * tim_p _AND
struct tm *res) struct tm *res)
{ {
time_t tim = *tim_p + _GMT_OFFSET; return (_mktm_r (tim_p, res, 1));
return (localtime_r (&tim, res));
} }

View File

@ -1,104 +1,18 @@
/* /*
* localtime_r.c * localtime_r.c
* Original Author: Adapted from tzcode maintained by Arthur David Olson.
* *
* Converts the calendar time pointed to by tim_p into a broken-down time * Converts the calendar time pointed to by tim_p into a broken-down time
* expressed as local time. Returns a pointer to a structure containing the * expressed as local time. Returns a pointer to a structure containing the
* broken-down time. * broken-down time.
*/ */
#include <stdlib.h>
#include <time.h> #include <time.h>
#include "local.h"
#define SECSPERMIN 60L
#define MINSPERHOUR 60L
#define HOURSPERDAY 24L
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY)
#define DAYSPERWEEK 7
#define MONSPERYEAR 12
#define YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY 4
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
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] = {
365,
366
} ;
struct tm * struct tm *
_DEFUN (localtime_r, (tim_p, res), _DEFUN (localtime_r, (tim_p, res),
_CONST time_t * tim_p _AND _CONST time_t * tim_p _AND
struct tm *res) struct tm *res)
{ {
long days, rem; return _mktm_r (tim_p, res, 0);
int y;
int yleap;
_CONST int *ip;
days = ((long) *tim_p) / SECSPERDAY;
rem = ((long) *tim_p) % SECSPERDAY;
while (rem < 0)
{
rem += SECSPERDAY;
--days;
}
while (rem >= SECSPERDAY)
{
rem -= SECSPERDAY;
++days;
}
/* compute hour, min, and sec */
res->tm_hour = (int) (rem / SECSPERHOUR);
rem %= SECSPERHOUR;
res->tm_min = (int) (rem / SECSPERMIN);
res->tm_sec = (int) (rem % SECSPERMIN);
/* compute day of week */
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
res->tm_wday += DAYSPERWEEK;
/* compute year & day of year */
y = EPOCH_YEAR;
if (days >= 0)
{
for (;;)
{
yleap = isleap(y);
if (days < year_lengths[yleap])
break;
y++;
days -= year_lengths[yleap];
}
}
else
{
do
{
--y;
yleap = isleap(y);
days += year_lengths[yleap];
} while (days < 0);
}
res->tm_year = y - YEAR_BASE;
res->tm_yday = days;
ip = mon_lengths[yleap];
for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
days -= ip[res->tm_mon];
res->tm_mday = days + 1;
/* set daylight saving time flag */
res->tm_isdst = -1;
return (res);
} }

54
newlib/libc/time/local.h Normal file
View File

@ -0,0 +1,54 @@
/* local header used by libc/time routines */
#include <_ansi.h>
#include <time.h>
#define SECSPERMIN 60L
#define MINSPERHOUR 60L
#define HOURSPERDAY 24L
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY)
#define DAYSPERWEEK 7
#define MONSPERYEAR 12
#define YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY 4
#define EPOCH_YEARS_SINCE_LEAP 2
#define EPOCH_YEARS_SINCE_CENTURY 70
#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
extern time_t __tzstart_std;
extern time_t __tzstart_dst;
extern int __tznorth;
extern int __tzyear;
typedef struct __tzrule_struct
{
char ch;
int m;
int n;
int d;
int s;
time_t change;
int offset;
} __tzrule_type;
extern __tzrule_type __tzrule[2];
struct tm * _EXFUN (_mktm_r, (_CONST time_t *, struct tm *, int __is_gmtime));
int _EXFUN (__tzcalc_limits, (int __year));
/* locks for multi-threading */
#ifdef __SINGLE_THREAD__
#define TZ_LOCK
#define TZ_UNLOCK
#else
#define TZ_LOCK __tz_lock()
#define TZ_UNLOCK __tz_unlock()
#endif
void _EXFUN(__tz_lock,(_VOID));
void _EXFUN(__tz_unlock,(_VOID));

View File

@ -47,6 +47,7 @@ ANSI C requires <<mktime>>.
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "local.h"
#define _SEC_IN_MINUTE 60L #define _SEC_IN_MINUTE 60L
#define _SEC_IN_HOUR 3600L #define _SEC_IN_HOUR 3600L
@ -156,7 +157,7 @@ mktime (tim_p)
{ {
time_t tim = 0; time_t tim = 0;
long days = 0; long days = 0;
int year; int year, isdst;
/* validate structure */ /* validate structure */
validate_structure (tim_p); validate_structure (tim_p);
@ -200,5 +201,50 @@ mktime (tim_p)
/* compute total seconds */ /* compute total seconds */
tim += (days * _SEC_IN_DAY); tim += (days * _SEC_IN_DAY);
isdst = tim_p->tm_isdst;
if (_daylight)
{
int y = tim_p->tm_year + YEAR_BASE;
if (y == __tzyear || __tzcalc_limits (y))
{
/* calculate start of dst in dst local time and
start of std in both std local time and dst local time */
time_t startdst_dst = __tzrule[0].change - __tzrule[1].offset;
time_t startstd_dst = __tzrule[1].change - __tzrule[1].offset;
time_t startstd_std = __tzrule[1].change - __tzrule[0].offset;
/* if the time is in the overlap between dst and std local times */
if (tim >= startstd_std && tim < startstd_dst)
; /* we let user decide or leave as -1 */
else
{
isdst = (__tznorth
? (tim >= startdst_dst && tim < startstd_std)
: (tim >= startdst_dst || tim < startstd_std));
/* if user committed and was wrong, perform correction */
if ((isdst ^ tim_p->tm_isdst) == 1)
{
/* we either subtract or add the difference between
time zone offsets, depending on which way the user got it wrong */
int diff = __tzrule[0].offset - __tzrule[1].offset;
if (!isdst)
diff = -diff;
tim_p->tm_sec += diff;
validate_structure (tim_p);
tim += diff; /* we also need to correct our current time calculation */
}
}
}
}
/* add appropriate offset to put time in gmt format */
if (isdst == 1)
tim += __tzrule[1].offset;
else /* otherwise assume std time */
tim += __tzrule[0].offset;
/* reset isdst flag to what we have calculated */
tim_p->tm_isdst = isdst;
return tim; return tim;
} }

248
newlib/libc/time/mktm_r.c Normal file
View File

@ -0,0 +1,248 @@
/*
* mktm_r.c
* Original Author: Adapted from tzcode maintained by Arthur David Olson.
* Modifications: Changed to mktm_r and added __tzcalc_limits - 04/10/02, Jeff Johnston
*
* Converts the calendar time pointed to by tim_p into a broken-down time
* expressed as local time. Returns a pointer to a structure containing the
* broken-down time.
*/
#include <stdlib.h>
#include <time.h>
#include "local.h"
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] = {
365,
366
} ;
struct tm *
_DEFUN (_mktm_r, (tim_p, res, is_gmtime),
_CONST time_t * tim_p _AND
struct tm *res _AND
int is_gmtime)
{
long days, rem;
time_t lcltime;
int i;
int y;
int yleap;
_CONST int *ip;
/* base decision about std/dst time on current time */
lcltime = *tim_p;
days = ((long)lcltime) / SECSPERDAY;
rem = ((long)lcltime) % SECSPERDAY;
while (rem < 0)
{
rem += SECSPERDAY;
--days;
}
while (rem >= SECSPERDAY)
{
rem -= SECSPERDAY;
++days;
}
/* compute hour, min, and sec */
res->tm_hour = (int) (rem / SECSPERHOUR);
rem %= SECSPERHOUR;
res->tm_min = (int) (rem / SECSPERMIN);
res->tm_sec = (int) (rem % SECSPERMIN);
/* compute day of week */
if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)
res->tm_wday += DAYSPERWEEK;
/* compute year & day of year */
y = EPOCH_YEAR;
if (days >= 0)
{
for (;;)
{
yleap = isleap(y);
if (days < year_lengths[yleap])
break;
y++;
days -= year_lengths[yleap];
}
}
else
{
do
{
--y;
yleap = isleap(y);
days += year_lengths[yleap];
} while (days < 0);
}
res->tm_year = y - YEAR_BASE;
res->tm_yday = days;
ip = mon_lengths[yleap];
for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)
days -= ip[res->tm_mon];
res->tm_mday = days + 1;
if (!is_gmtime)
{
int offset;
int hours, mins, secs;
TZ_LOCK;
if (_daylight)
{
if (y == __tzyear || __tzcalc_limits (y))
res->tm_isdst = (__tznorth
? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change)
: (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change));
else
res->tm_isdst = -1;
}
else
res->tm_isdst = 0;
offset = (res->tm_isdst == 1 ? __tzrule[1].offset : __tzrule[0].offset);
hours = offset / SECSPERHOUR;
offset = offset % SECSPERHOUR;
mins = offset / SECSPERMIN;
secs = offset % SECSPERMIN;
res->tm_sec -= secs;
res->tm_min -= mins;
res->tm_hour -= hours;
if (res->tm_sec >= SECSPERMIN)
{
res->tm_min += 1;
res->tm_sec -= SECSPERMIN;
}
else if (res->tm_sec < 0)
{
res->tm_min -= 1;
res->tm_sec += SECSPERMIN;
}
if (res->tm_min >= MINSPERHOUR)
{
res->tm_hour += 1;
res->tm_min -= MINSPERHOUR;
}
else if (res->tm_min < 0)
{
res->tm_hour -= 1;
res->tm_min += MINSPERHOUR;
}
if (res->tm_hour >= HOURSPERDAY)
{
++res->tm_yday;
++res->tm_wday;
if (res->tm_wday > 6)
res->tm_wday = 0;
++res->tm_mday;
res->tm_hour -= HOURSPERDAY;
if (res->tm_mday >= ip[res->tm_mon])
{
res->tm_mday -= ip[res->tm_mon] - 1;
res->tm_mon += 1;
if (res->tm_mon == 12)
{
res->tm_mon = 0;
res->tm_year += 1;
res->tm_yday = 0;
}
}
}
else if (res->tm_hour < 0)
{
res->tm_yday -= 1;
res->tm_wday -= 1;
if (res->tm_wday < 0)
res->tm_wday = 6;
res->tm_mday -= 1;
res->tm_hour += 24;
if (res->tm_mday == 0)
{
res->tm_mon -= 1;
if (res->tm_mon < 0)
{
res->tm_mon = 11;
res->tm_year -= 1;
res->tm_yday = 365 + isleap(res->tm_year);
}
res->tm_mday = ip[res->tm_mon];
}
}
TZ_UNLOCK;
}
else
res->tm_isdst = 0;
return (res);
}
int
_DEFUN (__tzcalc_limits, (year),
int year)
{
int days, year_days, years;
int i, j;
if (year < EPOCH_YEAR)
return 0;
__tzyear = year;
years = (year - EPOCH_YEAR);
year_days = years * 365 +
(years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +
(years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;
for (i = 0; i < 2; ++i)
{
if (__tzrule[i].ch == 'J')
days = year_days + __tzrule[i].d + (isleap(year) && __tzrule[i].d >= 60);
else if (__tzrule[i].ch == 'D')
days = year_days + __tzrule[i].d;
else
{
int yleap = isleap(year);
int m_day, m_wday, wday_diff;
_CONST int *ip = mon_lengths[yleap];
days = year_days;
for (j = 1; j < __tzrule[i].m; ++j)
days += ip[j-1];
m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;
wday_diff = __tzrule[i].d - m_wday;
if (wday_diff < 0)
wday_diff += DAYSPERWEEK;
m_day = (__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;
while (m_day >= ip[j])
m_day -= DAYSPERWEEK;
days += m_day;
}
/* store the change-over time in GMT form by adding offset */
__tzrule[i].change = days * SECSPERDAY + __tzrule[i].s + __tzrule[i].offset;
}
__tznorth = (__tzrule[0].change < __tzrule[1].change);
return 1;
}

View File

@ -115,9 +115,9 @@ o %Y
The full year, formatted with four digits to include the century. The full year, formatted with four digits to include the century.
o %Z o %Z
Defined by ANSI C as eliciting the time zone if available; it is not The time zone name. If tm_isdst is -1, no output is generated.
available in this implementation (which accepts `<<%Z>>' but generates Otherwise, the time zone name based on the TZ environment variable
no output for it). is used.
o %% o %%
A single character, `<<%>>'. A single character, `<<%>>'.
@ -142,6 +142,7 @@ ANSI C requires <<strftime>>, but does not specify the contents of
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include "local.h"
static _CONST int dname_len[7] = static _CONST int dname_len[7] =
{6, 6, 7, 9, 8, 6, 8}; {6, 6, 7, 9, 8, 6, 8};
@ -426,6 +427,23 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
return 0; return 0;
break; break;
case 'Z': case 'Z':
if (tim_p->tm_isdst >= 0)
{
int size;
TZ_LOCK;
size = strlen(_tzname[tim_p->tm_isdst]);
for (i = 0; i < size; i++)
{
if (count < maxsize - 1)
s[count++] = _tzname[tim_p->tm_isdst][i];
else
{
TZ_UNLOCK;
return 0;
}
}
TZ_UNLOCK;
}
break; break;
case '%': case '%':
if (count < maxsize - 1) if (count < maxsize - 1)

44
newlib/libc/time/tzlock.c Normal file
View File

@ -0,0 +1,44 @@
/*
FUNCTION
<<__tz_lock>>, <<__tz_unlock>>--lock time zone global variables
INDEX
__tz_lock
INDEX
__tz_unlock
ANSI_SYNOPSIS
#include "local.h"
void __tz_lock (void);
void __tz_unlock (void);
TRAD_SYNOPSIS
void __tz_lock();
void __tz_unlock();
DESCRIPTION
The <<tzset>> facility functions call these functions when they need
to ensure the values of global variables. The version of these routines supplied
in the library do not do anything. If multiple threads of execution
can call the time functions and give up scheduling in the middle, then you
you need to define your own versions of these functions in order to
safely lock the time zone variables during a call. If you do not, the results
of <<localtime>>, <<mktime>>, <<ctime>>, and <<strftime>> are undefined.
The lock <<__tz_lock>> may not be called recursively; that is,
a call <<__tz_lock>> will always lock all subsequent <<__tz_lock>> calls
until the corresponding <<__tz_unlock>> call on the same thread is made.
*/
#include <_ansi.h>
#include "local.h"
_VOID
_DEFUN_VOID (__tz_lock)
{
}
_VOID
_DEFUN_VOID (__tz_unlock)
{
}

72
newlib/libc/time/tzset.c Normal file
View File

@ -0,0 +1,72 @@
/*
FUNCTION
<<tzset>>---set timezone characteristics from TZ environment variable
INDEX
tzset
ANSI_SYNOPSIS
#include <time.h>
void tzset(void);
void _tzset_r (struct _reent *);
TRAD_SYNOPSIS
#include <time.h>
void tzset();
void _tzset_r (reent_ptr)
struct _reent *reent_ptr;
DESCRIPTION
<<tzset>> examines the TZ environment variable and sets up the three
external variables: <<_timezone>>, <<_daylight>>, and <<tzname>>. The
value of <<_timezone>> shall be the offset from the current time zone
to GMT. The value of <<_daylight>> shall be 0 if there is no daylight
savings time for the current time zone, otherwise it will be non-zero.
The <<tzname>> array has two entries: the first is the name of the
standard time zone, the second is the name of the daylight-savings time
zone.
The TZ environment variable is expected to be in the following POSIX
format:
stdoffset1[dst[offset2][,start[/time1],end[/time2]]]
where: std is the name of the standard time-zone (minimum 3 chars)
offset1 is the value to add to local time to arrive at Universal time
it has the form: hh[:mm[:ss]]
dst is the name of the alternate (daylight-savings) time-zone (min 3 chars)
offset2 is the value to add to local time to arrive at Universal time
it has the same format as the std offset
start is the day that the alternate time-zone starts
time1 is the optional time that the alternate time-zone starts
(this is in local time and defaults to 02:00:00 if not specified)
end is the day that the alternate time-zone ends
time2 is the time that the alternate time-zone ends
(it is in local time and defaults to 02:00:00 if not specified)
Note that there is no white-space padding between fields. Also note that
if TZ is null, the default is Universal GMT which has no daylight-savings
time. If TZ is empty, the default EST5EDT is used.
The function <<_tzset_r>> is identical to <<tzset>> only it is reentrant
and is used for applications that use multiple threads.
RETURNS
There is no return value.
PORTABILITY
<<tzset>> is part of the POSIX standard.
Supporting OS subroutine required: None
*/
#include <_ansi.h>
#include <reent.h>
#include <time.h>
#include "local.h"
_VOID
_DEFUN_VOID (tzset)
{
_tzset_r (_REENT);
}

204
newlib/libc/time/tzset_r.c Normal file
View File

@ -0,0 +1,204 @@
#include <_ansi.h>
#include <reent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include "local.h"
static char __tzname_std[11];
static char __tzname_dst[11];
static char *prev_tzenv = NULL;
/* default to GMT */
char *_tzname[2] = {"GMT" "GMT"};
int _daylight = 0;
time_t _timezone = (time_t)0;
int __tzyear = 0;
int __tznorth = 1;
__tzrule_type __tzrule[2] = { {'J', 0, 0, 0, 0, (time_t)0, 0 },
{'J', 0, 0, 0, 0, (time_t)0, 0 } };
_VOID
_DEFUN (_tzset_r, (reent_ptr),
struct _reent *reent_ptr)
{
char *tzenv;
int hh, mm, ss, sign, m, w, d, n;
int i, ch;
if ((tzenv = _getenv_r (reent_ptr, "TZ")) == NULL)
{
TZ_LOCK;
_timezone = (time_t)0;
_daylight = 0;
_tzname[0] = "GMT";
_tzname[1] = "GMT";
TZ_UNLOCK;
return;
}
TZ_LOCK;
if (prev_tzenv != NULL && strcmp(tzenv, prev_tzenv) == 0)
{
TZ_UNLOCK;
return;
}
free(prev_tzenv);
prev_tzenv = _strdup_r (reent_ptr, tzenv);
/* ignore implementation-specific format specifier */
if (*tzenv == ':')
++tzenv;
if (sscanf (tzenv, "%10[^0-9,+-]%n", __tzname_std, &n) <= 0)
{
TZ_UNLOCK;
return;
}
tzenv += n;
sign = 1;
if (*tzenv == '-')
{
sign = -1;
++tzenv;
}
else if (*tzenv == '+')
++tzenv;
mm = 0;
ss = 0;
if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) < 1)
{
TZ_UNLOCK;
return;
}
__tzrule[0].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
_tzname[0] = __tzname_std;
tzenv += n;
if (sscanf (tzenv, "%10[^0-9,+-]%n", __tzname_dst, &n) <= 0)
{
_tzname[1] = _tzname[0];
TZ_UNLOCK;
return;
}
else
_tzname[1] = __tzname_dst;
tzenv += n;
/* otherwise we have a dst name, look for the offset */
sign = 1;
if (*tzenv == '-')
{
sign = -1;
++tzenv;
}
else if (*tzenv == '+')
++tzenv;
hh = 0;
mm = 0;
ss = 0;
if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) <= 0)
__tzrule[1].offset = __tzrule[0].offset - 3600;
else
__tzrule[1].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
tzenv += n;
if (*tzenv == ',')
++tzenv;
for (i = 0; i < 2; ++i)
{
if (*tzenv == 'M')
{
if (sscanf (tzenv, "M%hu%n.%hu%n.%hu%n", &m, &n, &w, &n, &d, &n) != 3 ||
m < 1 || m > 12 || w < 1 || w > 5 || d > 6)
{
TZ_UNLOCK;
return;
}
__tzrule[i].ch = 'M';
__tzrule[i].m = m;
__tzrule[i].n = w;
__tzrule[i].d = d;
tzenv += n;
}
else
{
char *end;
if (*tzenv == 'J')
{
ch = 'J';
++tzenv;
}
else
ch = 'D';
d = strtoul (tzenv, &end, 10);
/* if unspecified, default to US settings */
if (end == tzenv)
{
if (i == 0)
{
__tzrule[0].ch = 'M';
__tzrule[0].m = 4;
__tzrule[0].n = 1;
__tzrule[0].d = 0;
}
else
{
__tzrule[1].ch = 'M';
__tzrule[1].m = 10;
__tzrule[1].n = 5;
__tzrule[1].d = 0;
}
}
else
{
__tzrule[i].ch = ch;
__tzrule[i].d = d;
}
tzenv = end;
}
/* default time is 02:00:00 am */
hh = 2;
mm = 0;
ss = 0;
if (*tzenv == '/')
sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n);
__tzrule[i].s = ss + SECSPERMIN * mm + SECSPERHOUR * hh;
}
__tzcalc_limits (__tzyear);
_timezone = (time_t)(__tzrule[0].offset);
_daylight = __tzrule[0].offset != __tzrule[1].offset;
TZ_UNLOCK;
}