Author: sebor Date: Mon Sep 5 13:57:44 2005 New Revision: 278837 URL: http://svn.apache.org/viewcvs?rev=278837&view=rev Log: 2005-09-05 Martin Sebor STDCXX-3 * tests/include/driver.h: New. Declarations of test suite driver functions. * tests/include/testdefs.h: New. Definitions of test suite macros. * tests/include/printf.h: New. Declarations of the rw_sprintf() family of testsuite helper functions for formatted output. * tests/include/valcmp.h: New. Declarations of the rw_valcmp() family of testsuite helper functions for comparing arrays of heterogeneous integral objects. * tests/include/cmdopt.h: New. Declarations of the rw_runopts() and rw_setopts() helper functions for the processing of command line options. * tests/src/valcmp.cpp: New. Implementation of the above. * tests/src/printf.cpp: Ditto. * tests/src/cmdopt.cpp: Ditto. * tests/src/driver.cpp: Ditto. * etc/config/GNUmakefile.tst: Partially reverted r225375 and renamed the test/ subdirectory back to tests/. * etc/config/GNUmakefile.rwt: Ditto. Added: incubator/stdcxx/trunk/tests/ incubator/stdcxx/trunk/tests/include/ incubator/stdcxx/trunk/tests/include/cmdopt.h (with props) incubator/stdcxx/trunk/tests/include/driver.h (with props) incubator/stdcxx/trunk/tests/include/printf.h (with props) incubator/stdcxx/trunk/tests/include/testdefs.h (with props) incubator/stdcxx/trunk/tests/include/valcmp.h (with props) incubator/stdcxx/trunk/tests/localization/ incubator/stdcxx/trunk/tests/localization/22.locale.money.put.cpp (with props) incubator/stdcxx/trunk/tests/src/ incubator/stdcxx/trunk/tests/src/cmdopt.cpp (with props) incubator/stdcxx/trunk/tests/src/driver.cpp (with props) incubator/stdcxx/trunk/tests/src/printf.cpp (with props) incubator/stdcxx/trunk/tests/src/valcmp.cpp (with props) Modified: incubator/stdcxx/trunk/etc/config/GNUmakefile.rwt incubator/stdcxx/trunk/etc/config/GNUmakefile.tst Modified: incubator/stdcxx/trunk/etc/config/GNUmakefile.rwt URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/etc/config/GNUmakefile.rwt?rev=278837&r1=278836&r2=278837&view=diff ============================================================================== --- incubator/stdcxx/trunk/etc/config/GNUmakefile.rwt (original) +++ incubator/stdcxx/trunk/etc/config/GNUmakefile.rwt Mon Sep 5 13:57:44 2005 @@ -18,7 +18,7 @@ # The place where the sources are looked for; # used in the variables setup in makefile.common -TESTDIR = $(TOPDIR)/test +TESTDIR = $(TOPDIR)/tests SRCDIRS = $(TESTDIR)/src TARGET = $(TESTDIR)/$(TESTLIB) Modified: incubator/stdcxx/trunk/etc/config/GNUmakefile.tst URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/etc/config/GNUmakefile.tst?rev=278837&r1=278836&r2=278837&view=diff ============================================================================== --- incubator/stdcxx/trunk/etc/config/GNUmakefile.tst (original) +++ incubator/stdcxx/trunk/etc/config/GNUmakefile.tst Mon Sep 5 13:57:44 2005 @@ -8,7 +8,7 @@ # # $ make # -# To make all tests uder $(TOPDIR)/test. Will generate a .d file +# To make all tests uder $(TOPDIR)/tests. Will generate a .d file # an place in the directory $(DEPENDDIR) for every source file. # # $ make [ tagets ] run | runall | run_all @@ -31,7 +31,7 @@ include ../makefile.in # tests & test library directories -TESTDIR = $(TOPDIR)/test +TESTDIR = $(TOPDIR)/tests SRCDIRS = $(TESTDIR) # get the test suite subdirectories Added: incubator/stdcxx/trunk/tests/include/cmdopt.h URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/include/cmdopt.h?rev=278837&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/include/cmdopt.h (added) +++ incubator/stdcxx/trunk/tests/include/cmdopt.h Mon Sep 5 13:57:44 2005 @@ -0,0 +1,44 @@ +/*************************************************************************** + * + * $Id$ + * + ************************************************************************ + * + * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave + * Software division. Licensed 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. + * + **************************************************************************/ + +#ifndef CMDOPT_H_INCLUDED +#define CMDOPT_H_INCLUDED + + +#include // for libstd config macros +#include // for test config macros + + +_TEST_EXPORT int +rw_setopts (const char*, ...); + +_TEST_EXPORT int +rw_runopts (int, char*[]); + +_TEST_EXPORT int +rw_runopts (const char*); + +_TEST_EXPORT int +rw_enabled (const char*); + +_TEST_EXPORT int +rw_enabled (int); + + +#endif // CMDOPT_H_INCLUDED Propchange: incubator/stdcxx/trunk/tests/include/cmdopt.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/include/cmdopt.h ------------------------------------------------------------------------------ svn:keywords = Id Added: incubator/stdcxx/trunk/tests/include/driver.h URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/include/driver.h?rev=278837&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/include/driver.h (added) +++ incubator/stdcxx/trunk/tests/include/driver.h Mon Sep 5 13:57:44 2005 @@ -0,0 +1,57 @@ +/************************************************************************ + * + * driver.h - testsuite driver declarations + * + * $Id$ + * + *************************************************************************** + * + * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave + * Software division. Licensed 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. + * + **************************************************************************/ + +#ifndef RW_DRIVER_H_INCLUDED +#define RW_DRIVER_H_INCLUDED + +#include // for libstd config macros +#include // for test config macros + + +_TEST_EXPORT int +rw_test (int, char*[], const char*, const char*, const char*, + int (*)(int, char**), const char*, ...); + +_TEST_EXPORT int +rw_fatal (int, const char*, int, const char*, ...); + +_TEST_EXPORT int +rw_error (int, const char*, int, const char*, ...); + +_TEST_EXPORT int +rw_assert (int, const char*, int, const char*, ...); + +_TEST_EXPORT int +rw_warn (int, const char*, int, const char*, ...); + +_TEST_EXPORT int +rw_note (int, const char*, int, const char*, ...); + +_TEST_EXPORT int +rw_info (int, const char*, int, const char*, ...); + +_TEST_EXPORT int +rw_debug (int, const char*, int, const char*, ...); + +_TEST_EXPORT int +rw_trace (int, const char*, int, const char*, ...); + +#endif // RW_DRIVER_H_INCLUDED Propchange: incubator/stdcxx/trunk/tests/include/driver.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/include/driver.h ------------------------------------------------------------------------------ svn:keywords = Id Added: incubator/stdcxx/trunk/tests/include/printf.h URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/include/printf.h?rev=278837&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/include/printf.h (added) +++ incubator/stdcxx/trunk/tests/include/printf.h Mon Sep 5 13:57:44 2005 @@ -0,0 +1,148 @@ +/************************************************************************ + * + * printf.h - declarations of the rw_printf family of functions + * + * $Id:$ + * + ************************************************************************ + * + * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave + * Software division. Licensed 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. + * + **************************************************************************/ + +#ifndef RW_PRINTF_H_INCLUDED +#define RW_PRINTF_H_INCLUDED + +#include + +struct rw_file; + +// the equivalent of stdout and stderr +extern _TEST_EXPORT rw_file* const rw_stdout; +extern _TEST_EXPORT rw_file* const rw_stderr; + + +/************************************************************************ + * Formatted file output. + ************************************************************************/ + +/** + * Prints to rw_stdout. + */ +_TEST_EXPORT int +rw_printf (const char*, ...); + +/** + * Prints to a file. + */ +_TEST_EXPORT int +rw_fprintf (rw_file*, const char*, ...); + + +/************************************************************************ + * Formatted string output. + ************************************************************************/ + +/** + * Prints to a character buffer. + */ +_TEST_EXPORT int +rw_sprintf (char*, const char*, ...); + +/** + * Prints to a character buffer of given size. + */ +_TEST_EXPORT int +rw_snprintf (char*, _RWSTD_SIZE_T, const char*, ...); + + +/************************************************************************ + * Formatted string output into a dynamically allocated buffer. + ************************************************************************/ + +/** + * Prints to a dynamically allocated character buffer. + * + * @param fmt Format specifier. + * + * @return On success, returns a pointer to the dynamically allocated + * character buffer. Otherwise, returns 0. + */ +_TEST_EXPORT char* +rw_sprintfa (const char* fmt, ...); + + +/** + * Prints to a dynamically allocated character buffer. + * + * @param buf A pointer to character buffer where the function should + * store its output. + * @param bufise The size of the character buffer in bytes. + * + * @return On success, if the size of the supplied buffer was sufficient + * to format all characters including the terminating NUL, returns + * buf. Otherwise, if the size of the supplied buffer was not + * sufficient, returns a pointer to the newly allocated character + * buffer of sufficient size. Returns 0 on failure. + */ +_TEST_EXPORT char* +rw_snprintfa (char *buf, _RWSTD_SIZE_T bufsize, const char* fmt, ...); + + +/** + * Prints to a dynamically allocated character buffer of sufficient size. + * Provided for portability with the BSD and GNU C libraries: + * + * http://www.freebsd.org/cgi/man.cgi?query=asprintf + * http://www.openbsd.org/cgi-bin/man.cgi?query=asprintf + * http://netbsd.gw.com/cgi-bin/man-cgi?asprintf++NetBSD-current + * http://www.gnu.org/software/libc/manual/html_node/Dynamic-Output.html + * + * @param pbuf Pointer to a pointer to character set by the caller to + * to address of the inital character buffer, or 0 of no such + * buffer exists. The function sets the pointer to a the address + * of the dynamically allocated character buffer, or leaves it + * unchanged if it doesn't allocate any buffer. + * @param pbufsize Pointer to a size_t set by the caller to the size of + * the inital character buffer. The function sets the value pointed + * to by this argument to the size of the dynamically allocated + * character buffer, or leaves it unchanged if it doesn't allocate + * any buffer. + * @param fmt Format specifier. + * The format specifier string has the same syntax as C99 sprintf + * (see 7.19.6.1 of ISO/IEC 9899:1999) with the following extensions: + * + * %n$ where n is a integer (see IEEE Std 1003.1) + * %m the value of strerror(errno) + * + * %{?} if clause (extracts an int) + * %{:} else clause + * %{;} end of if/else clause + * %{#s} quoted narrow character string + * %{#ls} quoted wide character string + * %{$envvar} value of an environment variable envvar + * %{f} function pointer + * %{M} member pointer + * %{#m} name of the errno constant (such as EINVAL) + * %{n} buffer size + * %{S} pointer to std::string + * %{lS} pointer to std::wstring + * %{tm} pointer to struct tm + * %{InJ} where n is one of { 8, 16, 32, 64 } and J { d, o, x, X } + * + * @return On success, returns the number of characters formatted into + * the buffer, otherwise -1. + */ +_TEST_EXPORT int +rw_asnprintf (char** pbuf, _RWSTD_SIZE_T *pbufsize, const char *fmt, ...); + +#endif // RW_PRINTF_H_INCLUDED Propchange: incubator/stdcxx/trunk/tests/include/printf.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/include/printf.h ------------------------------------------------------------------------------ svn:keywords = Id Added: incubator/stdcxx/trunk/tests/include/testdefs.h URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/include/testdefs.h?rev=278837&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/include/testdefs.h (added) +++ incubator/stdcxx/trunk/tests/include/testdefs.h Mon Sep 5 13:57:44 2005 @@ -0,0 +1,62 @@ +/************************************************************************ + * + * testdefs.h - common testsuite definitions + * + * $Id$ + * + *************************************************************************** + * + * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave + * Software division. Licensed 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. + * + **************************************************************************/ + +#ifndef RW_TESTDEFS_H_INCLUDED +#define RW_TESTDEFS_H_INCLUDED + + +#include + + +#if (defined (_WIN32) || defined (_WIN64)) \ + && (defined (RWDLL) || defined (_RWSHARED)) +# ifndef _RWSTD_TEST_SRC + // using a shared lib, import names +# define _TEST_EXPORT __declspec (dllimport) +# else + // building a shared (test) lib, export names +# define _TEST_EXPORT __declspec (dllexport) +# endif // _RWSTD_LIB_SRC +#else +# define _TEST_EXPORT +#endif // archive/shared library + + +#if defined (_RWSTD_NO_TYPENAME) && !defined (typename) +# define typename /* ignore */ +#endif // _RWSTD_NO_TYPENAME && !typename + + +#ifndef _RWSTD_NO_FOR_INIT_SCOPE +# if defined (__GNUG__) && __GNUG__ < 3 +# define _RWSTD_NO_FOR_INIT_SCOPE +# endif // gcc < 3.0 +# if defined (_MSC_VER) && _MSC_VER < 1300 +# define _RWSTD_NO_FOR_INIT_SCOPE +# endif // MSVC < 7.0 +#endif // _RWSTD_NO_FOR_INIT_SCOPE + +#ifdef _RWSTD_NO_FOR_INIT_SCOPE +# define for if (0) ; else for +#endif // _RWSTD_NO_FOR_INIT_SCOPE + + +#endif // RW_TESTDEFS_H_INCLUDED Propchange: incubator/stdcxx/trunk/tests/include/testdefs.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/include/testdefs.h ------------------------------------------------------------------------------ svn:keywords = Id Added: incubator/stdcxx/trunk/tests/include/valcmp.h URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/include/valcmp.h?rev=278837&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/include/valcmp.h (added) +++ incubator/stdcxx/trunk/tests/include/valcmp.h Mon Sep 5 13:57:44 2005 @@ -0,0 +1,82 @@ +/************************************************************************ + * + * valcmp.h - declarations of the rw_valcmp() family of helper functions + * + * $Id$ + * + ************************************************************************ + * + * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave + * Software division. Licensed 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. + * + **************************************************************************/ + +#ifndef RW_VALCMP_H_INCLUDED +#define RW_VALCMP_H_INCLUDED + +#include + + +#define CMP_NULTERM 1 /* the first 0 terminates processing */ +#define CMP_RETOFF 2 /* return offset of the first mismatch */ +#define CMP_NOCASE 4 /* case-insensitive character comparison */ + + +_TEST_EXPORT int +rw_valcmp (const void*, const void*, + _RWSTD_SIZE_T, _RWSTD_SIZE_T, _RWSTD_SIZE_T, int); + +/** + * Compares the contents of two arrays of objects of integral types, + * possibly of different sizes, for equality, in a strncmp/memcmp + * way. + * + * @param buf1 Pointer to an array of 0 or more objects of integral type. + * @param buf2 Pointer to an array of 0 or more objects of integral type. + * @param nelems The maximum number of elements to compare. + * @param flags Bitmap of flags that determine how the objects are + * compared. + * @return Returns -1, 0, or +1, depending on whether the first array + * is less than, equal to, or greater than the second array. + */ + +template +inline int +rw_valcmp (const T* buf1, + const U* buf2, + _RWSTD_SIZE_T nelems, + int flags = 0) +{ + return rw_valcmp (buf1, buf2, nelems, sizeof (T), sizeof (U), flags); +} + + +_TEST_EXPORT int +rw_strncmp (const char*, const char*, + _RWSTD_SIZE_T = _RWSTD_SIZE_MAX, int = CMP_NULTERM); + +#ifndef _RWSTD_NO_WCHAR_T + +_TEST_EXPORT int +rw_strncmp (const char*, const wchar_t*, + _RWSTD_SIZE_T = _RWSTD_SIZE_MAX, int = CMP_NULTERM); + +_TEST_EXPORT int +rw_strncmp (const wchar_t*, const char*, + _RWSTD_SIZE_T = _RWSTD_SIZE_MAX, int = CMP_NULTERM); + +_TEST_EXPORT int +rw_strncmp (const wchar_t*, const wchar_t*, + _RWSTD_SIZE_T = _RWSTD_SIZE_MAX, int = CMP_NULTERM); + +#endif // _RWSTD_NO_WCHAR_T + +#endif // RW_VALCMP_H_INCLUDED Propchange: incubator/stdcxx/trunk/tests/include/valcmp.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/include/valcmp.h ------------------------------------------------------------------------------ svn:keywords = Id Added: incubator/stdcxx/trunk/tests/localization/22.locale.money.put.cpp URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/localization/22.locale.money.put.cpp?rev=278837&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/localization/22.locale.money.put.cpp (added) +++ incubator/stdcxx/trunk/tests/localization/22.locale.money.put.cpp Mon Sep 5 13:57:44 2005 @@ -0,0 +1,854 @@ +/*************************************************************************** + * + * locale.money.put.cpp - tests exercising the std::money_put facet + * + * $Id$ + * + *************************************************************************** + * + * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave + * Software division. Licensed 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 +#include +#include // for sprintf() + +#include // for rw_enabled() +#include // for rw_test() +#include // for rw_valcmp() + +/**************************************************************************/ + +// set to non-zero value when grouping shouldn't be exercised +static int no_grouping; + +// set to non-zero value when the basic_string overloads +// of moneY-put::put() shouldn't be exercised +static int no_basic_string; + +/**************************************************************************/ + +template +struct Punct: std::moneypunct +{ + typedef typename std::moneypunct::char_type char_type; + typedef typename std::moneypunct::string_type string_type; + + static char_type decimal_point_; + static char_type thousands_sep_; + static const char *grouping_; + static const char_type *curr_symbol_; + static const char_type *positive_sign_; + static const char_type *negative_sign_; + static std::money_base::pattern pos_format_; + static std::money_base::pattern neg_format_; + static int frac_digits_; + + static int n_thousands_sep_; // number of calls to do_thousands_sep() + + Punct (): std::moneypunct(1) { } + + char_type do_decimal_point () const { + return decimal_point_; + } + + int do_frac_digits () const { + return frac_digits_; + } + + virtual string_type do_curr_symbol () const { + return curr_symbol_ ? curr_symbol_ : string_type (); + } + + virtual std::string do_grouping () const { + return grouping_; + } + + virtual char_type do_thousands_sep () const { + ++n_thousands_sep_; + return thousands_sep_; + } + + virtual string_type do_positive_sign () const { + return positive_sign_ ? positive_sign_ : string_type (); + } + + virtual string_type do_negative_sign () const { + return negative_sign_ ? negative_sign_ : string_type (); + } + + virtual std::money_base::pattern do_pos_format () const { + return pos_format_; + } + + virtual std::money_base::pattern do_neg_format () const { + return neg_format_; + } +}; + +template +const char* +Punct::grouping_ = ""; + +template +typename Punct::char_type +Punct::decimal_point_ = ':'; + +template +typename Punct::char_type +Punct::thousands_sep_ = ';'; + +template +const typename Punct::char_type* +Punct::curr_symbol_; + +template +const typename Punct::char_type* +Punct::positive_sign_; + +template +const typename Punct::char_type* +Punct::negative_sign_; + +template +std::money_base::pattern +Punct::pos_format_ = { { + std::money_base::symbol, + std::money_base::sign, + std::money_base::none, + std::money_base::value +} }; + +template +std::money_base::pattern +Punct::neg_format_ = { { + std::money_base::symbol, + std::money_base::sign, + std::money_base::none, + std::money_base::value +} }; + +template +int +Punct::n_thousands_sep_; + +template +int +Punct::frac_digits_; + +/**************************************************************************/ + +template +struct Ios: std::basic_ios +{ + Ios () { this->init (0); } +}; + +template +struct MoneyPut: std::money_put { }; + +/**************************************************************************/ + +bool test_neg_zero; + +/**************************************************************************/ + +std::money_base::pattern +set_pattern (const char *format) +{ + std::money_base::pattern pat; + + for (unsigned i = 0; i != sizeof pat.field / sizeof *pat.field; ++i) { + switch (format [i]) { + case '\0': case '@': pat.field [i] = std::money_base::none; break; + case '\1': case ' ': pat.field [i] = std::money_base::space; break; + case '\2': case '$': pat.field [i] = std::money_base::symbol; break; + case '\3': case '-': pat.field [i] = std::money_base::sign; break; + case '\4': case '1': pat.field [i] = std::money_base::value; break; + default: + _RWSTD_ASSERT (!!"bad format specifier"); + } + } + + return pat; +} + + +template +int type_test (int lineno, + charT /* unused */, + long double val /* value to format */, + const char *str /* expected result */, + char fill = ' ', + int flags = 0, + int frac_digits = 0, + int width = 0, + const char *format = 0 /* pattern or printf() format */, + const char *grouping = 0) +{ + if (!rw_enabled (lineno)) { + rw_note (0, __FILE__, __LINE__, "test on line %d disabled", lineno); + return 0; + } + + static const char* const cname = 1 < sizeof (charT) ? "wchar_t" : "char"; + + static int i = 0; // assertion number per specialization of type_test() + + if (!i) { + rw_info (0, 0, 0, "std::money_put<%s>::put(ostreambuf_iterator" + "<%s>, bool, ios_base, %s, long double)", + cname, cname, cname); + + rw_info (0, 0, 0, "std::money_put<%s>::put(ostreambuf_iterator" + "<%s>, bool, ios_base, %s, " + "const basic_string<%s>&))", + cname, cname, cname, cname); + } + + ////////////////////////////////////////////////////////////////// + // exercise put (..., long double) overload + + int nfail = 0; // number of failed assertions + + // unless 0, or unless it starts with '%', the `format' argument + // is treated as a money_base::pattern string; otherwise the + // default pattern is used + + // default format as in locale ("C") + const char *fmt_pat = !format || *format == '%' ? "\2\3\4\0" : format; + + if (!grouping) { + // default grouping as in locale ("C") + grouping = ""; + } + + const Punct pun; + + // take care to initialize Punct static data before installing + // the facet in case locale or the base facet calls the overridden + // virtuals early to cache the results + pun.grouping_ = grouping; + pun.frac_digits_ = frac_digits; + + if (val < 0.0) { + pun.neg_format_ = set_pattern (fmt_pat); + pun.pos_format_ = std::money_base::pattern (); + } + else if (val > 0.0) { + pun.neg_format_ = std::money_base::pattern (); + pun.pos_format_ = set_pattern (fmt_pat); + } + else { + // 0.0 and -0.0 + pun.neg_format_ = set_pattern (fmt_pat); + pun.pos_format_ = pun.neg_format_; + } + + // ios-derived object to pass to the facet + Ios ios; + + // money_put-derived object + const MoneyPut mp; + + // install the moneypunct facet in a locale and imbue the latter + // in the ios-derived object used by money_put + std::locale loc (ios.getloc (), (const std::moneypunct*)&pun); + ios.imbue (loc); + + // set the formatting flags and the width + ios.flags (std::ios_base::fmtflags (flags)); + ios.width (std::streamsize (width)); + + bool success; + + charT buf [256] = { 0 }; + + if (rw_enabled ("long double")) { + + // exercise 22.2.6.2.1, long double overload + *mp.put (buf, false, ios, charT (fill), val) = charT (); + + rw_assert (0 == ios.width (), __FILE__, lineno, + "money_put<%s>::put (%#p, false, const ios_base&, " + "%{#c}, %LfL) reset width from %d", + cname, buf, fill, val, width); + + success = 0 == rw_strncmp (buf, str); + + if (!success) + ++nfail; + + rw_assert (success, __FILE__, lineno, + "money_put<%s>::put (%#p, false, " + "const ios_base&, %{#c}, %LfL) == %{#s} got %{#s}; " + "flags = %{If}, grouping = %{#s}", + cname, buf, + fill, val, str, buf, + flags, grouping); + } + else { + static int msg_issued; + + rw_note (msg_issued++, __FILE__, 0, "long double test disabled"); + } + + ////////////////////////////////////////////////////////////////// + // exercise put (..., const basic_string&) overload + + if (frac_digits < 0) { + // do not perform string test(s) for negative values of frac_digits + // (extension implemented only for the long double overload of put()) + ++i; + return nfail; + } + + if (no_basic_string) { + rw_note (0, __FILE__, __LINE__, + "basic_string<%s> test on line %d disabled", lineno, cname); + return nfail; + } + + // zero out buffer + std::char_traits::assign (buf, sizeof buf / sizeof *buf, charT ()); + + // if the format string starts with a '%', + // use it to format the floating point value + if (!format || *format != '%') + format = "%.0" _RWSTD_LDBL_PRINTF_PREFIX "f"; + + char valbuf [256] = ""; + const std::size_t valbuflen = sprintf (valbuf, format, val); + + typedef std::char_traits Traits; + typedef std::allocator Allocator; + + const std::basic_string + valstr (valbuf, valbuf + valbuflen); + + // set width (reset by a previous call) + ios.width (std::streamsize (width)); + + // exercise 22.2.6.2.1, basic_string overload + *mp.put (buf, false, ios, charT (fill), valstr) = charT (); + + success = 0 == rw_strncmp (buf, str); + + if (!success) + ++nfail; + + rw_assert (success, __FILE__, lineno, + "money_put<%s>::put (%#p, false, " + "const ios_base&, %{#S}) == %{#s} got %{#s}; " + "flags = %{If}, grouping = %{#s}", + cname, fill, &valstr, buf, str, + flags, grouping); + + ++i; + + return nfail; +} + +/**************************************************************************/ + +// 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 + +#define Eofbit std::ios_base::eofbit +#define Failbit std::ios_base::failbit +#define Goodbit std::ios_base::goodbit + + +template +void ldbl_test (charT) +{ + static const charT curr_symbol1 [8] = { '$', '\0' }; + Punct::curr_symbol_ = curr_symbol1; + + Punct::decimal_point_ = ':'; + Punct::thousands_sep_ = ';'; + + static const charT signs1[][4] = { + // negative positive + { '~', '\0' }, { '\0', }, + }; + + Punct::negative_sign_ = signs1 [0]; + Punct::positive_sign_ = signs1 [1]; + + int ntried = 0; + int nfailed = 0; + +#define T __LINE__, charT () +#define TEST ++ntried, nfailed += type_test + + // enum part { none, space, symbol, sign, value }; + + // no symbol, empty sign, default format + TEST (T, 0., "0", ' '); + TEST (T, 1., "1", ' '); + TEST (T, 12., "12", ' '); + TEST (T, 123., "123", ' '); + TEST (T, 1234., "1234", ' '); + TEST (T, 12345., "12345", ' '); + TEST (T, 123456., "123456", ' '); + TEST (T, 1234567., "1234567", ' '); + TEST (T, 12345678., "12345678", ' '); + TEST (T, 123456789., "123456789", ' '); + + TEST (T, 12345678.9, "12345679", ' '); + TEST (T, 1234567.89, "1234568", ' '); + TEST (T, 123456.789, "123457", ' '); + TEST (T, 12345.6789, "12346", ' '); + TEST (T, 1234.56789, "1235", ' '); + TEST (T, 123.456789, "123", ' '); + TEST (T, 12.3456789, "12", ' '); + TEST (T, 1.23456789, "1", ' '); + TEST (T, .123456789, "0", ' '); + + // exercise correct handling of frac_digits + TEST (T, 9876543210., "987654321:0", ' ', 0, 1); + TEST (T, 876543210., "8765432:10", ' ', 0, 2); + TEST (T, 76543210., "76543:210", ' ', 0, 3); + TEST (T, 6543210., "654:3210", ' ', 0, 4); + TEST (T, 543210., "5:43210", ' ', 0, 5); + TEST (T, 43210., "0:043210", ' ', 0, 6); + TEST (T, 3210., "0:0003210", ' ', 0, 7); + TEST (T, 210., "0:00000210", ' ', 0, 8); + TEST (T, 10., "0:000000010", ' ', 0, 9); + TEST (T, 1., "0:000000001", ' ', 0, 9); + TEST (T, 0., "0:000000000", ' ', 0, 9); + TEST (T, 200., "0:000000200", ' ', 0, 9); + TEST (T, 3000., "0:000003000", ' ', 0, 9); + TEST (T, 40000., "0:000040000", ' ', 0, 9); + TEST (T, 500000., "0:000500000", ' ', 0, 9); + TEST (T, 6000000., "0:006000000", ' ', 0, 9); + TEST (T, 70000000., "0:070000000", ' ', 0, 9); + TEST (T, 800000000., "0:800000000", ' ', 0, 9); + TEST (T, -900000000., "~0:900000000", ' ', 0, 9); + TEST (T, -80000000., "~0:080000000", ' ', 0, 9); + TEST (T, -7000000., "~0:007000000", ' ', 0, 9); + TEST (T, -600000., "~0:000600000", ' ', 0, 9); + TEST (T, -50000., "~0:000050000", ' ', 0, 9); + TEST (T, -4000., "~0:000004000", ' ', 0, 9); + TEST (T, -300., "~0:000000300", ' ', 0, 9); + TEST (T, -20., "~0:000000020", ' ', 0, 9); + TEST (T, -1., "~0:000000001", ' ', 0, 9); + + if (test_neg_zero) + TEST (T, -0., "~0:000000000", ' ', 0, 9); + + // extension: fixed and negative frac_digits + TEST (T, 1.0, "1:0", ' ', Fixed, -1); + TEST (T, 2.0, "2:00", ' ', Fixed, -2); + TEST (T, 3.0, "3:000", ' ', Fixed, -3); + TEST (T, 4.1, "4:1000", ' ', Fixed, -4); + TEST (T, 52.34, "52:34000", ' ', Fixed, -5); + TEST (T, 634.56789, "634:5679", ' ', Fixed, -4); + + + // exhaustively exercise valid permutations of format patterns + // (`none' allowed in all but the first position by 22.2.6.3, p1) + TEST (T, 12, "12", '\0', 0, 0, 0, "\3\0\4\2", ""); + TEST (T, 123, "123", '\0', 0, 0, 0, "\3\0\2\4", ""); + TEST (T, 1234, "1234", '\0', 0, 0, 0, "\3\2\4\0", ""); + TEST (T, 2345, "2345", '\0', 0, 0, 0, "\3\4\2\0", ""); + TEST (T, 3456, "3456", '\0', 0, 0, 0, "\3\4\0\2", ""); + TEST (T, 4567, "4567", '\0', 0, 0, 0, "\4\0\2\3", ""); + TEST (T, 5678, "5678", '\0', 0, 0, 0, "\4\2\0\3", ""); + TEST (T, 6789, "6789", '\0', 0, 0, 0, "\4\2\3\0", ""); + TEST (T, 7890, "7890", '\0', 0, 0, 0, "\4\0\3\2", ""); + TEST (T, 8901, "8901", '\0', 0, 0, 0, "\2\4\0\3", ""); + TEST (T, 9012, "9012", '\0', 0, 0, 0, "\2\0\4\3", ""); + TEST (T, 123, "123", '\0', 0, 0, 0, "\2\0\3\4", ""); + + // format using `space' in valid positions (all but + // the first and last as specified by 22.2.6.3, p1) + // the actual space character (not the fill char) + // is required + TEST (T, 9, " 9", '*', 0, 0, 0, "\3\1\4\2", ""); + TEST (T, 98, " 98", '*', 0, 0, 0, "\3\1\2\4", ""); + TEST (T, 987, "987 ", '*', 0, 0, 0, "\3\4\1\2", ""); + TEST (T, 876, "876 ", '*', 0, 0, 0, "\4\1\2\3", ""); + TEST (T, 765, "765 ", '*', 0, 0, 0, "\4\2\1\3", ""); + TEST (T, 654, "654 ", '*', 0, 0, 0, "\4\1\3\2", ""); + TEST (T, 543, "543 ", '*', 0, 0, 0, "\2\4\1\3", ""); + TEST (T, 432, " 432", '*', 0, 0, 0, "\2\1\4\3", ""); + TEST (T, 321, " 321", '*', 0, 0, 0, "\2\1\3\4", ""); + + TEST (T, 0, "$0", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 1, "$1", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 12, "$12", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 123, "$123", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 1234, "$1234", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 12345, "$12345", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 123456, "$123456", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 1234567, "$1234567", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + TEST (T, 12345678, "$12345678", '\0', Showbase, 0, 0, "\2\3\4\0", ""); + + TEST (T, 0, "$0", '\0', Showbase, 0, 0, 0, "\2"); + TEST (T, 1, "$1", '\0', Showbase, 0, 0, 0, "\2\2"); + TEST (T, 12, "$12", '\0', Showbase, 0, 0, 0, "\2"); + TEST (T, 123, "$1;23", '\0', Showbase, 0, 0, 0, "\2\2"); + TEST (T, 1234, "$12;34", '\0', Showbase, 0, 0, 0, "\2"); + TEST (T, 12345, "$1;23;45", '\0', Showbase, 0, 0, 0, "\2\2"); + TEST (T, 123456, "$12;34;56", '\0', Showbase, 0, 0, 0, "\2"); + TEST (T, 1234567, "$1;23;45;67", '\0', Showbase, 0, 0, 0, "\2\2"); + TEST (T, 12345678, "$12;34;56;78", '\0', Showbase, 0, 0, 0, "\2"); + TEST (T, 123456789, "$1;23;45;67;89", '\0', Showbase, 0, 0, 0, "\2\2"); + + if (test_neg_zero) + TEST (T, -0.0, "$~0", '\0', Showbase, 0, 0, 0, "\3\3"); + + TEST (T, -1, "$~1", '\0', Showbase, 0, 0, 0, "\3"); + TEST (T, -12, "$~12", '\0', Showbase, 0, 0, 0, "\3\3"); + TEST (T, -123, "$~123", '\0', Showbase, 0, 0, 0, "\3"); + TEST (T, -1234, "$~1;234", '\0', Showbase, 0, 0, 0, "\3\3"); + TEST (T, -12345, "$~12;345", '\0', Showbase, 0, 0, 0, "\3"); + TEST (T, -123456, "$~123;456", '\0', Showbase, 0, 0, 0, "\3\3"); + TEST (T, -1234567, "$~1;234;567", '\0', Showbase, 0, 0, 0, "\3"); + TEST (T, -12345678, "$~12;345;678", '\0', Showbase, 0, 0, 0, "\3\3"); + TEST (T, -123456789, "$~123;456;789", '\0', Showbase, 0, 0, 0, "\3"); + + // for convenience + const char *f = "\3\2\4\0"; // { sign, symbol, value, none } + + TEST (T, -321, "~$32;1", '\0', Showbase, 0, 0, f, "\1\2"); + TEST (T, -4322, "~$432;2", '\0', Showbase, 0, 0, f, "\1\3"); + TEST (T, -54323, "~$5;4;3;2;3", '\0', Showbase, 0, 0, f, "\1\1"); + TEST (T, -654324, "~$6;5;4;3;2;4", '\0', Showbase, 0, 0, f, "\1\1"); + TEST (T, -7654325, "~$765;432;5", '\0', Showbase, 0, 0, f, "\1\3"); + TEST (T, -87654326, "~$8;7;6;5;4;3;26", '\0', Showbase, 0, 0, f, "\2\1"); + TEST (T, -987654327, "~$98;76;54;32;7", '\0', Showbase, 0, 0, f, "\1\2"); + + static const charT curr_symbol2 [8] = { 'X', 'Y', '\0' }; + Punct::curr_symbol_ = curr_symbol2; + + static const charT signs2[][8] = { + // negative positive + { '(', ')', '\0' }, { '{', '}', '\0' } + }; + + Punct::negative_sign_ = signs2 [0]; + Punct::positive_sign_ = signs2 [1]; + Punct::thousands_sep_ = '.'; + Punct::decimal_point_ = '.'; + + f = "\3\4\1\2"; // { sign, value, space, symbol } + + TEST (T, -1357911, "(1.3.5.7.9.1.1 XY)", '*', Showbase, 0, 0, f, "\1"); + TEST (T, -2468012, "(2.46.80.12 XY)", '-', Showbase, 0, 0, f, "\2"); + TEST (T, -3692513, "(3.692.513 XY)", ' ', Showbase, 0, 0, f, "\3"); + TEST (T, -9999914, "(999.9914 XY)", '@', Showbase, 0, 0, f, "\4"); + TEST (T, -1000015, "(10.00015 XY)", '#', Showbase, 0, 0, f, "\5"); + TEST (T, -16, "(16 XY)", ')', Showbase, 0, 0, f, "\6"); + + TEST (T, +1357917, "{1.3.5.7.9.1.7 XY}", ',', Showbase, 0, 0, f, "\1"); + TEST (T, +2468018, "{2.46.80.18 XY}", '+', Showbase, 0, 0, f, "\2"); + TEST (T, +3692519, "{3.692.519 XY}", '0', Showbase, 0, 0, f, "\3"); + TEST (T, +9999920, "{999.9920 XY}", '1', Showbase, 0, 0, f, "\4"); + TEST (T, +1000021, "{10.00021 XY}", '\0', Showbase, 0, 0, f, "\5"); + TEST (T, +22, "{22 XY}", '{', Showbase, 0, 0, f, "\6"); + TEST (T, +123, "{123 }", '_', 0, 0, 0, f, "\6"); + TEST (T, -224, "(224 )", '_', 0, 0, 0, f, "\7"); + + TEST (T, +325, "{ XY325}", ' ', Showbase, 0, 0, "\3\1\2\4", "\xa"); + TEST (T, -426, "( XY426)", ' ', Showbase, 0, 0, "\3\1\2\4", "\xb"); + TEST (T, +527, "{XY 527}", ' ', Showbase, 0, 0, "\3\2\1\4", "\xc"); + TEST (T, -628, "(XY 628)", ' ', Showbase, 0, 0, "\3\2\1\4", "\xd"); + TEST (T, +729, "{XY729}", ' ', Showbase, 0, 0, "\3\2\0\4", "\xe"); + TEST (T, -830, "(XY830)", ' ', Showbase, 0, 0, "\3\2\0\4", "\xf"); + TEST (T, +931, "{XY931}", ' ', Showbase, 0, 0, "\3\0\2\4", "\x10"); + TEST (T, -1032, "(XY1032)", ' ', Showbase, 0, 0, "\3\0\2\4"); + TEST (T, +1133, "1133{XY}", ' ', Showbase, 0, 0, "\4\3\2\0"); + TEST (T, -1234, "1234XY()", ' ', Showbase, 0, 0, "\4\2\3\0"); + TEST (T, +1335, "1335XY{}", ' ', Showbase, 0, 0, "\4\2\0\3"); + TEST (T, -1436, "1436XY ()", ' ', Showbase, 0, 0, "\4\2\1\3"); + TEST (T, +1537, "1537XY{}", ' ', Showbase, 0, 0, "\4\0\2\3"); + TEST (T, -1638, "1638 XY()", ' ', Showbase, 0, 0, "\4\1\2\3"); + TEST (T, +1739, "XY1739{}", ' ', Showbase, 0, 0, "\2\4\0\3"); + TEST (T, -1840, "XY1840 ()", ' ', Showbase, 0, 0, "\2\4\1\3"); + TEST (T, +1941, "XY1941{}", ' ', Showbase, 0, 0, "\2\0\4\3"); + TEST (T, -2042, "XY 2042()", ' ', Showbase, 0, 0, "\2\1\4\3"); + TEST (T, +2143, "XY{2143}", ' ', Showbase, 0, 0, "\2\3\4\0"); + TEST (T, -2244, "XY(2244)", ' ', Showbase, 0, 0, "\2\3\0\4"); + TEST (T, +2345, "XY{ 2345}", ' ', Showbase, 0, 0, "\2\3\1\4"); + + // 22.2.6.2, p2: + // ...copies of `fill' are inserted as necessary to pad to the + // specified width. For the value `af' equal to (str.flags() + // & str.adjustfield), if (af == str.internal) is true, the fill + // characters are placed where `none' or `space' appears in the + // formatting pattern; otherwise if (af == str.left) is true, they + // are placed after the other characters; otherwise, they are + // placed before the other characters. + + TEST (T, -2446, "___XY( 2446)", '_', Showbase, 0, 12, "\2\3\1\4"); + TEST (T, +2547, "____XY{2547}", '_', Showbase, 0, 12, "\2\3\0\4"); + + TEST (T, -2648, "___XY( 2648)", '_', Showbase | Right, 0, 12, "\2\3\1\4"); + TEST (T, +2749, "____XY{2749}", '_', Showbase | Right, 0, 12, "\2\3\0\4"); + + TEST (T, -2850, "XY( 2850)___", '_', Showbase | Left, 0, 12, "\2\3\1\4"); + TEST (T, +2951, "XY{2951}____", '_', Showbase | Left, 0, 12, "\2\3\0\4"); + + TEST (T, -3052, "___XY( 3052)", '_', + Showbase | Left | Right, 0, 12, "\2\3\1\4"); + + TEST (T, +3153, "____XY{3153}", '_', + Showbase | Left | Right, 0, 12, "\2\3\0\4"); + + TEST (T, -3254, "___XY( 3254)", '_', + Showbase | Left | Right | Internal, 0, 12, "\2\3\1\4"); + + TEST (T, +3355, "____XY{3355}", '_', + Showbase | Left | Right | Internal, 0, 12, "\2\3\0\4"); + + TEST (T, -3456, "XY( ___3456)", '_', + Showbase | Internal, 0, 12, "\2\3\1\4"); + + TEST (T, +3557, "XY{____3557}", '_', + Showbase | Internal, 0, 12, "\2\3\0\4"); + + TEST (T, -3658, "XY____(3658)", '_', + Showbase | Internal, 0, 12, "\2\0\3\4"); + + TEST (T, +3759, "XY{3759____}", '_', + Showbase | Internal, 0, 12, "\2\3\4\0"); + + TEST (T, 3759, "XY{37.59}", '_', + Showbase | Internal, 0, 8, "\2\3\4\0", "\2"); + + TEST (T, 3760, "XY{ 37.60}", '_', + Showbase | Internal, 0, 8, "\2\3\1\4", "\2"); + + TEST (T, 12345678900000000000.0, "XY{ ........1.23.45678.9000.00.000.0.00}", + '.', Showbase | Internal, 0, 40, "\2\3\1\4", "\2\1\3\2\4\5\2"); + + TEST (T, 1234567890000000000.0, "{ ...........1234.56789.0000.000.00.0XY}", + '.', Showbase | Internal, 0, 40, "\3\1\4\2", "\1\2\3\4\5\6"); + + // exercise justification with non-zero frac_digits + TEST (T, 1, "_____{0.1}", '_', 0, 1, 10, "-@1$"); + TEST (T, 12, "_____{1.2}", '_', 0, 1, 10, "-@1$"); + TEST (T, 123, "____{1.23}", '_', 0, 2, 10, "-@1$"); + TEST (T, 1234, "_{12.34XY}", '_', Showbase, 2, 10, "-@1$"); + TEST (T, 1235, "_{ 12.35XY}", '_', Showbase, 2, 11, "- 1$"); + + TEST (T, 2, "******{0.2}", '*', Right, 1, 11, "-@1$"); + TEST (T, 23, "******{2.3}", '*', Right, 1, 11, "-@1$"); + TEST (T, 234, "*****{2.34}", '*', Right, 2, 11, "-@1$"); + TEST (T, 2345, "**{23.45XY}", '*', Right | Showbase, 2, 11, "-@1$"); + TEST (T, 2346, "**{ 23.46XY}", '*', Right | Showbase, 2, 12, "- 1$"); + + TEST (T, 3, "{0.3}#######", '#', Left, 1, 12, "-@1$"); + TEST (T, 34, "{3.4}#######", '#', Left, 1, 12, "-@1$"); + TEST (T, 345, "{3.45}######", '#', Left, 2, 12, "-@1$"); + TEST (T, 3456, "{34.56XY}###", '#', Left | Showbase, 2, 12, "-@1$"); + TEST (T, 3457, "{ 34.57XY}###", '#', Left | Showbase, 2, 13, "- 1$"); + + TEST (T, 4, "{=====0.4}", '=', Internal, 1, 10, "-@1$"); + TEST (T, 45, "{=====4.5}", '=', Internal, 1, 10, "-@1$"); + TEST (T, 456, "{====4.56}", '=', Internal, 2, 10, "-@1$"); + TEST (T, 4567, "{=45.67XY}", '=', Internal | Showbase, 2, 10, "-@1$"); + TEST (T, 4568, "{ =45.68XY}", '=', Internal | Showbase, 2, 11, "- 1$"); + + Punct::thousands_sep_ = ','; + Punct::decimal_point_ = '.'; + + // justification with grouping + TEST (T, 105, "====={1,0.5}", '=', 0, 1, 12, "-@1$", "\1"); + TEST (T, 1056, "===={1,05.6}", '=', 0, 1, 12, "-@1$", "\2"); + TEST (T, 10567, "==={1,05.67}", '=', 0, 2, 12, "-@1$", "\2"); + TEST (T, 105678, "=={10,56.78XY}", '=', Showbase, 2, 14, "-@1$", "\2"); + TEST (T, 105679, "={ 10,56.79XY}", '=', Showbase, 2, 14, "- 1$", "\2"); + TEST (T, 105680, "={ 1,056,80XY}", '=', Showbase, 0, 14, "- 1$", "\2\3"); + + int flags = Right | Showbase; + TEST (T, 106, ">>>>>{1,0.6}", '>', Right, 1, 12, "-@1$", "\1"); + TEST (T, 1057, ">>>>{1,05.7}", '>', Right, 1, 12, "-@1$", "\2"); + TEST (T, 10568, ">>>{1,05.68}", '>', Right, 2, 12, "-@1$", "\2"); + TEST (T, 105679, ">>{10,56.79XY}", '>', flags, 2, 14, "-@1$", "\2"); + TEST (T, 105680, ">{ 10,56.80XY}", '>', flags, 2, 14, "- 1$", "\2"); + TEST (T, 105681, ">{ 1,056,81XY}", '>', flags, 0, 14, "- 1$", "\2\3"); + + flags = Left | Showbase; + TEST (T, 107, "{1,0.7}<<<<<", '<', Left, 1, 12, "-@1$", "\1"); + TEST (T, 1058, "{1,05.8}<<<<", '<', Left, 1, 12, "-@1$", "\2"); + TEST (T, 10569, "{1,05.69}<<<", '<', Left, 2, 12, "-@1$", "\2"); + TEST (T, 105680, "{10,56.80XY}<<", '<', flags, 2, 14, "-@1$", "\2"); + TEST (T, 105681, "{ 10,56.81XY}<", '<', flags, 2, 14, "- 1$", "\2"); + TEST (T, 105682, "{ 1,056,82XY}<", '<', flags, 0, 14, "- 1$", "\2\3"); + + flags = Internal | Showbase; + TEST (T, 108, "{^^^^^1,0.8}", '^', Internal, 1, 12, "-@1$", "\1"); + TEST (T, 1059, "{^^^^1,05.9}", '^', Internal, 1, 12, "-@1$", "\2"); + TEST (T, 10570, "{^^^1,05.70}", '^', Internal, 2, 12, "-@1$", "\2"); + TEST (T, 105681, "{^^10,56.81XY}", '^', flags, 2, 14, "-@1$", "\2"); + TEST (T, 105682, "{ ^10,56.82XY}", '^', flags, 2, 14, "- 1$", "\2"); + TEST (T, 105683, "{ ^1,056,83XY}", '^', flags, 0, 14, "- 1$", "\2\3"); + + flags = Left | Right | Showbase; + TEST (T, 109, "#####{1,0.9}", '#', Left | Right, 1, 12, "-@1$", "\1"); + TEST (T, 1060, "####{1,06.0}", '#', Left | Right, 1, 12, "-@1$", "\2"); + TEST (T, 10571, "###{1,05.71}", '#', Left | Right, 2, 12, "-@1$", "\2"); + TEST (T, 105682, "##{10,56.82XY}", '#', flags, 2, 14, "-@1$", "\2"); + TEST (T, 105683, "#{ 10,56.83XY}", '#', flags, 2, 14, "- 1$", "\2"); + TEST (T, 105684, "#{ 10,56,84XY}", '#', flags, 0, 14, "- 1$", "\2"); + + + // verify that mon_put (..., const basic_string&) ignores the part + // of the string starting with the first non-numeric character +#undef FMT +#define FMT(fmt) "%.0" _RWSTD_LDBL_PRINTF_PREFIX "f" fmt + + // using default format "\2\3\4\0": {symbol, sign, value, none} + TEST (T, 10, "{1.0}", ' ', 0, 1, -1, FMT (" ")); + TEST (T, 10, "{1.0}", ' ', 0, 1, -1, FMT (".")); + + TEST (T, -11, "(1.1)", ' ', 0, 1, -1, FMT (" ")); + TEST (T, -11, "(1.1)", ' ', 0, 1, -1, FMT (".")); + + TEST (T, 101, "{1.01}", ' ', 0, 2, -1, FMT (" ")); + TEST (T, 101, "{1.01}", ' ', 0, 2, -1, FMT (".")); + + Punct::negative_sign_ = signs1 [0]; + Punct::positive_sign_ = signs1 [1]; + + TEST (T, 1012, "1,0.12", ' ', 0, 2, -1, FMT (" 0"), "\1"); + TEST (T, 1013, "1,0.13", ' ', 0, 2, -1, FMT (".1"), "\1"); + + TEST (T, -1014, "~1,01.4", ' ', 0, 1, -1, FMT ("~2"), "\2"); + TEST (T, -1015, "~1,01.5", ' ', 0, 1, -1, FMT (",3"), "\2"); +} + +/**************************************************************************/ + +void grouping_test () +{ + if (!rw_enabled ("char")) { + rw_note (0, __FILE__, __LINE__, "char test disabled"); + return; + } + + rw_info (0, 0, 0, "std::money_put<%s>::put(ostreambuf_iterator" + "<%s>, bool, ios_base, %s, long double); correct use of " + "moneypunct<%s, false>::grouping() and thousands_sep()", + "char", "char", "char", "char"); + + typedef Punct PunctT; + + // construct a "replacement" moneypunct-derived facet + const PunctT pun; + + // group after every digit + PunctT::grouping_ = "\1"; + + // reset the do_thousands_sep()-call counter + PunctT::thousands_sep_ = ';'; + PunctT::decimal_point_ = ':'; + PunctT::n_thousands_sep_ = 0; + + // construct and initialize a basic_ios-derived object + struct Ios: std::basic_ios { Ios () { this->init (0); } } ios; + + // construct a money_put-derived facet to exercise + struct MoneyPut: std::money_put { } mp; + + // imbue a stream object with a custom locale + // containing the replacement punctuation facet + std::locale l; + std::locale loc (l, (const std::moneypunct*)&pun); + ios.imbue (loc); + + // decimal output, no special formatting + ios.setf (std::ios::fmtflags ()); + + char buf [40] = ""; + + *mp.put (buf, false, ios, '\0', 123456789.0L) = '\0'; + + // verify that the number was formatted correctly + rw_assert (0 == rw_strncmp (buf, "1;2;3;4;5;6;7;8;9"), __FILE__, __LINE__, + "money_put::do_put(..., 123456789.0L) " + "== %#s, got %#s", "1;2;3;4;5;6;7;8;9", buf); + + // verify that do_thousands_sep() was called at least once + // (but not necessarily for each thousands separator inserted + // into the output, since the value is allowed to be cached) + rw_assert (0 != PunctT::n_thousands_sep_, __FILE__, __LINE__, + "money_put::do_put(..., 123456789.0L) " + "called moneypunct::do_thousands_sep()"); +} + +/**************************************************************************/ + +static int +run_test (int, char*[]) +{ + // check to see if we can test -0.0 + static double d = -0.0; + test_neg_zero = 1.0 / d < d; + + if (no_grouping) + rw_note (0, __FILE__, __LINE__, "grouping test disabled"); + else + grouping_test (); + + if (rw_enabled ("char")) + ldbl_test (char ()); + else + rw_note (0, __FILE__, __LINE__, "char test disabled"); + +#ifndef _RWSTD_NO_WCHAR_T + + if (rw_enabled ("wchar_t")) + ldbl_test (wchar_t ()); + else + rw_note (0, __FILE__, __LINE__, "wchar_t test disabled"); + +#endif // _RWSTD_NO_WCHAR_T + + return 0; +} + +/**************************************************************************/ + +int main (int argc, char *argv[]) +{ + return rw_test (argc, argv, __FILE__, + "lib.locale.money.put", + 0 /* no comment */, run_test, + "|-no-grouping# |-no-basic_string#", + &no_grouping, &no_basic_string); +} Propchange: incubator/stdcxx/trunk/tests/localization/22.locale.money.put.cpp ------------------------------------------------------------------------------ svn:eol-style = native Added: incubator/stdcxx/trunk/tests/src/cmdopt.cpp URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/src/cmdopt.cpp?rev=278837&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/src/cmdopt.cpp (added) +++ incubator/stdcxx/trunk/tests/src/cmdopt.cpp Mon Sep 5 13:57:44 2005 @@ -0,0 +1,1053 @@ +/*************************************************************************** + * + * $Id$ + * + ************************************************************************ + * + * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave + * Software division. Licensed 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 + +#include +#include +#include +#include +#include +#include + +#ifndef EINVAL +# define EINVAL 22 /* e.g., HP-UX, Linux, Solaris */ +#endif // EINVAL + +/**************************************************************************/ + +typedef int (optcallback_t)(int, char*[]); + +struct cmdopts_t +{ + char loptbuf_ [32]; // buffer for long option name + optcallback_t *callback_; // function to call to process option + int *pcntr_; // counter to increment for each occurrence + + char *lopt_; // long option name + char sopt_; // short option name + + size_t maxcalls_; // how many times option can be invoked + size_t ncalls_; // how many times it has been invoked + + bool arg_ : 1; // option takes an argument? + bool inv_ : 1; // callback invocation inverted + bool envseen_ : 1; // environment option already processed + +}; + + +// total number of registered options +static size_t ncmdopts; + +// number of default (always defined) options +static size_t ndefopts; +static cmdopts_t cmdoptbuf [32]; +static cmdopts_t *cmdopts = cmdoptbuf; +static size_t optbufsize = sizeof cmdoptbuf / sizeof *cmdoptbuf; + +enum { + rw_bool, rw_char, rw_uchar, rw_schar, rw_ushrt, rw_shrt, + rw_uint, rw_int, rw_ulong, rw_long, rw_ullong, rw_llong, + rw_flt, rw_dbl, rw_ldbl, rw_wchar, rw_pvoid +}; + +static int rw_disabled_types = 0; +static int rw_enabled_types = 0; + +struct linerange_t { + int first; + int last; +}; + +static size_t nlineranges; +static linerange_t *lineranges; +static size_t rangebufsize; + +/**************************************************************************/ + +static int +rw_print_help (int argc, char *argv[]) +{ + if (1 == argc && argv && 0 == argv [0]) { + static const char helpstr[] = { + "Without an argument, prints this help to stdout and exits with\n" + "a status of 0 without further processing.\n" + "With the optional argument prints help on the option with that\n" + "name, if one exists, and exits with a status of 0. If an option\n" + "with the specified name does not exist, prints an error message\n" + "to stderr and exits with a status of 1.\n" + "The leading underscores in the name of an option are optional.\n" + }; + + argv [0] = _RWSTD_CONST_CAST (char*, helpstr); + + return 0; + } + + // the option name to get help on, if any + const char* opthelp = 1 < argc ? argv [1] : 0; + + // remove the optional one or two leading underscores + if (opthelp && '-' == opthelp [0] && opthelp [1]) + opthelp += 1 + ('-' == opthelp [1]); + + if (0 == opthelp) + printf ("OPTIONS\n"); + + // set to a non-zero when the specified option is found + int option_found = 0; + + for (size_t i = 0; i != ncmdopts; ++i) { + + if (opthelp && *opthelp) { + + if ( cmdopts [i].sopt_ == opthelp [0] && '\0' == opthelp [1] + || cmdopts [i].lopt_ + && 0 == strcmp (cmdopts [i].lopt_ + 1, opthelp)) { + + // remember that we found the option whose (short + // or long) name we're to give help on; after printing + // the help text on the option keep looping in case + // there is another option and callback with the same + // name (unlikely but possible) + option_found = 1; + } + else { + // the option doesn't match, continue searching + continue; + } + } + + printf (" "); + + if (cmdopts [i].sopt_) { + printf ("-%c", cmdopts [i].sopt_); + + if (cmdopts [i].lopt_) + printf (" | "); + } + + const char *pfx = ""; + const char *sfx = pfx; + + if (cmdopts [i].lopt_) { + printf ("-%s", cmdopts [i].lopt_); + if ( cmdopts [i].arg_ + && '=' != cmdopts [i].lopt_ [strlen (cmdopts [i].lopt_) - 1]) { + pfx = " [ "; + sfx = " ]"; + } + } + + printf ("%s%s%s", pfx, cmdopts [i].arg_ ? "" : "", sfx); + + if (_RWSTD_SIZE_MAX == cmdopts [i].maxcalls_) + printf (" (each occurrence evaluated)\n"); + else if (1 < cmdopts [i].maxcalls_) + printf (" (at most %lu occurrences evaluated)\n", + cmdopts [i].maxcalls_); + else + printf (" (only the first occurrence evaluated)\n"); + + // invoke callback with the "--help" option + if (cmdopts [i].callback_) { + + char* help [2] = { 0, 0 }; + + cmdopts [i].callback_ (1, help); + + for (const char *line = help [0]; line; ) { + + const char* const nl = strchr (line, '\n'); + const int len = nl ? int (nl - line) : int (strlen (line)); + + printf (" %.*s\n", len, line); + + line = nl; + if (nl) + ++line; + } + } + } + + if (opthelp && !option_found) { + fprintf (stderr, "Unknown option \"%s\".\n", opthelp); + exit (1); + } + + exit (0); + + return 0; +} + + +static int +rw_set_ignenv (int argc, char *argv[]) +{ + if (1 == argc && argv && 0 == argv [0]) { + static const char helpstr[] = { + "Prevents options specified in the RWSTD_TESTOPTS environment\n" + "variable from taking effect.\n" + "Unless this option is specified, the RWSTD_TESTOPTS environment\n" + "variable is processed as if its value were specified on the \n" + "command line.\n" + "For example, setting the value of the variable to the string\n" + "\"--verbose --no-wchar\" and invoking this program with no\n" + "command line arguments will have the same effect as invoking\n" + "it with the two arguments on the command line.\n" + }; + + argv [0] = _RWSTD_CONST_CAST (char*, helpstr); + + return 0; + } + + return 0; +} + +static int rw_enable_type (int bit, bool enable) +{ + const int set_mask = 1 << bit; + + if (enable) + rw_enabled_types |= set_mask; + else + rw_disabled_types |= set_mask; + + return 0; +} + +#define DEFINE_HANDLERS(T) \ + static int rw_no_ ## T (int, char *[]) { \ + return rw_enable_type (rw_ ## T, false); \ + } \ + static int rw_en_ ## T (int, char *[]) { \ + return rw_enable_type (rw_ ## T, true); \ + } \ + typedef void unused_type /* allow a semicolon */ + + +DEFINE_HANDLERS (bool); +DEFINE_HANDLERS (char); +DEFINE_HANDLERS (schar); +DEFINE_HANDLERS (uchar); +DEFINE_HANDLERS (shrt); +DEFINE_HANDLERS (ushrt); +DEFINE_HANDLERS (int); +DEFINE_HANDLERS (uint); +DEFINE_HANDLERS (long); +DEFINE_HANDLERS (ulong); +DEFINE_HANDLERS (llong); +DEFINE_HANDLERS (ullong); +DEFINE_HANDLERS (flt); +DEFINE_HANDLERS (dbl); +DEFINE_HANDLERS (ldbl); +DEFINE_HANDLERS (wchar); +DEFINE_HANDLERS (pvoid); + +static int +rw_enable_lines (int first, int last, bool enable) +{ + if (nlineranges == rangebufsize) { + const size_t newbufsize = 2 * nlineranges + 1; + + linerange_t* const newranges = + (linerange_t*)malloc (newbufsize * sizeof (linerange_t)); + + if (0 == newranges) { + abort (); + } + + memcpy (newranges, lineranges, nlineranges * sizeof (linerange_t)); + + free (lineranges); + + lineranges = newranges; + rangebufsize = newbufsize; + } + + if (enable) { + lineranges [nlineranges].first = first; + lineranges [nlineranges].last = last; + } + else { + lineranges [nlineranges].first = -first; + lineranges [nlineranges].last = -last; + } + + ++nlineranges; + + return 0; +} + + +static int +rw_enable_line (int argc, char *argv[], bool enable) +{ + if (1 == argc && argv && 0 == argv [0]) { + + static const char helpstr[] = { + "Enables or disables the lines specified by .\n" + "The syntax of is as follows: \n" + " ::= [ , ]\n" + " ::= [ - ] | - [ ]\n" + }; + + argv [0] = _RWSTD_CONST_CAST (char*, helpstr); + + return 0; + } + + char *parg = strchr (argv [0], '='); + assert (0 != parg); + + const char* const argbeg = ++parg; + + // the lower bound of a range of lines to be enabled or disabled + // negative values are not valid and denote an implicit lower bound + // of 1 (such as in "-3" which is a shorthand for "1-3") + long first = -1; + + for ( ; '\0' != *parg ; ) { + + printf ("%s (%ld)\n", parg, first); + + // skip any leading whitespace + for ( ; ' ' == *parg; ++parg); + + if ('-' == *parg) { + if (first < 0) { + first = 0; + ++parg; + } + else { + fprintf (stderr, + "invalid character '%c' at position %d: \"%s\"\n", + *parg, int (parg - argbeg), argv [0]); + return 2; + } + } + + // parse a numeric argument + char *end; + long line = strtol (parg, &end, 0); + + // skip any trailing whitespace + for ( ; ' ' == *end; ++end); + + if (end == parg || '-' != *end && ',' != *end && '\0' != *end) { + fprintf (stderr, + "invalid character '%c' at position %d: \"%s\"\n", + *end, int (parg - argbeg), argv [0]); + return 2; + } + + if (0 <= first) { + if (line < 0) { + fprintf (stderr, + "invalid value %ld at position %d: \"%s\"\n", + line, int (parg - argbeg), argv [0]); + return 2; + } + + ++line; + + if ((',' == *end || '-' == *end) && end [1]) + ++end; + } + else if (',' == *end) { + first = line++; + if ('\0' == end [1]) { + fprintf (stderr, + "invalid character '%c' at position %d: \"%s\"\n", + *end, int (parg - argbeg), argv [0]); + return 2; + } + + ++end; + } + else if ('-' == *end) { + first = line; + while (' ' == *++end); + if ('\0' == *end) { + line = _RWSTD_INT_MAX; + } + else if (',' == *end) { + line = _RWSTD_INT_MAX; + ++end; + } + else + line = -1; + } + else if ('\0' == *end) { + first = line++; + } + else { + fprintf (stderr, + "invalid character '%c' at position %d: \"%s\"\n", + *end, int (parg - argbeg), argv [0]); + return 2; + } + + parg = end; + + if (0 <= first && first < line) { + printf (" [%ld, %ld)\n", first, line); + rw_enable_lines (first, line, enable); + first = -1; + } + } + + for (size_t i = 0; i != nlineranges; ++i) { + printf ("[%d, %d)\n", lineranges [i].first, lineranges [i].last); + } + + return 0; +} + +static int rw_en_line (int argc, char *argv[]) +{ + return rw_enable_line (argc, argv, true); +} + +static int rw_no_line (int argc, char *argv[]) +{ + return rw_enable_line (argc, argv, false); +} + +static void rw_set_myopts () +{ + if (0 != ncmdopts) + return; + + static bool recursive; + + if (recursive) + return; + + recursive = true; + + rw_setopts ("|-help: " // argument optional + "|-ignenv " + // options to disable fundamental types + "|-no-bool |-no-char |-no-schar |-no-uchar " + "|-no-shrt |-no-ushrt " + "|-no-int |-no-uint " + "|-no-long |-no-ulong " + "|-no-llong |-no-ullong " + "|-no-flt |-no-dbl |-no-ldbl " + "|-no-wchar |-no-pvoid " + // option to disable ranges of lines + "|-no-line= " + // options to enable fundamental types + "|-enable-bool |-enable-char |-enable-schar |-enable-uchar " + "|-enable-shrt |-enable-ushrt " + "|-enable-int |-enable-uint " + "|-enable-long |-enable-ulong " + "|-enable-llong |-enable-ullong " + "|-enable-flt |-enable-dbl |-enable-ldbl " + "|-enable-wchar |-enable-pvoid " + // option to enable ranges of lines + "|-enable-line= ", + // + rw_print_help, + rw_set_ignenv, + // handlers to disable fundamental types + rw_no_bool, rw_no_char, rw_no_schar, rw_no_uchar, + rw_no_shrt, rw_no_ushrt, + rw_no_int, rw_no_uint, + rw_no_long, rw_no_ulong, + rw_no_llong, rw_no_ullong, + rw_no_flt, rw_no_dbl, rw_no_ldbl, + rw_no_wchar, rw_no_pvoid, + rw_no_line, + // handlers to enable fundamental types + rw_en_bool, rw_en_char, rw_en_schar, rw_en_uchar, + rw_en_shrt, rw_en_ushrt, + rw_en_int, rw_en_uint, + rw_en_long, rw_en_ulong, + rw_en_llong, rw_en_ullong, + rw_en_flt, rw_en_dbl, rw_en_ldbl, + rw_en_wchar, rw_en_pvoid, + rw_en_line, + (optcallback_t*)0); + + ndefopts = ncmdopts; + + recursive = false; +} + + +////////////////////////////////////////////////////////////////////// +// syntax of the option description string: +// +// opts ::= opt [ ':' | '=' | '#' ] [ @N | @* | '!' ] [ opts ] +// opt ::= [ '|' ] +// ::= '|' +// sopt ::= char +// lopt ::= char char* +// char ::= any character other than a space (' '), bar ('|'), +// colon (':') and the equals sign ('=') + +_TEST_EXPORT int +rw_vsetopts (const char *opts, va_list va) +{ + if (0 == opts) { + + // reset to 0 + + for (size_t i = 0; i != ncmdopts; ++i) { + if (cmdopts [i].lopt_ != cmdopts [i].loptbuf_) + free (cmdopts [i].lopt_); + } + + if (cmdopts != cmdoptbuf) + free (cmdopts); + + cmdopts = cmdoptbuf; + ncmdopts = 0; + + return 0; + } + + rw_set_myopts (); + + const char *next = opts; + + for ( ; ; ++ncmdopts) { + + while (' ' == *next) + ++next; + + if ('\0' == *next) { + break; + } + + if (ncmdopts == optbufsize) { + + const size_t newbufsize = 2 * ncmdopts + 1; + + cmdopts_t* const newopts = + (cmdopts_t*)malloc (newbufsize * sizeof (cmdopts_t)); + + if (0 == newopts) { + abort (); + } + + memcpy (newopts, cmdopts, ncmdopts * sizeof (cmdopts_t)); + + if (cmdopts != cmdoptbuf) + free (cmdopts); + + cmdopts = newopts; + optbufsize = newbufsize; + } + + memset (cmdopts + ncmdopts, 0, sizeof *cmdopts); + + if ('|' != *next) + cmdopts [ncmdopts].sopt_ = *next++; + + if ('|' == *next) { + const char* end = strpbrk (++next, "|@:=*!# "); + if (0 == end) + end = next + strlen (next); + + // copy the option name up to but not including the delimiter + // (except when the delimiter is the equals sign ('='), which + // becomes the last character of the option name + const size_t optlen = size_t (end - next) + ('=' == *end); + + if (optlen < sizeof cmdopts [ncmdopts].loptbuf_) + cmdopts [ncmdopts].lopt_ = cmdopts [ncmdopts].loptbuf_; + else + cmdopts [ncmdopts].lopt_ = (char*)malloc (optlen + 1); + + memcpy (cmdopts [ncmdopts].lopt_, next, optlen); + cmdopts [ncmdopts].lopt_ [optlen] = '\0'; + + next = end; + } + + // only the first occurrence of each command line option + // causes an invocation of the callback, all subsequent + // ones will be ignored by default + cmdopts [ncmdopts].maxcalls_ = 1; + + bool arg_is_callback = true; + + if (':' == *next || '=' == *next) { + // ':' : argument optional + // '=' : argument required + cmdopts [ncmdopts].arg_ = true; + ++next; + } + else if ('#' == *next) { + // insead of a pointer to a callback, the argument + // is a pointer to an int counter that is to be + // incremented for each occurrence of the option + // during processing + arg_is_callback = false; + ++next; + + // an unlimited number of occurrences of the option + // are allowed and will be counted + cmdopts [ncmdopts].maxcalls_ = _RWSTD_SIZE_MAX; + } + + if ('@' == *next) { + + ++next; + + // at most how many occurrences of an option can be processed? + if ('*' == *next) { + // unlimited + cmdopts [ncmdopts].maxcalls_ = _RWSTD_SIZE_MAX; + ++next; + } + else { + // at most this many + char *end; + cmdopts [ncmdopts].maxcalls_ = strtoul (next, &end, 10); + next = end; + } + } + else if ('!' == *next) { + cmdopts [ncmdopts].inv_ = true; + ++next; + } + + if (arg_is_callback) { + // retrieve the callback and verify it's not null + // (null callback is permitted in the special case when + // the short option is '-', i.e., when setting up or + // resetting an "unknown option" handler) + cmdopts [ncmdopts].callback_ = va_arg (va, optcallback_t*); + } + else { + // retrieve the address of the int counter where to keep + // track of the number of occurrences of the option + cmdopts [ncmdopts].pcntr_ = va_arg (va, int*); + } + + if ( '-' != cmdopts [ncmdopts].sopt_ + && 0 == cmdopts [ncmdopts].callback_ + && 0 == cmdopts [ncmdopts].pcntr_) { + + if (cmdopts [ncmdopts].lopt_) + fprintf (stderr, "null handler for option -%s\n", + cmdopts [ncmdopts].lopt_); + else + fprintf (stderr, "null handler for option -%c\n", + cmdopts [ncmdopts].sopt_); + + abort (); + } + } + + return int (ncmdopts - ndefopts); +} + + +_TEST_EXPORT int +rw_setopts (const char *opts, ...) +{ + va_list va; + va_start (va, opts); + const int result = rw_vsetopts (opts, va); + va_end (va); + return result; +} + + +_TEST_EXPORT int +rw_runopts (int argc, char *argv[]) +{ + rw_set_myopts (); + + static bool recursive = false; + + // ignore options set in the environment? + bool ignenv = recursive; + + // return status + int status = 0; + + // number of options processed + int nopts = 0; + + // index of registered option whose callback should be invoked + // for command line options that do not match any other + size_t not_found_inx = _RWSTD_SIZE_MAX; + + // iterate over the command line arguments until a callback + // returns a non-zero value or until all options have been + // successfully processed + for (int i = 0; i < argc && argv [i] && 0 == status; ++i) { + + if (0 == strcmp ("--ignore-environment", argv [i])) { + // ignore options set in the environment + ignenv = true; + continue; + } + + if (0 == strcmp ("--", argv [i])) { + // "--" terminates options, everything + // after it is treated as an argument + break; + } + + bool found = false; + + // look up each command line option (i.e., a string that starts + // with a dash ('-')) and invoke the callback associated with it + for (size_t j = 0; j != ncmdopts; ++j) { + + if ('-' == cmdopts [j].sopt_) + not_found_inx = j; + + if ('-' == argv [i][0]) { + + // the name of the option without the leading dash + const char* const optname = argv [i] + 1; + + // look for the first equals sign + const char* const eq = strchr (optname, '='); + + // compute the length of the ooption including the equals + // sign (if any) + const size_t optlen = + eq ? size_t (eq - optname + 1) : strlen (optname); + + // try to match the long option first, and only if it + // doesn't match try the short single-character option + if ( cmdopts [j].lopt_ + && optlen == strlen (cmdopts [j].lopt_) + && 0 == memcmp (optname, cmdopts [j].lopt_, optlen) + || cmdopts [j].sopt_ + && optname [0] == cmdopts [j].sopt_ + && (1 == optlen || cmdopts [j].arg_)) { + + // matching option has been found + found = true; + + // ignore the option if invoked recursively (by processing + // options set in the environment) and the option has + // already been seen (this prevents duplicate processing + // of options that are set both on the command line and + // in the environment and allows option with an argument + // set on the command line to override those set in the + // environment) + + if (cmdopts [j].ncalls_ && recursive) + continue; + + // if the option has been evaluated the maximum number + // of times, avoid evaluating it and continue processing + if (cmdopts [j].maxcalls_ <= cmdopts [j].ncalls_) + continue; + + if (cmdopts [j].callback_) { + if (!cmdopts [j].inv_) { + // when the command line argument matched + // the option, invoke the callback function + status = cmdopts [j].callback_ (argc - i, argv + i); + } + } + else { + assert (0 != cmdopts [j].pcntr_); + ++*cmdopts [j].pcntr_; + } + + ++cmdopts [j].ncalls_; + + if (recursive) + cmdopts [j].envseen_ = true; + + ++nopts; + + if (status) { + // when the status returned from the last callback + // is non-0 stop further processing (including + // any options set in the environment) and return + // status to the caller + ignenv = true; + break; + } + } + } + } + + if (!found && '-' == argv [i][0]) { + + // invoke the appropriate error handler for an option + // that was not found + if (_RWSTD_SIZE_MAX != not_found_inx) { + + // invoke the error handler set up through rw_setopts() + // and let the handler decide whether to go on processing + // other options or whether to abort + status = cmdopts [not_found_inx].callback_ (argc - i, argv + i); + if (status) { + // no further processing done + ignenv = true; + break; + } + } + else { + // print an error message to stderr when no error + // handler has been set up + fprintf (stderr, "unknown option: %s\n", argv [i]); + ignenv = true; + errno = EINVAL; + status = 1; + break; + } + } + } + + if (!ignenv) { + // process options from the environment + const char* const envar = getenv ("RWSTD_TESTOPTS"); + if (envar) { + recursive = true; + rw_runopts (envar); + recursive = false; + } + } + + // invoke any inverted callbacks or bump their user-specified counters, + // and reset internal counters indicating if/how many times each option + // has been processed + for (size_t j = 0; j != ncmdopts; ++j) { + + if (cmdopts [j].inv_ && 0 == cmdopts [j].ncalls_ && 0 == status) { + + if (cmdopts [j].callback_) + status = cmdopts [j].callback_ (0, 0); + else { + assert (0 != cmdopts [j].pcntr_); + ++*cmdopts [j].pcntr_; + } + } + + cmdopts [j].ncalls_ = 0; + cmdopts [j].envseen_ = false; + } + + return status; +} + + +_TEST_EXPORT int +rw_runopts (const char *str) +{ + assert (0 != str); + + rw_set_myopts (); + + char buf [80]; // fixed size buffer to copy `str' into + char *pbuf = buf; // a modifiable copy of `str' + + size_t len = strlen (str); + if (len >= sizeof buf) { + // allocate if necessary + pbuf = (char*)malloc (len + 1); + if (!pbuf) + return -1; + } + + // copy `str' to modifiable buffer + memcpy (pbuf, str, len + 1); + + char *tmp_argv_buf [32] = { 0 }; // fixed size argv buffer + char **argv = tmp_argv_buf; // array of arguments + + // initial size of argument array (will grow as necessary) + size_t argv_size = sizeof tmp_argv_buf / sizeof *tmp_argv_buf; + size_t argc = 0; // number of arguments in array + + int in_quotes = 0; // quoted argument being processed + + for (char *s = pbuf; *s; ++s) { + if ('"' == *s) { + in_quotes = !in_quotes; + continue; + } + + if (in_quotes) + continue; + + // split up unquoted space-separated arguments + if (argc == 0 || ' ' == *s) { + if (argc > 0) + *s = 0; + + // skip over leading spaces + if (argc > 0 || ' ' == *s) + while (' ' == *++s); + + if (*s) { + if (argc == argv_size) { + // grow `argv' as necessary + char **tmp = (char**)malloc (sizeof *tmp * argv_size * 2); + if (!tmp) { + if (argv != tmp_argv_buf) + free (argv); + return -1; + } + + // copy existing elementes and zero out any new entries + memcpy (tmp, argv, sizeof *tmp * argv_size); + memset (tmp + argv_size, 0, sizeof *tmp * argv_size); + + // free existing buffer if necessary + if (argv != tmp_argv_buf) + free (argv); + + // reassign buffer and increase size + argv = tmp; + argv_size *= 2; + } + + // add argument to array + argv [argc++] = s; + } + } + } + + // process `argc' options pointed to by `argv' + const int status = rw_runopts (int (argc), argv); + + // free buffers if necessary + if (argv != tmp_argv_buf) + free (argv); + + if (pbuf != buf) + free (pbuf); + + return status; + +} + + +_TEST_EXPORT int +rw_enabled (const char *name) +{ + int enabled = -1; + + static const struct { + int bit; + const char *name; + } types[] = { + { rw_bool, "bool" }, + + { rw_char, "char" }, + + { rw_schar, "schar" }, + { rw_schar, "signed char" }, + { rw_uchar, "uchar" }, + { rw_uchar, "unsigned char" }, + + { rw_shrt, "shrt" }, + { rw_shrt, "short" }, + { rw_shrt, "signed short" }, + { rw_ushrt, "ushrt" }, + { rw_ushrt, "unsigned short" }, + + { rw_int, "int" }, + { rw_int, "signed int" }, + { rw_uint, "uint" }, + { rw_uint, "unsigned int" }, + + { rw_long, "long" }, + { rw_long, "signed long" }, + { rw_ulong, "ulong" }, + { rw_ulong, "unsigned long" }, + + { rw_llong, "llong" }, + { rw_llong, "long long" }, + { rw_llong, "signed long long" }, + { rw_ullong, "ullong" }, + { rw_ullong, "unsigned long long" }, + + { rw_flt, "flt" }, + { rw_flt, "float" }, + + { rw_dbl, "dbl" }, + { rw_dbl, "double" }, + + { rw_ldbl, "ldbl" }, + { rw_ldbl, "long double" }, + + { rw_wchar, "wchar" }, + { rw_wchar, "wchar_t" }, + + { rw_pvoid, "pvoid" }, + { rw_pvoid, "void*" } + }; + + for (size_t i = 0; i != sizeof types / sizeof *types; ++i) { + if (0 == strcmp (types [i].name, name)) { + const int mask = 1 << types [i].bit; + + enabled = !(rw_disabled_types & mask); + + if (rw_enabled_types) + enabled = enabled && (rw_enabled_types & mask); + + break; + } + } + + return enabled; +} + + +_TEST_EXPORT int +rw_enabled (int line) +{ + int nenabled = 0; + int ndisabled = 0; + + int line_enabled = -1; + + for (size_t i = 0; i != nlineranges; ++i) { + + const int first = lineranges [i].first; + const int last = lineranges [i].last; + + if (first < 0) { + line = -line; + ++ndisabled; + } + else { + ++nenabled; + } + + if (lineranges [i].first <= line && line < lineranges [i].last) + line_enabled = 0 < line; + } + + if (nenabled && -1 == line_enabled) + line_enabled = 0; + + return line_enabled; +} Propchange: incubator/stdcxx/trunk/tests/src/cmdopt.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/src/cmdopt.cpp ------------------------------------------------------------------------------ svn:keywords = Id