Discussion:
[PATCH] Add timegm POSIX call [updated]
Andrew Russell via newlib
2018-08-22 19:12:41 UTC
Permalink
From 7f6e9b06c27be11fb37302af29c4fd6932a1cab5 Mon Sep 17 00:00:00 2001
From: Andrew Russell <***@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

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
@***@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;
+
+ /* compute day of the week */
+ __set_tm_wday(days, tim_p);
+
+ return tim;
+}
--
2.18.0.1017.ga543ac7ca45-goog
Freddie Chopin
2018-08-22 21:02:59 UTC
Permalink
Post by Andrew Russell via newlib
-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 ->
Post by Andrew Russell via newlib
@@ -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
2018-08-22 23:37:07 UTC
Permalink
Post by Freddie Chopin
Post by Andrew Russell via newlib
-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?
Post by Freddie Chopin
Post by Andrew Russell via newlib
@@ -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
2018-08-23 07:27:53 UTC
Permalink
Post by Brian Inglis
Post by Andrew Russell via newlib
@@ -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
2018-08-27 06:39:37 UTC
Permalink
Post by Freddie Chopin
Post by Brian Inglis
Post by Andrew Russell via newlib
@@ -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.
Andrew Russell via newlib
2018-08-23 18:26:11 UTC
Permalink
From e7472f255204596fe9f55c8c953db923f74f411f Mon Sep 17 00:00:00 2001
From: Andrew Russell <***@google.com>
Date: Thu, 23 Aug 2018 11:10:21 -0700
Subject: [PATCH 1/1] Refactor mktime and add the POSIX function timegm

Added the reduced sizes for the days constants.
---
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 | 81 +++++++++++++++++++++++++-----------
newlib/libc/time/timegm.c | 63 ++++++++++++++++++++++++++++
7 files changed, 136 insertions(+), 25 deletions(-)
create mode 100644 newlib/libc/time/timegm.c

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
@***@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..93a85b83c 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..b671c3fcd 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,25 +46,36 @@ 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 uint_least8_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])

-static const int _DAYS_BEFORE_MONTH[12] =
+static const uint_least16_t _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..d83d97082
--- /dev/null
+++ b/newlib/libc/time/timegm.c
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+ /* compute day of the week */
+ __set_tm_wday(days, tim_p);
+
+ return tim;
+}
--
2.18.0.1017.ga543ac7ca45-goog
Andrew Russell via newlib
2018-08-23 19:56:20 UTC
Permalink
From 45939beb4546d0bc005062e30c05cfea88e6bf47 Mon Sep 17 00:00:00 2001
From: Andrew Russell <***@google.com>
Date: Thu, 23 Aug 2018 11:10:21 -0700
Subject: [PATCH 1/1] Refactor mktime and add the POSIX function timegm

Updated with appropriate version-gating of the timegm() symbol from time.h

---
newlib/libc/include/time.h | 3 ++
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 | 81 +++++++++++++++++++++++++-----------
newlib/libc/time/timegm.c | 63 ++++++++++++++++++++++++++++
7 files changed, 138 insertions(+), 25 deletions(-)
create mode 100644 newlib/libc/time/timegm.c

diff --git a/newlib/libc/include/time.h b/newlib/libc/include/time.h
index a2efcc15e..e5e151881 100644
--- a/newlib/libc/include/time.h
+++ b/newlib/libc/include/time.h
@@ -56,6 +56,9 @@ struct tm
clock_t clock (void);
double difftime (time_t _time2, time_t _time1);
time_t mktime (struct tm *_timeptr);
+#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_GNU_SOURCE)
+time_t timegm (struct tm *_timeptr);
+#endif // defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_GNU_SOURCE)
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
@***@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..93a85b83c 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..b671c3fcd 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,25 +46,36 @@ 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 uint_least8_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])

