Add strptime %s.
Bug: https://issuetracker.google.com/37128336
Test: ran tests
Change-Id: I1a660dbdb5f008e42226f26489f0f01b6db18025
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 2100630..0e9a7d3 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -38,7 +38,9 @@
//#include <sys/localedef.h>
#include <ctype.h>
+#include <errno.h>
#include <locale.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tzfile.h"
@@ -128,7 +130,7 @@
fmt++;
continue;
}
-
+
if ((c = *fmt++) != '%')
goto literal;
@@ -154,7 +156,7 @@
_LEGAL_ALT(0);
alt_format |= _ALT_O;
goto again;
-
+
/*
* "Complex" conversion rules, implemented through recursion.
*/
@@ -169,7 +171,7 @@
if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
return (NULL);
break;
-
+
case 'R': /* The time as "%H:%M". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
@@ -337,6 +339,25 @@
return (NULL);
break;
+ case 's':
+ {
+ // Android addition, based on FreeBSD's implementation.
+ int saved_errno = errno;
+ errno = 0;
+ const unsigned char* old_bp = bp;
+ long n = strtol((const char*) bp, (char**) &bp, 10);
+ time_t t = n;
+ if (bp == old_bp || errno == ERANGE || ((long) t) != n) {
+ errno = saved_errno;
+ return NULL;
+ }
+ errno = saved_errno;
+
+ if (localtime_r(&t, tm) == NULL) return NULL;
+ }
+ break;
+
+
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
_LEGAL_ALT(_ALT_O);
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 2b9935a..ff427a6 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -871,3 +871,54 @@
ASSERT_EQ(buf, ctime_r(&t, buf));
ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", buf);
}
+
+// https://issuetracker.google.com/37128336
+TEST(time, strftime_strptime_s) {
+ char buf[32];
+ const struct tm tm0 = { .tm_year = 1982-1900, .tm_mon = 0, .tm_mday = 1 };
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378720000>", buf);
+
+ setenv("TZ", "UTC", 1);
+ strftime(buf, sizeof(buf), "<%s>", &tm0);
+ EXPECT_STREQ("<378691200>", buf);
+
+ struct tm tm;
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ char* p = strptime("378720000x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+
+ setenv("TZ", "UTC", 1);
+ tzset();
+ memset(&tm, 0xff, sizeof(tm));
+ p = strptime("378691200x", "%s", &tm);
+ ASSERT_EQ('x', *p);
+ EXPECT_EQ(0, tm.tm_sec);
+ EXPECT_EQ(0, tm.tm_min);
+ EXPECT_EQ(0, tm.tm_hour);
+ EXPECT_EQ(1, tm.tm_mday);
+ EXPECT_EQ(0, tm.tm_mon);
+ EXPECT_EQ(82, tm.tm_year);
+ EXPECT_EQ(5, tm.tm_wday);
+ EXPECT_EQ(0, tm.tm_yday);
+ EXPECT_EQ(0, tm.tm_isdst);
+}
+
+TEST(time, strptime_s_nothing) {
+ struct tm tm;
+ ASSERT_EQ(nullptr, strptime("x", "%s", &tm));
+}