From 2e8e6a99ee156e8cd15b5e4b9a0eeaa49e2a970b Mon Sep 17 00:00:00 2001 From: Paolo Carlini Date: Thu, 7 Jan 2010 00:22:51 +0000 Subject: re PR libstdc++/26701 (std::time_get parses only 2 digits of year, in en_GB locale.) 2010-01-06 Paolo Carlini PR libstdc++/26701 * include/bits/locale_facets_nonio.tcc (time_get<>::_M_extract_num): Encode short two digits over four parsings to negative numbers. (time_get<>::_M_extract_via_format): Adjust, accept both two digits and four digits for both 'y' and 'Y'. (time_get<>::do_get_year): Call time_get<>::_M_extract_num. * doc/xml/manual/prerequisites.xml: Add en_GB. * testsuite/lib/libstdc++.exp: Adjust * testsuite/22_locale/time_get/get_date/char/26701.cc: New. * testsuite/22_locale/time_get/get_date/wchar_t/26701.cc: Likewise. From-SVN: r155685 --- libstdc++-v3/ChangeLog | 13 +++++ libstdc++-v3/doc/xml/manual/prerequisites.xml | 1 + libstdc++-v3/include/bits/locale_facets_nonio.tcc | 33 +++++------ .../22_locale/time_get/get_date/char/26701.cc | 64 ++++++++++++++++++++++ .../22_locale/time_get/get_date/wchar_t/26701.cc | 64 ++++++++++++++++++++++ libstdc++-v3/testsuite/lib/libstdc++.exp | 1 + 6 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get_date/char/26701.cc create mode 100644 libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/26701.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 02c19c1..cb10263 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,16 @@ +2010-01-06 Paolo Carlini + + PR libstdc++/26701 + * include/bits/locale_facets_nonio.tcc (time_get<>::_M_extract_num): + Encode short two digits over four parsings to negative numbers. + (time_get<>::_M_extract_via_format): Adjust, accept both two digits + and four digits for both 'y' and 'Y'. + (time_get<>::do_get_year): Call time_get<>::_M_extract_num. + * doc/xml/manual/prerequisites.xml: Add en_GB. + * testsuite/lib/libstdc++.exp: Adjust + * testsuite/22_locale/time_get/get_date/char/26701.cc: New. + * testsuite/22_locale/time_get/get_date/wchar_t/26701.cc: Likewise. + 2010-01-06 Benjamin Kosnik PR libstdc++/42491 diff --git a/libstdc++-v3/doc/xml/manual/prerequisites.xml b/libstdc++-v3/doc/xml/manual/prerequisites.xml index 6a55e0c..8391fe4 100644 --- a/libstdc++-v3/doc/xml/manual/prerequisites.xml +++ b/libstdc++-v3/doc/xml/manual/prerequisites.xml @@ -73,6 +73,7 @@ de_DE ISO-8859-1 de_DE@euro ISO-8859-15 +en_GB ISO-8859-1 en_HK ISO-8859-1 en_PH ISO-8859-1 en_US ISO-8859-1 diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.tcc b/libstdc++-v3/include/bits/locale_facets_nonio.tcc index 73cd747..e788457 100644 --- a/libstdc++-v3/include/bits/locale_facets_nonio.tcc +++ b/libstdc++-v3/include/bits/locale_facets_nonio.tcc @@ -778,16 +778,16 @@ _GLIBCXX_END_LDBL_NAMESPACE break; case 'y': case 'C': // C99 - // Two digit year. [tm_year] - __beg = _M_extract_num(__beg, __end, __tm->tm_year, 0, 99, 2, - __io, __tmperr); - break; + // Two digit year. case 'Y': - // Year [1900). [tm_year] + // Year [1900). + // NB: We parse either two digits, implicitly years since + // 1900, or 4 digits, full year. In both cases we can + // reconstruct [tm_year]. See also libstdc++/26701. __beg = _M_extract_num(__beg, __end, __mem, 0, 9999, 4, __io, __tmperr); if (!__tmperr) - __tm->tm_year = __mem - 1900; + __tm->tm_year = __mem < 0 ? __mem + 100 : __mem - 1900; break; case 'Z': // Timezone info. @@ -865,6 +865,9 @@ _GLIBCXX_END_LDBL_NAMESPACE } if (__i == __len) __member = __value; + // Special encoding for do_get_year, 'y', and 'Y' above. + else if (__len == 4 && __i == 2) + __member = __value - 100; else __err |= ios_base::failbit; @@ -1116,19 +1119,13 @@ _GLIBCXX_END_LDBL_NAMESPACE { const locale& __loc = __io._M_getloc(); const ctype<_CharT>& __ctype = use_facet >(__loc); + int __tmpyear; + ios_base::iostate __tmperr = ios_base::goodbit; - size_t __i = 0; - int __value = 0; - for (; __beg != __end && __i < 4; ++__beg, ++__i) - { - const char __c = __ctype.narrow(*__beg, '*'); - if (__c >= '0' && __c <= '9') - __value = __value * 10 + (__c - '0'); - else - break; - } - if (__i == 2 || __i == 4) - __tm->tm_year = __i == 2 ? __value : __value - 1900; + __beg = _M_extract_num(__beg, __end, __tmpyear, 0, 9999, 4, + __io, __tmperr); + if (!__tmperr) + __tm->tm_year = __tmpyear < 0 ? __tmpyear + 100 : __tmpyear - 1900; else __err |= ios_base::failbit; diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_date/char/26701.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_date/char/26701.cc new file mode 100644 index 0000000..b02fefe --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_date/char/26701.cc @@ -0,0 +1,64 @@ +// { dg-require-namedlocale "" } + +// 2010-01-06 Paolo Carlini + +// Copyright (C) 2010 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 22.2.5.1.1 time_get members + +#include +#include +#include + +// libstdc++/26701 +void test01() +{ + using namespace std; + bool test __attribute__((unused)) = true; + + typedef istreambuf_iterator iterator_type; + + locale loc_en = locale("en_GB"); + + tm tm0 = __gnu_test::test_tm(0, 0, 0, 0, 0, 0, 0, 0, 0); + + iterator_type end; + + istringstream iss; + iss.imbue(loc_en); + const time_get& tg = use_facet >(iss.getloc()); + + const ios_base::iostate good = ios_base::goodbit; + ios_base::iostate errorstate = good; + + iss.str("01/02/2003"); + iterator_type is_it0(iss); + + errorstate = good; + tg.get_date(is_it0, end, iss, errorstate, &tm0); + VERIFY( errorstate == ios_base::eofbit ); + VERIFY( tm0.tm_year + 1900 == 2003 ); + VERIFY( tm0.tm_mon + 1 == 2 ); + VERIFY( tm0.tm_mday == 1 ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/26701.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/26701.cc new file mode 100644 index 0000000..2f4980a --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/26701.cc @@ -0,0 +1,64 @@ +// { dg-require-namedlocale "" } + +// 2010-01-06 Paolo Carlini + +// Copyright (C) 2010 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// 22.2.5.1.1 time_get members + +#include +#include +#include + +// libstdc++/26701 +void test01() +{ + using namespace std; + bool test __attribute__((unused)) = true; + + typedef istreambuf_iterator iterator_type; + + locale loc_en = locale("en_GB"); + + tm tm0 = __gnu_test::test_tm(0, 0, 0, 0, 0, 0, 0, 0, 0); + + iterator_type end; + + wistringstream iss; + iss.imbue(loc_en); + const time_get& tg = use_facet >(iss.getloc()); + + const ios_base::iostate good = ios_base::goodbit; + ios_base::iostate errorstate = good; + + iss.str(L"01/02/2003"); + iterator_type is_it0(iss); + + errorstate = good; + tg.get_date(is_it0, end, iss, errorstate, &tm0); + VERIFY( errorstate == ios_base::eofbit ); + VERIFY( tm0.tm_year + 1900 == 2003 ); + VERIFY( tm0.tm_mon + 1 == 2 ); + VERIFY( tm0.tm_mday == 1 ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp index 09cae6d..45a43de 100644 --- a/libstdc++-v3/testsuite/lib/libstdc++.exp +++ b/libstdc++-v3/testsuite/lib/libstdc++.exp @@ -869,6 +869,7 @@ proc check_v3_target_namedlocale { } { puts $f " locale(\"de_DE\");" puts $f " locale(\"de_DE.ISO-8859-15@euro\");" puts $f " locale(\"de_DE@euro\");" + puts $f " locale(\"en_GB\");" puts $f " locale(\"en_HK\");" puts $f " locale(\"en_PH\");" puts $f " locale(\"en_US\");" -- cgit v1.1