--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/driver.cpp Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,1234 @@
+/************************************************************************
+ *
+ * driver.cpp - definitions of the test driver
+ *
+ * $Id: driver.cpp 290009 2005-09-18 23:28:26Z sebor $
+ *
+ ************************************************************************
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+// expand _TEST_EXPORT macros
+#define _RWSTD_TEST_SRC
+
+#include "opt_diags.h"
+#include "opt_lines.h"
+#include "opt_trace.h"
+#include "opt_types.h"
+
+#include <cmdopt.h> // for rw_setopts()
+#include <printf.h> // for rw_snprintfa()
+
+#include <assert.h> // for assert
+#include <setjmp.h> // for longjmp, setjmp, ...
+#include <stdarg.h> // for va_list
+#include <stdio.h> // for fileno, fprintf
+#include <stdlib.h> // for free
+#include <string.h> // for strchr, strcpy
+#include"std_log_result.h"
+#define LOG_FILENAME_LINE __FILE__, __LINE__
+#if !defined (_WIN32) && !defined (_WIN64)
+# include <unistd.h> // for isatty
+
+// declare fileno in case it's not declared (for strict ANSI conformance)
+extern "C" {
+
+_RWSTD_DLLIMPORT int (fileno)(FILE*) _LIBC_THROWS ();
+
+} // extern "C"
+
+#else
+ // no isatty on Windoze
+# define _RWSTD_NO_ISATTY
+#endif // _WIN{32,64}
+
+// expand _TEST_EXPORT macros
+#define _RWSTD_TEST_SRC
+#include <driver.h>
+
+/************************************************************************/
+
+#define RW_TEST_STRSTR(x) #x
+#define RW_TEST_STR(x) RW_TEST_STRSTR(x)
+
+#ifndef RW_TEST_COMPILER
+# if defined (__DECCXX__)
+# define RW_TEST_COMPILER "Compaq C++, __DECCXX__ = " \
+ RW_TEST_STR (__DECCXX__)
+# elif defined (__INTEL_COMPILER)
+# if defined (__EDG_VERSION__)
+# define RW_TEST_ICC_EDG_VER \
+ ", __EDG_VERSION__ = " RW_TEST_STR (__EDG_VERSION__)
+# else
+# define RW_TEST_ICC_EDG_VER ""
+# endif
+# if defined (_MSC_VER)
+# define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
+ RW_TEST_STR (__INTEL_COMPILER) ", _MSC_VER = " \
+ RW_TEST_STR (_MSC_VER) \
+ RW_TEST_ICC_EDG_VER
+# elif defined (__INTEL_COMPILER_BUILD_DATE)
+# define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
+ RW_TEST_STR (__INTEL_COMPILER) \
+ ", __INTEL_COMPILER_BUILD_DATE = " \
+ RW_TEST_STR (__INTEL_COMPILER_BUILD_DATE) \
+ RW_TEST_ICC_EDG_VER
+# else
+# define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
+ RW_TEST_STR (__INTEL_COMPILER) \
+ RW_TEST_ICC_EDG_VER
+# endif
+# elif defined (__GNUC__)
+# if defined (__VERSION__)
+# define RW_TEST_GCC_VER ", __VERSION__ = \"" __VERSION__ "\""
+# else
+# define RW_TEST_GCC_VER ""
+# endif
+# if defined (__GNUC_PATCHLEVEL__)
+# define RW_TEST_COMPILER "gcc " \
+ RW_TEST_STR (__GNUC__) "." \
+ RW_TEST_STR (__GNUC_MINOR__) "." \
+ RW_TEST_STR (__GNUC_PATCHLEVEL__) \
+ RW_TEST_GCC_VER
+# else
+# define RW_TEST_COMPILER "gcc " \
+ RW_TEST_STR (__GNUC__) "." RW_TEST_STR (__GNUC_MINOR__)
+ RW_TEST_GCC_VER
+# endif
+# elif defined (_COMPILER_VERSION) && defined (__sgi)
+# define RW_TEST_COMPILER "SGI MIPSpro, _COMPILER_VERSION = " \
+ RW_TEST_STR (_COMPILER_VERSION)
+# elif defined (__INTEL_COMPILER)
+# if defined (_MSC_VER)
+# define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
+ RW_TEST_STR (__INTEL_COMPILER) ", _MSC_VER = " \
+ RW_TEST_STR (_MSC_VER)
+# else
+# define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
+ RW_TEST_STR (__INTEL_COMPILER)
+# endif
+# elif defined (__EDG__)
+# define RW_TEST_COMPILER "EDG eccp, __EDG_VERSION__ = " \
+ RW_TEST_STR (__EDG_VERSION__)
+# elif defined (__HP_aCC)
+# define RW_TEST_COMPILER "HP aCC, __HP_aCC = " \
+ RW_TEST_STR (__HP_aCC)
+# elif defined (__IBMCPP__)
+# define RW_TEST_COMPILER "IBM VisualAge C++, __IBMCPP__ = " \
+ RW_TEST_STR (__IBMCPP__)
+# elif defined (_MSC_VER)
+# define RW_TEST_COMPILER "MSVC, _MSC_VER = " \
+ RW_TEST_STR (_MSC_VER)
+# elif defined (__SUNPRO_CC)
+# define RW_TEST_COMPILER "SunPro, __SUNPRO_CC = " \
+ RW_TEST_STR (__SUNPRO_CC)
+# else
+# define RW_TEST_COMPILER "unknown"
+# endif
+#endif
+
+#ifndef RW_TEST_LIBSTD
+# ifdef _RWSTD_VER
+# define RW_TEST_LIBSTD "Rogue Wave C++ Standard Library, " \
+ "_RWSTD_VER = " RW_TEST_STR (_RWSTD_VER)
+# elif defined (__GLIBCXX__)
+# define RW_TEST_LIBSTD "GNU C++ Standard Library, " \
+ "__GLIBCXX__ = " \
+ RW_TEST_STR (__GLIBCXX__)
+# elif defined (_STLPORT_VERSION)
+ // check for STLport before SGI STL since STLport,
+ // being derived from SGI STL, #defines both macros
+# define RW_TEST_LIBSTD "STLport, " \
+ "_STLPORT_VERSION = " \
+ RW_TEST_STR (_STLPORT_VERSION)
+# elif defined (__SGI_STL)
+# define RW_TEST_LIBSTD "SGI STL, " \
+ "__SGI_STL = " \
+ RW_TEST_STR (__SGI_STL)
+# elif defined (_YVALS)
+ // is there a better way to identify the Dinkumware
+ // implementation? does it have a version macro?
+# define RW_TEST_LIBSTD "Dinkum C++ Standard Library"
+# endif
+#endif // RW_TEST_LIBSTD
+
+#ifndef RW_TEST_HARDWARE
+# if defined (__alpha__) || defined (__alpha)
+# define RW_TEST_ARCH "alpha"
+# elif defined (__amd64__) || defined (__amd64)
+# if defined (__LP64__) || defined (_LP64)
+# define RW_TEST_ARCH "amd64/LP64"
+# else
+# define RW_TEST_ARCH "amd64/ILP32"
+# endif
+# elif defined (_PA_RISC2_0)
+# define RW_TEST_ARCH "pa-risc 2.0"
+# elif defined (_PA_RISC1_0)
+# define RW_TEST_ARCH "pa-risc 1.0"
+# elif defined (__hppa)
+# define RW_TEST_ARCH "pa-risc"
+# elif defined (__pentiumpro__) || defined (__pentiumpro)
+# define RW_TEST_ARCH "pentiumpro"
+# elif defined (__pentium__) || defined (__pentium)
+# define RW_TEST_ARCH "pentium"
+# elif defined (__i486__) || defined (__i486)
+# define RW_TEST_ARCH "i486"
+# elif defined (__i386__) || defined (__i386)
+# define RW_TEST_ARCH "i386"
+# elif defined (__i586__) || defined (__i586)
+# define RW_TEST_ARCH "i586"
+# elif defined (__ia64)
+# define RW_TEST_ARCH "ia64"
+# elif defined (__mips)
+# define RW_TEST_ARCH "mips"
+# elif defined (__sparcv9)
+# define RW_TEST_ARCH "sparc-v9"
+# elif defined (__sparcv8)
+# define RW_TEST_ARCH "sparc-v8"
+# elif defined (__sparc)
+# define RW_TEST_ARCH "sparc"
+# elif defined (_POWER)
+# if defined (_ARCH_PWR5)
+# define RW_TEST_ARCH "power-5"
+# elif defined (_ARCH_PWR4)
+# define RW_TEST_ARCH "power-4"
+# elif defined (_ARCH_PWR3)
+# define RW_TEST_ARCH "power-3"
+# elif defined (_ARCH_604)
+# define RW_TEST_ARCH "powerpc-604"
+# elif defined (_ARCH_603)
+# define RW_TEST_ARCH "powerpc-603"
+# elif defined (_ARCH_602)
+# define RW_TEST_ARCH "powerpc-602"
+# elif defined (_ARCH_601)
+# define RW_TEST_ARCH "powerpc-601"
+# elif defined (_ARCH_403)
+# define RW_TEST_ARCH "powerpc-403"
+# elif defined (_ARCH_PPC64)
+# define RW_TEST_ARCH "powerpc/LP64"
+# else
+# define RW_TEST_ARCH "powerpc"
+# endif
+# elif defined (_WIN64)
+# define RW_TEST_ARCH "ia64"
+# elif defined (_WIN32)
+# define RW_TEST_ARCH "i86"
+# elif defined (__x86_64__) || defined (__x86_64)
+# if defined (__LP64__) || defined (_LP64)
+# define RW_TEST_ARCH "x86_64/LP64"
+# else
+# define RW_TEST_ARCH "x86_64/ILP32"
+# endif
+# else
+# define RW_TEST_ARCH "unknown"
+# endif
+
+
+# if defined (_AIX54)
+# define RW_TEST_OS "aix-5.4 (or better)"
+# elif defined (_AIX53)
+# define RW_TEST_OS "aix-5.3"
+# elif defined (_AIX52)
+# define RW_TEST_OS "aix-5.2"
+# elif defined (_AIX51)
+# define RW_TEST_OS "aix-5.1"
+# elif defined (_AIX50)
+# define RW_TEST_OS "aix-5.0"
+# elif defined (_AIX43)
+# define RW_TEST_OS "aix-4.3"
+# elif defined (_AIX41)
+# define RW_TEST_OS "aix-4.1"
+# elif defined (_AIX32)
+# define RW_TEST_OS "aix-3.2"
+# elif defined (_AIX)
+# define RW_TEST_OS "aix"
+# elif defined (__hpux)
+# define RW_TEST_OS "hp-ux"
+# elif defined (__osf__)
+# define RW_TEST_OS "tru64-unix"
+# elif defined (__sgi) && defined (__mips)
+# define RW_TEST_OS "irix"
+# elif defined (__linux__) || defined (__linux)
+
+ // get Linux release string (UTS_RELEASE)
+# include <linux/version.h>
+
+# ifndef UTS_RELEASE
+# define UTS_RELEASE "(unknown release)"
+# endif // UTS_RELEASE
+
+# if defined (__ELF__)
+# define LINUX_TYPE "linux-elf"
+# else
+# define LINUX_TYPE "linux"
+# endif
+
+# define RW_TEST_OS LINUX_TYPE " " \
+ UTS_RELEASE " with glibc " \
+ RW_TEST_STR (__GLIBC__) "." \
+ RW_TEST_STR (__GLIBC_MINOR__)
+
+# elif defined (__SunOS_5_10)
+# define RW_TEST_OS "sunos-5.10"
+# elif defined (__SunOS_5_9)
+# define RW_TEST_OS "sunos-5.9"
+# elif defined (__SunOS_5_8)
+# define RW_TEST_OS "sunos-5.8"
+# elif defined (__SunOS_5_7)
+# define RW_TEST_OS "sunos-5.7"
+# elif defined (__SunOS_5_6)
+# define RW_TEST_OS "sunos-5.6"
+# elif defined (__sun__)
+# define RW_TEST_OS "sunos"
+# elif defined (_WIN64)
+# define RW_TEST_OS "win64"
+# elif defined (_WIN32)
+# define RW_TEST_OS "win32"
+# else
+# define RW_TEST_OS "unknown"
+# endif
+
+# define RW_TEST_HARDWARE RW_TEST_ARCH " running " RW_TEST_OS
+#else
+# define RW_TEST_HARDWARE "unknown"
+#endif
+
+/************************************************************************/
+
+// defined in printf.cpp but not declared in printf.h
+_TEST_EXPORT int
+rw_vasnprintf (char**, size_t*, const char*, va_list);
+
+/************************************************************************/
+
+// array to store the number of each type of diagnostic
+static int
+ndiags [N_DIAG_TYPES][2] /* = { { total, active }, ... }*/;
+
+static FILE *ftestout;
+
+static jmp_buf test_env;
+
+// set to 1 after the driver has been initialized
+static int driver_initialized = 0;
+
+// set to 1 after the driver has finished running
+static int driver_finished = 0;
+
+#if 0 // disabled
+// %S: severity
+// %M: diagnostic
+// %m: diagnostic if not empty
+// %F: file name
+// %f: file name if not empty
+// %C: clause
+// %c: clause if not empty
+// %L: line number
+// %l: line number if valid
+// %T: text
+// %t: text if not empty
+static char diag_pattern [80];
+#endif
+
+// option: use CSV format (comma separated values)
+static int _rw_opt_csv = 0;
+
+static char clause_id [80];
+
+/************************************************************************/
+
+#define CHECK_INIT(init, func) _rw_check_init (init, __LINE__, func)
+
+static inline void
+_rw_check_init (bool init, int line, const char *func)
+{
+ if (init && !driver_initialized) {
+ fprintf (stderr, "%s:%d: %s: test driver already initialized\n",
+ __FILE__, line, func);
+ std_log(LOG_FILENAME_LINE,"%s:%d: %s: test driver already initialized\n",
+ __FILE__, line, func);
+ abort ();
+ }
+
+ if (!init && driver_initialized) {
+ fprintf (stderr, "%s:%d: %s: test driver not initialized yet\n",
+ __FILE__, line, func);
+ std_log(LOG_FILENAME_LINE,"%s:%d: %s: test driver not initialized yet\n",
+ __FILE__, line, func);
+ abort ();
+ }
+
+ if (driver_finished) {
+ fprintf (stderr, "%s:%d: %s: test finished, cannot call\n",
+ __FILE__, line, func);
+ std_log(LOG_FILENAME_LINE,"%s:%d: %s: test finished, cannot call\n",
+ __FILE__, line, func);
+ }
+}
+
+/************************************************************************/
+
+static int
+_rw_opt_brief (int argc, char *argv[])
+{
+ static int opt_brief;
+
+ if (0 == argc) {
+ // query mode: return the value of the option
+ return opt_brief;
+ }
+
+ if (1 == argc && argv && 0 == argv [0]) {
+ // help mode: set argv[0] to the text of the help message
+
+ static const char helpstr[] = {
+ "Enables brief mode.\n"
+ };
+
+ argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
+
+ return 0;
+ }
+
+ // set mode: enable the option
+ opt_brief = 1;
+
+ return 0;
+}
+
+/************************************************************************/
+
+static int
+_rw_opt_quiet (int argc, char *argv[])
+{
+ static int opt_quiet;
+
+ if (0 == argc) {
+ // query mode: return the value of the option
+ return opt_quiet;
+ }
+
+ if (1 == argc && argv && 0 == argv [0]) {
+ // help mode: set argv[0] to the text of the help message
+
+ static const char helpstr[] = {
+ "Enables quiet mode.\n"
+ "In quiet mode only diagnostics with severity 7 and above are "
+ "issued."
+ };
+
+ argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
+
+ return 0;
+ }
+
+ // set mode: enable the option
+ _rw_diag_mask = ~((1 << 7) | (1 << 8) | (1 << 9));
+ opt_quiet = 1;
+
+ return 0;
+}
+
+/************************************************************************/
+
+static int
+_rw_opt_verbose (int argc, char *argv[])
+{
+ static int opt_verbose;
+
+ if (0 == argc) {
+ // query mode: return the value of the option
+ return opt_verbose;
+ }
+
+ if (1 == argc && argv && 0 == argv [0]) {
+ // help mode: set argv[0] to the text of the help message
+
+ static const char helpstr[] = {
+ "Enables verbose mode.\n"
+ };
+
+ argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
+
+ return 0;
+ }
+
+ // set mode: enable the option
+ opt_verbose = 1;
+
+ return 0;
+}
+
+/************************************************************************/
+
+static int
+_rw_setopt_csv (int argc, char *argv[])
+{
+ if (1 == argc && argv && 0 == argv [0]) {
+ static const char helpstr[] = {
+ "Enables CSV (comma separated values) mode.\n"
+ };
+
+ argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
+
+ return 0;
+ }
+
+ _rw_opt_csv = 1;
+ return 0;
+}
+
+/************************************************************************/
+
+static int
+_rw_opt_compat (int argc, char *argv[])
+{
+ static int opt_compat;
+
+ if (0 == argc) {
+ // query mode: return the value of the option
+ return opt_compat;
+ }
+
+ if (1 == argc && argv && 0 == argv [0]) {
+ // help mode: set argv[0] to the text of the help message
+
+ static const char helpstr[] = {
+ "Enables RWTest-format compatibility mode.\n"
+ };
+
+ argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
+
+ return 0;
+ }
+
+ // set mode: enable the option
+ opt_compat = 1;
+
+ return 0;
+}
+
+/************************************************************************/
+
+static int
+_rw_opt_no_stdout (int argc, char *argv[])
+{
+ static int opt_no_stdout;
+
+ if (0 == argc) {
+ // query mode: return the value of the option
+ return opt_no_stdout;
+ }
+
+ if (1 == argc && argv && 0 == argv [0]) {
+ // help mode: set argv[0] to the text of the help message
+
+ static const char helpstr[] = {
+ "Prevents the program from using stdandard output for diagnostic\n"
+ "messages. Instead, the driver will create a log file with a name\n"
+ "obtained from the from the basename of the program source file,\n"
+ "usually obtained by passing the value of the __FILE__ macro to\n"
+ "the driver, with the .out extension. If successful, the driver\n"
+ "will write all diagnostic messages issued by the program to this\n"
+ "file. Otherwise, the driver exits with an error.\n"
+ };
+
+ argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
+
+ return 0;
+ }
+
+ // set mode: enable the option
+ opt_no_stdout = 1;
+
+ return 0;
+}
+
+/************************************************************************/
+
+static int
+_rw_setopt_output_file (int argc, char *argv[])
+{
+ if (1 == argc && argv && 0 == argv [0]) {
+ static const char helpstr[] = {
+ "Specifies the name of the output file to be used by the program\n"
+ "for diagnostic messages. Unless this option is specified, the\n"
+ "program will issue all diagnostic messages to the standard output."
+ "\nDriver diagnostics are always directed to stderr.\n"
+ };
+
+ argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
+
+ return 0;
+ }
+
+ const char *file_name = 0;
+
+ if ('-' == argv [0][0] && 'O' == argv [0][1] || 'o' == argv [0][1]) {
+ file_name = argv [0] + 2;
+ }
+ else if (1 < argc && '-' != argv [1][0]) {
+ file_name = argv [1];
+ }
+
+ if (file_name) {
+
+ FILE* const f = fopen (file_name, "w");
+
+ if (f) {
+ if (ftestout && ftestout != stderr)
+ fclose (ftestout);
+
+ ftestout = f;
+ }
+ }
+
+ // return 0 on success, any non-zero value on failure
+ return !(ftestout != 0);
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_vsetopts (const char *opts, va_list va);
+
+/************************************************************************/
+
+static int
+_rw_use_color ()
+{
+#ifndef _RWSTD_NO_ISATTY
+
+ // is output sent to a terminal?
+ // if so, assume a vt100 compatible terminal for now
+ static const int tty = isatty (fileno (ftestout));
+
+#else // if defined (_RWSTD_NO_ISATTY)
+
+ // FIXME: deal with a missing isatty() and Windows
+ static const int tty = 0;
+
+#endif // _RWSTD_NO_ISATTY
+
+ return 0 != tty;
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_vtest (int argc, char **argv,
+ const char *file_name,
+ const char *clause,
+ const char *comment,
+ int (*fun)(int, char**),
+ const char *optstr,
+ va_list va)
+{
+ CHECK_INIT (false, "rw_vtest()");
+
+ driver_initialized = 1;
+
+ if (optstr && 0 > rw_vsetopts (optstr, va)) {
+ fprintf (stderr, "%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
+ std_log(LOG_FILENAME_LINE,"%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
+ return 1;
+ }
+
+ const int nopts =
+ rw_setopts ("|-no-stdout "
+ "|-diags= " // argument required
+ "|-trace "
+ "|-severity= " // argument required
+ "|-csv "
+ "|-compat "
+ "o|-output:" // argument optional
+ "b|-brief "
+ "q|-quiet "
+ "v|-verbose",
+ _rw_opt_no_stdout,
+ _rw_setopt_diags,
+ _rw_setopt_trace,
+ _rw_setopt_trace_mask,
+ _rw_setopt_csv,
+ _rw_opt_compat,
+ _rw_setopt_output_file,
+ _rw_opt_brief,
+ _rw_opt_quiet,
+ _rw_opt_verbose,
+ 0);
+
+ if (3 > nopts) {
+ fprintf (stderr, "%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
+ std_log(LOG_FILENAME_LINE,"%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
+ abort ();
+ return 1;
+ }
+
+#ifndef _RWSTD_USE_CONFIG
+
+ // enable RWTest-format compatibility mode
+ _rw_opt_compat (1, 0);
+
+ // disable output to stdout
+ _rw_opt_no_stdout (1, 0);
+
+#endif // _RWSTD_USE_CONFIG
+
+ _rw_setopts_types ();
+
+ _rw_setopts_lines ();
+
+ int status = rw_runopts (argc, argv);
+
+ if (status)
+ return status;
+
+ if (0 == ftestout) {
+
+ if (_rw_opt_no_stdout (0, 0) && file_name) {
+ char fname [256] = "C:\\";
+
+ const char* const slash = strrchr (file_name, _RWSTD_PATH_SEP);
+ strcat (fname, slash ? slash + 1 : file_name);
+
+ char* const dot = strchr (fname, '.');
+ if (dot)
+ strcpy (dot, ".out");
+ else
+ strcat (fname, ".out");
+
+ ftestout = fopen (fname, "w");
+ }
+ else
+ ftestout = stdout;
+ }
+
+ if (clause)
+ strcpy (clause_id, clause);
+
+ const char begin_fmt[] = {
+ "\n"
+ "# COMPILER: %s\n"
+ "# ENVIRONMENT: %s\n"
+ "# FILE: %s\n"
+ "# COMPILED: %s, %s\n"
+ "# COMMENT: %s\n"
+ "######################################################"
+ };
+
+ const char* const fname = strrchr (file_name, _RWSTD_PATH_SEP);
+
+ rw_info (0, 0, 0,
+ begin_fmt,
+ RW_TEST_COMPILER, RW_TEST_HARDWARE,
+ fname ? fname + 1 : file_name,
+ __DATE__, __TIME__,
+ comment ? comment : "");
+
+ status = setjmp (test_env);
+
+ if (0 == status) {
+ // environment set, execute the callback function
+ status = fun (argc, argv);
+ }
+ else {
+ // fatal test error (via a call to rw_fatal())
+ }
+
+ driver_finished = 1;
+
+ static const char tblrow[] =
+ "+-----------------------+--------+--------+--------+";
+
+ fprintf (ftestout,
+ "# %s\n"
+ "# | DIAGNOSTIC | ACTIVE | TOTAL |INACTIVE|\n"
+ "# %s\n",
+ tblrow, tblrow);
+
+ int nlines = 0;
+
+ for (int i = 0; i != N_DIAG_TYPES; ++i) {
+ if (ndiags [i][0] || !(_rw_diag_mask & (1 << diag_trace))) {
+
+ // print out details for any non-zero totals
+ // or for all totals when debugging or tracing
+ // is enabled
+
+ ++nlines;
+
+ const long num = (ndiags [i][0] - ndiags [i][1]) * 100L;
+ const long den = ndiags [i][0];
+
+ const long pct = den ? num / den : 0;
+
+ const char* pfx = "";
+ const char* sfx = "";
+
+ static int use_color = _rw_use_color ();
+
+ if (use_color) {
+ pfx = ndiags [i][1] ? diag_msgs [i].esc_pfx : "";
+ sfx = ndiags [i][1] ? diag_msgs [i].esc_sfx : "";
+ }
+
+ fprintf (ftestout,
+ "# | (S%d) %-*s |%s %6d %s| %6d | %5ld%% |\n",
+ i, int (sizeof diag_msgs [i].code), diag_msgs [i].code,
+ pfx, ndiags [i][1], sfx, ndiags [i][0], pct);
+ }
+ }
+
+ if (0 == nlines)
+ fprintf (ftestout, "# no diagnostics\n");
+
+ fprintf (ftestout, "# %s\n", tblrow);
+
+ if (_rw_opt_compat (0, 0)) {
+
+ // TO DO: get rid of this
+
+ // RWTest compatibility format
+
+ fprintf (ftestout,
+ "######################################################\n"
+ "## Warnings = %d\n"
+ "## Assertions = %d\n"
+ "## FailedAssertions = %d\n",
+ ndiags [diag_warn][1] + ndiags [diag_xwarn][1],
+ ndiags [diag_assert][0],
+ ndiags [diag_assert][1] + ndiags [diag_xassert][1]);
+ }
+
+ fclose (ftestout);
+ ftestout = 0;
+
+ return status;
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_test (int argc, char **argv,
+ const char *fname,
+ const char *clause,
+ const char *comment,
+ int (*testfun)(int, char**),
+ const char *optstr,
+ ...)
+{
+ CHECK_INIT (false, "rw_test()");
+
+ va_list va;
+ va_start (va, optstr);
+
+ const int status =
+ rw_vtest (argc, argv, fname, clause, comment, testfun, optstr, va);
+
+ va_end (va);
+
+ return status;
+}
+
+/************************************************************************/
+
+// escape every occurrence of the double quote character in the string
+// pointed to by buf by prepending to it the escape character specified
+// by the last acrgument
+// returns the new buffer if the size of the existing buffer isn't
+// sufficient and sets *pbufsize to the size of the newly allocated
+// buffer, otherwise the original value of buf and leaves *pbufsize
+// unchanged
+static char*
+_rw_escape (char *buf, size_t bufsize, char esc)
+{
+ // handle null buffer
+ if (0 == buf)
+ return buf;
+
+ // count the number of embedded quotes
+ char *quote = buf;
+ size_t nquotes = 0;
+ while ((quote = strchr (quote, '"'))) {
+ ++nquotes;
+ ++quote;
+ }
+
+ // no quotes found, return the original buffer
+ if (0 == nquotes)
+ return buf;
+
+ // conpute the size of the buffer that will be needed to escape
+ // all the double quotes
+ size_t newbufsize = strlen (buf) + nquotes + 1;
+
+ char *newbuf = 0;
+
+ if (0 /* newbufsize <= bufsize */) {
+ // FIXME: escape embedded quotes in place w/o reallocation
+ _RWSTD_UNUSED (bufsize);
+ }
+ else {
+ newbuf = (char*)malloc (newbufsize);
+ if (0 == newbuf) {
+ return 0;
+ }
+
+ // set the next pointer to the beginning of the new buffer
+ // as the destination where to copy the string argument
+ char *next = newbuf;
+
+ // set quote to initially point to the beginning of
+ // the source buffer and then just past the last quote
+ quote = buf;
+
+ for (char *q = buf; ; ++q) {
+
+ // look for the next (or first) quote
+ q = strchr (q, '"');
+
+ // compute the number of characters, excluding the quote
+ // to copy to the destination buffer
+ const size_t nchars = q ? size_t (q - quote) : strlen (quote);
+
+ memcpy (next, quote, nchars);
+
+ if (q) {
+ // append the escape character to the destination buffer
+ next [nchars] = esc;
+
+ // append the quote from the source string
+ next [nchars + 1] = '"';
+
+ // advance the destination pointer past the quote
+ next += nchars + 2;
+
+ // advance the source pointer past the embedded quote
+ quote = q + 1;
+ }
+ else {
+ // NUL-terminate the destination buffer
+ *next = '\0';
+ break;
+ }
+ }
+ }
+
+ return newbuf;
+}
+
+/************************************************************************/
+
+static void
+_rw_vissue_diag (diag_t diag, int severity, const char *file, int line,
+ const char *fmt, va_list va)
+{
+ CHECK_INIT (true, "_rw_vissue_diag()");
+
+ if (0 == fmt)
+ fmt = "";
+
+ static char fmterr[] = "*** formatting error ***";
+
+ char *usrbuf = 0;
+ const int nchars = rw_vasnprintf (&usrbuf, 0, fmt, va);
+
+ if (nchars < 0 || 0 == usrbuf)
+ usrbuf = fmterr;
+
+ // compute the number of newline characters in the text
+ int nlines = 0;
+ for (const char *nl = usrbuf; (nl = strchr (nl, '\n')); ++nl)
+ ++nlines;
+
+ static const int use_color = _rw_use_color ();
+
+ const char* const diagstr[] = {
+ use_color ? diag_msgs [severity].esc_pfx : "",
+ *diag_msgs [severity].code ? diag_msgs [severity].code : "UNKNOWN",
+ use_color ? diag_msgs [severity].esc_sfx : "",
+ _rw_opt_verbose (0, 0) && *diag_msgs [severity].desc ?
+ diag_msgs [severity].desc : 0
+ };
+
+ const char* const traced_diag =
+ 0 == severity && diag_msgs [diag].code ? diag_msgs [diag].code : 0;
+
+ const char* const slash = file ? strrchr (file, _RWSTD_PATH_SEP) : 0;
+ if (slash)
+ file = slash + 1;
+
+ char *mybuf = 0;
+
+ if (_rw_opt_csv) {
+
+ // format all fields as comma separated values (CSV):
+ // -- a field containing the quote character, the comma,
+ // or the newline or linefeed character must be enclosed
+ // in a pair of double quotes
+ // -- every occurrence of the double quote character in a field
+ // must be escaped by prepening another double quote character
+ // to it
+
+ // escape all double quotes by prepending the double
+ // quote character to each according to the CSV format
+ char* const newbuf = _rw_escape (usrbuf, 0, '"');
+ if (newbuf != usrbuf) {
+ free (usrbuf);
+ usrbuf = newbuf;
+ }
+
+ mybuf =
+ rw_sprintfa ("%d, " // severity
+ "\"%s%s" // diagnostic
+ "%{?}_%s%{;}%s\", " // traced diagnostic
+ "\"%s\", " // clause
+ "\"%s\", " // file
+ "%d, " // line
+ "\"%s\"", // user text
+ severity,
+ diagstr [0], diagstr [1],
+ 0 != traced_diag, traced_diag, diagstr [2],
+ clause_id,
+ 0 != file ? file : "",
+ line,
+ usrbuf);
+ }
+ else {
+
+ nlines += 2 + ('\0' != *clause_id) + (0 != file) + (0 < line);
+
+ mybuf =
+ rw_sprintfa ("# %s" // escape prefix
+ "%s" // diagnostic
+ "%{?}_%s%{;}" // traced diagnostic
+ "%s " // escape suffix
+ "(S%d)" // severity
+ "%{?}, %s%{;} " // description
+ "(%d lines):\n" // number of lines
+ "# TEXT: %s\n" // user text
+ "%{?}# CLAUSE: %s\n%{;}" // clause if not empty
+ "%{?}# FILE: %s\n%{;}" // file if not null
+ "%{?}# LINE: %d\n%{;}", // line if positive
+ diagstr [0],
+ diagstr [1],
+ 0 != traced_diag, traced_diag,
+ diagstr [2],
+ severity,
+ 0 != diagstr [3], diagstr [3],
+ nlines,
+ usrbuf,
+ '\0' != *clause_id, clause_id,
+ 0 != file, file,
+ 0 < line, line);
+ }
+#if 0 // disabled
+ else {
+
+ mybuf =
+ rw_sprintfa ("# %s%s" // diagnostic
+ "%{?}_%s%{;}%s " // traced diagnostic
+ "(S%d): " // severity
+ "%{?}[%s] %{;}" // clause if not empty
+ "%{?}(%d lines): %{;}" // number of lines if > 1
+ "%{?}%s:" // if (file) then file
+ "%{?}%d:%{;} " // if (0 < line) line
+ "%{:}" // else
+ "%{?}line %d: %{;}" // if (0 < line) line
+ "%{;}" // endif
+ "%s", // user text
+ diagstr [0], diagstr [1],
+ 0 != traced_diag, traced_diag, diagstr [2],
+ severity,
+ '\0' != *clause_id, clause_id,
+ 1 < nlines, nlines,
+ 0 != file, file,
+ 0 < line, line,
+ 0 < line, line,
+ usrbuf);
+ }
+#endif // 0/1
+
+ fprintf (ftestout, "%s\n", mybuf);
+
+ if (mybuf != fmterr)
+ free (mybuf);
+
+ if (usrbuf != fmterr)
+ free (usrbuf);
+}
+
+/************************************************************************/
+
+static void
+_rw_vdiag (diag_t diag, int severity, const char *file, int line,
+ const char *fmt, va_list va)
+{
+ CHECK_INIT (true, "_rw_vdiag()");
+
+ // check if the diagnostic is expected
+ const int expected = 0 != _rw_expected (line);
+
+ if (expected) {
+ if (severity) {
+ // if the diagnostic is expected to be active,
+ // adjust its type and severity
+ if (diag_assert == diag)
+ diag = diag_xassert;
+ else if (diag_warn == diag)
+ diag = diag_xwarn;
+
+ severity = diag * severity;
+ }
+ else {
+ // if the diagnostic is expected to be active but isn't,
+ // adjust its type to an unexpectdly inactive one
+ if (diag_assert == diag || diag_warn == diag)
+ diag = diag_expect;
+
+ severity = diag;
+ }
+ }
+ else if (diag) {
+ // normalize the severity
+ severity = diag * severity;
+ }
+
+ if (severity < 0)
+ severity = 0;
+ else if (N_DIAG_TYPES <= severity)
+ severity = N_DIAG_TYPES - 1;
+
+ // increment the diagnostic counter
+ ++ndiags [diag][0];
+
+ if (severity) {
+
+ ++ndiags [diag][1];
+ }
+
+ const int sevbit = (1 << severity);
+
+ if (0 == (sevbit & _rw_diag_mask)) {
+ // issue the diagnostic
+ _rw_vissue_diag (diag, severity, file, line, fmt, va);
+ }
+
+ if (diag_fatal == diag && severity) {
+ // fatal error, terminate test
+ longjmp (test_env, severity);
+ }
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_fatal (int success, const char *file, int line, const char *fmt, ...)
+{
+ CHECK_INIT (true, "rw_fatal()");
+
+ va_list va;
+ va_start (va, fmt);
+
+ _rw_vdiag (diag_fatal, 0 == success, file, line, fmt, va);
+
+ va_end (va);
+
+ return success;
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_error (int success, const char *file, int line, const char *fmt, ...)
+{
+ CHECK_INIT (true, "rw_error()");
+
+ va_list va;
+ va_start (va, fmt);
+
+ _rw_vdiag (diag_error, 0 == success, file, line, fmt, va);
+
+ va_end (va);
+
+ return success;
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_assert (int success, const char *file, int line, const char *fmt, ...)
+{
+ CHECK_INIT (true, "rw_assert()");
+
+ va_list va;
+ va_start (va, fmt);
+
+ _rw_vdiag (diag_assert, 0 == success, file, line, fmt, va);
+
+ va_end (va);
+
+ return success;
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_warn (int success, const char *file, int line, const char *fmt, ...)
+{
+ CHECK_INIT (true, "rw_warn()");
+
+ va_list va;
+ va_start (va, fmt);
+
+ _rw_vdiag (diag_warn, 0 == success, file, line, fmt, va);
+
+ va_end (va);
+
+ return success;
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_note (int success, const char *file, int line, const char *fmt, ...)
+{
+ CHECK_INIT (true, "rw_note()");
+
+ va_list va;
+ va_start (va, fmt);
+
+ _rw_vdiag (diag_note, 0 == success, file, line, fmt, va);
+
+ va_end (va);
+
+ return success;
+}
+
+/************************************************************************/
+
+_TEST_EXPORT int
+rw_info (int success, const char *file, int line, const char *fmt, ...)
+{
+ CHECK_INIT (true, "rw_info()");
+
+ va_list va;
+ va_start (va, fmt);
+
+ _rw_vdiag (diag_info, 0 == success, file, line, fmt, va);
+
+ va_end (va);
+
+ return success;
+}