OSDN Git Service

Change clock() to allow wrapping.
authorManuel Novoa III <mjn3@codepoet.org>
Sat, 8 May 2004 05:12:14 +0000 (05:12 -0000)
committerManuel Novoa III <mjn3@codepoet.org>
Sat, 8 May 2004 05:12:14 +0000 (05:12 -0000)
Add timegm() function.
Make lookup_tzname() static (as it should have been).
Have strftime() get timezone information from the passed struct
  for the %z and %Z conversions when using struct tm extensions.

include/time.h
libc/misc/time/time.c

index f957dc2..5dc1919 100644 (file)
@@ -322,10 +322,8 @@ extern int stime (__const time_t *__when) __THROW;
 /* Miscellaneous functions many Unices inherited from the public domain
    localtime package.  These are included only for compatibility.  */
 
-#if 0
 /* Like `mktime', but for TP represents Universal Time, not local time.  */
 extern time_t timegm (struct tm *__tp) __THROW;
-#endif
 
 /* Another name for `mktime'.  */
 extern time_t timelocal (struct tm *__tp) __THROW;
index 8176e07..ac2fe59 100644 (file)
@@ -1,31 +1,10 @@
-/*  Copyright (C) 2002     Manuel Novoa III
+/* Copyright (C) 2002-2004   Manuel Novoa III    <mjn3@codepoet.org>
  *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
+ * GNU Library General Public License (LGPL) version 2 or later.
  *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
- *
- *  You should have received a copy of the GNU Library General Public
- *  License along with this library; if not, write to the Free
- *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
  */
 
-/*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!
- *
- *  Besides uClibc, I'm using this code in my libc for elks, which is
- *  a 16-bit environment with a fairly limited compiler.  It would make
- *  things much easier for me if this file isn't modified unnecessarily.
- *  In particular, please put any new or replacement functions somewhere
- *  else, and modify the makefile to use your version instead.
- *  Thanks.  Manuel
- *
- *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */
-
 /* June 15, 2002     Initial Notes:
  *
  * Note: It is assumed throught that time_t is either long or unsigned long.
  * Dec 14, 2003 Fix some dst issues in _time_mktime().
  *   Normalize the tm_isdst value to -1, 0, or 1.
  *   If no dst for this timezone, then reset tm_isdst to 0.
+ *
+ * May 7, 2004
+ *   Change clock() to allow wrapping.
+ *   Add timegm() function.
+ *   Make lookup_tzname() static (as it should have been).
+ *   Have strftime() get timezone information from the passed struct
+ *     for the %z and %Z conversions when using struct tm extensions.
  */
 
 #define _GNU_SOURCE
@@ -219,6 +205,13 @@ extern struct tm *_time_t2tm(const time_t *__restrict timer,
 
 extern time_t _time_mktime(struct tm *timeptr, int store_on_success);
 
+extern struct tm *__time_localtime_tzi(const time_t *__restrict timer,
+                                                                          struct tm *__restrict result,
+                                                                          rule_struct *tzi);
+
+extern time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success,
+                                                          rule_struct *tzi);
+
 /**********************************************************************/
 #ifdef L_asctime
 
