Add timegm POSIX call [updated]

Message ID CAEFwyTN5cr1gUcZzBKwid4iy9iyrz6Tj1XW19UJ=j5b_xWnKzA@mail.gmail.com
State New
Headers show
Series
  • Add timegm POSIX call [updated]
Related show

Commit Message

Andrew Russell via newlib Aug. 22, 2018, 7:12 p.m.
From 7f6e9b06c27be11fb37302af29c4fd6932a1cab5 Mon Sep 17 00:00:00 2001
From: Andrew Russell <ahrussell@google.com>

Date: Wed, 22 Aug 2018 12:05:04 -0700
Subject: [PATCH 1/1] Refactor mktime and add the POSIX function timegm

Updated the timegm POSIX call patch proposal from mailing list feedback.

---
 newlib/libc/include/time.h   |  1 +
 newlib/libc/saber            |  1 +
 newlib/libc/time/Makefile.am |  2 +
 newlib/libc/time/Makefile.in | 11 ++++-
 newlib/libc/time/local.h     |  2 +
 newlib/libc/time/mktime.c    | 79 +++++++++++++++++++++++++-----------
 newlib/libc/time/timegm.c    | 62 ++++++++++++++++++++++++++++
 7 files changed, 134 insertions(+), 24 deletions(-)
 create mode 100644 newlib/libc/time/timegm.c

+  /* compute day of the week */
+  __set_tm_wday(days, tim_p);
+
+  return tim;
+}
-- 
2.18.0.1017.ga543ac7ca45-goog

Comments

Freddie Chopin Aug. 22, 2018, 9:02 p.m. | #1
On Wed, 2018-08-22 at 12:12 -0700, Andrew Russell via newlib wrote:
> -static const int DAYS_IN_MONTH[12] =

> +static const int_least16_t DAYS_IN_MONTH[12] =

>  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};


Shouldn't the type here be actually int_least8_t and int_least16_t used
here ->

> @@ -58,11 +61,21 @@ static const int DAYS_IN_MONTH[12] =

>  static const int _DAYS_BEFORE_MONTH[12] =

>  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};


?

Regards,
FCh
Brian Inglis Aug. 22, 2018, 11:37 p.m. | #2
On 2018-08-22 15:02, Freddie Chopin wrote:
> On Wed, 2018-08-22 at 12:12 -0700, Andrew Russell via newlib wrote:

>> -static const int DAYS_IN_MONTH[12] =

>> +static const int_least16_t DAYS_IN_MONTH[12] =

>>  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

> 

> Shouldn't the type here be actually int_least8_t and int_least16_t used

> here ->


or uint_least{8,16}_t?

>> @@ -58,11 +61,21 @@ static const int DAYS_IN_MONTH[12] =

>>  static const int _DAYS_BEFORE_MONTH[12] =

>>  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};


and initialization use {U}INT{8,16}_C(value) macros?

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada
Freddie Chopin Aug. 23, 2018, 7:27 a.m. | #3
On Wed, 2018-08-22 at 17:37 -0600, Brian Inglis wrote:
> > > @@ -58,11 +61,21 @@ static const int DAYS_IN_MONTH[12] =

> > >  static const int _DAYS_BEFORE_MONTH[12] =

> > >  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

> 

> and initialization use {U}INT{8,16}_C(value) macros?


