Tweak white space parsing rules (again):

* White space matches zero or more white space characters.

  * %n matches one white space character.

  * %t matches zero or one white space characters.
This commit is contained in:
Howard Hinnant
2017-05-07 15:25:07 -04:00
parent cf0481b9af
commit f493bd67f2
2 changed files with 104 additions and 24 deletions

50
date.h
View File

@@ -5364,22 +5364,22 @@ template <class CharT, class Traits, class ...Args>
void void
read(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args) read(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args)
{ {
// No-op if a0 == CharT{}
if (a0 != CharT{}) if (a0 != CharT{})
{ {
auto ic = is.peek(); auto ic = is.peek();
if (Traits::eq_int_type(ic, Traits::eof()) || if (Traits::eq_int_type(ic, Traits::eof()))
!Traits::eq(Traits::to_char_type(ic), a0)) {
is.setstate(std::ios::failbit | std::ios::eofbit);
return;
}
if (!Traits::eq(Traits::to_char_type(ic), a0))
{ {
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
return; return;
} }
(void)is.get(); (void)is.get();
} }
else
{
while (isspace(is.peek()))
(void)is.get();
}
read(is, std::forward<Args>(args)...); read(is, std::forward<Args>(args)...);
} }
@@ -5486,12 +5486,6 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
using detail::rld; using detail::rld;
for (; *fmt && is.rdstate() == std::ios::goodbit; ++fmt) for (; *fmt && is.rdstate() == std::ios::goodbit; ++fmt)
{ {
if (isspace(*fmt))
{
// space matches 0 or more white space characters
ws(is);
continue;
}
switch (*fmt) switch (*fmt)
{ {
case 'a': case 'a':
@@ -5791,20 +5785,23 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 't': case 't':
if (command) if (command)
{ {
// %n and %t match 1 or more white space characters // %n matches a single white space character
// consecutive %n and %t count as one // %t matches 0 or 1 white space characters
auto ic = is.peek(); auto ic = is.peek();
if (Traits::eq_int_type(ic, Traits::eof())) if (Traits::eq_int_type(ic, Traits::eof()))
break;
if (!isspace(ic))
{ {
is.setstate(ios::failbit); ios_base::iostate err = ios_base::eofbit;
if (*fmt == 'n')
err |= ios_base::failbit;
is.setstate(err);
break; break;
} }
ws(is); if (isspace(ic))
for (++fmt; *fmt == 'n' || *fmt == 't'; ++fmt) {
; (void)is.get();
--fmt; }
else if (*fmt == 'n')
is.setstate(ios_base::failbit);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6192,8 +6189,13 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
modified = CharT{}; modified = CharT{};
} }
} }
else else // !command
read(is, *fmt); {
if (isspace(*fmt))
ws(is); // space matches 0 or more white space characters
else
read(is, *fmt);
}
break; break;
} }
} }

View File

@@ -740,6 +740,81 @@ test_leading_ws()
assert(d2 == may/4/2017); assert(d2 == may/4/2017);
} }
void
test_space()
{
using namespace std;
using namespace date;
{
istringstream in{"05/04/17"};
year_month_day d1;
in >> parse(" %D", d1);
assert(d1 == may/4/2017);
}
{
istringstream in{" 05/04/17"};
year_month_day d1;
in >> parse(" %D", d1);
assert(d1 == may/4/2017);
}
{
istringstream in{" 05/04/17"};
year_month_day d1;
in >> parse(" %D", d1);
assert(d1 == may/4/2017);
}
}
void
test_n()
{
using namespace std;
using namespace date;
{
istringstream in{"05/04/17"};
year_month_day d1;
in >> parse("%n%D", d1);
assert(in.fail());
}
{
istringstream in{" 05/04/17"};
year_month_day d1;
in >> parse("%n%D", d1);
assert(d1 == may/4/2017);
}
{
istringstream in{" 05/04/17"};
year_month_day d1;
in >> parse("%n%D", d1);
assert(in.fail());
}
}
void
test_t()
{
using namespace std;
using namespace date;
{
istringstream in{"05/04/17"};
year_month_day d1;
in >> parse("%t%D", d1);
assert(d1 == may/4/2017);
}
{
istringstream in{" 05/04/17"};
year_month_day d1;
in >> parse("%t%D", d1);
assert(d1 == may/4/2017);
}
{
istringstream in{" 05/04/17"};
year_month_day d1;
in >> parse("%t%D", d1);
assert(in.fail());
}
}
int int
main() main()
{ {
@@ -769,4 +844,7 @@ main()
test_Z(); test_Z();
test_trailing_Z(); test_trailing_Z();
test_leading_ws(); test_leading_ws();
test_space();
test_n();
test_t();
} }