@@ -376,51 +369,63 @@ char *asctime_r(register const struct tm *__restrict ptm,
 
 #include <sys/times.h>
 
-/* Note: According to glibc...
- *    CAE XSH, Issue 4, Version 2: <time.h>
- *    The value of CLOCKS_PER_SEC is required to be 1 million on all
- *    XSI-conformant systems.
- */
-
 #ifndef __BCC__
 #if CLOCKS_PER_SEC != 1000000L
 #error unexpected value for CLOCKS_PER_SEC!
 #endif
 #endif
 
+#ifdef __UCLIBC_CLK_TCK_CONST
+# if __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC
+#  error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
+# elif __UCLIBC_CLK_TCK_CONST < 1
+#  error __UCLIBC_CLK_TCK_CONST < 1!
+# endif
+#endif
+
+/* Note: SUSv3 notes
+ *
+ *   On XSI-conformant systems, CLOCKS_PER_SEC is defined to be one million.
+ *
+ *   The value returned by clock() may wrap around on some implementations.
+ *   For example, on a machine with 32-bit values for clock_t, it wraps
+ *   after 2147 seconds.
+ *
+ * This implies that we should bitwise and with LONG_MAX.
+ */
+
 clock_t clock(void)
 {
        struct tms xtms;
        unsigned long t;
 
        times(&xtms);
+
        t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
 
 #ifndef __UCLIBC_CLK_TCK_CONST
-#error __UCLIBC_CLK_TCK_CONST not defined!
-#endif
 
-#undef CLK_TCK
-#define CLK_TCK __UCLIBC_CLK_TCK_CONST
+# error __UCLIBC_CLK_TCK_CONST not defined!
 
-#if CLK_TCK > CLOCKS_PER_SEC
-#error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
-#elif CLK_TCK < 1
-#error __UCLIBC_CLK_TCK_CONST < 1!
-#endif
+#elif ((CLOCKS_PER_SEC % __UCLIBC_CLK_TCK_CONST) == 0)
+
+       /* CLOCKS_PER_SEC == k * __UCLIBC_CLK_TCK_CONST for some integer k >= 1. */
+       return ((t * (CLOCKS_PER_SEC/__UCLIBC_CLK_TCK_CONST)) & LONG_MAX);
 
-#if (CLK_TCK == CLOCKS_PER_SEC)
-       return (t <= LONG_MAX) ? t : -1;
-#elif (CLOCKS_PER_SEC % CLK_TCK) == 0
-       return (t <= (LONG_MAX / (CLOCKS_PER_SEC/CLK_TCK)))
-               ? t * (CLOCKS_PER_SEC/CLK_TCK)
-               : -1;
 #else
-       return (t <= ((LONG_MAX / CLOCKS_PER_SEC) * CLK_TCK
-                                 + ((LONG_MAX % CLOCKS_PER_SEC) * CLK_TCK) / CLOCKS_PER_SEC))
-               ? (((t / CLK_TCK) * CLOCKS_PER_SEC)
-                  + (((t % CLK_TCK) * CLOCKS_PER_SEC) / CLK_TCK))
-               : -1;
+
+       /* Unlike the previous case, the scaling factor is not an integer.
+        * So when tms_utime, tms_stime, or their sum wraps, some of the
+        * "visible" bits in the return value are affected.  Nothing we
+        * can really do about this though other than handle tms_utime and
+        * tms_stime seperately and then sum.  But since that doesn't really
+        * buy us much, we don't bother. */
+
+       return ((((t / __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
+                        + ((((t % __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
+                                / __UCLIBC_CLK_TCK_CONST))
+                        ) & LONG_MAX);
+
 #endif
 }
 
@@ -525,6 +530,24 @@ struct tm *localtime(const time_t *timer)
 /**********************************************************************/
 #ifdef L_localtime_r
 
+struct tm *localtime_r(register const time_t *__restrict timer,
+                                          register struct tm *__restrict result)
+{
+       TZLOCK;
+
+       tzset();
+
+       __time_localtime_tzi(timer, result, _time_tzinfo);
+
+       TZUNLOCK;
+
+       return result;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L__time_localtime_tzi
+
 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
 
 struct ll_tzname_item;
@@ -539,7 +562,7 @@ static ll_tzname_item_t ll_tzname[] = {
        { NULL, "???" }           /* Always 2nd. (invalid or out-of-memory) */
 };
 
-const char *lookup_tzname(const char *key)
+static const char *lookup_tzname(const char *key)
 {
        ll_tzname_item_t *p;
 
@@ -574,9 +597,9 @@ static const unsigned char day_cor[] = { /* non-leap */
 
 /* Note: timezone locking is done by localtime_r. */
 
-static int tm_isdst(register const struct tm *__restrict ptm)
+static int tm_isdst(register const struct tm *__restrict ptm,
+                                       register rule_struct *r)
 {
-       register rule_struct *r = _time_tzinfo;
        long sec;
        int i, isdst, isleap, day, day0, monlen, mday;
        int oday;                                       /* Note: oday can be uninitialized. */
@@ -647,21 +670,18 @@ static int tm_isdst(register const struct tm *__restrict ptm)
        return (isdst & 1);
 }
 
-struct tm *localtime_r(register const time_t *__restrict timer,
-                                          register struct tm *__restrict result)
+struct tm *__time_localtime_tzi(register const time_t *__restrict timer,
+                                                               register struct tm *__restrict result,
+                                                               rule_struct *tzi)
 {
        time_t x[1];
        long offset;
        int days, dst;
 
-       TZLOCK;
-
-       tzset();
-
        dst = 0;
        do {
                days = -7;
-               offset = 604800L - _time_tzinfo[dst].gmt_offset;
+               offset = 604800L - tzi[dst].gmt_offset;
                if (*timer > (LONG_MAX - 604800L)) {
                        days = -days;
                        offset = -offset;
@@ -671,12 +691,11 @@ struct tm *localtime_r(register const time_t *__restrict timer,
                _time_t2tm(x, days, result);
                result->tm_isdst = dst;
 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
-               result->tm_gmtoff = - _time_tzinfo[dst].gmt_offset;
-               result->tm_zone = lookup_tzname(_time_tzinfo[dst].tzname);
+               result->tm_gmtoff = - tzi[dst].gmt_offset;
+               result->tm_zone = lookup_tzname(tzi[dst].tzname);
 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
-       } while ((++dst < 2) && ((result->tm_isdst = tm_isdst(result)) != 0));
-
-       TZUNLOCK;
+       } while ((++dst < 2)
+                        && ((result->tm_isdst = tm_isdst(result, tzi)) != 0));
 
        return result;
 }
@@ -694,6 +713,20 @@ time_t mktime(struct tm *timeptr)
        return  _time_mktime(timeptr, 1);
 }
 
+#endif
+/**********************************************************************/
+#ifdef L_timegm
+/* Like `mktime' but timeptr represents Universal Time, not local time. */
+
+time_t timegm(struct tm *timeptr)
+{
+       rule_struct gmt_tzinfo[2];
+
+       memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo));
+       strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */
+
+       return  _time_mktime_tzi(timeptr, 1, gmt_tzinfo);
+}
 
 #endif
 /**********************************************************************/
@@ -913,7 +946,9 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,
        long tzo;
        register const char *p;
        register const char *o;
+#ifndef __UCLIBC_HAS_TM_EXTENSIONS__
        const rule_struct *rsp;
+#endif
        const char *stack[MAX_PUSH];
        size_t count;
        size_t o_count;
@@ -1027,15 +1062,28 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,
                                        goto OUTPUT;
                                }
 
+#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
+
+#define RSP_TZUNLOCK   ((void) 0)
+#define RSP_TZNAME             timeptr->tm_zone
+#define RSP_GMT_OFFSET timeptr->tm_gmtoff
+
+#else
+
+#define RSP_TZUNLOCK   TZUNLOCK
+#define RSP_TZNAME             rsp->tzname
+#define RSP_GMT_OFFSET rsp->gmt_offset
+
                                TZLOCK;
 
                                rsp = _time_tzinfo;
                                if (timeptr->tm_isdst > 0) {
                                        ++rsp;
                                }
+#endif
 
                                if (*p == 'Z') {
-                                       o = rsp->tzname;
+                                       o = RSP_TZNAME;
                                        assert(o != NULL);
 #if 0
                                        if (!o) {       /* PARANOIA */
@@ -1043,15 +1091,15 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,
                                        }
 #endif
                                        o_count = SIZE_MAX;
-                                       TZUNLOCK;
+                                       RSP_TZUNLOCK;
                                        goto OUTPUT;
                                } else {                /* z */
                                        *s = '+';
-                                       if ((tzo = -rsp->gmt_offset) < 0) {
+                                       if ((tzo = -RSP_GMT_OFFSET) < 0) {
                                                tzo = -tzo;
                                                *s = '-';
                                        }
-                                       TZUNLOCK;
+                                       RSP_TZUNLOCK;
                                        ++s;
                                        --count;
 
@@ -1060,6 +1108,7 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,
                        
                                        i = 16 + 6;     /* 0-fill, width = 4 */
                                }
+
                        } else {
                                /* TODO: don't need year for U, W */
                                for (i=0 ; i < 3 ; i++) {
@@ -2087,12 +2136,32 @@ struct tm __time_tm;    /* Global shared by gmtime() and localtime(). */
 /**********************************************************************/
 #ifdef L__time_mktime
 
+time_t _time_mktime(struct tm *timeptr, int store_on_success)
+{
+       time_t t;
+
+       TZLOCK;
+
+       tzset();
+
+       t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo);
+
+       TZUNLOCK;
+
+       return t;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L__time_mktime_tzi
+
 static const unsigned char vals[] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
            29,
 };
 
-time_t _time_mktime(struct tm *timeptr, int store_on_success)
+time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success,
+                                               rule_struct *tzi)
 {
 #ifdef __BCC__
        long days, secs;
@@ -2106,13 +2175,9 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
        register const unsigned char *s;
        int d, default_dst;
 
-       TZLOCK;
-
-       tzset();
-
        memcpy(p, timeptr, sizeof(struct tm));
 
-       if (!_time_tzinfo[1].tzname[0]) { /* No dst in this timezone, */
+       if (!tzi[1].tzname[0]) { /* No dst in this timezone, */
                p[8] = 0;                               /* so set tm_isdst to 0. */
        }
 
@@ -2150,7 +2215,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
        d = p[5] - 1;
        days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
        secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
-               + _time_tzinfo[default_dst].gmt_offset;
+               + tzi[default_dst].gmt_offset;
  DST_CORRECT:
        if (secs < 0) {
                secs += 120009600L;
@@ -2165,7 +2230,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
        d = p[5] - 1;
        d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
        secs = p[0]
-               + _time_tzinfo[default_dst].gmt_offset
+               + tzi[default_dst].gmt_offset
                + 60*( p[1]
                           + 60*(p[2]
                                         + 24*(((146073L * ((long long)(p[6])) + d)
@@ -2183,7 +2248,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
        d = ((struct tm *)p)->tm_isdst;
        t = secs;
 
-       localtime_r(&t, (struct tm *)p);
+       __time_localtime_tzi(&t, (struct tm *)p, tzi);
 
        if (t == ((time_t)(-1))) {      /* Remember, time_t can be unsigned. */
            goto DONE;
@@ -2193,8 +2258,8 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
 #ifdef __BCC__
                secs -= (days * 86400L);
 #endif
-               secs += (_time_tzinfo[1-default_dst].gmt_offset
-                                - _time_tzinfo[default_dst].gmt_offset);
+               secs += (tzi[1-default_dst].gmt_offset
+                                - tzi[default_dst].gmt_offset);
                goto DST_CORRECT;
        }
 
@@ -2205,8 +2270,6 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
 
 
  DONE:
-       TZUNLOCK;
-
        return t;
 }
 
@@ -2254,7 +2317,3 @@ int dysize(int year)
 
 #endif
 /**********************************************************************/
-/* Like `mktime', but for TP represents Universal Time, not local time.  */
-/* time_t timegm(struct tm *tp) */
-
-