Correct to_stream/from_stream handling of stream data

* to_stream and from_stream now reset the stream formatting state to
  default settings on entry, and restore the stream state on exit.

* to_stream and from_stream now correctly handle mis-modified flags.

* Fix %h to be equivalent to %b instead of %B.

* This addresses issues 319, 320 and 321.
This commit is contained in:
Howard Hinnant
2018-03-31 13:06:57 -04:00
parent e7e1482087
commit 0125d330ab

View File

@@ -944,9 +944,10 @@ namespace detail {
template<class CharT, class Traits = std::char_traits<CharT>> template<class CharT, class Traits = std::char_traits<CharT>>
class save_stream class save_stream
{ {
std::basic_ostream<CharT, Traits>& os_; std::basic_ios<CharT, Traits>& os_;
CharT fill_; CharT fill_;
std::ios::fmtflags flags_; std::ios::fmtflags flags_;
std::streamsize width_;
std::locale loc_; std::locale loc_;
public: public:
@@ -954,16 +955,18 @@ public:
{ {
os_.fill(fill_); os_.fill(fill_);
os_.flags(flags_); os_.flags(flags_);
os_.width(width_);
os_.imbue(loc_); os_.imbue(loc_);
} }
save_stream(const save_stream&) = delete; save_stream(const save_stream&) = delete;
save_stream& operator=(const save_stream&) = delete; save_stream& operator=(const save_stream&) = delete;
explicit save_stream(std::basic_ostream<CharT, Traits>& os) explicit save_stream(std::basic_ios<CharT, Traits>& os)
: os_(os) : os_(os)
, fill_(os.fill()) , fill_(os.fill())
, flags_(os.flags()) , flags_(os.flags())
, width_(os.width(0))
, loc_(os.getloc()) , loc_(os.getloc())
{} {}
}; };
@@ -3729,7 +3732,7 @@ typename std::enable_if
>::type >::type
abs(std::chrono::duration<Rep, Period> d) abs(std::chrono::duration<Rep, Period> d)
{ {
return d >= d.zero() ? d : -d; return d >= d.zero() ? +d : -d;
} }
template <class Rep, class Period> template <class Rep, class Period>
@@ -4578,6 +4581,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
using namespace detail; using namespace detail;
date::detail::save_stream<CharT, Traits> ss(os);
os.fill(' ');
os.flags(std::ios::skipws | std::ios::dec);
os.width(0);
tm tm{}; tm tm{};
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
auto& facet = use_facet<time_put<CharT>>(os.getloc()); auto& facet = use_facet<time_put<CharT>>(os.getloc());
@@ -4626,7 +4633,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
const CharT f[] = {'%', *fmt}; const CharT f[] = {'%', *fmt};
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
#else // ONLY_C_LOCALE #else // ONLY_C_LOCALE
os << month_names().first[tm.tm_mon+12*(*fmt == 'b')]; os << month_names().first[tm.tm_mon+12*(*fmt != 'B')];
#endif // ONLY_C_LOCALE #endif // ONLY_C_LOCALE
} }
else else
@@ -4709,8 +4716,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto y = static_cast<int>(fds.ymd.year()); auto y = static_cast<int>(fds.ymd.year());
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'O'})
#endif #endif
{
save_stream<CharT, Traits> _(os); save_stream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
@@ -4725,19 +4734,19 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
os.width(2); os.width(2);
os << -(y-99)/100; os << -(y-99)/100;
} }
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'E'}) else if (modified == CharT{'E'})
{ {
tm.tm_year = y - 1900; tm.tm_year = y - 1900;
CharT f[3] = {'%', 'E', 'C'}; CharT f[3] = {'%', 'E', 'C'};
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
command = nullptr; command = nullptr;
modified = CharT{}; modified = CharT{};
} }
@@ -4751,27 +4760,31 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day())); auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
save_stream<CharT, Traits> _(os); save_stream<CharT, Traits> _(os);
if (*fmt == CharT{'d'}) if (*fmt == CharT{'d'})
os.fill('0'); os.fill('0');
else
os.fill(' ');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(2); os.width(2);
os << d; os << d;
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
tm.tm_mday = d; tm.tm_mday = d;
CharT f[3] = {'%', 'O', *fmt}; CharT f[3] = {'%', 'O', *fmt};
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
command = nullptr; command = nullptr;
modified = CharT{}; modified = CharT{};
} }
@@ -4869,26 +4882,28 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto hms = fds.tod; auto hms = fds.tod;
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
if (*fmt == CharT{'I'}) if (*fmt == CharT{'I'})
hms.make12(); hms.make12();
if (hms.hours() < hours{10}) if (hms.hours() < hours{10})
os << CharT{'0'}; os << CharT{'0'};
os << hms.hours().count(); os << hms.hours().count();
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
tm.tm_hour = static_cast<int>(hms.hours().count()); tm.tm_hour = static_cast<int>(hms.hours().count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -4925,24 +4940,26 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto m = static_cast<unsigned>(fds.ymd.month()); auto m = static_cast<unsigned>(fds.ymd.month());
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
if (m < 10) if (m < 10)
os << CharT{'0'}; os << CharT{'0'};
os << m; os << m;
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
tm.tm_mon = static_cast<int>(m-1); tm.tm_mon = static_cast<int>(m-1);
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -4954,24 +4971,26 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
if (fds.tod.minutes() < minutes{10}) if (fds.tod.minutes() < minutes{10})
os << CharT{'0'}; os << CharT{'0'};
os << fds.tod.minutes().count(); os << fds.tod.minutes().count();
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
tm.tm_min = static_cast<int>(fds.tod.minutes().count()); tm.tm_min = static_cast<int>(fds.tod.minutes().count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -4996,23 +5015,23 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'p': case 'p':
if (command) if (command)
{ {
#if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ {
#if !ONLY_C_LOCALE
const CharT f[] = {'%', *fmt}; const CharT f[] = {'%', *fmt};
tm.tm_hour = static_cast<int>(fds.tod.hours().count()); tm.tm_hour = static_cast<int>(fds.tod.hours().count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
}
else
{
os << CharT{'%'} << modified << *fmt;
}
#else #else
if (fds.tod.hours() < hours{12}) if (fds.tod.hours() < hours{12})
os << ampm_names().first[0]; os << ampm_names().first[0];
else else
os << ampm_names().first[1]; os << ampm_names().first[1];
#endif #endif
}
else
{
os << CharT{'%'} << modified << *fmt;
}
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5022,19 +5041,14 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'r': case 'r':
if (command) if (command)
{ {
#if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ {
#if !ONLY_C_LOCALE
const CharT f[] = {'%', *fmt}; const CharT f[] = {'%', *fmt};
tm.tm_hour = static_cast<int>(fds.tod.hours().count()); tm.tm_hour = static_cast<int>(fds.tod.hours().count());
tm.tm_min = static_cast<int>(fds.tod.minutes().count()); tm.tm_min = static_cast<int>(fds.tod.minutes().count());
tm.tm_sec = static_cast<int>(fds.tod.seconds().count()); tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
}
else
{
os << CharT{'%'} << modified << *fmt;
}
#else #else
time_of_day<seconds> tod(duration_cast<seconds>(fds.tod.to_duration())); time_of_day<seconds> tod(duration_cast<seconds>(fds.tod.to_duration()));
tod.make12(); tod.make12();
@@ -5052,6 +5066,11 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
else else
os << ampm_names().first[1]; os << ampm_names().first[1];
#endif #endif
}
else
{
os << CharT{'%'} << modified << *fmt;
}
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5085,22 +5104,24 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
os << fds.tod.s_; os << fds.tod.s_;
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
tm.tm_sec = static_cast<int>(fds.tod.s_.seconds().count()); tm.tm_sec = static_cast<int>(fds.tod.s_.seconds().count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5147,22 +5168,24 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
return os; return os;
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
os << (wd != 0 ? wd : 7u); os << (wd != 0 ? wd : 7u);
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
tm.tm_wday = static_cast<int>(wd); tm.tm_wday = static_cast<int>(wd);
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5176,8 +5199,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto ld = local_days(ymd); auto ld = local_days(ymd);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
auto st = local_days(sun[1]/jan/ymd.year()); auto st = local_days(sun[1]/jan/ymd.year());
if (ld < st) if (ld < st)
os << CharT{'0'} << CharT{'0'}; os << CharT{'0'} << CharT{'0'};
@@ -5188,8 +5213,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
os << CharT{'0'}; os << CharT{'0'};
os << wn; os << wn;
} }
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
@@ -5200,11 +5225,11 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count()); tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5217,8 +5242,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto ld = local_days(fds.ymd); auto ld = local_days(fds.ymd);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
auto y = year_month_day{ld + days{3}}.year(); auto y = year_month_day{ld + days{3}}.year();
auto st = local_days((y - years{1})/12/thu[last]) + (mon-thu); auto st = local_days((y - years{1})/12/thu[last]) + (mon-thu);
if (ld < st) if (ld < st)
@@ -5230,8 +5257,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
if (wn < 10) if (wn < 10)
os << CharT{'0'}; os << CharT{'0'};
os << wn; os << wn;
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
@@ -5243,11 +5270,11 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count()); tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5262,22 +5289,24 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
return os; return os;
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
os << wd; os << wd;
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
tm.tm_wday = static_cast<int>(wd); tm.tm_wday = static_cast<int>(wd);
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5291,8 +5320,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto ld = local_days(ymd); auto ld = local_days(ymd);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
auto st = local_days(mon[1]/jan/ymd.year()); auto st = local_days(mon[1]/jan/ymd.year());
if (ld < st) if (ld < st)
os << CharT{'0'} << CharT{'0'}; os << CharT{'0'} << CharT{'0'};
@@ -5303,8 +5334,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
os << CharT{'0'}; os << CharT{'0'};
os << wn; os << wn;
} }
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
@@ -5315,11 +5346,11 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count()); tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5329,11 +5360,11 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'X': case 'X':
if (command) if (command)
{ {
#if !ONLY_C_LOCALE
if (modified == CharT{'O'}) if (modified == CharT{'O'})
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
else else
{ {
#if !ONLY_C_LOCALE
tm = std::tm{}; tm = std::tm{};
tm.tm_sec = static_cast<int>(fds.tod.seconds().count()); tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
tm.tm_min = static_cast<int>(fds.tod.minutes().count()); tm.tm_min = static_cast<int>(fds.tod.minutes().count());
@@ -5344,10 +5375,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
*fe++ = modified; *fe++ = modified;
*fe++ = *fmt; *fe++ = *fmt;
facet.put(os, os, os.fill(), &tm, begin(f), fe); facet.put(os, os, os.fill(), &tm, begin(f), fe);
}
#else #else
os << fds.tod; os << fds.tod;
#endif #endif
}
command = nullptr; command = nullptr;
modified = CharT{}; modified = CharT{};
} }
@@ -5387,22 +5418,24 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto y = fds.ymd.year(); auto y = fds.ymd.year();
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'O'})
#endif #endif
{
os << y; os << y;
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'E'}) else if (modified == CharT{'E'})
{ {
const CharT f[] = {'%', modified, *fmt}; const CharT f[] = {'%', modified, *fmt};
tm.tm_year = static_cast<int>(y) - 1900; tm.tm_year = static_cast<int>(y) - 1900;
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif
else else
{ {
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
} }
#endif
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
} }
@@ -5933,6 +5966,10 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
typename basic_istream<CharT, Traits>::sentry ok{is, true}; typename basic_istream<CharT, Traits>::sentry ok{is, true};
if (ok) if (ok)
{ {
date::detail::save_stream<CharT, Traits> ss(is);
is.fill(' ');
is.flags(std::ios::skipws | std::ios::dec);
is.width(0);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
auto& f = use_facet<time_get<CharT>>(is.getloc()); auto& f = use_facet<time_get<CharT>>(is.getloc());
std::tm tm{}; std::tm tm{};
@@ -5976,6 +6013,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 'A': case 'A':
if (command) if (command)
{ {
if (modified == CharT{})
{
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
f.get(is, nullptr, is, err, &tm, command, fmt+1); f.get(is, nullptr, is, err, &tm, command, fmt+1);
@@ -5988,6 +6027,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
if (!is.fail()) if (!is.fail())
wd = i % 7; wd = i % 7;
#endif #endif
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6000,6 +6042,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 'h': case 'h':
if (command) if (command)
{ {
if (modified == CharT{})
{
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
f.get(is, nullptr, is, err, &tm, command, fmt+1); f.get(is, nullptr, is, err, &tm, command, fmt+1);
@@ -6012,6 +6056,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
if (!is.fail()) if (!is.fail())
m = i % 12 + 1; m = i % 12 + 1;
#endif #endif
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6022,6 +6069,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 'c': case 'c':
if (command) if (command)
{ {
if (modified != CharT{'O'})
{
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
f.get(is, nullptr, is, err, &tm, command, fmt+1); f.get(is, nullptr, is, err, &tm, command, fmt+1);
@@ -6067,6 +6116,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
ws(is); ws(is);
read(is, rs{Y, 1, 4u}); read(is, rs{Y, 1, 4u});
#endif #endif
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6077,6 +6129,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 'x': case 'x':
if (command) if (command)
{ {
if (modified != CharT{'O'})
{
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
f.get(is, nullptr, is, err, &tm, command, fmt+1); f.get(is, nullptr, is, err, &tm, command, fmt+1);
@@ -6091,6 +6145,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
read(is, ru{m, 1, 2}, CharT{'/'}, ru{d, 1, 2}, CharT{'/'}, read(is, ru{m, 1, 2}, CharT{'/'}, ru{d, 1, 2}, CharT{'/'},
rs{y, 1, 2}); rs{y, 1, 2});
#endif #endif
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6101,6 +6158,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 'X': case 'X':
if (command) if (command)
{ {
if (modified != CharT{'O'})
{
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
f.get(is, nullptr, is, err, &tm, command, fmt+1); f.get(is, nullptr, is, err, &tm, command, fmt+1);
@@ -6126,6 +6185,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
s = round<Duration>(duration<long double>{S}); s = round<Duration>(duration<long double>{S});
} }
#endif #endif
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6199,8 +6261,12 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{
read(is, rs{d, 1, width == -1 ? 2u : static_cast<unsigned>(width)}); read(is, rs{d, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
}
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
@@ -6213,9 +6279,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
d = tm.tm_mday; d = tm.tm_mday;
is.setstate(err); is.setstate(err);
} }
#endif
else else
read(is, CharT{'%'}, width, modified, *fmt); read(is, CharT{'%'}, width, modified, *fmt);
#endif
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6228,14 +6294,16 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
int H; int H;
read(is, ru{H, 1, width == -1 ? 2u : static_cast<unsigned>(width)}); read(is, ru{H, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
if (!is.fail()) if (!is.fail())
h = hours{H}; h = hours{H};
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
@@ -6244,9 +6312,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
h = hours{tm.tm_hour}; h = hours{tm.tm_hour};
is.setstate(err); is.setstate(err);
} }
#endif
else else
read(is, CharT{'%'}, width, modified, *fmt); read(is, CharT{'%'}, width, modified, *fmt);
#endif
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6298,14 +6366,16 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
int M; int M;
read(is, ru{M, 1, width == -1 ? 2u : static_cast<unsigned>(width)}); read(is, ru{M, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
if (!is.fail()) if (!is.fail())
min = minutes{M}; min = minutes{M};
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
@@ -6314,9 +6384,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
min = minutes{tm.tm_min}; min = minutes{tm.tm_min};
is.setstate(err); is.setstate(err);
} }
#endif
else else
read(is, CharT{'%'}, width, modified, *fmt); read(is, CharT{'%'}, width, modified, *fmt);
#endif
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6329,6 +6399,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
read(is, rs{m, 1, width == -1 ? 2u : static_cast<unsigned>(width)}); read(is, rs{m, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
@@ -6340,9 +6412,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
m = tm.tm_mon + 1; m = tm.tm_mon + 1;
is.setstate(err); is.setstate(err);
} }
#endif
else else
read(is, CharT{'%'}, width, modified, *fmt); read(is, CharT{'%'}, width, modified, *fmt);
#endif
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6353,6 +6425,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 'n': case 'n':
case 't': case 't':
if (command) if (command)
{
if (modified == CharT{})
{ {
// %n matches a single white space character // %n matches a single white space character
// %t matches 0 or 1 white space characters // %t matches 0 or 1 white space characters
@@ -6371,6 +6445,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
} }
else if (*fmt == 'n') else if (*fmt == 'n')
is.setstate(ios_base::failbit); is.setstate(ios_base::failbit);
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6382,9 +6459,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
// Error if haven't yet seen %I // Error if haven't yet seen %I
if (command) if (command)
{ {
#if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ {
#if !ONLY_C_LOCALE
if (I == not_a_hour_12_value) if (I == not_a_hour_12_value)
goto broken; goto broken;
tm = std::tm{}; tm = std::tm{};
@@ -6395,9 +6472,6 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
goto broken; goto broken;
h = hours{tm.tm_hour}; h = hours{tm.tm_hour};
I = not_a_hour_12_value; I = not_a_hour_12_value;
}
else
read(is, CharT{'%'}, width, modified, *fmt);
#else #else
if (I == not_a_hour_12_value) if (I == not_a_hour_12_value)
goto broken; goto broken;
@@ -6415,6 +6489,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
h = hours{0}; h = hours{0};
I = not_a_hour_12_value; I = not_a_hour_12_value;
#endif #endif
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6426,6 +6503,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
case 'r': case 'r':
if (command) if (command)
{ {
if (modified == CharT{})
{
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
f.get(is, nullptr, is, err, &tm, command, fmt+1); f.get(is, nullptr, is, err, &tm, command, fmt+1);
@@ -6462,6 +6541,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
min = minutes{M}; min = minutes{M};
s = round<Duration>(duration<long double>{S}); s = round<Duration>(duration<long double>{S});
#endif #endif
}
else
read(is, CharT{'%'}, width, modified, *fmt);
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6497,16 +6579,18 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
using dfs = detail::decimal_format_seconds<Duration>; using dfs = detail::decimal_format_seconds<Duration>;
CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
long double S; long double S;
read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)}); read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)});
if (!is.fail()) if (!is.fail())
s = round<Duration>(duration<long double>{S}); s = round<Duration>(duration<long double>{S});
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
@@ -6515,9 +6599,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
s = duration_cast<Duration>(seconds{tm.tm_sec}); s = duration_cast<Duration>(seconds{tm.tm_sec});
is.setstate(err); is.setstate(err);
} }
#endif
else else
read(is, CharT{'%'}, width, modified, *fmt); read(is, CharT{'%'}, width, modified, *fmt);
#endif
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6558,6 +6642,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'O'})
#endif #endif
read(is, rs{Y, 1, width == -1 ? 4u : static_cast<unsigned>(width)}); read(is, rs{Y, 1, width == -1 ? 4u : static_cast<unsigned>(width)});
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
@@ -6569,9 +6655,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
Y = tm.tm_year + 1900; Y = tm.tm_year + 1900;
is.setstate(err); is.setstate(err);
} }
#endif
else else
read(is, CharT{'%'}, width, modified, *fmt); read(is, CharT{'%'}, width, modified, *fmt);
#endif
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};
@@ -6679,8 +6765,10 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{ {
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
{ #else
if (modified != CharT{'E'})
#endif #endif
{
read(is, ru{wd, 1, width == -1 ? 1u : static_cast<unsigned>(width)}); read(is, ru{wd, 1, width == -1 ? 1u : static_cast<unsigned>(width)});
if (!is.fail() && *fmt == 'u') if (!is.fail() && *fmt == 'u')
{ {
@@ -6689,8 +6777,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
else if (wd == 0) else if (wd == 0)
wd = 7; wd = 7;
} }
#if !ONLY_C_LOCALE
} }
#if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
{ {
ios_base::iostate err = ios_base::goodbit; ios_base::iostate err = ios_base::goodbit;
@@ -6699,9 +6787,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
wd = tm.tm_wday; wd = tm.tm_wday;
is.setstate(err); is.setstate(err);
} }
#endif
else else
read(is, CharT{'%'}, width, modified, *fmt); read(is, CharT{'%'}, width, modified, *fmt);
#endif
command = nullptr; command = nullptr;
width = -1; width = -1;
modified = CharT{}; modified = CharT{};