blob: 41b637deb4f47b80ef1a15b446158b1f25776945 [file] [log] [blame]
/***************************************************************************
*
* 22.locale.time.get.cpp - tests exercising the std::time_get facet
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 2001-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include <locale>
#include <sstream> // for stringstream
#include <climits> // for INT_{MIN,MAX}
#include <clocale> // for LC_ALL
#include <cstdio> // for fprintf()
#include <cstdlib> // for getenv()
#include <cstring> // for memcmp(), strlen()
#include <ctime> // for struct tm
#include <rw_driver.h> // for rw_test()
#include <rw_file.h> // for rw_nextfd()
#include <rw_locale.h> // for rw_locale_query()
#include <rw_printf.h> // for rw_snprintf()
/**************************************************************************/
template <class charT>
void do_test (int lineno, charT, const char *cname,
std::tm val, const char *pat, int consumed,
const char *fmt, int flags, int err_expect = -1)
{
std::basic_ostringstream<charT> ostrm;
typedef std::istreambuf_iterator<charT> InIter;
typedef std::ostreambuf_iterator<charT> OutIter;
const std::time_get<charT, InIter> &tg =
std::use_facet<std::time_get<charT, InIter> >(ostrm.getloc ());
const std::time_put<charT, OutIter> &tp =
std::use_facet<std::time_put<charT, OutIter> >(ostrm.getloc ());
ostrm.flags (std::ios_base::fmtflags (flags));
charT wpatbuf [256];
for (std::size_t j = 0; !!(wpatbuf [j] = pat [j]); ++j);
const charT *wpat = wpatbuf;
const charT *wpatend = wpat + std::char_traits<charT>::length (wpat);
// format string
OutIter it (ostrm);
tp.put (it, ostrm, charT (' '), &val, wpat, wpatend);
// working around dumb compilers such as MSVC 6.0 that
// do not zero initialize POD structs when using tm()
static std::tm zero_tm;
std::tm x = zero_tm;
std::basic_istringstream<charT> istrm (ostrm.str ());
istrm.flags (std::ios_base::fmtflags (flags));
std::ios_base::iostate err = std::ios_base::goodbit;
const char *fname = 0;
InIter ibeg = InIter (istrm);
InIter iend;
_TRY {
if ( '\0' == fmt [1]
|| ('E' == fmt [0] || 'O' == fmt [0] && '\0' == fmt [2])) {
// single-character format strings "a", "b", "x", "X", and "Y"
// exercise the standard time_get interface, i.e., get_weekday(),
// get_monthname(), and get_year()
// other single or two character format strings, e.g., "Ec" or "Ex"
// exercise the single character extension (format specifier and
// an optional modifier)
switch (*fmt) {
case 'a':
fname = "get_weekday";
iend = tg.get_weekday (ibeg, iend, istrm, err, &x);
break;
case 'b':
fname = "get_monthname";
iend = tg.get_monthname (ibeg, iend, istrm, err, &x);
break;
case 'x':
fname = "get_date";
iend = tg.get_date (ibeg, iend, istrm, err, &x);
break;
case 'X':
fname = "get_time";
iend = tg.get_time (ibeg, iend, istrm, err, &x);
break;
case 'Y':
fname = "get_year";
iend = tg.get_year (ibeg, iend, istrm, err, &x);
break;
default:
fname = "get";
if ('E' == fmt [0] || 'O' == fmt [0])
iend = tg.get (ibeg, iend, istrm, err, &x,
fmt [1], fmt [0]);
else
iend = tg.get (ibeg, iend, istrm, err, &x, *fmt);
break;
}
}
else {
// multi-character format strings exercise the pattern
// extensions to time_get, ala strptime()
charT fmtstr [256];
charT *end;
const char *pfmt = fmt;
for (end = fmtstr; *pfmt; *end++ = *pfmt++);
fname = "get";
iend = tg.get (ibeg, iend, istrm, err, &x, fmtstr, end);
}
}
_CATCH (...) {
rw_error (0, 0, lineno,
"line %d. time_get<%s>::%s (%{*Ac}, ..., \"%s\") "
"unexpectedly threw an exception",
__LINE__, cname, fname,
int (sizeof (charT)), ostrm.str ().data (), fmt);
return;
}
int extracted = -1 == consumed ? -1
: int (istrm.rdbuf ()->pubseekoff (0, std::ios::cur, std::ios::in));
if (extracted == -1)
consumed = -1;
int success =
extracted == consumed && (-1 == err_expect || err == err_expect);
rw_assert (success, __FILE__, lineno,
"line %d. time_get<%s>::%s (%{*Ac}, ..., \"%s\") "
"ate %d, expected %d, rdstate() == %{Is}, got %{Is}",
__LINE__, cname, fname,
int (sizeof (charT)), ostrm.str ().data (), fmt,
extracted, consumed, err_expect, err);
success = 0 == std::memcmp (&x, &val, sizeof x);
rw_assert (success, __FILE__, lineno,
"line %d. time_get<%s>::%s (%{*Ac}, ..., \"%s\") got %{t}, "
"expected %{t}, flags = %{If}, locale (%s)",
__LINE__, cname, fname,
int (sizeof (charT)), ostrm.str ().data (), fmt, &x,
&val, flags, std::locale ().name ().data ());
}
/**************************************************************************/
std::tm mktm (int sec = 0, int min = 0, int hour = 0,
int mday = 0, int mon = 0, int year = 0,
int wday = 0, int yday = 0, int isdst = 0)
{
std::tm tmp = std::tm ();
if (sec < 0) {
// get the current local time
std::time_t t = std::time (0);
std::tm *ptm = std::localtime (&t);
return ptm ? *ptm : tmp;
}
// use arguments to initialize struct
tmp.tm_sec = sec; // seconds after the minute [0, 60]
tmp.tm_min = min; // minutes after the hour [0, 59]
tmp.tm_hour = hour; // hours since midnight [0, 23]
tmp.tm_mday = mday; // day of the month [1, 31]
tmp.tm_mon = mon; // months since January [0, 11]
tmp.tm_year = year; // years since 1900
tmp.tm_wday = wday; // days since Sunday [0, 6]
tmp.tm_yday = yday; // days since January 1 [0, 365]
tmp.tm_isdst = isdst; // Daylight Saving Time flag
return tmp;
}
// for convenience
#define Boolalpha std::ios_base::boolalpha
#define Dec std::ios_base::dec
#define Fixed std::ios_base::fixed
#define Hex std::ios_base::hex
#define Internal std::ios_base::internal
#define Left std::ios_base::left
#define Oct std::ios_base::oct
#define Right std::ios_base::right
#define Scientific std::ios_base::scientific
#define Showbase std::ios_base::showbase
#define Showpoint std::ios_base::showpoint
#define Showpos std::ios_base::showpos
#define Skipws std::ios_base::skipws
#define Unitbuf std::ios_base::unitbuf
#define Uppercase std::ios_base::uppercase
#define Bin std::ios_base::bin
#define Adjustfield std::ios_base::adjustfield
#define Basefield std::ios_base::basefield
#define Floatfield std::ios_base::floatfield
#define Nolock std::ios_base::nolock
#define Nolockbuf std::ios_base::nolockbuf
// capitalize to prevent EDG eccp from expanding the macros
// in .cc files when implicit inclusion is used (causes errors
// in constructs such as traits_type::eof ())
#define Bad std::ios_base::badbit
#define Eof std::ios_base::eofbit
#define Fail std::ios_base::failbit
#define Good std::ios_base::goodbit
#define T __LINE__, charT (), cname, mktm
#define TEST do_test
#define FUNCTION(fun) \
rw_info (0, 0, __LINE__, \
"std::time_get<%s>::%s() in locale (\"%s\")", \
cname, fun, std::locale ().name ().c_str ())
#define STEP(desc) rw_info (0, 0, __LINE__, "%s", desc)
template <class charT>
void test_posix (charT, const char *cname)
{
// set the global locale object
std::locale::global (std::locale ("C"));
// exercise abbreviated weekday names (time_get::get_weekday())
FUNCTION ("get_weekday");
TEST (T (0, 0, 0, 0, 0, 0, 0), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 6), "%a", -1, "a", 0, Eof);
// comparison is case insensitive
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sun", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0), "SUN", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0), "sun", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Mon", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Tue", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Wed", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Thu", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Fri", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Sat", 3, "a", 0, Eof);
// abbreviation followed by a letter other than the one
// that follows in a full name is acepted
TEST (T (0, 0, 0, 0, 0, 0, 0), "suna", 3, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 1), "monb", 3, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "tuec", 3, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 3), "wedd", 3, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 4), "thue", 3, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 5), "frif", 3, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 6), "satg", 3, "a", 0, Good);
// exercise failure on invalid input including incomplete
// full names (other than valid cases exercised above)
TEST (T (0, 0, 0, 0, 0, 0, 0), " Sun", 0, "a", 0, Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0), "Mond", 4, "a", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0), "Tuesd", 5, "a", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0), "Wednesd", 7, "a", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0), "Thursda.", 7, "a", 0, Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0), "Fridax", 5, "a", 0, Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0), "6Saturday", 0, "a", 0, Fail);
// exercise full weekday names
TEST (T (0, 0, 0, 0, 0, 0, 0), "%A", -1, "a", 0, -1);
TEST (T (0, 0, 0, 0, 0, 0, 1), "%A", -1, "a", 0, -1);
TEST (T (0, 0, 0, 0, 0, 0, 2), "%A", -1, "a", 0, -1);
TEST (T (0, 0, 0, 0, 0, 0, 3), "%A", -1, "a", 0, -1);
TEST (T (0, 0, 0, 0, 0, 0, 4), "%A", -1, "a", 0, -1);
TEST (T (0, 0, 0, 0, 0, 0, 5), "%A", -1, "a", 0, -1);
TEST (T (0, 0, 0, 0, 0, 0, 6), "%A", -1, "a", 0, -1);
// comparison is case insensitive
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sunday", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 0), "SUNDAY", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 0), "sunday", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Monday", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Tuesday", 7, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Wednesday", 9, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Thursday", 8, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Friday", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Saturday", 8, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sunday ", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Monday 0", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Tuesdayy", 7, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Wednesday.", 9, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Thursday,", 8, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Friday/", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Saturday:", 8, "a", 0, Good);
// exercise abbreviated month names (time_get::get_monthname())
FUNCTION ("get_monthname");
TEST (T (0, 0, 0, 0, 0), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 1), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 2), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 3), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 4), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 5), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 6), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 7), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 8), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 9), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 10), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 11), "%b", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 0), "Jan", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 1), "Feb", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 2), "Mar", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 3), "Apr", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 4), "May", 3, "b", 0, Good);
TEST (T (0, 0, 0, 0, 5), "Jun", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 6), "Jul", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 7), "Aug", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 8), "Sep", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 9), "Oct", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 10), "Nov", 3, "b", 0, Eof);
TEST (T (0, 0, 0, 0, 11), "Dec", 3, "b", 0, Eof);
// exercise invalid abbreviated month names
TEST (T (0, 0, 0, 0, 0), "J", 1, "b", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0), "J ", 1, "b", 0, Fail);
TEST (T (0, 0, 0, 0, 0), "Ja", 2, "b", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0), "Ju", 2, "b", 0, Eof | Fail);
// exercise full month names
TEST (T (0, 0, 0, 0, 0), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 1), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 2), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 3), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 4), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 5), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 6), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 7), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 8), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 9), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 10), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 11), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 0), "January", 7, "b", 0, Good);
TEST (T (0, 0, 0, 0, 0), "January ", 7, "b", 0, Good);
TEST (T (0, 0, 0, 0, 1), "February", 8, "b", 0, Good);
TEST (T (0, 0, 0, 0, 2), "March", 5, "b", 0, Good);
TEST (T (0, 0, 0, 0, 2), "Marchh", 5, "b", 0, Good);
TEST (T (0, 0, 0, 0, 3), "April", 5, "b", 0, Good);
TEST (T (0, 0, 0, 0, 4), "May", 3, "b", 0, Good);
TEST (T (0, 0, 0, 0, 5), "June", 4, "b", 0, Good);
TEST (T (0, 0, 0, 0, 6), "July", 4, "b", 0, Good);
TEST (T (0, 0, 0, 0, 6), "Jull", 3, "b", 0, Good);
TEST (T (0, 0, 0, 0, 7), "August", 6, "b", 0, Good);
TEST (T (0, 0, 0, 0, 8), "September", 9, "b", 0, Good);
TEST (T (0, 0, 0, 0, 9), "October", 7, "b", 0, Good);
TEST (T (0, 0, 0, 0, 10), "November", 8, "b", 0, Good);
TEST (T (0, 0, 0, 0, 11), "December", 8, "b", 0, Good);
// exercise invalid full month names
TEST (T (0, 0, 0, 0, 0), "Januar", 6, "b", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0), "Februar", 7, "b", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0), " March", 0, "b", 0, Fail);
TEST (T (0, 0, 0, 0, 0), "apri/", 4, "b", 0, Fail);
TEST (T (0, 0, 0, 0, 0), "/MAY", 0, "b", 0, Fail);
TEST (T (0, 0, 0, 0, 0), ":Jun", 0, "b", 0, Fail);
TEST (T (0, 0, 0, 0, 0), "Ju ", 2, "b", 0, Fail);
// exercise date (time_get::get_date())
FUNCTION ("get_date");
TEST (T (0, 0, 0, 1, 0, 100), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 2, 1, 111), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 3, 2, 122), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 4, 3, 133), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 5, 4, 144), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 6, 5, 155), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 7, 6, 166), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 8, 7, 168), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 9, 8, 69), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 10, 9, 99), "%x", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 11, 5, 155), "06/11/55", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 12, 6, 167), "07/12/67", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 23, 7, 78), "08/23/78", 8, "x", 0, Eof);
TEST (T (0, 0, 0, 31, 11, 89), "12/31/89", 8, "x", 0, Eof);
// exercise time (time_get::get_time())
FUNCTION ("get_time");
TEST (T ( 0, 0, 0), "%X", 8, "X", 0, Eof);
TEST (T ( 1, 59, 11), "%X", 8, "X", 0, Eof);
TEST (T (12, 48, 10), "%X", 8, "X", 0, Eof);
TEST (T (23, 37, 9), "%X", 8, "X", 0, Eof);
TEST (T (34, 26, 8), "%X", 8, "X", 0, Eof);
TEST (T (45, 15, 7), "%X", 8, "X", 0, Eof);
TEST (T (56, 4, 6), "%X", 8, "X", 0, Eof);
TEST (T ( 0, 0, 0), "00:00:00", 8, "X", 0, Eof);
TEST (T (60, 9, 23), "23:09:60", 8, "X", 0, Eof);
TEST (T (59, 18, 22), "22:18:59", 8, "X", 0, Eof);
TEST (T (58, 27, 21), "21:27:58", 8, "X", 0, Eof);
TEST (T (57, 36, 20), "20:36:57", 8, "X", 0, Eof);
TEST (T (56, 45, 19), "19:45:56", 8, "X", 0, Eof);
TEST (T (55, 54, 18), "18:54:55", 8, "X", 0, Eof);
// exercise year (time_get::get_year())
FUNCTION ("get_year");
TEST (T (0, 0, 0, 0, 0, -1900), "0", 1, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1900), "00", 2, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1899), "001", 3, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -124), "1776", 4, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0), "1900", 4, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 1), "1901", 4, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 99), "1999", 4, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 102), "2002", 4, "Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 98099), "99999", 5, "Y", 0, Eof);
FUNCTION ("get");
// exercise extensions implementing complete IEEE Std 1003.1-2001 support
// http://www.opengroup.org/onlinepubs/007904975/functions/strptime.html
// capital format specifier (other than "X") implies the
// testing of std::time_get<>::get (..., char, char)
// %a The day of the week, using the locale's weekday names;
// either the abbreviated or full name may be specified.
// %A Equivalent to %a.
STEP ("%a, %A: the day of the week");
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sun", 3, "A", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Mon", 3, "A", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Tue", 3, "A", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Wed", 3, "A", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Thu", 3, "A", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Fri", 3, "A", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Sat", 3, "A", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sunday", 6, "A", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Monday", 6, "A", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Tuesday", 7, "A", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Wednesday", 9, "A", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Thursday", 8, "A", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Friday", 6, "A", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Saturday", 8, "A", 0, Good);
// %b The month, using the locale's month names;
// either the abbreviated or full name may be specified.
// %B Equivalent to %b.
STEP ("%b, %B: the month");
TEST (T (0, 0, 0, 0, 0), "January", 7, "B", 0, Good);
TEST (T (0, 0, 0, 0, 1), "February", 8, "B", 0, Good);
TEST (T (0, 0, 0, 0, 2), "March", 5, "B", 0, Good);
TEST (T (0, 0, 0, 0, 3), "April", 5, "B", 0, Good);
TEST (T (0, 0, 0, 0, 4), "May", 3, "B", 0, Good);
TEST (T (0, 0, 0, 0, 5), "June", 4, "B", 0, Good);
TEST (T (0, 0, 0, 0, 6), "July", 4, "B", 0, Good);
TEST (T (0, 0, 0, 0, 7), "August", 6, "B", 0, Good);
TEST (T (0, 0, 0, 0, 8), "September", 9, "B", 0, Good);
TEST (T (0, 0, 0, 0, 9), "October", 7, "B", 0, Good);
TEST (T (0, 0, 0, 0, 10), "November", 8, "B", 0, Good);
TEST (T (0, 0, 0, 0, 11), "December", 8, "B", 0, Good);
// %c Replaced by the locale's appropriate date and time representation.
STEP ("%c: date and time representation");
rw_warn (0, 0, __LINE__, "%%c not being exercised");
// %C: The century number [00,99]; leading zeros are permitted
// but not required.
STEP ("%C: the century number");
TEST (T (0, 0, 0, 0, 0, -1900), "0", 1, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1800), "1", 1, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1700), "2", 1, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1600), "3", 1, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1500), "04", 2, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0), "19", 2, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 100), "20", 2, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 200), "21", 2, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 1300), "32", 2, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 8000), "99", 2, "C", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0), "100", 3, "C", 0, Eof | Fail);
// %d The day of the month [01,31]; leading zeros are permitted but not
// required.
STEP ("%d: day of the month");
TEST (T (0, 0, 0, 1), "1", 1, "d", 0, Eof);
TEST (T (0, 0, 0, 2), "02", 2, "d", 0, Eof);
TEST (T (0, 0, 0, 28), "28", 2, "d", 0, Eof);
TEST (T (0, 0, 0, 29), "29", 2, "d", 0, Eof);
TEST (T (0, 0, 0, 30), "030", 3, "d", 0, Eof);
TEST (T (0, 0, 0, 31), "0031", 4, "d", 0, Eof);
TEST (T (0, 0, 0, 0), "0", 1, "d", 0, Eof | Fail);
// leading whitespace not allowed
TEST (T (0, 0, 0, 0), " 3", 0, "d", 0, Fail);
TEST (T (0, 0, 0, 0), "32", 2, "d", 0, Eof | Fail);
// %D The date as %m/%d/%y.
STEP ("%D: the date as %m/%d/%y");
TEST (T (0, 0, 0, 14, 3, 102), "4/14/2", 6, "D", 0, Eof);
TEST (T (0, 0, 0, 14, 3, 102), "04/14/02", 8, "D", 0, Eof);
TEST (T (0, 0, 0, 14, 3, 102), "04/14/002", 9, "D", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0), "0/1/2002", 1, "D", 0, Fail);
TEST (T (0, 0, 0, 0, 0, 0), "4/0/2002", 3, "D", 0, Fail);
TEST (T (0, 0, 0, 0, 0, 0), "4/32/2002", 4, "D", 0, Fail);
// %e Equivalent to %d; leading zeros are permitted but not required.
STEP ("%e: equivalent to %d");
TEST (T (0, 0, 0, 1), "01", 2, "e", 0, Eof);
TEST (T (0, 0, 0, 9), "9", 1, "e", 0, Eof);
TEST (T (0, 0, 0, 31), "31", 2, "e", 0, Eof);
TEST (T (0, 0, 0, 0), "0", 1, "e", 0, Eof | Fail);
// leading whitespace not allowed
TEST (T (0, 0, 0, 0), " 2", 0, "e", 0, Fail);
TEST (T (0, 0, 0, 0), "99", 2, "e", 0, Eof | Fail);
// %h Equivalent to %b.
STEP ("%h: equivalent to %b");
TEST (T (0, 0, 0, 0, 0), "Jan", 3, "h", 0, Eof);
TEST (T (0, 0, 0, 0, 1), "February", 8, "h", 0, Good);
TEST (T (0, 0, 0, 0, 2), "Mar", 3, "h", 0, Eof);
TEST (T (0, 0, 0, 0, 3), "April", 5, "h", 0, Good);
TEST (T (0, 0, 0, 0, 4), "May", 3, "h", 0, Good);
TEST (T (0, 0, 0, 0, 5), "June", 4, "h", 0, Good);
TEST (T (0, 0, 0, 0, 6), "Jul", 3, "h", 0, Eof);
TEST (T (0, 0, 0, 0, 7), "August", 6, "h", 0, Good);
TEST (T (0, 0, 0, 0, 8), "Sep", 3, "h", 0, Eof);
TEST (T (0, 0, 0, 0, 9), "October", 7, "h", 0, Good);
TEST (T (0, 0, 0, 0, 10), "Nov", 3, "h", 0, Eof);
TEST (T (0, 0, 0, 0, 11), "December", 8, "h", 0, Good);
// %H The hour (24-hour clock) [00,23]; leading zeros are permitted
// but not required.
STEP ("%H: the hour (24-hour clock)");
TEST (T (0, 0, 0), "0", 1, "H", 0, Eof);
TEST (T (0, 0, 0), "00", 2, "H", 0, Eof);
TEST (T (0, 0, 0), "000", 3, "H", 0, Eof);
TEST (T (0, 0, 1), "1", 1, "H", 0, Eof);
TEST (T (0, 0, 2), "2", 1, "H", 0, Eof);
TEST (T (0, 0, 3), "3", 1, "H", 0, Eof);
TEST (T (0, 0, 11), "11", 2, "H", 0, Eof);
TEST (T (0, 0, 12), "12", 2, "H", 0, Eof);
TEST (T (0, 0, 13), "13", 2, "H", 0, Eof);
TEST (T (0, 0, 23), "23", 2, "H", 0, Eof);
TEST (T (0, 0, 23), "023", 3, "H", 0, Eof);
TEST (T (0, 0, 0), "024", 3, "H", 0, Eof | Fail);
TEST (T (0, 0, 0), "987", 3, "H", 0, Eof | Fail);
// %I The hour (12-hour clock) [01,12]; leading zeros are permitted
// but not required.
STEP ("%I: the hour (12-hour clock)");
TEST (T (0, 0, 0), "1", 1, "I", 0, Eof);
TEST (T (0, 0, 1), "2", 1, "I", 0, Eof);
TEST (T (0, 0, 2), "3", 1, "I", 0, Eof);
TEST (T (0, 0, 3), "4", 1, "I", 0, Eof);
TEST (T (0, 0, 4), "5", 1, "I", 0, Eof);
TEST (T (0, 0, 5), "6", 1, "I", 0, Eof);
TEST (T (0, 0, 6), "7", 1, "I", 0, Eof);
TEST (T (0, 0, 7), "8", 1, "I", 0, Eof);
TEST (T (0, 0, 8), "9", 1, "I", 0, Eof);
TEST (T (0, 0, 9), "10", 2, "I", 0, Eof);
TEST (T (0, 0, 10), "11", 2, "I", 0, Eof);
TEST (T (0, 0, 11), "12", 2, "I", 0, Eof);
TEST (T (0, 0, 0), "13", 2, "I", 0, Eof | Fail);
TEST (T (0, 0, 0), "013", 3, "I", 0, Eof | Fail);
TEST (T (0, 0, 0), "123", 3, "I", 0, Eof | Fail);
TEST (T (0, 0, 0), "0", 1, "I", 0, Eof | Fail);
// %j The day number of the year [001,366]; leading zeros are permitted
// but not required.
TEST (T (0, 0, 0, 0, 0, 0, 0, 0), "1", 1, "j", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0, 1), "2", 1, "j", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0, 2), "03", 2, "j", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0, 9), "10", 2, "j", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0, 364), "365", 3, "j", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0, 365), "366", 3, "j", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0, 0), "0", 1, "j", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0, 0), "367", 3, "j", 0, Eof | Fail);
#ifdef __GLIBC__
STEP ("%k: equivalent to %H (GNU glibc extension)");
TEST (T (0, 0, 0), "0", 1, "k", 0, Eof);
TEST (T (0, 0, 1), "1", 1, "k", 0, Eof);
TEST (T (0, 0, 9), "9", 1, "k", 0, Eof);
TEST (T (0, 0, 10), "10", 2, "k", 0, Eof);
TEST (T (0, 0, 11), "11", 2, "k", 0, Eof);
TEST (T (0, 0, 12), "12", 2, "k", 0, Eof);
TEST (T (0, 0, 13), "13", 2, "k", 0, Eof);
TEST (T (0, 0, 23), "23", 2, "k", 0, Eof);
TEST (T (0, 0, 23), "023", 3, "k", 0, Eof);
TEST (T (0, 0, 0), "024", 3, "k", 0, Eof | Fail);
TEST (T (0, 0, 0), "987", 3, "k", 0, Eof | Fail);
#endif // __GLIBC__
// %m The month number [01,12]; leading zeros are permitted
// but not required.
STEP ("%m: the month number");
TEST (T (0, 0, 0, 0, 0, 0), "1", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 1, 0), "2", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 2, 0), "3", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 3, 0), "4", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 4, 0), "5", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 5, 0), "6", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 6, 0), "7", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 7, 0), "8", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 8, 0), "9", 1, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 9, 0), "10", 2, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 10, 0), "11", 2, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 11, 0), "12", 2, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0), "01", 2, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 1, 0), "02", 2, "m", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0), "0", 1, "m", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0, 0), "13", 2, "m", 0, Eof | Fail);
// %M The minute [00,59]; leading zeros are permitted but not required.
STEP ("%M: the minute");
TEST (T (0, 0), "0", 1, "M", 0, Eof);
TEST (T (0, 0), "00", 2, "M", 0, Eof);
TEST (T (0, 0), "000", 3, "M", 0, Eof);
TEST (T (0, 1), "1", 1, "M", 0, Eof);
TEST (T (0, 2), "2", 1, "M", 0, Eof);
TEST (T (0, 19), "19", 2, "M", 0, Eof);
TEST (T (0, 29), "29", 2, "M", 0, Eof);
TEST (T (0, 59), "59", 2, "M", 0, Eof);
TEST (T (0, 0), "60", 2, "M", 0, Eof | Fail);
// %n Any white space.
STEP ("%n: any whitespace");
TEST (T (), "", 0, "n", 0, Eof);
TEST (T (), " ", 1, "n", 0, Eof);
TEST (T (), " ", 2, "n", 0, Eof);
TEST (T (), " ", 3, "n", 0, Eof);
TEST (T (), "\n ", 2, "n", 0, Eof);
TEST (T (), " \t", 2, "n", 0, Eof);
TEST (T (), "\n\t", 2, "n", 0, Eof);
TEST (T (), ".", 0, "n", 0, Good);
TEST (T (), " 1", 1, "n", 0, Good);
TEST (T (), "\t 2", 2, "n", 0, Good);
// %p The locale's equivalent of a.m or p.m.
STEP ("%p: the equivalent of AM/PM");
TEST (T (0, 0, 1), "AM", 2, "p", 0, Good);
TEST (T (0, 0, 13), "PM", 2, "p", 0, Good);
TEST (T (0, 0, 0), "", 0, "p", 0, Eof | Fail);
TEST (T (0, 0, 0), "A", 1, "p", 0, Eof | Fail);
TEST (T (0, 0, 0), "P", 1, "p", 0, Eof | Fail);
TEST (T (0, 0, 0), "M", 0, "p", 0, Fail);
TEST (T (0, 0, 0), "A ", 1, "p", 0, Fail);
TEST (T (0, 0, 0), "P ", 1, "p", 0, Fail);
// %r 12-hour clock time using the AM/PM notation if t_fmt_ampm is
// not an empty string in the LC_TIME portion of the current locale;
// in the POSIX locale, this shall be equivalent to %I:%M:%S %p.
STEP ("%r: 12-hour clock time using the AM/PM notation");
rw_warn (0, 0, __LINE__, "%%r not being exercised");
// %R The time as %H:%M.
STEP ("%R: the time as %H:%M");
TEST (T (0, 0, 0), "0:0", 3, "R", 0, Eof);
TEST (T (0, 1, 0), "0:1", 3, "R", 0, Eof);
TEST (T (0, 2, 0), "0:02", 4, "R", 0, Eof);
TEST (T (0, 59, 0), "0:59", 4, "R", 0, Eof);
TEST (T (0, 48, 1), "1:48", 4, "R", 0, Eof);
TEST (T (0, 37, 11), "11:37", 5, "R", 0, Eof);
TEST (T (0, 26, 19), "19:26", 5, "R", 0, Eof);
TEST (T (0, 15, 22), "22:15", 5, "R", 0, Eof);
TEST (T (0, 4, 23), "23:04", 5, "R", 0, Eof);
TEST (T (0, 3, 23), "23:03:00", 5, "R", 0, Good);
TEST (T (0, 2, 23), "23:2:01", 4, "R", 0, Good);
TEST (T (0, 0, 0), "23:60", 5, "R", 0, Eof | Fail);
TEST (T (0, 0, 0), "24:00", 2, "R", 0, Fail);
// %S The seconds [00,60]; leading zeros are permitted but not required.
STEP ("%S: the seconds");
TEST (T ( 0), "0", 1, "S", 0, Eof);
TEST (T ( 1), "01", 2, "S", 0, Eof);
TEST (T ( 2), "002", 3, "S", 0, Eof);
TEST (T (13), "13", 2, "S", 0, Eof);
TEST (T (24), "24", 2, "S", 0, Eof);
TEST (T (34), "34", 2, "S", 0, Eof);
TEST (T (45), "45", 2, "S", 0, Eof);
TEST (T (56), "56", 2, "S", 0, Eof);
TEST (T (60), "60", 2, "S", 0, Eof);
TEST (T ( 0), "61", 2, "S", 0, Eof | Fail);
// %t Any white space.
STEP ("%t: any whitespace");
TEST (T (), "\t", 1, "t", 0, Eof);
TEST (T (), " ", 1, "t", 0, Eof);
TEST (T (), " ", 2, "t", 0, Eof);
TEST (T (), "\n ", 2, "t", 0, Eof);
// %T The time as %H:%M:%S.
STEP ("%T: the time as %H:%M:%S");
TEST (T ( 0, 0, 0), "0:0:00", 6, "T", 0, Eof);
TEST (T ( 1, 1, 0), "0:1:1", 5, "T", 0, Eof);
TEST (T ( 2, 2, 0), "0:02:2", 6, "T", 0, Eof);
TEST (T ( 3, 59, 0), "0:59:3", 6, "T", 0, Eof);
TEST (T ( 4, 48, 1), "1:48:04", 7, "T", 0, Eof);
TEST (T ( 5, 37, 11), "11:37:5", 7, "T", 0, Eof);
TEST (T ( 6, 26, 19), "19:26:006", 9, "T", 0, Eof);
TEST (T ( 7, 15, 22), "22:015:7", 8, "T", 0, Eof);
TEST (T ( 8, 4, 23), "023:004:8", 9, "T", 0, Eof);
TEST (T (60, 59, 23), "023:59:60", 9, "T", 0, Eof);
TEST (T ( 0, 0, 0), "23:59:61", 8, "T", 0, Eof | Fail);
TEST (T ( 0, 0, 0), "0:0:62", 6, "T", 0, Eof | Fail);
TEST (T ( 0, 0, 0), "0:0", 3, "T", 0, Eof | Fail);
TEST (T ( 0, 0, 0), "999", 3, "T", 0, Eof | Fail);
// %U The week number of the year (Sunday as the first day of the week)
// as a decimal number [00,53]; leading zeros are permitted but not
// required.
STEP ("%U: the Sunday-based week of the year");
rw_warn (0, 0, __LINE__, "%%U not being exercised");
// %w The weekday as a decimal number [0,6], with 0 representing
// Sunday; leading zeros are permitted but not required.
STEP ("%w: the Sunday-based weekday as a decimal number");
TEST (T (0, 0, 0, 0, 0, 0, 0), "0", 1, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0), "00", 2, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "1", 1, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "01", 2, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "2", 1, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "3", 1, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "4", 1, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "5", 1, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 6), "6", 1, "w", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 0), "7", 1, "w", 0, Eof | Fail);
// %W The week number of the year (Monday as the first day of the
// week) as a decimal number [00,53]; leading zeros are permitted
// but not required.
STEP ("%W: the Monday-based week of the year");
rw_warn (0, 0, __LINE__, "%%W not being exercised");
// %x The date, using the locale's date format.
STEP ("%x: the date");
TEST (T (0, 0, 0, 25, 6, 67), "7/25/1967", 9, "%x", 0, Eof);
// %X The time, using the locale's time format.
STEP ("%X: the time");
TEST (T (12, 34, 5), "5:34:12", 7, "%X", 0, Eof);
TEST (T (23, 45, 6), " 6:45:23", 8, " %X", 0, Eof);
// %y The year within century. When a century is not otherwise
// specified, values in the range [69,99] shall refer to years 1969
// to 1999 inclusive, and values in the range [00,68] shall refer
// to years 2000 to 2068 inclusive; leading zeros shall be permitted
// but shall not be required.
// Note: It is expected that in a future version of
// IEEE Std 1003.1-2001 the default century inferred from a
// 2-digit year will change. (This would apply to all commands
// accepting a 2-digit year as input.)
STEP ("%y: the year within century");
TEST (T (0, 0, 0, 0, 0, 100), "0", 1, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 100), "00", 2, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 101), "1", 1, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 102), "2", 1, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 103), "03", 2, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 168), "68", 2, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 69), "69", 2, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 99), "99", 2, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1800), "100", 3, "%y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 102), "2002", 4, "%y", 0, Eof);
// %Y The year, including the century (for example, 1988).
STEP ("%Y: the year, including the century");
TEST (T (0, 0, 0, 0, 0, -1900), "0", 1, "%Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, -1900), " 0", 2, " %Y", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 99), "\t1999", 5, " %Y", 0, Eof);
STEP ("invalid pattern");
TEST (T (0), "0", 0, "E", 0, Fail);
TEST (T (0), "0", 0, "i", 0, Fail);
TEST (T (0), "0", 0, "J", 0, Fail);
TEST (T (0), "0", 0, "N", 0, Fail);
TEST (T (0), "0", 0, "P", 0, Fail);
TEST (T (0), "0", 0, "s", 0, Fail);
TEST (T (0), "0", 0, "u", 0, Fail);
TEST (T (0), "0", 0, "z", 0, Fail);
TEST (T (0), "0", 0, "Z", 0, Fail);
// %Ec The locale's alternative date and time representation.
// %EC The name of the base year (period) in the locale's alternative
// representation.
// %Ex The locale's alternative date representation.
// %EX The locale's alternative time representation.
// %Ey The offset from %EC (year only) in the locale's alternative
// representation.
// %EY The full alternative year representation.
// %Od The day of the month using the locale's alternative numeric
// symbols; leading zeros are permitted but not required.
// %Oe Equivalent to %Od.
// %OH The hour (24-hour clock) using the locale's alternative numeric
// symbols.
// %OI The hour (12-hour clock) using the locale's alternative numeric
// symbols.
// %Om The month using the locale's alternative numeric symbols.
// %OM The minutes using the locale's alternative numeric symbols.
// %OS The seconds using the locale's alternative numeric symbols.
// %OU The week number of the year (Sunday as the first day of the week)
// using the locale's alternative numeric symbols.
// %Ow The number of the weekday (Sunday=0) using the locale's
// alternative numeric symbols.
// %OW The week number of the year (Monday as the first day of the
// week) using the locale's alternative numeric symbols.
// %Oy The year (offset from %C ) using the locale's alternative numeric
// symbols.
rw_warn (0, 0, __LINE__, "E modifier not being exercised");
rw_warn (0, 0, __LINE__, "O modifier not being exercised");
// exercise pattern strings containing multiple format specifiers
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sun Jan", 7, "%a %b", 0, Eof);
TEST (T (0, 0, 0, 0, 1, 0, 1), "Mon Feb", 8, "%a %b", 0, Eof);
TEST (T (0, 0, 0, 0, 2, 0, 2), "Tue%nMar", 7, "%a %b", 0, Eof);
TEST (T (0, 0, 0, 0, 3, 0, 3), "Wed%t Apr", 8, "%a %b", 0, Eof);
TEST (T (0, 0, 0, 0, 2, 0, 5), "Friday March", 12, "%a %b", 0, Good);
}
/**************************************************************************/
template <class charT>
void test_english (charT, const char *cname, const char *locname)
{
_TRY {
// set the global locale object to the german locale
std::locale::global (std::locale (locname));
}
_CATCH (...) {
rw_error (0, 0, __LINE__,
"locale(%#s) unexpectedly threw an exception", locname);
return;
}
// exercise abbreviated weekday names
FUNCTION ("get_weekday");
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sun", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Mon", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Tue", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Wed", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Thu", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Fri", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Sat", 3, "a", 0, Eof);
// exercise full weekday names
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sunday", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Monday", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Tuesday", 7, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Wednesday", 9, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Thursday", 8, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Friday", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Saturday", 8, "a", 0, Good);
// exercise full month names
FUNCTION ("get_monthname");
TEST (T (0, 0, 0, 0, 0), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 1), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 2), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 3), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 4), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 5), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 6), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 7), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 8), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 9), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 10), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 11), "%B", -1, "b", 0, -1);
// exercise date (time_get::get_date())
FUNCTION ("get_date");
TEST (T (0, 0, 0, 1, 0, 100), "%x", 8, "x", 0, Eof);
// exercise time (time_get::get_time())
FUNCTION ("get_time");
int len;
{
// determine whether "%X" is equivalent to "%I:%M:%S %p"
// (e.g., HP-UX or Linux) or to "%I:%M:%S" (e.g., Compaq
// Tru64 UNIX)
char buf [32];
const std::tm tmb = mktm (0, 0, 1);
len = int (std::strftime (buf, sizeof buf, "%X", &tmb));
}
const int hour = 11 == len ? 12 : 0;
TEST (T ( 0, 0, 0), "%X", len, "X", 0, 11 == len ? Good : Eof);
TEST (T ( 0, 0, 1), "%X", len, "X", 0, 11 == len ? Good : Eof);
TEST (T ( 0, 0, 11), "%X", len, "X", 0, 11 == len ? Good : Eof);
TEST (T ( 0, 0, 12), "%X", len, "X", 0, 11 == len ? Good : Eof);
TEST (T ( 0, 0, 13), "%X", len, "X", 0, 11 == len ? Good : Eof);
TEST (T ( 0, 0, 23), "%X", len, "X", 0, 11 == len ? Good : Eof);
TEST (T ( 0, 0, 12 - hour), "12:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 1), "01:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 2), "02:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 3), "03:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 4), "04:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 5), "05:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 6), "06:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 7), "07:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 8), "08:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 9), "09:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 10), "10:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 11), "11:00:00 AM", len, "X", 0, Good);
TEST (T ( 0, 0, 12), "12:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 1), "01:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 2), "02:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 3), "03:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 4), "04:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 5), "05:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 6), "06:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 7), "07:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 8), "08:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 9), "09:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 10), "10:00:00 PM", len, "X", 0, Good);
TEST (T ( 0, 0, hour + 11), "11:00:00 PM", len, "X", 0, Good);
TEST (T (60, 9, hour + 11), "11:09:60 PM", len, "X", 0, Good);
}
/**************************************************************************/
template <class charT>
void test_german (charT, const char *cname, const char *locname)
{
_TRY {
// set the global locale object to the german locale
std::locale::global (std::locale (locname));
}
_CATCH (...) {
rw_error (0, 0, __LINE__,
"locale(%#s) unexpectedly threw an exception", locname);
return;
}
// exercise abbreviated weekday names
// these may be { So, Mo, Di, Mi, Do, Sa } (e.g., Compaq Tru64 UNIX)
// or { Son, Mon, Die, Mit, Don, Sam } (e.g., Linux, SunOS, or Win32)
FUNCTION ("get_weekday");
TEST (T (0, 0, 0, 0, 0, 0, 0), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "%a", -1, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 6), "%a", -1, "a", 0, Eof);
// exercise full weekday names
TEST (T (0, 0, 0, 0, 0, 0, 0), "Sonntag", 7, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 1), "Montag", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "Dienstag", 8, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 3), "Mittwoch", 8, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 4), "Donnerstag", 10, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 5), "Freitag", 7, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 6), "Samstag", 7, "a", 0, Good);
// exercise full month names
FUNCTION ("get_monthname");
TEST (T (0, 0, 0, 0, 0), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 1), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 2), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 3), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 4), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 5), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 6), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 7), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 8), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 9), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 10), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 11), "%B", -1, "b", 0, -1);
}
/**************************************************************************/
template <class charT>
void test_danish (charT, const char *cname, const char *locname)
{
_TRY {
// set the global locale object to the german locale
std::locale::global (std::locale (locname));
}
_CATCH (...) {
rw_error (0, 0, __LINE__,
"locale(%#s) unexpectedly threw an exception", locname);
return;
}
// exercise abbreviated weekday names
FUNCTION ("get_weekday");
TEST (T (0, 0, 0, 0, 0, 0, 0), "%a", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "%a", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "%a", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "%a", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "%a", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "%a", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 6), "%a", 3, "a", 0, Eof);
// avoid using <s><o/><n> or <s><o/><n><d><a><g> since it
// contains the non-ASCII character <o/> (o with a slash)
TEST (T (0, 0, 0, 0, 0, 0, 1), "man", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 2), "tir", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 3), "ons", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 4), "tor", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 5), "fre", 3, "a", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "mandag", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "tirsdag", 7, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 3), "onsdag", 6, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 4), "torsdag", 7, "a", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 5), "fredag", 6, "a", 0, Good);
// exercise full month names
FUNCTION ("get_monthname");
TEST (T (0, 0, 0, 0, 0), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 1), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 2), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 3), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 4), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 5), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 6), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 7), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 8), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 9), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 10), "%B", -1, "b", 0, -1);
TEST (T (0, 0, 0, 0, 11), "%B", -1, "b", 0, -1);
}
/**************************************************************************/
struct time_data
{
const char* abday [7]; // %a abbreviated day name
const char* day [7]; // %A full day name
const char* abmon [12]; // %b abbreviated month name
const char* mon [12]; // %B full month name
const char* am_pm [2]; // %p AM/PM designator
const char* d_t_fmt; // %c date and time
const char* d_fmt; // %x date
const char* t_fmt; // %X time
const char* t_fmt_ampm; // %r time with the AM/PM designaror
const char* era_d_t_fmt; // %Ec alternative date and time
const char* era_d_fmt; // %EX alternative date
const char* era_t_fmt; // %Ex alternative time
const char* const* alt_digits; // alternative numeric symbols
struct era_data {
int offset;
int start_day; // [1..31]
int start_mon; // [0..11]
int start_year;
int end_day; // [1..31]
int end_mon; // [0..11]
int end_year; // INT_MIN, [0..9999], INT_MAX
const char *name;
const char *format;
};
const era_data* era;
};
// the root of the locale directory (RWSTD_LOCALE_ROOT)
// set in main() instead of here to avoid Solaris 7 putenv() bug (PR #30017)
static const char*
locale_root;
static const char*
make_LC_TIME (const time_data *td)
{
static char locnamebuf [1024];
if (*locnamebuf)
return locnamebuf;
// create a temporary locale definition file
char srcfname [1024];
if (rw_snprintf (srcfname, sizeof srcfname, "%s%c%s",
locale_root, _RWSTD_PATH_SEP, "LC_TIME.src") < 0)
return 0;
std::FILE *fout = std::fopen (srcfname, "w");
rw_fatal (0 != fout, 0, __LINE__,
"fopen(%#s, \"w\") failed: %{#m} - %m", srcfname);
// rw_fatal() doesn't return on failure
RW_ASSERT (0 != fout);
std::fprintf (fout, "LC_TIME\n");
unsigned i;
std::fprintf (fout, "abday ");
for (i = 0; i != sizeof td->abday / sizeof *td->abday; ++i) {
std::fprintf (fout, "\"");
pcs_write (fout, td->abday [i]);
std::fprintf (fout, "\"%c", i < 6 ? ';' : '\n');
}
std::fprintf (fout, "day ");
for (i = 0; i != sizeof td->day / sizeof *td->day; ++i) {
std::fprintf (fout, "\"");
pcs_write (fout, td->day [i]);
std::fprintf (fout, "\"%c", i < 6 ? ';' : '\n');
}
std::fprintf (fout, "abmon ");
for (i = 0; i != sizeof td->abmon / sizeof *td->abmon; ++i) {
std::fprintf (fout, "\"");
pcs_write (fout, td->abmon [i]);
std::fprintf (fout, "\"%c", i < 11 ? ';' : '\n');
}
std::fprintf (fout, "mon ");
for (i = 0; i != sizeof td->mon / sizeof *td->mon; ++i) {
std::fprintf (fout, "\"");
pcs_write (fout, td->mon [i]);
std::fprintf (fout, "\"%c", i < 11 ? ';' : '\n');
}
std::fprintf (fout, "am_pm ");
for (i = 0; i != sizeof td->am_pm / sizeof *td->am_pm; ++i) {
std::fprintf (fout, "\"");
pcs_write (fout, td->am_pm [i]);
std::fprintf (fout, "\"%c", i < 1 ? ';' : '\n');
}
// write out d_t_fmt, d_fmt, t_fmt, etc.
// preface each line with a comment giving
// the specification in a human-readable format
std::fprintf (fout, "\n# d_t_fmt \"%s\"\nd_t_fmt \"",
td->d_t_fmt);
pcs_write (fout, td->d_t_fmt);
std::fprintf (fout, "\"\n\n# d_fmt \"%s\"\nd_fmt \"",
td->d_fmt);
pcs_write (fout, td->d_fmt);
std::fprintf (fout, "\"\n\n# t_fmt \"%s\"\nt_fmt \"",
td->t_fmt);
pcs_write (fout, td->t_fmt);
std::fprintf (fout, "\"\n\n# t_fmt_ampm \"%s\"\nt_fmt_ampm \"",
td->t_fmt_ampm);
pcs_write (fout, td->t_fmt_ampm);
std::fprintf (fout, "\"\n\n# era_d_t_fmt \"%s\"\nera_d_t_fmt \"",
td->era_d_t_fmt);
pcs_write (fout, td->era_d_t_fmt);
std::fprintf (fout, "\"\n\n# era_d_fmt \"%s\"\nera_d_fmt \"",
td->era_d_fmt);
pcs_write (fout, td->era_d_fmt);
std::fprintf (fout, "\"\n\n# era_t_fmt \"%s\"\nera_t_fmt \"",
td->era_t_fmt);
pcs_write (fout, td->era_t_fmt);
std::fprintf (fout, "\"\nalt_digits ");
for (i = 0; td->alt_digits [i]; ++i) {
std::fprintf (fout, "\"");
pcs_write (fout, td->alt_digits [i]);
std::fprintf (fout, "\"%c", td->alt_digits [i + 1] ? ';' : '\n');
}
std::fprintf (fout, "\n\nera ");
for (i = 0; INT_MIN != td->era [i].offset; ++i) {
char segment [256];
std::sprintf (segment, "%c:%d:%04d/%02d/%02d:",
td->era [i].offset < 0 ? '-' : '+',
td->era [i].offset < 0 ? -td->era [i].offset
: td->era [i].offset,
td->era [i].start_year + 1900,
td->era [i].start_mon + 1,
td->era [i].start_day);
const char *end_date = 0;
if (INT_MIN == td->era [i].end_year)
end_date = "-*"; // beginning of time
else if (INT_MAX == td->era [i].end_year)
end_date = "+*"; // end of time
if (end_date) {
std::sprintf (segment + std::strlen (segment), "%s:%s:%s",
end_date, td->era [i].name, td->era [i].format);
}
else {
std::sprintf (segment + std::strlen (segment),
"%04d/%02d/%02d:%s:%s",
td->era [i].end_year + 1900,
td->era [i].end_mon + 1,
td->era [i].end_day,
td->era [i].name,
td->era [i].format);
}
std::fprintf (fout, "\"");
pcs_write (fout, segment);
std::fprintf (fout, "\"%c",
INT_MIN == td->era [i + 1].offset ? '\n' : ';');
}
std::fprintf (fout, "\nEND LC_TIME\n");
std::fclose (fout);
// create a temporary character map file
char cmfname [1024];
if (rw_snprintf (cmfname, sizeof cmfname, "%s%c%s",
locale_root, _RWSTD_PATH_SEP, "LC_TIME.cm") < 0)
return 0;
fout = std::fopen (cmfname, "w");
rw_fatal (0 != fout, 0, __LINE__,
"fopen(%#s, \"w\") failed: %{#m} - %m", cmfname);
// rw_fatal() doesn't return on failure
RW_ASSERT (0 != fout);
pcs_write (fout, 0);
std::fclose (fout);
// process the locale definition file and the character map
const char* const locname =
rw_localedef ("-w ", srcfname, cmfname, "test-locale");
if (locname && (std::strlen(locname) < sizeof locnamebuf))
std::strcpy (locnamebuf, locname);
return locname;
}
static const char*
make_LC_TIME ()
{
const char* const alt_digits[] = {
"", "1st", "2nd", "3rd", "4th",
"5th", "6th", "7th", "8th", "9th",
"10th", "11th", "12th", "13th", "14th",
"15th", "16th", "17th", "18th", "19th",
"20th", "21st", "22nd", "23rd", "24th",
"25th", "26th", "27th", "28th", "29th",
"30th", "31st", 0 // sentinel
};
const time_data::era_data era[] = {
// some entries copied and modified from HP-UX 11.11 ja_JP.utf8
//
// # 1990-01-02 and onward: "Heisei%EyNen" (1990 is Heisei 2 Nen.)
// # 1990-01-01 to 1990-01-02: "%C" (no era specified)
// # 1989-01-08 to 1989-12-31: "HeiseiGannen"
// # 1927-01-01 to 1989-01-07: "Showa%EyNen" (1927 is Showa 2 Nen.)
// # 1927-01-01 and prior: "foo"
// era "+:2:1990/01/02:+*:<U????><U????>:%EC%Ey<U????>";
// "+:1:1989/01/08:1989/12/31:<U????>:%EC<U????><U????>";
// "+:2:1927/01/01:1989/01/07:<U????><U????>:%EC%Ey<U????>";
// "-:7:1926/12/31:-*:foo:bar%EC%Ey"
// 7|2 |1 | |2 starting year in an era
// <<<|>>>>>>>>>|>>>>>>>>>|.|>>> direction in which years increase
// ^ ^ ^ ^
// | | | |
// | | | +-> Jan 2, 1990 (Heisei %Ey Nen)
// | | +-> Dec 31, 1989 (%C)
// | +-> Jan 7, 1989 (Heisei Gannen)
// +-> Jan 1, 1927 (Showa %Ey Nen)
// +-< Dec 31, 1926 (foobar %Ey)
{ 2, 2, 0, 90, 0, 0, INT_MAX, "Heisei", "%EC %Ey Nen" },
{ 1, 8, 0, 89, 31, 11, 89, "Heisei", "%EC Gannen" },
{ 2, 1, 0, 27, 7, 0, 89, "Showa", "%EC %Ey Nen" },
{ -7, 31, 11, 26, 0, 0, INT_MIN, "bar", "foo%EC %Ey" },
{ INT_MIN /* sentinel entry */, 0, 0, 0, 0, 0, 0, 0, 0 }
};
const time_data td = {
// %a
{ "[Sun]", "[Mon]", "[Tue]", "[Wed]", "[Thu]", "[Fri]", "[Sat]" },
// %A
{
"[Sunday]", "[Monday]", "[Tuesday]", "[Wednesday]", "[Thursday]",
"[Friday]", "[Saturday]"
},
// %b
{
"[Jan]", "[Feb]", "[Mar]", "[Apr]", "[May]", "[Jun]",
"[Jul]", "[Aug]", "[Sep]", "[Oct]", "[Nov]", "[Dec]",
},
// %B
{
"[January]", "[February]", "[March]", "[April]", "[May]", "[June]",
"[July]", "[August]", "[September]", "[October]", "[November]",
"[December]",
},
{ "[A.M.]", "[P.M.]" }, // %p
"[[%a][%b][%d][%H][%M][%S][%y]]", // %c
"[[%3m][%.4d][%4.3y]]", // %x
"[[%3H][%.4M][%4.3S]]", // %X
"[[%I][%M][%S][%p]]", // %r
"[[%A][%B][%Od][%H][%M][%S][%Y]]", // %Ec
"%Ow weekday, %OU week, %Oy year", // %Ex
"%OH hour, %OM minute, %OS second", // %EX
alt_digits, era
};
const char* const locname = make_LC_TIME (&td);
return locname;
}
/**************************************************************************/
template <class charT>
void test_user (charT, const char *cname, const char *locname)
{
const char* const envar = std::getenv (LOCALE_ROOT_ENVAR);
rw_info (0, 0, __LINE__,
"std::time_get<%s>, in locale(\"%s\") "
"created from a generated LC_TIME file; "
LOCALE_ROOT_ENVAR "=%s",
cname, locname, envar);
// construct a locale object from the binary database
std::locale loc;
_TRY {
loc = std::locale (loc, locname, std::locale::time);
}
_CATCH (...) {
rw_error (0, 0, __LINE__,
"locale (locale (), \"%s\", locale::time) "
"unexpectedly threw an exception", locname);
return;
}
// set the global locale (used by the test function)
std::locale::global (loc);
// %Ec: The locale's alternative date and time representation.
STEP ("%Ec: alternative date and time representation");
TEST (T (0, 0, 0, 1, 0, 0, 0),
// "[[%A][%B][%Od][%H][%M][%S][%Y]]"
"[[[Sunday]][[January]][1st][00][00][00][1900]]", 46,
"%Ec", 0, Good);
TEST (T (5, 4, 3, 2, 1, 1, 1),
"[[[monday]][[february]][2nd][03][04][05][1901]]", 47,
"%Ec", 0, Good);
TEST (T (60, 59, 23, 31, 2, -1898, 2),
// %Y requires a four digit year, 02 is not treated as 2002
"[[[TUE]][[MAR]][31st][23][59][60][02]]", 38,
"%Ec", 0, Good);
// %EC: The name of the base year (period) in the locale's
// alternative representation.
// %Ex: The locale's alternative date representation.
STEP ("%Ex: alternative date representation");
rw_warn (0, 0, __LINE__, "%%Ex not being exercised");
// verify that facet computes the remaining tm members from
// the supplied data
//TEST (T (0, 0, 0, 21, 4, 2002, 2, 141),
// // "%Ow weekday, %OU week, %Oy year"
// "2nd weekday, 21st week, 2nd year", 32,
// // i.e., May 21, 2002
// "%Ex", 0, Good);
// %EX: The locale's alternative time representation.
STEP ("%EX: alternative time representation");
// verify that 0 is correctly parsed if alternative numeric
// symbols are expected and the symbol for zero is empty
TEST (T (0, 1, 2),
// "%OH hour, %OM minute, %OS second"
"2nd hour, 1st minute, 0 second", 30,
"%EX", 0, Good);
TEST (T (21, 22, 23),
// "%OH hour, %OM minute, %OS second"
"23rd hour, 22nd minute, 21st second", 35,
"%EX", 0, Good);
// %Ey: The offset from %EC (year only) in the locale's
// alternative representation.
STEP ("%Ey: offset from %EC in alternative representation.");
rw_warn (0, 0, __LINE__, "%%Ey not being exercised");
// %EY: The full alternative year representation.
STEP ("%EY: the full alternative year representation");
rw_warn (0, 0, __LINE__, "%%EY not being exercised");
// %Od: The day of the month using the locale's alternative
// numeric symbols; leading zeros are permitted but not required.
STEP ("%Od: the day of the month using alternative numeric symbols");
TEST (T (0, 0, 0, 1), "1st", 3, "%Od", 0, Good);
TEST (T (0, 0, 0, 2), "2nd", 3, "%Od", 0, Good);
TEST (T (0, 0, 0, 11), "11th", 4, "%Od", 0, Good);
TEST (T (0, 0, 0, 21), "21st", 4, "%Od", 0, Good);
TEST (T (0, 0, 0, 30), "30th", 4, "%Od", 0, Good);
TEST (T (0, 0, 0, 31), "31st", 4, "%Od", 0, Good);
TEST (T (0, 0, 0, 0), "32", 2, "%Od", 0, Eof | Fail);
// %Oe: Equivalent to %Od.
STEP ("%Oe: equivalent to %Od");
TEST (T (0, 0, 0, 3), "3rd", 3, "%Oe", 0, Good);
TEST (T (0, 0, 0, 4), "4th", 3, "%Oe", 0, Good);
TEST (T (0, 0, 0, 9), "9th", 3, "%Oe", 0, Good);
TEST (T (0, 0, 0, 10), "10th", 4, "%Oe", 0, Good);
TEST (T (0, 0, 0, 0), "32nd", 2, "%Oe", 0, Fail);
TEST (T (0, 0, 0, 0), "33", 2, "%Oe", 0, Eof | Fail);
// %OH: The hour (24-hour clock) using the locale's alternative
// numeric symbols.
STEP ("%OH: the hour (24-hour clock) using alternative numeric symbols");
TEST (T (0, 0, 0), "0", 1, "%OH", 0, Eof);
TEST (T (0, 0, 0), "00", 2, "%OH", 0, Eof);
TEST (T (0, 0, 1), "1st", 3, "%OH", 0, Good);
TEST (T (0, 0, 2), "2nd", 3, "%OH", 0, Good);
TEST (T (0, 0, 11), "11th", 4, "%OH", 0, Good);
TEST (T (0, 0, 12), "12th", 4, "%OH", 0, Good);
TEST (T (0, 0, 13), "13th", 4, "%OH", 0, Good);
TEST (T (0, 0, 23), "23rd", 4, "%OH", 0, Good);
// %OI: The hour (12-hour clock) using the locale's alternative
// numeric symbols.
STEP ("%OI: the hour (12-hour clock) using alternative numeric symbols");
TEST (T (0, 0, 0), "0", 1, "%OI", 0, Eof);
TEST (T (0, 0, 0), "000", 3, "%OI", 0, Eof);
TEST (T (0, 0, 3), "3rd", 3, "%OI", 0, Good);
TEST (T (0, 0, 11), "11th", 4, "%OI", 0, Good);
TEST (T (0, 0, 12), "12th", 4, "%OI", 0, Good);
TEST (T (0, 0, 0), "13th", 4, "%OI", 0, Fail);
TEST (T (0, 0, 0), "14", 2, "%OI", 0, Eof | Fail);
// %Om: The month using the locale's alternative numeric symbols.
STEP ("%Om: the month using alternative numeric symbols");
TEST (T (0, 0, 0, 0, 0), "1st", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 1), "2nd", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 2), "3rd", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 3), "4th", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 4), "5th", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 5), "6th", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 6), "7th", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 7), "8th", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 8), "9th", 3, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 9), "10th", 4, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 10), "11th", 4, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 11), "12th", 4, "%Om", 0, Good);
TEST (T (0, 0, 0, 0, 0), "13th", 4, "%Om", 0, Fail);
TEST (T (0, 0, 0, 0, 0), "0", 1, "%Om", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0), "00", 2, "%Om", 0, Eof | Fail);
TEST (T (0, 0, 0, 0, 0), "01", 2, "%Om", 0, Eof | Fail);
// %OM: The minutes using the locale's alternative numeric symbols.
STEP ("%OM: the minutes using alternative numeric symbols");
TEST (T (0, 0), "0", 1, "%OM", 0, Eof);
TEST (T (0, 1), "1st", 3, "%OM", 0, Good);
TEST (T (0, 2), "2nd", 3, "%OM", 0, Good);
TEST (T (0, 3), "3rd", 3, "%OM", 0, Good);
TEST (T (0, 4), "4th", 3, "%OM", 0, Good);
TEST (T (0, 29), "29th", 4, "%OM", 0, Good);
TEST (T (0, 30), "30th", 4, "%OM", 0, Good);
TEST (T (0, 31), "31st", 4, "%OM", 0, Good);
TEST (T (0, 32), "32", 2, "%OM", 0, Eof);
TEST (T (0, 0), "60", 2, "%OM", 0, Eof | Fail);
TEST (T (0, 0), "2", 1, "%OM", 0, Eof | Fail);
// %OS: The seconds using the locale's alternative numeric symbols.
STEP ("%OS: the seconds using alternative numeric symbols");
TEST (T ( 0), "0", 1, "%OS", 0, Eof);
TEST (T ( 1), "1st", 3, "%OS", 0, Good);
TEST (T ( 2), "2nd", 3, "%OS", 0, Good);
TEST (T ( 3), "3rd", 3, "%OS", 0, Good);
TEST (T ( 4), "4th", 3, "%OS", 0, Good);
TEST (T (29), "29th", 4, "%OS", 0, Good);
TEST (T (30), "30th", 4, "%OS", 0, Good);
TEST (T (31), "31st", 4, "%OS", 0, Good);
TEST (T (32), "32", 2, "%OS", 0, Eof);
TEST (T (59), "059", 3, "%OS", 0, Eof);
TEST (T (60), "0060", 4, "%OS", 0, Eof);
TEST (T ( 0), "61", 2, "%OS", 0, Eof | Fail);
TEST (T ( 0), "21", 2, "%OS", 0, Eof | Fail);
// %OU: The week number of the year (Sunday as the first day of the week)
// using the locale's alternative numeric symbols.
STEP ("%OU: the Sunday-based week using alternative numeric symbols");
rw_warn (0, 0, __LINE__, "%%OU not being exercised");
// %Ow: The number of the weekday (Sunday=0) using the locale's
// alternative numeric symbols.
STEP ("%Ow: Sunday-based weekday using alternative numeric symbols");
TEST (T (0, 0, 0, 0, 0, 0, 0), "0", 1, "%Ow", 0, Eof);
TEST (T (0, 0, 0, 0, 0, 0, 1), "1st", 3, "%Ow", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 2), "2nd", 3, "%Ow", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 6), "6th", 3, "%Ow", 0, Good);
TEST (T (0, 0, 0, 0, 0, 0, 0), "7th", 3, "%Ow", 0, Fail);
TEST (T (0, 0, 0, 0, 0, 0, 0), "8", 1, "%Ow", 0, Eof | Fail);
// %OW: The week number of the year (Monday as the first day of the week)
// using the locale's alternative numeric symbols.
STEP ("%OW: the Monday-based week using alternative numeric symbols");
rw_warn (0, 0, __LINE__, "%%OW not being exercised");
// %Oy: The year (offset from %C ) using the locale's alternative
// numeric symbols.
STEP ("%Oy: year offset from %C using alternative numeric symbols");
rw_warn (0, 0, __LINE__, "%%Oy not being exercised");
}
/**************************************************************************/
static int
run_test (int, char**)
{
// set up RWSTD_LOCALE_ROOT and other environment variables
// here as opposed to at program startup to work around a
// SunOS 5.7 bug in putenv() (PR ##30017)
locale_root = rw_set_locale_root ();
// store the next available file descriptor
// in order to detect file descriptor leaks
const int fd0 = rw_nextfd (0);
test_posix (char (), "char");
const char *locname;
const char en[] = "en-*-*-*";
const char de[] = "de-*-*-*";
const char da[] = "da-*-*-*";
int nnamed = 0;
// try to find and exercise the english locale
if ((locname = rw_locale_query (LC_ALL, en, 1)) && *locname) {
test_english (char (), "char", locname);
++nnamed;
}
// try to find and exercise the german locale
if ((locname = rw_locale_query (LC_ALL, de, 1)) && *locname) {
test_german (char (), "char", locname);
++nnamed;
}
// try to find and exercise the danish locale
if ((locname = rw_locale_query (LC_ALL, da, 1)) && *locname) {
test_danish (char (), "char", locname);
++nnamed;
}
//////////////////////////////////////////////////////////////////
// exercise the time_get facets with a user-defined locale
std::locale::global (std::locale ("C"));
// create a LC_TIME database based on user-defined data
locname = make_LC_TIME ();
if (!locname) {
rw_error (0, 0, __LINE__, "failed to generate LC_TIME locale data");
return 0;
}
test_user (char (), "char", locname);
#ifndef _RWSTD_NO_WCHAR_T
test_posix (wchar_t (), "wchar_t");
test_user (wchar_t (), "wchar_t", locname);
#endif // _RWSTD_NO_WCHAR_T
// reset the gloab locale to free up resources (such as file
// descriptors used by time_get_byname to map locale databases)
std::locale::global (std::locale ("C"));
const int fd1 = rw_nextfd (0);
rw_assert (0 == fd1 - fd0, 0, __LINE__,
"%d file descriptor leaks detected", fd1 - fd0);
rw_assert (0 != nnamed, 0, __LINE__,
"time_get not exercised in named locales");
return 0;
}
/**************************************************************************/
int main (int argc, char *argv[])
{
return rw_test (argc, argv, __FILE__,
"lib.locale.time.get",
0 /* no comment */,
run_test,
"",
0);
}