This would just add noise to the code for no other purpose. At least in
my opinion (;

Regards,
FCh
Brian Inglis Aug. 27, 2018, 6:39 a.m. | #4
On 2018-08-23 01:27, Freddie Chopin wrote:
> On Wed, 2018-08-22 at 17:37 -0600, Brian Inglis wrote:

>>>> @@ -58,11 +61,21 @@ static const int DAYS_IN_MONTH[12] =

>>>>  static const int _DAYS_BEFORE_MONTH[12] =

>>>>  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

>>

>> and initialization use {U}INT{8,16}_C(value) macros?

> 

> This would just add noise to the code for no other purpose. At least in

> my opinion (;


Thou shouldst consider carefully new cries of great rejoicing by the prophets,
lest some interpreter in times to come dunt thy console with endless
lamentations for thine careless inscriptions without qualification, upon some
prophets contemnation of heretical literals unblessed by suffixation.

[With apologies to Henry Spencer ;^> ]

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.

Patch

diff --git a/newlib/libc/include/time.h b/newlib/libc/include/time.h
index a2efcc15e..8440ecb3c 100644
--- a/newlib/libc/include/time.h
+++ b/newlib/libc/include/time.h
@@ -56,6 +56,7 @@  struct tm
 clock_t    clock (void);
 double    difftime (time_t _time2, time_t _time1);
 time_t    mktime (struct tm *_timeptr);
+time_t    timegm (struct tm *_timeptr);
 time_t    time (time_t *_timer);
 #ifndef _REENT_ONLY
 char   *asctime (const struct tm *_tblock);
diff --git a/newlib/libc/saber b/newlib/libc/saber
index 4f16f976e..f57063f82 100644
--- a/newlib/libc/saber
+++ b/newlib/libc/saber
@@ -122,6 +122,7 @@  time/gmtime.c
 time/localtime.c
 time/mktime.c
 time/strftime.c
+time/timegm.c


 load stdio/fiprintf.c
diff --git a/newlib/libc/time/Makefile.am b/newlib/libc/time/Makefile.am
index be040baec..5c73c3a17 100644
--- a/newlib/libc/time/Makefile.am
+++ b/newlib/libc/time/Makefile.am
@@ -17,6 +17,7 @@  LIB_SOURCES = \
  lcltime.c \
  lcltime_r.c \
  mktime.c \
+ timegm.c \
  month_lengths.c \
  strftime.c  \
  strptime.c \
@@ -54,6 +55,7 @@  CHEWOUT_FILES = \
  gmtime.def \
  lcltime.def \
  mktime.def \
+ timegm.def \
  strftime.def \
  time.def \
  tzlock.def \
diff --git a/newlib/libc/time/Makefile.in b/newlib/libc/time/Makefile.in
index a32333234..2845f7438 100644
--- a/newlib/libc/time/Makefile.in
+++ b/newlib/libc/time/Makefile.in
@@ -80,6 +80,7 @@  am__objects_1 = lib_a-asctime.$(OBJEXT)
lib_a-asctime_r.$(OBJEXT) \
  lib_a-lcltime_r.$(OBJEXT) lib_a-mktime.$(OBJEXT) \
  lib_a-month_lengths.$(OBJEXT) lib_a-strftime.$(OBJEXT) \
  lib_a-strptime.$(OBJEXT) lib_a-time.$(OBJEXT) \
+ lib_a-timegm.$(OBJEXT) \
  lib_a-tzcalc_limits.$(OBJEXT) lib_a-tzlock.$(OBJEXT) \
  lib_a-tzset.$(OBJEXT) lib_a-tzset_r.$(OBJEXT) \
  lib_a-tzvars.$(OBJEXT) lib_a-wcsftime.$(OBJEXT)
@@ -90,7 +91,8 @@  libtime_la_LIBADD =
 am__objects_2 = asctime.lo asctime_r.lo clock.lo ctime.lo ctime_r.lo \
  difftime.lo gettzinfo.lo gmtime.lo gmtime_r.lo lcltime.lo \
  lcltime_r.lo mktime.lo month_lengths.lo strftime.lo \
- strptime.lo time.lo tzcalc_limits.lo tzlock.lo tzset.lo \
+ strptime.lo time.lo timegm.lo \
+ tzcalc_limits.lo tzlock.lo tzset.lo \
  tzset_r.lo tzvars.lo wcsftime.lo
 @USE_LIBTOOL_TRUE@am_libtime_la_OBJECTS = $(am__objects_2)
 libtime_la_OBJECTS = $(am_libtime_la_OBJECTS)
@@ -282,6 +284,7 @@  LIB_SOURCES = \
  strftime.c  \
  strptime.c \
  time.c \
+ timegm.c        \
  tzcalc_limits.c \
  tzlock.c \
  tzset.c \
@@ -463,6 +466,12 @@  lib_a-mktime.o: mktime.c
 lib_a-mktime.obj: mktime.c
  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)
$(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-mktime.obj `if test -f 'mktime.c';
then $(CYGPATH_W) 'mktime.c'; else $(CYGPATH_W) '$(srcdir)/mktime.c'; fi`

+lib_a-timegm.o: timegm.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)
$(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-timegm.o `test -f 'timegm.c' || echo
'$(srcdir)/'`timegm.c
+
+lib_a-timegm.obj: timegm.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)
$(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-timegm.obj `if test -f 'timegm.c';
then $(CYGPATH_W) 'timegm.c'; else $(CYGPATH_W) '$(srcdir)/timegm.c'; fi`
+
 lib_a-month_lengths.o: month_lengths.c
  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)
$(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-month_lengths.o `test -f
'month_lengths.c' || echo '$(srcdir)/'`month_lengths.c

diff --git a/newlib/libc/time/local.h b/newlib/libc/time/local.h
index dce51cda2..119ddc35e 100644
--- a/newlib/libc/time/local.h
+++ b/newlib/libc/time/local.h
@@ -38,3 +38,5 @@  void _tzset_unlocked (void);
 void __tz_lock (void);
 void __tz_unlock (void);

+time_t __mktime_internal(struct tm *tim_p);
+void __set_tm_wday(long days, struct tm *tim_p);
diff --git a/newlib/libc/time/mktime.c b/newlib/libc/time/mktime.c
index 02032599a..53fb63ce7 100644
--- a/newlib/libc/time/mktime.c
+++ b/newlib/libc/time/mktime.c
@@ -11,6 +11,8 @@ 
  * represented, returns the value (time_t) -1.
  *
  * Modifications: Fixed tm_isdst usage - 27 August 2008 Craig Howland.
+ *                      Refactor code from mktime.c to share internal
+ *                      functions. - 17 July 2018 Andrew Russell.
  */

 /*
@@ -44,13 +46,14 @@  ANSI C requires <<mktime>>.

 #include <stdlib.h>
 #include <time.h>
+#include <stdint.h>
 #include "local.h"

 #define _SEC_IN_MINUTE 60L
 #define _SEC_IN_HOUR 3600L
 #define _SEC_IN_DAY 86400L

-static const int DAYS_IN_MONTH[12] =
+static const int_least16_t DAYS_IN_MONTH[12] =
 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

 #define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x])
@@ -58,11 +61,21 @@  static const int DAYS_IN_MONTH[12] =
 static const int _DAYS_BEFORE_MONTH[12] =
 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

-#define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) %
400) == 0))
-#define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365)
+/* returns either 0 or 1 */
+static int
+__is_leap_year (int year)
+{
+  return (year % 4) == 0 && ((year % 100) != 0 || (((year / 100) & 3) ==
(-(YEAR_BASE / 100)  & 3)));
+}
+
+static int
+__days_in_year (int year)
+{
+  return __is_leap_year(year) ? 366 : 365;
+}

-static void
-validate_structure (struct tm *tim_p)
+static void
+__validate_tm_structure (struct tm *tim_p)
 {
   div_t res;
   int days_in_feb = 28;
@@ -112,7 +125,7 @@  validate_structure (struct tm *tim_p)
         }
     }

-  if (_DAYS_IN_YEAR (tim_p->tm_year) == 366)
+  if (__days_in_year(tim_p->tm_year) == 366)
     days_in_feb = 29;

   if (tim_p->tm_mday <= 0)
@@ -124,7 +137,7 @@  validate_structure (struct tm *tim_p)
        tim_p->tm_year--;
        tim_p->tm_mon = 11;
        days_in_feb =
- ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
+ ((__days_in_year(tim_p->tm_year) == 366) ?
  29 : 28);
      }
    tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon);
