Merge "Convert new tests to GTEST_SKIP."
diff --git a/docs/status.md b/docs/status.md
index 0cbcb47..d6a2f4c 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -45,14 +45,17 @@
* `getloadavg` (BSD/GNU extension in <stdlib.h>)
New libc behavior in Q (API level 29):
- * Whole printf family now supports the GNU `%m` extension, rather than a special-case hack in `syslog`
- * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension
- * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff
- * `aligned_alloc` correctly verifies that `size` is a multiple of `alignment`
+ * Whole printf family now supports the GNU `%m` extension, rather than a
+ special-case hack in `syslog`.
+ * `popen` now always uses `O_CLOEXEC`, not just with the `e` extension.
+ * Bug fixes to handling of UTF-8 U+fffe/U+ffff and code points above U+10ffff.
+ * `aligned_alloc` correctly verifies that `size` is a multiple of `alignment`.
* Using `%n` with the printf family is now reported as a FORTIFY failure.
Previous versions of Android would ignore the `%n` but not consume the
corresponding pointer argument, leading to obscure errors. The scanf family
is unchanged.
+ * Support in strptime for `%F`, `%G`, `%g`, `%P`, `%u`, `%V`, and `%v`.
+ (strftime already supported them all.)
* [fdsan](fdsan.md) detects common file descriptor errors at runtime.
New libc functions in P (API level 28):
@@ -74,9 +77,9 @@
* `syncfs`
New libc behavior in P (API level 28):
- * `%C` and `%S` support in the printf family (previously only the wprintf family supported these)
- * `%mc`/`%ms`/`%m[` support in the scanf family
- * `%s` support in strptime (strftime already supported it)
+ * `%C` and `%S` support in the printf family (previously only the wprintf family supported these).
+ * `%mc`/`%ms`/`%m[` support in the scanf family.
+ * `%s` support in strptime (strftime already supported it).
* Using a `pthread_mutex_t` after it's been destroyed will be detected at
runtime and reported as a FORTIFY failure.
* Passing a null `FILE*` or `DIR*` to libc is now detected at runtime and
diff --git a/libc/tzcode/strptime.c b/libc/tzcode/strptime.c
index 0e9a7d3..41eaa9b 100644
--- a/libc/tzcode/strptime.c
+++ b/libc/tzcode/strptime.c
@@ -172,6 +172,12 @@
return (NULL);
break;
+ case 'F': /* The date as "%Y-%m-%d". */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%Y-%m-%d", tm, cr)))
+ return (NULL);
+ continue;
+
case 'R': /* The time as "%H:%M". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
@@ -190,6 +196,12 @@
return (NULL);
break;
+ case 'v': /* The date as "%e-%b-%Y". */
+ _LEGAL_ALT(0);
+ if (!(bp = _strptime(bp, "%e-%b-%Y", tm, cr)))
+ return (NULL);
+ break;
+
case 'X': /* The time, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
@@ -305,6 +317,7 @@
tm->tm_mon--;
break;
+ case 'P':
case 'p': /* The locale's equivalent of AM/PM. */
_LEGAL_ALT(0);
/* AM? */
@@ -377,6 +390,33 @@
return (NULL);
break;
+ case 'u': /* The day of week, monday = 1. */
+ _LEGAL_ALT(_ALT_O);
+ if (!(_conv_num(&bp, &i, 1, 7)))
+ return (NULL);
+ tm->tm_wday = i % 7;
+ continue;
+
+ case 'g': /* The year corresponding to the ISO week
+ * number but without the century.
+ */
+ if (!(_conv_num(&bp, &i, 0, 99)))
+ return (NULL);
+ continue;
+
+ case 'G': /* The year corresponding to the ISO week
+ * number with century.
+ */
+ do
+ bp++;
+ while (isdigit(*bp));
+ continue;
+
+ case 'V': /* The ISO 8601:1988 week number as decimal */
+ if (!(_conv_num(&bp, &i, 0, 53)))
+ return (NULL);
+ continue;
+
case 'Y': /* The year. */
_LEGAL_ALT(_ALT_E);
if (!(_conv_num(&bp, &i, 0, 9999)))
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 637fa85..8653d91 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -296,6 +296,59 @@
EXPECT_STREQ("09:41:53", buf);
}
+TEST(time, strptime_F) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm tm = {};
+ ASSERT_EQ('\0', *strptime("2019-03-26", "%F", &tm));
+ EXPECT_EQ(119, tm.tm_year);
+ EXPECT_EQ(2, tm.tm_mon);
+ EXPECT_EQ(26, tm.tm_mday);
+}
+
+TEST(time, strptime_P_p) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm tm = {.tm_hour = 12};
+ ASSERT_EQ('\0', *strptime("AM", "%p", &tm));
+ EXPECT_EQ(0, tm.tm_hour);
+
+ tm = {.tm_hour = 12};
+ ASSERT_EQ('\0', *strptime("AM", "%P", &tm));
+ EXPECT_EQ(0, tm.tm_hour);
+}
+
+TEST(time, strptime_u) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm tm = {};
+ ASSERT_EQ('\0', *strptime("2", "%u", &tm));
+ EXPECT_EQ(2, tm.tm_wday);
+}
+
+TEST(time, strptime_v) {
+ setenv("TZ", "UTC", 1);
+
+ struct tm tm = {};
+ ASSERT_EQ('\0', *strptime("26-Mar-1980", "%v", &tm));
+ EXPECT_EQ(80, tm.tm_year);
+ EXPECT_EQ(2, tm.tm_mon);
+ EXPECT_EQ(26, tm.tm_mday);
+}
+
+TEST(time, strptime_V_G_g) {
+ setenv("TZ", "UTC", 1);
+
+ // %V (ISO-8601 week number), %G (year of week number, without century), and
+ // %g (year of week number) have no effect when parsed, and are supported
+ // solely so that it's possible for strptime(3) to parse everything that
+ // strftime(3) can output.
+ struct tm tm = {};
+ ASSERT_EQ('\0', *strptime("1 2 3", "%V %G %g", &tm));
+ struct tm zero = {};
+ EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0);
+}
+
void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time_t interval_ns) {
itimerspec ts;
ts.it_value.tv_sec = value_s;