-static const int _DAYS_BEFORE_MONTH[12] =
+static const uint_least16_t _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..d83d97082
--- /dev/null
+++ b/newlib/libc/time/timegm.c
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+ /* compute day of the week */
+ __set_tm_wday(days, tim_p);
+
+ return tim;
+}
--
2.18.0.1017.ga543ac7ca45-goog
Corinna Vinschen
2018-08-24 11:28:22 UTC
Permalink
Post by Andrew Russell via newlib
Post by Andrew Russell via newlib
From 45939beb4546d0bc005062e30c05cfea88e6bf47 Mon Sep 17 00:00:00 2001
Date: Thu, 23 Aug 2018 11:10:21 -0700
Subject: [PATCH 1/1] Refactor mktime and add the POSIX function timegm
Updated with appropriate version-gating of the timegm() symbol from time.h
---
newlib/libc/include/time.h | 3 ++
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 | 81 +++++++++++++++++++++++++-----------
newlib/libc/time/timegm.c | 63 ++++++++++++++++++++++++++++
7 files changed, 138 insertions(+), 25 deletions(-)
create mode 100644 newlib/libc/time/timegm.c
diff --git a/newlib/libc/include/time.h b/newlib/libc/include/time.h
index a2efcc15e..e5e151881 100644
--- a/newlib/libc/include/time.h
+++ b/newlib/libc/include/time.h
@@ -56,6 +56,9 @@ struct tm
clock_t clock (void);
double difftime (time_t _time2, time_t _time1);
time_t mktime (struct tm *_timeptr);
+#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_GNU_SOURCE)
This is not correct. Don't use the _XXX_SOURCE macros in the header
files, use the __XXX_VISIBLE macros instead. Please have a look at the
descriptive comments in newlib/libc/include/sys/features.h and compare
with other usages of the __XXX_VISIBLE macros.

Btw., _BSD_SOURCE and _SVID_SOURCE are deprecated, as on Linux. That's
_DEFAULT_SOURCE these days (but see above).


Thanks,
Corinna
--
Corinna Vinschen
Cygwin Maintainer
Red Hat
Andrew Russell via newlib
2018-08-24 18:25:29 UTC
Permalink
Thanks for the head's up, Corinna. Updated.

From 44fec0ae308ae6bc8c6f46b9a428d8ac28045f4b Mon Sep 17 00:00:00 2001
From: Andrew Russell <***@google.com>
Date: Thu, 23 Aug 2018 11:10:21 -0700
Subject: [PATCH 1/1] Refactor mktime and add the POSIX function timegm

---
newlib/libc/include/time.h | 3 ++
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 | 81 +++++++++++++++++++++++++-----------
newlib/libc/time/timegm.c | 63 ++++++++++++++++++++++++++++
7 files changed, 138 insertions(+), 25 deletions(-)
create mode 100644 newlib/libc/time/timegm.c

diff --git a/newlib/libc/include/time.h b/newlib/libc/include/time.h
index a2efcc15e..e79bd4b93 100644
--- a/newlib/libc/include/time.h
+++ b/newlib/libc/include/time.h
@@ -56,6 +56,9 @@ struct tm
clock_t clock (void);
double difftime (time_t _time2, time_t _time1);
time_t mktime (struct tm *_timeptr);
+#if __BSD_VISIBLE || __SVID_VISIBLE || __GNU_VISIBLE
+time_t timegm (struct tm *_timeptr);
+#endif // __BSD_VISIBLE || __SVID_VISIBLE || __GNU_VISIBLE
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
@***@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..93a85b83c 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..b671c3fcd 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,25 +46,36 @@ 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 uint_least8_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])

-static const int _DAYS_BEFORE_MONTH[12] =
+static const uint_least16_t _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..d83d97082
--- /dev/null
+++ b/newlib/libc/time/timegm.c
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+ /* compute day of the week */
+ __set_tm_wday(days, tim_p);
+
+ return tim;
+}
--
2.19.0.rc0.228.g281dcd1b4d0-goog
Corinna Vinschen
2018-08-27 10:48:26 UTC
Permalink
Post by Andrew Russell via newlib
Thanks for the head's up, Corinna. Updated.
Post by Andrew Russell via newlib
From 44fec0ae308ae6bc8c6f46b9a428d8ac28045f4b Mon Sep 17 00:00:00 2001
Date: Thu, 23 Aug 2018 11:10:21 -0700
Subject: [PATCH 1/1] Refactor mktime and add the POSIX function timegm
---
newlib/libc/include/time.h | 3 ++
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 | 81 +++++++++++++++++++++++++-----------
newlib/libc/time/timegm.c | 63 ++++++++++++++++++++++++++++
7 files changed, 138 insertions(+), 25 deletions(-)
create mode 100644 newlib/libc/time/timegm.c
Your patch doesn't apply cleanly, probably mangled by your MUA. Can you
please send it again as attachment, as created by `git format-patch'?


Thanks,
Corinna
--
Corinna Vinschen
Cygwin Maintainer
Red Hat
Loading...