os/ossrv/stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/driver.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/driver.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1256 @@
     1.4 +/************************************************************************
     1.5 + *
     1.6 + * driver.cpp - definitions of the test driver
     1.7 + *
     1.8 + * $Id: driver.cpp 290009 2005-09-18 23:28:26Z sebor $
     1.9 + *
    1.10 + ************************************************************************
    1.11 + *
    1.12 + * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
    1.13 + * Software division. Licensed under the Apache License, Version 2.0 (the
    1.14 + * "License");  you may  not use this file except  in compliance with the
    1.15 + * License.    You    may   obtain   a   copy   of    the   License    at
    1.16 + * http://www.apache.org/licenses/LICENSE-2.0.    Unless   required    by
    1.17 + * applicable law  or agreed to  in writing,  software  distributed under
    1.18 + * the License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR
    1.19 + * CONDITIONS OF  ANY KIND, either  express or implied.  See  the License
    1.20 + * for the specific language governing permissions  and limitations under
    1.21 + * the License.
    1.22 + *
    1.23 + **************************************************************************/
    1.24 +
    1.25 +// expand _TEST_EXPORT macros
    1.26 +#define _RWSTD_TEST_SRC
    1.27 +
    1.28 +#include "opt_diags.h"
    1.29 +#include "opt_lines.h"
    1.30 +#include "opt_trace.h"
    1.31 +#include "opt_types.h"
    1.32 +
    1.33 +#include <cmdopt.h>    // for rw_setopts()
    1.34 +#include <printf.h>    // for rw_snprintfa()
    1.35 +
    1.36 +#include <assert.h>    // for assert
    1.37 +#include <setjmp.h>    // for longjmp, setjmp, ...
    1.38 +#include <stdarg.h>    // for va_list
    1.39 +#include <stdio.h>     // for fileno, fprintf
    1.40 +#include <stdlib.h>    // for free
    1.41 +#include <string.h>    // for strchr, strcpy
    1.42 +#include"std_log_result.h"
    1.43 +#define LOG_FILENAME_LINE __FILE__, __LINE__
    1.44 +#if !defined (_WIN32) && !defined (_WIN64)
    1.45 +#  include <unistd.h>    // for isatty
    1.46 +
    1.47 +// declare fileno in case it's not declared (for strict ANSI conformance)
    1.48 +extern "C" {
    1.49 +
    1.50 +IMPORT_C int (fileno)(FILE*) _LIBC_THROWS ();
    1.51 +
    1.52 +}   // extern "C"
    1.53 +
    1.54 +#else
    1.55 +   // no isatty on Windoze
    1.56 +#  define _RWSTD_NO_ISATTY
    1.57 +#endif   // _WIN{32,64}
    1.58 +
    1.59 +// expand _TEST_EXPORT macros
    1.60 +#define _RWSTD_TEST_SRC
    1.61 +#include <driver.h>
    1.62 +
    1.63 +/************************************************************************/
    1.64 +
    1.65 +#define RW_TEST_STRSTR(x)   #x
    1.66 +#define RW_TEST_STR(x)      RW_TEST_STRSTR(x)
    1.67 +
    1.68 +#ifndef RW_TEST_COMPILER
    1.69 +#  if defined (__DECCXX__)
    1.70 +#    define RW_TEST_COMPILER "Compaq C++, __DECCXX__ = " \
    1.71 +            RW_TEST_STR (__DECCXX__)
    1.72 +#  elif defined (__INTEL_COMPILER)
    1.73 +#    if defined (__EDG_VERSION__)
    1.74 +#      define RW_TEST_ICC_EDG_VER \
    1.75 +              ", __EDG_VERSION__ = "  RW_TEST_STR (__EDG_VERSION__)
    1.76 +#    else
    1.77 +#      define RW_TEST_ICC_EDG_VER ""
    1.78 +#    endif
    1.79 +#    if defined (_MSC_VER)
    1.80 +#      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
    1.81 +              RW_TEST_STR (__INTEL_COMPILER) ", _MSC_VER = " \
    1.82 +              RW_TEST_STR (_MSC_VER) \
    1.83 +              RW_TEST_ICC_EDG_VER
    1.84 +#    elif defined (__INTEL_COMPILER_BUILD_DATE)
    1.85 +#      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
    1.86 +              RW_TEST_STR (__INTEL_COMPILER) \
    1.87 +              ", __INTEL_COMPILER_BUILD_DATE = " \
    1.88 +              RW_TEST_STR (__INTEL_COMPILER_BUILD_DATE) \
    1.89 +              RW_TEST_ICC_EDG_VER
    1.90 +#    else
    1.91 +#      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
    1.92 +              RW_TEST_STR (__INTEL_COMPILER) \
    1.93 +              RW_TEST_ICC_EDG_VER
    1.94 +#    endif
    1.95 +#  elif defined (__GNUC__)
    1.96 +#    if defined (__VERSION__)
    1.97 +#      define RW_TEST_GCC_VER ", __VERSION__ = \"" __VERSION__ "\""
    1.98 +#    else
    1.99 +#      define RW_TEST_GCC_VER ""
   1.100 +#    endif
   1.101 +#    if defined (__GNUC_PATCHLEVEL__)
   1.102 +#      define RW_TEST_COMPILER "gcc "            \
   1.103 +              RW_TEST_STR (__GNUC__) "."         \
   1.104 +              RW_TEST_STR (__GNUC_MINOR__) "."   \
   1.105 +              RW_TEST_STR (__GNUC_PATCHLEVEL__)  \
   1.106 +              RW_TEST_GCC_VER
   1.107 +#    else
   1.108 +#      define RW_TEST_COMPILER "gcc " \
   1.109 +              RW_TEST_STR (__GNUC__) "." RW_TEST_STR (__GNUC_MINOR__) 
   1.110 +              RW_TEST_GCC_VER
   1.111 +#    endif
   1.112 +#  elif defined (_COMPILER_VERSION) && defined (__sgi)
   1.113 +#    define RW_TEST_COMPILER "SGI MIPSpro, _COMPILER_VERSION = " \
   1.114 +            RW_TEST_STR (_COMPILER_VERSION)
   1.115 +#  elif defined (__INTEL_COMPILER)
   1.116 +#    if defined (_MSC_VER)
   1.117 +#      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
   1.118 +              RW_TEST_STR (__INTEL_COMPILER) ", _MSC_VER = " \
   1.119 +              RW_TEST_STR (_MSC_VER)
   1.120 +#    else
   1.121 +#      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
   1.122 +              RW_TEST_STR (__INTEL_COMPILER)
   1.123 +#    endif
   1.124 +#  elif defined (__EDG__)
   1.125 +#    define RW_TEST_COMPILER "EDG eccp, __EDG_VERSION__ = " \
   1.126 +            RW_TEST_STR (__EDG_VERSION__)
   1.127 +#  elif defined (__HP_aCC)
   1.128 +#    define RW_TEST_COMPILER "HP aCC, __HP_aCC = " \
   1.129 +            RW_TEST_STR (__HP_aCC)
   1.130 +#  elif defined (__IBMCPP__)
   1.131 +#    define RW_TEST_COMPILER "IBM VisualAge C++, __IBMCPP__ = " \
   1.132 +            RW_TEST_STR (__IBMCPP__)
   1.133 +#  elif defined (_MSC_VER)
   1.134 +#    define RW_TEST_COMPILER "MSVC, _MSC_VER = " \
   1.135 +            RW_TEST_STR (_MSC_VER)
   1.136 +#  elif defined (__SUNPRO_CC)
   1.137 +#    define RW_TEST_COMPILER "SunPro, __SUNPRO_CC = " \
   1.138 +            RW_TEST_STR (__SUNPRO_CC)
   1.139 +#  else
   1.140 +#    define RW_TEST_COMPILER "unknown"
   1.141 +#  endif
   1.142 +#endif
   1.143 +
   1.144 +#ifndef RW_TEST_LIBSTD
   1.145 +#  ifdef _RWSTD_VER
   1.146 +#    define RW_TEST_LIBSTD "Rogue Wave C++ Standard Library, " \
   1.147 +            "_RWSTD_VER = " RW_TEST_STR (_RWSTD_VER)
   1.148 +#  elif defined (__GLIBCXX__)
   1.149 +#    define RW_TEST_LIBSTD "GNU C++ Standard Library, " \
   1.150 +            "__GLIBCXX__ = " \
   1.151 +            RW_TEST_STR (__GLIBCXX__)
   1.152 +#  elif defined (_STLPORT_VERSION)
   1.153 +     // check for STLport before SGI STL since STLport,
   1.154 +     // being derived from SGI STL, #defines both macros
   1.155 +#    define RW_TEST_LIBSTD "STLport, " \
   1.156 +            "_STLPORT_VERSION = " \
   1.157 +            RW_TEST_STR (_STLPORT_VERSION)
   1.158 +#  elif defined (__SGI_STL)
   1.159 +#    define RW_TEST_LIBSTD "SGI STL, " \
   1.160 +            "__SGI_STL = " \
   1.161 +            RW_TEST_STR (__SGI_STL)
   1.162 +#  elif defined (_YVALS)
   1.163 +     // is there a better way to identify the Dinkumware
   1.164 +     // implementation? does it have a version macro?
   1.165 +#    define RW_TEST_LIBSTD "Dinkum C++ Standard Library"
   1.166 +#  endif
   1.167 +#endif   // RW_TEST_LIBSTD
   1.168 +
   1.169 +#ifndef RW_TEST_HARDWARE
   1.170 +#  if defined (__alpha__) || defined (__alpha)
   1.171 +#    define RW_TEST_ARCH "alpha"
   1.172 +#  elif defined (__amd64__) || defined (__amd64)
   1.173 +#    if defined (__LP64__) || defined (_LP64)
   1.174 +#      define RW_TEST_ARCH "amd64/LP64"
   1.175 +#    else
   1.176 +#      define RW_TEST_ARCH "amd64/ILP32"
   1.177 +#    endif
   1.178 +#  elif defined (_PA_RISC2_0)
   1.179 +#    define RW_TEST_ARCH "pa-risc 2.0"
   1.180 +#  elif defined (_PA_RISC1_0)
   1.181 +#    define RW_TEST_ARCH "pa-risc 1.0"
   1.182 +#  elif defined (__hppa)
   1.183 +#    define RW_TEST_ARCH "pa-risc"
   1.184 +#  elif defined (__pentiumpro__) || defined (__pentiumpro)
   1.185 +#    define RW_TEST_ARCH "pentiumpro"
   1.186 +#  elif defined (__pentium__) || defined (__pentium)
   1.187 +#    define RW_TEST_ARCH "pentium"
   1.188 +#  elif defined (__i486__) || defined (__i486)
   1.189 +#    define RW_TEST_ARCH "i486"
   1.190 +#  elif defined (__i386__) || defined (__i386)
   1.191 +#    define RW_TEST_ARCH "i386"
   1.192 +#  elif defined (__i586__) || defined (__i586)
   1.193 +#    define RW_TEST_ARCH "i586"
   1.194 +#  elif defined (__ia64)
   1.195 +#    define RW_TEST_ARCH "ia64"
   1.196 +#  elif defined (__mips)
   1.197 +#    define RW_TEST_ARCH "mips"
   1.198 +#  elif defined (__sparcv9)
   1.199 +#    define RW_TEST_ARCH "sparc-v9"
   1.200 +#  elif defined (__sparcv8)
   1.201 +#    define RW_TEST_ARCH "sparc-v8"
   1.202 +#  elif defined (__sparc)
   1.203 +#    define RW_TEST_ARCH "sparc"
   1.204 +#  elif defined (_POWER)
   1.205 +#    if defined (_ARCH_PWR5)
   1.206 +#      define RW_TEST_ARCH "power-5"
   1.207 +#    elif defined (_ARCH_PWR4)
   1.208 +#      define RW_TEST_ARCH "power-4"
   1.209 +#    elif defined (_ARCH_PWR3)
   1.210 +#      define RW_TEST_ARCH "power-3"
   1.211 +#    elif defined (_ARCH_604)
   1.212 +#      define RW_TEST_ARCH "powerpc-604"
   1.213 +#    elif defined (_ARCH_603)
   1.214 +#      define RW_TEST_ARCH "powerpc-603"
   1.215 +#    elif defined (_ARCH_602)
   1.216 +#      define RW_TEST_ARCH "powerpc-602"
   1.217 +#    elif defined (_ARCH_601)
   1.218 +#      define RW_TEST_ARCH "powerpc-601"
   1.219 +#    elif defined (_ARCH_403)
   1.220 +#      define RW_TEST_ARCH "powerpc-403"
   1.221 +#    elif defined (_ARCH_PPC64)
   1.222 +#      define RW_TEST_ARCH "powerpc/LP64"
   1.223 +#    else
   1.224 +#      define RW_TEST_ARCH "powerpc"
   1.225 +#    endif
   1.226 +#  elif defined (_WIN64)
   1.227 +#    define RW_TEST_ARCH "ia64"
   1.228 +#  elif defined (_WIN32)
   1.229 +#    define RW_TEST_ARCH "i86"
   1.230 +#  elif defined (__x86_64__) || defined (__x86_64)
   1.231 +#    if defined (__LP64__) || defined (_LP64)
   1.232 +#      define RW_TEST_ARCH "x86_64/LP64"
   1.233 +#    else
   1.234 +#      define RW_TEST_ARCH "x86_64/ILP32"
   1.235 +#    endif
   1.236 +#  else
   1.237 +#    define RW_TEST_ARCH "unknown"
   1.238 +#  endif
   1.239 +
   1.240 +
   1.241 +#  if defined (_AIX54)
   1.242 +#    define RW_TEST_OS "aix-5.4 (or better)"
   1.243 +#  elif defined (_AIX53)
   1.244 +#    define RW_TEST_OS "aix-5.3"
   1.245 +#  elif defined (_AIX52)
   1.246 +#    define RW_TEST_OS "aix-5.2"
   1.247 +#  elif defined (_AIX51)
   1.248 +#    define RW_TEST_OS "aix-5.1"
   1.249 +#  elif defined (_AIX50)
   1.250 +#    define RW_TEST_OS "aix-5.0"
   1.251 +#  elif defined (_AIX43)
   1.252 +#    define RW_TEST_OS "aix-4.3"
   1.253 +#  elif defined (_AIX41)
   1.254 +#    define RW_TEST_OS "aix-4.1"
   1.255 +#  elif defined (_AIX32)
   1.256 +#    define RW_TEST_OS "aix-3.2"
   1.257 +#  elif defined (_AIX)
   1.258 +#    define RW_TEST_OS "aix"
   1.259 +#  elif defined (__hpux)
   1.260 +#    define RW_TEST_OS "hp-ux"
   1.261 +#  elif defined (__osf__)
   1.262 +#    define RW_TEST_OS "tru64-unix"
   1.263 +#  elif defined (__sgi) && defined (__mips)
   1.264 +#    define RW_TEST_OS "irix"
   1.265 +#  elif defined (__linux__) || defined (__linux)
   1.266 +
   1.267 +     // get Linux release string (UTS_RELEASE)
   1.268 +#    include <linux/version.h>
   1.269 +
   1.270 +#    ifndef UTS_RELEASE
   1.271 +#      define UTS_RELEASE "(unknown release)"
   1.272 +#    endif   // UTS_RELEASE
   1.273 +
   1.274 +#    if defined (__ELF__)
   1.275 +#      define LINUX_TYPE "linux-elf"
   1.276 +#    else
   1.277 +#      define LINUX_TYPE "linux"
   1.278 +#    endif
   1.279 +
   1.280 +#    define RW_TEST_OS LINUX_TYPE " "     \
   1.281 +            UTS_RELEASE " with glibc "    \
   1.282 +            RW_TEST_STR (__GLIBC__) "."   \
   1.283 +            RW_TEST_STR (__GLIBC_MINOR__)
   1.284 +
   1.285 +#  elif defined (__SunOS_5_10)
   1.286 +#    define RW_TEST_OS "sunos-5.10"
   1.287 +#  elif defined (__SunOS_5_9)
   1.288 +#    define RW_TEST_OS "sunos-5.9"
   1.289 +#  elif defined (__SunOS_5_8)
   1.290 +#    define RW_TEST_OS "sunos-5.8"
   1.291 +#  elif defined (__SunOS_5_7)
   1.292 +#    define RW_TEST_OS "sunos-5.7"
   1.293 +#  elif defined (__SunOS_5_6)
   1.294 +#    define RW_TEST_OS "sunos-5.6"
   1.295 +#  elif defined (__sun__)
   1.296 +#    define RW_TEST_OS "sunos"
   1.297 +#  elif defined (_WIN64)
   1.298 +#    define RW_TEST_OS "win64"
   1.299 +#  elif defined (_WIN32)
   1.300 +#    define RW_TEST_OS "win32"
   1.301 +#  else
   1.302 +#    define RW_TEST_OS "unknown"
   1.303 +#  endif
   1.304 +
   1.305 +#  define RW_TEST_HARDWARE RW_TEST_ARCH " running " RW_TEST_OS
   1.306 +#else
   1.307 +#  define RW_TEST_HARDWARE "unknown"
   1.308 +#endif
   1.309 +
   1.310 +/************************************************************************/
   1.311 +
   1.312 +// defined in printf.cpp but not declared in printf.h
   1.313 +_TEST_EXPORT int
   1.314 +rw_vasnprintf (char**, size_t*, const char*, va_list);
   1.315 +
   1.316 +/************************************************************************/
   1.317 +
   1.318 +// array to store the number of each type of diagnostic
   1.319 +static int
   1.320 +ndiags [N_DIAG_TYPES][2] /* = { { total, active }, ... }*/;
   1.321 +
   1.322 +static FILE *ftestout;
   1.323 +
   1.324 +static jmp_buf test_env;
   1.325 +
   1.326 +// set to 1 after the driver has been initialized
   1.327 +static int driver_initialized = 0;
   1.328 +
   1.329 +// set to 1 after the driver has finished running
   1.330 +static int driver_finished = 0;
   1.331 +
   1.332 +#if 0   // disabled
   1.333 +// %S: severity
   1.334 +// %M: diagnostic
   1.335 +// %m: diagnostic if not empty
   1.336 +// %F: file name
   1.337 +// %f: file name if not empty
   1.338 +// %C: clause
   1.339 +// %c: clause if not empty
   1.340 +// %L: line number
   1.341 +// %l: line number if valid
   1.342 +// %T: text
   1.343 +// %t: text if not empty
   1.344 +static char diag_pattern [80];
   1.345 +#endif
   1.346 +
   1.347 +// option: use CSV format (comma separated values)
   1.348 +static int _rw_opt_csv = 0;
   1.349 +
   1.350 +static char clause_id [80];
   1.351 +
   1.352 +/************************************************************************/
   1.353 +
   1.354 +#define CHECK_INIT(init, func)   _rw_check_init (init, __LINE__, func)
   1.355 +
   1.356 +static inline void
   1.357 +_rw_check_init (bool init, int line, const char *func)
   1.358 +{
   1.359 +    if (init && !driver_initialized) {
   1.360 +        fprintf (stderr, "%s:%d: %s: test driver already initialized\n",
   1.361 +                 __FILE__, line, func);
   1.362 +     std_log(LOG_FILENAME_LINE,"%s:%d: %s: test driver already initialized\n",
   1.363 +                 __FILE__, line, func);                 
   1.364 +        abort ();
   1.365 +    }
   1.366 +
   1.367 +    if (!init && driver_initialized) {
   1.368 +        fprintf (stderr, "%s:%d: %s: test driver not initialized yet\n",
   1.369 +                 __FILE__, line, func);
   1.370 +      std_log(LOG_FILENAME_LINE,"%s:%d: %s: test driver not initialized yet\n",
   1.371 +                 __FILE__, line, func);                  
   1.372 +        abort ();
   1.373 +    }
   1.374 +
   1.375 +    if (driver_finished) {
   1.376 +        fprintf (stderr, "%s:%d: %s: test finished, cannot call\n",
   1.377 +                 __FILE__, line, func);
   1.378 +     std_log(LOG_FILENAME_LINE,"%s:%d: %s: test finished, cannot call\n",
   1.379 +                 __FILE__, line, func);                 
   1.380 +    }
   1.381 +}
   1.382 +
   1.383 +/************************************************************************/
   1.384 +
   1.385 +static int
   1.386 +_rw_opt_brief (int argc, char *argv[])
   1.387 +{
   1.388 +    static int opt_brief;
   1.389 +
   1.390 +    if (0 == argc) {
   1.391 +        // query mode: return the value of the option
   1.392 +        return opt_brief;
   1.393 +    }
   1.394 +
   1.395 +    if (1 == argc && argv && 0 == argv [0]) {
   1.396 +        // help mode: set argv[0] to the text of the help message
   1.397 +
   1.398 +        static const char helpstr[] = {
   1.399 +            "Enables brief mode.\n"
   1.400 +        };
   1.401 +
   1.402 +        argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   1.403 +
   1.404 +        return 0;
   1.405 +    }
   1.406 +
   1.407 +    // set mode: enable the option
   1.408 +    opt_brief = 1;
   1.409 +
   1.410 +    return 0;
   1.411 +}
   1.412 +
   1.413 +/************************************************************************/
   1.414 +
   1.415 +static int
   1.416 +_rw_opt_quiet (int argc, char *argv[])
   1.417 +{
   1.418 +    static int opt_quiet;
   1.419 +
   1.420 +    if (0 == argc) {
   1.421 +        // query mode: return the value of the option
   1.422 +        return opt_quiet;
   1.423 +    }
   1.424 +
   1.425 +    if (1 == argc && argv && 0 == argv [0]) {
   1.426 +        // help mode: set argv[0] to the text of the help message
   1.427 +
   1.428 +        static const char helpstr[] = {
   1.429 +            "Enables quiet mode.\n"
   1.430 +            "In quiet mode only diagnostics with severity 7 and above are "
   1.431 +            "issued."
   1.432 +        };
   1.433 +
   1.434 +        argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   1.435 +
   1.436 +        return 0;
   1.437 +    }
   1.438 +
   1.439 +    // set mode: enable the option
   1.440 +    _rw_diag_mask = ~((1 << 7) | (1 << 8) | (1 << 9));
   1.441 +    opt_quiet     = 1;
   1.442 +
   1.443 +    return 0;
   1.444 +}
   1.445 +
   1.446 +/************************************************************************/
   1.447 +
   1.448 +static int
   1.449 +_rw_opt_verbose (int argc, char *argv[])
   1.450 +{
   1.451 +    static int opt_verbose;
   1.452 +
   1.453 +    if (0 == argc) {
   1.454 +        // query mode: return the value of the option
   1.455 +        return opt_verbose;
   1.456 +    }
   1.457 +
   1.458 +    if (1 == argc && argv && 0 == argv [0]) {
   1.459 +        // help mode: set argv[0] to the text of the help message
   1.460 +
   1.461 +        static const char helpstr[] = {
   1.462 +            "Enables verbose mode.\n"
   1.463 +        };
   1.464 +
   1.465 +        argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   1.466 +
   1.467 +        return 0;
   1.468 +    }
   1.469 +
   1.470 +    // set mode: enable the option
   1.471 +    opt_verbose = 1;
   1.472 +
   1.473 +    return 0;
   1.474 +}
   1.475 +
   1.476 +/************************************************************************/
   1.477 +
   1.478 +static int
   1.479 +_rw_setopt_csv (int argc, char *argv[])
   1.480 +{
   1.481 +    if (1 == argc && argv && 0 == argv [0]) {
   1.482 +        static const char helpstr[] = {
   1.483 +            "Enables CSV (comma separated values) mode.\n"
   1.484 +        };
   1.485 +
   1.486 +        argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   1.487 +
   1.488 +        return 0;
   1.489 +    }
   1.490 +
   1.491 +    _rw_opt_csv = 1;
   1.492 +    return 0;
   1.493 +}
   1.494 +
   1.495 +/************************************************************************/
   1.496 +
   1.497 +static int
   1.498 +_rw_opt_compat (int argc, char *argv[])
   1.499 +{
   1.500 +    static int opt_compat;
   1.501 +
   1.502 +    if (0 == argc) {
   1.503 +        // query mode: return the value of the option
   1.504 +        return opt_compat;
   1.505 +    }
   1.506 +
   1.507 +    if (1 == argc && argv && 0 == argv [0]) {
   1.508 +        // help mode: set argv[0] to the text of the help message
   1.509 +
   1.510 +        static const char helpstr[] = {
   1.511 +            "Enables RWTest-format compatibility mode.\n"
   1.512 +        };
   1.513 +
   1.514 +        argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   1.515 +
   1.516 +        return 0;
   1.517 +    }
   1.518 +
   1.519 +    // set mode: enable the option
   1.520 +    opt_compat = 1;
   1.521 +
   1.522 +    return 0;
   1.523 +}
   1.524 +
   1.525 +/************************************************************************/
   1.526 +
   1.527 +static int
   1.528 +_rw_opt_no_stdout (int argc, char *argv[])
   1.529 +{
   1.530 +    static int opt_no_stdout;
   1.531 +
   1.532 +    if (0 == argc) {
   1.533 +        // query mode: return the value of the option
   1.534 +        return opt_no_stdout;
   1.535 +    }
   1.536 +
   1.537 +    if (1 == argc && argv && 0 == argv [0]) {
   1.538 +        // help mode: set argv[0] to the text of the help message
   1.539 +
   1.540 +        static const char helpstr[] = {
   1.541 +            "Prevents the program from using stdandard output for diagnostic\n"
   1.542 +            "messages. Instead, the driver will create a log file with a name\n"
   1.543 +            "obtained from the from the basename of the program source file,\n"
   1.544 +            "usually obtained by passing the value of the __FILE__ macro to\n"
   1.545 +            "the driver, with the .out extension. If successful, the driver\n"
   1.546 +            "will write all diagnostic messages issued by the program to this\n"
   1.547 +            "file. Otherwise, the driver exits with an error.\n"
   1.548 +        };
   1.549 +
   1.550 +        argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   1.551 +
   1.552 +        return 0;
   1.553 +    }
   1.554 +    
   1.555 +    // set mode: enable the option
   1.556 +    opt_no_stdout = 1;
   1.557 +
   1.558 +    return 0;
   1.559 +}
   1.560 +
   1.561 +/************************************************************************/
   1.562 +
   1.563 +static int
   1.564 +_rw_setopt_output_file (int argc, char *argv[])
   1.565 +{
   1.566 +    if (1 == argc && argv && 0 == argv [0]) {
   1.567 +        static const char helpstr[] = {
   1.568 +            "Specifies the name of the output file to be used by the program\n"
   1.569 +            "for diagnostic messages. Unless this option is specified, the\n"
   1.570 +            "program will issue all diagnostic messages to the standard output."
   1.571 +            "\nDriver diagnostics are always directed to stderr.\n"
   1.572 +        };
   1.573 +
   1.574 +        argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   1.575 +
   1.576 +        return 0;
   1.577 +    }
   1.578 +
   1.579 +    const char *file_name = 0;
   1.580 +
   1.581 +    if ('-' == argv [0][0] && 'O' == argv [0][1] || 'o' == argv [0][1]) {
   1.582 +        file_name = argv [0] + 2;
   1.583 +    }
   1.584 +    else if (1 < argc && '-' != argv [1][0]) {
   1.585 +        file_name = argv [1];
   1.586 +    }
   1.587 +
   1.588 +    if (file_name) {
   1.589 +
   1.590 +        FILE* const f = fopen (file_name, "w");
   1.591 +
   1.592 +        if (f) {
   1.593 +            if (ftestout && ftestout != stderr)
   1.594 +                fclose (ftestout);
   1.595 +
   1.596 +            ftestout = f;
   1.597 +        }
   1.598 +    }
   1.599 +
   1.600 +    // return 0 on success, any non-zero value on failure
   1.601 +    return !(ftestout != 0);
   1.602 +}
   1.603 +
   1.604 +/************************************************************************/
   1.605 +
   1.606 +_TEST_EXPORT int
   1.607 +rw_vsetopts (const char *opts, va_list va);
   1.608 +
   1.609 +/************************************************************************/
   1.610 +
   1.611 +static int
   1.612 +_rw_use_color ()
   1.613 +{
   1.614 +#ifndef _RWSTD_NO_ISATTY
   1.615 +
   1.616 +    // is output sent to a terminal?
   1.617 +    // if so, assume a vt100 compatible terminal for now
   1.618 +    static const int tty = isatty (fileno (ftestout));
   1.619 +
   1.620 +#else   // if defined (_RWSTD_NO_ISATTY)
   1.621 +
   1.622 +    // FIXME: deal with a missing isatty() and Windows
   1.623 +    static const int tty = 0;
   1.624 +
   1.625 +#endif   // _RWSTD_NO_ISATTY
   1.626 +
   1.627 +    return 0 != tty;
   1.628 +}
   1.629 +
   1.630 +/************************************************************************/
   1.631 +
   1.632 +_TEST_EXPORT int
   1.633 +rw_vtest (int argc, char **argv,
   1.634 +          const char *file_name,
   1.635 +          const char *clause,
   1.636 +          const char *comment,
   1.637 +          int (*fun)(int, char**),
   1.638 +          const char *optstr,
   1.639 +          va_list     va)
   1.640 +{
   1.641 +    CHECK_INIT (false, "rw_vtest()");
   1.642 +
   1.643 +    driver_initialized = 1;
   1.644 +
   1.645 +    if (optstr && 0 > rw_vsetopts (optstr, va)) {
   1.646 +        fprintf (stderr, "%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   1.647 +        std_log(LOG_FILENAME_LINE,"%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   1.648 +        return 1;
   1.649 +    }
   1.650 +
   1.651 +    const int nopts =
   1.652 +        rw_setopts ("|-no-stdout "
   1.653 +                    "|-diags= "      // argument required
   1.654 +                    "|-trace "
   1.655 +                    "|-severity= "   // argument required
   1.656 +                    "|-csv "
   1.657 +                    "|-compat "
   1.658 +                    "o|-output:"     // argument optional
   1.659 +                    "b|-brief "
   1.660 +                    "q|-quiet "
   1.661 +                    "v|-verbose",
   1.662 +                    _rw_opt_no_stdout,
   1.663 +                    _rw_setopt_diags,
   1.664 +                    _rw_setopt_trace,
   1.665 +                    _rw_setopt_trace_mask,
   1.666 +                    _rw_setopt_csv,
   1.667 +                    _rw_opt_compat,
   1.668 +                    _rw_setopt_output_file,
   1.669 +                    _rw_opt_brief,
   1.670 +                    _rw_opt_quiet,
   1.671 +                    _rw_opt_verbose,
   1.672 +                    0);
   1.673 +
   1.674 +    if (3 > nopts) {
   1.675 +        fprintf (stderr, "%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   1.676 +        std_log(LOG_FILENAME_LINE,"%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   1.677 +        abort ();
   1.678 +        return 1;
   1.679 +    }
   1.680 +
   1.681 +#ifndef _RWSTD_USE_CONFIG
   1.682 +
   1.683 +    // enable RWTest-format compatibility mode
   1.684 +    _rw_opt_compat (1, 0);
   1.685 +
   1.686 +    // disable output to stdout
   1.687 +    _rw_opt_no_stdout (1, 0);
   1.688 +
   1.689 +#endif   // _RWSTD_USE_CONFIG
   1.690 +
   1.691 +    _rw_setopts_types ();
   1.692 +
   1.693 +    _rw_setopts_lines ();
   1.694 +
   1.695 +    int status = rw_runopts (argc, argv);
   1.696 +
   1.697 +    if (status)
   1.698 +        return status;
   1.699 +
   1.700 +    if (0 == ftestout) {
   1.701 +
   1.702 +        if (_rw_opt_no_stdout (0, 0) && file_name) {
   1.703 +            char fname [256] = "C:\\";
   1.704 +            
   1.705 +            char* temp_ret = strchr (file_name, '/');
   1.706 +            
   1.707 +            if(temp_ret != NULL)
   1.708 +            {    
   1.709 +             const char* const slash = strrchr (file_name, '/');
   1.710 +
   1.711 +             strcat (fname, slash ? slash + 1 : file_name);
   1.712 +            }
   1.713 +            else
   1.714 +            {    
   1.715 +             const char* const slash = strrchr (file_name, _RWSTD_PATH_SEP);
   1.716 +
   1.717 +             strcat (fname, slash ? slash + 1 : file_name);
   1.718 +            }
   1.719 +            
   1.720 +            char* const dot = strchr (fname, '.');
   1.721 +            if (dot)
   1.722 +                strcpy (dot, ".out");
   1.723 +            else
   1.724 +                strcat (fname, ".out");
   1.725 +
   1.726 +            ftestout = fopen (fname, "w");
   1.727 +        }
   1.728 +        else
   1.729 +            ftestout = stdout;
   1.730 +    }
   1.731 +
   1.732 +    if (clause)
   1.733 +        strcpy (clause_id, clause);
   1.734 +
   1.735 +    const char begin_fmt[] = {
   1.736 +        "\n"
   1.737 +        "# COMPILER: %s\n"
   1.738 +        "# ENVIRONMENT: %s\n"
   1.739 +        "# FILE: %s\n"
   1.740 +        "# COMPILED: %s, %s\n"
   1.741 +        "# COMMENT: %s\n"
   1.742 +        "######################################################"
   1.743 +    };
   1.744 +
   1.745 +    const char* const fname = strrchr (file_name, _RWSTD_PATH_SEP);
   1.746 +
   1.747 +    rw_info (0, 0, 0,
   1.748 +             begin_fmt,
   1.749 +             RW_TEST_COMPILER, RW_TEST_HARDWARE,
   1.750 +             fname ? fname + 1 : file_name,
   1.751 +             __DATE__, __TIME__,
   1.752 +             comment ? comment : "");
   1.753 +
   1.754 +    status = setjmp (test_env);
   1.755 +
   1.756 +    if (0 == status) {
   1.757 +        // environment set, execute the callback function
   1.758 +        status = fun (argc, argv);
   1.759 +    }
   1.760 +    else {
   1.761 +        // fatal test error (via a call to rw_fatal())
   1.762 +    }
   1.763 +
   1.764 +    driver_finished = 1;
   1.765 +
   1.766 +    static const char tblrow[] =
   1.767 +        "+-----------------------+--------+--------+--------+";
   1.768 +
   1.769 +    fprintf (ftestout,
   1.770 +             "# %s\n"
   1.771 +             "# | DIAGNOSTIC            | ACTIVE |  TOTAL |INACTIVE|\n"
   1.772 +             "# %s\n",
   1.773 +             tblrow, tblrow);
   1.774 +
   1.775 +    int nlines = 0;
   1.776 +
   1.777 +    for (int i = 0; i != N_DIAG_TYPES; ++i) {
   1.778 +        if (ndiags [i][0] || !(_rw_diag_mask & (1 << diag_trace))) {
   1.779 +
   1.780 +            // print out details for any non-zero totals
   1.781 +            // or for all totals when debugging or tracing
   1.782 +            // is enabled
   1.783 +
   1.784 +            ++nlines;
   1.785 +
   1.786 +            const long num = (ndiags [i][0] - ndiags [i][1]) * 100L;
   1.787 +            const long den = ndiags [i][0];
   1.788 +
   1.789 +            const long pct = den ? num / den : 0;
   1.790 +
   1.791 +            const char* pfx = "";
   1.792 +            const char* sfx = "";
   1.793 +
   1.794 +            static int use_color = _rw_use_color ();
   1.795 +
   1.796 +            if (use_color) {
   1.797 +                pfx = ndiags [i][1] ? diag_msgs [i].esc_pfx : "";
   1.798 +                sfx = ndiags [i][1] ? diag_msgs [i].esc_sfx : "";
   1.799 +            }
   1.800 +
   1.801 +            fprintf (ftestout,
   1.802 +                     "# | (S%d) %-*s |%s %6d %s| %6d | %5ld%% |\n",
   1.803 +                     i, int (sizeof diag_msgs [i].code), diag_msgs [i].code,
   1.804 +                     pfx, ndiags [i][1], sfx, ndiags [i][0], pct);
   1.805 +        }
   1.806 +    }
   1.807 +
   1.808 +    if (0 == nlines)
   1.809 +        fprintf (ftestout, "# no diagnostics\n");
   1.810 +
   1.811 +    fprintf (ftestout, "# %s\n", tblrow);
   1.812 +
   1.813 +    if (_rw_opt_compat (0, 0)) {
   1.814 +
   1.815 +        // TO DO: get rid of this
   1.816 +
   1.817 +        // RWTest compatibility format
   1.818 +
   1.819 +        fprintf (ftestout,
   1.820 +                 "######################################################\n"
   1.821 +                 "## Warnings = %d\n"
   1.822 +                 "## Assertions = %d\n"
   1.823 +                 "## FailedAssertions = %d\n",
   1.824 +                 ndiags [diag_warn][1] + ndiags [diag_xwarn][1],
   1.825 +                 ndiags [diag_assert][0],
   1.826 +                 ndiags [diag_assert][1] + ndiags [diag_xassert][1]);
   1.827 +    }
   1.828 +
   1.829 +    fclose (ftestout);
   1.830 +    ftestout = 0;
   1.831 +
   1.832 +    return status;
   1.833 +}
   1.834 +
   1.835 +/************************************************************************/
   1.836 +
   1.837 +_TEST_EXPORT int
   1.838 +rw_test (int argc, char **argv,
   1.839 +         const char *fname,
   1.840 +         const char *clause,
   1.841 +         const char *comment,
   1.842 +         int (*testfun)(int, char**),
   1.843 +         const char *optstr,
   1.844 +         ...)
   1.845 +{
   1.846 +    CHECK_INIT (false, "rw_test()");
   1.847 +
   1.848 +    va_list va;
   1.849 +    va_start (va, optstr);
   1.850 +
   1.851 +    const int status =
   1.852 +        rw_vtest (argc, argv, fname, clause, comment, testfun, optstr, va);
   1.853 +
   1.854 +    va_end (va);
   1.855 +
   1.856 +    return status;
   1.857 +}
   1.858 +
   1.859 +/************************************************************************/
   1.860 +
   1.861 +// escape every occurrence of the double quote character in the string
   1.862 +// pointed to by buf by prepending to it the escape character specified
   1.863 +// by the last acrgument
   1.864 +// returns the new buffer if the size of the existing buffer isn't
   1.865 +// sufficient and sets *pbufsize to the size of the newly allocated
   1.866 +// buffer, otherwise the original value of buf and leaves *pbufsize
   1.867 +// unchanged
   1.868 +static char*
   1.869 +_rw_escape (char *buf, size_t bufsize, char esc)
   1.870 +{
   1.871 +    // handle null buffer
   1.872 +    if (0 == buf)
   1.873 +        return buf;
   1.874 +
   1.875 +    // count the number of embedded quotes
   1.876 +    char *quote = buf;
   1.877 +    size_t nquotes = 0;
   1.878 +    
   1.879 +    #ifdef __ARMCC__
   1.880 +    #pragma diag_suppress 1293
   1.881 +    #endif
   1.882 +    while ((quote = strchr (quote, '"'))) {
   1.883 +        ++nquotes;
   1.884 +        ++quote;
   1.885 +    }
   1.886 +    
   1.887 +
   1.888 +    // no quotes found, return the original buffer
   1.889 +    if (0 == nquotes)
   1.890 +        return buf;
   1.891 +
   1.892 +    // conpute the size of the buffer that will be needed to escape
   1.893 +    // all the double quotes
   1.894 +    size_t newbufsize = strlen (buf) + nquotes + 1;
   1.895 +
   1.896 +    char *newbuf = 0;
   1.897 +
   1.898 +    if (0 /* newbufsize <= bufsize */) {
   1.899 +        // FIXME: escape embedded quotes in place w/o reallocation
   1.900 +        _RWSTD_UNUSED (bufsize);
   1.901 +    }
   1.902 +    else {
   1.903 +        newbuf = (char*)malloc (newbufsize);
   1.904 +        if (0 == newbuf) {
   1.905 +            return 0;
   1.906 +        }
   1.907 +
   1.908 +        // set the next pointer to the beginning of the new buffer
   1.909 +        // as the destination where to copy the string argument
   1.910 +        char *next = newbuf;
   1.911 +
   1.912 +        // set quote to initially point to the beginning of
   1.913 +        // the source buffer and then just past the last quote
   1.914 +        quote = buf;
   1.915 +
   1.916 +        for (char *q = buf; ; ++q) {
   1.917 +
   1.918 +            // look for the next (or first) quote
   1.919 +            q = strchr (q, '"');
   1.920 +
   1.921 +            // compute the number of characters, excluding the quote
   1.922 +            // to copy to the destination buffer
   1.923 +            const size_t nchars = q ? size_t (q - quote) : strlen (quote);
   1.924 +
   1.925 +            memcpy (next, quote, nchars);
   1.926 +
   1.927 +            if (q) {
   1.928 +                // append the escape character to the destination buffer
   1.929 +                next [nchars] = esc;
   1.930 +
   1.931 +                // append the quote from the source string
   1.932 +                next [nchars + 1] = '"';
   1.933 +
   1.934 +                // advance the destination pointer past the quote
   1.935 +                next += nchars + 2;
   1.936 +
   1.937 +                // advance the source pointer past the embedded quote
   1.938 +                quote = q + 1;
   1.939 +            }
   1.940 +            else {
   1.941 +                // NUL-terminate the destination buffer
   1.942 +                *next = '\0';
   1.943 +                break;
   1.944 +            }
   1.945 +        }
   1.946 +    }
   1.947 +
   1.948 +    return newbuf;
   1.949 +}
   1.950 +
   1.951 +/************************************************************************/
   1.952 +
   1.953 +static void
   1.954 +_rw_vissue_diag (diag_t diag, int severity, const char *file, int line,
   1.955 +                 const char *fmt, va_list va)
   1.956 +{
   1.957 +    CHECK_INIT (true, "_rw_vissue_diag()");
   1.958 +
   1.959 +    if (0 == fmt)
   1.960 +        fmt = "";
   1.961 +
   1.962 +    static char fmterr[] = "*** formatting error ***";
   1.963 +
   1.964 +    char *usrbuf = 0;
   1.965 +    const int nchars = rw_vasnprintf (&usrbuf, 0, fmt, va);
   1.966 +
   1.967 +    if (nchars < 0 || 0 == usrbuf)
   1.968 +        usrbuf = fmterr;
   1.969 +
   1.970 +    // compute the number of newline characters in the text
   1.971 +    int nlines = 0;
   1.972 +    
   1.973 +    #ifdef __ARMCC__
   1.974 +    #pragma diag_suppress 1293
   1.975 +    #endif
   1.976 +    for (const char *nl = usrbuf; (nl = strchr (nl, '\n')); ++nl)
   1.977 +        ++nlines;
   1.978 +    
   1.979 +
   1.980 +    static const int use_color = _rw_use_color ();
   1.981 +
   1.982 +    const char* const diagstr[] = {
   1.983 +        use_color ? diag_msgs [severity].esc_pfx : "",
   1.984 +        *diag_msgs [severity].code ? diag_msgs [severity].code : "UNKNOWN",
   1.985 +        use_color  ? diag_msgs [severity].esc_sfx : "",
   1.986 +        _rw_opt_verbose (0, 0) && *diag_msgs [severity].desc ?
   1.987 +        diag_msgs [severity].desc : 0
   1.988 +    };
   1.989 +
   1.990 +    const char* const traced_diag =
   1.991 +        0 == severity && diag_msgs [diag].code ? diag_msgs [diag].code : 0;
   1.992 +
   1.993 +    const char* const slash = file ? strrchr (file, _RWSTD_PATH_SEP) : 0;
   1.994 +    if (slash)
   1.995 +        file = slash + 1;
   1.996 +
   1.997 +    char *mybuf = 0;
   1.998 +
   1.999 +    if (_rw_opt_csv) {
  1.1000 +
  1.1001 +        // format all fields as comma separated values (CSV):
  1.1002 +        // -- a field containing the quote character, the comma,
  1.1003 +        //    or the newline or linefeed character must be enclosed
  1.1004 +        //    in a pair of double quotes
  1.1005 +        // -- every occurrence of the double quote character in a field
  1.1006 +        //    must be escaped by prepening another double quote character
  1.1007 +        //    to it
  1.1008 +
  1.1009 +        // escape all double quotes by prepending the double
  1.1010 +        // quote character to each according to the CSV format
  1.1011 +        char* const newbuf = _rw_escape (usrbuf, 0, '"');
  1.1012 +        if (newbuf != usrbuf) {
  1.1013 +            free (usrbuf);
  1.1014 +            usrbuf = newbuf;
  1.1015 +        }
  1.1016 +
  1.1017 +        mybuf =
  1.1018 +            rw_sprintfa ("%d, "                      // severity
  1.1019 +                         "\"%s%s"                    // diagnostic
  1.1020 +                         "%{?}_%s%{;}%s\", "         // traced diagnostic
  1.1021 +                         "\"%s\", "                  // clause
  1.1022 +                         "\"%s\", "                  // file
  1.1023 +                         "%d, "                      // line
  1.1024 +                         "\"%s\"",                   // user text
  1.1025 +                         severity,
  1.1026 +                         diagstr [0], diagstr [1],
  1.1027 +                         0 != traced_diag, traced_diag, diagstr [2],
  1.1028 +                         clause_id,
  1.1029 +                         0 != file ? file : "",
  1.1030 +                         line,
  1.1031 +                         usrbuf);
  1.1032 +    }
  1.1033 +    else {
  1.1034 +
  1.1035 +        nlines += 2 + ('\0' != *clause_id) + (0 != file) + (0 < line);
  1.1036 +
  1.1037 +        mybuf =
  1.1038 +            rw_sprintfa ("# %s"                      // escape prefix
  1.1039 +                         "%s"                        // diagnostic
  1.1040 +                         "%{?}_%s%{;}"               // traced diagnostic
  1.1041 +                         "%s "                       // escape suffix
  1.1042 +                         "(S%d)"                     // severity
  1.1043 +                         "%{?}, %s%{;} "             // description
  1.1044 +                         "(%d lines):\n"             // number of lines
  1.1045 +                         "# TEXT: %s\n"              // user text
  1.1046 +                         "%{?}# CLAUSE: %s\n%{;}"    // clause if not empty
  1.1047 +                         "%{?}# FILE: %s\n%{;}"      // file if not null
  1.1048 +                         "%{?}# LINE: %d\n%{;}",     // line if positive
  1.1049 +                         diagstr [0],
  1.1050 +                         diagstr [1],
  1.1051 +                         0 != traced_diag, traced_diag,
  1.1052 +                         diagstr [2],
  1.1053 +                         severity,
  1.1054 +                         0 != diagstr [3], diagstr [3],
  1.1055 +                         nlines,
  1.1056 +                         usrbuf,
  1.1057 +                         '\0' != *clause_id, clause_id,
  1.1058 +                         0 != file, file,
  1.1059 +                         0 < line, line);
  1.1060 +    }
  1.1061 +#if 0   // disabled
  1.1062 +    else {
  1.1063 +
  1.1064 +        mybuf =
  1.1065 +            rw_sprintfa ("# %s%s"                 // diagnostic
  1.1066 +                         "%{?}_%s%{;}%s "         // traced diagnostic
  1.1067 +                         "(S%d): "                // severity
  1.1068 +                         "%{?}[%s] %{;}"          // clause if not empty
  1.1069 +                         "%{?}(%d lines): %{;}"   // number of lines if > 1
  1.1070 +                         "%{?}%s:"                // if (file) then file
  1.1071 +                         "%{?}%d:%{;} "           //   if (0 < line) line
  1.1072 +                         "%{:}"                   // else
  1.1073 +                         "%{?}line %d: %{;}"      //   if (0 < line) line
  1.1074 +                         "%{;}"                   // endif
  1.1075 +                         "%s",                    // user text
  1.1076 +                         diagstr [0], diagstr [1],
  1.1077 +                         0 != traced_diag, traced_diag, diagstr [2],
  1.1078 +                         severity,
  1.1079 +                         '\0' != *clause_id, clause_id,
  1.1080 +                         1 < nlines, nlines,
  1.1081 +                         0 != file, file,
  1.1082 +                         0 < line, line,
  1.1083 +                         0 < line, line,
  1.1084 +                         usrbuf);
  1.1085 +    }
  1.1086 +#endif   // 0/1
  1.1087 +
  1.1088 +    fprintf (ftestout, "%s\n", mybuf);
  1.1089 +
  1.1090 +    if (mybuf != fmterr)
  1.1091 +        free (mybuf);
  1.1092 +
  1.1093 +    if (usrbuf != fmterr)
  1.1094 +        free (usrbuf);
  1.1095 +}
  1.1096 +
  1.1097 +/************************************************************************/
  1.1098 +
  1.1099 +static void
  1.1100 +_rw_vdiag (diag_t diag, int severity, const char *file, int line,
  1.1101 +           const char *fmt, va_list va)
  1.1102 +{
  1.1103 +    CHECK_INIT (true, "_rw_vdiag()");
  1.1104 +
  1.1105 +    // check if the diagnostic is expected
  1.1106 +    const int expected = 0 != _rw_expected (line);
  1.1107 +
  1.1108 +    if (expected) {
  1.1109 +        if (severity) {
  1.1110 +            // if the diagnostic is expected to be active,
  1.1111 +            // adjust its type and severity
  1.1112 +            if (diag_assert == diag)
  1.1113 +                diag = diag_xassert;
  1.1114 +            else if (diag_warn == diag)
  1.1115 +                diag = diag_xwarn;
  1.1116 +
  1.1117 +            severity = diag * severity;
  1.1118 +        }
  1.1119 +        else {
  1.1120 +            // if the diagnostic is expected to be active but isn't,
  1.1121 +            // adjust its type to an unexpectdly inactive one
  1.1122 +            if (diag_assert == diag || diag_warn == diag)
  1.1123 +                diag = diag_expect;
  1.1124 +
  1.1125 +            severity = diag;
  1.1126 +        }
  1.1127 +    }
  1.1128 +    else if (diag) {
  1.1129 +        // normalize the severity
  1.1130 +        severity = diag * severity;
  1.1131 +    }
  1.1132 +
  1.1133 +    if (severity < 0)
  1.1134 +        severity = 0;
  1.1135 +    else if (N_DIAG_TYPES <= severity)
  1.1136 +        severity = N_DIAG_TYPES - 1;
  1.1137 +
  1.1138 +    // increment the diagnostic counter
  1.1139 +    ++ndiags [diag][0];
  1.1140 +
  1.1141 +    if (severity) {
  1.1142 +
  1.1143 +        ++ndiags [diag][1];
  1.1144 +    }
  1.1145 +
  1.1146 +    const int sevbit = (1 << severity);
  1.1147 +
  1.1148 +    if (0 == (sevbit & _rw_diag_mask)) {
  1.1149 +        // issue the diagnostic
  1.1150 +        _rw_vissue_diag (diag, severity, file, line, fmt, va);
  1.1151 +    }
  1.1152 +
  1.1153 +    if (diag_fatal == diag && severity) {
  1.1154 +        // fatal error, terminate test
  1.1155 +        longjmp (test_env, severity);
  1.1156 +    }
  1.1157 +}
  1.1158 +
  1.1159 +/************************************************************************/
  1.1160 +
  1.1161 +_TEST_EXPORT int
  1.1162 +rw_fatal (int success, const char *file, int line, const char *fmt, ...)
  1.1163 +{
  1.1164 +    CHECK_INIT (true, "rw_fatal()");
  1.1165 +
  1.1166 +    va_list va;
  1.1167 +    va_start (va, fmt);
  1.1168 +
  1.1169 +    _rw_vdiag (diag_fatal, 0 == success, file, line, fmt, va);
  1.1170 +
  1.1171 +    va_end (va);
  1.1172 +
  1.1173 +    return success;
  1.1174 +}
  1.1175 +
  1.1176 +/************************************************************************/
  1.1177 +
  1.1178 +_TEST_EXPORT int
  1.1179 +rw_error (int success, const char *file, int line, const char *fmt, ...)
  1.1180 +{
  1.1181 +    CHECK_INIT (true, "rw_error()");
  1.1182 +
  1.1183 +    va_list va;
  1.1184 +    va_start (va, fmt);
  1.1185 +
  1.1186 +    _rw_vdiag (diag_error, 0 == success, file, line, fmt, va);
  1.1187 +
  1.1188 +    va_end (va);
  1.1189 +
  1.1190 +    return success;
  1.1191 +}
  1.1192 +
  1.1193 +/************************************************************************/
  1.1194 +
  1.1195 +_TEST_EXPORT int
  1.1196 +rw_assert (int success, const char *file, int line, const char *fmt, ...)
  1.1197 +{
  1.1198 +    CHECK_INIT (true, "rw_assert()");
  1.1199 +
  1.1200 +    va_list va;
  1.1201 +    va_start (va, fmt);
  1.1202 +
  1.1203 +    _rw_vdiag (diag_assert, 0 == success, file, line, fmt, va);
  1.1204 +
  1.1205 +    va_end (va);
  1.1206 +
  1.1207 +    return success;
  1.1208 +}
  1.1209 +
  1.1210 +/************************************************************************/
  1.1211 +
  1.1212 +_TEST_EXPORT int
  1.1213 +rw_warn (int success, const char *file, int line, const char *fmt, ...)
  1.1214 +{
  1.1215 +    CHECK_INIT (true, "rw_warn()");
  1.1216 +
  1.1217 +    va_list va;
  1.1218 +    va_start (va, fmt);
  1.1219 +
  1.1220 +    _rw_vdiag (diag_warn, 0 == success, file, line, fmt, va);
  1.1221 +
  1.1222 +    va_end (va);
  1.1223 +
  1.1224 +    return success;
  1.1225 +}
  1.1226 +
  1.1227 +/************************************************************************/
  1.1228 +
  1.1229 +_TEST_EXPORT int
  1.1230 +rw_note (int success, const char *file, int line, const char *fmt, ...)
  1.1231 +{
  1.1232 +    CHECK_INIT (true, "rw_note()");
  1.1233 +
  1.1234 +    va_list va;
  1.1235 +    va_start (va, fmt);
  1.1236 +
  1.1237 +    _rw_vdiag (diag_note, 0 == success, file, line, fmt, va);
  1.1238 +
  1.1239 +    va_end (va);
  1.1240 +
  1.1241 +    return success;
  1.1242 +}
  1.1243 +
  1.1244 +/************************************************************************/
  1.1245 +
  1.1246 +_TEST_EXPORT int
  1.1247 +rw_info (int success, const char *file, int line, const char *fmt, ...)
  1.1248 +{
  1.1249 +    CHECK_INIT (true, "rw_info()");
  1.1250 +
  1.1251 +    va_list va;
  1.1252 +    va_start (va, fmt);
  1.1253 +
  1.1254 +    _rw_vdiag (diag_info, 0 == success, file, line, fmt, va);
  1.1255 +
  1.1256 +    va_end (va);
  1.1257 +
  1.1258 +    return success;
  1.1259 +}