2008-05-27 Travis Vitek <vitek@roguewave.com>
Merged branches/4.3.x@660567 to trunk
git-svn-id: https://svn.apache.org/repos/asf/stdcxx/trunk@660776 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bin/genxviews b/bin/genxviews
index 87eb1db..cc5a158 100755
--- a/bin/genxviews
+++ b/bin/genxviews
@@ -205,12 +205,14 @@
<th>Operating System</td>
<th>Architecture</td>
<th>Compiler</td>
- <th>Build Results</td>
- <th>Logs</td>
- <th>Time<br>(sec)</td>
+ <th title="Cross-build result page">Build Results</td>
+ <th title="Total number of logs">Logs</td>
+ <th title="Number of logs added since the last run">New</td>
+ <th title="Timestamp of oldest log">Age</td>
+ <th title="Time to process all logs">Time<br>(sec)</td>
</tr>
- </thead>
- <tbody>
+ </thead>
+ <tbody>
EOF
@@ -228,10 +230,10 @@
fi
cat<<EOF | output
- <tr>
- <td>$osname</td>
- <td>$arch</td>
- <td>$compiler</td>
+ <tr>
+ <td>$osname</td>
+ <td>$arch</td>
+ <td>$compiler</td>
EOF
# build types:
@@ -247,6 +249,8 @@
suffixes="a A d D s S"
unset buildlogs
+ unset oldest
+
count=0
for b in $btypes; do
@@ -261,8 +265,16 @@
done
done
+ if [ -e $outdir/$xfile ]; then
+ # count the number of logs that are newer than the cross-build file
+ newlogs=`find $logdir/ -name "$alllogs" -newer $outdir/$xfile | wc -l`
+ else
+ # cross-build file doesn't exist yet, all logs are considered new
+ newlogs=$count
+ fi
+
if [ $verbose -ne 0 ]; then
- echo "$myname: found $count logs: $buildlogs"
+ echo "$myname: found $count logs ($newlogs new): $buildlogs"
fi
# create a title for the page
@@ -273,16 +285,26 @@
if [ "$buildlogs" = "" ]; then
# format missing logs in italics
- output " <td><i>$xfile</i></td>"
+ output " <td><i>$xfile</i></td>"
else
- if [ $verbose -ne 0 ]; then
- echo "$myname: $XBUILDGEN $verarg -s -o$outdir/$xfile -T\"$title\" $buildlogs"
- fi
+ output " <td><a href=\"$xfile\">$xfile</a></td>"
- output " <td><a href=\"$xfile\">$xfile</a></td>"
+ oldest=` cd $logdir && ls -lrt $buildlogs | head -n 1 \
+ | awk '{ print $6 " " $7 " " $8 }'`
- if [ $dryrun -eq 0 ]; then
- $XBUILDGEN $verarg -s -o$outdir/$xfile -T"$title" $buildlogs
+ if [ $newlogs -gt 0 ]; then
+
+ # only invoken xbuildgen when there are new logs to proecess
+ # otherwise simply point at the previously generated cross
+ # build file
+
+ if [ $verbose -ne 0 ]; then
+ echo "$myname: $XBUILDGEN $verarg -s -o$outdir/$xfile -T\"$title\" $buildlogs"
+ fi
+
+ if [ $dryrun -eq 0 ]; then
+ $XBUILDGEN $verarg -s -o$outdir/$xfile -T"$title" $buildlogs
+ fi
fi
fi
@@ -297,9 +319,11 @@
duration=`expr $end - $duration`
cat<<EOF | output
- <td>$count</td>
- <td>$duration</td>
- </tr>
+ <td>$count</td>
+ <td>$newlogs</td>
+ <td>$oldest</td>
+ <td>$duration</td>
+ </tr>
EOF
}
diff --git a/etc/config/gcc.config b/etc/config/gcc.config
index e493b1e..59bdd79 100644
--- a/etc/config/gcc.config
+++ b/etc/config/gcc.config
@@ -273,45 +273,47 @@
SINGL_CPPFLAGS =
SINGL_LDFLAGS =
-# (try to) determine the architecture via the (non-standard) -p option
-# the option is recognized on at least HP-UX, IRIX, and Linux (are there
-# any other systems running on IA64?)
-arch=$(shell uname -p 2>/dev/null)
+# gcc can generate 32-bit or 64-bit code by default, depending
+# on how it's configured
+# determine whether the default compiler invocation produces
+# wide (64-bit) or narrow (32-bit) code and set compiler,
+# linker, and other options accordingly
+wide = $(shell cd /tmp; tmpfile=stdcxx-longsize-$$; export tmpfile; \
+ echo "int main() { return 8 == sizeof (long); }" \
+ > $$tmpfile.c \
+ && $(CXX) $$tmpfile.c >/dev/null 2>&1 -o $$tmpfile; \
+ ./$$tmpfile; echo $$?; rm -f $$tmpfile.c $$tmpfile)
-ifeq ($(arch),ia64)
- # LP64 is the default (implicit) setting on IA64
+ifeq ($(wide),0)
+ # narrow (32-bit) mode is implicit
+ # use wide (64-bit) flags to explicitly enable LP64 mode
+
ifeq ($(OSNAME),HP-UX)
- # -milp32, -mlp64, etc. are options specific to HP-UX
+ # -milp32 and -mlp64 are options specific to HP-UX
+ CXXFLAGS.wide = -mlp64
+ LDFLAGS.wide = -mlp64
+ LDSOFLAGS.wide = -mlp64
+ ARFLAGS.wide =
+ else
+ CXXFLAGS.wide = -m64
+ LDFLAGS.wide = -m64
+ LDSOFLAGS.wide = -m64
+ ARFLAGS.wide =
+ endif
+
+else
+ # wide (64-bit) mode is implicit
+ # use narrow (32-bit) flags to explicitly enable ILP32 mode
+
+ ifeq ($(OSNAME),HP-UX)
CXXFLAGS.narrow = -milp32
LDFLAGS.narrow = -milp32
LDSOFLAGS.narrow = -milp32
ARFLAGS.narrow =
- endif
-else
- # determine whether the default compiler invocation produces
- # wide (64-bit) or narrow (32-bit) code and set compiler,
- # linker, and other flags accordingly
- wide = $(shell tmpfile=/tmp/longsize-$$; export tmpfile; \
- echo "int main() { return 8 == sizeof (long); }" \
- > $$tmpfile.c \
- && $(CXX) $$tmpfile.c >/dev/null 2>&1 -o $$tmpfile; \
- $$tmpfile; echo $$?; rm -f $$tmpfile.c $$tmpfile)
-
- ifeq ($(wide),0)
- # wide (64-bit) flags
- CXXFLAGS.wide = -m64
- LDFLAGS.wide = -m64
- LDSOFLAGS.wide = -m64
- ARFLAGS.wide =
-
- # narrow (32-bit) mode is implicit
else
- # narrow (32-bit) flags
CXXFLAGS.narrow = -m32
LDFLAGS.narrow = -m32
LDSOFLAGS.narrow = -m32
ARFLAGS.narrow =
-
- # wide (64-bit) mode is implicit
endif
endif
diff --git a/etc/config/src/MBSTATE_T.cpp b/etc/config/src/MBSTATE_T.cpp
index 3938686..59fb1c6 100644
--- a/etc/config/src/MBSTATE_T.cpp
+++ b/etc/config/src/MBSTATE_T.cpp
@@ -18,12 +18,24 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1999-2007 Rogue Wave Software, Inc.
+ * Copyright 1999-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include "config.h"
+#if defined (__EDG__) \
+ && !defined (__DECCXX) \
+ && !defined (__HP_aCC) \
+ && !defined (__INTEL_COMPILER) \
+ && !defined (_SGI_COMPILER_VERSION)
+ // disable error #450-D: the type "long long" is nonstandard
+ // when using the vanilla EDG eccp in strict mode (i.e., w/o
+ // long long support)
+# pragma diag_suppress 450
+#endif // EDG eccp on Linux
+
+
// defined to get the correct definition of mbstate_t, available on HPUX;
// once we get the correct size of the struct, _RWSTD_NO_MBSTATE_T is
// defined in rw/_config.h and we (and the users of the library) are left
diff --git a/etc/config/src/MMAP.cpp b/etc/config/src/MMAP.cpp
new file mode 100644
index 0000000..5f168cd
--- /dev/null
+++ b/etc/config/src/MMAP.cpp
@@ -0,0 +1,46 @@
+// checking for mmap() and munmap() in <sys/mman.h>
+
+/***************************************************************************
+ *
+ * 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 2008 Rogue Wave Software, Inc.
+ *
+ **************************************************************************/
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+
+void* map_file (int fd)
+{
+ return mmap (0, 4096, PROT_READ, MAP_PRIVATE, fd, 0);
+}
+
+
+int main (int argc, char *argv[])
+{
+ // avoid executing the code except when one or more command
+ // line arguments have been specified
+ if (argc < 2)
+ return 0;
+
+ void *p = map_file (argc);
+ munmap (p, 0);
+
+ return 0;
+}
diff --git a/etc/config/src/WCTRANS_T.cpp b/etc/config/src/WCTRANS_T.cpp
index 2062d2b..4fdc428 100644
--- a/etc/config/src/WCTRANS_T.cpp
+++ b/etc/config/src/WCTRANS_T.cpp
@@ -18,12 +18,24 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1999-2007 Rogue Wave Software, Inc.
+ * Copyright 1999-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include "config.h"
+#if defined (__EDG__) \
+ && !defined (__DECCXX) \
+ && !defined (__HP_aCC) \
+ && !defined (__INTEL_COMPILER) \
+ && !defined (_SGI_COMPILER_VERSION)
+ // disable error #450-D: the type "long long" is nonstandard
+ // when using the vanilla EDG eccp in strict mode (i.e., w/o
+ // long long support)
+# pragma diag_suppress 450
+#endif // EDG eccp on Linux
+
+
#ifndef _RWSTD_NO_WCHAR_H
# include <wchar.h>
#endif // _RWSTD_NO_WCHAR_H
diff --git a/etc/config/src/WCTYPE_T.cpp b/etc/config/src/WCTYPE_T.cpp
index d6afe96..749e726 100644
--- a/etc/config/src/WCTYPE_T.cpp
+++ b/etc/config/src/WCTYPE_T.cpp
@@ -18,12 +18,25 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1999-2007 Rogue Wave Software, Inc.
+ * Copyright 1999-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include "config.h"
+
+#if defined (__EDG__) \
+ && !defined (__DECCXX) \
+ && !defined (__HP_aCC) \
+ && !defined (__INTEL_COMPILER) \
+ && !defined (_SGI_COMPILER_VERSION)
+ // disable error #450-D: the type "long long" is nonstandard
+ // when using the vanilla EDG eccp in strict mode (i.e., w/o
+ // long long support)
+# pragma diag_suppress 450
+#endif // EDG eccp on Linux
+
+
#ifndef _RWSTD_NO_WCHAR_H
# include <wchar.h>
#endif // _RWSTD_NO_WCHAR_H
diff --git a/etc/config/src/WINT_T.cpp b/etc/config/src/WINT_T.cpp
index 1053768..1d20c21 100644
--- a/etc/config/src/WINT_T.cpp
+++ b/etc/config/src/WINT_T.cpp
@@ -18,12 +18,24 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1999-2007 Rogue Wave Software, Inc.
+ * Copyright 1999-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
#include "config.h"
+#if defined (__EDG__) \
+ && !defined (__DECCXX) \
+ && !defined (__HP_aCC) \
+ && !defined (__INTEL_COMPILER) \
+ && !defined (_SGI_COMPILER_VERSION)
+ // disable error #450-D: the type "long long" is nonstandard
+ // when using the vanilla EDG eccp in strict mode (i.e., w/o
+ // long long support)
+# pragma diag_suppress 450
+#endif // EDG eccp on Linux
+
+
#ifndef _RWSTD_NO_WCHAR_H
# include <wchar.h>
#endif // _RWSTD_NO_WCHAR_H
diff --git a/etc/config/vacpp.config b/etc/config/vacpp.config
index a39bfda..1b2e43e 100644
--- a/etc/config/vacpp.config
+++ b/etc/config/vacpp.config
@@ -241,10 +241,11 @@
# check if the -qtemplateregistry option is recognized
-use_tempinc=$(shell echo "int i;" >/tmp/foo.$$$$.c \
+use_tempinc=$(shell cd $${TMPDIR:=/tmp} \
+ && echo "int i;" >foo.$$$$.c \
&& $(CXX) -c -qmaxerr=1:w -qtemplateregistry \
- /tmp/foo.$$$$.c >/dev/null 2>&1; \
- echo $$?; rm /tmp/foo.$$$$.c)
+ foo.$$$$.c >/dev/null 2>&1; \
+ echo $$?; rm -f foo.$$$$.c foo.$$$$.o)
# template repository/registry name override
diff --git a/examples/manual/failure.cpp b/examples/manual/failure.cpp
index f9a1838..4394cfe 100644
--- a/examples/manual/failure.cpp
+++ b/examples/manual/failure.cpp
@@ -1,6 +1,7 @@
/**************************************************************************
*
- * failure.cpp - Example program demonstrating ios::failure.
+ * failure.cpp - Example program demonstrating the use of ios::failure
+ * and its extendsions provided by this implementation.
*
* $Id$
*
@@ -22,7 +23,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -31,39 +32,78 @@
#include <examples.h>
+
#ifndef _RWSTD_NO_EXCEPTIONS
int main ()
{
- try {
- // Enable exceptions in cin.
- std::cin.exceptions (std::ios::eofbit);
+ const std::ios::iostate allbits =
+ std::ios::badbit | std::ios::eofbit | std::ios::failbit;
+
+ // Enable all exceptions in cin.
+ std::cin.exceptions (allbits);
- // Clear all bits and set eofbit.
- std::cin.clear (std::ios::eofbit);
- }
- catch (const std::ios::failure &e) {
- std::cout << "Caught an exception: " << e.what () << std::endl;
- }
- catch (const std::exception &e) {
- std::cout << "Caught an exception: " << e.what () << std::endl;
+ while (!std::cin.eof ()) {
- return 1; // Indicate failure.
- }
- catch (...) {
- std::cout << "Caught an unknown exception" << std::endl;
+ // Clear state bits.
+ std::cin.clear ();
- return 1; // Indicate failure.
- }
+ try {
+ short i;
+ char ch;
- return 0;
+ // Try to extract a character and an integer.
+ std::cin >> ch >> i;
+
+ std::cout << ch << ' ' << i << '\n';
+ }
+
+#ifndef _RWSTD_NO_EXT_FAILURE
+
+ // Classes badbit_set, eofbit_set, and failbit_set are
+ // derived from failure and are optional extensions of
+ // this implementation.
+
+ catch (const std::ios::badbit_set &e) {
+ std::cout << "Caught std::ios::badbit_set: "
+ << e.what () << '\n';
+ }
+ catch (const std::ios::eofbit_set &e) {
+ std::cout << "Caught std::ios::eofbit_set: "
+ << e.what () << '\n';
+ }
+ catch (const std::ios::failbit_set &e) {
+ std::cout << "Caught std::ios::failbit_set: "
+ << e.what () << '\n';
+ }
+
+#endif // _RWSTD_NO_EXT_FAILURE
+
+ catch (const std::ios::failure &e) {
+ std::cout << "Caught std::ios::failure: "
+ << e.what () << '\n';
+ }
+ catch (const std::exception &e) {
+ std::cout << "Caught std::exception: "
+ << e.what () << '\n';
+
+ return 1; // Indicate error.
+ }
+ catch (...) {
+ std::cout << "Caught an unknown exception\n";
+
+ return 1; // Indicate error.
+ }
+ }
+
+ return 0;
}
-#else
+#else // if defined (_RWSTD_NO_EXCEPTIONS)
int main ()
{
- std::cout << "Exceptions not supported." << std::endl;
+ std::cout << "Exceptions not supported\n";
return 0;
}
diff --git a/examples/manual/in/failure.in b/examples/manual/in/failure.in
new file mode 100644
index 0000000..7a3f19b
--- /dev/null
+++ b/examples/manual/in/failure.in
@@ -0,0 +1,4 @@
+a+1234
+b-1234567890
+c+2345
+d-
diff --git a/examples/manual/out/failure.out b/examples/manual/out/failure.out
index 5e895ea..4edab2a 100644
--- a/examples/manual/out/failure.out
+++ b/examples/manual/out/failure.out
@@ -1 +1,5 @@
-Caught an exception: std::cin: stream object has set ios::eofbit
+a 1234
+Caught std::ios::failbit_set: std::cin: stream object has set ios::failbit
+c 2345
+Caught std::ios::failbit_set: std::cin: stream object has set ios::failbit
+Caught std::ios::failure: std::cin: stream object has set failbit, eofbit
diff --git a/include/loc/_ctype.h b/include/loc/_ctype.h
index df1bcdf..d68ea38 100644
--- a/include/loc/_ctype.h
+++ b/include/loc/_ctype.h
@@ -25,7 +25,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 2001-2005 Rogue Wave Software.
+ * Copyright 2001-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -541,7 +541,11 @@
inline char
ctype<wchar_t>::narrow (char_type __c, char __dfault) const
{
- const _RWSTD_SIZE_T __inx = _RWSTD_STATIC_CAST (_RWSTD_UWCHAR_INT_T, __c);
+ // carefully convert wchar_t to the unsigned form of its
+ // underlying integer type, avoiding sign extension and
+ // similar issues
+ const _RWSTD_UWCHAR_INT_T __inx =
+ _RWSTD_STATIC_CAST (_RWSTD_UWCHAR_INT_T, __c);
// optimize away all but the first call to the virtual do_widen()
if ( __inx < sizeof _C_narrow_tab / sizeof *_C_narrow_tab
diff --git a/include/rw/_iosfailure.h b/include/rw/_iosfailure.h
index c8f0718..4eed019 100644
--- a/include/rw/_iosfailure.h
+++ b/include/rw/_iosfailure.h
@@ -25,7 +25,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -56,11 +56,25 @@
};
-struct _RWSTD_EXPORT __rw_badbit_set: __rw_failure { };
+// (optionally) thrown when stream sets badbit
+struct _RWSTD_EXPORT __rw_badbit_set: __rw_failure
+{
+ virtual ~__rw_badbit_set () _THROWS (());
+};
-struct _RWSTD_EXPORT __rw_eofbit_set: __rw_failure { };
-struct _RWSTD_EXPORT __rw_failbit_set: __rw_failure { };
+// (optionally) thrown when stream sets eofbit
+struct _RWSTD_EXPORT __rw_eofbit_set: __rw_failure
+{
+ virtual ~__rw_eofbit_set () _THROWS (());
+};
+
+
+// (optionally) thrown when stream sets failbit
+struct _RWSTD_EXPORT __rw_failbit_set: __rw_failure
+{
+ virtual ~__rw_failbit_set () _THROWS (());
+};
} // namespace __rw
diff --git a/src/catalog.cpp b/src/catalog.cpp
index ec64f15..5c24a69 100644
--- a/src/catalog.cpp
+++ b/src/catalog.cpp
@@ -140,6 +140,8 @@
__rw_catlist[j-1] = __rw_catlist[j];
if (j < __rw_catlist.size())
__rw_catlist[j] = 0;
+ else
+ __rw_catlist[__rw_catlist.size () - 1] = 0;
return 0;
}
return -1;
diff --git a/src/exception.cpp b/src/exception.cpp
index 3b75c2b..8adc4e4 100644
--- a/src/exception.cpp
+++ b/src/exception.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -936,8 +936,10 @@
}
-// outline to reduce code bloat caused by compilers that emit the vtbl
-// in every translation unit containing the definition of the class
+// trivial dtors outlined to reduce code bloat caused by compilers that
+// emit the vtbl in every translation unit containing the definition of
+// the class
+
// virtual dtor
/* virtual */ __rw_failure::~__rw_failure () _THROWS (())
{
@@ -945,4 +947,22 @@
}
+/* virtual */ __rw_badbit_set::~__rw_badbit_set () _THROWS (())
+{
+ // no-op
+}
+
+
+/* virtual */ __rw_eofbit_set::~__rw_eofbit_set () _THROWS (())
+{
+ // no-op
+}
+
+
+/* virtual */ __rw_failbit_set::~__rw_failbit_set () _THROWS (())
+{
+ // no-op
+}
+
+
} // namespace __rw
diff --git a/src/fpclass.h b/src/fpclass.h
new file mode 100644
index 0000000..80fdb65
--- /dev/null
+++ b/src/fpclass.h
@@ -0,0 +1,270 @@
+/***************************************************************************
+ *
+ * fpclass.h - definitions of floating point classification functions
+ * mirrorring those defined by C99 in <math.h>
+ *
+ * $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 2008 Rogue Wave Software, Inc.
+ *
+ **************************************************************************/
+
+#ifndef _RWSTD_FPCLASS_H_INCLUDED
+#define _RWSTD_FPCLASS_H_INCLUDED
+
+#include <rw/_defs.h>
+
+#include <float.h> // for _finite(), _fpclass(), _isnan(), _copysign()
+#include <math.h> // for isfinite(), isnan(), isinf(), signbit()
+
+#ifndef _RWSTD_NO_IEEEFP_H
+# include <ieeefp.h> // for fpclass(), isnan()
+#endif // _RWSTD_NO_IEEEFP_H
+
+
+#if defined (_MSC_VER)
+
+
+inline bool
+__rw_isfinite (double val)
+{
+ return !!_finite (val);
+}
+
+
+inline bool
+__rw_signbit (double val)
+{
+ return 0 > _copysign (1., val);
+}
+
+
+inline bool
+__rw_isinf (double val)
+{
+ const int fpc = _fpclass (val);
+
+ if (_FPCLASS_NINF == fpc) {
+ // verify that __rw_signbit() correctly determines
+ // the sign of negative infinity
+ _RWSTD_ASSERT (__rw_signbit (val));
+ return true;
+ }
+ else if (_FPCLASS_PINF == fpc) {
+ // verify that __rw_signbit() correctly determines
+ // the sign of positive infinity
+ _RWSTD_ASSERT (!__rw_signbit (val));
+ return true;
+ }
+
+ return false;
+}
+
+
+inline bool
+__rw_isnan (double val)
+{
+ return !!_isnan (val);
+}
+
+
+inline bool __rw_isqnan (double val)
+{
+ return _FPCLASS_QNAN == _fpclass (val);
+}
+
+
+inline bool __rw_issnan (double val)
+{
+ return _FPCLASS_SNAN == _fpclass (val);
+}
+
+
+#elif defined (_RWSTD_OS_SUNOS)
+
+inline bool
+__rw_isfinite (double val)
+{
+ return !!finite (val);
+}
+
+
+inline bool
+__rw_signbit (double val)
+{
+ // implement own signbit() to avoid dragging in libm or libsunmath
+ return _RWSTD_REINTERPRET_CAST (const _RWSTD_UINT64_T&, val) >> 63;
+}
+
+
+inline bool
+__rw_isinf (double val)
+{
+ const int fpc = fpclass (val);
+
+ if (FP_NINF == fpc) {
+ // verify that __rw_signbit() correctly determines
+ // the sign of negative infinity
+ _RWSTD_ASSERT (__rw_signbit (val));
+ return true;
+ }
+ else if (FP_PINF == fpc) {
+ // verify that __rw_signbit() correctly determines
+ // the sign of positive infinity
+ _RWSTD_ASSERT (!__rw_signbit (val));
+ return true;
+ }
+
+ return false;
+}
+
+
+inline bool
+__rw_isnan (double val)
+{
+ return 0 != isnan (val);
+}
+
+
+inline bool
+__rw_isqnan (double val)
+{
+ return FP_QNAN == fpclass (val);
+}
+
+
+inline bool
+__rw_issnan (double val)
+{
+ return FP_SNAN == fpclass (val);
+}
+
+
+#elif defined (fpclassify)
+
+
+inline bool
+__rw_isfinite (double val)
+{
+ return !!isfinite (val);
+}
+
+
+inline bool
+__rw_signbit (double val)
+{
+ return !!signbit (val);
+}
+
+
+inline bool
+__rw_isinf (double val)
+{
+ return !!isinf (val);
+}
+
+
+inline bool
+__rw_isnan (double val)
+{
+ return !!isnan (val);
+}
+
+
+inline bool
+__rw_isqnan (double)
+{
+ return false;
+}
+
+
+inline bool
+__rw_issnan (double)
+{
+ return false;
+}
+
+#else
+
+inline bool __rw_isfinite (double) { return true; }
+
+inline bool __rw_signbit (double) { return false; }
+
+inline bool __rw_isinf (double) { return false; }
+
+inline bool __rw_isnan (double) { return false; }
+
+inline bool __rw_isqnan (double) { return false; }
+
+inline bool __rw_issnan (double) { return false; }
+
+#endif
+
+
+inline bool __rw_isfinite (float) { return true; }
+
+inline bool __rw_signbit (float) { return false; }
+
+inline bool __rw_isinf (float) { return false; }
+
+inline bool __rw_isnan (float) { return false; }
+
+inline bool __rw_isqnan (float) { return false; }
+
+inline bool __rw_issnan (float) { return false; }
+
+
+#ifndef _RWSTD_NO_LONG_DOUBLE
+
+# if _RWSTD_DBL_SIZE == _RWSTD_LDBL_SIZE
+
+inline bool __rw_isfinite (long double x) { return __rw_isfinite (double (x)); }
+
+inline bool __rw_signbit (long double x) { return __rw_signbit (double (x)); }
+
+inline bool __rw_isinf (long double x) { return __rw_isinf (double (x)); }
+
+inline bool __rw_isnan (long double x) { return __rw_isnan (double (x)); }
+
+inline bool __rw_isqnan (long double x) { return __rw_isqnan (double (x)); }
+
+inline bool __rw_issnan (long double x) { return __rw_issnan (double (x)); }
+
+# else // _RWSTD_DBL_SIZE != _RWSTD_LDBL_SIZE
+
+inline bool __rw_isfinite (long double) { return true; }
+
+inline bool __rw_signbit (long double) { return false; }
+
+inline bool __rw_isinf (long double) { return false; }
+
+inline bool __rw_isnan (long double) { return false; }
+
+inline bool __rw_isqnan (long double) { return false; }
+
+inline bool __rw_issnan (long double) { return false; }
+
+# endif // _RWSTD_DBL_SIZE == _RWSTD_LDBL_SIZE
+
+#endif // _RWSTD_NO_LONG_DOUBLE
+
+
+#endif // _RWSTD_FPCLASS_H_INCLUDED
diff --git a/src/limits.cpp b/src/limits.cpp
index 3c72c34..187617f 100644
--- a/src/limits.cpp
+++ b/src/limits.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -31,12 +31,17 @@
#include <rw/_defs.h>
// define generic template and specializations
-#include <limits>
+// use the quoted form of the #include directive to fool Sun C++
+// otherwise the compiler fails to #include the header twice,
+// most likely because it makes assumptions about headers with
+// (C++) standard names
+#include "limits"
#if _MSC_VER != 1300 // working around an MSVC 7.0 bug (PR #26562)
# undef _RWSTD_LIMITS_INCLUDED
# define _RWSTD_DEFINE_EXPORTS
// define static data members of specializations
-# include <limits>
+ // again, use the quoted form of the #include directive
+# include "limits"
#endif // MSVC != 7.0
diff --git a/src/messages.cpp b/src/messages.cpp
index ad91a82..e9866f7 100644
--- a/src/messages.cpp
+++ b/src/messages.cpp
@@ -70,6 +70,14 @@
} loc;
};
+struct __rw_open_cat_page
+{
+ static const size_t _C_size = 8;
+
+ __rw_open_cat_page* _C_next; // next page
+ __rw_open_cat_data _C_data [_C_size];
+};
+
// manages a global, per-process repository of open catalogs according
// to the following table:
@@ -90,21 +98,25 @@
static __rw_open_cat_data*
__rw_manage_cat_data (int &cat, __rw_open_cat_data *pcat_data)
{
- // a per-process array of catalog data structs
- static __rw_open_cat_data catalog_buf [8];
- static __rw_open_cat_data* catalogs = catalog_buf;
+ // a per-process array of pointers to catalog data structs
+ static __rw_open_cat_data* catalog_buf [__rw_open_cat_page::_C_size];
+ static __rw_open_cat_data** catalogs = 0;
+
+ // first page of a per-process list of pages of catalog data structs
+ static __rw_open_cat_page catalog_page;
static size_t n_catalogs = 0;
static size_t catalog_bufsize = sizeof catalog_buf / sizeof *catalog_buf;
static size_t largest_cat = 0;
- static int init = 0;
-
- if (0 == init) {
+ if (!catalogs) {
+
for (size_t i = 0; i < catalog_bufsize; ++i) {
- catalogs [i].catd = _RWSTD_BAD_CATD;
+ catalog_page._C_data [i].catd = _RWSTD_BAD_CATD;
+ catalog_buf [i] = &catalog_page._C_data [i];
}
- init = 1;
+
+ catalogs = catalog_buf;
}
if (-1 == cat) {
@@ -115,27 +127,40 @@
if (pcat_data) {
if (n_catalogs == catalog_bufsize) {
- // reallocate buffer of facet pointers
- __rw_open_cat_data* const tmp =
- new __rw_open_cat_data[n_catalogs * 2];
+ // allocate new page of catalog data
+ __rw_open_cat_page* const page =
+ new __rw_open_cat_page;
- memcpy (tmp, catalogs, n_catalogs * sizeof *tmp);
+ // insert new page into singly-linked page list
+ page->_C_next = catalog_page._C_next;
+ catalog_page._C_next = page;
+
+ // initialize new page
+ for (size_t i = 0; i < __rw_open_cat_page::_C_size; ++i) {
+ page->_C_data [i].catd = _RWSTD_BAD_CATD;
+ }
+
+ // rwallocate buffer of catalog data pointers
+ __rw_open_cat_data** const data =
+ new __rw_open_cat_data* [n_catalogs + __rw_open_cat_page::_C_size];
+
+ memcpy (data, catalogs, n_catalogs * sizeof *data);
if (catalogs != catalog_buf)
delete[] catalogs;
- catalogs = tmp;
- catalog_bufsize *= 2;
+ catalogs = data;
+ catalog_bufsize += __rw_open_cat_page::_C_size;
- for (size_t i = n_catalogs; i < catalog_bufsize; ++i) {
- catalogs [i].catd = _RWSTD_BAD_CATD;
+ for (size_t i = 0; i < __rw_open_cat_page::_C_size; ++i) {
+ catalogs [n_catalogs + i] = &page->_C_data [i];
}
cat = int (n_catalogs);
- memcpy (&catalogs [cat].loc, &pcat_data->loc,
- sizeof (_STD::locale));
- catalogs [cat].catd = pcat_data->catd;
+ catalogs [cat]->catd = pcat_data->catd;
+ memcpy (&catalogs [cat]->loc, &pcat_data->loc,
+ sizeof (_STD::locale));
if (size_t (cat) > largest_cat)
largest_cat = size_t (cat);
@@ -145,38 +170,42 @@
else {
// find the first open slot and use it.
cat = 0;
- while (catalogs [cat].catd != _RWSTD_BAD_CATD) {
+ while (catalogs [cat]->catd != _RWSTD_BAD_CATD) {
++cat;
}
+ catalogs [cat]->catd = pcat_data->catd;
+ memcpy (&catalogs [cat]->loc, &pcat_data->loc,
+ sizeof (_STD::locale));
+
if (size_t (cat) > largest_cat)
largest_cat = size_t (cat);
- memcpy (&catalogs [cat].loc, &pcat_data->loc,
- sizeof (_STD::locale));
-
- catalogs [cat].catd = pcat_data->catd;
++n_catalogs;
}
}
}
else {
+
if (0 == pcat_data) {
// find struct and return it
if (size_t (cat) < catalog_bufsize)
- return catalogs + cat;
+ return catalogs [cat];
return 0;
}
// initialize the struct to an invalid state
--n_catalogs;
- catalogs [cat].catd = _RWSTD_BAD_CATD;
+ catalogs [cat]->catd = _RWSTD_BAD_CATD;
+
if (size_t (cat) == largest_cat) {
// find the next smallest valid slot
+ largest_cat = 0;
+
for (int i = cat; i >= 0; --i) {
- if (catalogs [i].catd != _RWSTD_BAD_CATD) {
+ if (catalogs [i]->catd != _RWSTD_BAD_CATD) {
largest_cat = size_t (i);
break;
}
@@ -186,11 +215,9 @@
sizeof catalog_buf / sizeof *catalog_buf;
if ((largest_cat < bufsize / 2) && (catalogs != catalog_buf)) {
-
// when there are no more open catalogs indexed beyond
- // second half of the statically allocated repository, copy
- // the open catalogs back into the statically allocated
- // repository.
+ // second half of the static pointer repository, copy
+ // the open catalog pointers back into the repository.
catalog_bufsize = bufsize;
@@ -198,7 +225,19 @@
catalog_bufsize * sizeof (*catalogs));
delete[] catalogs;
+
catalogs = catalog_buf;
+
+ // remove all pages, they're not in use
+ while (catalog_page._C_next)
+ {
+ // remove next page from page list
+ __rw_open_cat_page* page = catalog_page._C_next;
+ catalog_page._C_next = page->_C_next;
+
+ // deallocate that page
+ delete page;
+ }
}
}
}
diff --git a/src/mman.cpp b/src/mman.cpp
index eb42e37..5a3a10c 100644
--- a/src/mman.cpp
+++ b/src/mman.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 2001-2006 Rogue Wave Software.
+ * Copyright 2001-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -36,9 +36,9 @@
#include <sys/stat.h>
-#ifndef _MSC_VER
+#ifndef _RWSTD_NO_MMAP
# include <sys/mman.h>
-#else
+#elif defined (_WIN32)
# include <windows.h>
# include <io.h>
#endif // _MSC_VER
@@ -69,12 +69,17 @@
*size = sb.st_size;
-#if !defined(_MSC_VER)
- const int fd = open (fname, O_RDONLY);
+#ifndef _WIN32
+ const int fd = open (fname, O_RDONLY);
+
if (-1 == fd)
return 0;
+#endif // _WIN32
+
+#ifndef _RWSTD_NO_MMAP
+
// On HPUX systems MAP_SHARED will prevent a second mapping of the same
// file if the regions are overlapping; one solution is to make the
// mapping private.
@@ -92,7 +97,9 @@
if (MAP_FAILED == data) // failure
return 0;
-#else
+
+#elif defined (_WIN32)
+
HANDLE mmf =
CreateFile (fname, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
@@ -114,6 +121,23 @@
CloseHandle (mmf);
CloseHandle (mmfv);
+#else // no mmap() or equivalent
+
+# ifndef _RWSTD_NO_MUNMAP
+# define _RWSTD_NO_MUNMAP
+# endif // _RWSTD_NO_MUNMAP
+
+ // read() takes a size_t argument, convert off_t to it
+ const size_t mapsize = size_t (sb.st_size);
+
+ void* data = operator new (mapsize);
+ const ssize_t nread = read (fd, data, mapsize);
+
+ if (size_t (nread) != mapsize) {
+ operator delete (data);
+ data = 0;
+ }
+
#endif // _MSC_VER
return data;
@@ -128,10 +152,12 @@
void* pv = _RWSTD_CONST_CAST (void*, pcv);
// POSIX munmap() takes a void*, but not all platforms conform
-#ifndef _MSC_VER
+#ifndef _RWSTD_NO_MUNMAP
munmap (_RWSTD_STATIC_CAST (_RWSTD_MUNMAP_ARG1_T, pv), size);
-#else
+#elif defined (_WIN32)
UnmapViewOfFile (pv);
+#else // no munmap()
+ operator delete (pv);
#endif // _MSC_VER
}
diff --git a/src/num_put.cpp b/src/num_put.cpp
index a9d9e5e..5d2e7c4 100644
--- a/src/num_put.cpp
+++ b/src/num_put.cpp
@@ -34,15 +34,9 @@
#include <stdio.h> // for snprintf()
#include <string.h> // for memmove(), memset()
-#include <float.h> // for _finite(), _fpclass(), _isnan(), _copysign()
-#include <math.h> // for isfinite(), isnan(), isinf(), signbit()
-
-#ifndef _RWSTD_NO_IEEEFP_H
-# include <ieeefp.h> // for fpclass(), isnan()
-#endif // _RWSTD_NO_IEEEFP_H
-
#include <loc/_num_put.h>
+#include "fpclass.h" // for __rw_isfinite(), ...
#include "strtol.h" // for __rw_digit_map
#include "punct.h" // for __rw_get_stdio_fmat
@@ -80,161 +74,14 @@
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-#if defined (_MSC_VER)
-
-inline bool __rw_isfinite (double val) { return !!_finite (val); }
-
-inline bool __rw_signbit (double val) { return 0 > _copysign (1., val); }
-
-inline bool __rw_isinf (double val) {
- const int fpc = _fpclass (val);
-
- if (_FPCLASS_NINF == fpc) {
- // verify that __rw_signbit() correctly determines
- // the sign of negative infinity
- _RWSTD_ASSERT (__rw_signbit (val));
- return true;
- }
- else if (_FPCLASS_PINF == fpc) {
- // verify that __rw_signbit() correctly determines
- // the sign of positive infinity
- _RWSTD_ASSERT (!__rw_signbit (val));
- return true;
- }
-
- return false;
-}
-
-inline bool __rw_isnan (double val) { return !!_isnan (val); }
-
-inline bool __rw_isqnan (double val) {
- return _FPCLASS_QNAN == _fpclass (val);
-}
-
-inline bool __rw_issnan (double val) {
- return _FPCLASS_SNAN == _fpclass (val);
-}
-
-#elif defined (_RWSTD_OS_SUNOS)
-
-inline bool __rw_isfinite (double val) { return !!finite (val); }
-
-inline bool __rw_signbit (double val)
-{
- // implement own signbit() to avoid dragging in libm or libsunmath
- return _RWSTD_REINTERPRET_CAST (const _RWSTD_UINT64_T&, val) >> 63;
-}
-
-inline bool __rw_isinf (double val) {
- const int fpc = fpclass (val);
-
- if (FP_NINF == fpc) {
- // verify that __rw_signbit() correctly determines
- // the sign of negative infinity
- _RWSTD_ASSERT (__rw_signbit (val));
- return true;
- }
- else if (FP_PINF == fpc) {
- // verify that __rw_signbit() correctly determines
- // the sign of positive infinity
- _RWSTD_ASSERT (!__rw_signbit (val));
- return true;
- }
-
- return false;
-}
-
-inline bool __rw_isnan (double val) { return 0 != isnan (val); }
-
-inline bool __rw_isqnan (double val) { return FP_QNAN == fpclass (val); }
-
-inline bool __rw_issnan (double val) { return FP_SNAN == fpclass (val); }
-
-#elif defined (fpclassify)
-
-inline bool __rw_isfinite (double val) { return !!isfinite (val); }
-
-inline bool __rw_signbit (double val) { return !!signbit (val); }
-
-inline bool __rw_isinf (double val) { return !!isinf (val); }
-
-inline bool __rw_isnan (double val) { return !!isnan (val); }
-
-inline bool __rw_isqnan (double) { return false; }
-
-inline bool __rw_issnan (double) { return false; }
-
-#else
-
-inline bool __rw_isfinite (double) { return true; }
-
-inline bool __rw_signbit (double) { return false; }
-
-inline bool __rw_isinf (double) { return false; }
-
-inline bool __rw_isnan (double) { return false; }
-
-inline bool __rw_isqnan (double) { return false; }
-
-inline bool __rw_issnan (double) { return false; }
-
-#endif
-
-
-inline bool __rw_isfinite (float) { return true; }
-
-inline bool __rw_signbit (float) { return false; }
-
-inline bool __rw_isinf (float) { return false; }
-
-inline bool __rw_isnan (float) { return false; }
-
-inline bool __rw_isqnan (float) { return false; }
-
-inline bool __rw_issnan (float) { return false; }
-
-
-#ifndef _RWSTD_NO_LONG_DOUBLE
-
-# if _RWSTD_DBL_SIZE == _RWSTD_LDBL_SIZE
-
-inline bool __rw_isfinite (long double x) { return __rw_isfinite (double (x)); }
-
-inline bool __rw_signbit (long double x) { return __rw_signbit (double (x)); }
-
-inline bool __rw_isinf (long double x) { return __rw_isinf (double (x)); }
-
-inline bool __rw_isnan (long double x) { return __rw_isnan (double (x)); }
-
-inline bool __rw_isqnan (long double x) { return __rw_isqnan (double (x)); }
-
-inline bool __rw_issnan (long double x) { return __rw_issnan (double (x)); }
-
-# else // _RWSTD_DBL_SIZE != _RWSTD_LDBL_SIZE
-
-inline bool __rw_isfinite (long double) { return true; }
-
-inline bool __rw_signbit (long double) { return false; }
-
-inline bool __rw_isinf (long double) { return false; }
-
-inline bool __rw_isnan (long double) { return false; }
-
-inline bool __rw_isqnan (long double) { return false; }
-
-inline bool __rw_issnan (long double) { return false; }
-
-# endif // _RWSTD_DBL_SIZE == _RWSTD_LDBL_SIZE
-
-#endif // _RWSTD_NO_LONG_DOUBLE
-
-
static int
__rw_fmat_infinite (char *buf, size_t bufsize, double val, unsigned flags)
{
_RWSTD_ASSERT (!__rw_isfinite (val));
_RWSTD_ASSERT (5 <= bufsize);
+ _RWSTD_UNUSED (bufsize);
+
char* end = buf;
const bool cap = !!(flags & _RWSTD_IOS_UPPERCASE);
diff --git a/src/ti_num_get.cpp b/src/ti_num_get.cpp
index 2105dae..50b114f 100644
--- a/src/ti_num_get.cpp
+++ b/src/ti_num_get.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -47,6 +47,16 @@
#define TARGS_C <char, _RWSTD_ISTREAMBUF_ITER (char) >
+
+#if 6 == _RWSTD_HP_aCC_MAJOR
+ // silence the useless HP aCC 6 remark 4244: extern storage class
+ // used with a function definition on the "extern _RWSTD_EXPORT"
+ // macro argument below where the redundant "extern" is there to
+ // silence HP aCC 3 Warning (suggestion) 933: Null macro argument #1
+# pragma diag_suppress 4244
+#endif // aCC 6
+
+
_RWSTD_SPECIALIZE_FACET_ID (num_get, TARGS_C);
_RWSTD_DEFINE_FACET_FACTORY (extern _RWSTD_EXPORT, num_get, TARGS_C, num_get);
_RWSTD_SPECIALIZE_USE_FACET (num_get);
diff --git a/src/ti_num_put.cpp b/src/ti_num_put.cpp
index 53bf9fe..40c477c 100644
--- a/src/ti_num_put.cpp
+++ b/src/ti_num_put.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -45,6 +45,16 @@
#define TARGS_C <char, _RWSTD_OSTREAMBUF_ITER (char) >
+
+#if 6 == _RWSTD_HP_aCC_MAJOR
+ // silence the useless HP aCC 6 remark 4244: extern storage class
+ // used with a function definition on the "extern _RWSTD_EXPORT"
+ // macro argument below where the redundant "extern" is there to
+ // silence HP aCC 3 Warning (suggestion) 933: Null macro argument #1
+# pragma diag_suppress 4244
+#endif // aCC 6
+
+
_RWSTD_SPECIALIZE_FACET_ID (num_put, TARGS_C);
_RWSTD_DEFINE_FACET_FACTORY (extern _RWSTD_EXPORT, num_put, TARGS_C, num_put);
_RWSTD_SPECIALIZE_USE_FACET (num_put);
diff --git a/src/ti_numpunct.cpp b/src/ti_numpunct.cpp
index 85ce67c..3240f10 100644
--- a/src/ti_numpunct.cpp
+++ b/src/ti_numpunct.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -45,6 +45,15 @@
#include "use_facet.h"
+#if 6 == _RWSTD_HP_aCC_MAJOR
+ // silence the useless HP aCC 6 remark 4244: extern storage class
+ // used with a function definition on the "extern _RWSTD_EXPORT"
+ // macro argument below where the redundant "extern" is there to
+ // silence HP aCC 3 Warning (suggestion) 933: Null macro argument #1
+# pragma diag_suppress 4244
+#endif // aCC 6
+
+
_RWSTD_SPECIALIZE_FACET_ID (numpunct, <char>);
_RWSTD_DEFINE_FACET_FACTORY (extern _RWSTD_EXPORT, numpunct, <char>, numpunct);
_RWSTD_SPECIALIZE_USE_FACET (numpunct);
diff --git a/src/version.cpp b/src/version.cpp
index 7127093..d2b14b0 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -35,6 +35,7 @@
#ifdef _RWSTD_VER_STR
extern const char __rw_ident[] = {
+ // %Z% keyword ("@(#)") retrieved by the POSIX what utility
"@(#) Apache C++ Standard Library version " _RWSTD_VER_STR
};
diff --git a/tests/include/rw_thread.h b/tests/include/rw_thread.h
index 621a7d6..9a19a80 100644
--- a/tests/include/rw_thread.h
+++ b/tests/include/rw_thread.h
@@ -33,6 +33,8 @@
extern "C" {
+ typedef void* rw_thread_proc (void*);
+} // extern "C"
struct rw_thread_attr_t;
@@ -48,7 +50,7 @@
_TEST_EXPORT int
rw_thread_create (rw_thread_t*,
rw_thread_attr_t*,
- void* (*)(void*),
+ rw_thread_proc*,
void*);
@@ -62,6 +64,13 @@
// array with their id's; if (tidarray == 0), waits for all
// threads to join and fills the aragarray with the result
// returned from each thread
+// if (timeout != 0), then a timer will be started, and the function
+// rw_thread_pool_timeout_expired() will return true after that number
+// of seconds has passed. there is only one timer, so use timeouts
+// with caution. if you provide tidarray, you should join threads
+// before starting another pool, otherwise threads from the first
+// pool may not exit until the threads from a later second pool are
+// signalled to stop.
// if (nthreads == SIZE_MAX), sets nthreads to the positive result
// of rw_get_processors() plus 1, or to 2 otherwise
// returns 0 on success, or a non-zero value indicating the thread
@@ -70,15 +79,20 @@
rw_thread_pool (rw_thread_t* /* tidarray */,
_RWSTD_SIZE_T /* nthreads */,
rw_thread_attr_t* /* attr */,
- void* (*)(void*) /* thr_proc */,
- void** /* argarray */);
+ rw_thread_proc* /* thr_proc */,
+ void** /* argarray */,
+ _RWSTD_SIZE_T /* timeout */ = 0);
+
+// returns non-zero if the thread timeout flag has been set. should
+// be polled periodically by threads created by rw_thread_pool() so
+// that they know that the soft timeout has expired
+// see notes above for details
+_TEST_EXPORT int
+rw_thread_pool_timeout_expired ();
// returns the number of logical processors/cores on the system,
// or -1 on error
_TEST_EXPORT int
rw_get_cpus ();
-
-} // extern "C"
-
#endif // RW_RWTHREAD_H_INCLUDED
diff --git a/tests/iostream/27.filebuf.cpp b/tests/iostream/27.filebuf.cpp
new file mode 100644
index 0000000..9765487
--- /dev/null
+++ b/tests/iostream/27.filebuf.cpp
@@ -0,0 +1,2804 @@
+/***************************************************************************
+ *
+ * 27.filebuf.cpp - test exercising class template basic_filebuf
+ *
+ * $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 1994-2008 Rogue Wave Software.
+ *
+ **************************************************************************/
+
+#include <cerrno> // for errno
+#include <csignal> // for signal()
+#include <cstdio> // for FILE, fopen(), remove()
+#include <cstring> // for memcmp()
+#include <cwchar> // for mbstate_t
+
+#include <fstream>
+
+#if !defined (_WIN32) && !defined (_WIN64)
+
+# ifdef __SUNPRO_CC
+ // working around a SunOS/SunPro bug (PR #26255)
+# undef _TIME_T
+# endif
+
+# include <cstdlib> // for exit()
+# include <fcntl.h> // for open(), O_XXX constants
+# include <unistd.h> // for fork()
+# include <sys/stat.h> // for mkfifo()
+# include <sys/types.h> // for pid_t
+# include <sys/wait.h> // for wait()
+#else
+# include <fcntl.h> // for O_XXX constants
+# include <io.h> // for open()
+#endif // _WIN{32,64}
+
+#ifndef SIGPIPE
+# define SIGPIPE 13 /* HP-UX, Linux, and SunOS value */
+#endif // SIGPIPE
+
+#include <driver.h>
+#include <file.h>
+#include <valcmp.h>
+
+
+#define REMOVE_FILE(tmpfname) \
+ rw_warn (0 == std::remove (tmpfname), __FILE__, __LINE__, \
+ "std::remove(\"%s\") failed: %m", tmpfname)
+
+/**************************************************************************/
+
+
+template <class charT>
+static void
+test_ctors (const char* tname)
+{
+ typedef std::basic_filebuf<charT, std::char_traits<charT> > Filebuf;
+
+ int fdcount [2];
+ int next_fd [2];
+
+ //////////////////////////////////////////////////////////////////
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::basic_filebuf()", tname);
+
+ next_fd [0] = rw_nextfd (fdcount + 0);
+
+ {
+ Filebuf fb;
+
+ // verify the postcondition in 27.8.1.2, p2
+ rw_assert (!fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::basic_filebuf().is_open() == "
+ "false, got true", tname);
+
+ // verify that no file descriptor has been allocated
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ rw_assert (next_fd [0] == next_fd [1] && fdcount [0] == fdcount [1],
+ __FILE__, __LINE__,
+ "%d file descriptor leak(s) detected after construction",
+ fdcount [1] - fdcount [0]);
+ }
+
+ // verify that no file descriptor has been closed
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ //////////////////////////////////////////////////////////////////
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::~basic_filebuf()", tname);
+
+ rw_assert (next_fd [0] == next_fd [1] && fdcount [0] == fdcount [1],
+ __FILE__, __LINE__,
+ "%d file descriptor leak(s) detected after destruction",
+ fdcount [1] - fdcount [0]);
+
+
+ const char* const tmpfname = rw_tmpnam (0);
+ if (!tmpfname) {
+ return;
+ }
+
+ {
+ Filebuf fb;
+
+ next_fd [0] = rw_nextfd (fdcount + 0);
+
+ Filebuf *tmp = fb.open (tmpfname, std::ios::out);
+
+ // verify that open() succeeds and allocates a file descriptor
+ rw_assert (0 != tmp, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open(\"%s\", std::ios_base::out) "
+ "failed", tname, tmpfname);
+
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ rw_assert (next_fd [0] != next_fd [1]
+ && fdcount [0] + 1 == fdcount [1], __FILE__, __LINE__,
+ "%d file descriptor mismatch detected after open()",
+ fdcount [1] - fdcount [0]);
+ }
+
+ // verify that dtor closes the file descriptor
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ rw_assert (next_fd [0] == next_fd [1] && fdcount [0] == fdcount [1],
+ __FILE__, __LINE__,
+ "%d file descriptor leak(s) detected after destruction",
+ fdcount [1] - fdcount [0]);
+
+
+#ifndef _RWSTD_NO_EXT_FILEBUF
+
+ //////////////////////////////////////////////////////////////////
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::basic_filebuf(FILE*) "
+ "[extension]", tname);
+
+# ifdef stdin
+
+ {
+ std::FILE* const fp = std::fopen (tmpfname, "w");
+
+ next_fd [0] = rw_nextfd (fdcount + 0);
+
+ // object takes over the ownership of the file pointer
+ Filebuf fb (fp);
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::basic_filebuf (FILE*).is_open() "
+ "== true, got false", tname);
+
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ rw_assert (next_fd [0] == next_fd [1] && fdcount [0] == fdcount [1],
+ __FILE__, __LINE__,
+ "%d file descriptor mismatch detected after open()",
+ fdcount [1] - fdcount [0]);
+ }
+
+ // verify that dtor closes the file descriptor
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ rw_assert (fdcount [0] == fdcount [1] + 1, __FILE__, __LINE__,
+ "%d file descriptor leak(s) detected after destruction",
+ fdcount [1] - fdcount [0]);
+
+# else // if !defined (stdin)
+
+ rw_assert (false, __FILE__, __LINE__,
+ "macro stdin unexpectedly not #defined, "
+ "basic_filebuf<%s>::basic_filebuf (FILE*) "
+ "extension not tested", tname);
+
+# endif // stdin
+
+ //////////////////////////////////////////////////////////////////
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::basic_filebuf(int) "
+ "[extension]", tname);
+
+ Filebuf *pfb = 0;
+
+ {
+ std::FILE* const fp = std::fopen (tmpfname, "w");
+
+ // object takes over the ownership of the file pointer
+ pfb = new Filebuf (fp);
+
+ next_fd [0] = rw_nextfd (fdcount + 0);
+
+ // object takes over the ownership of the file descriptor
+ Filebuf fb (pfb->fd ());
+
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::basic_filebuf (int).is_open() "
+ "== true, got false", tname);
+
+ rw_assert (next_fd [0] == next_fd [1] && fdcount [0] == fdcount [1],
+ __FILE__, __LINE__,
+ "%d file descriptor mismatch detected after open()",
+ fdcount [1] - fdcount [0]);
+ }
+
+ // verify that dtor closes the file descriptor
+ next_fd [1] = rw_nextfd (fdcount + 1);
+
+ rw_assert (fdcount [0] == fdcount [1] + 1, __FILE__, __LINE__,
+ "%d file descriptor leak(s) detected after destruction",
+ fdcount [1] - fdcount [0]);
+
+ delete pfb;
+
+#endif // _RWSTD_NO_EXT_FILEBUF
+
+ REMOVE_FILE (tmpfname);
+}
+
+/***************************************************************************/
+
+extern "C" {
+
+// instead of calling signal(SIGPIPE, SIG_IGN)
+void ignore_signal (int)
+{
+ std::signal (SIGPIPE, ignore_signal);
+}
+
+} // extern "C"
+
+
+template <class charT>
+static void
+test_open (const char* tname)
+{
+ typedef std::basic_filebuf<charT, std::char_traits<charT> > Filebuf;
+
+ const char* const tmpfname = rw_tmpnam (0);
+
+ if (!tmpfname) {
+ return;
+ }
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::is_open ()", tname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::open (const char*, "
+ "ios_base::openmode)", tname);
+
+ /*****************************************************************
+
+ Table 92
+
+ +-----+-----+-----+-----+-----+-----+
+ | bin | in | out |trunc| app |stdio|
+ +=====+=====+=====+=====+=====+=====+
+ | | | + | | | "w" |
+ +-----+-----+-----+-----+-----+-----+
+ | | | + | | + | "a" |
+ +-----+-----+-----+-----+-----+-----+
+ | | | + | + | | "w" |
+ +-----+-----+-----+-----+-----+-----+
+ | | + | | | | "r" |
+ +-----+-----+-----+-----+-----+-----+
+ | | + | + | | |"r+" |
+ +-----+-----+-----+-----+-----+-----+
+ | | + | + | + | |"w+" |
+ +=====+=====+=====+=====+=====+=====+
+ | + | | + | | |"wb" |
+ +-----+-----+-----+-----+-----+-----+
+ | + | | + | | + |"ab" |
+ +-----+-----+-----+-----+-----+-----+
+ | + | | + | + | |"wb" |
+ +-----+-----+-----+-----+-----+-----+
+ | + | + | | | |"rb" |
+ +-----+-----+-----+-----+-----+-----+
+ | + | + | + | | |"r+b"|
+ +-----+-----+-----+-----+-----+-----+
+ | + | + | + | + | |"w+b"|
+ +-----+-----+-----+-----+-----+-----+
+
+ r open text file for reading
+ w truncate to zero length or create text file for writing
+ a append; open or create text file for writing at EOF
+ rb open binary file for reading
+ wb truncate to zero length or create binary file for writing
+ ab append; open or create binary file for writing at EOF
+ r+ open text file for update (reading and writing)
+ w+ truncate to zero length or create text file for update
+ a+ append; open or create text file for update at EOF
+ r+b or rb+ open binary file for update (reading and writing)
+ w+b or wb+ truncate to zero length or create binary file for update
+ a+b or ab+ append; open or create binary file for update at EOF
+
+ ******************************************************************/
+
+#define BEGIN_MODE(openmode, ext) \
+ mode = (openmode), \
+ rw_info (0, __FILE__, __LINE__, "%{Io} %s", mode, ext)
+
+#define ASSERT_OPEN(expr, mode, txt) \
+ rw_assert (expr, __FILE__, __LINE__, \
+ "basic_filebuf<%s>::open (\"%s\", %{Io}) %s ", \
+ tname, tmpfname, mode, txt) \
+
+ std::ios_base::openmode mode;
+
+ const std::ios::openmode iomodes[] = {
+ std::ios::openmode ()
+
+#ifndef _RWSTD_NO_EXT_STDIO
+
+ , std::ios::stdio
+
+#endif // _RWSTD_NO_EXT_STDIO
+
+ };
+
+ const std::size_t niomodes = sizeof iomodes / sizeof *iomodes;
+
+ const char* buf = 0;
+ std::size_t size = 0;
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::out)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::out | iomodes [minx], "");
+
+ {
+ Filebuf ().open (tmpfname, mode);
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 != buf, mode, "failed to create a new file");
+
+ if (buf)
+ ASSERT_OPEN (!size, mode,
+ "unexpectedly created a non-empty file");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ {
+ Filebuf ().open (tmpfname, mode);
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 != buf, mode, "failed to open an existing file");
+
+ if (buf)
+ ASSERT_OPEN (!size, mode,
+ "unexpectedly created a non-empty file");
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::out | ios::app)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::out | std::ios::app | iomodes [minx], "");
+
+ REMOVE_FILE (tmpfname);
+
+ {
+ Filebuf ().open (tmpfname, mode);
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 != buf, mode, "failed to create a new file");
+
+ if (buf)
+ ASSERT_OPEN (!size, mode, "unexpectedly created a non-empty file");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ {
+ Filebuf ().open (tmpfname, mode);
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 != buf, mode, "failed to open an existing file");
+
+ if (buf)
+ ASSERT_OPEN (6 == size, mode,
+ "unexpectedly truncated a non-empty file");
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::out | ios::trunc)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::out | std::ios::trunc | iomodes [minx], "");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ {
+ // open a file for writing and truncate it to 0 size
+ Filebuf ().open (tmpfname, mode);
+ }
+
+ // read the contents of the file and verify that they are empty
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ // file must exist
+ ASSERT_OPEN (0 != buf, mode, "failed to open an existing file");
+
+ // the size of the file must be 0
+ if (buf)
+ ASSERT_OPEN (!size, mode, "failed to truncate a non-empty file");
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::nocreate)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ // ios::nocreate is meaningless by itself
+ BEGIN_MODE (std::ios::nocreate | iomodes [minx], "[extension]");
+
+ Filebuf fb;
+
+ fb.open (tmpfname, mode);
+
+ // verify that the call failed
+ ASSERT_OPEN (!fb.is_open (), mode,
+ "unexpectedly succeeded to open a non-existent file");
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::out | ios::nocreate)
+
+ BEGIN_MODE (std::ios::out | std::ios::nocreate, "[extension]");
+
+ // ios::nocreate will prevent the call to open from creating
+ // the file if it doesn't exist
+
+ REMOVE_FILE (tmpfname);
+
+ {
+ Filebuf fb;
+
+ // try to open a file that doesn't exist for output but prevent
+ // the call from creating it by setting the nocreate bit
+ fb.open (tmpfname, mode);
+
+ // verify that the call failed
+ ASSERT_OPEN (!fb.is_open (), mode,
+ "unexpectedly succeeded to open a non-existent file");
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 == buf, mode, "unexpectedly created a file");
+
+ // the same as above but with an existing file
+ rw_fwrite (tmpfname, "foobar");
+
+ {
+ Filebuf fb;
+
+ // try to open an existing file
+ fb.open (tmpfname, mode);
+
+ // verify that the call succeeded
+ ASSERT_OPEN (fb.is_open (), mode,
+ "unexpectedly succeeded to open an existing file");
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 != buf, mode, "failed to open an existing file");
+
+#ifndef _RWSTD_NO_EXT_STDIO
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::stdio| ios::out | ios::nocreate)
+
+ BEGIN_MODE (std::ios::stdio | std::ios::out | std::ios::nocreate,
+ "[extension]");
+
+ REMOVE_FILE (tmpfname);
+
+ // ios::nocreate can't be implemented with ios::stdio
+ // and the call must fail
+ {
+ Filebuf fb;
+
+ fb.open (tmpfname, mode);
+
+ // verify that the call failed
+ ASSERT_OPEN (!fb.is_open (), mode,
+ "unexpectedly succeeded to open a non-existent file");
+ }
+
+ // verify that the file wasn't created
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 == buf, mode, "unexpectedly created a file");
+
+#endif // _RWSTD_NO_EXT_STDIO
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::out | ios::nocreate | ios::trunc)
+
+ // ios::trunc has no effect on ios::nocreate
+ BEGIN_MODE (std::ios::out | std::ios::nocreate | std::ios::trunc,
+ "[extension]");
+
+ // remove file in case it was unexpectedly created above
+ std::remove (tmpfname);
+
+ {
+ Filebuf fb;
+
+ // try to open a file that doesn't exist for output but prevent
+ // the call from creating it by setting the nocreate bit
+ fb.open (tmpfname, mode);
+
+ // verify that the call failed
+ ASSERT_OPEN (!fb.is_open (), mode,
+ "unexpectedly succeeded to open a non-existent file");
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 == buf, mode, "unexpectedly created a file");
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::noreplace)
+
+ // remove file in case it was unexpectedly created above
+ std::remove (tmpfname);
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ // ios::noreplace is meaningless by itself
+ BEGIN_MODE (std::ios::noreplace | iomodes [minx], "[extension]");
+
+ Filebuf fb;
+
+ fb.open (tmpfname, mode);
+
+ // verify that the call failed
+ ASSERT_OPEN (!fb.is_open (), mode,
+ "unexpectedly succeeded to open a non-existent file");
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::out | ios::noreplace)
+
+ // ios::noreplace will cause the call to open to succeed only
+ // if the file doesn't exist, otherwise the call will fail
+ BEGIN_MODE (std::ios::out | std::ios::noreplace, "[extension]");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ {
+ Filebuf fb;
+
+ // try to open an existing file for output but prevent
+ // the call from replacing it by setting the noreplace bit
+ fb.open (tmpfname, mode);
+
+ // verify that the call failed
+ ASSERT_OPEN (!fb.is_open (), mode,
+ "unexpectedly succeeded to open an existing file");
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 != buf, mode, "unexpectedly removed an existing file");
+
+ if (buf)
+ ASSERT_OPEN (0 != size, mode, "unexpectdly truncated a non-empty file");
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::out | ios::trunc | ios::noreplace)
+
+ BEGIN_MODE (std::ios::out | std::ios::trunc | std::ios::noreplace,
+ "[extension]");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ {
+ Filebuf fb;
+
+ // try to open an existing file for output
+ fb.open (tmpfname, mode);
+
+ // verify that the call failed
+ ASSERT_OPEN (!fb.is_open (), mode,
+ "failed to open an existing file");
+ }
+
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size));
+
+ ASSERT_OPEN (0 != buf, mode, "unexpectedly removed an existing file");
+
+ if (buf)
+ ASSERT_OPEN (0 != size, mode, "failed to truncate a non-empty file");
+
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::in)
+
+ charT readbuf [256];
+ const std::size_t readbuf_size = sizeof readbuf / sizeof *readbuf;
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::in | iomodes [minx], "");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ Filebuf fb;
+
+ const charT foobar[] = { 'f', 'o', 'o', 'b', 'a', 'r' };
+
+ if (fb.open (tmpfname, mode)) {
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ std::memset (readbuf, 0, sizeof readbuf);
+ fb.sgetn (readbuf, readbuf_size);
+
+ ASSERT_OPEN (!std::memcmp (readbuf, foobar, sizeof foobar),
+ mode, "failed to open an existing file for reading");
+ }
+ else {
+ ASSERT_OPEN (0, mode, "failed to open an existing file");
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::in | ios::out)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::in | std::ios::out | iomodes [minx], "");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ Filebuf fb;
+
+ if (fb.open (tmpfname, mode)) {
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ const charT FOO[] = { 'F', 'O', 'O' };
+ const charT bar[] = { 'b', 'a', 'r' };
+
+ if (3 != fb.sputn (FOO, sizeof FOO / sizeof *FOO))
+ ASSERT_OPEN (false, mode,
+ "failed to open an existing file for writing "
+ "(sputn() failed)");
+
+ // an input operation must be separated from a
+ // preceding output operation by a seek() or flush()
+ fb.pubsync ();
+
+ std::memset (readbuf, 0, sizeof readbuf);
+ const std::streamsize got = fb.sgetn (readbuf, readbuf_size);
+
+ if (3 == got) {
+ rw_assert (!std::memcmp (readbuf, bar, sizeof bar),
+ __FILE__, __LINE__,
+ "sgetn() retrieved the wrong data)");
+ }
+ else
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn() == 3, got %td: %{*.*Ac}, "
+ "expected %{*.*Ac}",
+ got, int (sizeof (charT)), got, readbuf,
+ int (sizeof (charT)),
+ int (sizeof bar / sizeof *bar), bar);
+ }
+ else {
+ ASSERT_OPEN (0, mode, "failed to open an existing file");
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::in | ios::out | ios::trunc)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE ( std::ios::in | std::ios::out | std::ios::trunc
+ | iomodes [minx], "");
+
+ rw_fwrite (tmpfname, "foobar");
+
+ Filebuf fb;
+
+ if (fb.open (tmpfname, mode)) {
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ const charT FOO[] = { 'F', 'O', 'O' };
+
+ std::memset (readbuf, 0, sizeof readbuf);
+ if (0 != fb.sgetn (readbuf, readbuf_size))
+ ASSERT_OPEN (false, mode,
+ "failed to truncate a non-empty file");
+
+ if (3 != fb.sputn (FOO, sizeof FOO / sizeof *FOO))
+ ASSERT_OPEN (false, mode,
+ "failed to open an existing file for writing "
+ "(sputn() failed)");
+
+ // an input operation must be separated from a
+ // preceding output operation by a seek() or flush()
+ fb.pubseekoff (0, std::ios::beg);
+
+ std::memset (readbuf, 0, sizeof readbuf);
+ if (3 != fb.sgetn (readbuf, readbuf_size))
+ ASSERT_OPEN (false, mode,
+ "failed to open an existing file for reading "
+ "(sgetn() failed after a sputn())");
+
+ ASSERT_OPEN (!std::memcmp (readbuf, FOO, sizeof FOO), mode,
+ "failed to open an existing file for reading "
+ "and writing (sgetn() retrieved the wrong data)");
+ }
+ else {
+ ASSERT_OPEN (0, mode, "failed to open an existing file");
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::binary | ios::in)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::binary | std::ios::in | iomodes [minx], "");
+
+ // create a file containing various combinations of new-line
+ // and line-feed and read the file in using the ios::binary
+ // flag, expecting the original contents of the file on
+ // output (i.e., no CR/LF conversion on Win32)
+ const char bindata[] = "\nf\ro\n\ro\r\n\b\n\ra\r\rr";
+
+ // rw_fwrite() returns the number of bytes successfully written
+ size = rw_fwrite (tmpfname, bindata, sizeof bindata - 1, "wb");
+
+ Filebuf fb;
+
+ if (fb.open (tmpfname, mode)) {
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ std::memset (readbuf, 0, sizeof readbuf);
+ const std::streamsize N = fb.sgetn (readbuf, readbuf_size);
+
+ if (N != std::streamsize (size))
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %d) == %d, "
+ "got %d", tname, readbuf,
+ readbuf_size, size, N);
+
+ for (std::streamsize i = 0; i != N; ++i) {
+
+ if (char (readbuf [i]) != bindata [i]) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn() data "
+ "mismatch: got \"%s\", expected \"%s\"",
+ tname, readbuf, bindata);
+ break;
+ }
+ }
+ }
+ else {
+ ASSERT_OPEN (0, mode, "failed to open an existing file");
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::binary | ios::out)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::binary | std::ios::out | iomodes [minx], "");
+
+ Filebuf fb;
+
+ if (fb.open (tmpfname, mode)) {
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ const charT XYZ[] = {
+ '\n', 'X', '\r', 'Y', '\n', '\r', 'Z', '\r', '\n', '\0'
+ };
+
+ const std::streamsize N = sizeof XYZ / sizeof *XYZ - 1;
+
+ if (N != fb.sputn (XYZ, N))
+ ASSERT_OPEN (false, mode,
+ "failed to open an existing file for writing "
+ "(sputn() failed)");
+
+ fb.close ();
+
+ size = 0;
+ buf = _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &size, "rb"));
+
+ rw_assert (std::size_t (N) == size, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sputn() wrote %d bytes, "
+ "%d expected",
+ tname, size, N * sizeof (charT));
+
+ for (std::streamsize i = 0; i != N; ++i) {
+
+ if (buf [i] != char (XYZ [i])) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sputn() data "
+ "mismatch: wrote \"%s\", expected \"%s\"",
+ tname, buf, XYZ);
+ break;
+ }
+ }
+ }
+ else {
+ ASSERT_OPEN (0, mode, "failed to open an existing file");
+ }
+ }
+
+ REMOVE_FILE (tmpfname);
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open ((const char*)0, ios::in)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::in | iomodes [minx],
+ ", file name = 0 [extension]");
+
+ // verify that open() succeeds when the first argument
+ // is the null pointer (the call creates a temporary
+ // file and opens it for reading -- such a file may not
+ // be very useful but since it's harmless there's no
+ // reason it shouldn't be possible)
+
+ Filebuf fb;
+ fb.open ((const char*)0, mode);
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ // FIXME: verify that the call to close removes the file
+ fb.close ();
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open ((const char*)0, ios::out)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::out | iomodes [minx],
+ ", file name = 0 [extension]");
+
+ // verify that open() succeeds when the first argument
+ // is the null pointer (the call creates a temporary
+ // file and opens it for writing)
+
+ Filebuf fb;
+ fb.open ((const char*)0, mode);
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ // FIXME: verify that the call to close removes the file
+ fb.close ();
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open ((const char*)0, ios::in | ios::out)
+
+ for (std::size_t minx = 0; minx != niomodes; ++minx) {
+
+ BEGIN_MODE (std::ios::in | std::ios::out | iomodes [minx],
+ ", file name = 0 [extension]");
+
+ Filebuf fb;
+ fb.open ((const char*)0, mode);
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ // FIXME: verify that the call to close removes the file
+ fb.close ();
+ }
+
+
+#if !defined (_WIN32) && !defined (_WIN64)
+
+ //////////////////////////////////////////////////////////////////
+ // exercise open (..., ios::ate)
+
+ BEGIN_MODE (std::ios::ate | std::ios::out, "");
+
+ std::signal (SIGPIPE, ignore_signal);
+
+ if (mkfifo (tmpfname, S_IRWXU))
+ rw_assert (false, __FILE__, __LINE__,
+ "mkfifo (\"%s\", S_IRWXU) failed", tmpfname);
+ else {
+
+ const pid_t childpid = fork ();
+
+ if (childpid > 0) { // parent process
+
+ Filebuf fb;
+
+ const Filebuf* const fbp = fb.open (tmpfname, mode);
+
+ // verify that open(ate) fails for an existing but unseekable file
+ if (fbp) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open(\"%s\", ios::ate | "
+ "ios::out) == 0 after a failed seek to end",
+ tname, tmpfname);
+ }
+
+ // verify that is_open() returns false after a failed open
+ if (fb.is_open ()) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open() == false"
+ " after a failed call to open", tname);
+ }
+
+ // reap our child's exit status
+ wait (0);
+ }
+ else if (0 == childpid) { // child process
+
+ Filebuf fb;
+
+ if (fb.open (tmpfname, std::ios::in))
+ fb.sgetc ();
+ else
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open(\"%s\", "
+ "ios::in) failed in child process",
+ tname, tmpfname);
+
+ std::exit (0);
+ }
+ else
+ rw_assert (false, __FILE__, __LINE__, "fork() failed");
+
+ REMOVE_FILE (tmpfname);
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise close ()
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::close ()", tname);
+
+ std::signal (SIGPIPE, ignore_signal);
+
+ if (mkfifo (tmpfname, S_IRWXU))
+ rw_assert (false, __FILE__, __LINE__,
+ "mkfifo (\"%s\", S_IRWXU) failed", tmpfname);
+ else {
+
+ // verify that close() returns 0 on failure by opening and
+ // writing into a pipe in the parent process that the child
+ // prematurely closes
+
+ const pid_t childpid = fork ();
+
+ if (childpid > 0) { // parent process
+
+ Filebuf fb;
+
+ if (fb.open (tmpfname, std::ios::out)) {
+
+ // write into the file buffer
+ fb.sputc (charT ());
+
+ // wait for child to open and close the pipe
+ wait (0);
+
+ // close() will try to flush the contents of the buffer
+ // into the pipe which should fail, since the other end
+ // of the pipe has already been closed
+ if (fb.close ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::close() unexpectedly "
+ "suceeded", tname);
+ }
+ else
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open (\"%s\", ios::out) "
+ " != 0; got 0", tname, tmpfname);
+ }
+ else if (0 == childpid) { // child process
+
+ Filebuf fb;
+
+ if (!fb.open (tmpfname, std::ios::in))
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open(\"%s\", "
+ "ios::in) failed in child process",
+ tname, tmpfname);
+
+ std::exit (0);
+ }
+ else
+ rw_assert (false, __FILE__, __LINE__, "fork() failed");
+
+ REMOVE_FILE (tmpfname);
+ }
+
+#endif // _WIN{32,64}
+
+}
+
+/***************************************************************************/
+
+template <class charT>
+static void
+test_sync (const char* tname)
+{
+ typedef std::basic_filebuf<charT, std::char_traits<charT> > Filebuf;
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::sync ()", tname);
+
+ const char* const tmpfname = rw_tmpnam (0);
+ if (!tmpfname) {
+ return;
+ }
+
+ {
+ Filebuf fb;
+
+ static const charT foo[] = { 'f', 'o', 'o' };
+ static const charT BAR[] = { 'B', 'A', 'R' };
+
+ // create a non-empty file
+ rw_fwrite (tmpfname, "foobar");
+
+ if (fb.open (tmpfname, std::ios::in)) {
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ charT readbuf [256] = { 0 };
+
+ // read the first part of the file; filebuf will actually
+ // end up reading and caching the entire contents of the
+ // file
+ std::streamsize got = fb.sgetn (readbuf, 3);
+
+ // verify the contents of buffer match that of the file
+ if (3 != got)
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn() == 3, got %d", got);
+
+ rw_assert (!std::memcmp (readbuf, foo, sizeof foo),
+ __FILE__, __LINE__,
+ "sgetn() retrieved \"%s\", expected \"%s\")",
+ readbuf, foo);
+
+ // overwrite the contents of the file
+ rw_fwrite (tmpfname, "FOOBAR");
+
+ // call sync, excpecting filebuf to synchromnize with
+ // the new contents of the file while maintaining
+ // the correct position
+ const int res = fb.pubsync ();
+
+ rw_assert (0 == res, __FILE__, __LINE__,
+ "pubsync() == 0, got %d", res);
+
+ std::memset (readbuf, 0, sizeof readbuf);
+
+ // continue to read the file where the first sgetn()
+ // call left off
+ got = fb.sgetn (readbuf, 3);
+
+ // verify that the new contents of the file have been read
+ if (3 != got)
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn() == 3, got %d", got);
+
+ rw_assert (!std::memcmp (readbuf, BAR, sizeof BAR),
+ __FILE__, __LINE__,
+ "sgetn() retrieved \"%s\", expected \"%s\")",
+ readbuf, BAR);
+ }
+ else {
+ rw_assert (false, __FILE__, __LINE__,
+ "failed to open an existing file");
+ }
+ }
+
+ {
+ Filebuf fb;
+
+ static const charT foo[] = { 'f', 'o', 'o' };
+
+ // create a non-empty file
+ rw_fwrite (tmpfname, "foobar");
+
+ if (fb.open (tmpfname, std::ios::in)) {
+
+ rw_assert (fb.is_open (), __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open()", tname);
+
+ charT readbuf [256] = { 0 };
+
+ // read the first part of the file; filebuf will actually
+ // end up reading and caching the entire contents of the
+ // file
+ std::streamsize got = fb.sgetn (readbuf, 3);
+
+ // verify the contents of buffer match that of the file
+ if (3 != got)
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn() == 3, got %d", got);
+
+ rw_assert (!std::memcmp (readbuf, foo, sizeof foo),
+ __FILE__, __LINE__,
+ "sgetn() retrieved \"%s\", expected \"%s\")",
+ readbuf, foo);
+
+ // overwrite the contents of the file with less data
+ rw_fwrite (tmpfname, "BA");
+
+ // call sync, excpecting filebuf to synchromnize with
+ // the new contents of the file
+ // since there is less data in the file than the current
+ // offset, verify that the offset is adjusted to be the
+ // same as the end of the actual file
+ const int res = fb.pubsync ();
+
+ rw_assert (0 == res, __FILE__, __LINE__,
+ "pubsync() == 0, got %d", res);
+
+ std::memset (readbuf, 0, sizeof readbuf);
+
+ // try to continue to read the file where the first sgetn()
+ // call left off, expecting a failure
+ got = fb.sgetn (readbuf, 3);
+
+ // verify that nothing has been read
+ if (0 != got)
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn() == 0, got %d", got);
+
+ // verify that the end of the file is correctly reported
+ const typename Filebuf::off_type off =
+ fb.pubseekoff (0, std::ios::end);
+
+ rw_assert (off == 2, __FILE__, __LINE__,
+ "pubseekoff(0, ios::end) == 2, got %d", off);
+ }
+ else {
+ rw_assert (false, __FILE__, __LINE__,
+ "failed to open an existing file");
+ }
+ }
+}
+
+/***************************************************************************/
+
+
+template <class charT>
+static void
+test_attach (const char* tname)
+{
+#ifndef _RWSTD_NO_EXT_FILEBUF
+
+ //////////////////////////////////////////////////////////////////
+ // exercise attach(int) and fd()
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::attach (int) [extension]", tname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::fd () [extension]", tname);
+
+ typedef std::basic_filebuf<charT, std::char_traits<charT> > Filebuf;
+
+ // Extension:
+ // basic_filebuf* attach(int fd)
+ // Connects *this to an open file descriptor, fd. Unless detach() is
+ // called, the file descriptor will be closed during the first call
+ // to close() or when the object is destroyed. Returns this on success,
+ // 0 on failure (e.g., when this->is_open() evaluates to true).
+
+ int lastfd = -1;
+
+ {
+ Filebuf fb;
+
+ // get a new valid file descriptor
+ const int fd = open (DEV_NULL, O_RDWR);
+
+ if (fd < 0) {
+ rw_assert (false, __FILE__, __LINE__,
+ "open (\"%s\", O_RDWR) < 0; "
+ "aborting test", DEV_NULL);
+ return;
+ }
+
+ lastfd = fd;
+
+ // attach the filebuf object to the file descriptor
+ Filebuf *pfb = fb.attach (fd);
+
+ // verify that attach() succeeded
+ if (&fb != pfb)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) == %p, got 0",
+ tname, fd, &fb);
+
+ // verify that fd() returns the attached file descriptor
+ if (fd != fb.fd ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::fd() == %d, got %d",
+ tname, fd, fb.fd ());
+
+ // verify that the filebuf object is open
+ if (!fb.is_open ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open() == true, "
+ "got false after a successful call to attach(%d)",
+ tname, fd);
+
+ // Filebuf dtor should close the file descriptor (checked below)
+ }
+
+ {
+ Filebuf fb;
+
+ // create a new file descriptor
+ const int fd = open (DEV_NULL, O_RDWR);
+
+ // verify that the dtor in the block above closed the filebuf's fd
+ if (fd != lastfd)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) caused "
+ "a file descriptor leak after object destruction",
+ tname, lastfd);
+
+ lastfd = fd;
+
+ // attach this object to the new file descriptor
+ Filebuf *pfb = fb.attach (fd);
+
+ // verify that attach() succeeded
+ if (&fb != pfb)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) == %p, got 0",
+ tname, fd, &fb);
+
+ // verify that fd() returns the attached file descriptor
+ if (fd != fb.fd ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::fd() == %d, got %d",
+ tname, fd, fb.fd ());
+
+ // verify that the filebuf object is open
+ if (!fb.is_open ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open() == true, "
+ "got false after a successful call to attach(%d)",
+ tname, fd);
+
+ // call close
+ pfb = fb.close ();
+
+ // verify that the call to close() succeeded
+ if (&fb != pfb)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::close() == %p, got 0",
+ tname, &fb);
+
+ // verify that fd() returns an invalid file descriptor after
+ // a successful call to close()
+ if (0 <= fb.fd ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::fd() < 0, got %d after "
+ "a call to close()",
+ tname, fb.fd ());
+
+ // verify that is_open() returns false after the call to close()
+ if (fb.is_open ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open() == false, "
+ "got true after a successful call to close()",
+ tname);
+ }
+
+ {
+ Filebuf fb;
+
+ // get a new valid file descriptor
+ const int fd = open (DEV_NULL, O_RDWR);
+
+ // verify that the dtor in the block above closed the filebuf's fd
+ if (fd != lastfd)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) caused "
+ "a file descriptor leak after object destruction",
+ tname, lastfd);
+
+ lastfd = fd;
+
+ // attach the filebuf object to the file descriptor
+ Filebuf *pfb = fb.attach (fd);
+
+ // verify that attach() succeeded
+ if (&fb != pfb)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) == %p, got 0",
+ tname, fd, &fb);
+
+ pfb = fb.attach (fd);
+
+ // verify that a subsequent call to attach() (with the same
+ // or different file descriptor) failed
+ if (&fb == pfb)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) == 0, got %p",
+ tname, fd, &fb);
+
+ const int new_fd = open (DEV_NULL, O_RDWR);
+
+ pfb = fb.attach (fd);
+
+ if (&fb == pfb)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) == 0, got %p",
+ tname, fd, &fb);
+
+ close (new_fd);
+
+ // Filebuf dtor should close the file descriptor (checked below)
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // exercise detach()
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s>::detach () [extension]", tname);
+
+ // Extension:
+ // int detach()
+ // Flushes any waiting output to the file associated with the file
+ // descriptor, and disconnects the file descriptor from *this so
+ // that subsequent calls to close() will not close the file
+ // descriptor. Returns the detached file descriptor on success,
+ // -1 on failure.
+
+ {
+ Filebuf fb;
+
+ // get a new valid file descriptor
+ const int fd = open (DEV_NULL, O_RDWR);
+
+ // verify that the dtor in the block above closed the filebuf's fd
+ if (fd != lastfd)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::attach(int = %d) caused "
+ "a file descriptor leak after object destruction",
+ tname, lastfd);
+
+ lastfd = fd;
+
+ // attach the filebuf object to the file descriptor
+ fb.attach (fd);
+
+ const int old_fd = fb.detach ();
+
+ // verify that detach() returned the original file descriptor
+ if (fd != old_fd)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() == %d, got %d",
+ tname, fd, old_fd);
+
+ // verify that is_open() returns false after the call to detach()
+ if (fb.is_open ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open() == false, "
+ "got true after a call to detach()", tname);
+
+ // verify that fd() returns an invalid file descriptor after
+ // a successful call to detach()
+ if (0 <= fb.fd ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::fd() < 0, got %d after "
+ "a call to detach()()", tname, fb.fd ());
+
+ close (old_fd);
+
+ errno = 0;
+ }
+
+ // verify that the dtor in the block above didn't try to close
+ // the already explicitly closed file descriptor
+ if (errno)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::~basic_filebuf() attempted to "
+ "close a detached file descriptor", tname);
+
+ {
+ Filebuf fb;
+
+ if (fb.fd () >= 0)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::fd() < 0, got %d for an "
+ "object that's not open", tname, fb.fd ());
+
+ const int old_fd = fb.detach ();
+
+ // verify detach() returns an invalid file descriptor when called
+ // on a filebuf object that's not open
+ if (0 <= old_fd)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() < 0, got %d",
+ tname, old_fd);
+ }
+
+ const char* const tmpfname = rw_tmpnam (0);
+
+ if (!tmpfname) {
+ return;
+ }
+
+ {
+ Filebuf fb;
+
+ // open a writeable file
+ const int fd = open (tmpfname, O_CREAT | O_WRONLY, 0666);
+
+ if (fd < 0) {
+ rw_warn (false, __FILE__, __LINE__,
+ "open (\"%s\", O_CREAT | O_WRONLY, 0666) "
+ "failed: %m", tmpfname);
+ }
+
+ // attach filebuf to the file descriptor
+ fb.attach (fd);
+
+ const charT data[] = { '0', '1', '2', '\0' };
+ const std::size_t nelems = sizeof data / sizeof *data - 1;
+
+ // write into the filebuf object
+ const std::size_t wrote = fb.sputn (data, nelems);
+
+ if (wrote != nelems)
+ rw_assert (false, __FILE__, __LINE__,
+ "sputn(\"%s\", %d) == %d, got %d",
+ data, nelems, nelems, wrote);
+
+ // and detach
+ const int old_fd = fb.detach ();
+ if (fd != old_fd)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() == %d, got %d",
+ fd, old_fd);
+
+ // verify by reading the contents of the named file that
+ // the call to detach() wrote the contents of the filebuf
+ // object's data buffer into the file before detaching
+ std::size_t nbytes = 0;
+ const char* const buf =
+ _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, &nbytes));
+
+ if ( !buf || nbytes != nelems
+ || rw_strncmp (buf, data, nelems))
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() failed to flush "
+ "data to the attached file descriptor; "
+ "read %lu bytes: %s, expected \"012\"",
+ tname, nbytes, buf);
+
+ REMOVE_FILE (tmpfname);
+ }
+
+ {
+ Filebuf fb;
+
+ // create a new file and open it for writing
+ const int fd = open (tmpfname, O_CREAT | O_WRONLY, 0666);
+
+ // attach filebuf to the file descriptor (will set mode to ios::out
+ // based on the O_WRONLY open mode of the file descriptor)
+ fb.attach (fd);
+
+ // close and reopen the same file descriptor as read-only
+ close (fd);
+ if (fd != open (tmpfname, O_RDONLY)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "open (\"%s\", O_RDONLY) != %d; aborting test",
+ tmpfname, fd);
+ return;
+ }
+
+ static const charT data[] = { '0', '1', '2', '\0' };
+ static const std::size_t nelems = sizeof data / sizeof *data - 1;
+
+ // write into the filebuf object's buffer
+ if (nelems != std::size_t (fb.sputn (data, nelems)))
+ rw_assert (false, __FILE__, __LINE__, "sputn() failed");
+
+ // and try to detach (must try to flush data into file)
+ const int bad_fd = fb.detach ();
+
+ // verify that detach() failed (due to the failure
+ // to write to a read-only file descriptor)
+ if (bad_fd >= 0)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() < 0, got %d after "
+ "a failure to write to read-only file descriptor",
+ tname, bad_fd);
+
+ // verify that the call to detach() failed to flush the contents
+ // of the filebuf object's data buffer into a read-only file by
+ // testing that the size of the file is unchanged (i.e., 0)
+ std::size_t nbytes = 0;
+
+ const char* buf =
+ _RWSTD_STATIC_CAST (char*, rw_fread (tmpfname, 0));
+
+ if (buf && nbytes)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() unexpectedly wrote "
+ "%u bytes to a read-only file: \"%s\"",
+ tname, nbytes, buf);
+
+ // close and reopen the same file descriptor as write-only
+ close (fd);
+ if (fd != open (tmpfname, O_WRONLY)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "open (\"%s\", O_WRONLY) != %d; aborting test",
+ tmpfname, fd);
+ return;
+ }
+
+ // and detach (must successfully flush data into file)
+ const int good_fd = fb.detach ();
+
+ // verify that the call to detach() was successful
+ if (good_fd < 0)
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() == %d, got %d",
+ tname, fd, good_fd);
+
+ // verify that the filebuf object is no longer open
+ if (fb.is_open ())
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::is_open() unexpectedly "
+ "true after a successful call to detach()",
+ tname);
+
+ // verify that this call to detach() wrote out the contents of the
+ // filebuf object's data buffer into the writeable file by checking
+ // the size and contents of the file
+ buf = (char*)rw_fread (tmpfname, &nbytes);
+
+ if ( !buf || nbytes != nelems
+ || rw_strncmp (buf, data, nelems))
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::detach() failed to flush "
+ "data to the attached file descriptor; "
+ "read %lu bytes: %s, expected %s",
+ tname, nbytes, buf, data);
+
+ // close the file descriptor before removing the file
+ close (good_fd);
+
+ REMOVE_FILE (tmpfname);
+ }
+
+#else // if defined (_RWSTD_NO_EXT_FILEBUF)
+
+ _RWSTD_UNUSED (tname);
+
+#endif // _RWSTD_NO_EXT_FILEBUF
+
+}
+
+/***************************************************************************/
+
+// CodeCvt<charT> performs a state-dependent conversion
+// the first byte of the state_type object encodes the state,
+// any remaining bytes must be 0
+// internal characters are externally represented as sequences
+// of 1 to 22 chars, escape sequences are 11 to 13 chars long
+// and all start with the "<ESC-" prefix
+//
+// for example, the string "Hello, World!\n" will be externally
+// represented by the following sequence of narrow characters:
+//
+// "<ESC-UPPER>H<ESC-LOWER>ello<ESC-PUNCT><comma><SP><ESC-UPPER>"
+// "W<ESC-LOWER>orld<ESC-PUNCT><exclamation-mark><ESC-CNTRL>\n"
+
+template <class charT>
+struct CodeCvt: std::codecvt<charT, char, std::mbstate_t>
+{
+ typedef std::codecvt<charT, char, std::mbstate_t> Base;
+
+ enum { cntrl, punct, digit, upper, lower, hexcode };
+
+public:
+
+ typedef typename Base::intern_type intern_type;
+ typedef typename Base::extern_type extern_type;
+ typedef typename Base::state_type state_type;
+
+ explicit CodeCvt (std::size_t ref = 0)
+ : Base (ref) { }
+
+protected:
+
+ virtual std::codecvt_base::result
+ do_out (state_type&,
+ const intern_type*, const intern_type*, const intern_type*&,
+ extern_type*, extern_type*, extern_type*&) const;
+
+ virtual std::codecvt_base::result
+ do_in (state_type&,
+ const extern_type*, const extern_type*, const extern_type*&,
+ intern_type*, intern_type*, intern_type*&) const;
+
+ virtual std::codecvt_base::result
+ do_unshift (state_type&, extern_type*, extern_type*, extern_type*&) const;
+
+ virtual int do_encoding () const _THROWS (()) {
+ return -1; // state-dependent encoding
+ }
+
+ virtual bool do_always_noconv () const _THROWS (()) {
+ return false; // conversion always necessary
+ }
+
+ // returns the maximum `N' of extern chars in the range [from, from_end)
+ // such that N represents max or fewer internal chars
+ virtual int
+ do_length (state_type&, const extern_type*,
+ const extern_type*, std::size_t) const;
+
+ // returns the max value do_length (s, from, from_end, 1) can return
+ // for any valid range [from, from_end) - see LWG issue 74
+ virtual int do_max_length () const _THROWS (()) {
+ return -1;
+ }
+};
+
+
+extern const char* const escapes[] = {
+ "<ESC-CNTRL>", "<ESC-PUNCT>", "<ESC-DIGIT>",
+ "<ESC-UPPER>", "<ESC-LOWER>", "<ESC-HEXCODE>"
+};
+
+
+extern const char* const charnames[] = {
+ // control characters (<ESC-CNTRL>)
+ "<NUL>", "<SOH>", "<STX>", "<ETX>", "<EOT>", "<ENQ>", "<ACK>", "<BEL>",
+ "<BS>", "<HT>", "\n", "<VT>", "<FF>", "<CR>" /* '\r' */, "<SO>", "<SI>",
+ "<DLE>", "<DC1>", "<DC2>", "<DC3>", "<DC4>", "<NAK>", "<SYN>", "<ETB>",
+ "<CAN>", "<EM>", "<SUB>", "<ESC>", "<FS>", "<GS>", "<RS>", "<US>",
+ // punctuators (<ESC-PUNCT>)
+ "<SP>",
+ "<exclamation-mark>",
+ "<quotation-mark>",
+ "<number-sign>",
+ "<dollar-sign>",
+ "<percent-sign>",
+ "<ampersand>",
+ "<apostrophe>",
+ "<left-parenthesis>",
+ "<right-parenthesis>",
+ "<asterisk>",
+ "<plus-sign>",
+ "<comma>",
+ "<hyphen>",
+ "<period>",
+ "<slash>",
+ // digits (<ESC-DIGIT>)
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+ // punctuators (<ESC-PUNCT>)
+ "<colon>",
+ "<semicolon>",
+ "<less-than-sign>",
+ "<equals-sign>",
+ "<greater-than-sign>",
+ "<question-mark>",
+ "<commercial-at>",
+ // uppercase letters (<ESC_UPPER>)
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+ // punctuators (<ESC-PUNCT>)
+ "<left-square-bracket>",
+ "<backslash>",
+ "<right-square-bracket>",
+ "<circumflex>",
+ "<underscore>",
+ "<grave-accent>",
+ // lowercase letters (<ESC_LOWER>)
+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
+ // punctuators (<ESC-PUNCT>)
+ "<left-curly-bracket>",
+ "<vertical-line>",
+ "<right-curly-bracket>",
+ "<tilde>",
+ // control characters (<ESC-CNTRL>)
+ "<DEL>"
+ // characters above '\x7f' are represented in hex (<ESC-HEXCODE>)
+};
+
+
+template <class charT>
+std::codecvt_base::result
+CodeCvt<charT>::do_out ( state_type &state,
+ const intern_type *from,
+ const intern_type *from_end,
+ const intern_type *&from_next,
+ extern_type *to,
+ extern_type *to_end,
+ extern_type *&to_next) const
+{
+ std::codecvt_base::result res = std::codecvt_base::ok;
+
+ char hexbuf [5] = "";
+
+ int int_state = hexcode;
+
+ for (from_next = from, to_next = to; from_next != from_end; ++from_next) {
+
+ typedef std::char_traits<intern_type> Traits;
+
+ const std::size_t uch = std::size_t (Traits::to_int_type (*from_next));
+
+ if (uch < ' ') {
+ int_state = cntrl;
+ }
+ else if (uch >= ' ' && uch <= '/') {
+ int_state = punct;
+ }
+ else if (uch >= '0' && uch <= '9') {
+ int_state = digit;
+ }
+ else if (uch >= ':' && uch <= '@') {
+ int_state = punct;
+ }
+ else if (uch >= 'A' && uch <= 'Z') {
+ int_state = upper;
+ }
+ else if (uch >= '[' && uch <= '`') {
+ int_state = punct;
+ }
+ else if (uch >= 'a' && uch <= 'z') {
+ int_state = lower;
+ }
+ else if (uch >= '{' && uch <= '~') {
+ int_state = punct;
+ }
+ else if (uch == '\x7f') {
+ int_state = cntrl;
+ }
+ else if (uch <= 0xff) {
+ int_state = hexcode;
+
+ if (to_end - to_next < 4) {
+ res = std::codecvt_base::partial;
+ break;
+ }
+
+ // convert `uch' to a hexadecimal escape sequence
+ static const char hexdigits[] = "0123456789abcdef";
+
+ hexbuf [0] = '\\';
+ hexbuf [1] = 'x';
+ hexbuf [2] = hexdigits [uch >> 8];
+ hexbuf [3] = hexdigits [uch & 0x0fU];
+ hexbuf [4] = '\0';
+ }
+ else {
+ res = std::codecvt_base::error;
+ break;
+ }
+
+ if (int (*(char*)&state) != int_state) {
+
+ const std::size_t len = std::strlen (escapes [int_state]);
+
+ if (len > std::size_t (to_end - to_next)) {
+ res = std::codecvt_base::partial;
+ break;
+ }
+
+ std::memcpy (to_next, escapes [int_state], len);
+ to_next += len;
+
+ *(char*)&state = char (int_state);
+ }
+
+ const char* const outs = *hexbuf ? hexbuf : charnames [uch];
+
+ const std::size_t len = std::strlen (outs);
+
+ if (len > std::size_t (to_end - to_next)) {
+ res = std::codecvt_base::partial;
+ break;
+ }
+
+ std::memcpy (to_next, outs, len);
+ to_next += len;
+ }
+
+ return res;
+}
+
+
+// looks for a character whose name starts at `*pbeg' in the table
+// of character names, `chartbl' containing `tblsize' elements
+// if a unique (even partial) match is found, returns the index of
+// the character in the table; if the unique match is complete,
+// also advances `*pbeg' by the length of the match
+std::size_t find_char (const char **pbeg, const char *end,
+ const char* const chartbl[], std::size_t tblsize)
+{
+ const std::size_t nchars = sizeof charnames / sizeof *charnames;
+
+ std::size_t hits [nchars] = { 0 };
+
+ const char* cur = *pbeg;
+
+ for (; cur != end; ++cur) {
+
+ const std::size_t inx = cur - *pbeg;
+
+ std::size_t nmatches = 0;
+
+ for (std::size_t i = 0; i != tblsize; ++i) {
+ if (hits [i] == inx && chartbl [i] && *cur == chartbl [i][inx]) {
+ ++hits [i];
+ ++nmatches;
+ }
+ }
+
+ if (!nmatches)
+ break;
+ }
+
+ std::size_t nmatches = 0;
+ std::size_t imaxhits = 0;
+ std::size_t inx = std::size_t (-1);
+
+ for (std::size_t i = 0; i != tblsize; ++i) {
+
+ if (!chartbl [i])
+ continue;
+
+ if (hits [i] > hits [imaxhits])
+ imaxhits = i;
+
+ if (hits [i] == std::strlen (chartbl [i])) {
+
+ if (std::size_t (-1) == inx)
+ inx = 0;
+
+ if (hits [i] == hits [inx]) {
+ ++nmatches;
+ inx = i;
+ }
+ else if (hits [i] > hits [inx]) {
+ nmatches = 1;
+ inx = i;
+ }
+ }
+ else if (std::size_t (-1) != inx && hits [i] > hits [inx]) {
+ nmatches = 0;
+ inx = i;
+ }
+ }
+
+ if (inx != std::size_t (-1) && 1 == nmatches)
+ *pbeg = cur;
+
+ if (hits [imaxhits] == std::size_t (end - *pbeg))
+ inx = imaxhits;
+
+ return inx;
+}
+
+
+template <class charT>
+std::codecvt_base::result
+CodeCvt<charT>::do_in ( state_type &state,
+ const extern_type *from,
+ const extern_type *from_end,
+ const extern_type *&from_next,
+ intern_type *to,
+ intern_type *to_end,
+ intern_type *&to_next) const
+{
+ std::codecvt_base::result res = std::codecvt_base::ok;
+
+ for (to_next = to, from_next = from; to_next != to_end; ++to_next) {
+
+ top_of_loop:
+
+ if (from_next == from_end)
+ break;
+
+ const std::size_t navail = from_end - from_next;
+
+ // check the beginning of the sequence to see if
+ // it may possibly start with an escape sequence
+
+ if (navail <= 5 && !std::memcmp (from_next, "<ESC-", navail))
+ return std::codecvt_base::partial;
+
+ if (navail > 5 && !std::memcmp (from_next, "<ESC-", 5)) {
+
+ // found the beginning of what might be an escape sequence
+
+ if (navail >= 11) {
+
+ const std::size_t nescapes = sizeof escapes / sizeof *escapes;
+
+ for (std::size_t i = 0; i != nescapes; ++i) {
+
+ const std::size_t len = std::strlen (escapes [i]);
+
+ if (!std::memcmp (escapes [i], from_next, len)) {
+
+ // found an escape sequence
+
+ // set the state variable
+ *(char*)&state = char (i);
+
+ // advance past the escape sequence
+ from_next += len;
+
+ // continue iterating over the rest of the sequence
+ goto top_of_loop;
+ }
+ }
+ }
+ else {
+ // not enough external elements to convert
+ // to an internal character
+ return std::codecvt_base::partial;
+ }
+ }
+
+ std::size_t chinx = std::size_t (-1); // character index
+ std::size_t choff = 0; // character offset
+
+ const char* const from_next_save = from_next;
+
+ switch (*(char*)&state) {
+
+ case cntrl:
+ chinx = find_char (&from_next, from_end, charnames, ' ' + 1U);
+ if ( std::size_t (-1) == chinx
+ && 5 <= from_end - from_next
+ && !std::memcmp (from_next, "<DEL>", 5)) {
+ chinx = '\x7f';
+ from_next += 5;
+ }
+ break;
+
+ case punct: {
+
+ static const char* const pun[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ "<SP>",
+ "<exclamation-mark>",
+ "<quotation-mark>",
+ "<number-sign>",
+ "<dollar-sign>",
+ "<percent-sign>",
+ "<ampersand>",
+ "<apostrophe>",
+ "<left-parenthesis>",
+ "<right-parenthesis>",
+ "<asterisk>",
+ "<plus-sign>",
+ "<comma>",
+ "<hyphen>",
+ "<period>",
+ "<slash>",
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ "<colon>",
+ "<semicolon>",
+ "<less-than-sign>",
+ "<equals-sign>",
+ "<greater-than-sign>",
+ "<question-mark>",
+ "<commercial-at>",
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ "<left-square-bracket>",
+ "<backslash>",
+ "<right-square-bracket>",
+ "<circumflex>",
+ "<underscore>",
+ "<grave-accent>",
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ "<left-curly-bracket>",
+ "<vertical-line>",
+ "<right-curly-bracket>",
+ "<tilde>",
+ 0
+ };
+
+ chinx = find_char (&from_next, from_end,
+ pun, sizeof pun / sizeof *pun);
+
+ break;
+ }
+
+ case digit:
+ choff = '0';
+
+ if (*from_next >= '0' && *from_next <= '9')
+ chinx = *from_next++ - '0';
+
+ // commented out code replaced by the above for efficiency
+ // chinx = find_char (&from_next, from_end, charnames + choff, 10);
+ break;
+
+ case lower:
+ choff = 'a';
+
+ // assume ASCII
+ if (*from_next >= 'a' && *from_next <= 'z')
+ chinx = *from_next++ - 'a';
+
+ // commented out code replaced by the above for efficiency
+ // chinx = find_char (&from_next, from_end, charnames + choff, 26);
+ break;
+
+ case upper:
+ choff = 'A';
+
+ // assume ASCII
+ if (*from_next >= 'A' && *from_next <= 'Z')
+ chinx = *from_next++ - 'A';
+
+ // commented out code replaced by the above for efficiency
+ // chinx = find_char (&from_next, from_end, charnames + choff, 26);
+ break;
+
+ case hexcode: {
+ if (from_end - from_next < 4)
+ return std::codecvt_base::partial;
+
+ if ( from_next [0] != '\\' || from_next [1] != 'x'
+ || !( from_next [2] >= '0' && from_next [2] <= '9'
+ || from_next [2] >= 'A' && from_next [2] <= 'F'
+ || from_next [2] >= 'a' && from_next [2] <= 'f')
+ || !( from_next [3] >= '0' && from_next [3] <= '9'
+ || from_next [3] >= 'A' && from_next [3] <= 'F'
+ || from_next [3] >= 'a' && from_next [3] <= 'f'))
+ return std::codecvt_base::error;
+
+ // convert a hex literal to a number
+ chinx = 0;
+ for (unsigned i = 2; i != 4; ++i) {
+ chinx <<= 4;
+ if (from_next [i] >= '0' && from_next [i] <= '9')
+ chinx += from_next [i] - '0';
+ else if (from_next [i] >= 'A' && from_next [i] <= 'F')
+ chinx += 10 + (from_next [i] - 'A');
+ else
+ chinx += 10 + (from_next [i] - 'a');
+ }
+
+ break;
+ }
+
+ default:
+ chinx = std::size_t (-1);
+ break;
+ }
+
+ if (std::size_t (-1) == chinx) {
+ res = std::codecvt_base::error;
+ break;
+ }
+
+ // the combination of a valid `chinx' and an unmodified
+ // `from_next' pointer indicates a partial match
+ if (from_next == from_next_save) {
+ res = std::codecvt_base::partial;
+ break;
+ }
+
+ *to_next = charT (chinx + choff);
+ }
+
+ return res;
+}
+
+
+template <class charT>
+std::codecvt_base::result
+CodeCvt<charT>::
+do_unshift (state_type &state,
+ extern_type *to,
+ extern_type *to_end,
+ extern_type *&to_next) const
+{
+ to_next = to;
+
+ if (!*(char*)&state)
+ return std::codecvt_base::noconv;
+
+ const std::size_t len = std::strlen (escapes [0]);
+
+ if (len > std::size_t (to_end - to_next))
+ return std::codecvt_base::partial;
+
+ std::memcpy (to_next, escapes [0], len);
+ to_next += len;
+
+ std::memset (&state, 0, sizeof state);
+
+ return std::codecvt_base::ok;
+}
+
+
+template <class charT>
+int
+CodeCvt<charT>::
+do_length (state_type&, const extern_type*,
+ const extern_type*, std::size_t) const
+{
+ return 0;
+}
+
+/***************************************************************************/
+
+static const char*
+get_codecvt_result (std::codecvt_base::result res)
+{
+ switch (res) {
+ case std::codecvt_base::error: return "std::codecvt_base::error";
+ case std::codecvt_base::noconv: return "std::codecvt_base::noconv";
+ case std::codecvt_base::ok: return "std::codecvt_base::ok";
+ case std::codecvt_base::partial: return "std::codecvt_base::partial";
+ }
+
+ return "unknown";
+}
+
+
+template <class charT>
+static void
+test_codecvt (const char* tname)
+{
+ rw_info (0, __FILE__, __LINE__,
+ "std::basic_filebuf<%s> with a state-dependent encoding",
+ tname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "sgetn() with state-dependent code conversion");
+
+ // read in the text of this source file as plain text
+
+ typedef std::basic_filebuf<charT, std::char_traits<charT> > Filebuf;
+ typedef typename Filebuf::off_type off_type;
+
+ Filebuf noconv_in;
+
+ // use ios_base::binary to avoid CR/LF conversion issues
+ if (!noconv_in.open (__FILE__, std::ios::binary | std::ios::in)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open (\"%s\", "
+ "ios_base::binary | ios_base::in) failed",
+ tname, __FILE__);
+ return;
+ }
+
+ // seek to the end of the file to get its size in bytes
+ const std::streamsize noconv_fsize =
+ noconv_in.pubseekoff (0, std::ios::end);
+
+ if (noconv_fsize <= 0) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::pubseekoff "
+ "(0, ios_base::end) >= 0, got %i",
+ tname, noconv_fsize);
+ return;
+ }
+
+ if (0 != noconv_in.pubseekoff (0, std::ios::beg)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::pubseekoff "
+ "(0, ios_base::beg) failed", tname);
+ return;
+ }
+
+ const char* const tmpfname = rw_tmpnam (0);
+
+ if (!tmpfname) {
+ return;
+ }
+
+ // allocate a buffer large enough to hold the contents of the
+ // file in internal representation without codeset conversion
+ charT *noconv_intbuf = new charT [noconv_fsize];
+
+ // sgetn() returns the number of internal characters read in
+ // which must equal the number of external characters read by
+ // the `noconv_in' file buffer (since it does no conversion)
+ std::streamsize nread = noconv_in.sgetn (noconv_intbuf, noconv_fsize);
+
+ if (nread != noconv_fsize) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %i) == %i), got %i",
+ tname, noconv_intbuf,
+ noconv_fsize, noconv_fsize, nread);
+ delete[] noconv_intbuf;
+ return;
+ }
+
+ const CodeCvt<charT> cvt (1);
+
+ // write out the text of this file using the test codecvt facet
+ // that performs state-dependent encoding
+ Filebuf conv_out;
+
+ conv_out.pubimbue (std::locale (std::locale::classic (), &cvt));
+
+ if (!conv_out.open (tmpfname, std::ios::binary | std::ios::out)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open (\"%s\", ios_base::out) "
+ "failed", tname, tmpfname);
+ delete[] noconv_intbuf;
+ return;
+ }
+
+ // sputn() returns the number of internal characters written out
+ // which must equal the number of external characters read by
+ // the `noconv_in' file buffer (since it does no conversion)
+ const std::streamsize nwrote = conv_out.sputn (noconv_intbuf, nread);
+
+ if (nread != nwrote) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sputn (\"%s\", %i) == %i), "
+ "got %i", tname,
+ noconv_intbuf, nread, nread, nwrote);
+ delete[] noconv_intbuf;
+ return;
+ }
+
+ // close file buffer to flush it out
+ if (!conv_out.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(\"%s\").close() failed",
+ tname, tmpfname);
+
+ std::filebuf nin; // narrow input stream buffer
+
+ if (!nin.open (tmpfname, std::ios::binary | std::ios::in)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::open (\"%s\", ios_base::in) failed",
+ tname, tmpfname);
+ delete[] noconv_intbuf;
+ return;
+ }
+
+ // get the size of the converted file in external characters
+ const std::streamsize conv_fsize = nin.pubseekoff (0, std::ios::end);
+
+ if (conv_fsize <= noconv_fsize) {
+ rw_assert (false, __FILE__, __LINE__,
+ "filebuf::pubseekoff (0, ios_base::end) > %i, got %i",
+ noconv_fsize, conv_fsize);
+ delete[] noconv_intbuf;
+ return;
+ }
+
+ if (0 != nin.pubseekoff (0, std::ios::beg)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "filebuf::pubseekoff (0, ios_base::beg) failed");
+ delete[] noconv_intbuf;
+ return;
+ }
+
+ // allocate a buffer large enough to hold the contents of the
+ // file in external representation without codeset conversion
+ char *noconv_extbuf = new char [conv_fsize];
+ std::memset (noconv_extbuf, 0, conv_fsize);
+
+ // read in the (unconverted) contents of the file
+ nread = nin.sgetn (noconv_extbuf, conv_fsize);
+
+ if (nread != conv_fsize) {
+ rw_assert (false, __FILE__, __LINE__,
+ "filebuf::sgetn (%p, %i) == %i, got %i",
+ noconv_extbuf, conv_fsize, conv_fsize, nread);
+ delete[] noconv_intbuf;
+ delete[] noconv_extbuf;
+ return;
+ }
+
+ if (!nin.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(\"%s\").close() failed",
+ tname, tmpfname);
+
+ std::mbstate_t state;
+ std::memset (&state, 0, sizeof state);
+
+ const char *from = noconv_extbuf;
+ const char *from_end = noconv_extbuf + nread;
+ const char *from_next = 0;
+
+ // allocate a buffer large enough to hold the contents of the
+ // file in internal representation with codeset conversion
+ charT *conv_intbuf = new charT [noconv_fsize];
+ std::memset (conv_intbuf, 0, noconv_fsize * sizeof *conv_intbuf);
+
+ charT *to = conv_intbuf;
+ charT *to_end = conv_intbuf + noconv_fsize;
+ charT *to_next = 0;
+
+ // convert the contents of the file using the test codecvt facet
+ const std::codecvt_base::result cvtres =
+ cvt.in (state, from, from_end, from_next, to, to_end, to_next);
+
+ if (std::codecvt_base::ok != cvtres) {
+ rw_assert (false, __FILE__, __LINE__,
+ "CodeCvt<%s>::in ({ %d, ... }, %p, %p, %p, %p, %p, %p) "
+ "== std::codecvt_base::ok, got %s",
+ tname, *(unsigned char*)&state,
+ from, from_end, from_next, to, to_end, to_next,
+ get_codecvt_result (cvtres));
+ delete[] noconv_intbuf;
+ delete[] noconv_extbuf;
+ delete[] conv_intbuf;
+ return;
+ }
+
+ const std::streamsize n_ext_cvt = from_next - from;
+ const std::streamsize n_int_cvt = to_next - to;
+
+ rw_assert (n_ext_cvt == conv_fsize, __FILE__, __LINE__,
+ "CodeCvt<%s>::in() converted %i external characters, "
+ "expected %i", tname, n_ext_cvt, conv_fsize);
+
+ rw_assert (n_int_cvt == noconv_fsize, __FILE__, __LINE__,
+ "CodeCvt<%s>::in() produced %i internal characters, "
+ "expected %i", tname, n_int_cvt, noconv_fsize);
+
+ // verify that the contents of the unconverted internal buffer
+ // (i.e., the text of this file in internal representation) are
+ // the same as the contents of the converted internal buffer
+ // (i.e., the text of this file converted to the external
+ // state-dependent representation and then converted back to
+ // the internal encoding)
+ rw_assert (!std::memcmp (noconv_intbuf, conv_intbuf, n_int_cvt),
+ __FILE__, __LINE__, "code conversion mismatch");
+
+
+ // read in the text of the temporary file encoded in
+ // a state-dependent encoding and convert it to its
+ // internal representation
+ Filebuf conv_in;
+
+ conv_in.pubimbue (std::locale (std::locale::classic (), &cvt));
+
+ conv_in.open (tmpfname, std::ios::in);
+
+ std::memset (conv_intbuf, 0, noconv_fsize * sizeof *conv_intbuf);
+
+ nread = conv_in.sgetn (conv_intbuf, noconv_fsize);
+
+ if (nread != noconv_fsize) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %i) == %i, got %i",
+ tname, conv_intbuf, noconv_fsize,
+ noconv_fsize, nread);
+ delete[] noconv_intbuf;
+ delete[] noconv_extbuf;
+ delete[] conv_intbuf;
+ return;
+ }
+
+ rw_assert (!std::memcmp (noconv_intbuf, conv_intbuf,
+ n_int_cvt * sizeof *noconv_intbuf),
+ __FILE__, __LINE__, "code conversion mismatch");
+
+ if (!noconv_in.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(" __FILE__ ").close() failed",
+ tname);
+
+ if (!conv_in.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(\"%s\").close() failed",
+ tname, tmpfname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "pubseekoff() and pubseekpos() with state-dependent "
+ "code conversion");
+
+ noconv_in.open (__FILE__, std::ios::binary | std::ios::in);
+ conv_in.open (tmpfname, std::ios::binary | std::ios::in);
+
+ for (std::streamsize i = 0; i < noconv_fsize; i += noconv_fsize / 13) {
+
+ typedef typename Filebuf::pos_type pos_type;
+
+ noconv_in.pubseekoff (0, std::ios::beg);
+ conv_in.pubseekoff (0, std::ios::beg);
+
+ std::memset (noconv_intbuf, 0, noconv_fsize * sizeof *noconv_intbuf);
+ std::memset (conv_intbuf, 0, noconv_fsize * sizeof *conv_intbuf);
+
+ nread = noconv_in.sgetn (noconv_intbuf, i);
+
+ if (i != nread) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %d) == %d, "
+ "got %d", tname, noconv_intbuf, i, i, nread);
+ break;
+ }
+
+ nread = conv_in.sgetn (conv_intbuf, i);
+
+ if (i != nread) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %d) == %d, "
+ "got %d", tname, conv_intbuf, i, i, nread);
+ break;
+ }
+
+ if (std::memcmp (noconv_intbuf, conv_intbuf,
+ i * sizeof *conv_intbuf)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. code conversion mismatch", i);
+ break;
+ }
+
+ const pos_type noconv_pos =
+ noconv_in.pubseekoff (0, std::ios::cur);
+
+ const pos_type conv_pos =
+ conv_in.pubseekoff (0, std::ios::cur);
+
+ std::memset (noconv_intbuf, 0, noconv_fsize * sizeof *noconv_intbuf);
+ std::memset (conv_intbuf, 0, noconv_fsize * sizeof *conv_intbuf);
+
+ nread = noconv_in.sgetn (noconv_intbuf, noconv_fsize);
+
+ if (noconv_fsize - i != nread) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %d) == %d, "
+ "got %d", tname, noconv_intbuf,
+ noconv_fsize, noconv_fsize - i, nread);
+ break;
+ }
+
+ nread = conv_in.sgetn (conv_intbuf, noconv_fsize);
+
+ if (noconv_fsize - i != nread) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %d) == %d, "
+ "got %d", tname, conv_intbuf,
+ noconv_fsize, noconv_fsize - i, nread);
+ break;
+ }
+
+ if (std::memcmp (noconv_intbuf, conv_intbuf,
+ nread * sizeof *noconv_intbuf)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. data mismatch after conversion", i);
+ break;
+ }
+
+ if (!noconv_in.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(" __FILE__ ").close() failed",
+ tname);
+
+ if (!conv_in.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(\"%s\").close() failed",
+ tname, tmpfname);
+
+ noconv_in.open (__FILE__, std::ios::binary | std::ios::in);
+ conv_in.open (tmpfname, std::ios::binary | std::ios::in);
+
+ const pos_type noconv_pos_new = noconv_in.pubseekpos (noconv_pos);
+
+ if (noconv_pos_new != noconv_pos) {
+
+ std::mbstate_t noconv_state = noconv_pos.state ();
+ std::mbstate_t noconv_state_new = noconv_pos_new.state ();
+
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::pubseekpos ({ %d, %d }, "
+ "ios_base::cur) == { %d, %d }, got { %d, %d }",
+ tname,
+ off_type (noconv_pos), *(char*)&noconv_state,
+ off_type (noconv_pos), *(char*)&noconv_state,
+ off_type (noconv_pos_new),
+ *(char*)&noconv_state_new);
+ break;
+ }
+
+ const pos_type conv_pos_new = conv_in.pubseekpos (conv_pos);
+
+ if (conv_pos_new != conv_pos) {
+ std::mbstate_t conv_state = noconv_pos.state ();
+ std::mbstate_t conv_state_new = noconv_pos_new.state ();
+
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::pubseekpos ({ %d, %d }, "
+ "ios_base::cur) == { %d, %d }, got { %d, %d }",
+ tname,
+ off_type (conv_pos), *(char*)&conv_state,
+ off_type (conv_pos), *(char*)&conv_state,
+ off_type (conv_pos_new),
+ *(char*)&conv_state_new);
+ break;
+ }
+
+ std::memset (noconv_intbuf, 0, noconv_fsize * sizeof *noconv_intbuf);
+ nread = noconv_in.sgetn (noconv_intbuf, noconv_fsize);
+
+ if (noconv_fsize - i != nread) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %d) == %d, "
+ "got %d (no code conversion)",
+ tname, noconv_intbuf,
+ noconv_fsize, noconv_fsize - i, nread);
+ break;
+ }
+
+ if (std::memcmp (noconv_intbuf, conv_intbuf,
+ nread * sizeof *noconv_intbuf)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "data mismatch (no code conversion)");
+ break;
+ }
+
+ std::memset (conv_intbuf, 0, noconv_fsize * sizeof *conv_intbuf);
+ nread = conv_in.sgetn (conv_intbuf, noconv_fsize);
+
+ if (noconv_fsize - i != nread) {
+ rw_assert (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>::sgetn (%p, %d) == %d, "
+ "got %d (with code conversion)",
+ tname, conv_intbuf,
+ noconv_fsize, noconv_fsize - i, nread);
+ break;
+ }
+
+ if (std::memcmp (noconv_intbuf, conv_intbuf,
+ nread * sizeof *noconv_intbuf)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "code conversion mismatch");
+ break;
+ }
+ }
+
+ delete[] noconv_intbuf;
+ delete[] noconv_extbuf;
+ delete[] conv_intbuf;
+
+ if (!noconv_in.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(" __FILE__ ").close() failed",
+ tname);
+
+ if (!conv_in.close ())
+ rw_warn (false, __FILE__, __LINE__,
+ "basic_filebuf<%s>(\"%s\").close() failed",
+ tname, tmpfname);
+
+ REMOVE_FILE (tmpfname);
+}
+
+/***************************************************************************/
+
+
+template <class charT>
+static void
+test_codecvt_with_seek ()
+{
+ rw_info (0, __FILE__, __LINE__,
+ "interleaved input, output, and seeks in ios_base::app "
+ "mode with state-dependent code conversion");
+
+ typedef std::basic_filebuf<charT, std::char_traits<charT> > FileBuf;
+
+ FileBuf inbuf;
+
+ // open this source file
+ inbuf.open (__FILE__, std::ios::in);
+
+ const std::streamsize N = 0xfffff;
+ charT *buf = new charT [N];
+
+ // read the text of the file into a local buffer
+ const std::streamsize nchars = inbuf.sgetn (buf, N);
+
+ if (nchars <= 0) {
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn(..., %d) > 0, got %d", N, nchars);
+ delete[] buf;
+ return;
+ }
+
+ inbuf.close ();
+
+ FileBuf iobuf;
+
+ // imbue a locale containing a CodeCvt<charT> facet into the filebuf
+ iobuf.pubimbue (std::locale (std::locale::classic (), new CodeCvt<charT>));
+
+ const char* const tmpfname = rw_tmpnam (0);
+
+ if (!tmpfname) {
+ delete[] buf;
+ return;
+ }
+
+ // remove file just in case it exists (it shouldn't)
+ std::remove (tmpfname);
+
+ // open the filebuf on a temporary file
+ if (!iobuf.open (tmpfname, std::ios::in | std::ios::out | std::ios::app)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "open (\"%s\", ios::in | ios::out | ios::app) failed",
+ tmpfname);
+ delete[] buf;
+ return;
+ }
+
+ charT *pb = buf;
+
+ // alterante writes, seeks, and reads to/from the filebuf
+ for (std::streamsize n = nchars, i = nchars; n; i = n / 2) {
+
+ const std::streamsize nput = iobuf.sputn (pb, n - i);
+
+ iobuf.pubseekoff (0, std::ios::beg);
+
+ charT *localbuf = new charT [N];
+ const std::streamsize nget = iobuf.sgetn (localbuf, n - i);
+
+ // verify the consistency of the read data
+ if (nget != n - i || std::memcmp (buf, localbuf, nget * sizeof *buf)) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn(..., %d) == %d, got %d (or inconsistent data)",
+ n - i, n - i, nget);
+ delete[] localbuf;
+ break;
+ }
+
+ delete[] localbuf;
+
+ iobuf.pubseekoff (0, std::ios::beg);
+
+ pb += nput;
+ n -= nput;
+
+ }
+
+ iobuf.close ();
+
+ // imbue the filebuf object with a locale with the conversion facet
+ inbuf.pubimbue (std::locale (std::locale::classic (),
+ new CodeCvt<charT>));
+
+ // and open the temporary file one more time
+ if (!inbuf.open (tmpfname, std::ios::in)) {
+ rw_assert (false, __FILE__, __LINE__, "");
+ delete[] buf;
+
+ REMOVE_FILE (tmpfname);
+ return;
+ }
+
+ charT *cvtbuf = new charT [N];
+
+ // read the whole file into a temporary buffer
+ std::streamsize ncvt = inbuf.sgetn (cvtbuf, N);
+
+ // verify that the contents are consistent with the original data
+ if (nchars != ncvt || std::memcmp (buf, cvtbuf, nchars * sizeof *buf)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "sgetn(..., %d) == %d, got %d (or inconsistent data)",
+ N, nchars, ncvt);
+
+ }
+
+ delete[] buf;
+ delete[] cvtbuf;
+
+ // close file before removing it
+ inbuf.close ();
+
+ REMOVE_FILE (tmpfname);
+}
+
+/***************************************************************************/
+
+
+template <class charT>
+static void
+do_test (const char* tname)
+{
+ rw_info (0, __FILE__, __LINE__, "std::basic_filebuf<%s>", tname);
+
+ // exercise basic_filebuf constructors
+ test_ctors<charT> (tname);
+
+ // exercise basic_filebuf::open()
+ test_open<charT> (tname);
+
+ // exercise basic_filebuf::sync()
+ test_sync<charT> (tname);
+
+ // exercise the basic_filebuf::attach() and detach() extensions
+ test_attach<charT> (tname);
+
+ // exercise basic_filebuf functionality with a non-trivial
+ // codecvt facet that implements stateful conversion
+ test_codecvt<charT> (tname);
+ test_codecvt_with_seek<charT> ();
+}
+
+
+static int
+run_test (int /*argc*/, char* /*argv*/ [])
+{
+ do_test<char> ("char");
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ do_test<wchar_t> ("wchar_t");
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ return 0;
+}
+
+
+/*extern*/ int
+main (int argc, char* argv [])
+{
+ return rw_test (argc, argv, __FILE__,
+ "[lib.filebuf]",
+ "", // no comment
+ run_test, "", 0);
+}
+
diff --git a/tests/iostream/27.ios.members.static.cpp b/tests/iostream/27.ios.members.static.cpp
new file mode 100644
index 0000000..437779e
--- /dev/null
+++ b/tests/iostream/27.ios.members.static.cpp
@@ -0,0 +1,462 @@
+/***************************************************************************
+ *
+ * 27.ios.members.static.cpp - test exercising [lib.ios.members.static]
+ *
+ * $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 1994-2008 Rogue Wave Software.
+ *
+ **************************************************************************/
+
+// exercise that the default setting of ios_base::sync_with_stdio()
+// produces the expected output, i.e., that the ouptut of the standard
+// iostream objects, std::cout, std::cerr, etc., is properly interleaved
+// with the output produced by interleaving calls to stdio printf()
+// also exercises the ability of buffered standard iostream objects
+// (i.e., cout, wcout, clog, and wclog) to flush output on program exit
+
+#include <cerrno> // for errno
+#include <cstdio> // for fprintf, L_tmpnam
+#include <cstdlib> // for STD{ERR,OUT}_FILENO
+#include <cstring> // for strerror
+#include <iostream>
+
+// rwtest headers
+#include <driver.h>
+#include <file.h>
+
+#if !defined _WIN32 && !defined _WIN64
+
+# include <fcntl.h>
+# include <unistd.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+
+# define DEV_TTY "/dev/tty"
+
+#else // if defined _WIN32 || defined _WIN64
+
+# include <fcntl.h>
+# include <io.h>
+
+# ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+# define STDOUT_FILENO 1
+# define STDERR_FILENO 2
+# endif // STDIN_FILENO
+
+# define DEV_TTY "CON:"
+
+#endif // _WIN{32,64}
+
+
+// use buffers larger than L_tmpnam with rw_tmpnam()
+char stderr_fname [256]; // name of file to which stderr is redirected
+char stdout_fname [256]; // name of file to which stderr is redirected
+char stdio_fname [256]; // same as above but for both stderr and stdout
+
+/**************************************************************************/
+
+template <class charT>
+/*static*/ void
+test_file (const char* fname, const char* expect)
+{
+ std::FILE* fp = std::fopen (fname, "r");
+
+ if (!fp) {
+ rw_assert (false, __FILE__, __LINE__,
+ "fopen (\"%s\", \"r\") failed: %s",
+ fname, std::strerror (errno));
+
+ return;
+ }
+
+ enum { bufsiz = 256 };
+ char buf [bufsiz] = { 0 };
+ std::fgets (buf, bufsiz, fp);
+
+ rw_assert (!std::strcmp (expect, buf), __FILE__, __LINE__,
+ "expected output: \"%s\", got: \"%s\"", expect, buf);
+
+ std::fclose (fp);
+}
+
+/**************************************************************************/
+
+static void
+do_test ()
+{
+ static const char stdout_expect[] = {
+ "[STDOUT_FILENO]"
+ "[cout,1][stdout,1][cout,2][stdout,2]"
+
+#ifndef _RWSTD_NO_WCHAR_T
+ "[wcout,1][stdout,3][wcout,2][stdout,4]"
+#endif // _RWSTD_NO_WCHAR_T
+ };
+
+ static const char stderr_expect[] = {
+ "[STDERR_FILENO]"
+ "[cerr,1][stderr,1][cerr,2][stderr,2]"
+ "[clog,1][stderr,3][clog,2][stderr,4]"
+
+#ifndef _RWSTD_NO_WCHAR_T
+ "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
+ "[wclog,1][stderr,7][wclog,2][stderr,8]"
+#endif // _RWSTD_NO_WCHAR_T
+ };
+
+ static const char stdio_expect[] = {
+ "[STDOUT_FILENO][STDERR_FILENO]"
+ "[cout,1][stdout,1][cout,2]" // no [stdout,2] here
+ "[cerr,1][stderr,1][cerr,2][stderr,2]"
+ "[clog,1][stderr,3][clog,2][stderr,4]"
+ "[stdout,2]" // but [stdout,2] flushed here
+
+#ifndef _RWSTD_NO_WCHAR_T
+ "[wcout,1][stdout,3][wcout,2]" // no [stdout,2] here
+ "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
+ "[wclog,1][stderr,7][wclog,2][stderr,8]"
+ "[stdout,4]" // but [stdout,2] flushed here
+#endif // _RWSTD_NO_WCHAR_T
+ };
+
+ rw_info (0, __FILE__, __LINE__,
+ "ios_base::sync_with_stdio (true)");
+
+ // call not necessary, stdio synchronized by default
+ // std::ios_base::sync_with_stdio (true);
+
+ rw_info (0, __FILE__, __LINE__,
+ "interleaved std::cout and stdout output");
+ test_file<char> (stdout_fname, stdout_expect);
+
+ rw_info (0, __FILE__, __LINE__,
+ "interleaved std::cerr and stderr output");
+ test_file<char> (stderr_fname, stderr_expect);
+
+ rw_info (0, __FILE__, __LINE__,
+ "interleaved std::cout/cerr and stdout/stderr output");
+ test_file<char> (stdio_fname, stdio_expect);
+}
+
+/**************************************************************************/
+
+static int
+redirect_to_file (const char* fname, int fd)
+{
+ static int fd_tty = open (DEV_TTY, O_WRONLY);
+
+ if (fd_tty < 0) {
+ std::fprintf (stderr,
+ "open (\"" DEV_TTY "\", O_WRONLY) failed: %s\n",
+ std::strerror (errno));
+
+ fd_tty = STDERR_FILENO;
+ }
+
+ char buf [1024];
+ int n;
+
+ // create a new file and redirect `fd' to it
+ const int fd_tmp =
+ open (fname, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666);
+
+ if (fd_tmp < 0) {
+ n = std::sprintf (buf,
+ "open (\"%s\", O_WRONLY | O_CREAT | O_TRUNC, "
+ "0666) failed: %s\n",
+ fname, std::strerror (errno));
+ write (fd_tty, buf, n);
+ return -1; // bail out after a critical error
+ }
+
+ const int fd2 = dup2 (fd_tmp, fd);
+
+ if (0 > fd2) {
+ n = std::sprintf (buf,
+ "dup2 (%d, %d) failed: %s\n",
+ fd2, fd, std::strerror (errno));
+ write (fd_tty, buf, n);
+ return -2; // bail out after a critical error
+ }
+
+ if (fd2 != fd) {
+ n = std::sprintf (buf,
+ "dup2 (%d, %d) != %d; got %d\n",
+ fd_tmp, fd, fd, fd2);
+ // should never happen
+ write (fd_tty, buf, n);
+ }
+
+ if (close (fd_tmp)) {
+ n = std::sprintf (buf,
+ "close (%d) failed: %s\n",
+ fd_tmp, std::strerror (errno));
+ write (fd_tty, buf, n);
+ // proceed after a benign error
+ }
+
+ return fd2;
+}
+
+
+static int
+exec_stdout_setup ()
+{
+ // create a new file and redirect stdout to it
+ const int fd_stdout = redirect_to_file (stdout_fname, STDOUT_FILENO);
+
+ if (fd_stdout != STDOUT_FILENO)
+ return fd_stdout;
+
+ // expected output (w/o newlines):
+ // "[STDOUT_FILENO]"
+ // "[cout,1][stdout,1]"
+ // "[cout,2][stdout,2]"
+ // "[wcout,1][stdout,3]"
+ // "[wcout,2][stdout,4]"
+
+ write (STDOUT_FILENO, "[STDOUT_FILENO]", 15);
+ std::cout << "[cout,1]";
+ std::printf ("[stdout,1]");
+ std::cout << "[cout,2]"; // flushes the printf() above
+ std::printf ("[stdout,2]");
+
+#ifndef _RWSTD_WCHAR_T
+
+ std::wcout << "[wcout,1]"; // flushes the printf() above
+ std::printf ("[stdout,3]");
+ std::wcout << "[wcout,2]"; // flushes the printf() above
+ std::printf ("[stdout,4]"); // flushed during termination
+
+#endif // _RWSTD_WCHAR_T
+
+ return 0;
+}
+
+
+static int
+exec_stderr_setup ()
+{
+ // create a new file and redirect stderr to it
+ const int fd_stderr = redirect_to_file (stderr_fname, STDERR_FILENO);
+
+ if (fd_stderr != STDERR_FILENO)
+ return fd_stderr;
+
+ // expected output (w/o newlines):
+ // "[STDERR_FILENO]"
+ // "[cerr,1][stderr,1][cerr,2][stderr,2]"
+ // "[clog,1][stderr,3][clog,2][stderr,4]"
+ // "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
+ // "[wclog,1][stderr,7][wclog,2][stderr,8]"
+
+ write (STDERR_FILENO, "[STDERR_FILENO]", 15);
+ std::cerr << "[cerr,1]";
+ std::fprintf (stderr, "[stderr,1]");
+ std::cerr << "[cerr,2]";
+ std::fprintf (stderr, "[stderr,2]");
+ std::clog << "[clog,1]";
+ std::fprintf (stderr, "[stderr,3]");
+ std::clog << "[clog,2]";
+ std::fprintf (stderr, "[stderr,4]");
+
+#ifndef _RWSTD_WCHAR_T
+
+ std::wcerr << "[wcerr,1]";
+ std::fprintf (stderr, "[stderr,5]");
+ std::wcerr << "[wcerr,2]";
+ std::fprintf (stderr, "[stderr,6]");
+ std::wclog << "[wclog,1]";
+ std::fprintf (stderr, "[stderr,7]");
+ std::wclog << "[wclog,2]";
+ std::fprintf (stderr, "[stderr,8]");
+
+#endif // _RWSTD_WCHAR_T
+
+ return 0;
+}
+
+
+static int
+exec_stdio_setup ()
+{
+ // create a new file and redirect both stdout and stderr to it
+ const int fd_stdout = redirect_to_file (stdio_fname, STDOUT_FILENO);
+ const int fd_stderr = redirect_to_file (stdio_fname, STDERR_FILENO);
+
+ if (fd_stdout != STDOUT_FILENO)
+ return fd_stdout;
+
+ if (fd_stderr != STDERR_FILENO)
+ return fd_stderr;
+
+ // expected output (w/o newlines):
+ // "[STDOUT_FILENO][STDERR_FILENO]"
+ // "[cout,1][stdout,1][cout,2]"
+ // "[cerr,1][stderr,1][cerr,2][stderr,2]"
+ // "[clog,1][stderr,3][clog,2][stderr,4]"
+ // "[stdout,2]"
+ // "[wcout,1][stdout,3][wcout,2]"
+ // "[wcerr,1][stderr,5][wcerr,2][stderr,6]"
+ // "[wclog,1][stderr,7][wclog,2][stderr,8]"
+ // "[stdout,4]"
+
+ write (STDOUT_FILENO, "[STDOUT_FILENO]", 15);
+ write (STDERR_FILENO, "[STDERR_FILENO]", 15);
+
+ std::cout << "[cout,1]";
+ std::printf ("[stdout,1]");
+ std::cout << "[cout,2]";
+ std::printf ("[stdout,2]"); // flushed after STDERR output below
+
+ std::cerr << "[cerr,1]";
+ std::fprintf (stderr, "[stderr,1]");
+ std::cerr << "[cerr,2]";
+ std::fprintf (stderr, "[stderr,2]");
+ std::clog << "[clog,1]";
+ std::fprintf (stderr, "[stderr,3]");
+ std::clog << "[clog,2]";
+ std::fprintf (stderr, "[stderr,4]");
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ std::wcout << "[wcout,1]";
+ std::printf ("[stdout,3]");
+ std::wcout << "[wcout,2]";
+ std::printf ("[stdout,4]"); // flushed after STDERR output below
+
+ std::wcerr << "[wcerr,1]";
+ std::fprintf (stderr, "[stderr,5]");
+ std::wcerr << "[wcerr,2]";
+ std::fprintf (stderr, "[stderr,6]");
+ std::wclog << "[wclog,1]";
+ std::fprintf (stderr, "[stderr,7]");
+ std::wclog << "[wclog,2]";
+ std::fprintf (stderr, "[stderr,8]");
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ return 0;
+}
+
+/**************************************************************************/
+
+struct cleanup
+{
+ int dummy;
+
+ ~cleanup () {
+ if (*stdout_fname)
+ std::remove (stdout_fname);
+ if (*stderr_fname)
+ std::remove (stderr_fname);
+ if (*stdio_fname)
+ std::remove (stdio_fname);
+ }
+};
+
+
+static int
+run_test (int /* unused */, char* /* unused */ [])
+{
+ const cleanup remove_tmp_files = { 0 };
+
+ // prevent unused warnings
+ (void)&remove_tmp_files;
+
+ if (!rw_tmpnam (stdout_fname)) {
+ std::fprintf (stderr,
+ "rw_tmpnam (%p) failed: %s\n",
+ stdout_fname, std::strerror (errno));
+ return 1;
+ }
+
+ if (!rw_tmpnam (stderr_fname)) {
+ std::fprintf (stderr,
+ "rw_tmpnam (%p) failed: %s\n",
+ stderr_fname, std::strerror (errno));
+ return 1;
+ }
+
+ if (!rw_tmpnam (stdio_fname)) {
+ std::fprintf (stderr,
+ "rw_tmpnam (%p) failed: %s\n",
+ stdio_fname, std::strerror (errno));
+ return 1;
+ }
+
+#if !defined (_WIN32) && !defined (_WIN64)
+
+ // create three child process and have each redirect
+ // its stdout, stderr, and both, respectively, to
+ // a file
+ // after all the children exit, the parent will check
+ // the contents of the file to determine whether all
+ // streams have been properly flushed and synchronized
+
+ for (int i = 0; i != 3; ++i) {
+ const pid_t child_pid = fork ();
+
+ if (child_pid < 0) { // fork error
+
+ std::fprintf (stderr, "fork() failed: %s\n",
+ std::strerror (errno));
+
+ return 1;
+ }
+ else if (child_pid > 0) { // parent
+ wait (0);
+ }
+ else { // child
+
+ int ret = 1;
+
+ switch (i) {
+ case 0: ret = exec_stderr_setup (); break;
+ case 1: ret = exec_stdout_setup (); break;
+ case 2: ret = exec_stdio_setup (); break;
+ }
+
+ // prevent child process from cleaning up files
+ *stdout_fname = *stderr_fname = *stdio_fname = '\0';
+ return ret;
+ }
+ }
+
+#endif // _WIN{32,64}
+
+ do_test ();
+
+ return 0;
+}
+
+
+/* extern */ int
+main (int argc, char* argv [])
+{
+ return rw_test (argc, argv, __FILE__,
+ "lib.ios.members.static",
+ "27.4.2.4 ios_base static members",
+ run_test, "", 0);
+}
+
diff --git a/tests/iostream/27.istream.get.cpp b/tests/iostream/27.istream.get.cpp
new file mode 100644
index 0000000..806e586
--- /dev/null
+++ b/tests/iostream/27.istream.get.cpp
@@ -0,0 +1,170 @@
+/************************************************************************
+ *
+ * 27.istream.get.cpp - test exercising istream::get()
+ *
+ * $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.
+ *
+ **************************************************************************/
+
+#include <fstream>
+#include <sstream>
+
+#include <cstdio>
+#include <cstring>
+
+#include <driver.h>
+
+
+template <class CharT, class FileStream>
+void test_get (FileStream &f, const char *type,
+ const CharT array [], std::size_t)
+{
+ rw_assert (!!f, 0, __LINE__, "basic_ifstream<%s, Traits>", type);
+
+ const CharT delim = f.widen ('\xff');
+
+ CharT buf [5] = { 0 }; // 4 chars + terminating null
+ const std::size_t bufsize = sizeof buf / sizeof *buf;
+
+ std::size_t n = 0;
+
+ // read chars into character buffer, at most 4 at a time
+ while (f.get (buf, bufsize, delim)) {
+
+ rw_assert (f.good () && array [n] == *buf, 0, __LINE__,
+ "%d. basic_ifstream<%s>::get (%p, %d, '\\x%x')",
+ n, type, buf, bufsize, delim);
+
+ ++n;
+
+ CharT ch;
+ f.get (ch);
+
+ rw_assert (f.good () && ch == array [n], 0, __LINE__,
+ "%d. basic_ifstream<%s>::get ('\\x%x'); expected '\\x%x'",
+ n, type, ch, array [n]);
+ ++n;
+ }
+
+ // reached the end of stream
+ rw_assert ((std::ios::eofbit | std::ios::failbit) == f.rdstate (),
+ 0, __LINE__, "basic_ifstream<%s>::get(...)", type);
+}
+
+
+template <class CharT>
+void run_test (CharT, const char *tname)
+{
+ typedef CharT char_type;
+ typedef std::char_traits<char_type> traits_type;
+
+ CharT array [256]; // array of chars
+
+ const std::size_t nelems = sizeof array / sizeof *array;
+
+ // use tmpname(buffer) instead of tmpnam(0) because HP-UX returns 0
+ // for tmpnam (0) on MT environments
+ char fname [L_tmpnam];
+ std::tmpnam (fname);
+
+ rw_fatal (0 != fname, 0, __LINE__, "tmpnam(%#p) != 0", fname);
+
+ if (1) {
+ std::basic_ofstream<char_type, traits_type> f (fname);
+
+ rw_assert (!!f, 0, __LINE__,
+ "basic_ofstream <%s>::basic_ofstream (#%s)",
+ tname, fname);
+
+ // populate array with some chars with '\xff' interspersed
+
+ CharT *p = array;
+
+ for (std::size_t i = 0; std::size_t (i) < nelems / 2; ++i) {
+ *p++ = char_type (i + 1);
+
+ // separate each character with a `\xff'
+ *p++ = f.widen ('\xff');
+ }
+
+ // write array to stream in one shot
+ f.write (array, nelems);
+
+ rw_assert (f.good (), 0, __LINE__,
+ "basic_ofstream<%s>::write (%p, %d)",
+ tname, array, nelems);
+
+ f.close ();
+
+ rw_assert (f.good (), 0, __LINE__,
+ "basic_ofstream<%s>::close()", tname);
+ }
+
+ if (1) {
+ std::basic_ifstream<char_type, traits_type> f (fname);
+
+ rw_assert (!!f, 0, __LINE__,
+ "basic_ifstream<%s>::basic_ifstream (%#s)",
+ tname, fname);
+
+ // see if we can read the whole thing in correctly
+ test_get (f, tname, array, nelems);
+
+ // should have reached EOF above
+ rw_assert ((std::ios::eofbit | std::ios::failbit) == f.rdstate (),
+ 0, __LINE__,
+ "basic_ifstream<%s>::get(...)", tname);
+
+ f.close ();
+
+ // successful close should have no effect on rdstate
+ rw_assert ((std::ios::eofbit | std::ios::failbit) == f.rdstate (),
+ 0, __LINE__,
+ "basic_ifstream<%s>::get(...)", tname);
+ }
+
+ std::remove (fname);
+}
+
+
+static int run_test (int, char**)
+{
+ run_test (char (), "char");
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ run_test (wchar_t (), "wchar_t");
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ return 0;
+}
+
+/**************************************************************************/
+
+int main (int argc, char *argv[])
+{
+ return rw_test (argc, argv, __FILE__,
+ "istream.get",
+ 0 /* no comment */,
+ run_test,
+ "", 0);
+}
diff --git a/tests/iostream/27.std.manip.cpp b/tests/iostream/27.std.manip.cpp
new file mode 100644
index 0000000..d071b3e
--- /dev/null
+++ b/tests/iostream/27.std.manip.cpp
@@ -0,0 +1,710 @@
+/***********************************************************************
+ *
+ * 27.std.manip.cpp - test exercising 27.6.3 - Standard manipulators
+ *
+ * $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 1994-2008 Rogue Wave Software.
+ *
+ **************************************************************************/
+
+#include <rw/_defs.h>
+
+#if !defined _MSC_VER || _MSC_VER > 1310
+
+ // disabled for MSVC to work around its innumerable bugs
+
+ // prevent the inclusion of non-essential public headers; only headers
+ // necessary to compile each header #included here are #included
+ // will produce errors if any templates defined in the header are
+ // instantiated without the names they use having been completely defined
+# define _RWSTD_NO_REDUNDANT_DEFINITIONS
+
+ // prevent out-of-line template definitions in .cc files from being
+ // explicitly #included during the processing of library headers (faster
+ // compilation) assumes that the test doesn't instantiate those templates
+ // on types other than those they were explcitly instantiated on (will
+ // have no effect if explicit instantiation is disabled or unsupported)
+# define _RWSTD_NO_TEMPLATE_DEFINITIONS
+#endif // !defined _MSC_VER || _MSC_VER > 1310
+
+
+#include <climits>
+#include <iomanip>
+#include <istream>
+#include <ostream>
+#include <sstream>
+
+#include <driver.h>
+
+/***********************************************************************/
+
+// user-defined Traits type exercises the ability to instantiate
+// std::ws and any supporting templates on types other than the
+// default std::char_traits<charT>
+
+template <class charT>
+struct CharTraits: std::char_traits<charT> { /* empty */ };
+
+template < typename T >
+/*static*/ const char* type_name ();
+
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ const char*
+type_name< char > ()
+{
+ return "char";
+}
+
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ const char*
+type_name< std::char_traits<char> > ()
+{
+ return "std::char_traits<char>";
+}
+
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ const char*
+type_name< CharTraits<char> > ()
+{
+ return "CharTraits<char>";
+}
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ const char*
+type_name< wchar_t > ()
+{
+ return "wchar_t";
+}
+
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ const char*
+type_name< std::char_traits<wchar_t> > ()
+{
+ return "std::char_traits<wchar_t>";
+}
+
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ const char*
+type_name< CharTraits<wchar_t> > ()
+{
+ return "CharTraits<wchar_t>";
+}
+
+#endif // _RWSTD_NO_WCHAR_T
+
+/***********************************************************************/
+
+enum Manip {
+ resetiosflags,
+ setiosflags,
+ setbase,
+ setfill,
+ setprecision,
+ setw
+};
+
+
+template <class charT, class Traits>
+struct StreamBuf: std::basic_streambuf<charT, Traits> { /* empty */ };
+
+
+template <class charT, class Traits>
+static int
+test (int lineno, Manip m, int iarg, charT carg)
+{
+ static/*?*/ const char* const cname = type_name< charT > ();
+ static/*?*/ const char* const tname = type_name< Traits > ();
+
+ typedef std::ios_base::fmtflags Fmtflags;
+ typedef std::basic_istream<charT, Traits> Istream;
+ typedef std::basic_ostream<charT, Traits> Ostream;
+ typedef std::basic_iostream<charT, Traits> IOstream;
+
+ StreamBuf<charT, Traits> sb;
+
+ // stream objects used to apply manipulators to
+ Istream in1 (&sb);
+ Ostream out1 (&sb);
+ IOstream inout1 (&sb);
+
+ // stream objects used to call member functions on
+ Istream in2 (&sb);
+ Ostream out2 (&sb);
+ IOstream inout2 (&sb);
+
+ int nfailed = 0;
+
+ switch (m) {
+
+ case resetiosflags: { // exercise 27.6.3, p3
+
+ Istream &in3 = in1 >> std::resetiosflags (Fmtflags (iarg));
+ in2.setf (Fmtflags (0), Fmtflags (iarg));
+
+ if (in2.flags () != in3.flags ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "in >> std::resetiosflags(%{If}) with basic_istream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ Ostream &out3 = out1 << std::resetiosflags (Fmtflags (iarg));
+ out2.setf (Fmtflags (0), Fmtflags (iarg));
+
+ if (out2.flags () != out3.flags ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "out << std::resetiosflags(%{If}) with basic_ostream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ Ostream &inout3 = inout1 << std::resetiosflags (Fmtflags (iarg));
+ inout2.setf (Fmtflags (0), Fmtflags (iarg));
+
+ if (inout2.flags () != inout3.flags ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "io << std::resetiosflags(%{If}) with basic_iostream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ break;
+ }
+
+ case setiosflags: { // exercise 27.6.3, p3
+
+ Istream &in3 = in1 >> std::setiosflags (Fmtflags (iarg));
+ in2.setf (Fmtflags (iarg));
+
+ if (in2.flags () != in3.flags ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setiosflags (%s) with basic_istream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ Ostream &out3 = out1 << std::setiosflags (Fmtflags (iarg));
+ out2.setf (Fmtflags (iarg));
+
+ if (out2.flags () != out3.flags ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setiosflags (%s) with basic_ostream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ Ostream &inout3 = inout1 << std::setiosflags (Fmtflags (iarg));
+ inout2.setf (Fmtflags (iarg));
+
+ if (inout2.flags () != inout3.flags ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setiosflags (%s) with basic_iostream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ break;
+ }
+
+ case setbase: { // exercise 27.6.3, p5
+
+ out1 << std::setbase (iarg);
+
+ if (0 == iarg || 2 == iarg || 8 == iarg || 10 ==iarg || 16 == iarg) {
+ out2.setf ( 8 == iarg ? std::ios_base::oct
+#ifndef _RWSTD_NO_EXT_BIN_IO
+ : 2 == iarg ? std::ios_base::bin
+#endif // _RWSTD_NO_EXT_BIN_IO
+ : 10 == iarg ? std::ios_base::dec
+ : 16 == iarg ? std::ios_base::hex
+ : Fmtflags (0),
+ std::ios_base::basefield);
+
+ if (out1.flags () != out2.flags ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setbase (%d)", iarg);
+ }
+ }
+
+ std::basic_ostringstream<charT, std::char_traits<charT> > ostrm;
+
+ static const struct {
+ charT str[12];
+ } num[] = {
+ { { '1', '2', '3', '4', '\0' } }, // dec
+ { { 'm', 'c', 'c', 'x', 'x', 'x', 'i', 'v', '\0' } }, // roman
+ { { '1', '0', '0', '1', '1', '0', '1', '0', '0', '1', '0', '\0' } },
+ { { '1', '2', '0', '0', '2', '0', '1', '\0' } }, // 3
+ { { '1', '0', '3', '1', '0', '2', '\0' } }, // 4
+ { { '1', '4', '4', '1', '4', '\0' } }, // 5
+ { { '5', '4', '1', '4', '\0' } }, // 6
+ { { '3', '4', '1', '2', '\0' } }, // 7
+ { { '2', '3', '2', '2', '\0' } }, // oct
+ { { '1', '6', '2', '1', '\0' } }, // 9
+ { { '1', '2', '3', '4', '\0' } }, // dec
+ { { 'a', '2', '2', '\0' } }, // 11
+ { { '8', '6', 'a', '\0' } }, // 12
+ { { '7', '3', 'c', '\0' } }, // 13
+ { { '6', '4', '2', '\0' } }, // 14
+ { { '5', '7', '4', '\0' } }, // 15
+ { { '4', 'd', '2', '\0' } }, // hex
+ { { '4', '4', 'a', '\0' } }, // 17
+ { { '3', 'e', 'a', '\0' } }, // 18
+ { { '3', '7', 'i', '\0' } }, // 19
+ { { '3', '1', 'e', '\0' } }, // 20
+ { { '2', 'g', 'g', '\0' } }, // 21
+ { { '2', 'c', '2', '\0' } }, // 22
+ { { '2', '7', 'f', '\0' } }, // 23
+ { { '2', '3', 'a', '\0' } }, // 24
+ { { '1', 'o', '9', '\0' } }, // 25
+ { { '1', 'l', 'c', '\0' } }, // 26
+ { { '1', 'i', 'j', '\0' } }, // 27
+ { { '1', 'g', '2', '\0' } }, // 28
+ { { '1', 'd', 'g', '\0' } }, // 29
+ { { '1', 'b', '4', '\0' } }, // 30
+ { { '1', '8', 'p', '\0' } }, // 31
+ { { '1', '6', 'i', '\0' } }, // 32
+ { { '1', '4', 'd', '\0' } }, // 33
+ { { '1', '2', 'a', '\0' } }, // 34
+ { { '1', '0', '9', '\0' } }, // 35
+ { { 'y', 'a', '\0' } } // 36
+ };
+
+ ostrm << std::setbase (iarg);
+ ostrm << 1234;
+
+ const int inx = iarg >= 0 && iarg <= 36 ? iarg : 0;
+
+ if (ostrm.str () != num [inx].str) {
+ ++nfailed;
+ rw_assert (0, __FILE__, __LINE__,
+ "std::setbase (%d) inserted 1234 as \"%s\"; "
+ "expected \"%s\"", iarg,
+ ostrm.str ().data (), num [inx].str);
+ }
+
+ break;
+ }
+
+ case setfill: { // exercise 27.6.3, p6
+ Istream &in3 = in1 >> std::setfill (carg);
+ in2.fill (carg);
+
+ if (in2.fill () != in3.fill ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "in >> std::setfill('%c') with basic_istream"
+ "<%s, %s >", carg, cname, tname);
+ }
+
+ Ostream &out3 = out1 << std::setfill (carg);
+ out2.fill (carg);
+
+ if (out2.fill () != out3.fill ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "out << std::setfill('%c') with basic_ostream"
+ "<%s, %s >", carg, cname, tname);
+ }
+
+ Ostream &inout3 = inout1 << std::setfill (carg);
+ inout2.fill (carg);
+
+ if (inout2.fill () != inout3.fill ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "io << std::setfill('%c') with basic_iostream"
+ "<%s, %s >", carg, cname, tname);
+ }
+
+ break;
+ }
+
+ case setprecision: { // exercise 27.6.3, p7
+
+ Istream &in3 = in1 >> std::setprecision (iarg);
+ in2.precision (std::streamsize (iarg));
+
+ if (in2.precision () != in3.precision ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setprecision (%d) with basic_istream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ Ostream &out3 = out1 << std::setprecision (iarg);
+ out2.precision (std::streamsize (iarg));
+
+ if (out2.precision () != out3.precision ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setprecision (%d) with basic_ostream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ Ostream &inout3 = inout1 << std::setprecision (iarg);
+ inout2.precision (std::streamsize (iarg));
+
+ if (inout2.precision () != inout3.precision ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setprecision (%d) with basic_iostream "
+ "<%s, %s >", iarg, cname, tname);
+ }
+
+ break;
+ }
+
+ case setw: { // exercise 27.6.3, p8
+
+ Istream &in3 = in1 >> std::setw (iarg);
+ in2.width (std::streamsize (iarg));
+
+ if (in2.width () != in3.width ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setw (%d) with basic_istream<%s, %s >",
+ iarg, cname, tname);
+ }
+
+ Ostream &out3 = out1 << std::setw (iarg);
+ out2.width (std::streamsize (iarg));
+
+ if (out2.width () != out3.width ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setw (%d) with basic_ostream<%s, %s >",
+ iarg, cname, tname);
+ }
+
+ Ostream &inout3 = inout1 << std::setw (iarg);
+ inout2.width (std::streamsize (iarg));
+
+ if (inout2.width () != inout3.width ()) {
+ ++nfailed;
+ rw_assert (0, __FILE__, lineno,
+ "std::setw (%d) with basic_iostream<%s, %s >",
+ iarg, cname, tname);
+ }
+
+ break;
+ }
+
+ }
+
+ return nfailed;
+}
+
+/***********************************************************************/
+
+// 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
+
+
+template <class charT, class Traits>
+static void do_test ()
+{
+#define TEST(M, V, C) \
+ ++ntried; nfailed += test< charT, Traits > (__LINE__, M, V, C)
+
+ int ntried = 0;
+ int nfailed = 0;
+
+ /////////////////////////////////////////////////////////////////////
+ // exercise std::resetiosflags
+
+ const char* const cname = type_name< charT > ();
+ const char* const tname = type_name< Traits > ();
+
+ rw_info (0, __FILE__, __LINE__,
+ "27.6.3, p3 - std::resetiosflags(ios_base::"
+ "fmtflags) with basic_{i,o,io}stream<%s, %s >",
+ cname, tname);
+
+ TEST (resetiosflags, Boolalpha, charT ());
+ TEST (resetiosflags, Dec, charT ());
+ TEST (resetiosflags, Fixed, charT ());
+ TEST (resetiosflags, Hex, charT ());
+ TEST (resetiosflags, Internal, charT ());
+ TEST (resetiosflags, Left, charT ());
+ TEST (resetiosflags, Oct, charT ());
+ TEST (resetiosflags, Right, charT ());
+ TEST (resetiosflags, Scientific, charT ());
+ TEST (resetiosflags, Showbase, charT ());
+ TEST (resetiosflags, Showpoint, charT ());
+ TEST (resetiosflags, Showpos, charT ());
+ TEST (resetiosflags, Skipws, charT ());
+ TEST (resetiosflags, Unitbuf, charT ());
+ TEST (resetiosflags, Uppercase, charT ());
+
+#ifndef _RWSTD_NO_EXT_BIN_IO
+
+ TEST (resetiosflags, Bin, charT ());
+
+#endif // _RWSTD_NO_EXT_BIN_IO
+
+ TEST (resetiosflags, Adjustfield, charT ());
+ TEST (resetiosflags, Basefield, charT ());
+ TEST (resetiosflags, Floatfield, charT ());
+
+#ifndef _RWSTD_NO_EXT_REENTRANT_IO
+
+ TEST (resetiosflags, Nolock, charT ());
+ TEST (resetiosflags, Nolockbuf, charT ());
+
+#endif // _RWSTD_NO_EXT_REENTRANT_IO
+
+
+ TEST (resetiosflags, Oct | Dec, charT ());
+ TEST (resetiosflags, Oct | Hex, charT ());
+ TEST (resetiosflags, Dec | Hex, charT ());
+ TEST (resetiosflags, Oct | Dec | Hex, charT ());
+
+ TEST (resetiosflags, Left | Internal, charT ());
+ TEST (resetiosflags, Left | Right, charT ());
+ TEST (resetiosflags, Right | Internal, charT ());
+ TEST (resetiosflags, Left | Right | Internal, charT ());
+
+ TEST (resetiosflags, Showbase | Showpoint, charT ());
+ TEST (resetiosflags, Showbase | Showpos, charT ());
+ TEST (resetiosflags, Showbase | Showpoint | Showpos, charT ());
+
+ if (!nfailed)
+ rw_assert (true, __FILE__, __LINE__,
+ "std::resetiosflags failed %d out "
+ "of %d assertions", nfailed, ntried);
+
+ /////////////////////////////////////////////////////////////////////
+ // exercise std::setiosflags
+
+ rw_info (0, __FILE__, __LINE__,
+ "27.6.3, p4 - std::setiosflags(ios_base::"
+ "fmtflags) with basic_{i,o,io}stream<%s, %s >",
+ cname, tname);
+
+ ntried = nfailed = 0;
+
+ TEST (setiosflags, Boolalpha, charT ());
+ TEST (setiosflags, Dec, charT ());
+ TEST (setiosflags, Fixed, charT ());
+ TEST (setiosflags, Hex, charT ());
+ TEST (setiosflags, Internal, charT ());
+ TEST (setiosflags, Left, charT ());
+ TEST (setiosflags, Oct, charT ());
+ TEST (setiosflags, Right, charT ());
+ TEST (setiosflags, Scientific, charT ());
+ TEST (setiosflags, Showbase, charT ());
+ TEST (setiosflags, Showpoint, charT ());
+ TEST (setiosflags, Showpos, charT ());
+ TEST (setiosflags, Skipws, charT ());
+ TEST (setiosflags, Unitbuf, charT ());
+ TEST (setiosflags, Uppercase, charT ());
+
+#ifndef _RWSTD_NO_EXT_BIN_IO
+
+ TEST (setiosflags, Bin, charT ());
+
+#endif // _RWSTD_NO_EXT_BIN_IO
+
+ TEST (setiosflags, Adjustfield, charT ());
+ TEST (setiosflags, Basefield, charT ());
+ TEST (setiosflags, Floatfield, charT ());
+ TEST (setiosflags, Nolock, charT ());
+ TEST (setiosflags, Nolockbuf, charT ());
+
+ if (!nfailed)
+ rw_assert (true, __FILE__, __LINE__,
+ "std::setiosflags failed %d out "
+ "of %d assertions", nfailed, ntried);
+
+ /////////////////////////////////////////////////////////////////////
+ // exercise std::setbase
+
+ rw_info (0, __FILE__, __LINE__,
+ "27.6.3, p5 - std::setbase(int) with "
+ "basic_{i,o,io}stream<%s, %s >", cname, tname);
+
+ ntried = nfailed = 0;
+
+ TEST (setbase, 0, charT ());
+ TEST (setbase, 8, charT ());
+ TEST (setbase, 10, charT ());
+ TEST (setbase, 16, charT ());
+
+#ifndef _RWSTD_NO_EXT_BIN_IO
+
+ TEST (setbase, 2, charT ());
+
+#endif // _RWSTD_NO_EXT_BIN_IO
+
+#ifndef _RWSTD_NO_EXT_SETBASE
+
+ TEST (setbase, 0, charT ()); // autodetect
+ TEST (setbase, 1, charT ()); // roman
+ TEST (setbase, 2, charT ()); // bin
+ TEST (setbase, 3, charT ());
+ TEST (setbase, 4, charT ());
+ TEST (setbase, 5, charT ());
+ TEST (setbase, 6, charT ());
+ TEST (setbase, 7, charT ());
+ TEST (setbase, 8, charT ()); // oct
+ TEST (setbase, 9, charT ());
+ TEST (setbase, 10, charT ()); // dec
+ TEST (setbase, 11, charT ());
+ TEST (setbase, 12, charT ());
+ TEST (setbase, 16, charT ()); // hex
+ TEST (setbase, 17, charT ());
+ TEST (setbase, 36, charT ()); // 0-9, a-z
+ TEST (setbase, -1, charT ());
+ TEST (setbase, -2, charT ());
+
+#endif // _RWSTD_NO_EXT_SETBASE
+
+ if (!nfailed)
+ rw_assert (true, __FILE__, __LINE__,
+ "std::setbase failed %d out "
+ "of %d assertions", nfailed, ntried);
+
+ /////////////////////////////////////////////////////////////////////
+ // exercise std::setfill
+
+ rw_info (0, __FILE__, __LINE__,
+ "27.6.3, p6 - std::setfill(%s) with "
+ "basic_{i,o,io}stream<%s, %s >", cname, cname, tname);
+
+ ntried = nfailed = 0;
+
+ TEST (setfill, 0, charT ('\0'));
+ TEST (setfill, 0, charT ('\a'));
+ TEST (setfill, 0, charT ('\n'));
+ TEST (setfill, 0, charT ('\r'));
+ TEST (setfill, 0, charT ('\t'));
+ TEST (setfill, 0, charT ('\v'));
+ TEST (setfill, 0, charT (' '));
+ TEST (setfill, 0, charT ('*'));
+ TEST (setfill, 0, charT ('#'));
+
+ if (!nfailed)
+ rw_assert (true, __FILE__, __LINE__,
+ "std::setfill failed %d out "
+ "of %d assertions", nfailed, ntried);
+
+ /////////////////////////////////////////////////////////////////////
+ // exercise std::setprecision
+
+ rw_info (0, __FILE__, __LINE__,
+ "27.6.3, p7 - std::setprecision(int) with "
+ "basic_{i,o,io}stream<%s, %s >", cname, tname);
+
+ ntried = nfailed = 0;
+
+ TEST (setprecision, 0, charT ());
+ TEST (setprecision, 1, charT ());
+ TEST (setprecision, 2, charT ());
+ TEST (setprecision, SHRT_MAX, charT ());
+ TEST (setprecision, INT_MAX, charT ());
+ TEST (setprecision, -1, charT ());
+ TEST (setprecision, -2, charT ());
+ TEST (setprecision, SHRT_MIN, charT ());
+ TEST (setprecision, INT_MIN, charT ());
+
+ if (!nfailed)
+ rw_assert (true, __FILE__, __LINE__,
+ "std::setprecision failed %d out "
+ "of %d assertions", nfailed, ntried);
+
+ /////////////////////////////////////////////////////////////////////
+ // exercise std::setw
+
+ rw_info (0, __FILE__, __LINE__,
+ "27.6.3, p8 - std::setw(int) with "
+ "basic_{i,o,io}stream<%s, %s >", cname, tname);
+
+ ntried = nfailed = 0;
+
+ TEST (setw, 0, charT ());
+ TEST (setw, 1, charT ());
+ TEST (setw, 2, charT ());
+ TEST (setw, SHRT_MAX, charT ());
+ TEST (setw, INT_MAX, charT ());
+ TEST (setw, -1, charT ());
+ TEST (setw, -2, charT ());
+ TEST (setw, SHRT_MIN, charT ());
+ TEST (setw, INT_MIN, charT ());
+
+ if (!nfailed)
+ rw_assert (true, __FILE__, __LINE__,
+ "std::setw failed %d out "
+ "of %d assertions", nfailed, ntried);
+}
+
+/***********************************************************************/
+
+static int
+run_test (int /*argc*/, char* /*argv*/ [])
+{
+ do_test<char, std::char_traits<char> > ();
+ do_test<char, CharTraits<char> > ();
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ do_test<wchar_t, std::char_traits<wchar_t> > ();
+ do_test<wchar_t, CharTraits<wchar_t> > ();
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ return 0;
+}
+
+
+/*extern*/ int
+main (int argc, char* argv [])
+{
+ return rw_test (argc, argv, __FILE__,
+ "[lib.std.manip]",
+ "27.6.3 Standard manipulators",
+ run_test, "", 0);
+}
+
diff --git a/tests/localization/22.locale.codecvt.cpp b/tests/localization/22.locale.codecvt.cpp
new file mode 100644
index 0000000..cdb192a
--- /dev/null
+++ b/tests/localization/22.locale.codecvt.cpp
@@ -0,0 +1,2610 @@
+/***************************************************************************
+ *
+ * 22.locale.codecvt.cpp - test exercising the std::codecvt<> facets
+ *
+ * $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 1994-2008 Rogue Wave Software.
+ *
+ **************************************************************************/
+
+#ifdef __SUNPRO_CC
+ // working around a SunPro/SunOS 5.8 bug (PR #26255)
+# include <time.h>
+#endif // __SUNPRO_CC
+
+#include <locale>
+
+#include <cassert>
+#include <climits>
+#include <clocale>
+#include <csetjmp> // for longjmp(), setjmp(), ...
+#include <csignal> // for SIGABRT, signal()
+#include <cstdlib>
+#include <cstring>
+#include <cstdio>
+#include <cwchar> // for mbstate_t
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef _MSC_VER
+# include <iconv.h> // for iconv(), iconv_open(), iconv_close()
+# include <langinfo.h> // for CODESET, nl_langinfo()
+# include <unistd.h>
+#else
+# include <direct.h>
+#endif
+
+#define DEFINE_REPLACEMENT_NEW_AND_DELETE
+#include <driver.h>
+#include <file.h>
+#include <rw_locale.h>
+
+#ifndef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+// No dependency on C library min/max
+#undef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+/****************************************************************************/
+
+// mbs/wcs helper functions
+#if !defined _RWSTD_NO_WCHAR_T
+
+template <class T>
+/*static*/ std::size_t
+rwtest_mbstowcs (std::mbstate_t& state, T* pi,
+ const char* pe, std::size_t srclen)
+{
+# ifndef _RWSTD_NO_MBSRTOWCS
+
+ return std::mbsrtowcs (pi, &pe, srclen, &state);
+
+# else // if defined _RWSTD_NO_MBSRTOWCS
+
+ _RWSTD_UNUSED (state);
+ return std::mbstowcs (pi, pe, srclen);
+
+# endif // _RWSTD_NO_MBSRTOWCS
+}
+
+
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ std::size_t
+rwtest_mbstowcs<char> (std::mbstate_t& /*unused*/, char* /*unused*/,
+ const char* /*unused*/, std::size_t /*unused*/)
+{
+ return 0;
+}
+
+template <class charT>
+inline std::size_t
+rwtest_wcstombs (std::mbstate_t& state, const charT* pi,
+ char* pe, std::size_t srclen)
+{
+# ifndef _RWSTD_NO_WCSRTOMBS
+
+ return std::wcsrtombs (pe, &pi, srclen, &state);
+
+# else // if defined _RWSTD_NO_WCSRTOMBS)
+
+ _RWSTD_UNUSED (state);
+ return std::wcstombs (pe, pi, srclen);
+
+# endif // _RWSTD_NO_WCSRTOMBS
+}
+
+_RWSTD_SPECIALIZED_FUNCTION
+inline std::size_t
+rwtest_wcstombs<char>(std::mbstate_t& /*unused*/, const char* /*unused*/,
+ char* /*unused*/, std::size_t /*unused*/)
+{
+ return 0;
+}
+
+#endif // !defined _RWSTD_NO_WCHAR_T
+
+
+static std::size_t
+rwtest_mbslen (std::mbstate_t& state,
+ const char* pe,
+ const char* limit,
+ std::size_t cmax)
+{
+ std::size_t total = 0;
+ std::size_t ret = 0;
+
+ while (total < cmax && pe < limit)
+ {
+#ifndef _RWSTD_NO_MBRLEN
+
+ ret = std::mbrlen (pe, min (_RWSTD_MB_LEN_MAX, limit - pe), &state);
+
+#else // if defined _RWSTD_NO_MBRLEN
+
+ _RWSTD_UNUSED (state);
+ ret = std::mblen (pe, min (_RWSTD_MB_LEN_MAX, limit - pe));
+
+#endif // _RWSTD_NO_MBRLEN
+
+ if (ret >= std::size_t (-2))
+ break;
+
+ pe += ret;
+ ++total;
+ }
+
+ return total;
+}
+
+/****************************************************************************/
+
+// The codecvt facets and their required specializations
+typedef std::codecvt_base::result CodecvtResult;
+typedef std::codecvt<char,char,std::mbstate_t> Codecvt;
+typedef std::codecvt_byname<char,char,std::mbstate_t> CodecvtBn;
+
+#ifndef _RWSTD_NO_WCHAR_T
+typedef std::codecvt<wchar_t,char,std::mbstate_t> CodecvtW;
+typedef std::codecvt_byname<wchar_t,char,std::mbstate_t> CodecvtBnW;
+#endif // _RWSTD_NO_WCHAR_T
+
+
+// Type names used in assertion messages
+template <class T>
+struct TypeName
+{
+ static const char* name;
+};
+
+_RWSTD_SPECIALIZED_CLASS const char*
+TypeName<char>::name = "char";
+
+_RWSTD_SPECIALIZED_CLASS const char*
+TypeName<Codecvt>::name = "std::codecvt<char, char, std::mbstate_t>";
+
+_RWSTD_SPECIALIZED_CLASS const char*
+TypeName<CodecvtBn>::name = "std::codecvt_byname<char, char, std::mbstate_t>";
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+_RWSTD_SPECIALIZED_CLASS const char*
+TypeName<wchar_t>::name = "wchar_t";
+
+_RWSTD_SPECIALIZED_CLASS const char*
+TypeName<CodecvtW>::name = "std::codecvt<wchar_t, char, std::mbstate_t>";
+
+_RWSTD_SPECIALIZED_CLASS const char*
+TypeName<CodecvtBnW>::name =
+ "std::codecvt_byname<wchar_t, char, std::mbstate_t>";
+
+#endif // _RWSTD_NO_WCHAR_T
+
+/****************************************************************************/
+
+// bitmasks for calls to virtual functions
+enum {
+ dtor = 1 << 0,
+ do_out = 1 << 1,
+ do_in = 1 << 2,
+ do_unshift = 1 << 3,
+ do_encoding = 1 << 4,
+ do_always_noconv = 1 << 5,
+ do_length = 1 << 6,
+ do_max_length = 1 << 7
+};
+
+// bitset for all virtual function calls
+int call = 0;
+
+// template class for testing virtual calls
+template <class Base>
+struct CodecvtDerived: Base
+{
+ typedef Base base_type;
+ typedef typename base_type::intern_type itype;
+ typedef typename base_type::extern_type etype;
+ typedef typename base_type::state_type stype;
+ typedef typename std::codecvt_base::result result;
+
+ CodecvtDerived (const char*);
+
+ virtual ~CodecvtDerived () {
+ call |= ::dtor;
+ }
+
+ result
+ do_out (stype&, const itype*, const itype*, const itype*&,
+ etype*, etype*, etype*&) const {
+ call |= ::do_out;
+ return result ();
+ }
+
+ result
+ do_in (stype&, const etype*, const etype*, const etype*&,
+ itype*, itype*, itype*&) const {
+ call |= ::do_in;
+ return result ();
+ }
+
+ result
+ do_unshift (stype&, etype*, etype*, etype*&) const {
+ call |= ::do_unshift;
+ return result ();
+ }
+
+ int do_encoding () const _THROWS (()) {
+ call |= ::do_encoding;
+ return 0;
+ }
+
+ bool do_always_noconv () const _THROWS (()) {
+ call |= ::do_always_noconv;
+ return false;
+ }
+
+ int do_length (stype&, const etype*, const etype*,
+ std::size_t) const {
+ call |= ::do_length;
+ return 0;
+ }
+
+ int do_max_length () const _THROWS (()) {
+ call |= ::do_max_length;
+ return 0;
+ }
+};
+
+
+// specialization for the class constructor in CodecvtDerived
+_RWSTD_SPECIALIZED_CLASS
+CodecvtDerived<Codecvt>::CodecvtDerived (const char* /*unused*/)
+ : Codecvt () { }
+
+_RWSTD_SPECIALIZED_CLASS
+CodecvtDerived<CodecvtBn>::CodecvtDerived (const char* name)
+ : CodecvtBn (name) { }
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+_RWSTD_SPECIALIZED_CLASS
+CodecvtDerived<CodecvtW>::CodecvtDerived (const char* /*unused*/)
+ : CodecvtW () { }
+
+_RWSTD_SPECIALIZED_CLASS
+CodecvtDerived<CodecvtBnW>::CodecvtDerived (const char* name)
+ : CodecvtBnW (name) { }
+
+#endif // _RWSTD_NO_WCHAR_T
+
+
+// Tests the call of virtual member functions in codecvt facets
+template <class CodeCvtT>
+static void
+test_virtuals (const char* locale_name)
+{
+ rw_info (0, __FILE__, __LINE__,
+ "%s virtual functions", TypeName<CodeCvtT>::name);
+
+ CodecvtDerived<CodeCvtT> pccvt (locale_name);
+ CodeCvtT& cc = pccvt;
+
+ typedef typename CodeCvtT::intern_type intern_type;
+ typedef typename CodeCvtT::extern_type extern_type;
+
+ const extern_type* pce = 0;
+ extern_type* pe = 0;
+ const intern_type* pci = 0;
+ intern_type* pi = 0;
+
+ std::mbstate_t st = std::mbstate_t ();
+
+ // verify 22.2.1.5.1, p1
+ cc.out (st, pci, pci, pci, pe, pe, pe );
+ rw_assert ((call & do_out) != 0, __FILE__, __LINE__,
+ "%s::do_out call failed.", TypeName<CodeCvtT>::name);
+
+ // verify 22.2.1.5.1, p2
+ cc.in (st, pce, pce, pce, pi, pi, pi );
+ rw_assert ((call & do_in) != 0, __FILE__, __LINE__,
+ "%s::do_in call failed.", TypeName<CodeCvtT>::name);
+
+ // verify 22.2.1.5.1, p3
+ cc.unshift (st, pe, pe, pe);
+ rw_assert ((call & do_unshift) != 0, __FILE__, __LINE__,
+ "%s::do_unshift call failed.", TypeName<CodeCvtT>::name);
+
+ // verify 22.2.1.5.1, p4
+ cc.encoding ();
+ rw_assert ((call & do_encoding) != 0, __FILE__, __LINE__,
+ "%s::do_encoding call failed.", TypeName<CodeCvtT>::name);
+
+ // verify 22.2.1.5.1, p5
+ cc.always_noconv ();
+ rw_assert ((call & do_always_noconv) != 0, __FILE__, __LINE__,
+ "%s::do_always_noconv call failed.", TypeName<CodeCvtT>::name);
+
+ // verify 22.2.1.5.1, p6
+ cc.length (st, pce, pce, 0);
+ rw_assert ((call & do_length) != 0, __FILE__, __LINE__,
+ "%s::do_length call failed.", TypeName<CodeCvtT>::name);
+
+ // verify 22.2.1.5.1, p7
+ cc.max_length ();
+ rw_assert ((call & do_max_length) != 0, __FILE__, __LINE__,
+ "%s::do_max_length call failed.", TypeName<CodeCvtT>::name);
+}
+
+/****************************************************************************/
+
+const Codecvt& create_Codecvt (const std::locale&)
+{
+ static Codecvt cc;
+ return cc;
+}
+
+const CodecvtBn& create_CodecvtBn (const std::locale& loc)
+{
+ return _STD_USE_FACET (CodecvtBn, loc);
+}
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+const CodecvtW& create_CodecvtW (const std::locale&)
+{
+ static CodecvtW cc;
+ return cc;
+}
+
+const CodecvtBnW& create_CodecvtBnW (const std::locale& loc)
+{
+ return _STD_USE_FACET (CodecvtBnW, loc);
+}
+
+#endif // !defined _RWSTD_NO_WCHAR_T
+
+
+// facet operations results
+static const char*
+rwtest_codecvt_result (int res)
+{
+ // allow the function to be called up to 8 times in the same expression
+ // without overwriting the static buffer (each call will return a pointer
+ // to a new array)
+ static char buf [8][16];
+
+ static std::size_t index;
+
+ std::size_t inx = index;
+
+ index = (index + 1) % sizeof buf / sizeof *buf;
+
+ std::sprintf (buf [inx], "%#x", res);
+
+ return buf [inx];
+}
+
+static const char*
+rwtest_codecvt_result (CodecvtResult res)
+{
+ static const struct {
+ CodecvtResult res;
+ const char* str;
+ } results [] = {
+ { std::codecvt_base::ok, "std::codecvt_base::ok" },
+ { std::codecvt_base::partial, "std::codecvt_base::partial" },
+ { std::codecvt_base::noconv, "std::codecvt_base::noconv" },
+ { std::codecvt_base::error, "std::codecvt_base::error" }
+ };
+
+ for (unsigned i = 0; i != sizeof results / sizeof *results; ++i)
+ if (res == results [i].res)
+ return results [i].str;
+
+ return rwtest_codecvt_result (int (res));
+}
+
+/****************************************************************************/
+
+static bool
+rwtest_is_C_locale (const char* s)
+{
+ const char* old = std::setlocale (LC_ALL, s);
+ if (old == 0)
+ return false;
+
+ std::setlocale (LC_ALL, old);
+ return true;
+}
+
+/****************************************************************************/
+
+// Test custom locales, built on the fly
+template <class CodeCvtT>
+static void
+test_libstd_do_in (const char* locale_name, const CodeCvtT& cc,
+ const typename CodeCvtT::extern_type* buffe,
+ typename CodeCvtT::intern_type*& buffi,
+ std::size_t sze, std::size_t& szi,
+ bool skip_C,
+ CodecvtResult& res, std::size_t& sz)
+{
+ // buffers types
+ typedef typename CodeCvtT::intern_type intern_t;
+ typedef typename CodeCvtT::extern_type extern_t;
+
+ const extern_t* pe = buffe;
+ const extern_t* pen = buffe;
+ const extern_t* pe_limit = buffe + sze;
+
+ szi = sze;
+ buffi = new intern_t [szi];
+ std::memset (buffi, 0, szi * sizeof (intern_t));
+
+ intern_t* pi = buffi;
+ intern_t* pin = pi;
+ intern_t* pi_limit = pi + sze;
+
+ // the state
+ std::mbstate_t state = std::mbstate_t ();
+
+ // do the conversion and store results
+ res = cc.in ( state, pe, pe_limit, pen, pi, pi_limit, pin );
+ szi = sz = pin - pi;
+
+ // if C library locale is available, then perform conversion and
+ // compare the results
+ if (skip_C || std::setlocale (LC_CTYPE, locale_name) == 0)
+ return;
+
+ intern_t* C_buffer = new intern_t [sze];
+ std::memset (C_buffer, 0, sze * sizeof (intern_t));
+
+ intern_t* C_pi = C_buffer;
+
+ std::mbstate_t C_state = std::mbstate_t ();
+
+ pen = pe;
+ std::size_t C_res =
+ rwtest_mbstowcs<intern_t> (C_state, C_pi, pen, sze);
+ if (res != std::codecvt_base::ok || C_res == std::size_t(-1)) {
+ delete [] C_buffer;
+ return;
+ }
+
+ // test against C library results - length and content
+ rw_assert (C_res == std::size_t(pin - pi), __FILE__, __LINE__,
+ "(%s) %s::do_in Clib length check:\n"
+ " C library conversion size : %d\n"
+ " std library conversion size : %d\n",
+ locale_name, TypeName<CodeCvtT>::name, C_res, pin - pi);
+
+ rw_assert (0 == std::memcmp (pi, C_pi, C_res), __FILE__, __LINE__,
+ "(%s) %s::do_in data check failed against C library conversion",
+ locale_name, TypeName<CodeCvtT>::name);
+
+ // clean up the allocations
+ delete [] C_buffer;
+}
+
+#define CCVT_MAX_LOCALE 5 // Max. number of locale to test
+#define CCVT_MB_CUR_MIN 1 // Minimum and maximum no. of
+#define CCVT_MB_CUR_MAX 6 // bytes per character
+
+template <class CodeCvtT>
+static void
+test_libstd_do_out (const char* locale_name, const CodeCvtT& cc,
+ typename CodeCvtT::extern_type*& buffe,
+ const typename CodeCvtT::intern_type* buffi,
+ std::size_t& sze, std::size_t szi,
+ bool skip_C,
+ CodecvtResult& res, std::size_t& sz)
+{
+ // buffers types
+ typedef typename CodeCvtT::intern_type intern_t;
+ typedef typename CodeCvtT::extern_type extern_t;
+
+ // the state
+ std::mbstate_t state = std::mbstate_t ();
+
+ buffe = new extern_t [CCVT_MB_CUR_MAX * szi];
+ std::memset (buffe, 0, CCVT_MB_CUR_MAX * szi);
+ extern_t* pe = buffe;
+ extern_t* pen = pe;
+ extern_t* pe_limit = pe + CCVT_MB_CUR_MAX * szi;
+
+ const intern_t* pi = buffi;
+ const intern_t* pin = buffi;
+ const intern_t* pi_limit = pi + szi;
+
+ // perform the conversion
+ res = cc.out ( state, pi, pi_limit, pin, pe, pe_limit, pen );
+ sze = sz = pen - pe;
+
+ if (skip_C || std::setlocale (LC_CTYPE, locale_name) == 0) {
+ return;
+ }
+
+ extern_t* C_buffer = new extern_t [CCVT_MB_CUR_MAX * szi];
+ std::memset (C_buffer, 0, CCVT_MB_CUR_MAX * szi);
+ extern_t* C_pe = C_buffer;
+
+ std::mbstate_t C_state = std::mbstate_t ();
+
+ std::size_t C_res =
+ rwtest_wcstombs<intern_t> (C_state, pi, C_pe, CCVT_MB_CUR_MAX * szi);
+ if (C_res == std::size_t(-1)) {
+ delete [] C_buffer;
+ return;
+ }
+
+ // test results against C library
+ rw_assert (C_res == std::size_t(pen - pe), __FILE__, __LINE__,
+ "(%s) %s::do_out Clib length check\n"
+ " C library conversion size : %d\n"
+ " std library conversion size : %d\n",
+ locale_name, TypeName<CodecvtBnW>::name,
+ C_res, (pen - pe));
+
+ rw_assert (0 == std::memcmp (pe, C_pe, C_res), __FILE__, __LINE__,
+ "(%s) %s::do_out Clib data check failed "
+ "against C library conversion",
+ locale_name, TypeName<CodecvtBnW>::name);
+
+ delete [] C_buffer;
+}
+
+template <class CodeCvtT>
+static void
+test_libstd_do_unshift (const CodeCvtT& cc,
+ std::mbstate_t& state,
+ typename CodeCvtT::extern_type* buffe,
+ std::size_t& sze,
+ CodecvtResult& res)
+{
+ // buffers types
+ typedef typename CodeCvtT::intern_type intern_t;
+ typedef typename CodeCvtT::extern_type extern_t;
+
+ extern_t* pe = buffe;
+ extern_t* pen = buffe;
+ extern_t* pe_limit = buffe + sze;
+
+ res = cc.unshift (state, pe, pe_limit, pen);
+ sze = pen - pe;
+}
+
+template <class CodeCvtT>
+static void
+test_libstd_do_always_noconv (const CodeCvtT& cc, bool& res)
+{
+ res = cc.always_noconv ();
+}
+
+// check do_max_length operation in facet
+template <class CodeCvtT>
+static void
+test_libstd_do_max_length (const CodeCvtT& cc, std::size_t& res )
+{
+ res = cc.max_length ();
+}
+
+// check do_length operation in facet
+template <class CodeCvtT>
+static void
+test_libstd_do_length (const char* locale_name, const CodeCvtT& cc,
+ const typename CodeCvtT::extern_type* buffe,
+ std::size_t& sze, bool skip_C)
+{
+ // buffers types
+ typedef CodecvtBnW::intern_type intern_t;
+ typedef CodecvtBnW::extern_type extern_t;
+
+ // the state
+ std::mbstate_t state = std::mbstate_t ();
+
+ extern_t* pe = _RWSTD_CONST_CAST(extern_t*, buffe);
+ extern_t* pe_limit = _RWSTD_CONST_CAST(extern_t*, buffe + sze);
+
+ sze = cc.length ( state, pe, pe_limit, sze );
+
+ if (skip_C)
+ return;
+
+ std::mbstate_t C_state = std::mbstate_t ();
+
+ std::size_t C_res =
+ rwtest_mbslen ( C_state, pe, pe_limit, sze );
+ // test the result against C library
+ rw_assert (sze == C_res, __FILE__, __LINE__,
+ "(%s) %s::do_length; "
+ "check against C library result failed :\n"
+ " C library result : %d\n"
+ " std library result : %d",
+ locale_name, TypeName<CodeCvtT>::name,
+ C_res, sze);
+}
+
+template <class CodeCvtT>
+static void
+test_libstd_do_encoding (const CodeCvtT& cc, std::size_t& sze)
+{
+ sze = cc.encoding ();
+}
+
+/****************************************************************************/
+
+// Primary template for checking libstd locale codecvt facets
+template <class CodeCvtT>
+static void
+test_libstd_codecvt (const char* locale_name, const CodeCvtT& cc,
+ const char* fname, bool skip_C,
+ CodecvtResult in_res, std::size_t in_res_sz,
+ CodecvtResult out_res, std::size_t out_res_sz,
+ CodecvtResult unshift_res,
+ bool always_noconv_res,
+ std::size_t encoding_res,
+ std::size_t length_res,
+ std::size_t max_length_res)
+{
+ // buffers types
+ typedef typename CodeCvtT::intern_type intern_t;
+ typedef typename CodeCvtT::extern_type extern_t;
+
+ // create a state object
+ std::mbstate_t state = std::mbstate_t ();
+
+ // pointers to buffers
+ extern_t* ebuffer = 0;
+ intern_t* ibuffer = 0;
+ extern_t* eebuffer = 0;
+
+ std::size_t elength = 0;
+ std::size_t ilength = 0;
+ std::size_t eelength = 0;
+
+ // read source file
+ ebuffer = _RWSTD_STATIC_CAST (extern_t*, rw_fread (fname, &elength, "rb"));
+
+ if (!ebuffer || !elength) {
+ rw_assert (false, __FILE__, __LINE__,
+ "failed to read from %s", fname);
+ return;
+ }
+
+ // operations results
+ CodecvtResult res;
+ bool bres;
+ std::size_t ires;
+ std::size_t res_sz;
+
+ char fcall [256];
+ std::sprintf (fcall, "%s::in(..., %p, %p, 0, %p, %p, 0)",
+ TypeName<CodeCvtT>::name,
+ (const void*)ebuffer, (const void*)(ebuffer + elength),
+ (const void*)ibuffer, (const void*)(ibuffer + ilength));
+
+ // Test do_in conversion result and size
+ test_libstd_do_in<CodeCvtT> (locale_name, cc,
+ ebuffer, ibuffer, elength, ilength,
+ skip_C, res, res_sz);
+
+ // 22.2.1.5 p3, 22.2.1.5.2 p2 - test operation result
+ rw_assert (res == in_res, __FILE__, __LINE__,
+ "%s == %s, got %s in locale(\"%s\")",
+ fcall,
+ rwtest_codecvt_result (in_res),
+ rwtest_codecvt_result (res),
+ locale_name);
+
+ // test the length of the internal buffer is correct; noconv does not do
+ // any copying of the data
+ if (res == std::codecvt_base::noconv) {
+ rw_assert (res_sz == 0, __FILE__, __LINE__,
+ "%s expected size 0 for %s, got %d instead "
+ "in locale(\"%s\")", fcall,
+ rwtest_codecvt_result (res), res_sz, locale_name);
+
+ // so copy all content from external buffer to internal buffer
+ ilength = elength;
+ for (std::size_t i = 0; i < elength; i++)
+ ibuffer [i] = intern_t (ebuffer [i]);
+
+ }
+ else {
+ rw_assert (ilength == in_res_sz && ilength == res_sz,
+ __FILE__, __LINE__,
+ "%s: conversion size: expected %d, got %d in locale(\"%s\")",
+ fcall, in_res_sz, ilength, locale_name);
+ }
+
+ // Test do_out conversion result and size
+ test_libstd_do_out<CodeCvtT> (locale_name, cc,
+ eebuffer, ibuffer, eelength, ilength,
+ skip_C, res, res_sz);
+
+ // 22.2.1.5 p3, 22.2.1.5.2 p2 - test operation result
+ rw_assert (res == out_res, __FILE__, __LINE__,
+ "(%s) %s::do_out() == %s, got %s",
+ locale_name, TypeName<CodecvtBnW>::name,
+ rwtest_codecvt_result (out_res), rwtest_codecvt_result (res));
+
+ if (res == std::codecvt_base::noconv) {
+ rw_assert (res_sz == 0, __FILE__, __LINE__,
+ "(%s) %s::do_out expected size 0 for %s, got %d instead",
+ locale_name, TypeName<CodeCvtT>::name,
+ rwtest_codecvt_result (res), res_sz);
+
+ // so copy all content from internal buffer to external buffer
+ eelength = ilength;
+ for (std::size_t i = 0; i < eelength; i++)
+ eebuffer [i] = extern_t (ibuffer [i]);
+
+ } else {
+ rw_assert (eelength == out_res_sz && eelength == res_sz,
+ __FILE__, __LINE__,
+ "(%s) %s::do_out conversion size: expected %d, got %d",
+ locale_name, TypeName<CodeCvtT>::name,
+ in_res_sz, ilength);
+ }
+
+ // Test the roundtrip conversion content and size
+ std::size_t cmp = 0;
+ if (std::memcmp (ebuffer, eebuffer, min (elength, eelength))) {
+ for (cmp = 0; cmp < min (elength, eelength); cmp++)
+ if (ebuffer [cmp] != eebuffer [cmp])
+ break;
+ }
+
+ rw_assert (elength == eelength, __FILE__, __LINE__,
+ "(%s) %s round-trip check size mismatch : "
+ " expected size %d , got size %d",
+ locale_name, TypeName<CodeCvtT>::name,
+ elength, eelength);
+
+ rw_assert (0 == std::memcmp (ebuffer, eebuffer,
+ min (elength, eelength)),
+ __FILE__, __LINE__,
+ "(%s) %s round-trip check content mismatch : at index %d",
+ locale_name, TypeName<CodeCvtT>::name, cmp);
+
+ // Test unshift operation
+ extern_t tmp [16];
+ std::size_t tmp_len = 16;
+ state = std::mbstate_t ();
+
+ test_libstd_do_unshift<CodeCvtT> (cc, state, tmp, tmp_len, res);
+
+ // 22.2.1.5.2 p5-6
+ rw_assert (res == unshift_res, __FILE__, __LINE__,
+ "(%s) %s::do_unshift; expected %s, got %s",
+ locale_name, TypeName<CodeCvtT>::name,
+ rwtest_codecvt_result (unshift_res),
+ rwtest_codecvt_result (res));
+
+ rw_assert (tmp_len == 0, __FILE__, __LINE__,
+ "(%s) %s::do_unshift; expected 0 length unshift sequence, "
+ "got %d", locale_name, TypeName<CodeCvtT>::name, tmp_len);
+
+ // Test do_always_noconv operation
+ test_libstd_do_always_noconv<CodeCvtT> (cc, bres);
+ rw_assert (bres == always_noconv_res, __FILE__, __LINE__,
+ "(%s) %s::do_always_noconv expected %s, got %s",
+ locale_name, TypeName<CodeCvtT>::name,
+ always_noconv_res?"true":"false", bres?"true":"false");
+
+ // Test do_max_length operation
+ test_libstd_do_max_length<CodeCvtT> (cc, ires);
+ // 22.2.1.5.2 p11
+ rw_assert (ires == max_length_res, __FILE__, __LINE__,
+ "(%s) %s::do_max_length expected %d, got %d",
+ locale_name, TypeName<CodeCvtT>::name,
+ max_length_res, ires);
+
+ // Test do_length operation
+ ires = elength;
+ test_libstd_do_length<CodeCvtT> (locale_name, cc,
+ ebuffer, ires, skip_C);
+ // 22.2.1.5.2 p10
+ rw_assert (ires == length_res, __FILE__, __LINE__,
+ "(%s) %s::do_length expected %d, got %d",
+ locale_name, TypeName<CodeCvtT>::name,
+ length_res, ires);
+
+ ires = 0;
+ test_libstd_do_encoding<CodeCvtT> (cc, ires);
+ // 22.2.1.5.2 p6
+ rw_assert (ires == encoding_res, __FILE__, __LINE__,
+ "(%s) %s::do_encoding expected %d, got %d",
+ locale_name, TypeName<CodeCvtT>::name,
+ encoding_res, ires);
+
+ delete [] ibuffer;
+ delete [] eebuffer;
+ // delete [] ebuffer;
+}
+
+/****************************************************************************/
+
+#if !defined _MSC_VER
+
+static unsigned int endian_test = 1;
+static bool big_endian = *(unsigned char*)&endian_test == 0;
+
+static iconv_t
+rwtest_iconv_open (bool ucs4, const char* enc)
+{
+ static const char* const ucs4_aliases [] = {
+ "UCS-4LE", "UCS-4", "UCS4", "ucs4", 0
+ };
+
+ static const char* const ucs2_aliases [] = {
+ "UCS-2LE", "UCS-2", "UCS2", "ucs2", 0
+ };
+
+ const char* const* pucs = ucs4 ? ucs4_aliases : ucs2_aliases;
+
+ // that accomodates Linux with its extra modifiers LE and BE
+ // (UCS-4 is synonym with UCS-4BE)
+ if (big_endian)
+ pucs++;
+
+ iconv_t id = iconv_t (-1);
+
+ for (; id == iconv_t (-1) && *pucs && **pucs; pucs++)
+ id = iconv_open (*pucs, enc);
+
+ return id;
+}
+
+
+static void
+rwtest_iconv_convert (iconv_t fd,
+ const char* in, std::size_t in_sz,
+ wchar_t* out, std::size_t& out_sz)
+{
+ out_sz *= sizeof (wchar_t);
+
+ // Two issues:
+ // - iconv shipped with the C library on RedHat 6.2 if reaches the end of
+ // the input buffer (out_sz == 0) reports E2BIG as if it has had not
+ // enuff space to store the result of the conversion
+ // - iconv shipped with C library on RedHat 6.2 apparently uses UCS-4 big
+ // endian on little endian machines too
+ std::size_t tmp = out_sz++ + 1;
+
+# if defined _RWSTD_NO_ICONV_CONST_CHAR
+ char* par1 = _RWSTD_CONST_CAST (char*, in);
+# else
+ const char* par1 = in;
+# endif // defined _RWSTD_NO_ICONV_CONST_CHAR
+ char* par2 = _RWSTD_REINTERPRET_CAST (char*, out);
+
+ std::size_t res = iconv (fd, &par1, &in_sz, &par2, &out_sz);
+ if (res == std::size_t (-1))
+ out_sz = 0;
+ else
+ out_sz = (tmp + 1 - out_sz) / sizeof (wchar_t);
+}
+
+#endif // defined _MSC_VER
+
+
+enum InternalEncoding {
+ use_libc, // use libc's native internal wchar_t encoding
+ use_UCS4, // use UCS-4 as the internal wchar_t encoding
+ use_UCS2 // use UCS-2 as the internal wchar_t encoding
+};
+
+
+static bool
+rwtest_convert_to_internal (InternalEncoding conv,
+ const char* native_locname,
+ const char* ebuffer, std::size_t elength,
+ wchar_t* ibuffer, std::size_t& ilength)
+{
+ ilength = 0;
+
+ if (!native_locname)
+ return false;
+
+ const char* const old_locale = std::setlocale (LC_CTYPE, native_locname);
+
+ if (!old_locale)
+ return false;
+
+ switch (conv) {
+
+#ifdef _MSC_VER
+
+ case use_UCS2:
+ // fall through...
+
+#endif // _MSC_VER
+
+ case use_libc: {
+
+ std::mbstate_t state = std::mbstate_t ();
+
+ ilength = rwtest_mbstowcs (state, ibuffer, ebuffer, elength);
+
+ break;
+ }
+
+#ifndef _MSC_VER
+
+ case use_UCS2:
+ case use_UCS4: {
+ // use iconv
+
+ const char* const codeset = nl_langinfo (CODESET);
+ if (!codeset) {
+ ilength = std::size_t (-1);
+ break;
+ }
+
+ const iconv_t id = rwtest_iconv_open (true, codeset);
+
+ if (iconv_t (-1) == id)
+ ilength = std::size_t (-1);
+ else {
+ rwtest_iconv_convert (id, ebuffer, elength, ibuffer, ilength);
+
+ iconv_close (id);
+ }
+
+ break;
+ }
+
+#endif // _MSC_VER
+
+ }
+
+ // restore the previous locale
+ std::setlocale (LC_CTYPE, old_locale);
+
+ if (std::size_t (-1) == ilength) {
+ ilength = 0;
+ return false;
+ }
+
+ return true;
+}
+
+
+static const char*
+rwtest_internal_type (InternalEncoding enc)
+{
+ static const char* const encs [] = {
+ "native", "UCS-4", "UCS-2", "invalid"
+ };
+
+ switch (enc) {
+ case use_libc:
+ return encs [0];
+ case use_UCS4:
+ return encs [1];
+ case use_UCS2:
+ return encs [2];
+ default:
+ return encs [3];
+ }
+}
+
+
+static std::size_t
+bmatch (const char* mem1, const char* mem2, std::size_t nchars)
+{
+ if (std::memcmp (mem1, mem2, nchars)) {
+
+ for (std::size_t i = 0; i != nchars; ++i)
+ if (mem1 [i] != mem2 [i])
+ return i;
+ }
+ return nchars;
+}
+
+
+static std::size_t
+bmatch (const wchar_t* mem1, const wchar_t* mem2, std::size_t nchars)
+{
+ if (std::size_t (-1) == nchars) {
+ // avoid warnings about unused overload above
+ return bmatch ((char*)0, (char*)0, 0);
+ }
+
+ if (std::memcmp (mem1, mem2, nchars * sizeof *mem1)) {
+
+ for (std::size_t i = 0; i != nchars; ++i)
+ if (mem1 [i] != mem2 [i])
+ return i;
+ }
+ return nchars;
+}
+
+
+static void
+test_ucs_modifier (const char* locale_name,
+ InternalEncoding conv,
+ const char* native_locname,
+ const CodecvtBnW& cc,
+ const char* fname,
+ CodecvtResult in_res,
+ std::size_t in_res_sz)
+{
+ // pointers to buffers
+ char* ebuf = 0;
+ wchar_t* ibuf = 0;
+ wchar_t* ibuf_native = 0;
+
+ // buffer sizes
+ std::size_t elen = 0;
+ std::size_t ilen = 0;
+ std::size_t ilen_native = 0;
+
+ // read source file
+ ebuf = _RWSTD_STATIC_CAST (char*, rw_fread (fname, &elen, "rb"));
+ if (!ebuf || !elen)
+ return;
+
+ // allocate and zero the internal buffer
+ ilen = elen;
+ ibuf = new wchar_t [ilen];
+ std::memset (ibuf, 0, ilen * sizeof *ibuf);
+
+ ilen_native = elen;
+
+ // to accommodate iconv shipped with RedHat 6.2, allocate one more wchar_t
+ ibuf_native = new wchar_t [ilen_native + 1];
+ std::memset (ibuf_native, 0, (ilen_native + 1) * sizeof *ibuf_native);
+
+ const char* from = ebuf;
+ const char* from_next = ebuf;
+ const char* from_limit = ebuf + elen;
+ wchar_t* to = ibuf;
+ wchar_t* to_next = ibuf;
+ wchar_t* to_limit = ibuf + elen;
+
+ // create a state object
+ std::mbstate_t state = std::mbstate_t ();
+
+ rw_info (0, __FILE__, __LINE__, "locale(\"%s\")", locale_name);
+
+ const std::codecvt_base::result res =
+ cc.in (state, from, from_limit, from_next, to, to_limit, to_next);
+
+ ilen = to_next - to;
+
+ if (res != in_res || in_res_sz != std::size_t (to_next - to)) {
+ rw_assert (false, __FILE__, __LINE__,
+ "(%s) EXT -> INT conversion using codecvt failed:\n"
+ " result : %s\n expected size %d, got %d",
+ locale_name, rwtest_codecvt_result (res),
+ in_res_sz, to_next - to);
+
+ delete [] ibuf_native;
+ delete [] ibuf;
+ return;
+
+ }
+
+ // test against the libc mbstowcs() or iconv() conversion
+ if (!rwtest_convert_to_internal (conv, native_locname, ebuf, elen,
+ ibuf_native, ilen_native)) {
+ delete [] ibuf_native;
+ delete [] ibuf;
+ return;
+ }
+
+ if (!ilen_native) {
+ rw_assert (false, __FILE__, __LINE__,
+ "(%s) EXT -> INT conversion using %s "
+ "(%s internally) failed",
+ locale_name,
+ (conv == use_libc) ? "mbstowcs()" : "iconv()",
+ rwtest_internal_type (conv));
+
+ delete [] ibuf_native;
+ delete [] ibuf;
+ return;
+ }
+
+ // Conversion and check against mbstowcs / iconv
+ rw_assert (ilen_native == ilen, __FILE__, __LINE__,
+ "(%s) EXT -> INT length check (%s internally):\n"
+ " size of native encoding: %d\n"
+ " size of codecvt encoding: %d\n",
+ locale_name, rwtest_internal_type (conv),
+ ilen, ilen_native);
+
+ if (ilen_native == ilen) {
+ const std::size_t diff = bmatch (to, ibuf_native, ilen);
+
+ rw_assert (diff >= ilen, __FILE__, __LINE__,
+ "codecvt<wchar_t, char, mbstate_t>::in() mismatch "
+ "at character %u of %u: '%s' != '%s'; in locale(\"%s\")",
+ diff, ilen, ibuf_native [diff],
+ to [diff], locale_name);
+ }
+
+ delete [] ibuf_native;
+ delete [] ibuf;
+}
+
+/****************************************************************************/
+
+std::jmp_buf jmp_env;
+
+// called in response to abort() or failed assertions
+extern "C"
+void SIGABRT_handler (int /*unused*/)
+{
+ std::longjmp (jmp_env, 1);
+}
+
+
+// exercise the facets' treatment of an invalid mbstate_t argument
+template <class CodeCvtT>
+static void
+test_mbstate_t (const CodeCvtT*, const char* name)
+{
+ const std::locale loc (name);
+
+ const CodeCvtT &cvt = _STD_USE_FACET (CodeCvtT, loc);
+
+ typedef typename CodeCvtT::intern_type intern_type;
+ typedef typename CodeCvtT::extern_type extern_type;
+ typedef typename CodeCvtT::state_type state_type;
+
+ state_type state;
+
+ // initialize `state' to an invalid value
+ std::memset (&state, -1, sizeof state);
+
+ intern_type in = intern_type ();
+ intern_type* in_0 = ∈
+ intern_type* in_1 = &in + 1;
+ intern_type* in_2 = 0;
+ const intern_type* const_in_2 = 0;
+
+ extern_type ext = extern_type ();
+ extern_type* ext_0 = &ext;
+ extern_type* ext_1 = &ext + 1;
+ extern_type* ext_2 = 0;
+ const extern_type* const_ext_2 = 0;
+
+#ifndef _RWSTDDEBUG
+ // when debugging is disabled, expect member functions to
+ // detect and indicate an invalid argument by setting the
+ // return value to codecvt_base::error
+ const bool expect_abort = false;
+#else
+ // when debugging is enabled, expect member functions to
+ // detect and indicate an invalid argument by calling abort()
+ const bool expect_abort = true;
+#endif
+
+#undef TEST
+#define TEST(resultT, result, fname, args) \
+ if (0 == setjmp (jmp_env)) { \
+ std::signal (SIGABRT, SIGABRT_handler); \
+ const resultT res = cvt.fname args; \
+ rw_assert (!expect_abort && result == res, __FILE__, __LINE__, \
+ "%s::%s (state_type&, ...) failed to " \
+ "detect an invalid state argument", \
+ TypeName<CodeCvtT>::name, #fname); \
+ } else \
+ rw_assert (expect_abort, __FILE__, __LINE__, \
+ "%s::%s (state_type&, ...) called abort() instead " \
+ "of gracefully indicating an invalid state argument", \
+ TypeName<CodeCvtT>::name, #fname)
+
+ const std::codecvt_base::result error = std::codecvt_base::error;
+
+ TEST (std::codecvt_base::result, error,
+ in, (state, ext_0, ext_1, const_ext_2, in_0, in_1, in_2));
+
+ TEST (std::codecvt_base::result, error,
+ out, (state, in_0, in_1, const_in_2, ext_0, ext_1, ext_2));
+
+ TEST (std::codecvt_base::result, error,
+ unshift, (state, ext_0, ext_1, ext_2));
+
+ TEST (int, 0,
+ length, (state, ext_0, ext_1, 0));
+
+ // verify that functions gracefully handle null pointers
+#undef TEST
+#define TEST(resultT, result, fname, args) \
+ if (0 == setjmp (jmp_env)) { \
+ std::signal (SIGABRT, SIGABRT_handler); \
+ const resultT res = cvt.fname args; \
+ rw_assert (result == res, __FILE__, __LINE__, \
+ "%s::%s (state_type&, (char_type*)0, ...) == %s, " \
+ "got %s (NULL pointer test)", \
+ TypeName<CodeCvtT>::name, #fname, \
+ rwtest_codecvt_result (result), \
+ rwtest_codecvt_result (res)); \
+ } else \
+ rw_assert (expect_abort, __FILE__, __LINE__, \
+ "%s::%s (state_type&, (char_type*)0, ...) " \
+ "unexpectedly called abort() (NULL pointer test)", \
+ TypeName<CodeCvtT>::name, #fname)
+
+ // initialize `state' to a valid value
+ std::memset (&state, 0, sizeof state);
+
+ // const below commented out to work around an HP aCC bug (PR #29666)
+ /* const */ std::codecvt_base::result result =
+ sizeof (intern_type) == sizeof (char)
+ ? std::codecvt_base::noconv : std::codecvt_base::ok;
+
+ TEST (std::codecvt_base::result, result,
+ in, (state, 0, 0, const_ext_2, 0, 0, in_2));
+
+ TEST (std::codecvt_base::result, result,
+ out, (state, 0, 0, const_in_2, 0, 0, ext_2));
+
+ TEST (std::codecvt_base::result, std::codecvt_base::noconv,
+ unshift, (state, 0, 0, ext_2));
+
+ TEST (int, 0,
+ length, (state, 0, 0, 0));
+}
+
+/****************************************************************************/
+
+static void
+test_invalid_args (const char* locname)
+{
+ // exercise the behavior of the base facets
+ rw_info (0, __FILE__, __LINE__,
+ "Testing %s with invalid arguments", TypeName<Codecvt>::name);
+ test_mbstate_t ((Codecvt*)0, "C");
+
+ rw_info (0, __FILE__, __LINE__,
+ "Testing %s with invalid arguments", TypeName<CodecvtW>::name);
+ test_mbstate_t ((CodecvtW*)0, "C");
+
+ char non_c_locname [256];
+ *non_c_locname = '\0';
+
+ for (const char *loc = rw_locale_query (); *loc;
+ loc += std::strlen (loc) + 1) {
+ if ( std::strcmp ("C", loc) && std::strcmp ("POSIX", loc)
+ && std::setlocale (LC_ALL, loc)) {
+ std::setlocale (LC_ALL, "C");
+ std::strcpy (non_c_locname, loc);
+ break;
+ }
+ }
+
+ if (*non_c_locname) {
+ // exercise the behavior of the derived facets when using
+ // libc locale names other than "C" or "POSIX"
+
+ rw_info (0, __FILE__, __LINE__,
+ "Testing libc based %s with invalid arguments "
+ "in locale(\"%s\")",
+ TypeName<CodecvtBn>::name, non_c_locname);
+
+ test_mbstate_t ((CodecvtBn*)0, non_c_locname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "Testing libc based %s with invalid arguments "
+ "in locale(\"%s\")",
+ TypeName<CodecvtBnW>::name, non_c_locname);
+ test_mbstate_t ((CodecvtBnW*)0, non_c_locname);
+ }
+
+ if (locname) {
+
+ // exercise the behavior of the byname facets when using own
+ // locale databases and when passed an invalid mbstate_t object
+ rw_info (0, __FILE__, __LINE__,
+ "Testing libstd %s with invalid arguments",
+ TypeName<CodecvtBn>::name);
+
+ test_mbstate_t ((CodecvtBn*)0, locname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "Testing libstd %s with invalid arguments",
+ TypeName<CodecvtBnW>::name);
+
+ test_mbstate_t ((CodecvtBnW*)0, locname);
+ }
+}
+
+/****************************************************************************/
+
+template <class internT>
+static void
+test_inout (int which, int line, const char* name,
+ const char* sext, std::size_t ext_len, std::size_t ext_num,
+ const internT* sint, std::size_t int_len, std::size_t int_num,
+ std::codecvt_base::result expect)
+{
+ _RWSTD_UNUSED (line);
+
+ char namebuf [256];
+ assert (255 >= std::strlen (name));
+ std::strcpy (namebuf, name);
+
+ // when non-0, the name the locale object is constructed with
+ const char* locale_name = 0;
+
+ // when non-0, the name the codevt_byname facet is constructed
+ // with before being installed in the locale object
+ const char* codecvt_name = 0;
+
+ // look for a locale name modifier
+ const char* const mod = std::strrchr (name, '@');
+
+ if (mod && 'U' == mod [1] && 'C' == mod [2] && 'S' == mod [3]) {
+
+ namebuf [mod - name] = '\0';
+ locale_name = namebuf;
+ codecvt_name = namebuf + (mod - name) + 1;
+ }
+
+ // check for the special names "UTF-8" and "utf-8" indicating
+ // a codecvt_byname facet with UTF-8 as the external encoding
+ // and UCS (either UCS-4 or UCS-2, depending on the width of
+ // wchar_t) as the internal encoding (i.e., synonyms for
+ // "UTF-8@UCS" and "utf-8@UCS" respectively)
+ if ( !std::strcmp (namebuf, "UTF-8")
+ || !std::strcmp (namebuf, "utf-8")) {
+ codecvt_name = namebuf;
+ locale_name = 0;
+ }
+ else
+ locale_name = namebuf;
+
+ typedef std::codecvt<internT, char, std::mbstate_t> Cvt;
+ typedef std::codecvt_byname<internT, char, std::mbstate_t> CvtByname;
+
+ std::locale loc;
+
+ // try to construct a locale with the given name
+ if (locale_name) {
+ _TRY {
+ loc = std::locale (locale_name);
+ }
+ _CATCH (...) {
+ const char* const envvar = std::getenv (LOCALE_ROOT_ENVAR);
+
+ rw_assert (false, __FILE__, __LINE__,
+ "locale(\"%s\") unexpectedly threw an exception; "
+ LOCALE_ROOT_ENVAR "=%s", locale_name,
+ envvar ? envvar : "(null)");
+
+ return;
+ }
+ }
+
+ // if `codecvt_name' is non-0, try to construct a codecvt_byname
+ // facet with that name and install it in the locale object
+ // constructed above
+ if (codecvt_name) {
+
+ const Cvt* pcvt = 0;
+
+ _TRY {
+ // first try to construct the facet
+ pcvt = new CvtByname (codecvt_name);
+ }
+ _CATCH (...) {
+ const char* const envvar = std::getenv (LOCALE_ROOT_ENVAR);
+
+ rw_assert (false, __FILE__, __LINE__,
+ "codecvt_byname<%s, char, mbstate_t>(\"%s\") "
+ "unexpectedly threw an exception; "
+ LOCALE_ROOT_ENVAR "=%s", TypeName<internT>::name,
+ codecvt_name, envvar ? envvar : "(null)");
+
+ return;
+ }
+ _TRY {
+ // next try to install the facet in the locale object
+ loc = std::locale (loc, pcvt);
+ }
+ _CATCH (...) {
+ rw_assert (false, __FILE__, __LINE__,
+ "locale combining ctor unexpectedly threw "
+ "an exception; ");
+ delete pcvt;
+ return;
+ }
+ }
+
+ // compute the length of the source sequence if it isn't specified
+ if (std::size_t (-1) == ext_len)
+ ext_len = sext ? std::strlen (sext) : 0;
+
+ // compute the length of the destination sequence if it isn't specified
+ if (std::size_t (-1) == int_len)
+ int_len = sint ? std::char_traits<internT>::length (sint) : 0;
+
+ // retrieve the codecvt or codecvt_byname facet from the locale object
+ const Cvt &cvt = std::use_facet<Cvt>(loc);
+
+ std::mbstate_t state;
+ std::memset (&state, 0, sizeof state);
+
+ // for convenience: fully qualified name of the function,
+ // including the values of function arguments
+ static char fcall [4096];
+
+ if ( ('I' == which || 'i' == which
+ || 'o' == which) && std::codecvt_base::ok == expect) {
+ // exercise do_in():
+ // * the type of `sext' is char
+ // * ext_len is the number of bytes in the external sequence
+ // * the type of `sint' is internT (i.e., char or wchar_t)
+ // * int_len is the number of internT characters
+ // in the expected internal sequence
+
+ const char* ext_lo = sext;
+ const char* ext_hi = sext + ext_len;
+ const char* ext_nxt = 0;
+
+ internT* int_lo = new internT [int_len + 1];
+ internT* int_hi = int_lo + int_len;
+ internT* int_nxt = 0;
+
+ std::memset (int_lo, 0, (int_len + 1) * sizeof *int_lo);
+
+ // is the `sext' array is not NUL-terminated, create a copy
+ // and NUL-terminate it
+ const char* pextstr = sext;
+ if (sext [ext_len]) {
+ char* const tmp = new char [ext_len + 1];
+ std::memcpy (tmp, sext, ext_len);
+ tmp [ext_len] = '\0';
+ pextstr = tmp;
+ }
+
+ std::sprintf (fcall, "codecvt<%s, char, mbstate_t>::in"
+ "(..., %p = %s, %p, %p, %p, %p, %p)",
+ TypeName<internT>::name,
+ (const void*)ext_lo, pextstr,
+ (const void*)ext_hi, (const void*)ext_nxt,
+ (const void*)int_lo, (const void*)int_hi,
+ (const void*)int_nxt);
+
+ if (pextstr != sext) {
+ // const_cast works around an MSVC 6.0 bug (PR #30092)
+ delete[] _RWSTD_CONST_CAST (char*, pextstr);
+ }
+
+ std::codecvt_base::result res;
+
+ _TRY {
+ res = cvt.in (state,
+ ext_lo, ext_hi, ext_nxt,
+ int_lo, int_hi, int_nxt);
+ }
+ _CATCH (...) {
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s unexpectedly threw an exception",
+ __LINE__, fcall);
+ }
+
+ // verify the value returned from the function
+ if (expect != res) {
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s == %s, got %s", __LINE__, fcall,
+ rwtest_codecvt_result (expect),
+ rwtest_codecvt_result (res));
+ }
+
+ // verify the value of the from_next pointer modified by the function
+ if (ext_nxt != ext_lo + ext_num) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s; from_next == %p, got %p (at offset %d)",
+ __LINE__, fcall, ext_lo + ext_num, ext_nxt,
+ ext_nxt - ext_lo);
+ }
+
+ // verify the value of the to_next pointer modified by the function
+ if (int_nxt != int_lo + int_num) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s; to_next == %p, got %p (at offset %d)",
+ __LINE__, fcall, int_lo + int_num, int_nxt,
+ int_nxt - int_lo);
+ }
+
+ if (std::codecvt_base::error != res) {
+
+ // verify that the contents of the destination sequence
+ // matches the expected sequence
+ const int cmp = std::memcmp (int_lo, sint, int_len);
+
+ if (cmp) {
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s -> %s, expected %s", __LINE__, fcall,
+ int_lo, sint);
+ }
+ }
+
+ delete[] int_lo;
+ }
+
+ if ( ('O' == which || 'o' == which
+ || 'i' == which) && std::codecvt_base::ok == expect) {
+ // exercise do_out():
+ // * the type of `sint' is internT (i.e., either char or wchar_t)
+ // * int_len is the number of internT characters
+ // * the type of `ext' is char
+ // * ext_len is the number of bytes in the expected sequence
+ // of external characters
+
+ char* ext_lo = new char [ext_len + 1];
+ char* ext_hi = ext_lo + ext_len;
+ char* ext_nxt = 0;
+
+ std::memset (ext_lo, 0, ext_len + 1);
+
+ const internT* int_lo = sint;
+ const internT* int_hi = int_lo + int_len;
+ const internT* int_nxt = 0;
+
+ const char* fmt;
+ if (sizeof (internT) == sizeof (char))
+ fmt = "codecvt<char, char, mbstate_t>::out"
+ "(..., %p = %s, %p, %p, %p, %p, %p)";
+ else if (sizeof (internT) == sizeof (wchar_t))
+ fmt = "codecvt<wchar_t, char, mbstate_t>::out"
+ "(..., %p = L%ls, %p, %p, %p, %p, %p)";
+
+ std::sprintf (fcall, fmt, (const void*)int_lo,
+ int_lo, (const void*)int_hi,
+ (const void*)int_nxt, (const void*)ext_lo,
+ (const void*)ext_hi, (const void*)ext_nxt);
+
+ std::codecvt_base::result res;
+
+ _TRY {
+ res = cvt.out (state,
+ int_lo, int_hi, int_nxt,
+ ext_lo, ext_hi, ext_nxt);
+ }
+ _CATCH (...) {
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s unexpectedly threw an exception",
+ __LINE__, fcall);
+ }
+
+ // verify the value returned from the function
+ if (expect != res) {
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s == %s, got %s", __LINE__, fcall,
+ rwtest_codecvt_result (expect),
+ rwtest_codecvt_result (res));
+ }
+
+ // verify the value of the from_next pointer modified by the function
+ if (int_nxt != int_lo + int_num) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s; from_next == %p, got %p (at offset %d)",
+ __LINE__, fcall, int_lo + int_num, int_nxt,
+ int_nxt - int_lo);
+ }
+
+ // verify the value of the to_next pointer modified by the function
+ if (ext_nxt != ext_lo + ext_num) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s; to_next == %p, got %p (at offset %d)",
+ __LINE__, fcall, ext_lo + ext_num, ext_nxt,
+ ext_nxt - ext_lo);
+ }
+
+ if (std::codecvt_base::error != res) {
+
+ // verify that the contents of the destination sequence
+ // matches the expected sequence
+ const int cmp = std::memcmp (ext_lo, sext, ext_len);
+
+ if (cmp) {
+
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. %s -> %s, expected %s", __LINE__, fcall,
+ ext_lo, sext);
+ }
+ }
+
+ delete[] ext_lo;
+ }
+}
+
+
+// the root of the locale directory (RWSTD_LOCALE_ROOT)
+// set in main() instead of here to avoid Solaris 7 putenv() bug (PR #30017)
+const char* locale_root;
+
+
+// creates a codecvt database from `charmap'
+static const char*
+create_codecvt (unsigned mb_min,
+ unsigned mb_max,
+ const char* charmap,
+ const char* charset_name = 0)
+{
+ // keeps track of successful calls and generates a unique
+ // name for each codeset conversion database and locale
+ static int call_no;
+
+ // construct the absolute pathname of a charmap file
+ char cm_pathname [PATH_MAX];
+
+ if (charset_name)
+ std::sprintf (cm_pathname, "%s" SLASH "%s.cm",
+ locale_root, charset_name);
+ else
+ std::sprintf (cm_pathname,
+ "%s" SLASH "codecvt-%u-%u.%d.cm",
+ locale_root, mb_min, mb_max, call_no);
+
+ // create the charmap file
+ std::FILE* pf = std::fopen (cm_pathname, "w");
+ if (!pf)
+ return 0;
+
+ if (charset_name)
+ std::fprintf (pf, "<code_set_name> %s\n", charset_name);
+ else
+ std::fprintf (pf, "<code_set_name> codecvt-%u-%u.%d\n",
+ mb_min, mb_max, call_no);
+
+ std::fprintf (pf, "<escape_char> /\n");
+
+ std::fprintf (pf, "<mb_cur_min> %u\n", mb_min);
+ std::fprintf (pf, "<mb_cur_max> %u\n\n\n", mb_max);
+ std::fprintf (pf, "CHARMAP\n");
+ std::fprintf (pf, charmap);
+ std::fprintf (pf, "\nEND CHARMAP\n");
+
+ std::fclose (pf);
+
+ // construct the absolute pathname of a dummy locale definition file
+ char src_pathname [PATH_MAX];
+ std::strcpy (src_pathname, locale_root);
+ std::strcat (src_pathname, SLASH "dummy.src");
+
+ // create the locale definition file
+ if (!(pf = std::fopen (src_pathname, "w")))
+ return 0;
+
+ // dummy source file must contain the LC_CTYPE section
+ // in order for localedef to generate the codecvt database
+ std::fprintf (pf, "LC_CTYPE\nEND LC_CTYPE\n");
+
+ std::fclose (pf);
+
+ // construct the filename of the locale
+ char locale_fname[32];
+ std::sprintf (locale_fname,
+ "locale-%u.%u-%d",
+ mb_min, mb_max, call_no);
+
+ // invoke localedef to create the named locale from the dummy
+ // locale definition file and the character set description file
+ // silence the following warnings:
+ // 701: no compatible locale found
+ // 702: member of portable character set <x> not found
+ // in the character map
+ // 706: iconv_open() failed
+ // : unknown symbol found in LC_COLLATE definition
+ // : some characters in the codeset were not explicitly
+ // given a collation value
+ const char* const locname =
+ rw_localedef ("-w701 -w702 -w706",
+ src_pathname, cm_pathname, locale_fname);
+
+ call_no += !!locname;
+
+ return locname;
+}
+
+
+// given a canonical locale name, `locname', tries to find a platform
+// specific locale name that corresponds to the name; when `codeset'
+// is non-0, also checks to see that the platform-specific locale's
+// codeset is the same as that specified by the argument
+// on success, returns the name of the platform-specific locale,
+// otherwise 0
+static const char*
+find_locale (const char* locname, const char* codeset)
+{
+ static const struct {
+ const char* locnames [16];
+ const char* codesets [16];
+ } aliases [] = {
+ { {
+ // canonical locale name, followed by its common aliases
+ "de_DE.ISO-8859-1",
+ "de_DE.iso88591", "de_DE.ISO8859-1", "de_DE", "DEU", "de", 0
+ }, {
+ // well-known codeset name, followed by its common aliases
+ "ISO-8859-1",
+ "ISO-88591", "ISO_8859-1", "ISO8859-1", "iso88591", "iso1", 0
+ // Windows Codepage 1252 (Latin I)
+ // http://www.microsoft.com/globaldev/reference/sbcs/1252.htm
+ } },
+ { {
+ "fr_FR.ISO-8859-1",
+ "fr_FR.iso88591", "fr_FR.ISO8859-1", "fr_FR", "FRA", "fr", 0
+ }, {
+ "ISO-8859-1",
+ "ISO-88591", "ISO_8859-1", "ISO8859-1", "iso88591", "iso1", 0
+ } },
+ { {
+ "ja_JP.Shift_JIS",
+ "ja_JP.SJIS", "japanese.sjis", "JPN", 0
+ }, {
+ "Shift_JIS",
+ "Shift-JIS", "SJIS", "SHIFT-JIS", "SHIFT_JIS", "shift-jis",
+ "sjis", 0
+ // Windows Codepage 932 (Japanese Shift-JIS)
+ // http://www.microsoft.com/globaldev/reference/dbcs/932.htm
+ } },
+ { {
+ "ja_JP.EUC-JP",
+ "ja_JP.eucJP", "ja_JP.EUC", "ja_JP.eucjp", 0
+ }, {
+ "EUC-JP",
+ "eucjp", "eucJP", "euc_jp", "euc", "ujis", 0
+ } },
+ { { 0 }, { 0 } }
+ };
+
+ const char* name = std::setlocale (LC_ALL, locname);
+
+ std::size_t inx = std::size_t (-1);
+
+ if (!name) {
+
+ // find the index, `inx', of `locname' in the table
+ for (std::size_t i = 0; i != sizeof aliases / sizeof *aliases; ++i) {
+ if (!aliases [i].locnames [0])
+ break;
+
+ if (!std::strcmp (locname, aliases [i].locnames [0])) {
+ inx = i;
+ break;
+ }
+ }
+
+ if (std::size_t (-1) != inx) {
+
+ // go through the locale name's aliases until one
+ // that's a valid argument to setlocale() is found
+ for (std::size_t j = 1; aliases [inx].locnames [j]; ++j) {
+ if (!aliases [inx].locnames [j])
+ break;
+
+ if (std::setlocale (LC_ALL, aliases [inx].locnames [j])) {
+ name = aliases [inx].locnames [j];
+ break;
+ }
+ }
+ }
+ }
+
+#ifndef _RWSTD_NO_NL_LANGINFO
+
+ if (name) {
+ const char* const cset = nl_langinfo (CODESET);
+
+ if (codeset && std::strcmp (codeset, cset)) {
+
+ // if `codeset' is specified, verify that it matches
+ // the codeset used to encode the libc locale found
+ // and set above
+
+ for (std::size_t j = 0; aliases [inx].codesets [j]; ++j) {
+
+ if (!std::strcmp (aliases [inx].codesets [j], cset)) {
+ std::setlocale (LC_ALL, "C");
+ return name;
+ }
+ }
+ name = 0;
+ }
+
+ std::setlocale (LC_ALL, "C");
+ }
+
+#endif // _RWSTD_NO_NL_LANGINFO
+
+ return name;
+}
+
+
+const char ext_ascii[] = {
+ // basic ASCII
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ // extended ASCII
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x89\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+};
+
+
+// tries to find a locale whose internal (wchar_t) representation
+// of the Extended ASCII character set does not match the ASCII
+// character values; if such locale is found, fills up to `bufsize'
+// elements of the `buf' array with such characters and returns
+// the name of the locale
+static const char*
+find_interesting_locale (char* buf, std::size_t bufsize)
+{
+ std::memset (buf, 0, bufsize);
+
+ const char* name = 0;
+
+ const char* const buf_save = buf;
+
+ for (name = rw_locale_query (); *name; name += std::strlen (name) + 1) {
+
+ if (!std::setlocale (LC_ALL, name))
+ continue;
+
+ wchar_t wide_ascii [sizeof ext_ascii] = { 0 };
+
+ // convert the array of narrow Extended ASCII characters
+ // to their corresponding wchar_t values using mbstowcs()
+ const std::size_t nchars =
+ std::mbstowcs (wide_ascii + 1, ext_ascii + 1, sizeof ext_ascii - 2);
+
+ // continue on error
+ if (!nchars || nchars > sizeof ext_ascii - 2)
+ continue;
+
+ // look for a wide character with value different
+ // from the narrow single-byte character
+ for (std::size_t i = 0; i != nchars; ++i) {
+
+ typedef unsigned char UChar;
+
+ // convert to unsigned char before comparing
+ const UChar uc = UChar (ext_ascii [i]);
+
+ if (unsigned (uc) != unsigned (wide_ascii [i])) {
+ if (bufsize) {
+ *buf++ = ext_ascii [i];
+ --bufsize;
+ }
+ }
+ }
+
+ if (buf != buf_save)
+ break;
+ }
+
+ return name;
+}
+
+
+template <class internT>
+static void
+test_inout (const char* tname)
+{
+ // for convenience
+ const std::codecvt_base::result error = std::codecvt_base::error;
+ const std::codecvt_base::result noconv = std::codecvt_base::noconv;
+ const std::codecvt_base::result ok = std::codecvt_base::ok;
+ const std::codecvt_base::result partial = std::codecvt_base::partial;
+
+ _RWSTD_UNUSED (noconv);
+
+ const char* locname = 0;
+
+ //////////////////////////////////////////////////////////////////
+ // exercise both codecvt::in() and codecvt::out()
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::codecvt<%s, char, mbstate_t>::in() "
+ "in a generated locale", tname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::codecvt<%s, char, mbstate_t>::out() "
+ "in a generated locale", tname);
+
+ // exercise a single-byte external encoding
+
+ rw_info (0, __FILE__, __LINE__, "<mb_cur_max> 1");
+
+ locname = create_codecvt (1, 1, // MB_CUR_MAX = 1 (min = 1)
+ // internal external (single-byte)
+ /* NUL */ "<U0000> /x30\n" // L"\0" <-> "0"
+ /* <A> */ "<U0041> /x31\n" // L"A" <-> "1"
+ /* <B> */ "<U0042> /x32\n" // L"B" <-> "2"
+ /* <C> */ "<U0043> /x33\n" // L"C" <-> "3"
+ /* <D> */ "<U0044> /x34\n" // L"D" <-> "4"
+ /* <E> */ "<U0045> /x35\n" // L"E" <-> "5"
+ /* <F> */ "<U0046> /x36\n" // L"F" <-> "6"
+ /* <Z> */ "<U005A> /x00\n" // L"Z" <-> "\0"
+
+#if _RWSTD_WCHAR_T_MAX > 0xffffU
+ "<U12345678> /x78\n" // 0x12345678 <-> "x"
+ "<U0DEDBEEF> /x79\n" // 0x0dedbeef <-> "y"
+#else // if (WCHAR_T_MAX <= 0xffffU)
+ "<U1234> /x78\n" // 0x1234 <-> "x"
+ "<UBEEF> /x79\n" // 0xbeef <-> "y"
+#endif // _RWSTD_WCHAR_T_MAX > 0xffffU
+ );
+
+ if (!locname) {
+ rw_assert (false, __FILE__, __LINE__,
+ "failed to generate locale");
+ return;
+ }
+
+#define DO_TEST(io, src, ext_len, ext_num, dst, int_len, int_num, res) \
+ test_inout (io, __LINE__, locname, src, ext_len, ext_num, \
+ dst, int_len, int_num, res)
+
+// TEST_IN: tests only codecvt::in()
+#define TEST_IN(src, ext_len, ext_num, dst, int_len, int_num, res) \
+ DO_TEST ('I', src, ext_len, ext_num, dst, int_len, int_num, res)
+
+// TEST_OUT: tests only codecvt::out()
+#define TEST_OUT(src, ext_len, ext_num, dst, int_len, int_num, res) \
+ DO_TEST ('O', src, ext_len, ext_num, dst, int_len, int_num, res)
+
+// TEST_IN_OUT: tests codecvt::in() and codecvt::out() only
+// if the expected result is codecvt_base::ok
+#define TEST_IN_OUT(src, ext_len, ext_num, dst, int_len, int_num, res) \
+ DO_TEST ('i', src, ext_len, ext_num, dst, int_len, int_num, res)
+
+// TEST_OUT_IN: tests codecvt::out() and codecvt::in() only
+// if the expected result is codecvt_base::ok
+#define TEST_OUT_IN(src, ext_len, ext_num, dst, int_len, int_num, res) \
+ DO_TEST ('o', src, ext_len, ext_num, dst, int_len, int_num, res)
+
+ // +------------------------- contents of external (source) buffer
+ // | +-------------------- size of external (source) sequence
+ // | | +----------------- expected size of consumed input
+ // | | | +-------------- expected contents of internal buffer
+ // | | | | +-------- size of dest. buffer (in chars)
+ // | | | | | +----- expected size of output (in chars)
+ // | | | | | | +-- expected result
+ // V V V V V V V
+ TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
+ TEST_IN_OUT ("0", 1, 1, L"", 1, 1, ok); // "0" maps to wchar_t (0)
+ TEST_IN_OUT ("1", 1, 1, L"A", 1, 1, ok);
+ TEST_IN_OUT ("2", 1, 1, L"B", 1, 1, ok);
+ TEST_IN_OUT ("3", 1, 1, L"C", 1, 1, ok);
+ TEST_IN_OUT ("4", 1, 1, L"D", 1, 1, ok);
+ TEST_IN_OUT ("5", 1, 1, L"E", 1, 1, ok);
+ TEST_IN_OUT ("6", 1, 1, L"F", 1, 1, ok);
+ TEST_IN_OUT ("7", 1, 0, L"", 1, 0, error);
+ TEST_IN_OUT ("0", 1, 0, L"", 0, 0, partial); // not enough space
+
+ TEST_IN_OUT ("12", 2, 2, L"AB", 2, 2, ok);
+ TEST_IN_OUT ("123", 3, 3, L"ABC", 3, 3, ok);
+ TEST_IN_OUT ("0123", 4, 4, L"\0ABC", 4, 4, ok);
+ TEST_IN_OUT ("0123Z", 5, 4, L"\0ABC", 5, 4, error);
+ TEST_IN_OUT ("01234", 5, 4, L"\0ABC", 4, 4, partial);
+
+#if _RWSTD_WCHAR_T_MAX > 0xffffU
+
+ TEST_IN_OUT ("x", 1, 1, L"\x12345678", 1, 1, ok);
+ TEST_IN_OUT ("y", 1, 1, L"\x0dedbeef", 1, 1, ok);
+
+ TEST_IN_OUT ("0123x", 5, 5, L"\0ABC\x12345678", 5, 5, ok);
+ TEST_IN_OUT ("123y", 4, 4, L"ABC\x0dedbeef", 4, 4, ok);
+
+#else
+
+ TEST_IN_OUT ("x", 1, 1, L"\x1234", 1, 1, ok);
+ TEST_IN_OUT ("y", 1, 1, L"\xbeef", 1, 1, ok);
+
+ TEST_IN_OUT ("0123x", 5, 5, L"\0ABC\x1234", 5, 5, ok);
+ TEST_IN_OUT ("123y", 4, 4, L"ABC\xbeef", 4, 4, ok);
+
+#endif // _RWSTD_WCHAR_T_MAX > 0xffffU
+
+
+ // exercise multi-byte external encodings
+
+ rw_info (0, __FILE__, __LINE__, "<mb_cur_max> 2");
+
+ locname = create_codecvt (1, 2, // MB_CUR_MAX = 2 (min = 1)
+ // internal external (multi-byte)
+ /* NUL */ "<U0000> /x30\n" // '\0' <-> "0"
+ /* <A> */ "<U0041> /x31/x61\n" // "A" <--> "1a"
+ /* <B> */ "<U0042> /x32\n" // "B" <--> "2"
+ /* <C> */ "<U0043> /x33/x62\n" // "C" <--> "3b"
+ /* <D> */ "<U0044> /x34\n" // "D" <--> "4"
+ /* <E> */ "<U0045> /x35/x63\n" // "E" <--> "3c"
+ /* <F> */ "<U0046> /x36\n" // "F" <--> "4"
+ /* <Z> */ "<U005A> /x00/x00"); // "Z" <--> "\0\0"
+
+ if (!locname) {
+ rw_assert (false, __FILE__, __LINE__,
+ "failed to generate locale");
+ return;
+ }
+
+ TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
+ TEST_IN_OUT ("0", 1, 1, L"", 1, 1, ok); // "0" maps to wchar_t (0)
+ TEST_IN_OUT ("1a", 2, 2, L"A", 1, 1, ok);
+ TEST_IN_OUT ("2", 1, 1, L"B", 1, 1, ok);
+ TEST_IN_OUT ("3b", 2, 2, L"C", 1, 1, ok);
+ TEST_IN_OUT ("4", 1, 1, L"D", 1, 1, ok);
+ TEST_IN_OUT ("5c", 2, 2, L"E", 1, 1, ok);
+ TEST_IN_OUT ("6", 1, 1, L"F", 1, 1, ok);
+ TEST_IN_OUT ("7", 1, 0, L"", 1, 0, error);
+ TEST_IN_OUT ("1", 1, 0, L"", 0, 0, partial); // not enough space
+
+ // exercise only in()
+ // result is partial due to the incomplete multibyte character
+ TEST_IN ("3", 1, 0, L"", 1, 0, partial);
+
+ TEST_IN_OUT ("01a23b", 6, 6, L"\0ABC", 4, 4, ok);
+ TEST_IN_OUT ("01a23b4", 7, 7, L"\0ABCD", 5, 5, ok);
+ TEST_IN_OUT ("01a23b45", 8, 7, L"\0ABCD", 5, 5, partial);
+ TEST_IN_OUT ("01a23b45c", 9, 9, L"\0ABCDE", 6, 6, ok);
+ TEST_IN_OUT ("01a23c45c", 9, 4, L"\0ABCDE", 6, 3, error);
+
+
+ rw_info (0, __FILE__, __LINE__, "<mb_cur_max> 6");
+
+ locname = create_codecvt (1, 6, // MB_CUR_MAX = 6 (min = 1)
+ // internal external (multi-byte)
+ /* NUL */ "<U0000> /x35\n" // "\0" <-> "5"
+ /* <A> */ "<U0041> /x30/x31\n" // "A" <--> "01"
+ /* <B> */ "<U0042> /x31/x32/x33\n" // "B" <--> "123"
+ /* <C> */ "<U0043> /x32/x33/x34/x35\n" // "C" <--> "2345"
+ /* <D> */ "<U0044> /x33/x34/x35/x36/x37\n" // "D" <--> "34567"
+ /* <E> */ "<U0045> /x34/x35/x36/x37/x38/x39\n" // "E" <--> "456789"
+ /* <Z> */ "<U005A> /x00/x00/x00"); // "Z" <--> "\0\0\0"
+
+ if (!locname) {
+ rw_assert (false, __FILE__, __LINE__, "failed to generate locale");
+ return;
+ }
+
+ TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
+ TEST_IN_OUT ("01", 2, 2, L"A", 1, 1, ok);
+ TEST_IN_OUT ("012", 3, 2, L"A", 1, 1, partial);
+ TEST_IN_OUT ("0123", 4, 2, L"A", 1, 1, partial);
+ TEST_IN_OUT ("01234", 5, 2, L"A", 1, 1, partial);
+ TEST_IN_OUT ("012345", 6, 6, L"AC", 2, 2, ok);
+ TEST_IN_OUT ("123456789", 9, 9, L"BE", 3, 2, ok);
+ TEST_IN_OUT ("456789012345", 12, 12, L"EAC", 3, 3, ok);
+
+ // the first one below is partial even though the external sequence
+ // ends in the invalid byte '6' since there is no room in the dest.
+ // buffer (this could be either partial or error, the latter if the
+ // function verifies the validity of the character before checking
+ // whether there is sufficient room in the destination buffer)
+ TEST_IN_OUT ("0123456", 7, 6, L"AC", 2, 2, partial /* or error */);
+ TEST_IN_OUT ("0123456", 7, 6, L"AC", 3, 2, error);
+
+#ifndef _RWSTD_NO_NL_LANGINFO
+
+ char chars [256];
+ const char* const interesting_locale_name =
+ find_interesting_locale (chars, sizeof chars);
+
+ if (interesting_locale_name) {
+
+ std::setlocale (LC_ALL, interesting_locale_name);
+ const char* const codeset = nl_langinfo (CODESET);
+
+ rw_info (0, __FILE__, __LINE__,
+ "<code_set_name> %s (locale(\"%s\"))",
+ codeset, interesting_locale_name);
+
+ typedef unsigned char UChar;
+
+ char charmap [sizeof chars * 40];
+
+ charmap [0] = '\0';
+
+ for (const char* pc = chars; *pc; ++pc) {
+ std::sprintf (charmap + std::strlen (charmap),
+ "<U%04X> /x%02x\n", UChar (*pc), UChar (*pc));
+ }
+
+ locname = create_codecvt (1, 1, charmap, codeset);
+
+ if (!locname) {
+ rw_assert (false, __FILE__, __LINE__,
+ "failed to generate locale");
+ return;
+ }
+
+ wchar_t wchars [sizeof chars];
+ std::mbstowcs (wchars, chars, std::strlen (chars));
+
+ std::setlocale (LC_ALL, "C");
+
+ for (std::size_t i = 0; chars [i]; ++i) {
+
+ const char cs [] = { chars [i], '\0' };
+ const wchar_t ws [] = { wchars [i], 0 };
+
+ TEST_IN_OUT (cs, 1, 1, ws, 1, 1, ok);
+ }
+ }
+
+#endif // _RWSTD_NO_NL_LANGINFO
+
+ // exercise codecvt_byname constructed with the special names below
+ const char* const names[] = {
+ // "UTF" prefix in all caps causes strict checking of UTF
+ // sequences at some loss in performance; "utf" prefix (all
+ // lowercase) allows for a faster implementation but accepts
+ // some sequences that are strictly speaking invalid (see
+ // below)
+
+ "UTF-8", "UTF-8@UCS",
+
+#if _RWSTD_WCHAR_T_MAX > 0xffffU
+ "UTF-8@UCS-4",
+#else // if _RWSTD_WCHAR_T_MAX <= 0xffffU
+ "UTF-8@UCS-2",
+#endif // WCHAR_T_MAX > 0xffffU
+
+ "utf-8", "utf-8@UCS",
+
+#if _RWSTD_WCHAR_T_MAX > 0xffffU
+ "utf-8@UCS-4",
+#else // if _RWSTD_WCHAR_T_MAX <= 0xffffU
+ "utf-8@UCS-2",
+#endif // WCHAR_T_MAX > 0xffffU
+ };
+
+ for (std::size_t i = 0; i != sizeof names / sizeof *names; ++i) {
+ locname = names [i];
+
+ rw_info (0, __FILE__, __LINE__,
+ "codecvt_byname<wchar_t, char, mbstate_t>"
+ "(\"%s\")", locname);
+
+ // strict conformance mode
+ const bool strict_mode = 'U' == *locname;
+
+ TEST_IN_OUT ("", 0, 0, L"", 0, 0, ok);
+ TEST_IN_OUT ("\0", 1, 1, L"\0", 1, 1, ok);
+ TEST_IN_OUT ("a", 1, 1, L"a", 1, 1, ok);
+ TEST_IN_OUT ("b", 1, 1, L"b", 1, 1, ok);
+ TEST_IN_OUT ("z", 1, 1, L"z", 1, 1, ok);
+ TEST_IN_OUT ("\x7f", 1, 1, L"\x7f", 1, 1, ok);
+
+ TEST_IN ("\x80", 1, 0, L"", 1, 0, error);
+ TEST_IN ("\x81", 1, 0, L"", 1, 0, error);
+ TEST_IN ("\x82", 1, 0, L"", 1, 0, error);
+ TEST_IN ("\xc1", 1, 0, L"", 1, 0, error);
+
+ TEST_IN_OUT ("\xc2\x80", 2, 2, L"\x80", 1, 1, ok);
+ TEST_IN_OUT ("\xc2\x81", 2, 2, L"\x81", 1, 1, ok);
+ TEST_IN_OUT ("\xc2\x82", 2, 2, L"\x82", 1, 1, ok);
+ TEST_IN_OUT ("\xc2\xbf", 2, 2, L"\xbf", 1, 1, ok);
+
+ TEST_IN_OUT ("\xc3\x80", 2, 2, L"\xc0", 1, 1, ok);
+ TEST_IN_OUT ("\xc3\x81", 2, 2, L"\xc1", 1, 1, ok);
+
+ TEST_IN_OUT ("\xde\xb0", 2, 2, L"\x07b0", 1, 1, ok);
+
+ TEST_IN_OUT ("\xe0\xa4\x81", 3, 3, L"\x0901", 1, 1, ok);
+ TEST_IN_OUT ("\xe3\x8f\xbe", 3, 3, L"\x33fe", 1, 1, ok);
+ TEST_IN_OUT ("\xe3\x90\x80", 3, 3, L"\x3400", 1, 1, ok);
+ TEST_IN_OUT ("\xe3\x91\x80", 3, 3, L"\x3440", 1, 1, ok);
+
+ if (strict_mode) {
+ // otherwise benign invalid patterns detected only in strict mode
+
+ // test the ability to detect and diagnose overlong sequences
+
+ // exercise, e.g., alternative encodings of U+0000 (i.e., <NUL>)
+ TEST_IN ("\xc0\x80", 2, 0, L"", 1, 0, error);
+ TEST_IN ("\xe0\x80\x80", 3, 0, L"", 1, 0, error);
+ TEST_IN ("\xf0\x80\x80\x80", 4, 0, L"", 1, 0, error);
+ TEST_IN ("\xf8\x80\x80\x80\x80", 5, 0, L"", 1, 0, error);
+ TEST_IN ("\xfc\x80\x80\x80\x80\x80", 6, 0, L"", 1, 0, error);
+
+ // exercise, e.g., alternative encodings of U+000A (i.e., <LF>)
+ TEST_IN ("\xc0\x8a", 2, 0, L"", 1, 0, error);
+ TEST_IN ("\xe0\x80\x8a", 3, 0, L"", 1, 0, error);
+ TEST_IN ("\xf0\x80\x80\x8a", 4, 0, L"", 1, 0, error);
+ TEST_IN ("\xf8\x80\x80\x80\x8a", 5, 0, L"", 1, 0, error);
+ TEST_IN ("\xfc\x80\x80\x80\x80\x8a", 6, 0, L"", 1, 0, error);
+
+ // test the ability to detect and diagnose UTF-16 surrogate
+ // pairs and the special code points U+FFFE and U+FFFF
+
+ TEST_OUT ("", 8, 0, L"\xd800", 1, 0, error);
+ TEST_OUT ("", 8, 0, L"\xd801", 1, 0, error);
+ TEST_OUT ("", 8, 0, L"\xdffe", 1, 0, error);
+ TEST_OUT ("", 8, 0, L"\xdfff", 1, 0, error);
+ TEST_OUT ("", 8, 0, L"\xfffe", 1, 0, error);
+ TEST_OUT ("", 8, 0, L"\xffff", 1, 0, error);
+
+ // the second and subsequent bytes of a multibyte UTF-8
+ // sequence must have the following bit pattern: 10xxxxxx
+ TEST_IN ("\xc2\x01", 2, 0, L"", 1, 0, error);
+ TEST_IN ("\xc2\xff", 2, 0, L"", 1, 0, error);
+
+ }
+ else {
+ // in relaxed mode the UTF-8 sequences below convert
+ // into the UCS characters U+3081 and U+30BF even
+ // though the UCS characters convert into 3-byte
+ // UTF-8 characters each (see below)
+ TEST_IN ("\xc2\x01", 2, 2, L"\x3081", 1, 1, ok);
+ TEST_IN ("\xc2\xff", 2, 2, L"\x30bf", 1, 1, ok);
+ }
+
+ TEST_OUT ("\xe3\x82\x81", 3, 3, L"\x3081", 1, 1, ok);
+ TEST_OUT ("\xe3\x82\xbf", 3, 3, L"\x30bf", 1, 1, ok);
+
+ TEST_IN_OUT ("\x00", 1, 1, L"\x00000000", 1, 1, ok);
+ TEST_IN_OUT ("\x7f", 1, 1, L"\x0000007f", 1, 1, ok);
+
+ TEST_IN_OUT ("\xc2\x80", 2, 2, L"\x00000080", 1, 1, ok);
+ TEST_IN_OUT ("\xdf\xbf", 2, 2, L"\x000007ff", 1, 1, ok);
+
+ TEST_IN_OUT ("\xe0\xa0\x80", 3, 3, L"\x00000800", 1, 1, ok);
+
+#if _RWSTD_WCHAR_T_MAX > 0xffffU
+
+ TEST_IN_OUT ("\xf0\x90\x8c\x80", 4, 4, L"\x00010300", 1, 1, ok);
+ TEST_IN_OUT ("\xf0\x90\x8c\x81", 4, 4, L"\x00010301", 1, 1, ok);
+ TEST_IN_OUT ("\xf4\x8f\xbf\x80", 4, 4, L"\x0010ffc0", 1, 1, ok);
+
+ TEST_IN_OUT ("\xf0\x90\x80\x80", 4, 4, L"\x0010000", 1, 1, ok);
+ TEST_IN_OUT ("\xf8\x88\x80\x80\x80", 5, 5, L"\x0200000", 1, 1, ok);
+ TEST_IN_OUT ("\xfc\x84\x80\x80\x80\x80", 6, 6, L"\x4000000", 1, 1, ok);
+
+#endif // _RWSTD_WCHAR_T_MAX > 0xffffU
+ }
+}
+
+/****************************************************************************/
+
+static void
+test_ascii (const char *locname, const char* native_locname)
+{
+ _RWSTD_ASSERT (0 != locname);
+ _RWSTD_ASSERT (0 != native_locname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "Testing conversion of Extended ASCII range in "
+ "locale(\"%s\") against the native locale \"%s\"",
+ locname, native_locname);
+
+ wchar_t wascii [sizeof ext_ascii];
+
+ const std::size_t ext_num = sizeof ext_ascii - 2;
+ std::size_t int_num = ext_num;
+
+ // try to convert the whole extended ascii range
+ if (rwtest_convert_to_internal (use_libc, native_locname,
+ ext_ascii + 1, ext_num,
+ wascii, int_num)) {
+
+ wascii [int_num] = L'\0';
+
+ test_inout ('i', __LINE__, locname,
+ ext_ascii + 1, ext_num, ext_num, wascii, int_num, int_num,
+ std::codecvt_base::ok);
+
+ return;
+ }
+
+ // conversion of the whole range failed,
+ // convert one character at a time
+
+ for (std::size_t i = 1; i != UCHAR_MAX + 1; ++i) {
+
+ if (rwtest_convert_to_internal (use_libc, native_locname,
+ ext_ascii + i, 1,
+ wascii, int_num)) {
+ wascii [int_num] = L'\0';
+
+ test_inout ('i', __LINE__, locname,
+ ext_ascii + i, 1, 1,
+ wascii, int_num, int_num,
+ std::codecvt_base::ok);
+ }
+ }
+}
+
+/****************************************************************************/
+
+// - checks the conversion for each the locales in the locales array
+static int
+run_test (int /*unused*/, char* /*unused*/ [])
+{
+ // 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 ();
+
+#if 0 // FIXME
+
+ // codecvt_byname<char, char, mbstate_t> behaves just like
+ // the base, codecvt<char, char, mbstate_t>, i.e., it does
+ // no conversion
+ test_inout (*this, char ());
+
+#endif // 0/1
+
+ test_inout<wchar_t> ("wchar_t");
+
+ test_virtuals<Codecvt> (0);
+ test_virtuals<CodecvtW> ("C");
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ test_virtuals<CodecvtBn> ("C");
+ test_virtuals<CodecvtBnW> ("C");
+
+#endif // _RWSTD_NO_WCHAR_T
+
+#define TEST_UCS_MODIFIER(T, mod, enc, locname, f, i, is) \
+ do { \
+ char locname_mod [256]; /* <locale-name>@<modifier>*/ \
+ if (*(mod)) \
+ std::sprintf (locname_mod, "%s@%s", locname, (mod)); \
+ else \
+ std::sprintf (locname_mod, "%s", locname); \
+ \
+ _TRY { \
+ const CodecvtBnW cc (locname_mod, 1); \
+ std::locale loc = std::locale (std::locale::classic (), &cc); \
+ \
+ cc._C_opts |= cc._C_use_libstd; \
+ cc._C_opts &= ~cc._C_use_libc; \
+ test_ucs_modifier (locname_mod, enc, s, cc, f, i, is); \
+ \
+ } _CATCH (...) { \
+ rw_assert (false, __FILE__, __LINE__, \
+ "unexpected exception in locale test %s", \
+ locname_mod); \
+ } \
+ } while (0)
+
+#define TEST_LIBSTD(L,T,C,c,f,s,i,is,o,os,ur,ar,er,lr,mr) \
+ _TRY { \
+ test_libstd_codecvt<T>(L,c,f,s,i,is,o,os,ur,ar,er,lr,mr); \
+ } _CATCH (...) { \
+ rw_assert (false, __FILE__, __LINE__, \
+ "unexpected exception in conversion using %s " \
+ "(locale %s)", C ? "C library" : "std library", L); \
+ }
+
+#define TEST_CONVERSION(T,L,C,f,s,i,is,o,os,ur,er,ar,lr,mr) \
+ do { \
+ std::locale loc; \
+ _TRY { \
+ loc = std::locale (L); \
+ } _CATCH (...) { \
+ rw_assert (false, __FILE__, __LINE__, \
+ "locale(\"%s\") unexpectedly threw an " \
+ "exception; " LOCALE_ROOT_ENVAR " = %s", L, \
+ locale_root); \
+ break; \
+ } \
+ _TRY { \
+ const T &cc = create_##T (loc); \
+ \
+ cc._C_opts |= cc._C_use_libstd; \
+ cc._C_opts &= ~cc._C_use_libc; \
+ TEST_LIBSTD (L,T,C,cc,f,s,i,is,o,os,ur,ar,er,lr,mr); \
+ \
+ if (C == true && rwtest_is_C_locale (f)) { \
+ cc._C_opts &= ~cc._C_use_libstd; \
+ cc._C_opts |= cc._C_use_libc; \
+ TEST_LIBSTD(L,T,C,cc,f,s,i,is,o,os,ur,ar,er,lr,mr); \
+ } \
+ } _CATCH (...) { \
+ rw_assert (false, __FILE__, __LINE__, \
+ "unexpected exception in locale test %s", L); \
+ } \
+ } while (0)
+
+
+ static const struct {
+ const char* src_name; // locale definition file name
+ const char* charmap_name; // charset description file name
+ const char* locale_name; // name of the locale database
+ std::size_t nbytes; // size of test buffer
+ std::size_t nchars; // number of characters in buffer
+ std::size_t encoding; // result of codecvt::encoding()
+ std::size_t max_length; // result of codecvt::max_length()
+ } locales [] = {
+ // single-width encodings where the number of characters
+ // equals the number of bytes (and max_length == 1)
+ { "de_DE", "ISO-8859-1", "de_DE.ISO-8859-1", 6826, 6826, 1, 1 },
+ { "fr_FR", "ISO-8859-1", "fr_FR.ISO-8859-1", 3920, 3920, 1, 1 },
+ // multi-byte encodings (variable width, and max_length > 1)
+ { "ja_JP", "Shift_JIS" , "ja_JP.Shift_JIS", 25115, 13001, 0, 2 },
+#if !defined _MSC_VER
+ { "ja_JP", "EUC-JP" , "ja_JP.EUC-JP", 20801, 14299, 0, 3 },
+ { "ja_JP", "UTF-8" , "ja_JP.UTF-8", 25056, 12000, 0, 6 },
+#endif // !defined _MSC_VER
+
+ // terminate the array
+ { 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+
+ // Testing actual locale databases with input files
+ rw_info (0, __FILE__, __LINE__,
+ "Testing locale databases - file conversions.");
+
+ // index of the first successfully built locale database
+ int first_good_locale = -1;
+
+ const char* const topdir = std::getenv ("TOPDIR");
+ if (!topdir || !*topdir) {
+ rw_assert (false, __FILE__, __LINE__,
+ "environment variable TOPDIR not set or empty");
+ }
+
+ for (std::size_t i = 0; locales [i].src_name; i++) {
+
+ // Testing actual locale databases with input files
+
+ // try to build a locale database and get its name
+ const char* const locname =
+ rw_localedef ("-w",
+ locales [i].src_name,
+ locales [i].charmap_name,
+ locales [i].locale_name);
+
+ if (!locname)
+ continue;
+
+ // find the native locale name correspomding to the canonical
+ // locale name hardcoded in the table above
+ const char* const native_locname =
+ find_locale (locales [i].locale_name, locales [i].charmap_name);
+
+ if (native_locname)
+ test_ascii (locales [i].locale_name, native_locname);
+ else {
+ std::fprintf (stderr, "*** failed to find a native locale to match"
+ " locale(\"%s\"), skipping Extended ASCII conversion"
+ " test\n", locales [i].locale_name);
+ }
+
+#define TESTS_ETC_PATH "tests" SLASH "etc"
+
+ // determine the full pathname of test files in the source tree
+ char pathname [PATH_MAX];
+ std::strcpy (pathname, topdir);
+ std::strcat (pathname, SLASH TESTS_ETC_PATH SLASH "codecvt.");
+ std::strcat (pathname, locales [i].locale_name);
+ std::strcat (pathname, ".in");
+
+ const char* const s = pathname;
+
+ // exercise the behavior of codecvt<char, char, mbstate_t>
+ TEST_CONVERSION (Codecvt, locales [i].locale_name, true, s, true,
+ std::codecvt_base::noconv, locales [i].nbytes,
+ std::codecvt_base::noconv, locales [i].nbytes,
+ std::codecvt_base::noconv, 1,
+ true, locales [i].nbytes, 1);
+
+ // exercise the behavior of codecvt_byname<char, char, mbstate_t>
+ TEST_CONVERSION (CodecvtBn, locales [i].locale_name, true, s, true,
+ std::codecvt_base::noconv, locales [i].nbytes,
+ std::codecvt_base::noconv, locales [i].nbytes,
+ std::codecvt_base::noconv, 1,
+ true, locales [i].nbytes, 1);
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ // exercise the behavior of codecvt<wchar_t, char, mbstate_t>
+ TEST_CONVERSION (CodecvtW, locales [i].locale_name, true, s, true,
+ std::codecvt_base::ok, locales [i].nbytes,
+ std::codecvt_base::ok, locales [i].nbytes,
+ std::codecvt_base::noconv, 1,
+ false, locales [i].nbytes, 1);
+
+ // exercise the behavior of codecvt_byname<wchar_t, char, mbstate_t>
+ TEST_CONVERSION (CodecvtBnW, locales [i].locale_name, true, s, false,
+ std::codecvt_base::ok, locales [i].nchars,
+ std::codecvt_base::ok, locales [i].nbytes,
+ std::codecvt_base::noconv, locales [i].encoding,
+ false, locales [i].nchars, locales [i].max_length);
+
+
+
+ // save the index of the first locale database successfully built
+ if (-1 == first_good_locale)
+ first_good_locale = _RWSTD_STATIC_CAST (int, i);
+
+ // FIXME: Until the LE (little endian) and BE (big endian) extra
+ // modifiers are implemented, the test is skipped for Linux distros
+ // such as Red Hat 6.2 that ship with glibc 2.1.1-6
+
+# if !defined __GLIBC__ \
+ || __GLIBC__ == 2 && __GLIBC_MINOR__ > 1 \
+ || __GLIBC__ > 2
+
+ // exercise the behavior of codecvt_byname<wchar_t, char, mbstate_t>
+ // in constructed with one of the additional @UCS name modifiers
+ TEST_UCS_MODIFIER (CodecvtBnW, "", use_libc,
+ locales [i].locale_name, s, std::codecvt_base::ok,
+ locales [i].nchars);
+
+ const InternalEncoding which_ucs =
+ sizeof (wchar_t) == 4 ? use_UCS4 : use_UCS2;
+
+ TEST_UCS_MODIFIER (CodecvtBnW,
+ use_UCS4 == which_ucs ? "UCS-4" : "UCS-2", which_ucs,
+ locales [i].locale_name, s, std::codecvt_base::ok,
+ locales [i].nchars);
+
+ TEST_UCS_MODIFIER (CodecvtBnW, "UCS", which_ucs,
+ locales [i].locale_name, s, std::codecvt_base::ok,
+ locales [i].nchars);
+
+# endif // GLIBC version > 2.1
+#endif // _RWSTD_NO_WCHAR_T
+
+ }
+
+ // exercise the behavior of the facets when passed
+ // an uninitialized or corrupt mbstate_t object
+ test_invalid_args (-1 == first_good_locale ?
+ (char*)0 : locales [first_good_locale].locale_name);
+
+ return 0;
+}
+
+
+/*extern*/ int
+main (int argc, char* argv [])
+{
+ return rw_test (argc, argv, __FILE__,
+ "[lib.locale.codecvt]",
+ "", // no comment
+ run_test, "", 0);
+}
+
diff --git a/tests/localization/22.locale.codecvt.mt.cpp b/tests/localization/22.locale.codecvt.mt.cpp
index 9b3cc26..55f071d 100644
--- a/tests/localization/22.locale.codecvt.mt.cpp
+++ b/tests/localization/22.locale.codecvt.mt.cpp
@@ -45,18 +45,21 @@
// default number of threads (will be adjusted to the number
// of processors/cores later)
-int rw_opt_nthreads = 1;
+int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
-int rw_opt_nloops = 5000;
+int opt_nloops = 5000;
// number of locales to use
-int rw_opt_nlocales = MAX_THREADS;
+int opt_nlocales = MAX_THREADS;
// should all threads share the same set of locale objects instead
// of creating their own?
-int rw_opt_shared_locale;
+int opt_shared_locale;
+
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
/**************************************************************************/
@@ -314,7 +317,10 @@
const int ni = RW_COUNT_OF (nsrc);
const int wi = RW_COUNT_OF (wsrc);
- for (int i = 0; i != rw_opt_nloops; ++i) {
+ for (int i = 0; i != opt_nloops; ++i) {
+
+ if (rw_thread_pool_timeout_expired ())
+ break;
const int inx = i % nlocales;
const MyCodecvtData& data = my_codecvt_data [inx];
@@ -322,8 +328,8 @@
// construct a named locale, get a reference to the codecvt
// facet from it and use it to format a random money value
const std::locale loc =
- rw_opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ opt_shared_locale ? data.locale_
+ : std::locale (data.locale_name_);
const MyCodecvtData::CvtId op =
MyCodecvtData::CvtId (i % MyCodecvtData::cvt_max);
@@ -460,7 +466,7 @@
run_test_fill<wchar_t>
(loc, wsrc [inx % wi], nsrc [inx % ni], data.wchar_data_);
- if (rw_opt_shared_locale)
+ if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
@@ -471,7 +477,7 @@
"failed to create locale(%#s)", name);
}
- if (nlocales == maxinx || nlocales == std::size_t (rw_opt_nlocales))
+ if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
@@ -482,8 +488,8 @@
rw_info (0, 0, 0,
"testing std::codecvt<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
- rw_opt_nthreads, 1 != rw_opt_nthreads,
- rw_opt_nloops, 1 != rw_opt_nloops,
+ opt_nthreads, 1 != opt_nthreads,
+ opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
///////////////////////////////////////////////////////////////////////
@@ -495,11 +501,12 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
@@ -509,11 +516,12 @@
test_wchar = true;
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
@@ -524,11 +532,12 @@
test_wchar = true;
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
return result;
}
@@ -541,24 +550,26 @@
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
- rw_opt_nthreads = rw_get_cpus ();
- if (rw_opt_nthreads < 2)
- rw_opt_nthreads = 2;
+ opt_nthreads = rw_get_cpus ();
+ if (opt_nthreads < 2)
+ opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.codecvt",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
- &rw_opt_nloops,
+ &opt_timeout,
+ &opt_nloops,
int (MAX_THREADS),
- &rw_opt_nthreads,
- &rw_opt_nlocales,
+ &opt_nthreads,
+ &opt_nlocales,
&rw_opt_setlocales,
- &rw_opt_shared_locale);
+ &opt_shared_locale);
}
diff --git a/tests/localization/22.locale.codecvt.out.cpp b/tests/localization/22.locale.codecvt.out.cpp
index 5599c15..bb331fb 100644
--- a/tests/localization/22.locale.codecvt.out.cpp
+++ b/tests/localization/22.locale.codecvt.out.cpp
@@ -197,7 +197,7 @@
struct WideCode
{
wchar_t wchar;
- char mbchar [MB_LEN_MAX];
+ char mbchar [MB_LEN_MAX + 1];
};
typedef WideCode mb_char_array_t [MB_LEN_MAX];
diff --git a/tests/localization/22.locale.collate.cpp b/tests/localization/22.locale.collate.cpp
new file mode 100644
index 0000000..f922d3c
--- /dev/null
+++ b/tests/localization/22.locale.collate.cpp
@@ -0,0 +1,1118 @@
+/***************************************************************************
+ *
+ * 22.locale.collate.cpp -- tests for collate-facet member functions
+ *
+ * $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 1994-2008 Rogue Wave Software.
+ *
+ **************************************************************************/
+
+#include <locale> // for collate, locale
+#include <string> // for string
+
+#include <algorithm> // for sort and unique
+#include <climits> // for UCHAR_MAX
+#include <clocale> // for LC_COLLATE, setlocale
+#include <cstdlib> // for exit()
+#include <cstdio> // for fprintf()
+#include <cstring> // for strcmp(), strcoll(), ...
+#include <cwchar> // for wcscoll()
+
+#include <driver.h>
+#include <environ.h>
+#include <file.h>
+#include <rw_locale.h>
+#include <rw_process.h>
+
+
+#if _RWSTD_PATH_SEP == '/'
+# define SLASH "/"
+#else
+# define SLASH "\\"
+#endif
+
+// strings declared extern to work around a SunPro bug (PR #28124)
+// get the source root
+#define RELPATH "etc" SLASH "nls"
+#define TESTS_ETC_PATH "tests" SLASH "etc"
+
+// the root of the locale directory (RWSTD_LOCALE_ROOT)
+#define LOCALE_ROOT "RWSTD_LOCALE_ROOT"
+const char* locale_root;
+
+#define LC_COLLATE_SRC "LC_COLLATE.src"
+#define LC_COLLATE_CM "LC_COLLATE.cm"
+#define TEST_LOCALE_NAME "test.locale"
+
+/**************************************************************************/
+
+// These overloads are necessary in our template
+// functions so that we can make a single function call reguardless
+// of the charT we are using
+
+int c_strcoll (const char* s1, const char* s2)
+{
+ const int ret = std::strcoll(s1, s2);
+ return ret ? ret > 0 ? 1 : -1 : 0;
+}
+
+std::size_t c_xfrm (char* to, const char* from, std::size_t size)
+{
+ char safety_buf [8];
+ if (0 == to && 0 == size) {
+ // prevent buggy implementations (such as MSVC 8) from trying
+ // to write to the destination buffer even though it's 0 and
+ // its size is zero (see stdcxx-69)
+ to = safety_buf;
+ *to = '\0';
+ }
+
+ std::size_t n = std::strxfrm (to, from, size);
+
+ if (to)
+ n = std::strlen (to);
+
+ return n;
+}
+
+std::size_t c_strlen (const char* s1)
+{
+ return std::strlen (s1);
+}
+
+const char* narrow (char* dst, const char* src)
+{
+ if (src == dst || !src || !dst)
+ return src;
+
+ std::memcpy (dst, src, std::strlen (src) + 1);
+ return dst;
+}
+
+const char* widen (char* dst, const char* src)
+{
+ if (src == dst || !src || !dst)
+ return src;
+
+ std::memcpy (dst, src, std::strlen (src) + 1);
+ return dst;
+}
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+int c_strcoll (const wchar_t* s1, const wchar_t* s2)
+{
+ const int ret = std::wcscoll(s1, s2);
+ return ret ? ret > 0 ? 1 : -1 : 0;
+}
+
+std::size_t c_xfrm (wchar_t* to, const wchar_t* from, std::size_t size)
+{
+#if !defined (_MSC_VER) || _MSC_VER > 1200
+
+ wchar_t safety_buf [8];
+ if (0 == to && 0 == size) {
+ // prevent buggy implementations (such as MSVC 8) from trying
+ // to write to the destination buffer even though it's 0 and
+ // its size is zero (see stdcxx-69)
+ to = safety_buf;
+ *to = L'\0';
+ }
+
+ std::size_t n = std::wcsxfrm (to, from, size);
+
+ if (to)
+ n = std::wcslen (to);
+
+#else // MSVC 6 and prior
+
+ // working around an MSVC 6.0 libc bug (PR #26437)
+
+ if (to) {
+ std::size_t n = std::wcsxfrm (to, from, size);
+
+ n = std::wcslen (to);
+
+ return n;
+ }
+
+ wchar_t tmp [1024];
+
+ std::size_t n = std::wcslen (from);
+
+ _RWSTD_ASSERT (n < sizeof tmp / sizeof *tmp);
+
+ std::wcscpy (tmp, from);
+
+ std::wcsxfrm (tmp, from, sizeof tmp / sizeof *tmp);
+
+ n = std::wcslen (tmp);
+
+#endif // MSVC 6
+
+ return n;
+}
+
+std::size_t c_strlen (const wchar_t* s1)
+{
+ return std::wcslen (s1);
+}
+
+const wchar_t* widen (wchar_t* dst, const char* src)
+{
+ static wchar_t buf [4096];
+
+ if (!src)
+ return 0;
+
+ if (!dst)
+ dst = buf;
+
+ std::size_t len = std::strlen (src);
+
+ _RWSTD_ASSERT (len < sizeof buf /sizeof *buf);
+
+ len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
+
+ if (std::size_t (-1) == len)
+ *dst = 0;
+
+ return dst;
+}
+
+const char* narrow (char* dst, const wchar_t* src)
+{
+ static char buf [4096];
+
+ if (!src)
+ return 0;
+
+ if (!dst)
+ dst = buf;
+
+ std::size_t len = std::wcslen (src);
+
+ _RWSTD_ASSERT (len < sizeof buf);
+
+ len = std::wcstombs (dst, src, sizeof buf / sizeof *buf);
+
+ if (std::size_t (-1) == len)
+ *dst = 0;
+
+ return dst;
+}
+
+#endif //_RWSTD_NO_WCHAR_T
+
+/**************************************************************************/
+
+template <class charT>
+/*static*/ void
+gen_str (charT* str, std::size_t size)
+{
+ // generate a random string with the given size
+ if (!size)
+ return;
+
+ // use ASCII characters in the printable range
+ for (std::size_t i = 0; i != size - 1; ++i)
+ str [i] = ' ' + std::rand () % ('~' - ' ');
+
+ str [size - 1] = charT ();
+}
+
+/**************************************************************************/
+
+template <class charT>
+/*static*/ void
+check_libc (const char* charTname)
+{
+ // the libc implementation of the library should act the same as
+ // the c-library. Go through all the locales, generate some random
+ // strings and make sure that the following holds true:
+ // transform acts like strxfrm and wcsxfrm,
+ // compare acts like strcoll and wcscoll
+
+ int nfail [3] = { 0 };
+
+ rw_info (0, __FILE__, __LINE__,
+ "libc std::collate<%s>::transform ()", charTname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "libc std::collate<%s>::compare ()", charTname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "std::collate<%s>::hash ()", charTname);
+
+ for (const char* locname = rw_locales (LC_COLLATE);
+ *locname; locname += std::strlen (locname) + 1) {
+
+ _TRY {
+ std::setlocale (LC_COLLATE, locname);
+ int max = MB_CUR_MAX;
+ if (max > 1)
+ continue;
+
+ std::locale loc;
+
+ _TRY {
+ loc = std::locale (locname);
+ }
+ _CATCH (...) {
+ rw_assert (false, __FILE__, __LINE__,
+ "std::locale(\"%s\") unexpectedly threw "
+ "an exception", locname);
+ continue;
+ }
+
+ const std::collate<charT> &co =
+ _STD_USE_FACET (std::collate<charT>, loc);
+ co._C_opts |= co._C_use_libc;
+ co._C_opts &= ~co._C_use_libstd;
+
+ // now the locale is set up so lets test the transform and
+ // compare functions
+
+ for (int loop_cntrl = 0; loop_cntrl < 10; loop_cntrl++) {
+
+#define STR_SIZE 16
+
+ charT str1 [STR_SIZE] = { 0 };
+ charT str2 [STR_SIZE] = { 0 };
+
+ // generate two random NUL-terminated strings
+ gen_str (str1, sizeof str1 / sizeof *str1);
+ gen_str (str2, sizeof str2 / sizeof *str2);
+
+ // call transform on the generated string
+ // not including the terminating NUL
+ const std::basic_string <charT, std::char_traits<charT>,
+ std::allocator<charT> > out =
+ co.transform (str1, str1 + sizeof str1 / sizeof *str1 - 1);
+
+ // get the size of the buffer needed to hold the
+ // transformed string (with the terminating NUL)
+ std::size_t size = 1U + c_xfrm (0, str1, 0);
+
+ // prevent errors caused by huge return values (e.g., MSVC)
+ if (size > STR_SIZE * 64)
+ size = 0;
+
+ std::basic_string <charT, std::char_traits<charT>,
+ std::allocator<charT> > c_out;
+
+ if (size) {
+ c_out.resize (size);
+
+ // call the C-library transform function
+ size = c_xfrm (&c_out [0], str1, size);
+
+ if (size > STR_SIZE * 64)
+ size = 0;
+
+ // shrink to fit (chop off the terminating NUL)
+ c_out.resize (size);
+ }
+
+ // make sure the output is the same
+ if (out != c_out) {
+ nfail[0]++;
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. collate<%s>::transform(%s, ...) "
+ "== %{S}, got %{S} in locale(\"%s\")",
+ loop_cntrl, charTname, str1,
+ &c_out, &out, locname);
+ }
+
+ // now call compare on the two generated strings
+ int ret1 = co.compare (str1, str1 + sizeof str1 / sizeof *str1,
+ str2, str2 + sizeof str2 / sizeof *str2);
+
+ // call the C-library comparison function
+ int ret2 = c_strcoll (str1, str2);
+
+ // make sure the results are the same
+ if (ret1 != ret2) {
+ nfail [1]++;
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. collate<%s>::compare(%s, ..., %s, ...) "
+ "== %d, got %d in locale(\"%s\")",
+ loop_cntrl, charTname, str1,
+ str2, ret2, ret1, locname);
+ }
+
+ // two strings that compare identically must hash
+ // identically as well. Calling hash on the same string is
+ // not very conclusive but generating strings that have exactly
+ // the same weights is not possible without knowing all the
+ // weight orderings
+ const long hashNum1 =
+ co.hash (str1, str1 + sizeof str1 / sizeof *str1);
+
+ const long hashNum2 =
+ co.hash (str1, str1 + sizeof str1 / sizeof *str1);
+
+ if (hashNum1 != hashNum2) {
+ nfail[2]++;
+ rw_assert (false, __FILE__, __LINE__,
+ "%d. collate<%s>::hash(%s, ...) == %d, "
+ "got %d in locale(\"%s\")",
+ loop_cntrl, charTname, str1,
+ hashNum1, hashNum2, locname);
+ }
+
+
+ }
+ }
+ _CATCH (...) {
+ rw_assert (false, __FILE__, __LINE__,
+ "locale(\"%s\") threw an exception", locname);
+ }
+ }
+
+ rw_assert (0 == nfail [0], __FILE__, __LINE__,
+ "collate<%s>::transform () failed %d times",
+ charTname, nfail [0]);
+
+ rw_assert (0 == nfail [1], __FILE__, __LINE__,
+ "collate<%s>::compare () failed %d times",
+ charTname, nfail [1]);
+
+ rw_assert (0 == nfail [2], __FILE__, __LINE__,
+ "collate<%s>::hash () failed %d times",
+ charTname, nfail [2]);
+}
+
+/**************************************************************************/
+
+static const char*
+make_test_locale ()
+{
+ // create a temporary locale definition file that exercises as
+ // many different parts of the collate standard as possible
+
+ char lc_collate_src_path [L_tmpnam + sizeof LC_COLLATE_SRC + 2];
+ std::strcpy (lc_collate_src_path, locale_root);
+ std::strcat (lc_collate_src_path, SLASH);
+ std::strcat (lc_collate_src_path, LC_COLLATE_SRC);
+
+ std::FILE *fout = std::fopen (lc_collate_src_path, "w");
+
+ const char lc_collate_file[] = {
+ "LC_COLLATE\n"
+ "script <ALL_FORWARD>\n"
+ "collating-element <er> from \"<e><r>\"\n"
+ "collating-element <ic> from \"ic\"\n"
+ "collating-symbol <LETTER>\n"
+ "collating-symbol <COLLATING_ELEMENT>\n"
+ "collating-symbol <DIGIT>\n"
+
+ "order_start forward;backward;forward,position\n"
+ "<LETTER>\n"
+ "<COLLATING_ELEMENT>\n"
+ "<DIGIT>\n"
+
+ "<a> <a> <LETTER> IGNORE\n"
+ "<b> <b> <LETTER> IGNORE\n"
+
+ // "<c>" will have a non-ignored position ordering
+ "<c> <c> <LETTER> <c>\n"
+
+ // try giving "<d>" a many-to-one weight
+ "<d> \"<d><a>\" <LETTER> IGNORE\n"
+
+ // try giving "<e>" a decimal value weight
+ "<e> \\d139 <LETTER> IGNORE\n"
+
+ // try giving "<f>" an octal value weight
+ "<f> \\36 <LETTER> IGNORE\n"
+
+ // try giving "<g>" a hex value weight
+ "<g> \\x3A <LETTER> IGNORE\n"
+
+ "<zero> <zero> <DIGIT> IGNORE\n"
+ "<one> <one> <DIGIT> <zero>\n"
+ "<two> <two> <DIGIT> IGNORE\n"
+ "<three> <three> <DIGIT> IGNORE\n"
+ "<er> <a> <COLLATING_ELEMENT> IGNORE\n"
+
+ // the <ic> collating element will be equivalent to the letter <c>
+ "<ic> <c> <LETTER> <c>\n"
+ "UNDEFINED IGNORE IGNORE IGNORE\n"
+
+ "order_end\n"
+
+ // define a section in which all of the orders are forward orders
+ "order_start <ALL_FORWARD>;forward;forward;forward\n"
+ "<h>\n<i>\n<j>\n<k>\n"
+ "order_end\n"
+
+ // reorder the elementes in the <ALL_FORWARD> section to appear
+ // after the letter "<g>"
+ "reorder-after <g>\n"
+ "<h>\n<i>\n<j>\n<k>\n"
+
+ // try to reorder "<a>" after "<b>"
+ "reorder-after <b>\n"
+ "<a> <a> <LETTER> IGNORE\n"
+ "reorder-end\n"
+
+ "\nEND LC_COLLATE\n"
+ };
+
+ std::fputs (lc_collate_file, fout);
+
+ std::fclose (fout);
+
+ // create a temporary character map file
+
+ char lc_collate_cm_path [L_tmpnam + sizeof LC_COLLATE_CM + 2];
+ std::strcpy (lc_collate_cm_path, locale_root);
+ std::strcat (lc_collate_cm_path, SLASH);
+ std::strcat (lc_collate_cm_path, LC_COLLATE_CM);
+
+ fout = std::fopen (lc_collate_cm_path, "w");
+ pcs_write (fout, 0);
+
+ std::fclose (fout);
+
+ return rw_localedef ("-w", lc_collate_src_path,
+ lc_collate_cm_path,
+ TEST_LOCALE_NAME);
+}
+
+/**************************************************************************/
+
+
+template <class charT>
+/*static*/ void
+check_libstd_test_locale (const char* charTname)
+{
+ rw_info (0, __FILE__, __LINE__,
+ "libstd std::collate<%s>::transform () "
+ "collate test database", charTname);
+ rw_info (0, __FILE__, __LINE__,
+ "libstd std::collate<%s>::compare () collate test "
+ "database", charTname);
+ rw_info (0, __FILE__, __LINE__,
+ "libstd std::collate<%s>::hash () collate test "
+ "database", charTname);
+
+ const char* const locname = make_test_locale ();
+ if (locname) {
+
+ std::locale loc;
+
+ _TRY {
+ loc = std::locale (locname);
+ }
+ _CATCH (...) {
+ const char* const var = std::getenv (LOCALE_ROOT);
+
+ rw_assert (false, __FILE__, __LINE__,
+ "std::locale(\"%s\") unexpectedly threw "
+ "an exception; " LOCALE_ROOT "=%s",
+ locname, var ? var : "(null)");
+ return;
+ }
+
+ const std::collate<charT> &co =
+ _STD_USE_FACET (std::collate<charT>, loc);
+ co._C_opts |= co._C_use_libstd;
+ co._C_opts &= ~co._C_use_libc;
+
+#define IGNORE 0
+
+ // first lets make sure that each character was given the
+ // correct weight for each level.
+
+#undef TEST
+#define TEST(ch, w0, w1, w2, w3, w3_is_fp) \
+ test_weight_val (charTname, co, charT (ch), w0, w1, w2, w3, w3_is_fp)
+
+ TEST ('a', 6, IGNORE, 2, IGNORE, true);
+ TEST ('b', 5, IGNORE, 2, IGNORE, true);
+ TEST ('c', 7, IGNORE, 2, 7, true);
+ TEST ('d', 8, 6, 2, IGNORE, true);
+ TEST ('e', 139, IGNORE, 2, IGNORE, true);
+ TEST ('f', 30, IGNORE, 2, IGNORE, true);
+ TEST ('g', 58, IGNORE, 2, IGNORE, true);
+ TEST ('h', 12, IGNORE, 12, 12, false);
+ TEST ('i', 13, IGNORE, 13, 13, false);
+ TEST ('j', 14, IGNORE, 14, 14, false);
+ TEST ('k', 15, IGNORE, 15, 15, false);
+ TEST ('0', 16, IGNORE, 4, IGNORE, true);
+ TEST ('1', 17, IGNORE, 4, 16, true);
+ TEST ('2', 18, IGNORE, 4, IGNORE, true);
+ TEST ('3', 19, IGNORE, 4, IGNORE, true);
+ TEST ('l', IGNORE, IGNORE, IGNORE, IGNORE, true);
+
+ // make sure that strings collate the way we expect them to
+
+ // a should collate greater then b
+ test_string (charTname, co, "a", "b", 1) ;
+
+ // the collating element "er" should collate after 'a' and 'b'
+ // but before 'c'
+ test_string (charTname, co, "er", "a", 1);
+ test_string (charTname, co, "er", "b", 1);
+ test_string (charTname, co, "er", "c", -1);
+
+ // the collating element "ic" should be equivalent to the letter 'c'
+ test_string (charTname, co, "ic", "c", 0);
+
+
+ // two strings that compare identically must hash
+ // identically as well.
+ // since ic and c are equivalent elements string they should hash
+ // the same
+ test_hash (charTname, co, "c", "ic");
+ }
+ else
+ rw_assert (false, __FILE__, __LINE__,
+ "unable to create a locale database");
+}
+
+/**************************************************************************/
+
+enum { bufsiz = 256 };
+
+template <class charT>
+/*static*/ void
+test_hash (const char* charTname, const std::collate<charT>& co,
+ const char* str1, const char* str2)
+{
+ // convert narrow string to a (possibly) wide representation
+ charT wstrbuf [bufsiz];
+ charT wstrbuf2 [bufsiz];
+
+ const charT* const wstr = widen (wstrbuf, str1);
+ const charT* const wstr2 = widen (wstrbuf2, str2);
+
+ long hashNum1 = co.hash (wstr, wstr + c_strlen (wstr));
+ long hashNum2 = co.hash (wstr2, wstr2 + c_strlen (wstr2));
+
+ if (hashNum1 != hashNum2) {
+ rw_assert (false, __FILE__, __LINE__,
+ "collate<%s>::hash(%s, ...) returned %d and\n "
+ "collate<%s>::hash(%s, ...) returned %d",
+ charTname, str1,
+ hashNum1, charTname, str2, hashNum2);
+ }
+}
+
+/**************************************************************************/
+
+template <class charT>
+/*static*/ void
+test_string (const char* charTname, const std::collate<charT>& co,
+ const char* str1, const char* str2,
+ int expected_val)
+{
+ // convert narrow string to a (possibly) wide representation
+ charT wstrbuf [bufsiz];
+ charT wstrbuf2 [bufsiz];
+
+ const charT* const wstr = widen (wstrbuf, str1);
+ const charT* const wstr2 = widen (wstrbuf2, str2);
+
+ int ret = co.compare (wstr, wstr + c_strlen (wstr),
+ wstr2, wstr2 + c_strlen(wstr2));
+ if (ret != expected_val)
+ rw_assert (false, __FILE__, __LINE__,
+ "libstd std::collate<%s>::compare"
+ "(%s, ..., %s, ...) == %d, got %d",
+ charTname, str1, str2, expected_val, ret);
+}
+
+/**************************************************************************/
+
+template <class charT>
+/*static*/ void
+test_weight_val (const char* charTname, const std::collate<charT>& co,
+ charT ch, int w1a, int w1b, int w2, int w3, bool w3_is_fp)
+{
+ int w [3][2] = { { w1a, w1b }, { w2, IGNORE }, { w3, IGNORE } };
+
+ typedef std::char_traits<charT> Traits;
+ typedef std::allocator<charT> Alloc;
+ typedef std::basic_string <charT, Traits, Alloc> String;
+
+ // construct an expected transformed string out of the weight arguments
+ String expected;
+
+ if (sizeof (charT) == sizeof (char)) {
+ for (int i = 0; i < 3; ++i) {
+ for (int k = 0; k < 2; ++k) {
+ if (w [i][k] != IGNORE) {
+ while (w [i][k] > _RWSTD_CHAR_MAX) {
+ expected += charT (_RWSTD_CHAR_MAX);
+ w [i][k] -= _RWSTD_CHAR_MAX;
+ }
+ expected += charT (w [i][k]);
+ }
+ else if (i == 2 && k == 0 && w3_is_fp)
+ expected += charT (_RWSTD_CHAR_MAX);
+ }
+
+ // mark the end of the pass
+ expected += charT (1);
+ }
+ }
+ else {
+ for (int i = 0; i < 3; ++i) {
+ for (int k = 0; k < 2; ++k) {
+ if (w [i][k] != IGNORE) {
+ expected += charT (w [i][k]);
+ }
+ else if (i == 2 && k == 0 && w3_is_fp)
+ expected += charT (_RWSTD_WCHAR_MAX);
+ }
+
+ expected += charT (1);
+ }
+ }
+
+ // get the transformed string
+ const String actual = co.transform (&ch, &ch + 1);
+
+ // make sure the strings are equal
+ rw_assert (expected != actual, __FILE__, __LINE__,
+ "collate<%s>::transform (\"%c\", ...) == %{S}, "
+ "got %{S}", charTname, ch, &expected, &actual);
+}
+
+/**************************************************************************/
+
+template <class charT>
+/*static*/ void
+check_libstd (const char* charTname)
+{
+ rw_info (0, __FILE__, __LINE__,
+ "libstd std::collate<%s>::transform () sorting "
+ "file test", charTname);
+
+ rw_info (0, __FILE__, __LINE__,
+ "libstd std::collate<%s>::compare () sorting "
+ "file test", charTname);
+
+
+ // This test works by using a series of sorted input files
+ // we randomize the words in the input files and sort them using
+ // the proper locale's collate facet. This test will automatically
+ // generate the required locales.
+
+ static const char* const locales[][3] = {
+ //
+ // +-- locale name
+ // | +-- character set
+ // | | +-- input file name
+ // | | |
+ // V V V
+ { "cs_CZ", "ISO-8859-2", "collate.cs_CZ.in" }, // Czech, Czech Rep.
+ { "da_DK", "ISO-8859-1", "collate.da_DK.in" }, // Danish, Denmark
+ { "en_US", "ISO-8859-1", "collate.en_US.in" }, // English, US
+ { "hr_HR", "ISO-8859-2", "collate.hr_HR.in" }, // Hungarian, Hungary
+ { "sv_SE", "ISO-8859-1", "collate.sv_SE.in" }, // Swedish, Sweden
+ { "th_TH", "TIS-620", "collate.th_TH.in" } // Thai, Thailand
+ };
+
+ const std::size_t nlocales = sizeof locales / sizeof *locales;
+
+ typedef std::char_traits<charT> Traits;
+ typedef std::allocator<charT> Allocator;
+ typedef std::basic_string<charT, Traits, Allocator> String;
+
+ for (std::size_t i = 0; i < nlocales; ++i) {
+
+ const char* const locname =
+ rw_localedef ("-w --no_position",
+ locales [i][0], locales [i][1], 0);
+
+ if (locname) {
+
+ std::locale loc;
+
+ _TRY {
+ loc = std::locale (locname);
+ }
+ _CATCH (...) {
+ const char* const var = std::getenv (LOCALE_ROOT);
+
+ rw_assert (false, __FILE__, __LINE__,
+ "std::locale(\"%s\") unexpectedly threw "
+ "an exception; " LOCALE_ROOT "=%s",
+ locname, var ? var : "(null)");
+ continue;
+ }
+
+ const std::collate<charT> &co =
+ _STD_USE_FACET (std::collate<charT>, loc);
+
+ co._C_opts |= co._C_use_libstd;
+ co._C_opts &= ~co._C_use_libc;
+
+ typedef std::codecvt<charT, char, std::mbstate_t> CodeCvt;
+
+ const CodeCvt &cvt = _STD_USE_FACET (CodeCvt, loc);
+
+ cvt._C_opts |= cvt._C_use_libstd;
+ cvt._C_opts &= ~cvt._C_use_libc;
+
+ // 'in' holds the strings from the input file and is there
+ // sorting will take place.
+ String in [1000];
+
+ // out holds the strings located in the output file
+ String out [1000];
+
+#define TOPDIR "TOPDIR" /* the TOPDIR environment variable */
+
+ const char* in_path = std::getenv (TOPDIR);
+ if (!in_path || !*in_path) {
+ std::fprintf (stderr, "TOPDIR not defined or empty");
+
+ std::exit (1);
+ }
+
+ std::string path (in_path);
+ path += SLASH TESTS_ETC_PATH SLASH;
+ path += locales [i][2];
+
+ std::FILE* const f = std::fopen (path.c_str (), "r");
+ if (!f) {
+ rw_assert (false, __FILE__, __LINE__,
+ "file \"%s\" could not be opened", path.c_str ());
+ break;
+ }
+
+ std::size_t j = 0;
+ while (1) {
+ char next_line [bufsiz];
+
+ if (0 != std::fgets (next_line, bufsiz, f)) {
+
+ std::size_t line_len = std::strlen (next_line);
+
+ // get rid of the newline character
+ next_line [--line_len] = '\0';
+
+ // convert from external to internal encoding
+ // (both of which might be the same type)
+ charT to [bufsiz];
+ const char* from_next;
+ charT* to_next;
+
+ static std::mbstate_t initial;
+ std::mbstate_t mbs = initial;
+
+ const std::codecvt_base::result res =
+ cvt.in (mbs,
+ next_line, next_line + line_len + 1,
+ from_next,
+ to, to + sizeof to / sizeof *to,
+ to_next);
+
+ if (cvt.ok == res) {
+ in [j] = to;
+ out [j] = to;
+ }
+ else if (cvt.noconv == res) {
+ in [j] = (charT*)next_line;
+ out [j] = (charT*)next_line;
+ }
+
+ j++;
+ }
+ else
+ break;
+ }
+ // close the file
+ std::fclose (f);
+
+ // now bubble sort the items in the array
+ std::size_t idx;
+ std::size_t idx2;
+ String tmp;
+ String tmp2;
+
+ bool flipped;
+
+ if (j > 1) {
+ idx = 1;
+ do {
+ flipped = false;
+ for (idx2 = j - 1; idx2 >= idx; --idx2) {
+
+ const std::size_t idx1 = idx2 - 1;
+
+ if (co.compare (in [idx1].c_str (),
+ in [idx1].c_str () + in [idx1].size (),
+ in [idx2].c_str (),
+ in [idx2].c_str () + in [idx2].size ())
+ > 0) {
+ in [idx1].swap (in [idx2]);
+ flipped = true;
+ }
+ }
+ } while (++idx < j && flipped);
+ }
+
+ // the items are sorted now lets make sure that they are sorted
+ // the same way they are sorted in the output file.
+ std::size_t nfail = 0;
+
+ for (std::size_t k = 0; k < j; ++k) {
+
+ if (in [k] != out [k]) {
+
+ nfail++;
+
+ rw_assert (false, __FILE__, __LINE__,
+ "%{S} != %{S} at line %u of %s",
+ &out [k], &in [k],
+ k + 1, locales [i][2]);
+
+ }
+ }
+
+ rw_assert (!nfail, __FILE__, __LINE__,
+ "collate<%s>::compare() failed %d times",
+ charTname, nfail);
+ }
+ }
+}
+
+/**************************************************************************/
+
+
+template <class charT>
+/*static*/ void
+check_hash_eff (const char* charTname)
+{
+ // test effectiveness of hash function
+ rw_info (0, __FILE__, __LINE__,
+ "std::collate<%s>::hash () -- effectiveness", charTname);
+
+ // since the same hash algorithm is used for both byname and non-byname
+ // facets, simply set up a std::locale that uses the "C" locale
+ std::locale loc ("C");
+ const std::collate<charT> &co =
+ _STD_USE_FACET (std::collate<charT>, loc);
+
+
+ int nfail = 0;
+
+ charT s[100];
+ bool next = true;
+
+ // generate `N' unique strings and hash them, storing each value
+ static const std::size_t N = 100;
+ long hashed [N] = { 0 };
+
+ std::size_t k;
+ for (k = 1; k != N && next; ++k) {
+ // generate a unique string
+ gen_str (s, k);
+
+ // compute hash value
+ hashed [k] = co.hash (s, s + std::char_traits<charT>::length(s));
+ }
+
+ // sort hashed values, then remove all duplicates
+ std::sort (hashed, hashed + k);
+ k = std::unique (hashed, hashed + k) - hashed;
+
+ // assert that the probability of a collision is less than 1%
+ // according to 22.2.4.1, p3, the likelihood should be very small,
+ // approaching 1.0 / numeric_limits<unsigned long>::max()
+ if (N - k > N /100) {
+ nfail++;
+ rw_assert (false, __FILE__, __LINE__,
+ "collate<%s>::do_hash (const char_type*, "
+ "const char_type*); "
+ "probability of collision %f",
+ charTname, double (N - k) / N);
+ }
+
+ rw_assert (!nfail, __FILE__, __LINE__,
+ "collate<%s>::do_hash () failed %d times", charTname,
+ nfail);
+
+}
+
+/**************************************************************************/
+
+
+template <class charT>
+/*static*/ void
+check_NUL (const char* charTname)
+{
+ rw_info (0, __FILE__, __LINE__,
+ "std::collate<%s>::compare() with embedded NULs", charTname);
+
+ // verify that the collate facet correctly handles
+ // character sequences with embedded NULs
+
+ charT buf_1 [STR_SIZE];
+ charT buf_2 [STR_SIZE];
+
+ bool fail = false;
+
+ unsigned i = 0;
+
+ for (const char* locname = rw_locales (LC_COLLATE);
+ *locname && !fail; locname += std::strlen (locname) + 1, ++i) {
+
+ std::locale loc;
+
+ _TRY {
+ loc = std::locale (locname);
+ }
+ _CATCH (...) {
+ continue;
+ }
+
+ const std::size_t buflen = sizeof buf_1 / sizeof *buf_1 - 1;
+
+ gen_str (buf_1, sizeof buf_1 / sizeof *buf_1);
+ std::memcpy (buf_2, buf_1, sizeof buf_2);
+
+ // compute a random index into the character buffers
+ // at which to set the element to NUL; the indices
+ // are such that (inx_1 > inx_2) always holds
+ const std::size_t inx_2 = std::rand () % (buflen - 1);
+ const std::size_t inx_1 =
+ inx_2 + 1 + std::rand () % (buflen - inx_2 - 1);
+
+ buf_2 [inx_2] = charT ();
+
+ typedef std::collate<charT> CollateT;
+
+ const CollateT &col = std::use_facet<CollateT>(loc);
+
+ int cmp = col.compare (buf_1, buf_1 + buflen, buf_2, buf_2 + buflen);
+
+ if (!cmp) {
+ typedef typename CollateT::string_type StringT;
+
+ const StringT str_1 (buf_1, buflen);
+ const StringT str_2 (buf_2, buflen);
+
+ fail = true;
+
+ rw_assert (false, __FILE__, __LINE__,
+ "collate<%s>::compare(%{S}, ..., %{S}, ...) "
+ "!= 0, got 0 in locale(\"%s\")", charTname,
+ &str_1, &str_2, locname);
+ }
+
+ // set the character at the smaller index in both buffers to
+ // NUL, then set a character at the larger index in the first
+ // buffer to NUL, compare the two, and verify that the buffers
+ // compare unequal (buf_1 probably less)
+ buf_1 [inx_1] = charT ();
+ buf_1 [inx_2] = charT ();
+
+ cmp = col.compare (buf_1, buf_1 + buflen, buf_2, buf_2 + buflen);
+
+ if (!cmp) {
+ typedef typename CollateT::string_type StringT;
+
+ const StringT str_1 (buf_1, buflen);
+ const StringT str_2 (buf_2, buflen);
+
+ fail = true;
+
+ rw_assert (false, __FILE__, __LINE__,
+ "collate<%s>::compare(%{S}, ..., %{S}, ...) "
+ "!= 0, got 0 in locale(\"%s\")", charTname,
+ &str_1, &str_2, locname);
+ }
+ }
+}
+
+/**************************************************************************/
+
+template <class charT>
+/*static*/ void
+do_test (const char* charTname)
+{
+ check_libstd_test_locale<charT> (charTname);
+ check_libstd<charT> (charTname);
+ check_libc<charT> (charTname);
+ check_NUL<charT> (charTname);
+ check_hash_eff<charT> (charTname);
+}
+
+
+#if _RWSTD_PATH_SEP == '/'
+# define RM_RF "rm -rf "
+#else
+# define RM_RF "rmdir /Q /S "
+#endif // _RWSTD_PATH_SEP == '/'
+
+
+static int
+run_test (int /*argc*/, char* /*argv*/ [])
+{
+ // set any additional environment variables defined in
+ // the RW_PUTENV environment variable (if it exists)
+ rw_putenv (0);
+
+ // create a temporary directory for files created by the test
+ char namebuf [L_tmpnam];
+ locale_root = std::tmpnam (namebuf);
+
+ char envvar [sizeof LOCALE_ROOT + L_tmpnam] = LOCALE_ROOT "=";
+ std::strcat (envvar, locale_root);
+
+ rw_system ("mkdir %s", locale_root);
+
+ // set the LOCALE_ROOT variable where std::locale looks
+ // for locale database files
+ rw_putenv (envvar);
+
+ do_test<char> ("char");
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ do_test<wchar_t> ("wchar_t");
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ // remove temporary locale databases created by the test
+ rw_system (RM_RF "%s", locale_root);
+
+ return 0;
+}
+
+
+/*extern*/ int
+main (int argc, char* argv [])
+{
+ return rw_test (argc, argv, __FILE__,
+ "[lib.category.collate]",
+ "22.2.4 The collate category",
+ run_test, "", 0);
+}
+
diff --git a/tests/localization/22.locale.cons.mt.cpp b/tests/localization/22.locale.cons.mt.cpp
index 69992b1..480e2d2 100644
--- a/tests/localization/22.locale.cons.mt.cpp
+++ b/tests/localization/22.locale.cons.mt.cpp
@@ -50,6 +50,9 @@
// command line option
int opt_combine;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -85,6 +88,9 @@
for (int i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
// compute an index into the array of locales
const std::size_t linx = i % nlocales;
@@ -183,7 +189,7 @@
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
- test_ctors, 0);
+ test_ctors, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -210,10 +216,12 @@
"lib.locale.cons",
"thread safety", run_test,
"|-combine~ "
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-locales=", // must be provided
&opt_combine,
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/localization/22.locale.ctype.mt.cpp b/tests/localization/22.locale.ctype.mt.cpp
index cbe1c56..bf5b021 100644
--- a/tests/localization/22.locale.ctype.mt.cpp
+++ b/tests/localization/22.locale.ctype.mt.cpp
@@ -66,6 +66,9 @@
// of creating their own?
int opt_shared_locale;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -118,6 +121,9 @@
for (int i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
const std::size_t inx = std::size_t (i) % nlocales;
// save the name of the locale
@@ -260,7 +266,8 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -276,7 +283,8 @@
// start a pool of threads to exercise the thread safety
// of the wchar_t specialization
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -293,7 +301,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -321,11 +330,13 @@
return rw_test (argc, argv, __FILE__,
"lib.locale.ctype",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // arg must be non-negative
"|-nthreads#0-* " // arg must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // arg must be provided
"|-shared-locale# ",
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/localization/22.locale.ctype.widen.cpp b/tests/localization/22.locale.ctype.widen.cpp
new file mode 100644
index 0000000..be80f2e
--- /dev/null
+++ b/tests/localization/22.locale.ctype.widen.cpp
@@ -0,0 +1,152 @@
+/***************************************************************************
+ *
+ * 22.locale.ctype.widen.cpp - tests exercising std::ctype<charT>::widen()
+ *
+ * $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 1994-2008 Rogue Wave Software.
+ *
+ **************************************************************************/
+
+#include <locale>
+
+#include <driver.h>
+
+typedef unsigned char UChar;
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+typedef std::ctype<wchar_t> WCtype;
+
+#endif // _RWSTD_NO_WCHAR_T
+
+/**************************************************************************/
+
+static void
+test_char ()
+{
+ rw_info (0, __FILE__, __LINE__, "std::ctype<char>::widen(char)");
+
+ const std::locale loc;
+
+ const WCtype& ctp = std::use_facet<WCtype> (loc);
+
+ for (int i = 0; i != int (_RWSTD_UCHAR_MAX) + 1; ++i) {
+
+ // compute the argument, and the expected and actual results
+ const char narrow = char (i);
+ const char expect = narrow;
+ const char wide = ctp.widen (narrow);
+
+ rw_assert (expect == wide, __FILE__, __LINE__,
+ "std::ctype<char>::widen(%#c) == %#c, got %#c",
+ narrow, expect, wide);
+ }
+}
+
+/**************************************************************************/
+
+// will leave this here for now since it appears to be a placeholder
+// for further testing
+
+static void
+test_byname_char ()
+{
+ rw_info (0, __FILE__, __LINE__,
+ "std::ctype_byname<char>::widen(char)");
+
+ rw_warn (false, __FILE__, __LINE__,
+ "ctype_byname<char>::widen() not exercised");
+}
+
+/**************************************************************************/
+
+static void
+test_wchar_t ()
+{
+ rw_info (0, __FILE__, __LINE__,
+ "std::ctype<wchar_t>::widen(char)");
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+ const std::locale loc;
+
+ const WCtype& ctp = std::use_facet<WCtype> (loc);
+
+ for (int i = 0; i != int (_RWSTD_UCHAR_MAX) + 1; ++i) {
+
+ // compute the argument, and the expected and actual results
+ const char narrow = char (i);
+ const wchar_t expect = wchar_t (UChar (narrow));
+ const wchar_t wide = ctp.widen (narrow);
+
+ rw_assert (expect == wide, __FILE__, __LINE__,
+ "std::ctype<wchar_t>::widen(%#c) == %#Lc, got %#Lc",
+ narrow, expect, wide);
+ }
+
+#else // if defined (_RWSTD_NO_WCHAR_T)
+
+ rw_warn (false, __FILE__, __LINE__,
+ "ctype<wchar_t>::widen() not exercised: "
+ "macro _RWSTD_NO_WCHAR_T defined");
+
+#endif // _RWSTD_NO_WCHAR_T
+
+}
+
+/**************************************************************************/
+
+// another placeholder for further testing?
+
+static void
+test_byname_wchar_t ()
+{
+ rw_info (0, __FILE__, __LINE__,
+ "std::ctype_byname<wchar_t>::widen(char)");
+
+ rw_warn (false, __FILE__, __LINE__,
+ "ctype_byname<wchar_t>::widen() not exercised");
+}
+
+/**************************************************************************/
+
+static int
+run_test (int /*unused*/, char* /*unused*/ [])
+{
+ test_char ();
+ test_byname_char ();
+
+ test_wchar_t ();
+ test_byname_wchar_t ();
+
+ return 0;
+}
+
+/*extern*/ int
+main (int argc, char* argv [])
+{
+ return rw_test (argc, argv, __FILE__,
+ "lib.locale.ctype.widen",
+ 0, // no comment
+ run_test, "", 0);
+}
+
diff --git a/tests/localization/22.locale.globals.mt.cpp b/tests/localization/22.locale.globals.mt.cpp
index 3a06939..ebf5dad 100644
--- a/tests/localization/22.locale.globals.mt.cpp
+++ b/tests/localization/22.locale.globals.mt.cpp
@@ -73,6 +73,9 @@
// disable exceptions?
int opt_no_exceptions;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -149,6 +152,9 @@
for (int i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
// save the name of the locale
const char* const locale_name = locales [i % nlocales];
@@ -395,6 +401,10 @@
const std::locale classic (std::locale::classic ());
for (int i = 0; i != opt_nloops; ++i) {
+
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
try {
use_facet_loop (classic, i);
}
@@ -510,7 +520,7 @@
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
- test_has_facet, 0);
+ test_has_facet, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -554,7 +564,7 @@
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
- test_use_facet, 0);
+ test_use_facet, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -586,6 +596,7 @@
"thread safety", run_test,
"|-has_facet~ "
"|-use_facet~ "
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // arg must be non-negative
"|-nthreads#0-* " // arg must be in [0, MAX_THREADS]
"|-locales= " // argument must be provided
@@ -605,6 +616,7 @@
"|-time_put~ ",
&opt_has_facet,
&opt_use_facet,
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/localization/22.locale.messages.mt.cpp b/tests/localization/22.locale.messages.mt.cpp
index f5a78fe..7b6c68e 100644
--- a/tests/localization/22.locale.messages.mt.cpp
+++ b/tests/localization/22.locale.messages.mt.cpp
@@ -30,44 +30,76 @@
#include <driver.h> // for rw_test()
#include <rw_locale.h> // for rw_create_catalog()
-#include <rw_thread.h>
+#include <rw_thread.h> // for rw_thread_pool()
+#include <rw_process.h> // for rw_system()
+#include <file.h> // for SHELL_RM_F
#include <valcmp.h> // for rw_strncmp ()
#include <cstring> // for strlen()
#include <cstdio> // for remove()
// maximum number of threads allowed by the command line interface
+#define MAX_CATALOGS 32
#define MAX_THREADS 32
#define MAX_LOOPS 100000
+// deault number of catalogs
+int opt_ncatalogs = 11;
+
// default number of threads (will be adjusted to the number
// of processors/cores later)
-int rw_opt_nthreads = 1;
+int opt_nthreads = 1;
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
-int rw_opt_nloops = 100000;
+int opt_nloops = 10000;
-// locale for threads to share
-static const
-std::locale locale;
+#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
-// message catalog for threads to share
-static
-std::messages_base::catalog catalog;
+// number of locales to use
+int opt_nlocales = MAX_THREADS;
-static
-std::messages_base::catalog wcatalog;
+#else // HP-UX in LP64 mode
+
+// work around a small cache size on HP-UX in LP64 mode
+// in LP64 mode (see STDCXX-812)
+int opt_nlocales = 9;
+
+#endif // HP-UX 32/64 bit mode
+
+// should all threads share the same set of locale objects instead
+// of creating their own?
+int opt_shared_locale;
+
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
/**************************************************************************/
-#ifndef _WIN32
-# define CAT_NAME "./rwstdmessages.cat"
-# define MSG_NAME "rwstdmessages.msg"
-#else
-# define CAT_NAME "rwstdmessages.dll"
-# define MSG_NAME "rwstdmessages.rc"
-#endif
+// array of locale names to use for testing
+static const char*
+locales [MAX_THREADS];
+
+// number of locale names in the array
+static std::size_t
+nlocales;
+
+/**************************************************************************/
+
+//
+struct MyMessageData
+{
+ // name of the locale the data corresponds to
+ const char* locale_name_;
+
+ // optionally set to the named locale for threads to share
+ std::locale locale_;
+
+} my_message_data [MAX_THREADS];
+
+char my_catalog_names [64][MAX_CATALOGS];
+
+/**************************************************************************/
#define MAX_SETS 5
#define MAX_MESSAGES 5
@@ -123,38 +155,6 @@
}
};
-static std::string str_messages;
-
-/**************************************************************************/
-
-template <class T>
-void test_open_close (const std::locale& loc,
- const std::messages<T>& msgs,
- const std::string& name)
-{
- std::messages_base::catalog cat =
- (msgs.open) (name, loc);
-
- RW_ASSERT (! (cat < 0));
-
- (msgs.close) (cat);
-}
-
-template <class T>
-void test_get (const std::messages<T>& msgs,
- const std::messages_base::catalog cat,
- int set, int msgid,
- const std::basic_string<T>& dflt)
-{
- // the msg_id() thing seems like a bug to me. if anything, the user
- // should never need to write or call msg_id().
-
- const typename std::messages<T>::string_type res =
- msgs.get (cat, set, msg_id (set, msgid), dflt);
-
- RW_ASSERT (!rw_strncmp (messages [set-1][msgid-1], res.c_str ()));
-}
-
/**************************************************************************/
extern "C" {
@@ -165,50 +165,146 @@
static void*
thread_func (void*)
{
- const std::string name (CAT_NAME);
-
- const std::messages<char>& nmsgs =
- std::use_facet<std::messages<char> >(locale);
-
const std::string ndflt ("\1\2\3\4");
+ struct {
+ std::messages_base::catalog cat;
+ std::locale loc;
+ } ncatalogs [4];
+
+ const unsigned n_ncatalogs = sizeof (ncatalogs) / sizeof (*ncatalogs);
+
+ // 22.2.7.1.2 says values less than 0 returned if catalog can't
+ // be opened, so we use -1 as a sentinel.
+ for (unsigned c = 0; c < n_ncatalogs; ++c)
+ ncatalogs [c].cat = -1;
+
#ifndef _RWSTD_NO_WCHAR_T
- const std::messages<wchar_t>& wmsgs =
- std::use_facet<std::messages<wchar_t> >(locale);
const std::wstring wdflt (L"\1\2\3\4");
-#endif // _RWSTD_NO_WCHAR_T
- for (int i = 0; i != rw_opt_nloops; ++i) {
+ struct {
+ std::messages_base::catalog cat;
+ std::locale loc;
+ } wcatalogs [5];
- int set = 1 + i % MAX_SETS;
- int msgid = 1 + i % MAX_MESSAGES;
+ const unsigned n_wcatalogs = sizeof (wcatalogs) / sizeof (*wcatalogs);
+
+ for (unsigned c = 0; c < n_wcatalogs; ++c)
+ wcatalogs [c].cat = -1;
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ ///////////////////////////////////////////////////////////////////////
+
+ for (int i = 0; i < opt_nloops; ++i) {
+
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
+ const MyMessageData& data = my_message_data [i % nlocales];
+
+ // construct a named locale, get a reference to the money_get
+ // facet from it and use it to format a random money value
+ const std::locale loc =
+ opt_shared_locale ? data.locale_
+ : std::locale (data.locale_name_);
+
+ const int set = 1 + i % MAX_SETS;
+ const int msgid = 1 + i % MAX_MESSAGES;
if (test_char) {
- if (i & 1) {
- test_get<char>(nmsgs, catalog, set, msgid, ndflt);
+ // exercise the narrow char specialization of the facet
+
+ const std::messages<char> &nm =
+ std::use_facet<std::messages<char> >(loc);
+
+ const unsigned cat_idx = i % n_ncatalogs;
+ if (! (ncatalogs [cat_idx].cat < 0)) {
+ (nm.close)(ncatalogs [cat_idx].cat);
}
- else {
- test_open_close<char>(locale, nmsgs, name);
+
+ const unsigned name_idx = i % opt_ncatalogs;
+
+ const std::messages_base::catalog cat =
+ (nm.open)(my_catalog_names [name_idx], loc);
+
+ ncatalogs [cat_idx].cat = cat;
+ ncatalogs [cat_idx].loc = loc;
+
+ if (i & 1) {
+
+ // get a message from the catalog every odd iteration
+ const std::messages<char>::string_type res =
+ nm.get (cat, set, msg_id (set, msgid), ndflt);
+
}
}
- if (test_wchar) {
-
#ifndef _RWSTD_NO_WCHAR_T
- if (i & 1) {
- test_get<wchar_t>(wmsgs, wcatalog, set, msgid, wdflt);
- }
- else {
- test_open_close<wchar_t>(locale, wmsgs, name);
+ if (test_wchar) {
+ // exercise the wide char specialization of the facet
+
+ const std::messages<wchar_t> &wm =
+ std::use_facet<std::messages<wchar_t> >(loc);
+
+ const unsigned cat_idx = i % n_wcatalogs;
+ if (! (wcatalogs [cat_idx].cat < 0)) {
+ (wm.close)(wcatalogs [cat_idx].cat);
}
-#endif // _RWSTD_NO_WCHAR_T
+ const unsigned name_idx = i % opt_ncatalogs;
+ const std::messages_base::catalog cat =
+ (wm.open)(my_catalog_names [name_idx], loc);
+
+ RW_ASSERT (! (cat < 0));
+
+ wcatalogs [cat_idx].cat = cat;
+ wcatalogs [cat_idx].loc = loc;
+
+ if (! (i & 1)) {
+
+ // get a message from the catalog every even iteration
+ const std::messages<wchar_t>::string_type res =
+ wm.get (cat, set, msg_id (set, msgid), wdflt);
+
+ }
+ }
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ // close any catalogs that are still open
+
+ for (unsigned c = 0; c < n_ncatalogs; ++c) {
+ if (! (ncatalogs [c].cat < 0)) {
+
+ const std::messages<char> &nm =
+ std::use_facet<std::messages<char> >(ncatalogs[c].loc);
+
+ (nm.close)(ncatalogs [c].cat);
}
}
+#ifndef _RWSTD_NO_WCHAR_T
+
+ for (unsigned c = 0; c < n_wcatalogs; ++c) {
+ if (! (wcatalogs [c].cat < 0)) {
+
+ const std::messages<wchar_t> &wm =
+ std::use_facet<std::messages<wchar_t> >(wcatalogs[c].loc);
+
+ (wm.close)(wcatalogs [c].cat);
+ }
+ }
+
+#endif // _RWSTD_NO_WCHAR_T
+
return 0;
}
@@ -219,36 +315,96 @@
static int
run_test (int, char**)
{
- for (int i = 0; i < MAX_SETS; ++i) {
- for (int j = 0; j < MAX_MESSAGES; ++j)
- str_messages.append (messages [i][j], std::strlen (messages [i][j]) + 1);
+ std::string catalog;
- str_messages.append (1, '\0');
+ // initialize the catalog data
+ for (int i = 0; i < MAX_SETS; ++i) {
+
+ for (int j = 0; j < MAX_MESSAGES; ++j) {
+ catalog.append (messages [i][j],
+ std::strlen (messages [i][j]) + 1);
+ }
+
+ catalog.append (1, '\0');
}
- // generate a message catalog
- rw_create_catalog (MSG_NAME, str_messages.c_str ());
- const std::string name (CAT_NAME);
+ ///////////////////////////////////////////////////////////////////////
- const std::messages<char>& nmsgs =
- std::use_facet<std::messages<char> >(locale);
+ // create the catalogs and initialize array of catalog names
+ for (int i = 0; i < opt_ncatalogs; ++i) {
- catalog = (nmsgs.open) (name, locale);
+ char* msg_name = my_catalog_names [i];
-#ifndef _RWSTD_NO_WCHAR_T
-
- const std::messages<wchar_t>& wmsgs =
- std::use_facet<std::messages<wchar_t> >(locale);
-
- wcatalog = (wmsgs.open) (name, locale);
-
+#ifndef _WIN32
+ std::sprintf (msg_name, "rwstdmessages_%d.msg", i);
+#else
+ std::sprintf (msg_name, "rwstdmessages_%d.rc", i);
#endif
+ const int failed = rw_create_catalog (msg_name, catalog.c_str ());
+ rw_fatal (!failed, 0, __LINE__,
+ "failed to create message catalog from %s",
+ msg_name);
+
+#ifndef _WIN32
+ std::sprintf (msg_name, "./rwstdmessages_%d.cat", i);
+#else
+ std::sprintf (msg_name, "rwstdmessages_%d.dll", i);
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+
+ // find all installed locales for which setlocale (LC_ALL) succeeds
+ const char* const locale_list =
+ rw_opt_locales ? rw_opt_locales : rw_locales (_RWSTD_LC_ALL);
+
+ const std::size_t maxinx = RW_COUNT_OF (locales);
+
+ for (const char* name = locale_list;
+ *name;
+ name += std::strlen (name) + 1) {
+
+ const std::size_t inx = nlocales;
+ locales [inx] = name;
+
+ // fill in the money and results for this locale
+ MyMessageData& data = my_message_data [inx];
+ data.locale_name_ = name;
+
+ try {
+ const std::locale loc (data.locale_name_);
+
+ const std::messages<char>& nm =
+ std::use_facet<std::messages<char> >(loc);
+
+#ifdef _RWSTD_NO_WCHAR_T
+
+ const std::messages<wchar_t>& nm =
+ std::use_facet<std::messages<wchar_t> >(loc);
+
+#endif // _RWSTD_NO_WCHAR_T
+
+ if (opt_shared_locale)
+ data.locale_ = loc;
+
+ nlocales += 1;
+
+ }
+ catch (...) {
+ rw_warn (!rw_opt_locales, 0, __LINE__,
+ "unable to use locale(%#s)", name);
+ }
+
+ if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
+ break;
+ }
+
rw_info (0, 0, 0,
"testing std::messages<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each",
- rw_opt_nthreads, 1 != rw_opt_nthreads,
- rw_opt_nloops, 1 != rw_opt_nloops);
+ opt_nthreads, 1 != opt_nthreads,
+ opt_nloops, 1 != opt_nloops);
///////////////////////////////////////////////////////////////////////
@@ -258,12 +414,12 @@
rw_info (0, 0, 0, "exercising std::messages<char>");
int result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0,
- thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
@@ -275,12 +431,12 @@
rw_info (0, 0, 0, "exercising std::messages<wchar_t>");
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0,
- thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
///////////////////////////////////////////////////////////////////////
@@ -291,26 +447,18 @@
"std::messages<wchar_t>");
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0,
- thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
///////////////////////////////////////////////////////////////////////
- (nmsgs.close) (catalog);
-
-#ifndef _RWSTD_NO_WCHAR_T
-
- (wmsgs.close) (wcatalog);
-
-#endif // _RWSTD_NO_WCHAR_T
-
- std::remove (CAT_NAME);
+ rw_system (SHELL_RM_F "rwstdmessages_*");
return result;
}
@@ -323,18 +471,23 @@
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
- rw_opt_nthreads = rw_get_cpus ();
- if (rw_opt_nthreads < 2)
- rw_opt_nthreads = 2;
+ opt_nthreads = rw_get_cpus ();
+ if (opt_nthreads < 2)
+ opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.messages",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
+ "|-ncatalogs#0-* " // must be non-negative
"|-nthreads#0-* ", // must be in [0, MAX_THREADS]
- &rw_opt_nloops,
+ &opt_timeout,
+ &opt_nloops,
+ int (MAX_CATALOGS),
+ &opt_ncatalogs,
int (MAX_THREADS),
- &rw_opt_nthreads);
+ &opt_nthreads);
}
diff --git a/tests/localization/22.locale.money.get.mt.cpp b/tests/localization/22.locale.money.get.mt.cpp
index 624d0fa..dbf5248 100644
--- a/tests/localization/22.locale.money.get.mt.cpp
+++ b/tests/localization/22.locale.money.get.mt.cpp
@@ -67,6 +67,9 @@
// of creating their own?
int opt_shared_locale;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -176,6 +179,9 @@
for (int i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
// save the name of the locale
const MyMoneyData& data = my_money_data [i % nlocales];
@@ -183,7 +189,7 @@
// facet from it and use it to format a random money value
const std::locale loc =
opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ : std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
@@ -403,7 +409,8 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -418,7 +425,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -436,7 +444,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -464,11 +473,13 @@
return rw_test (argc, argv, __FILE__,
"lib.locale.money.get",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/localization/22.locale.money.put.mt.cpp b/tests/localization/22.locale.money.put.mt.cpp
index 190c615..1e7e926 100644
--- a/tests/localization/22.locale.money.put.mt.cpp
+++ b/tests/localization/22.locale.money.put.mt.cpp
@@ -67,6 +67,9 @@
// of creating their own?
int opt_shared_locale;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -184,6 +187,9 @@
for (int i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
// save the name of the locale
const MyMoneyData& data = my_money_data [i % nlocales];
@@ -191,7 +197,7 @@
// facet from it and use it to format a random money value
const std::locale loc =
opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ : std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
@@ -409,7 +415,8 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -424,7 +431,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -442,7 +450,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -470,11 +479,13 @@
return rw_test (argc, argv, __FILE__,
"lib.locale.money.put",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/localization/22.locale.moneypunct.mt.cpp b/tests/localization/22.locale.moneypunct.mt.cpp
index d3c54ba..6227e45 100644
--- a/tests/localization/22.locale.moneypunct.mt.cpp
+++ b/tests/localization/22.locale.moneypunct.mt.cpp
@@ -43,14 +43,17 @@
// default number of threads (will be adjusted to the number
// of processors/cores later)
-int rw_opt_nthreads = 1;
+int opt_nthreads = 1;
// the default number of times for each thread to iterate
#define DFLT_LOOPS 10000
// the number of times each thread should iterate (will be set to
// DFLT_LOOPS unless explicitly specified on the command line)
-int rw_opt_nloops = -1;
+int opt_nloops = -1;
+
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
/**************************************************************************/
@@ -240,7 +243,10 @@
static void*
thread_func (void*)
{
- for (int i = 0; i != rw_opt_nloops; ++i) {
+ for (int i = 0; i != opt_nloops; ++i) {
+
+ if (rw_thread_pool_timeout_expired ())
+ break;
thread_loop_body (std::size_t (i));
}
@@ -388,13 +394,13 @@
// unless the number of iterations was explicitly specified
// on the command line, decrease the number to equal the number
// of excericsed locales when only one thread is being tested
- if (1 == rw_opt_nthreads && rw_opt_nloops < 0)
- rw_opt_nloops = int (nlocales);
+ if (1 == opt_nthreads && opt_nloops < 0)
+ opt_nloops = int (nlocales);
// when the number of iterations wasn't explicitly specified
// on the command line set it to the default value
- if (rw_opt_nloops < 0)
- rw_opt_nloops = DFLT_LOOPS;
+ if (opt_nloops < 0)
+ opt_nloops = DFLT_LOOPS;
rw_fatal (0 < nlocales, 0, __LINE__,
"must have at least one valid locale to test");
@@ -402,8 +408,8 @@
rw_info (0, 0, 0,
"testing std::moneypunct<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
- rw_opt_nthreads, 1 != rw_opt_nthreads,
- rw_opt_nloops, 1 != rw_opt_nloops,
+ opt_nthreads, 1 != opt_nthreads,
+ opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::moneypunct<char>");
@@ -413,11 +419,12 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
@@ -429,11 +436,12 @@
// start a pool of threads to exercise the thread safety
// of the wchar_t specialization
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
@@ -447,11 +455,12 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
@@ -466,20 +475,22 @@
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
- rw_opt_nthreads = rw_get_cpus ();
- if (rw_opt_nthreads < 2)
- rw_opt_nthreads = 2;
+ opt_nthreads = rw_get_cpus ();
+ if (opt_nthreads < 2)
+ opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.moneypunct",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-locales=", // must be provided
- &rw_opt_nloops,
+ &opt_timeout,
+ &opt_nloops,
int (MAX_THREADS),
- &rw_opt_nthreads,
+ &opt_nthreads,
&rw_opt_setlocales);
}
diff --git a/tests/localization/22.locale.num.get.cpp b/tests/localization/22.locale.num.get.cpp
index fba54b4..13a0b48 100644
--- a/tests/localization/22.locale.num.get.cpp
+++ b/tests/localization/22.locale.num.get.cpp
@@ -235,6 +235,13 @@
/**************************************************************************/
+// if non-zero expected to point to a maximum valid value
+// of type T that's being tested below (used for floating
+// point ranges)
+// on function return, the pointed to value is overwritten
+// with the actual extracted value
+void *pmax = 0;
+
enum IterType { iter_pointer, iter_istreambuf, iter_input };
@@ -244,7 +251,6 @@
const char *cname, // name of character type
IterType itype, // type of input iterator
const char *iname, // name of input iterator
- void *pmax,
nativeT val, // value expected to be extracted
const char *str, // input sequence
int eat_expect = -1, // number of consumed characters
@@ -438,7 +444,6 @@
const char *cname, // name of character type
IterType itype, // iterator type
const char *iname, // name of iterator type
- void *pmax,
nativeT val, // value expected to be extracted
const char *str, // input sequence
int eat_expect = -1, // number of consumed characters
@@ -449,15 +454,15 @@
switch (ctype) {
case narrow_char:
return do_test (lineno, (char*)0, cname, itype, iname,
- pmax, val, str, eat_expect, flags, err_expect, grouping);
+ val, str, eat_expect, flags, err_expect, grouping);
case wide_char:
return do_test (lineno, (wchar_t*)0, cname, itype, iname,
- pmax, val, str, eat_expect, flags, err_expect, grouping);
+ val, str, eat_expect, flags, err_expect, grouping);
case user_char:
break;
#if 0 // disabled
return do_test (lineno, (UserChar*)0, cname, itype, iname,
- pmax, val, str, eat_expect, flags, err_expect, grouping);
+ val, str, eat_expect, flags, err_expect, grouping);
#endif // disabled
}
@@ -497,8 +502,7 @@
/*************************************************************************/
#define TEST do_test
-#define T __LINE__, ctype, cname, itype, iname, 0
-#define T_MAX __LINE__, ctype, cname, itype, iname, &val
+#define T __LINE__, ctype, cname, itype, iname
template <class numT>
@@ -2441,7 +2445,8 @@
cname, iname);
// exercise bahvior on underflow
- float val = 0;
+ static float val = 0;
+ pmax = &val;
// on underflow, get() follows C99 requirements on strtof()
// i.e., it stores a value in the range [0, +/-FLT_MIN]
@@ -2452,34 +2457,35 @@
// normalized positive number in the return type; whether
// errno acquires the value ERANGE is implementation-defined.
- TEST (T_MAX, (val = FLT_MIN, 0.0f), "1.111111e-9999", 14, 0, Eof);
+ TEST (T, (val = FLT_MIN, 0.0f), "1.111111e-9999", 14, 0, Eof);
rw_assert (!(val < 0.0), 0, __LINE__,
"correct sign after positive underflow");
- TEST (T_MAX, (val = 0.0f, -FLT_MIN), "-1.111111e-9999", 15, 0, Eof);
+ TEST (T, (val = 0.0f, -FLT_MIN), "-1.111111e-9999", 15, 0, Eof);
rw_assert (!(val > 0.0), 0, __LINE__,
"correct sign after negative underflow");
if (1.234567e-39 < FLT_MIN) {
- TEST (T_MAX, (val = FLT_MIN, 0.0f), "1.234567e-39", 12, 0, Eof);
- TEST (T_MAX, (val = 0.0f, -FLT_MIN), "-1.234567e-39", 13, 0, Eof);
+ TEST (T, (val = FLT_MIN, 0.0f), "1.234567e-39", 12, 0, Eof);
+ TEST (T, (val = 0.0f, -FLT_MIN), "-1.234567e-39", 13, 0, Eof);
}
if (1.234567e-49 < FLT_MIN) {
- TEST (T_MAX, (val = FLT_MIN, 0.0f), "1.234567e-49", 12, 0, Eof);
- TEST (T_MAX, (val = 0.0f, -FLT_MIN), "-1.234567e-49", 13, 0, Eof);
+ TEST (T, (val = FLT_MIN, 0.0f), "1.234567e-49", 12, 0, Eof);
+ TEST (T, (val = 0.0f, -FLT_MIN), "-1.234567e-49", 13, 0, Eof);
}
if (1.234567e-99 < FLT_MIN) {
- TEST (T_MAX, (val = FLT_MIN, 0.0f), "1.234567e-99", 12, 0, Eof);
- TEST (T_MAX, (val = 0.0f, -FLT_MIN), "-1.234567e-99", 13, 0, Eof);
+ TEST (T, (val = FLT_MIN, 0.0f), "1.234567e-99", 12, 0, Eof);
+ TEST (T, (val = 0.0f, -FLT_MIN), "-1.234567e-99", 13, 0, Eof);
}
// exercise facet's behavior on underflow:
// parsing succeeds (fail is clear), +/-min is stored
- TEST (T_MAX, FLT_MIN, _RWSTD_STRSTR ( _RWSTD_DBL_MIN), -1, 0, Eof);
- TEST (T_MAX, -FLT_MIN, _RWSTD_STRSTR (-_RWSTD_DBL_MIN), -1, 0, Eof);
+ TEST (T, FLT_MIN, _RWSTD_STRSTR ( _RWSTD_DBL_MIN), -1, 0, Eof);
+ TEST (T, -FLT_MIN, _RWSTD_STRSTR (-_RWSTD_DBL_MIN), -1, 0, Eof);
+ pmax = 0; // reset before next test
rw_info (0, 0, 0, "std::num_get<%s, %s>::get (..., float&) on overflow",
@@ -2610,7 +2616,8 @@
cname, iname);
// exercise bahvior on underflow
- double val = DBL_MIN;
+ static double val = DBL_MIN;
+ pmax = &val;
// on underflow, get() follows C99 requirements on strtod()
// i.e., it stores a value in the range [0, +/-DBL_MIN]
@@ -2621,24 +2628,25 @@
// normalized positive number in the return type; whether
// errno acquires the value ERANGE is implementation-defined.
- TEST (T_MAX, (val = DBL_MIN, 0.0), "1.111111e-9999", 14, 0, Eof);
- TEST (T_MAX, (val = 0.0, -DBL_MIN), "-1.111111e-9999", 15, 0, Eof);
+ TEST (T, (val = DBL_MIN, 0.0), "1.111111e-9999", 14, 0, Eof);
+ TEST (T, (val = 0.0, -DBL_MIN), "-1.111111e-9999", 15, 0, Eof);
if (1.23456789e-309L < DBL_MIN) {
- TEST (T_MAX, (val = DBL_MIN, 0.0), "1.23456789e-309", 15, 0, Eof);
- TEST (T_MAX, (val = 0.0, -DBL_MIN), "-1.23456789e-309", 16, 0, Eof);
+ TEST (T, (val = DBL_MIN, 0.0), "1.23456789e-309", 15, 0, Eof);
+ TEST (T, (val = 0.0, -DBL_MIN), "-1.23456789e-309", 16, 0, Eof);
}
if (1.234567e-409L < DBL_MIN) {
- TEST (T_MAX, (val = DBL_MIN, 0.0), "1.23456789e-409", 15, 0, Eof);
- TEST (T_MAX, (val = 0.0, -DBL_MIN), "-1.23456789e-409", 16, 0, Eof);
+ TEST (T, (val = DBL_MIN, 0.0), "1.23456789e-409", 15, 0, Eof);
+ TEST (T, (val = 0.0, -DBL_MIN), "-1.23456789e-409", 16, 0, Eof);
}
if (1.234567e-999L < DBL_MIN) {
- TEST (T_MAX, (val = DBL_MIN, 0.0), "1.23456789e-999", 15, 0, Eof);
- TEST (T_MAX, (val = 0.0, -DBL_MIN), "-1.23456789e-999", 16, 0, Eof);
+ TEST (T, (val = DBL_MIN, 0.0), "1.23456789e-999", 15, 0, Eof);
+ TEST (T, (val = 0.0, -DBL_MIN), "-1.23456789e-999", 16, 0, Eof);
}
+ pmax = 0; // reset before next test
# ifdef _RWSTD_LDBL_MAX
@@ -2731,7 +2739,8 @@
cname, iname);
// exercise bahvior on underflow
- long double val = LDBL_MIN;
+ static long double val = LDBL_MIN;
+ pmax = &val;
// on underflow, get() follows C99 requirements on strtold()
// i.e., it stores a value in the range [0, +/-LDBL__MIN]
@@ -2742,22 +2751,23 @@
// normalized positive number in the return type; whether
// errno acquires the value ERANGE is implementation-defined.
- TEST (T_MAX, (val = LDBL_MIN, 0.0L), "1.987654321e-99999", 18, 0, Eof);
- TEST (T_MAX, (val = 0.0L, -LDBL_MIN), "-1.987654321e-99999", 19, 0, Eof);
+ TEST (T, (val = LDBL_MIN, 0.0L), "1.987654321e-99999", 18, 0, Eof);
+ TEST (T, (val = 0.0L, -LDBL_MIN), "-1.987654321e-99999", 19, 0, Eof);
const char fmt[] = "%Lg";
long double ld = 0.0;
if (1 == std::sscanf ("3.456789e-4932", fmt, &ld) && ld < LDBL_MIN) {
- TEST (T_MAX, (val = LDBL_MIN, 0.0L), "3.456789e-4932", 14, 0, Eof);
- TEST (T_MAX, (val = 0.0L, -LDBL_MIN), "-3.456789e-4932", 15, 0, Eof);
+ TEST (T, (val = LDBL_MIN, 0.0L), "3.456789e-4932", 14, 0, Eof);
+ TEST (T, (val = 0.0L, -LDBL_MIN), "-3.456789e-4932", 15, 0, Eof);
}
if (1 == std::sscanf ("3.456789e-9999", fmt, &ld) && ld < LDBL_MIN) {
- TEST (T_MAX, (val = LDBL_MIN, 0.0L), "3.456789e-9999", 14, 0, Eof);
- TEST (T_MAX, (val = 0.0L, -LDBL_MIN), "-3.456789e-9999", 15, 0, Eof);
+ TEST (T, (val = LDBL_MIN, 0.0L), "3.456789e-9999", 14, 0, Eof);
+ TEST (T, (val = 0.0L, -LDBL_MIN), "-3.456789e-9999", 15, 0, Eof);
}
+ pmax = 0; // reset before next test
# ifdef _RWSTD_LDBL_MAX
diff --git a/tests/localization/22.locale.num.get.mt.cpp b/tests/localization/22.locale.num.get.mt.cpp
index 5bdd3d4..467a782 100644
--- a/tests/localization/22.locale.num.get.mt.cpp
+++ b/tests/localization/22.locale.num.get.mt.cpp
@@ -42,10 +42,10 @@
// default number of threads (will be adjusted to the number
// of processors/cores later)
-int rw_opt_nthreads = 1;
+int opt_nthreads = 1;
// the number of times each thread should iterate
-int rw_opt_nloops = MAX_LOOPS;
+int opt_nloops = MAX_LOOPS;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
@@ -62,7 +62,10 @@
// should all threads share the same set of locale objects instead
// of creating their own?
-int rw_opt_shared_locale;
+int opt_shared_locale;
+
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
/**************************************************************************/
@@ -117,11 +120,13 @@
// holds the narrow/wide character representation of value_ and
// the number of used 'charT' in each buffer.
- char ncs_ [BufferSize];
+ char ncs_ [BufferSize];
+ std::size_t nlen_; // number of valid characters in buffer
#ifndef _RWSTD_NO_WCHAR_T
- wchar_t wcs_ [BufferSize];
+ wchar_t wcs_ [BufferSize];
+ std::size_t wlen_; // number of valid characters in buffer
#endif // _RWSTD_NO_WCHAR_T
@@ -338,7 +343,10 @@
wio.rdbuf (&wsb);
#endif // _RWSTD_NO_WCHAR_T
- for (int i = 0; i != rw_opt_nloops; ++i) {
+ for (int i = 0; i != opt_nloops; ++i) {
+
+ if (rw_thread_pool_timeout_expired ())
+ break;
// fill in the value and results for this locale
const MyNumData& data = my_num_data [i % nlocales];
@@ -346,8 +354,8 @@
// construct a named locale and imbue it in the ios object
// so that the locale is used not only by the num_put facet
const std::locale loc =
- rw_opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ opt_shared_locale ? data.locale_
+ : std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
@@ -356,7 +364,7 @@
std::use_facet<std::num_get<char> >(loc);
nio.imbue (loc);
- nsb.pubsetg (data.ncs_, Traits::length (data.ncs_));
+ nsb.pubsetg (data.ncs_, data.nlen_);
test_get_data (data, ng,
std::istreambuf_iterator<char>(&nsb),
@@ -377,7 +385,7 @@
std::use_facet<std::num_get<wchar_t> >(loc);
wio.imbue (loc);
- wsb.pubsetg (data.wcs_, WTraits::length (data.wcs_));
+ wsb.pubsetg (data.wcs_, data.wlen_);
test_get_data (data, wp,
std::istreambuf_iterator<wchar_t>(&wsb),
@@ -445,6 +453,8 @@
test_put_data (data, np, std::ostreambuf_iterator<char>(&nsb),
nio, ' ', '\0');
+ data.nlen_ = std::char_traits<char>::length (data.ncs_);
+
rw_fatal (!nio.fail (), __FILE__, __LINE__,
"num_put<char>::put(...) failed for locale(%#s)",
data.locale_name_);
@@ -460,13 +470,15 @@
test_put_data (data, wp, std::ostreambuf_iterator<wchar_t>(&wsb),
wio, L' ', L'\0');
+ data.wlen_ = std::char_traits<wchar_t>::length (data.wcs_);
+
rw_fatal (!wio.fail (), __FILE__, __LINE__,
"num_put<wchar_t>::put(...) failed for locale(%#s)",
data.locale_name_);
#endif // _RWSTD_NO_WCHAR_T
- if (rw_opt_shared_locale)
+ if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
@@ -487,8 +499,8 @@
rw_info (0, 0, 0,
"testing std::num_get<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
- rw_opt_nthreads, 1 != rw_opt_nthreads,
- rw_opt_nloops, 1 != rw_opt_nloops,
+ opt_nthreads, 1 != opt_nthreads,
+ opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::num_get<char>");
@@ -498,11 +510,12 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
@@ -513,11 +526,12 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
@@ -530,11 +544,12 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
@@ -549,24 +564,26 @@
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
- rw_opt_nthreads = rw_get_cpus ();
- if (rw_opt_nthreads < 2)
- rw_opt_nthreads = 2;
+ opt_nthreads = rw_get_cpus ();
+ if (opt_nthreads < 2)
+ opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.num.get",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
- &rw_opt_nloops,
+ &opt_timeout,
+ &opt_nloops,
int (MAX_THREADS),
- &rw_opt_nthreads,
+ &opt_nthreads,
&opt_nlocales,
&rw_opt_setlocales,
- &rw_opt_shared_locale);
+ &opt_shared_locale);
}
diff --git a/tests/localization/22.locale.num.put.mt.cpp b/tests/localization/22.locale.num.put.mt.cpp
index 73c9fd1..3fe4992 100644
--- a/tests/localization/22.locale.num.put.mt.cpp
+++ b/tests/localization/22.locale.num.put.mt.cpp
@@ -64,6 +64,9 @@
// of creating their own?
int opt_shared_locale;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -238,6 +241,9 @@
for (int i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
// fill in the value and results for this locale
const MyNumData& data = my_num_data [i % nlocales];
@@ -245,7 +251,7 @@
// so that the locale is used not only by the num_put facet
const std::locale loc =
opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ : std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
@@ -394,7 +400,8 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -409,7 +416,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -426,7 +434,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -454,11 +463,13 @@
return rw_test (argc, argv, __FILE__,
"lib.locale.num.put",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/localization/22.locale.numpunct.mt.cpp b/tests/localization/22.locale.numpunct.mt.cpp
index 3be343b..cc5399c 100644
--- a/tests/localization/22.locale.numpunct.mt.cpp
+++ b/tests/localization/22.locale.numpunct.mt.cpp
@@ -47,7 +47,7 @@
// the number of times each thread should iterate (unless specified
// otherwise on the command line)
-int rw_opt_nloops = 200000;
+int opt_nloops = 200000;
#if !defined (_RWSTD_OS_HP_UX) || defined (_ILP32)
@@ -66,6 +66,9 @@
// of creating their own?
int opt_shared_locale;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -111,7 +114,10 @@
static void*
thread_func (void*)
{
- for (int i = 0; i != rw_opt_nloops; ++i) {
+ for (int i = 0; i != opt_nloops; ++i) {
+
+ if (rw_thread_pool_timeout_expired ())
+ break;
const std::size_t inx = std::size_t (i) % nlocales;
@@ -120,7 +126,7 @@
// construct a named locale
const std::locale loc =
opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ : std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
@@ -250,7 +256,7 @@
"testing std::numpunct<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
opt_nthreads, 1 != opt_nthreads,
- rw_opt_nloops, 1 != rw_opt_nloops,
+ opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::numpunct<char>");
@@ -260,7 +266,8 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -276,7 +283,8 @@
// start a pool of threads to exercise the thread safety
// of the wchar_t specialization
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -293,7 +301,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -321,12 +330,14 @@
return rw_test (argc, argv, __FILE__,
"lib.locale.numpunct",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
- &rw_opt_nloops,
+ &opt_timeout,
+ &opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
&opt_nlocales,
diff --git a/tests/localization/22.locale.statics.mt.cpp b/tests/localization/22.locale.statics.mt.cpp
index 2a4261e..e112d43 100644
--- a/tests/localization/22.locale.statics.mt.cpp
+++ b/tests/localization/22.locale.statics.mt.cpp
@@ -50,6 +50,9 @@
int opt_classic;
int opt_global;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale objects to use for testing
@@ -92,6 +95,9 @@
{
for (std::size_t i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
const std::size_t inx = i % nlocales;
const std::locale last (std::locale::global (locales [inx]));
@@ -125,7 +131,7 @@
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
- test_classic, 0);
+ test_classic, 0, std::size_t (opt_timeout));
}
if (rw_note (0 <= opt_global, 0, __LINE__,
@@ -161,7 +167,7 @@
// create and start a pool of threads and wait for them to finish
result = rw_thread_pool (0, std::size_t (opt_nthreads), 0,
- test_global, 0);
+ test_global, 0, std::size_t (opt_timeout));
}
return result;
@@ -187,11 +193,13 @@
run_test,
"|-classic~ "
"|-global~ "
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // arg must be non-negative
"|-nthreads#0-* " // arg must be in [0, MAX_THREADS]
"|-locales= ", // argument must be provided
&opt_classic,
&opt_global,
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/localization/22.locale.time.get.mt.cpp b/tests/localization/22.locale.time.get.mt.cpp
index 94e8285..72ffc24 100644
--- a/tests/localization/22.locale.time.get.mt.cpp
+++ b/tests/localization/22.locale.time.get.mt.cpp
@@ -43,17 +43,20 @@
// default number of threads (will be adjusted to the number
// of processors/cores later)
-int rw_opt_nthreads = 1;
+int opt_nthreads = 1;
// the number of times each thread should iterate
-int rw_opt_nloops = 50000;
+int opt_nloops = 50000;
// number of locales to use
-int rw_opt_nlocales = MAX_THREADS;
+int opt_nlocales = MAX_THREADS;
// should all threads share the same set of locale objects instead
// of creating their own?
-int rw_opt_shared_locale;
+int opt_shared_locale;
+
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
/**************************************************************************/
@@ -162,7 +165,10 @@
std::ios_base::iostate state = std::ios_base::goodbit;
std::tm local;
- for (int i = 0; i != rw_opt_nloops; ++i) {
+ for (int i = 0; i != opt_nloops; ++i) {
+
+ if (rw_thread_pool_timeout_expired ())
+ break;
// save the name of the locale
const MyTimeData& data = my_time_data [i % nlocales];
@@ -171,8 +177,8 @@
// facet from it and use it to format a random time value
// using a random conversion specifier
const std::locale loc =
- rw_opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ opt_shared_locale ? data.locale_
+ : std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
@@ -420,7 +426,7 @@
#endif // _RWSTD_NO_WCHAR_T
- if (rw_opt_shared_locale)
+ if (opt_shared_locale)
data.locale_ = loc;
nlocales += 1;
@@ -431,7 +437,7 @@
"failed to create locale(%#s)", name);
}
- if (nlocales == maxinx || nlocales == std::size_t (rw_opt_nlocales))
+ if (nlocales == maxinx || nlocales == std::size_t (opt_nlocales))
break;
}
@@ -442,8 +448,8 @@
rw_info (0, 0, 0,
"testing std::time_get<charT> with %d thread%{?}s%{;}, "
"%d iteration%{?}s%{;} each, in %zu locales { %{ .*A@} }",
- rw_opt_nthreads, 1 != rw_opt_nthreads,
- rw_opt_nloops, 1 != rw_opt_nloops,
+ opt_nthreads, 1 != opt_nthreads,
+ opt_nloops, 1 != opt_nloops,
nlocales, int (nlocales), "%#s", locales);
rw_info (0, 0, 0, "exercising std::time_get<char>");
@@ -453,11 +459,12 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
#ifndef _RWSTD_NO_WCHAR_T
@@ -468,11 +475,12 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
// exercise both the char and the wchar_t specializations
// at the same time
@@ -485,11 +493,12 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (rw_opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
- rw_opt_nthreads, thread_func);
+ opt_nthreads, thread_func);
#endif // _RWSTD_NO_WCHAR_T
@@ -504,24 +513,26 @@
// set nthreads to the greater of the number of processors
// and 2 (for uniprocessor systems) by default
- rw_opt_nthreads = rw_get_cpus ();
- if (rw_opt_nthreads < 2)
- rw_opt_nthreads = 2;
+ opt_nthreads = rw_get_cpus ();
+ if (opt_nthreads < 2)
+ opt_nthreads = 2;
#endif // _RWSTD_REENTRANT
return rw_test (argc, argv, __FILE__,
"lib.locale.time.get",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
- &rw_opt_nloops,
+ &opt_timeout,
+ &opt_nloops,
int (MAX_THREADS),
- &rw_opt_nthreads,
- &rw_opt_nlocales,
+ &opt_nthreads,
+ &opt_nlocales,
&rw_opt_setlocales,
- &rw_opt_shared_locale);
+ &opt_shared_locale);
}
diff --git a/tests/localization/22.locale.time.put.cpp b/tests/localization/22.locale.time.put.cpp
index 5bca51c..6268a27 100644
--- a/tests/localization/22.locale.time.put.cpp
+++ b/tests/localization/22.locale.time.put.cpp
@@ -405,10 +405,15 @@
std::ostreambuf_iterator<charT> it (&sb);
+ // convert the narrow fill character to the generic charT
+ // being careful to avoid (potential) sign extension
+ typedef unsigned char UChar;
+ const charT wfill = charT (UChar (fill));
+
if (patend - pat == 2 && '%' == pat [0]) {
// format character, no modifier
- *tp.put (it, ios, fill, tmb, char (wpat [1])) = charT ();
+ *tp.put (it, ios, wfill, tmb, char (wpat [1])) = charT ();
const bool success = 0 == rw_strncmp (buf, result);
@@ -425,7 +430,7 @@
else if (patend - pat == 3 && '%' == pat [0]) {
// format character preceded by a format modifier
- *tp.put (it, ios, fill, tmb, char (wpat [2]), char (wpat [1])) =
+ *tp.put (it, ios, wfill, tmb, char (wpat [2]), char (wpat [1])) =
charT ();
const bool success = 0 == rw_strncmp (buf, result);
@@ -442,7 +447,7 @@
sb.pubsetp (buf, buf + sizeof buf / sizeof *buf);
// format string
- *tp.put (it, ios, fill, tmb, wpat, wpat + (patend - pat)) = charT ();
+ *tp.put (it, ios, wfill, tmb, wpat, wpat + (patend - pat)) = charT ();
const bool success = 0 == rw_strncmp (buf, result);
@@ -507,6 +512,8 @@
return 0;
std::FILE *fout = std::fopen (srcfname, "w");
+ if (0 == fout)
+ return 0;
std::fprintf (fout, "LC_TIME\n");
@@ -643,6 +650,9 @@
return 0;
fout = std::fopen (cmfname, "w");
+ if (0 == fout)
+ return 0;
+
pcs_write (fout, 0);
std::fclose (fout);
diff --git a/tests/localization/22.locale.time.put.mt.cpp b/tests/localization/22.locale.time.put.mt.cpp
index 717de55..d55f744 100644
--- a/tests/localization/22.locale.time.put.mt.cpp
+++ b/tests/localization/22.locale.time.put.mt.cpp
@@ -67,6 +67,9 @@
// of creating their own?
int opt_shared_locale;
+// default timeout used by each threaded section of this test
+int opt_timeout = 60;
+
/**************************************************************************/
// array of locale names to use for testing
@@ -157,6 +160,9 @@
for (int i = 0; i != opt_nloops; ++i) {
+ if (rw_thread_pool_timeout_expired ())
+ break;
+
// save the name of the locale
const MyTimeData& data = my_time_data [i % nlocales];
@@ -165,7 +171,7 @@
// using a random conversion specifier
const std::locale loc =
opt_shared_locale ? data.locale_
- : std::locale (data.locale_name_);
+ : std::locale (data.locale_name_);
if (test_char) {
// exercise the narrow char specialization of the facet
@@ -331,7 +337,8 @@
// create and start a pool of threads and wait for them to finish
int result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -346,7 +353,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -363,7 +371,8 @@
// start a pool of threads to exercise wstring thread safety
result =
- rw_thread_pool (0, std::size_t (opt_nthreads), 0, thread_func, 0);
+ rw_thread_pool (0, std::size_t (opt_nthreads), 0,
+ thread_func, 0, std::size_t (opt_timeout));
rw_error (result == 0, 0, __LINE__,
"rw_thread_pool(0, %d, 0, %{#f}, 0) failed",
@@ -391,11 +400,13 @@
return rw_test (argc, argv, __FILE__,
"lib.locale.time.put",
"thread safety", run_test,
+ "|-soft-timeout#0 " // must be non-negative
"|-nloops#0 " // must be non-negative
"|-nthreads#0-* " // must be in [0, MAX_THREADS]
"|-nlocales#0 " // arg must be non-negative
"|-locales= " // must be provided
"|-shared-locale# ",
+ &opt_timeout,
&opt_nloops,
int (MAX_THREADS),
&opt_nthreads,
diff --git a/tests/numerics/26.valarray.cassign.cpp b/tests/numerics/26.valarray.cassign.cpp
index 4d48ad9..7693b80 100644
--- a/tests/numerics/26.valarray.cassign.cpp
+++ b/tests/numerics/26.valarray.cassign.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright (C) 2007 Rogue Wave Software, Inc.
+ * Copyright (C) 2007-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -805,15 +805,15 @@
TEST (int);
TEST (double);
-#if 0x04020000 >= _RWSTD_VER
+#if 0x04020100 >= _RWSTD_VER
- // test fails to compile with stdcxx 4.2.0 and prior due to
+ // test fails to compile with stdcxx 4.2.1 and prior due to
// STDCXX-512: http://issues.apache.org/jira/browse/STDCXX-512
rw_warn (0, 0, __LINE__,
"test of UserClass disabled in stdcxx 4.2.0 and prior "
"due to STDCXX-512");
-#else // stdcxx > 4.2.0
+#else // stdcxx >= 4.2.1
TEST (UserClass);
diff --git a/tests/regress/18.limits.stdcxx-937.cpp b/tests/regress/18.limits.stdcxx-937.cpp
new file mode 100644
index 0000000..d04c2f1
--- /dev/null
+++ b/tests/regress/18.limits.stdcxx-937.cpp
@@ -0,0 +1,135 @@
+/************************************************************************
+ *
+ * 18.limits.stdcxx-937.cpp - test case for STDCXX-937
+ *
+ * $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.
+ *
+ **************************************************************************/
+
+#include <cassert>
+#include <limits>
+
+int main()
+{
+ // work extra hard to prevent aggressive optimizers from
+ // optimizing the code away on the assumption that no
+ // object has a null address
+ const void* const fmemaddr[] = {
+ &std::numeric_limits<float>::is_specialized,
+ &std::numeric_limits<float>::digits,
+ &std::numeric_limits<float>::digits10,
+
+ &std::numeric_limits<float>::is_signed,
+ &std::numeric_limits<float>::is_integer,
+ &std::numeric_limits<float>::is_exact,
+ &std::numeric_limits<float>:: radix,
+
+ &std::numeric_limits<float>::min_exponent,
+ &std::numeric_limits<float>::min_exponent10,
+ &std::numeric_limits<float>::max_exponent,
+ &std::numeric_limits<float>::max_exponent10,
+
+ &std::numeric_limits<float>::has_infinity,
+ &std::numeric_limits<float>::has_quiet_NaN,
+ &std::numeric_limits<float>::has_signaling_NaN,
+ &std::numeric_limits<float>::has_denorm,
+ &std::numeric_limits<float>::has_denorm_loss,
+
+ &std::numeric_limits<float>::is_iec559,
+ &std::numeric_limits<float>::is_bounded,
+ &std::numeric_limits<float>::is_modulo,
+
+ &std::numeric_limits<float>::traps,
+ &std::numeric_limits<float>::tinyness_before,
+
+ &std::numeric_limits<float>::round_style
+ };
+
+ const void* const memaddr[] = {
+ &std::numeric_limits<double>::is_specialized,
+ &std::numeric_limits<double>::digits,
+ &std::numeric_limits<double>::digits10,
+
+ &std::numeric_limits<double>::is_signed,
+ &std::numeric_limits<double>::is_integer,
+ &std::numeric_limits<double>::is_exact,
+ &std::numeric_limits<double>:: radix,
+
+ &std::numeric_limits<double>::min_exponent,
+ &std::numeric_limits<double>::min_exponent10,
+ &std::numeric_limits<double>::max_exponent,
+ &std::numeric_limits<double>::max_exponent10,
+
+ &std::numeric_limits<double>::has_infinity,
+ &std::numeric_limits<double>::has_quiet_NaN,
+ &std::numeric_limits<double>::has_signaling_NaN,
+ &std::numeric_limits<double>::has_denorm,
+ &std::numeric_limits<double>::has_denorm_loss,
+
+ &std::numeric_limits<double>::is_iec559,
+ &std::numeric_limits<double>::is_bounded,
+ &std::numeric_limits<double>::is_modulo,
+
+ &std::numeric_limits<double>::traps,
+ &std::numeric_limits<double>::tinyness_before,
+
+ &std::numeric_limits<double>::round_style
+ };
+
+ const void* const ldmemaddr[] = {
+ &std::numeric_limits<long double>::is_specialized,
+ &std::numeric_limits<long double>::digits,
+ &std::numeric_limits<long double>::digits10,
+
+ &std::numeric_limits<long double>::is_signed,
+ &std::numeric_limits<long double>::is_integer,
+ &std::numeric_limits<long double>::is_exact,
+ &std::numeric_limits<long double>:: radix,
+
+ &std::numeric_limits<long double>::min_exponent,
+ &std::numeric_limits<long double>::min_exponent10,
+ &std::numeric_limits<long double>::max_exponent,
+ &std::numeric_limits<long double>::max_exponent10,
+
+ &std::numeric_limits<long double>::has_infinity,
+ &std::numeric_limits<long double>::has_quiet_NaN,
+ &std::numeric_limits<long double>::has_signaling_NaN,
+ &std::numeric_limits<long double>::has_denorm,
+ &std::numeric_limits<long double>::has_denorm_loss,
+
+ &std::numeric_limits<long double>::is_iec559,
+ &std::numeric_limits<long double>::is_bounded,
+ &std::numeric_limits<long double>::is_modulo,
+
+ &std::numeric_limits<long double>::traps,
+ &std::numeric_limits<long double>::tinyness_before,
+
+ &std::numeric_limits<long double>::round_style
+ };
+
+ for (unsigned i = 0; i != sizeof memaddr / sizeof *memaddr; ++i) {
+ assert (fmemaddr [i] != 0);
+ assert (memaddr [i] != 0);
+ assert (ldmemaddr [i] != 0);
+ }
+
+ return 0;
+}
diff --git a/tests/regress/27.ostream.inserters.stdcxx-51.cpp b/tests/regress/27.ostream.inserters.stdcxx-51.cpp
new file mode 100644
index 0000000..052b3a2
--- /dev/null
+++ b/tests/regress/27.ostream.inserters.stdcxx-51.cpp
@@ -0,0 +1,126 @@
+/**************************************************************************
+ *
+ * 27.stream.inserters.stdcxx-51.cpp - regression test for STDCXX-51
+ *
+ * http://issues.apache.org/jira/browse/STDCXX-51
+ *
+ * $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.
+ *
+ **************************************************************************/
+
+#include <cassert>
+#include <cstdio>
+#include <limits>
+#include <sstream>
+
+
+template <class FloatT>
+bool test (const char *tname)
+{
+ // zero and one used to verify sanity
+ const FloatT zero = FloatT ();
+ const FloatT pone = +FloatT (1);
+ const FloatT none = -FloatT (1);
+
+ // positive and negative Infinity
+ const FloatT pinf = +std::numeric_limits<FloatT>::infinity ();
+ const FloatT ninf = -std::numeric_limits<FloatT>::infinity ();
+
+ // positive and negative Quiet NaN
+ const FloatT pqnan = +std::numeric_limits<FloatT>::quiet_NaN ();
+ const FloatT nqnan = -std::numeric_limits<FloatT>::quiet_NaN ();
+
+ // positive and negative Signaling NaN
+ const FloatT psnan = +std::numeric_limits<FloatT>::signaling_NaN ();
+ const FloatT nsnan = -std::numeric_limits<FloatT>::signaling_NaN ();
+
+ std::ostringstream out;
+
+ out << " 0.0: " << zero << '\n'
+ << " +/-1.0: " << pone << ' ' << none << '\n'
+ << " +/-INF: " << pinf << ' ' << ninf << '\n'
+ << " +/-QNAN: " << pqnan << ' ' << nqnan << '\n'
+ << " +/-SNAN: " << psnan << ' ' << nsnan << '\n';
+
+ // expected output
+ const char expect[] = {
+ " 0.0: 0\n"
+ " +/-1.0: 1 -1\n"
+ " +/-INF: inf -inf\n"
+ " +/-QNAN: qnan -qnan\n"
+ " +/-SNAN: snan -snan\n"
+ };
+
+ bool pass = true;
+
+ if (expect != out.str ()) {
+ std::fprintf (stderr, "Expected (%s):\n%s\nGot:\n%s\n",
+ tname, expect, out.str ().c_str ());
+ pass = false;
+ }
+
+ // clear string and set the uppercase bit in flags
+ out.str ("");
+ out.setf (out.uppercase);
+
+ out << " 0.0: " << zero << '\n'
+ << " +/-1.0: " << pone << ' ' << none << '\n'
+ << " +/-INF: " << pinf << ' ' << ninf << '\n'
+ << " +/-QNAN: " << pqnan << ' ' << nqnan << '\n'
+ << " +/-SNAN: " << psnan << ' ' << nsnan << '\n';
+
+ // expected output
+ const char EXPECT[] = {
+ " 0.0: 0\n"
+ " +/-1.0: 1 -1\n"
+ " +/-INF: INF -INF\n"
+ " +/-QNAN: QNAN -QNAN\n"
+ " +/-SNAN: SNAN -SNAN\n"
+ };
+
+ if (EXPECT != out.str ()) {
+ std::fprintf (stderr, "Expected (%s):\n%s\nGot:\n%s\n",
+ tname, EXPECT, out.str ().c_str ());
+ pass = false;
+ }
+
+ return pass;
+}
+
+
+int main ()
+{
+ bool pass;
+
+ // exercise the formatting of Infinities and NaNs
+ pass = test<float>("float");
+ pass = test<double>("double") && pass;
+
+#ifndef _RWSTD_NO_LONG_DOUBLE
+
+ pass = test<long double>("long double") && pass;
+
+#endif // _RWSTD_NO_LONG_DOUBLE
+
+ assert (pass);
+
+ return 0;
+}
diff --git a/tests/self/0.locale.cpp b/tests/self/0.locale.cpp
new file mode 100644
index 0000000..5310b81
--- /dev/null
+++ b/tests/self/0.locale.cpp
@@ -0,0 +1,115 @@
+/************************************************************************
+ *
+ * 0.locale.cpp - test exercising the test driver locale helpers
+ *
+ * $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 2008 Rogue Wave Software, Inc.
+ *
+ **************************************************************************/
+
+#include <cstdio> // for remove()
+#include <cstdlib> // for getenv()
+
+#include <environ.h> // for rw_putenv()
+#include <file.h> // for rw_fwrite()
+#include <driver.h> // for rw_test(), etc.
+#include <rw_locale.h> // for rw_localedef()
+#include <rw_printf.h> // for rw_fprintf()
+
+/**************************************************************************/
+
+static int
+test_localedef ()
+{
+ // the root of the locale directory (RWSTD_LOCALE_ROOT)
+ static const char* const locale_root = rw_set_locale_root ();
+
+ static int inx;
+
+ const int id = inx++;
+
+ // create a temporary locale definition file
+ char srcfname [1024];
+ if (rw_snprintf (srcfname, sizeof srcfname, "%s%c%s.%d",
+ locale_root, _RWSTD_PATH_SEP, "locale", id) < 0)
+ return -1;
+
+ // create a temporary character map file
+ char cmfname [1024];
+ if (rw_snprintf (cmfname, sizeof cmfname, "%s%c%s.%d.src",
+ locale_root, _RWSTD_PATH_SEP, "charmap", id) < 0)
+ return -1;
+
+ rw_fwrite (srcfname, "LC_CTYPE\nEND LC_CTYPE\n");
+ rw_fwrite (cmfname, "CHARMAP\nEND CHARMAP\n");
+
+ const char opts[] = "-w";
+ char locname[40];
+ rw_snprintf (locname, sizeof locname, "%s.%d", "locale", id);
+
+ // try to create the locale
+ const char* const ret =
+ rw_localedef (opts, srcfname, cmfname, locname);
+
+ const char* const topdir = std::getenv ("TOPDIR");
+
+ rw_assert (0 != ret, 0, __LINE__,
+ "rw_localedef(%s, %#s, %#s, %#s) failed with TOPDIR=%#s",
+ opts, srcfname, cmfname, locname, topdir);
+
+ // remove temporary files
+ std::remove (cmfname);
+ std::remove (srcfname);
+
+ return 0;
+}
+
+/**************************************************************************/
+
+static int
+run_test (int, char*[])
+{
+ // exercise with the default setting of TOPDIR
+ rw_error (0 == test_localedef (), 0, __LINE__, "");
+
+ // exercise with TOPDIR set but empty
+ rw_putenv ("TOPDIR=");
+ rw_error (0 == test_localedef (), 0, __LINE__, "");
+
+ // exercise with TOPDIR unset
+ rw_putenv ("TOPDIR");
+ rw_error (0 == test_localedef (), 0, __LINE__, "");
+
+ return 0;
+}
+
+/**************************************************************************/
+
+int main (int argc, char *argv[])
+{
+ return rw_test (argc, argv, __FILE__,
+ 0 /* no section */,
+ 0 /* no comment */,
+ run_test,
+ "",
+ 0);
+}
diff --git a/tests/src/alarm.cpp b/tests/src/alarm.cpp
index f7f0c65..7df7ea5 100644
--- a/tests/src/alarm.cpp
+++ b/tests/src/alarm.cpp
@@ -44,16 +44,16 @@
// exported/imported
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
-rw_sig_dfl = (rw_signal_handler_t*)-1;
+rw_sig_dfl = (rw_signal_handler_t*)0;
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
-rw_sig_ign = (rw_signal_handler_t*)-2;
+rw_sig_ign = (rw_signal_handler_t*)1;
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
-rw_sig_hold = (rw_signal_handler_t*)-3;
+rw_sig_hold = (rw_signal_handler_t*)2;
/* extern _TEST_EXPORT */ rw_signal_handler_t* const
-rw_sig_restore = (rw_signal_handler_t*)-4;
+rw_sig_restore = (rw_signal_handler_t*)3;
// may point to a user-defined handler for the alarm
@@ -133,7 +133,7 @@
# endif
# ifndef SIG_DFL
-# define SIG_IGN (rw_signal_handler_t*)0
+# define SIG_DFL (rw_signal_handler_t*)0
# endif // SIG_DFL
# ifndef SIG_IGN
diff --git a/tests/src/cmdopt.cpp b/tests/src/cmdopt.cpp
index cbdb185..6ec1cf3 100644
--- a/tests/src/cmdopt.cpp
+++ b/tests/src/cmdopt.cpp
@@ -20,7 +20,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 2005-2006 Rogue Wave Software.
+ * Copyright 2005-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -518,6 +518,8 @@
lopt = lastopt->loptbuf_;
else {
lopt = (char*)malloc (optlen + 1);
+ if (0 == lopt)
+ return -1; // error
lastopt->lopt_ = lopt;
}
@@ -534,6 +536,8 @@
int arg_is_callback = true;
+ RW_ASSERT (0 != next);
+
if ('#' == *next) {
// examples of option specification:
// --foo# option takes an optional numeric argument
diff --git a/tests/src/locale.cpp b/tests/src/locale.cpp
index f93480c..8ec8dbd 100644
--- a/tests/src/locale.cpp
+++ b/tests/src/locale.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 2001-2007 Rogue Wave Software, Inc.
+ * Copyright 2001-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -215,8 +215,22 @@
// otherwise, try to create the locale database
+ // fallback for when TOPDIR is unset or empty
+ char topdir_path_buf [] = __FILE__;
+
// use TOPDIR to determine the root of the source tree
- const char* const topdir = getenv (TOPDIR);
+ const char* topdir = getenv (TOPDIR);
+ if (!topdir || !*topdir) {
+
+ // try to get TOPDIR from __FILE__
+ char* const slash = strrchr (topdir_path_buf, _RWSTD_PATH_SEP);
+
+ if (slash) {
+ slash [-1] = '\0';
+ topdir = topdir_path_buf;
+ }
+ }
+
if (!topdir || !*topdir) {
rw_error (0, __FILE__, __LINE__,
"the environment variable %s is %s",
@@ -1097,8 +1111,22 @@
_rw_lookup_table_t countries_map;
_rw_lookup_table_t encodings_map;
+ // fallback for when TOPDIR is unset or empty
+ char topdir_path_buf [] = __FILE__;
+
// use TOPDIR to determine the root of the source tree
- const char* const topdir = getenv (TOPDIR);
+ const char* topdir = getenv (TOPDIR);
+ if (!topdir || !*topdir) {
+
+ // try to get TOPDIR from __FILE__
+ char* const slash = strrchr (topdir_path_buf, _RWSTD_PATH_SEP);
+
+ if (slash) {
+ slash [-1] = '\0';
+ topdir = topdir_path_buf;
+ }
+ }
+
if (!topdir || !*topdir) {
rw_error (0, __FILE__, __LINE__,
"the environment variable %s is %s",
diff --git a/tests/src/opt_diags.cpp b/tests/src/opt_diags.cpp
index e6fce5f..342a622 100644
--- a/tests/src/opt_diags.cpp
+++ b/tests/src/opt_diags.cpp
@@ -22,7 +22,7 @@
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
- * Copyright 1994-2006 Rogue Wave Software.
+ * Copyright 1994-2008 Rogue Wave Software, Inc.
*
**************************************************************************/
@@ -282,6 +282,8 @@
break;
}
+ RW_ASSERT (0 != end);
+
if (':' == *end || '\0' == *end) {
parg = end + (0 != *end);
end = strpbrk (parg, ":,");
@@ -299,6 +301,8 @@
break;
}
+ RW_ASSERT (0 != end);
+
if (':' == *end || '\0' == *end) {
parg = end + ('\0' != *end);
end = strpbrk (parg, ":,");
@@ -317,6 +321,8 @@
break;
}
+ RW_ASSERT (0 != end);
+
if (':' == *end || '\0' == *end) {
parg = end + (0 != *end);
end = strpbrk (parg, ":,");
diff --git a/tests/src/printf.cpp b/tests/src/printf.cpp
index 7c23f8e..872617f 100644
--- a/tests/src/printf.cpp
+++ b/tests/src/printf.cpp
@@ -1424,13 +1424,6 @@
if (spec.fl_zero)
*pf++ = '0';
- if (spec.mod != spec.mod_ext_A && 0 <= spec.width) {
- pf += sprintf (pf, "%i", spec.width);
- }
-
- if (0 <= spec.prec)
- pf += sprintf (pf, ".%i", spec.prec);
-
if (spec.mod == spec.mod_h)
*pf++ = 'h';
else if (spec.mod == spec.mod_hh) {
@@ -1458,6 +1451,13 @@
pf += strlen (pf);
}
+ if (spec.mod != spec.mod_ext_A && 0 <= spec.width) {
+ pf += sprintf (pf, "%i", spec.width);
+ }
+
+ if (0 <= spec.prec)
+ pf += sprintf (pf, ".%i", spec.prec);
+
*pf++ = char (spec.cvtspec);
*pf = '\0';
@@ -1499,7 +1499,6 @@
buffer [len - 3] = buffer [len - 2];
buffer [len - 2] = buffer [len - 1];
buffer [len - 1] = buffer [len];
- --len;
}
}
diff --git a/tests/src/thread.cpp b/tests/src/thread.cpp
index d2864d7..562b9d7 100644
--- a/tests/src/thread.cpp
+++ b/tests/src/thread.cpp
@@ -30,6 +30,7 @@
#define _RWSTD_TEST_SRC
#include <rw_thread.h>
+#include <rw_alarm.h> // for rw_alarm()
#include <stddef.h> // for size_t
#include <string.h> // for memset()
@@ -52,16 +53,41 @@
static long maxthreads;
+/************************************************************************/
+
+static volatile int
+_rw_timeout_expired = 0;
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_thread_pool_timeout_expired ()
+{
+ return _rw_timeout_expired != 0;
+}
+
+/************************************************************************/
+
+extern "C" {
+
+static void
+_rw_timeout_handler (int)
+{
+ _rw_timeout_expired = 1;
+}
+
+} // extern "C"
+
+/************************************************************************/
+
#if defined (_RWSTD_POSIX_THREADS)
# include <pthread.h>
-extern "C" {
-
_TEST_EXPORT int
rw_thread_create (rw_thread_t *thr_id,
rw_thread_attr_t*,
- void* (*thr_proc)(void*),
+ rw_thread_proc *thr_proc,
void *thr_arg)
{
#ifdef _RWSTD_OS_SUNOS
@@ -109,19 +135,15 @@
return result;
}
-} // extern "C"
-
/**************************************************************************/
#elif defined (_RWSTD_SOLARIS_THREADS)
# include <thread.h>
-extern "C" {
-
_TEST_EXPORT int
rw_thread_create (rw_thread_t *thr_id,
rw_thread_attr_t*,
- void* (*thr_proc)(void*),
+ rw_thread_proc *thr_proc,
void *thr_arg)
{
static int concurrency_set;
@@ -170,8 +192,6 @@
return result;
}
-} // extern "C"
-
/**************************************************************************/
#elif defined (_RWSTD_DEC_THREADS)
@@ -179,13 +199,10 @@
# include <setjmp.h>
# include <cma.h>
-
-extern "C" {
-
_TEST_EXPORT int
rw_thread_create (rw_thread_t *thr_id,
rw_thread_attr_t*,
- void* (*thr_proc)(void*),
+ rw_thread_proc *thr_proc,
void *thr_arg)
{
rw_thread_t tmpid;
@@ -244,19 +261,15 @@
return status;
}
-} // extern "C"
-
/**************************************************************************/
#elif defined (_WIN32) && defined (_MT)
# include <process.h> // for _beginthreadex()
-extern "C" {
-
_TEST_EXPORT int
rw_thread_create (rw_thread_t *thr_id,
rw_thread_attr_t*,
- void* (*thr_proc)(void*),
+ rw_thread_proc *thr_proc,
void *thr_arg)
{
int result = 0;
@@ -324,8 +337,6 @@
return result;
}
-} // extern "C"
-
/**************************************************************************/
#else // unknown/missing threads environment
@@ -352,12 +363,10 @@
# endif
# endif // ENOTSUP
-extern "C" {
-
_TEST_EXPORT int
rw_thread_create (rw_thread_t*,
rw_thread_attr_t*,
- void* (*)(void*),
+ rw_thread_proc*,
void*)
{
_RWSTD_UNUSED (maxthreads);
@@ -372,8 +381,6 @@
return ENOTSUP;
}
-} // extern "C"
-
#endif // threads environment
/**************************************************************************/
@@ -471,16 +478,20 @@
/**************************************************************************/
-extern "C" {
-
-
_TEST_EXPORT int
rw_thread_pool (rw_thread_t *thr_id,
size_t nthrs,
rw_thread_attr_t*,
- void* (*thr_proc)(void*),
- void* *thr_arg)
+ rw_thread_proc *thr_proc,
+ void* *thr_arg,
+ size_t timeout)
{
+ // apply timeout if one was specified
+ if (0 != timeout) {
+ _rw_timeout_expired = 0;
+ rw_alarm (timeout, _rw_timeout_handler);
+ }
+
// small buffer for thread ids when invoked with (thr_id == 0)
rw_thread_t id_buf [16];
@@ -575,5 +586,3 @@
return 0;
}
-
-} // extern "C"
diff --git a/tests/strings/21.cwctype.cpp b/tests/strings/21.cwctype.cpp
index 0457237..6199088 100644
--- a/tests/strings/21.cwctype.cpp
+++ b/tests/strings/21.cwctype.cpp
@@ -82,7 +82,6 @@
"iswlower",
#else
"",
-#endif
#ifdef iswprint
# undef iswprint
@@ -119,6 +118,8 @@
"",
#endif
+#endif
+
#ifdef tolower
# undef tolower
"tolower",