@@ -140,15 +153,24 @@  validate_structure (struct tm *tim_p)
        tim_p->tm_year++;
        tim_p->tm_mon = 0;
        days_in_feb =
- ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ?
+ ((__days_in_year(tim_p->tm_year) == 366) ?
  29 : 28);
      }
  }
     }
 }

-time_t
-mktime (struct tm *tim_p)
+void
+__set_tm_wday (long days, struct tm *tim_p)
+{
+  if ((tim_p->tm_wday = (days + 4) % 7) < 0)
+    tim_p->tm_wday += 7;
+}
+
+// Assumes the time at tim_p is a UTC time and returns its arithmetic
+// representation
+time_t
+__mktime_internal (struct tm *tim_p)
 {
   time_t tim = 0;
   long days = 0;
@@ -156,7 +178,7 @@  mktime (struct tm *tim_p)
   __tzinfo_type *tz = __gettzinfo ();

   /* validate structure */
-  validate_structure (tim_p);
+  __validate_tm_structure (tim_p);

   /* compute hours, minutes, seconds */
   tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) +
@@ -165,7 +187,7 @@  mktime (struct tm *tim_p)
   /* compute days in year */
   days += tim_p->tm_mday - 1;
   days += _DAYS_BEFORE_MONTH[tim_p->tm_mon];
-  if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366)
+  if (tim_p->tm_mon > 1 && __days_in_year(tim_p->tm_year) == 366)
     days++;

   /* compute day of the year */
@@ -178,17 +200,29 @@  mktime (struct tm *tim_p)
   if ((year = tim_p->tm_year) > 70)
     {
       for (year = 70; year < tim_p->tm_year; year++)
- days += _DAYS_IN_YEAR (year);
+ days += __days_in_year(year);
     }
   else if (year < 70)
     {
       for (year = 69; year > tim_p->tm_year; year--)
- days -= _DAYS_IN_YEAR (year);
-      days -= _DAYS_IN_YEAR (year);
+ days -= __days_in_year(year);
+      days -= __days_in_year(year);
     }

   /* compute total seconds */
