os/ossrv/stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/driver.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /************************************************************************
     2  *
     3  * driver.cpp - definitions of the test driver
     4  *
     5  * $Id: driver.cpp 290009 2005-09-18 23:28:26Z sebor $
     6  *
     7  ************************************************************************
     8  *
     9  * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
    10  * Software division. Licensed under the Apache License, Version 2.0 (the
    11  * "License");  you may  not use this file except  in compliance with the
    12  * License.    You    may   obtain   a   copy   of    the   License    at
    13  * http://www.apache.org/licenses/LICENSE-2.0.    Unless   required    by
    14  * applicable law  or agreed to  in writing,  software  distributed under
    15  * the License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR
    16  * CONDITIONS OF  ANY KIND, either  express or implied.  See  the License
    17  * for the specific language governing permissions  and limitations under
    18  * the License.
    19  *
    20  **************************************************************************/
    21 
    22 // expand _TEST_EXPORT macros
    23 #define _RWSTD_TEST_SRC
    24 
    25 #include "opt_diags.h"
    26 #include "opt_lines.h"
    27 #include "opt_trace.h"
    28 #include "opt_types.h"
    29 
    30 #include <cmdopt.h>    // for rw_setopts()
    31 #include <printf.h>    // for rw_snprintfa()
    32 
    33 #include <assert.h>    // for assert
    34 #include <setjmp.h>    // for longjmp, setjmp, ...
    35 #include <stdarg.h>    // for va_list
    36 #include <stdio.h>     // for fileno, fprintf
    37 #include <stdlib.h>    // for free
    38 #include <string.h>    // for strchr, strcpy
    39 #include"std_log_result.h"
    40 #define LOG_FILENAME_LINE __FILE__, __LINE__
    41 #if !defined (_WIN32) && !defined (_WIN64)
    42 #  include <unistd.h>    // for isatty
    43 
    44 // declare fileno in case it's not declared (for strict ANSI conformance)
    45 extern "C" {
    46 
    47 IMPORT_C int (fileno)(FILE*) _LIBC_THROWS ();
    48 
    49 }   // extern "C"
    50 
    51 #else
    52    // no isatty on Windoze
    53 #  define _RWSTD_NO_ISATTY
    54 #endif   // _WIN{32,64}
    55 
    56 // expand _TEST_EXPORT macros
    57 #define _RWSTD_TEST_SRC
    58 #include <driver.h>
    59 
    60 /************************************************************************/
    61 
    62 #define RW_TEST_STRSTR(x)   #x
    63 #define RW_TEST_STR(x)      RW_TEST_STRSTR(x)
    64 
    65 #ifndef RW_TEST_COMPILER
    66 #  if defined (__DECCXX__)
    67 #    define RW_TEST_COMPILER "Compaq C++, __DECCXX__ = " \
    68             RW_TEST_STR (__DECCXX__)
    69 #  elif defined (__INTEL_COMPILER)
    70 #    if defined (__EDG_VERSION__)
    71 #      define RW_TEST_ICC_EDG_VER \
    72               ", __EDG_VERSION__ = "  RW_TEST_STR (__EDG_VERSION__)
    73 #    else
    74 #      define RW_TEST_ICC_EDG_VER ""
    75 #    endif
    76 #    if defined (_MSC_VER)
    77 #      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
    78               RW_TEST_STR (__INTEL_COMPILER) ", _MSC_VER = " \
    79               RW_TEST_STR (_MSC_VER) \
    80               RW_TEST_ICC_EDG_VER
    81 #    elif defined (__INTEL_COMPILER_BUILD_DATE)
    82 #      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
    83               RW_TEST_STR (__INTEL_COMPILER) \
    84               ", __INTEL_COMPILER_BUILD_DATE = " \
    85               RW_TEST_STR (__INTEL_COMPILER_BUILD_DATE) \
    86               RW_TEST_ICC_EDG_VER
    87 #    else
    88 #      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
    89               RW_TEST_STR (__INTEL_COMPILER) \
    90               RW_TEST_ICC_EDG_VER
    91 #    endif
    92 #  elif defined (__GNUC__)
    93 #    if defined (__VERSION__)
    94 #      define RW_TEST_GCC_VER ", __VERSION__ = \"" __VERSION__ "\""
    95 #    else
    96 #      define RW_TEST_GCC_VER ""
    97 #    endif
    98 #    if defined (__GNUC_PATCHLEVEL__)
    99 #      define RW_TEST_COMPILER "gcc "            \
   100               RW_TEST_STR (__GNUC__) "."         \
   101               RW_TEST_STR (__GNUC_MINOR__) "."   \
   102               RW_TEST_STR (__GNUC_PATCHLEVEL__)  \
   103               RW_TEST_GCC_VER
   104 #    else
   105 #      define RW_TEST_COMPILER "gcc " \
   106               RW_TEST_STR (__GNUC__) "." RW_TEST_STR (__GNUC_MINOR__) 
   107               RW_TEST_GCC_VER
   108 #    endif
   109 #  elif defined (_COMPILER_VERSION) && defined (__sgi)
   110 #    define RW_TEST_COMPILER "SGI MIPSpro, _COMPILER_VERSION = " \
   111             RW_TEST_STR (_COMPILER_VERSION)
   112 #  elif defined (__INTEL_COMPILER)
   113 #    if defined (_MSC_VER)
   114 #      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
   115               RW_TEST_STR (__INTEL_COMPILER) ", _MSC_VER = " \
   116               RW_TEST_STR (_MSC_VER)
   117 #    else
   118 #      define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
   119               RW_TEST_STR (__INTEL_COMPILER)
   120 #    endif
   121 #  elif defined (__EDG__)
   122 #    define RW_TEST_COMPILER "EDG eccp, __EDG_VERSION__ = " \
   123             RW_TEST_STR (__EDG_VERSION__)
   124 #  elif defined (__HP_aCC)
   125 #    define RW_TEST_COMPILER "HP aCC, __HP_aCC = " \
   126             RW_TEST_STR (__HP_aCC)
   127 #  elif defined (__IBMCPP__)
   128 #    define RW_TEST_COMPILER "IBM VisualAge C++, __IBMCPP__ = " \
   129             RW_TEST_STR (__IBMCPP__)
   130 #  elif defined (_MSC_VER)
   131 #    define RW_TEST_COMPILER "MSVC, _MSC_VER = " \
   132             RW_TEST_STR (_MSC_VER)
   133 #  elif defined (__SUNPRO_CC)
   134 #    define RW_TEST_COMPILER "SunPro, __SUNPRO_CC = " \
   135             RW_TEST_STR (__SUNPRO_CC)
   136 #  else
   137 #    define RW_TEST_COMPILER "unknown"
   138 #  endif
   139 #endif
   140 
   141 #ifndef RW_TEST_LIBSTD
   142 #  ifdef _RWSTD_VER
   143 #    define RW_TEST_LIBSTD "Rogue Wave C++ Standard Library, " \
   144             "_RWSTD_VER = " RW_TEST_STR (_RWSTD_VER)
   145 #  elif defined (__GLIBCXX__)
   146 #    define RW_TEST_LIBSTD "GNU C++ Standard Library, " \
   147             "__GLIBCXX__ = " \
   148             RW_TEST_STR (__GLIBCXX__)
   149 #  elif defined (_STLPORT_VERSION)
   150      // check for STLport before SGI STL since STLport,
   151      // being derived from SGI STL, #defines both macros
   152 #    define RW_TEST_LIBSTD "STLport, " \
   153             "_STLPORT_VERSION = " \
   154             RW_TEST_STR (_STLPORT_VERSION)
   155 #  elif defined (__SGI_STL)
   156 #    define RW_TEST_LIBSTD "SGI STL, " \
   157             "__SGI_STL = " \
   158             RW_TEST_STR (__SGI_STL)
   159 #  elif defined (_YVALS)
   160      // is there a better way to identify the Dinkumware
   161      // implementation? does it have a version macro?
   162 #    define RW_TEST_LIBSTD "Dinkum C++ Standard Library"
   163 #  endif
   164 #endif   // RW_TEST_LIBSTD
   165 
   166 #ifndef RW_TEST_HARDWARE
   167 #  if defined (__alpha__) || defined (__alpha)
   168 #    define RW_TEST_ARCH "alpha"
   169 #  elif defined (__amd64__) || defined (__amd64)
   170 #    if defined (__LP64__) || defined (_LP64)
   171 #      define RW_TEST_ARCH "amd64/LP64"
   172 #    else
   173 #      define RW_TEST_ARCH "amd64/ILP32"
   174 #    endif
   175 #  elif defined (_PA_RISC2_0)
   176 #    define RW_TEST_ARCH "pa-risc 2.0"
   177 #  elif defined (_PA_RISC1_0)
   178 #    define RW_TEST_ARCH "pa-risc 1.0"
   179 #  elif defined (__hppa)
   180 #    define RW_TEST_ARCH "pa-risc"
   181 #  elif defined (__pentiumpro__) || defined (__pentiumpro)
   182 #    define RW_TEST_ARCH "pentiumpro"
   183 #  elif defined (__pentium__) || defined (__pentium)
   184 #    define RW_TEST_ARCH "pentium"
   185 #  elif defined (__i486__) || defined (__i486)
   186 #    define RW_TEST_ARCH "i486"
   187 #  elif defined (__i386__) || defined (__i386)
   188 #    define RW_TEST_ARCH "i386"
   189 #  elif defined (__i586__) || defined (__i586)
   190 #    define RW_TEST_ARCH "i586"
   191 #  elif defined (__ia64)
   192 #    define RW_TEST_ARCH "ia64"
   193 #  elif defined (__mips)
   194 #    define RW_TEST_ARCH "mips"
   195 #  elif defined (__sparcv9)
   196 #    define RW_TEST_ARCH "sparc-v9"
   197 #  elif defined (__sparcv8)
   198 #    define RW_TEST_ARCH "sparc-v8"
   199 #  elif defined (__sparc)
   200 #    define RW_TEST_ARCH "sparc"
   201 #  elif defined (_POWER)
   202 #    if defined (_ARCH_PWR5)
   203 #      define RW_TEST_ARCH "power-5"
   204 #    elif defined (_ARCH_PWR4)
   205 #      define RW_TEST_ARCH "power-4"
   206 #    elif defined (_ARCH_PWR3)
   207 #      define RW_TEST_ARCH "power-3"
   208 #    elif defined (_ARCH_604)
   209 #      define RW_TEST_ARCH "powerpc-604"
   210 #    elif defined (_ARCH_603)
   211 #      define RW_TEST_ARCH "powerpc-603"
   212 #    elif defined (_ARCH_602)
   213 #      define RW_TEST_ARCH "powerpc-602"
   214 #    elif defined (_ARCH_601)
   215 #      define RW_TEST_ARCH "powerpc-601"
   216 #    elif defined (_ARCH_403)
   217 #      define RW_TEST_ARCH "powerpc-403"
   218 #    elif defined (_ARCH_PPC64)
   219 #      define RW_TEST_ARCH "powerpc/LP64"
   220 #    else
   221 #      define RW_TEST_ARCH "powerpc"
   222 #    endif
   223 #  elif defined (_WIN64)
   224 #    define RW_TEST_ARCH "ia64"
   225 #  elif defined (_WIN32)
   226 #    define RW_TEST_ARCH "i86"
   227 #  elif defined (__x86_64__) || defined (__x86_64)
   228 #    if defined (__LP64__) || defined (_LP64)
   229 #      define RW_TEST_ARCH "x86_64/LP64"
   230 #    else
   231 #      define RW_TEST_ARCH "x86_64/ILP32"
   232 #    endif
   233 #  else
   234 #    define RW_TEST_ARCH "unknown"
   235 #  endif
   236 
   237 
   238 #  if defined (_AIX54)
   239 #    define RW_TEST_OS "aix-5.4 (or better)"
   240 #  elif defined (_AIX53)
   241 #    define RW_TEST_OS "aix-5.3"
   242 #  elif defined (_AIX52)
   243 #    define RW_TEST_OS "aix-5.2"
   244 #  elif defined (_AIX51)
   245 #    define RW_TEST_OS "aix-5.1"
   246 #  elif defined (_AIX50)
   247 #    define RW_TEST_OS "aix-5.0"
   248 #  elif defined (_AIX43)
   249 #    define RW_TEST_OS "aix-4.3"
   250 #  elif defined (_AIX41)
   251 #    define RW_TEST_OS "aix-4.1"
   252 #  elif defined (_AIX32)
   253 #    define RW_TEST_OS "aix-3.2"
   254 #  elif defined (_AIX)
   255 #    define RW_TEST_OS "aix"
   256 #  elif defined (__hpux)
   257 #    define RW_TEST_OS "hp-ux"
   258 #  elif defined (__osf__)
   259 #    define RW_TEST_OS "tru64-unix"
   260 #  elif defined (__sgi) && defined (__mips)
   261 #    define RW_TEST_OS "irix"
   262 #  elif defined (__linux__) || defined (__linux)
   263 
   264      // get Linux release string (UTS_RELEASE)
   265 #    include <linux/version.h>
   266 
   267 #    ifndef UTS_RELEASE
   268 #      define UTS_RELEASE "(unknown release)"
   269 #    endif   // UTS_RELEASE
   270 
   271 #    if defined (__ELF__)
   272 #      define LINUX_TYPE "linux-elf"
   273 #    else
   274 #      define LINUX_TYPE "linux"
   275 #    endif
   276 
   277 #    define RW_TEST_OS LINUX_TYPE " "     \
   278             UTS_RELEASE " with glibc "    \
   279             RW_TEST_STR (__GLIBC__) "."   \
   280             RW_TEST_STR (__GLIBC_MINOR__)
   281 
   282 #  elif defined (__SunOS_5_10)
   283 #    define RW_TEST_OS "sunos-5.10"
   284 #  elif defined (__SunOS_5_9)
   285 #    define RW_TEST_OS "sunos-5.9"
   286 #  elif defined (__SunOS_5_8)
   287 #    define RW_TEST_OS "sunos-5.8"
   288 #  elif defined (__SunOS_5_7)
   289 #    define RW_TEST_OS "sunos-5.7"
   290 #  elif defined (__SunOS_5_6)
   291 #    define RW_TEST_OS "sunos-5.6"
   292 #  elif defined (__sun__)
   293 #    define RW_TEST_OS "sunos"
   294 #  elif defined (_WIN64)
   295 #    define RW_TEST_OS "win64"
   296 #  elif defined (_WIN32)
   297 #    define RW_TEST_OS "win32"
   298 #  else
   299 #    define RW_TEST_OS "unknown"
   300 #  endif
   301 
   302 #  define RW_TEST_HARDWARE RW_TEST_ARCH " running " RW_TEST_OS
   303 #else
   304 #  define RW_TEST_HARDWARE "unknown"
   305 #endif
   306 
   307 /************************************************************************/
   308 
   309 // defined in printf.cpp but not declared in printf.h
   310 _TEST_EXPORT int
   311 rw_vasnprintf (char**, size_t*, const char*, va_list);
   312 
   313 /************************************************************************/
   314 
   315 // array to store the number of each type of diagnostic
   316 static int
   317 ndiags [N_DIAG_TYPES][2] /* = { { total, active }, ... }*/;
   318 
   319 static FILE *ftestout;
   320 
   321 static jmp_buf test_env;
   322 
   323 // set to 1 after the driver has been initialized
   324 static int driver_initialized = 0;
   325 
   326 // set to 1 after the driver has finished running
   327 static int driver_finished = 0;
   328 
   329 #if 0   // disabled
   330 // %S: severity
   331 // %M: diagnostic
   332 // %m: diagnostic if not empty
   333 // %F: file name
   334 // %f: file name if not empty
   335 // %C: clause
   336 // %c: clause if not empty
   337 // %L: line number
   338 // %l: line number if valid
   339 // %T: text
   340 // %t: text if not empty
   341 static char diag_pattern [80];
   342 #endif
   343 
   344 // option: use CSV format (comma separated values)
   345 static int _rw_opt_csv = 0;
   346 
   347 static char clause_id [80];
   348 
   349 /************************************************************************/
   350 
   351 #define CHECK_INIT(init, func)   _rw_check_init (init, __LINE__, func)
   352 
   353 static inline void
   354 _rw_check_init (bool init, int line, const char *func)
   355 {
   356     if (init && !driver_initialized) {
   357         fprintf (stderr, "%s:%d: %s: test driver already initialized\n",
   358                  __FILE__, line, func);
   359      std_log(LOG_FILENAME_LINE,"%s:%d: %s: test driver already initialized\n",
   360                  __FILE__, line, func);                 
   361         abort ();
   362     }
   363 
   364     if (!init && driver_initialized) {
   365         fprintf (stderr, "%s:%d: %s: test driver not initialized yet\n",
   366                  __FILE__, line, func);
   367       std_log(LOG_FILENAME_LINE,"%s:%d: %s: test driver not initialized yet\n",
   368                  __FILE__, line, func);                  
   369         abort ();
   370     }
   371 
   372     if (driver_finished) {
   373         fprintf (stderr, "%s:%d: %s: test finished, cannot call\n",
   374                  __FILE__, line, func);
   375      std_log(LOG_FILENAME_LINE,"%s:%d: %s: test finished, cannot call\n",
   376                  __FILE__, line, func);                 
   377     }
   378 }
   379 
   380 /************************************************************************/
   381 
   382 static int
   383 _rw_opt_brief (int argc, char *argv[])
   384 {
   385     static int opt_brief;
   386 
   387     if (0 == argc) {
   388         // query mode: return the value of the option
   389         return opt_brief;
   390     }
   391 
   392     if (1 == argc && argv && 0 == argv [0]) {
   393         // help mode: set argv[0] to the text of the help message
   394 
   395         static const char helpstr[] = {
   396             "Enables brief mode.\n"
   397         };
   398 
   399         argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   400 
   401         return 0;
   402     }
   403 
   404     // set mode: enable the option
   405     opt_brief = 1;
   406 
   407     return 0;
   408 }
   409 
   410 /************************************************************************/
   411 
   412 static int
   413 _rw_opt_quiet (int argc, char *argv[])
   414 {
   415     static int opt_quiet;
   416 
   417     if (0 == argc) {
   418         // query mode: return the value of the option
   419         return opt_quiet;
   420     }
   421 
   422     if (1 == argc && argv && 0 == argv [0]) {
   423         // help mode: set argv[0] to the text of the help message
   424 
   425         static const char helpstr[] = {
   426             "Enables quiet mode.\n"
   427             "In quiet mode only diagnostics with severity 7 and above are "
   428             "issued."
   429         };
   430 
   431         argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   432 
   433         return 0;
   434     }
   435 
   436     // set mode: enable the option
   437     _rw_diag_mask = ~((1 << 7) | (1 << 8) | (1 << 9));
   438     opt_quiet     = 1;
   439 
   440     return 0;
   441 }
   442 
   443 /************************************************************************/
   444 
   445 static int
   446 _rw_opt_verbose (int argc, char *argv[])
   447 {
   448     static int opt_verbose;
   449 
   450     if (0 == argc) {
   451         // query mode: return the value of the option
   452         return opt_verbose;
   453     }
   454 
   455     if (1 == argc && argv && 0 == argv [0]) {
   456         // help mode: set argv[0] to the text of the help message
   457 
   458         static const char helpstr[] = {
   459             "Enables verbose mode.\n"
   460         };
   461 
   462         argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   463 
   464         return 0;
   465     }
   466 
   467     // set mode: enable the option
   468     opt_verbose = 1;
   469 
   470     return 0;
   471 }
   472 
   473 /************************************************************************/
   474 
   475 static int
   476 _rw_setopt_csv (int argc, char *argv[])
   477 {
   478     if (1 == argc && argv && 0 == argv [0]) {
   479         static const char helpstr[] = {
   480             "Enables CSV (comma separated values) mode.\n"
   481         };
   482 
   483         argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   484 
   485         return 0;
   486     }
   487 
   488     _rw_opt_csv = 1;
   489     return 0;
   490 }
   491 
   492 /************************************************************************/
   493 
   494 static int
   495 _rw_opt_compat (int argc, char *argv[])
   496 {
   497     static int opt_compat;
   498 
   499     if (0 == argc) {
   500         // query mode: return the value of the option
   501         return opt_compat;
   502     }
   503 
   504     if (1 == argc && argv && 0 == argv [0]) {
   505         // help mode: set argv[0] to the text of the help message
   506 
   507         static const char helpstr[] = {
   508             "Enables RWTest-format compatibility mode.\n"
   509         };
   510 
   511         argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   512 
   513         return 0;
   514     }
   515 
   516     // set mode: enable the option
   517     opt_compat = 1;
   518 
   519     return 0;
   520 }
   521 
   522 /************************************************************************/
   523 
   524 static int
   525 _rw_opt_no_stdout (int argc, char *argv[])
   526 {
   527     static int opt_no_stdout;
   528 
   529     if (0 == argc) {
   530         // query mode: return the value of the option
   531         return opt_no_stdout;
   532     }
   533 
   534     if (1 == argc && argv && 0 == argv [0]) {
   535         // help mode: set argv[0] to the text of the help message
   536 
   537         static const char helpstr[] = {
   538             "Prevents the program from using stdandard output for diagnostic\n"
   539             "messages. Instead, the driver will create a log file with a name\n"
   540             "obtained from the from the basename of the program source file,\n"
   541             "usually obtained by passing the value of the __FILE__ macro to\n"
   542             "the driver, with the .out extension. If successful, the driver\n"
   543             "will write all diagnostic messages issued by the program to this\n"
   544             "file. Otherwise, the driver exits with an error.\n"
   545         };
   546 
   547         argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   548 
   549         return 0;
   550     }
   551     
   552     // set mode: enable the option
   553     opt_no_stdout = 1;
   554 
   555     return 0;
   556 }
   557 
   558 /************************************************************************/
   559 
   560 static int
   561 _rw_setopt_output_file (int argc, char *argv[])
   562 {
   563     if (1 == argc && argv && 0 == argv [0]) {
   564         static const char helpstr[] = {
   565             "Specifies the name of the output file to be used by the program\n"
   566             "for diagnostic messages. Unless this option is specified, the\n"
   567             "program will issue all diagnostic messages to the standard output."
   568             "\nDriver diagnostics are always directed to stderr.\n"
   569         };
   570 
   571         argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
   572 
   573         return 0;
   574     }
   575 
   576     const char *file_name = 0;
   577 
   578     if ('-' == argv [0][0] && 'O' == argv [0][1] || 'o' == argv [0][1]) {
   579         file_name = argv [0] + 2;
   580     }
   581     else if (1 < argc && '-' != argv [1][0]) {
   582         file_name = argv [1];
   583     }
   584 
   585     if (file_name) {
   586 
   587         FILE* const f = fopen (file_name, "w");
   588 
   589         if (f) {
   590             if (ftestout && ftestout != stderr)
   591                 fclose (ftestout);
   592 
   593             ftestout = f;
   594         }
   595     }
   596 
   597     // return 0 on success, any non-zero value on failure
   598     return !(ftestout != 0);
   599 }
   600 
   601 /************************************************************************/
   602 
   603 _TEST_EXPORT int
   604 rw_vsetopts (const char *opts, va_list va);
   605 
   606 /************************************************************************/
   607 
   608 static int
   609 _rw_use_color ()
   610 {
   611 #ifndef _RWSTD_NO_ISATTY
   612 
   613     // is output sent to a terminal?
   614     // if so, assume a vt100 compatible terminal for now
   615     static const int tty = isatty (fileno (ftestout));
   616 
   617 #else   // if defined (_RWSTD_NO_ISATTY)
   618 
   619     // FIXME: deal with a missing isatty() and Windows
   620     static const int tty = 0;
   621 
   622 #endif   // _RWSTD_NO_ISATTY
   623 
   624     return 0 != tty;
   625 }
   626 
   627 /************************************************************************/
   628 
   629 _TEST_EXPORT int
   630 rw_vtest (int argc, char **argv,
   631           const char *file_name,
   632           const char *clause,
   633           const char *comment,
   634           int (*fun)(int, char**),
   635           const char *optstr,
   636           va_list     va)
   637 {
   638     CHECK_INIT (false, "rw_vtest()");
   639 
   640     driver_initialized = 1;
   641 
   642     if (optstr && 0 > rw_vsetopts (optstr, va)) {
   643         fprintf (stderr, "%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   644         std_log(LOG_FILENAME_LINE,"%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   645         return 1;
   646     }
   647 
   648     const int nopts =
   649         rw_setopts ("|-no-stdout "
   650                     "|-diags= "      // argument required
   651                     "|-trace "
   652                     "|-severity= "   // argument required
   653                     "|-csv "
   654                     "|-compat "
   655                     "o|-output:"     // argument optional
   656                     "b|-brief "
   657                     "q|-quiet "
   658                     "v|-verbose",
   659                     _rw_opt_no_stdout,
   660                     _rw_setopt_diags,
   661                     _rw_setopt_trace,
   662                     _rw_setopt_trace_mask,
   663                     _rw_setopt_csv,
   664                     _rw_opt_compat,
   665                     _rw_setopt_output_file,
   666                     _rw_opt_brief,
   667                     _rw_opt_quiet,
   668                     _rw_opt_verbose,
   669                     0);
   670 
   671     if (3 > nopts) {
   672         fprintf (stderr, "%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   673         std_log(LOG_FILENAME_LINE,"%s:%d: rw_setopts() failed\n", __FILE__, __LINE__);
   674         abort ();
   675         return 1;
   676     }
   677 
   678 #ifndef _RWSTD_USE_CONFIG
   679 
   680     // enable RWTest-format compatibility mode
   681     _rw_opt_compat (1, 0);
   682 
   683     // disable output to stdout
   684     _rw_opt_no_stdout (1, 0);
   685 
   686 #endif   // _RWSTD_USE_CONFIG
   687 
   688     _rw_setopts_types ();
   689 
   690     _rw_setopts_lines ();
   691 
   692     int status = rw_runopts (argc, argv);
   693 
   694     if (status)
   695         return status;
   696 
   697     if (0 == ftestout) {
   698 
   699         if (_rw_opt_no_stdout (0, 0) && file_name) {
   700             char fname [256] = "C:\\";
   701             
   702             char* temp_ret = strchr (file_name, '/');
   703             
   704             if(temp_ret != NULL)
   705             {    
   706              const char* const slash = strrchr (file_name, '/');
   707 
   708              strcat (fname, slash ? slash + 1 : file_name);
   709             }
   710             else
   711             {    
   712              const char* const slash = strrchr (file_name, _RWSTD_PATH_SEP);
   713 
   714              strcat (fname, slash ? slash + 1 : file_name);
   715             }
   716             
   717             char* const dot = strchr (fname, '.');
   718             if (dot)
   719                 strcpy (dot, ".out");
   720             else
   721                 strcat (fname, ".out");
   722 
   723             ftestout = fopen (fname, "w");
   724         }
   725         else
   726             ftestout = stdout;
   727     }
   728 
   729     if (clause)
   730         strcpy (clause_id, clause);
   731 
   732     const char begin_fmt[] = {
   733         "\n"
   734         "# COMPILER: %s\n"
   735         "# ENVIRONMENT: %s\n"
   736         "# FILE: %s\n"
   737         "# COMPILED: %s, %s\n"
   738         "# COMMENT: %s\n"
   739         "######################################################"
   740     };
   741 
   742     const char* const fname = strrchr (file_name, _RWSTD_PATH_SEP);
   743 
   744     rw_info (0, 0, 0,
   745              begin_fmt,
   746              RW_TEST_COMPILER, RW_TEST_HARDWARE,
   747              fname ? fname + 1 : file_name,
   748              __DATE__, __TIME__,
   749              comment ? comment : "");
   750 
   751     status = setjmp (test_env);
   752 
   753     if (0 == status) {
   754         // environment set, execute the callback function
   755         status = fun (argc, argv);
   756     }
   757     else {
   758         // fatal test error (via a call to rw_fatal())
   759     }
   760 
   761     driver_finished = 1;
   762 
   763     static const char tblrow[] =
   764         "+-----------------------+--------+--------+--------+";
   765 
   766     fprintf (ftestout,
   767              "# %s\n"
   768              "# | DIAGNOSTIC            | ACTIVE |  TOTAL |INACTIVE|\n"
   769              "# %s\n",
   770              tblrow, tblrow);
   771 
   772     int nlines = 0;
   773 
   774     for (int i = 0; i != N_DIAG_TYPES; ++i) {
   775         if (ndiags [i][0] || !(_rw_diag_mask & (1 << diag_trace))) {
   776 
   777             // print out details for any non-zero totals
   778             // or for all totals when debugging or tracing
   779             // is enabled
   780 
   781             ++nlines;
   782 
   783             const long num = (ndiags [i][0] - ndiags [i][1]) * 100L;
   784             const long den = ndiags [i][0];
   785 
   786             const long pct = den ? num / den : 0;
   787 
   788             const char* pfx = "";
   789             const char* sfx = "";
   790 
   791             static int use_color = _rw_use_color ();
   792 
   793             if (use_color) {
   794                 pfx = ndiags [i][1] ? diag_msgs [i].esc_pfx : "";
   795                 sfx = ndiags [i][1] ? diag_msgs [i].esc_sfx : "";
   796             }
   797 
   798             fprintf (ftestout,
   799                      "# | (S%d) %-*s |%s %6d %s| %6d | %5ld%% |\n",
   800                      i, int (sizeof diag_msgs [i].code), diag_msgs [i].code,
   801                      pfx, ndiags [i][1], sfx, ndiags [i][0], pct);
   802         }
   803     }
   804 
   805     if (0 == nlines)
   806         fprintf (ftestout, "# no diagnostics\n");
   807 
   808     fprintf (ftestout, "# %s\n", tblrow);
   809 
   810     if (_rw_opt_compat (0, 0)) {
   811 
   812         // TO DO: get rid of this
   813 
   814         // RWTest compatibility format
   815 
   816         fprintf (ftestout,
   817                  "######################################################\n"
   818                  "## Warnings = %d\n"
   819                  "## Assertions = %d\n"
   820                  "## FailedAssertions = %d\n",
   821                  ndiags [diag_warn][1] + ndiags [diag_xwarn][1],
   822                  ndiags [diag_assert][0],
   823                  ndiags [diag_assert][1] + ndiags [diag_xassert][1]);
   824     }
   825 
   826     fclose (ftestout);
   827     ftestout = 0;
   828 
   829     return status;
   830 }
   831 
   832 /************************************************************************/
   833 
   834 _TEST_EXPORT int
   835 rw_test (int argc, char **argv,
   836          const char *fname,
   837          const char *clause,
   838          const char *comment,
   839          int (*testfun)(int, char**),
   840          const char *optstr,
   841          ...)
   842 {
   843     CHECK_INIT (false, "rw_test()");
   844 
   845     va_list va;
   846     va_start (va, optstr);
   847 
   848     const int status =
   849         rw_vtest (argc, argv, fname, clause, comment, testfun, optstr, va);
   850 
   851     va_end (va);
   852 
   853     return status;
   854 }
   855 
   856 /************************************************************************/
   857 
   858 // escape every occurrence of the double quote character in the string
   859 // pointed to by buf by prepending to it the escape character specified
   860 // by the last acrgument
   861 // returns the new buffer if the size of the existing buffer isn't
   862 // sufficient and sets *pbufsize to the size of the newly allocated
   863 // buffer, otherwise the original value of buf and leaves *pbufsize
   864 // unchanged
   865 static char*
   866 _rw_escape (char *buf, size_t bufsize, char esc)
   867 {
   868     // handle null buffer
   869     if (0 == buf)
   870         return buf;
   871 
   872     // count the number of embedded quotes
   873     char *quote = buf;
   874     size_t nquotes = 0;
   875     
   876     #ifdef __ARMCC__
   877     #pragma diag_suppress 1293
   878     #endif
   879     while ((quote = strchr (quote, '"'))) {
   880         ++nquotes;
   881         ++quote;
   882     }
   883     
   884 
   885     // no quotes found, return the original buffer
   886     if (0 == nquotes)
   887         return buf;
   888 
   889     // conpute the size of the buffer that will be needed to escape
   890     // all the double quotes
   891     size_t newbufsize = strlen (buf) + nquotes + 1;
   892 
   893     char *newbuf = 0;
   894 
   895     if (0 /* newbufsize <= bufsize */) {
   896         // FIXME: escape embedded quotes in place w/o reallocation
   897         _RWSTD_UNUSED (bufsize);
   898     }
   899     else {
   900         newbuf = (char*)malloc (newbufsize);
   901         if (0 == newbuf) {
   902             return 0;
   903         }
   904 
   905         // set the next pointer to the beginning of the new buffer
   906         // as the destination where to copy the string argument
   907         char *next = newbuf;
   908 
   909         // set quote to initially point to the beginning of
   910         // the source buffer and then just past the last quote
   911         quote = buf;
   912 
   913         for (char *q = buf; ; ++q) {
   914 
   915             // look for the next (or first) quote
   916             q = strchr (q, '"');
   917 
   918             // compute the number of characters, excluding the quote
   919             // to copy to the destination buffer
   920             const size_t nchars = q ? size_t (q - quote) : strlen (quote);
   921 
   922             memcpy (next, quote, nchars);
   923 
   924             if (q) {
   925                 // append the escape character to the destination buffer
   926                 next [nchars] = esc;
   927 
   928                 // append the quote from the source string
   929                 next [nchars + 1] = '"';
   930 
   931                 // advance the destination pointer past the quote
   932                 next += nchars + 2;
   933 
   934                 // advance the source pointer past the embedded quote
   935                 quote = q + 1;
   936             }
   937             else {
   938                 // NUL-terminate the destination buffer
   939                 *next = '\0';
   940                 break;
   941             }
   942         }
   943     }
   944 
   945     return newbuf;
   946 }
   947 
   948 /************************************************************************/
   949 
   950 static void
   951 _rw_vissue_diag (diag_t diag, int severity, const char *file, int line,
   952                  const char *fmt, va_list va)
   953 {
   954     CHECK_INIT (true, "_rw_vissue_diag()");
   955 
   956     if (0 == fmt)
   957         fmt = "";
   958 
   959     static char fmterr[] = "*** formatting error ***";
   960 
   961     char *usrbuf = 0;
   962     const int nchars = rw_vasnprintf (&usrbuf, 0, fmt, va);
   963 
   964     if (nchars < 0 || 0 == usrbuf)
   965         usrbuf = fmterr;
   966 
   967     // compute the number of newline characters in the text
   968     int nlines = 0;
   969     
   970     #ifdef __ARMCC__
   971     #pragma diag_suppress 1293
   972     #endif
   973     for (const char *nl = usrbuf; (nl = strchr (nl, '\n')); ++nl)
   974         ++nlines;
   975     
   976 
   977     static const int use_color = _rw_use_color ();
   978 
   979     const char* const diagstr[] = {
   980         use_color ? diag_msgs [severity].esc_pfx : "",
   981         *diag_msgs [severity].code ? diag_msgs [severity].code : "UNKNOWN",
   982         use_color  ? diag_msgs [severity].esc_sfx : "",
   983         _rw_opt_verbose (0, 0) && *diag_msgs [severity].desc ?
   984         diag_msgs [severity].desc : 0
   985     };
   986 
   987     const char* const traced_diag =
   988         0 == severity && diag_msgs [diag].code ? diag_msgs [diag].code : 0;
   989 
   990     const char* const slash = file ? strrchr (file, _RWSTD_PATH_SEP) : 0;
   991     if (slash)
   992         file = slash + 1;
   993 
   994     char *mybuf = 0;
   995 
   996     if (_rw_opt_csv) {
   997 
   998         // format all fields as comma separated values (CSV):
   999         // -- a field containing the quote character, the comma,
  1000         //    or the newline or linefeed character must be enclosed
  1001         //    in a pair of double quotes
  1002         // -- every occurrence of the double quote character in a field
  1003         //    must be escaped by prepening another double quote character
  1004         //    to it
  1005 
  1006         // escape all double quotes by prepending the double
  1007         // quote character to each according to the CSV format
  1008         char* const newbuf = _rw_escape (usrbuf, 0, '"');
  1009         if (newbuf != usrbuf) {
  1010             free (usrbuf);
  1011             usrbuf = newbuf;
  1012         }
  1013 
  1014         mybuf =
  1015             rw_sprintfa ("%d, "                      // severity
  1016                          "\"%s%s"                    // diagnostic
  1017                          "%{?}_%s%{;}%s\", "         // traced diagnostic
  1018                          "\"%s\", "                  // clause
  1019                          "\"%s\", "                  // file
  1020                          "%d, "                      // line
  1021                          "\"%s\"",                   // user text
  1022                          severity,
  1023                          diagstr [0], diagstr [1],
  1024                          0 != traced_diag, traced_diag, diagstr [2],
  1025                          clause_id,
  1026                          0 != file ? file : "",
  1027                          line,
  1028                          usrbuf);
  1029     }
  1030     else {
  1031 
  1032         nlines += 2 + ('\0' != *clause_id) + (0 != file) + (0 < line);
  1033 
  1034         mybuf =
  1035             rw_sprintfa ("# %s"                      // escape prefix
  1036                          "%s"                        // diagnostic
  1037                          "%{?}_%s%{;}"               // traced diagnostic
  1038                          "%s "                       // escape suffix
  1039                          "(S%d)"                     // severity
  1040                          "%{?}, %s%{;} "             // description
  1041                          "(%d lines):\n"             // number of lines
  1042                          "# TEXT: %s\n"              // user text
  1043                          "%{?}# CLAUSE: %s\n%{;}"    // clause if not empty
  1044                          "%{?}# FILE: %s\n%{;}"      // file if not null
  1045                          "%{?}# LINE: %d\n%{;}",     // line if positive
  1046                          diagstr [0],
  1047                          diagstr [1],
  1048                          0 != traced_diag, traced_diag,
  1049                          diagstr [2],
  1050                          severity,
  1051                          0 != diagstr [3], diagstr [3],
  1052                          nlines,
  1053                          usrbuf,
  1054                          '\0' != *clause_id, clause_id,
  1055                          0 != file, file,
  1056                          0 < line, line);
  1057     }
  1058 #if 0   // disabled
  1059     else {
  1060 
  1061         mybuf =
  1062             rw_sprintfa ("# %s%s"                 // diagnostic
  1063                          "%{?}_%s%{;}%s "         // traced diagnostic
  1064                          "(S%d): "                // severity
  1065                          "%{?}[%s] %{;}"          // clause if not empty
  1066                          "%{?}(%d lines): %{;}"   // number of lines if > 1
  1067                          "%{?}%s:"                // if (file) then file
  1068                          "%{?}%d:%{;} "           //   if (0 < line) line
  1069                          "%{:}"                   // else
  1070                          "%{?}line %d: %{;}"      //   if (0 < line) line
  1071                          "%{;}"                   // endif
  1072                          "%s",                    // user text
  1073                          diagstr [0], diagstr [1],
  1074                          0 != traced_diag, traced_diag, diagstr [2],
  1075                          severity,
  1076                          '\0' != *clause_id, clause_id,
  1077                          1 < nlines, nlines,
  1078                          0 != file, file,
  1079                          0 < line, line,
  1080                          0 < line, line,
  1081                          usrbuf);
  1082     }
  1083 #endif   // 0/1
  1084 
  1085     fprintf (ftestout, "%s\n", mybuf);
  1086 
  1087     if (mybuf != fmterr)
  1088         free (mybuf);
  1089 
  1090     if (usrbuf != fmterr)
  1091         free (usrbuf);
  1092 }
  1093 
  1094 /************************************************************************/
  1095 
  1096 static void
  1097 _rw_vdiag (diag_t diag, int severity, const char *file, int line,
  1098            const char *fmt, va_list va)
  1099 {
  1100     CHECK_INIT (true, "_rw_vdiag()");
  1101 
  1102     // check if the diagnostic is expected
  1103     const int expected = 0 != _rw_expected (line);
  1104 
  1105     if (expected) {
  1106         if (severity) {
  1107             // if the diagnostic is expected to be active,
  1108             // adjust its type and severity
  1109             if (diag_assert == diag)
  1110                 diag = diag_xassert;
  1111             else if (diag_warn == diag)
  1112                 diag = diag_xwarn;
  1113 
  1114             severity = diag * severity;
  1115         }
  1116         else {
  1117             // if the diagnostic is expected to be active but isn't,
  1118             // adjust its type to an unexpectdly inactive one
  1119             if (diag_assert == diag || diag_warn == diag)
  1120                 diag = diag_expect;
  1121 
  1122             severity = diag;
  1123         }
  1124     }
  1125     else if (diag) {
  1126         // normalize the severity
  1127         severity = diag * severity;
  1128     }
  1129 
  1130     if (severity < 0)
  1131         severity = 0;
  1132     else if (N_DIAG_TYPES <= severity)
  1133         severity = N_DIAG_TYPES - 1;
  1134 
  1135     // increment the diagnostic counter
  1136     ++ndiags [diag][0];
  1137 
  1138     if (severity) {
  1139 
  1140         ++ndiags [diag][1];
  1141     }
  1142 
  1143     const int sevbit = (1 << severity);
  1144 
  1145     if (0 == (sevbit & _rw_diag_mask)) {
  1146         // issue the diagnostic
  1147         _rw_vissue_diag (diag, severity, file, line, fmt, va);
  1148     }
  1149 
  1150     if (diag_fatal == diag && severity) {
  1151         // fatal error, terminate test
  1152         longjmp (test_env, severity);
  1153     }
  1154 }
  1155 
  1156 /************************************************************************/
  1157 
  1158 _TEST_EXPORT int
  1159 rw_fatal (int success, const char *file, int line, const char *fmt, ...)
  1160 {
  1161     CHECK_INIT (true, "rw_fatal()");
  1162 
  1163     va_list va;
  1164     va_start (va, fmt);
  1165 
  1166     _rw_vdiag (diag_fatal, 0 == success, file, line, fmt, va);
  1167 
  1168     va_end (va);
  1169 
  1170     return success;
  1171 }
  1172 
  1173 /************************************************************************/
  1174 
  1175 _TEST_EXPORT int
  1176 rw_error (int success, const char *file, int line, const char *fmt, ...)
  1177 {
  1178     CHECK_INIT (true, "rw_error()");
  1179 
  1180     va_list va;
  1181     va_start (va, fmt);
  1182 
  1183     _rw_vdiag (diag_error, 0 == success, file, line, fmt, va);
  1184 
  1185     va_end (va);
  1186 
  1187     return success;
  1188 }
  1189 
  1190 /************************************************************************/
  1191 
  1192 _TEST_EXPORT int
  1193 rw_assert (int success, const char *file, int line, const char *fmt, ...)
  1194 {
  1195     CHECK_INIT (true, "rw_assert()");
  1196 
  1197     va_list va;
  1198     va_start (va, fmt);
  1199 
  1200     _rw_vdiag (diag_assert, 0 == success, file, line, fmt, va);
  1201 
  1202     va_end (va);
  1203 
  1204     return success;
  1205 }
  1206 
  1207 /************************************************************************/
  1208 
  1209 _TEST_EXPORT int
  1210 rw_warn (int success, const char *file, int line, const char *fmt, ...)
  1211 {
  1212     CHECK_INIT (true, "rw_warn()");
  1213 
  1214     va_list va;
  1215     va_start (va, fmt);
  1216 
  1217     _rw_vdiag (diag_warn, 0 == success, file, line, fmt, va);
  1218 
  1219     va_end (va);
  1220 
  1221     return success;
  1222 }
  1223 
  1224 /************************************************************************/
  1225 
  1226 _TEST_EXPORT int
  1227 rw_note (int success, const char *file, int line, const char *fmt, ...)
  1228 {
  1229     CHECK_INIT (true, "rw_note()");
  1230 
  1231     va_list va;
  1232     va_start (va, fmt);
  1233 
  1234     _rw_vdiag (diag_note, 0 == success, file, line, fmt, va);
  1235 
  1236     va_end (va);
  1237 
  1238     return success;
  1239 }
  1240 
  1241 /************************************************************************/
  1242 
  1243 _TEST_EXPORT int
  1244 rw_info (int success, const char *file, int line, const char *fmt, ...)
  1245 {
  1246     CHECK_INIT (true, "rw_info()");
  1247 
  1248     va_list va;
  1249     va_start (va, fmt);
  1250 
  1251     _rw_vdiag (diag_info, 0 == success, file, line, fmt, va);
  1252 
  1253     va_end (va);
  1254 
  1255     return success;
  1256 }