Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2002-04-18 01:23:31 +0400
committerJeff Johnston <jjohnstn@redhat.com>2002-04-18 01:23:31 +0400
commit10d002160949c985e6f99fb8d647d5e3c67ef554 (patch)
tree6ffe46b0b090120c2a251ffc2ce19574fb5f1dfb /newlib/libc/time
parenta26c50352b4db457813ef86fb053bd838d310d30 (diff)
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.
Diffstat (limited to 'newlib/libc/time')
-rw-r--r--newlib/libc/time/Makefile.am12
-rw-r--r--newlib/libc/time/Makefile.in21
-rw-r--r--newlib/libc/time/gmtime.c5
-rw-r--r--newlib/libc/time/gmtime_r.c7
-rw-r--r--newlib/libc/time/lcltime_r.c90
-rw-r--r--newlib/libc/time/local.h54
-rw-r--r--newlib/libc/time/mktime.c48
-rw-r--r--newlib/libc/time/mktm_r.c248
-rw-r--r--newlib/libc/time/strftime.c24
-rw-r--r--newlib/libc/time/tzlock.c44
-rw-r--r--newlib/libc/time/tzset.c72
-rw-r--r--newlib/libc/time/tzset_r.c204
12 files changed, 719 insertions, 110 deletions
diff --git a/newlib/libc/time/Makefile.am b/newlib/libc/time/Makefile.am
index 3a7fbdb19..3735def7c 100644
--- a/newlib/libc/time/Makefile.am
+++ b/newlib/libc/time/Makefile.am
@@ -16,9 +16,13 @@ LIB_SOURCES = \
lcltime.c \
lcltime_r.c \
mktime.c \
+ mktm_r.c \
strftime.c \
- strptime.c \
- time.c
+ strptime.c \
+ time.c \
+ tzlock.c \
+ tzset.c \
+ tzset_r.c
libtime_la_LDFLAGS = -Xcompiler -nostdlib
@@ -43,7 +47,9 @@ CHEWOUT_FILES = \
lcltime.def \
mktime.def \
strftime.def \
- time.def
+ time.def \
+ tzlock.def \
+ tzset.def
SUFFIXES = .def
diff --git a/newlib/libc/time/Makefile.in b/newlib/libc/time/Makefile.in
index a6fb0ba8c..dcbac1878 100644
--- a/newlib/libc/time/Makefile.in
+++ b/newlib/libc/time/Makefile.in
@@ -107,9 +107,13 @@ LIB_SOURCES = \
lcltime.c \
lcltime_r.c \
mktime.c \
+ mktm_r.c \
strftime.c \
- strptime.c \
- time.c
+ strptime.c \
+ time.c \
+ tzlock.c \
+ tzset.c \
+ tzset_r.c
libtime_la_LDFLAGS = -Xcompiler -nostdlib
@@ -130,7 +134,9 @@ CHEWOUT_FILES = \
lcltime.def \
mktime.def \
strftime.def \
- time.def
+ time.def \
+ tzlock.def \
+ tzset.def
SUFFIXES = .def
@@ -151,15 +157,16 @@ LIBS = @LIBS@
lib_a_LIBADD =
@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@lcltime.o lcltime_r.o mktime.o strftime.o strptime.o \
-@USE_LIBTOOL_FALSE@time.o
+@USE_LIBTOOL_FALSE@lcltime.o lcltime_r.o mktime.o mktm_r.o strftime.o \
+@USE_LIBTOOL_FALSE@strptime.o time.o tzlock.o tzset.o tzset_r.o
LTLIBRARIES = $(noinst_LTLIBRARIES)
libtime_la_LIBADD =
@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@lcltime.lo lcltime_r.lo mktime.lo strftime.lo \
-@USE_LIBTOOL_TRUE@strptime.lo time.lo
+@USE_LIBTOOL_TRUE@lcltime.lo lcltime_r.lo mktime.lo mktm_r.lo \
+@USE_LIBTOOL_TRUE@strftime.lo strptime.lo time.lo tzlock.lo tzset.lo \
+@USE_LIBTOOL_TRUE@tzset_r.lo
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)
diff --git a/newlib/libc/time/gmtime.c b/newlib/libc/time/gmtime.c
index 4f5bbe403..d8e687559 100644
--- a/newlib/libc/time/gmtime.c
+++ b/newlib/libc/time/gmtime.c
@@ -59,9 +59,8 @@ struct tm *
_DEFUN (gmtime, (tim_p),
_CONST time_t * tim_p)
{
- time_t tim = *tim_p + _GMT_OFFSET;
-
- return (localtime (&tim));
+ _REENT_CHECK_TM(_REENT);
+ return gmtime_r (tim_p, (struct tm *)_REENT_TM(_REENT));
}
#endif
diff --git a/newlib/libc/time/gmtime_r.c b/newlib/libc/time/gmtime_r.c
index 7afa021c5..fb39238d3 100644
--- a/newlib/libc/time/gmtime_r.c
+++ b/newlib/libc/time/gmtime_r.c
@@ -3,15 +3,12 @@
*/
#include <time.h>
-
-#define _GMT_OFFSET 0
+#include "local.h"
struct tm *
_DEFUN (gmtime_r, (tim_p, res),
_CONST time_t * tim_p _AND
struct tm *res)
{
- time_t tim = *tim_p + _GMT_OFFSET;
-
- return (localtime_r (&tim, res));
+ return (_mktm_r (tim_p, res, 1));
}
diff --git a/newlib/libc/time/lcltime_r.c b/newlib/libc/time/lcltime_r.c
index 1b4269ee1..cf386719c 100644
--- a/newlib/libc/time/lcltime_r.c
+++ b/newlib/libc/time/lcltime_r.c
@@ -1,104 +1,18 @@
/*
* 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
* expressed as local time. Returns a pointer to a structure containing the
* broken-down time.
*/
-#include <stdlib.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 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
-} ;
+#include "local.h"
struct tm *
_DEFUN (localtime_r, (tim_p, res),
_CONST time_t * tim_p _AND
struct tm *res)
{
- long days, rem;
- 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);
+ return _mktm_r (tim_p, res, 0);
}
diff --git a/newlib/libc/time/local.h b/newlib/libc/time/local.h
new file mode 100644
index 000000000..722808715
--- /dev/null
+++ b/newlib/libc/time/local.h
@@ -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));
+
diff --git a/newlib/libc/time/mktime.c b/newlib/libc/time/mktime.c
index 80478dae9..f6f080d84 100644
--- a/newlib/libc/time/mktime.c
+++ b/newlib/libc/time/mktime.c
@@ -47,6 +47,7 @@ ANSI C requires <<mktime>>.
#include <stdlib.h>
#include <time.h>
+#include "local.h"
#define _SEC_IN_MINUTE 60L
#define _SEC_IN_HOUR 3600L
@@ -156,7 +157,7 @@ mktime (tim_p)
{
time_t tim = 0;
long days = 0;
- int year;
+ int year, isdst;
/* validate structure */
validate_structure (tim_p);
@@ -200,5 +201,50 @@ mktime (tim_p)
/* compute total seconds */
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;
}
diff --git a/newlib/libc/time/mktm_r.c b/newlib/libc/time/mktm_r.c
new file mode 100644
index 000000000..4fdfb9b7b
--- /dev/null
+++ b/newlib/libc/time/mktm_r.c
@@ -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;
+}
+
diff --git a/newlib/libc/time/strftime.c b/newlib/libc/time/strftime.c
index 1b44e1db9..57fe74eae 100644
--- a/newlib/libc/time/strftime.c
+++ b/newlib/libc/time/strftime.c
@@ -115,9 +115,9 @@ o %Y
The full year, formatted with four digits to include the century.
o %Z
-Defined by ANSI C as eliciting the time zone if available; it is not
-available in this implementation (which accepts `<<%Z>>' but generates
-no output for it).
+The time zone name. If tm_isdst is -1, no output is generated.
+Otherwise, the time zone name based on the TZ environment variable
+is used.
o %%
A single character, `<<%>>'.
@@ -142,6 +142,7 @@ ANSI C requires <<strftime>>, but does not specify the contents of
#include <stddef.h>
#include <stdio.h>
#include <time.h>
+#include "local.h"
static _CONST int dname_len[7] =
{6, 6, 7, 9, 8, 6, 8};
@@ -426,6 +427,23 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
return 0;
break;
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;
case '%':
if (count < maxsize - 1)
diff --git a/newlib/libc/time/tzlock.c b/newlib/libc/time/tzlock.c
new file mode 100644
index 000000000..66fa1c366
--- /dev/null
+++ b/newlib/libc/time/tzlock.c
@@ -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)
+{
+}
diff --git a/newlib/libc/time/tzset.c b/newlib/libc/time/tzset.c
new file mode 100644
index 000000000..c70e3ee6e
--- /dev/null
+++ b/newlib/libc/time/tzset.c
@@ -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);
+}
diff --git a/newlib/libc/time/tzset_r.c b/newlib/libc/time/tzset_r.c
new file mode 100644
index 000000000..a083e5b80
--- /dev/null
+++ b/newlib/libc/time/tzset_r.c
@@ -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;
+}
+
+
+
+
+