-  tim += (time_t)days * _SEC_IN_DAY;
+  tim += (days * _SEC_IN_DAY);
+
+  return tim;
+}
+
+time_t
+mktime (struct tm *tim_p)
+{
+  time_t tim = __mktime_internal(tim_p);
+  long days = tim / SECSPERDAY;
+  int year = tim_p->tm_year;
+  int isdst=0;
+  __tzinfo_type *tz = __gettzinfo ();

   TZ_LOCK;

@@ -204,7 +238,7 @@  mktime (struct tm *tim_p)

       if (y == tz->__tzyear || __tzcalc_limits (y))
  {
-   /* calculate start of dst in dst local time and
+   /* 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 = tz->__tzrule[0].change
      - (time_t) tz->__tzrule[1].offset;
@@ -237,7 +271,7 @@  mktime (struct tm *tim_p)
    tim_p->tm_sec += diff;
    tim += diff;  /* we also need to correct our current time calculation */
    int mday = tim_p->tm_mday;
-   validate_structure (tim_p);
+   __validate_tm_structure(tim_p);
    mday = tim_p->tm_mday - mday;
    /* roll over occurred */
    if (mday) {
@@ -251,9 +285,9 @@  mktime (struct tm *tim_p)
      /* handle yday */
      if ((tim_p->tm_yday += mday) < 0) {
    --year;
-   tim_p->tm_yday = _DAYS_IN_YEAR(year) - 1;
+   tim_p->tm_yday = __days_in_year(year) - 1;
      } else {
-   mday = _DAYS_IN_YEAR(year);
+   mday = __days_in_year(year);
    if (tim_p->tm_yday > (mday - 1))
  tim_p->tm_yday -= mday;
      }
@@ -275,8 +309,7 @@  mktime (struct tm *tim_p)
   tim_p->tm_isdst = isdst;

   /* compute day of the week */
-  if ((tim_p->tm_wday = (days + 4) % 7) < 0)
-    tim_p->tm_wday += 7;
-
+  __set_tm_wday(days, tim_p);
+
   return tim;
 }
diff --git a/newlib/libc/time/timegm.c b/newlib/libc/time/timegm.c
new file mode 100644
index 000000000..063d334d5
--- /dev/null
+++ b/newlib/libc/time/timegm.c
@@ -0,0 +1,62 @@ 
+/*
+ * timegm.c
+ * Original Author: A. Russell
+ *
+ * Converts the broken-down time, expressed as UTC time, in the structure
+ * pointed to by tim_p into a calendar time value. The original values of
the
+ * tm_wday and tm_yday fields of the structure are ignored, and the
original
+ * values of the other fields have no restrictions. On successful
completion
+ * the fields of the structure are set to represent the specified calendar
+ * time. Returns the specified calendar time. If the calendar time can not
be
+ * represented, returns the value (time_t) -1.  These functions are
nonstandard
+ * GNU extensions that are also present on the BSDs.  Avoid their use.
+ * Modifications: Refactored mktime.c to support both mktime and timegm
+                         - 23 July 2018 Andrew Russell.
+ */
+
+/*
+FUNCTION
+<<timegm>>---convert time to arithmetic representation
+
+INDEX
+ timegm
+
+SYNOPSIS
+ #include <time.h>
+ time_t timegm(struct tm *<[timp]>);
+
+DESCRIPTION
+<<timegm>> assumes the time at <[timp]> is a UTC time, and converts
+its representation from the traditional representation defined by
+<<struct tm>> into a representation suitable for arithmetic.
+
+<<timegm>> is the inverse of <<gmtime>>.
+
+RETURNS
+If the contents of the structure at <[timp]> do not form a valid
+calendar time representation, the result is <<-1>>.  Otherwise, the
+result is the time, converted to a <<time_t>> value.
+
+PORTABILITY
+<<timegm>> is a nonstandard GNU extension to POSIX also present on BSD.
+
+<<timegm>> requires no supporting OS subroutines.
+*/
+
+#include <stdlib.h>
+#include <time.h>
+#include "local.h"
+
+time_t timegm (struct tm *tim_p)
+{
+  time_t tim = __mktime_internal(tim_p);
+  long days = tim / SECSPERDAY;
+
+  /* set isdst flag to 0 since we are in UTC */
+  tim_p->tm_isdst = 0;
+