OSDN Git Service

2002-04-17 Jeff Johnston <jjohnstn@redhat.com>
authorjjohnstn <jjohnstn>
Wed, 17 Apr 2002 21:23:28 +0000 (21:23 +0000)
committerjjohnstn <jjohnstn>
Wed, 17 Apr 2002 21:23:28 +0000 (21:23 +0000)
        *  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.

16 files changed:
newlib/ChangeLog
newlib/libc/include/time.h
newlib/libc/stdlib/setenv_r.c
newlib/libc/sys/linux/machine/i386/crt0.c
newlib/libc/time/Makefile.am
newlib/libc/time/Makefile.in
newlib/libc/time/gmtime.c
newlib/libc/time/gmtime_r.c
newlib/libc/time/lcltime_r.c
newlib/libc/time/local.h [new file with mode: 0644]
newlib/libc/time/mktime.c
newlib/libc/time/mktm_r.c [new file with mode: 0644]
newlib/libc/time/strftime.c
newlib/libc/time/tzlock.c [new file with mode: 0644]
newlib/libc/time/tzset.c [new file with mode: 0644]
newlib/libc/time/tzset_r.c [new file with mode: 0644]

index d9d773e..c926507 100644 (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>
 
        * configure.in (CRT0_DIR): Set to libc/.
index fe43c28..c45be54 100644 (file)
@@ -8,6 +8,7 @@
 #define _TIME_H_
 
 #include "_ansi.h"
+#include <sys/reent.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -55,22 +56,29 @@ struct tm *_EXFUN(gmtime,   (const time_t *_timer));
 struct tm *_EXFUN(localtime,(const time_t *_timer));
 #endif
 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(ctime_r,      (const time_t *, char *));
 struct tm *_EXFUN(gmtime_r,    (const time_t *, struct tm *));
 struct tm *_EXFUN(localtime_r, (const time_t *, struct tm *));
 
-#ifdef __CYGWIN__
 #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 int _daylight;
 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
 #define tzname _tzname
 #endif
+
+/* CYGWIN also exposes daylight and timezone in the name space */
+#ifdef __CYGWIN__
 #ifndef daylight
 #define daylight _daylight
 #endif
@@ -81,13 +89,11 @@ extern __IMPORT char *_tzname[2];
 #else
 char *_EXFUN(timezone, (void));
 #endif
-void _EXFUN(tzset, (void));
-#endif
 #endif /* __CYGWIN__ */
+#endif /* !__STRICT_ANSI__ */
 
 #include <sys/features.h>
 
-
 #if defined(_POSIX_TIMERS)
 
 #include <signal.h>
index 6cc18a8..f06dc67 100644 (file)
@@ -1,5 +1,5 @@
 /* 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 <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include "envlock.h"
 
 extern char **environ;
@@ -69,8 +70,11 @@ _DEFUN (_setenv_r, (reent_ptr, name, value, rewrite),
         }
       if (strlen (C) >= l_value)
        {                       /* old larger; copy over */
-         while ((*C++ = *value++) != 0);
+         while ((*C++ = *value++) != 0);
           ENV_UNLOCK;
+         /* if we are changing the TZ environment variable, update timezone info */
+         if (strcmp (name, "TZ") == 0)
+           tzset ();
          return 0;
        }
     }
@@ -117,6 +121,10 @@ _DEFUN (_setenv_r, (reent_ptr, name, value, rewrite),
 
   ENV_UNLOCK;
 
+  /* if we are setting the TZ environment variable, update timezone info */
+  if (strcmp (name, "TZ") == 0)
+    tzset ();
+
   return 0;
 }
 
index 420a2b9..01ae7a3 100644 (file)
@@ -8,6 +8,7 @@
 
 
 #include <stdlib.h>
+#include <time.h>
 
 
 extern char **environ;
@@ -28,5 +29,6 @@ void _start(int args)
     char **argv = (char **) (params+1);
 
     environ = argv+argc+1;
+    tzset(); /* initialize timezone info */
     exit(main(argc,argv,environ));
 }
index 3a7fbdb..3735def 100644 (file)
@@ -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
 
index a6fb0ba..dcbac18 100644 (file)
@@ -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)
index 4f5bbe4..d8e6875 100644 (file)
@@ -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
index 7afa021..fb39238 100644 (file)
@@ -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));
 }
index 1b4269e..cf38671 100644 (file)
 /*
  * 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 (file)
index 0000000..7228087
--- /dev/null
@@ -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));
+
index 80478da..f6f080d 100644 (file)
@@ -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 (file)
index 0000000..4fdfb9b
--- /dev/null
@@ -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;
+}
+
index 1b44e1d..57fe74e 100644 (file)
@@ -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 (file)
index 0000000..66fa1c3
--- /dev/null
@@ -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 (file)
index 0000000..c70e3ee
--- /dev/null
@@ -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 (file)
index 0000000..a083e5b
--- /dev/null
@@ -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;
+}
+
+
+
+
+