Update contrib.
1 /************************************************************************
3 * driver.cpp - definitions of the test driver
5 * $Id: driver.cpp 290009 2005-09-18 23:28:26Z sebor $
7 ************************************************************************
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
20 **************************************************************************/
22 // expand _TEST_EXPORT macros
23 #define _RWSTD_TEST_SRC
25 #include "opt_diags.h"
26 #include "opt_lines.h"
27 #include "opt_trace.h"
28 #include "opt_types.h"
30 #include <cmdopt.h> // for rw_setopts()
31 #include <printf.h> // for rw_snprintfa()
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
44 // declare fileno in case it's not declared (for strict ANSI conformance)
47 IMPORT_C int (fileno)(FILE*) _LIBC_THROWS ();
52 // no isatty on Windoze
53 # define _RWSTD_NO_ISATTY
56 // expand _TEST_EXPORT macros
57 #define _RWSTD_TEST_SRC
60 /************************************************************************/
62 #define RW_TEST_STRSTR(x) #x
63 #define RW_TEST_STR(x) RW_TEST_STRSTR(x)
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__)
74 # define RW_TEST_ICC_EDG_VER ""
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) \
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) \
88 # define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
89 RW_TEST_STR (__INTEL_COMPILER) \
92 # elif defined (__GNUC__)
93 # if defined (__VERSION__)
94 # define RW_TEST_GCC_VER ", __VERSION__ = \"" __VERSION__ "\""
96 # define RW_TEST_GCC_VER ""
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__) \
105 # define RW_TEST_COMPILER "gcc " \
106 RW_TEST_STR (__GNUC__) "." RW_TEST_STR (__GNUC_MINOR__)
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)
118 # define RW_TEST_COMPILER "Intel C++, __INTEL_COMPILER = " \
119 RW_TEST_STR (__INTEL_COMPILER)
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)
137 # define RW_TEST_COMPILER "unknown"
141 #ifndef RW_TEST_LIBSTD
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, " \
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, " \
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"
164 #endif // RW_TEST_LIBSTD
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"
173 # define RW_TEST_ARCH "amd64/ILP32"
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"
221 # define RW_TEST_ARCH "powerpc"
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"
231 # define RW_TEST_ARCH "x86_64/ILP32"
234 # define RW_TEST_ARCH "unknown"
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)
264 // get Linux release string (UTS_RELEASE)
265 # include <linux/version.h>
268 # define UTS_RELEASE "(unknown release)"
269 # endif // UTS_RELEASE
271 # if defined (__ELF__)
272 # define LINUX_TYPE "linux-elf"
274 # define LINUX_TYPE "linux"
277 # define RW_TEST_OS LINUX_TYPE " " \
278 UTS_RELEASE " with glibc " \
279 RW_TEST_STR (__GLIBC__) "." \
280 RW_TEST_STR (__GLIBC_MINOR__)
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"
299 # define RW_TEST_OS "unknown"
302 # define RW_TEST_HARDWARE RW_TEST_ARCH " running " RW_TEST_OS
304 # define RW_TEST_HARDWARE "unknown"
307 /************************************************************************/
309 // defined in printf.cpp but not declared in printf.h
311 rw_vasnprintf (char**, size_t*, const char*, va_list);
313 /************************************************************************/
315 // array to store the number of each type of diagnostic
317 ndiags [N_DIAG_TYPES][2] /* = { { total, active }, ... }*/;
319 static FILE *ftestout;
321 static jmp_buf test_env;
323 // set to 1 after the driver has been initialized
324 static int driver_initialized = 0;
326 // set to 1 after the driver has finished running
327 static int driver_finished = 0;
332 // %m: diagnostic if not empty
334 // %f: file name if not empty
336 // %c: clause if not empty
338 // %l: line number if valid
340 // %t: text if not empty
341 static char diag_pattern [80];
344 // option: use CSV format (comma separated values)
345 static int _rw_opt_csv = 0;
347 static char clause_id [80];
349 /************************************************************************/
351 #define CHECK_INIT(init, func) _rw_check_init (init, __LINE__, func)
354 _rw_check_init (bool init, int line, const char *func)
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);
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);
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);
380 /************************************************************************/
383 _rw_opt_brief (int argc, char *argv[])
385 static int opt_brief;
388 // query mode: return the value of the option
392 if (1 == argc && argv && 0 == argv [0]) {
393 // help mode: set argv[0] to the text of the help message
395 static const char helpstr[] = {
396 "Enables brief mode.\n"
399 argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
404 // set mode: enable the option
410 /************************************************************************/
413 _rw_opt_quiet (int argc, char *argv[])
415 static int opt_quiet;
418 // query mode: return the value of the option
422 if (1 == argc && argv && 0 == argv [0]) {
423 // help mode: set argv[0] to the text of the help message
425 static const char helpstr[] = {
426 "Enables quiet mode.\n"
427 "In quiet mode only diagnostics with severity 7 and above are "
431 argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
436 // set mode: enable the option
437 _rw_diag_mask = ~((1 << 7) | (1 << 8) | (1 << 9));
443 /************************************************************************/
446 _rw_opt_verbose (int argc, char *argv[])
448 static int opt_verbose;
451 // query mode: return the value of the option
455 if (1 == argc && argv && 0 == argv [0]) {
456 // help mode: set argv[0] to the text of the help message
458 static const char helpstr[] = {
459 "Enables verbose mode.\n"
462 argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
467 // set mode: enable the option
473 /************************************************************************/
476 _rw_setopt_csv (int argc, char *argv[])
478 if (1 == argc && argv && 0 == argv [0]) {
479 static const char helpstr[] = {
480 "Enables CSV (comma separated values) mode.\n"
483 argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
492 /************************************************************************/
495 _rw_opt_compat (int argc, char *argv[])
497 static int opt_compat;
500 // query mode: return the value of the option
504 if (1 == argc && argv && 0 == argv [0]) {
505 // help mode: set argv[0] to the text of the help message
507 static const char helpstr[] = {
508 "Enables RWTest-format compatibility mode.\n"
511 argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
516 // set mode: enable the option
522 /************************************************************************/
525 _rw_opt_no_stdout (int argc, char *argv[])
527 static int opt_no_stdout;
530 // query mode: return the value of the option
531 return opt_no_stdout;
534 if (1 == argc && argv && 0 == argv [0]) {
535 // help mode: set argv[0] to the text of the help message
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"
547 argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
552 // set mode: enable the option
558 /************************************************************************/
561 _rw_setopt_output_file (int argc, char *argv[])
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"
571 argv [0] = _RWSTD_CONST_CAST (char*, helpstr);
576 const char *file_name = 0;
578 if ('-' == argv [0][0] && 'O' == argv [0][1] || 'o' == argv [0][1]) {
579 file_name = argv [0] + 2;
581 else if (1 < argc && '-' != argv [1][0]) {
582 file_name = argv [1];
587 FILE* const f = fopen (file_name, "w");
590 if (ftestout && ftestout != stderr)
597 // return 0 on success, any non-zero value on failure
598 return !(ftestout != 0);
601 /************************************************************************/
604 rw_vsetopts (const char *opts, va_list va);
606 /************************************************************************/
611 #ifndef _RWSTD_NO_ISATTY
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));
617 #else // if defined (_RWSTD_NO_ISATTY)
619 // FIXME: deal with a missing isatty() and Windows
620 static const int tty = 0;
622 #endif // _RWSTD_NO_ISATTY
627 /************************************************************************/
630 rw_vtest (int argc, char **argv,
631 const char *file_name,
634 int (*fun)(int, char**),
638 CHECK_INIT (false, "rw_vtest()");
640 driver_initialized = 1;
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__);
649 rw_setopts ("|-no-stdout "
650 "|-diags= " // argument required
652 "|-severity= " // argument required
655 "o|-output:" // argument optional
662 _rw_setopt_trace_mask,
665 _rw_setopt_output_file,
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__);
678 #ifndef _RWSTD_USE_CONFIG
680 // enable RWTest-format compatibility mode
681 _rw_opt_compat (1, 0);
683 // disable output to stdout
684 _rw_opt_no_stdout (1, 0);
686 #endif // _RWSTD_USE_CONFIG
688 _rw_setopts_types ();
690 _rw_setopts_lines ();
692 int status = rw_runopts (argc, argv);
699 if (_rw_opt_no_stdout (0, 0) && file_name) {
700 char fname [256] = "C:\\";
702 char* temp_ret = strchr (file_name, '/');
706 const char* const slash = strrchr (file_name, '/');
708 strcat (fname, slash ? slash + 1 : file_name);
712 const char* const slash = strrchr (file_name, _RWSTD_PATH_SEP);
714 strcat (fname, slash ? slash + 1 : file_name);
717 char* const dot = strchr (fname, '.');
719 strcpy (dot, ".out");
721 strcat (fname, ".out");
723 ftestout = fopen (fname, "w");
730 strcpy (clause_id, clause);
732 const char begin_fmt[] = {
735 "# ENVIRONMENT: %s\n"
737 "# COMPILED: %s, %s\n"
739 "######################################################"
742 const char* const fname = strrchr (file_name, _RWSTD_PATH_SEP);
746 RW_TEST_COMPILER, RW_TEST_HARDWARE,
747 fname ? fname + 1 : file_name,
749 comment ? comment : "");
751 status = setjmp (test_env);
754 // environment set, execute the callback function
755 status = fun (argc, argv);
758 // fatal test error (via a call to rw_fatal())
763 static const char tblrow[] =
764 "+-----------------------+--------+--------+--------+";
768 "# | DIAGNOSTIC | ACTIVE | TOTAL |INACTIVE|\n"
774 for (int i = 0; i != N_DIAG_TYPES; ++i) {
775 if (ndiags [i][0] || !(_rw_diag_mask & (1 << diag_trace))) {
777 // print out details for any non-zero totals
778 // or for all totals when debugging or tracing
783 const long num = (ndiags [i][0] - ndiags [i][1]) * 100L;
784 const long den = ndiags [i][0];
786 const long pct = den ? num / den : 0;
788 const char* pfx = "";
789 const char* sfx = "";
791 static int use_color = _rw_use_color ();
794 pfx = ndiags [i][1] ? diag_msgs [i].esc_pfx : "";
795 sfx = ndiags [i][1] ? diag_msgs [i].esc_sfx : "";
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);
806 fprintf (ftestout, "# no diagnostics\n");
808 fprintf (ftestout, "# %s\n", tblrow);
810 if (_rw_opt_compat (0, 0)) {
812 // TO DO: get rid of this
814 // RWTest compatibility format
817 "######################################################\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]);
832 /************************************************************************/
835 rw_test (int argc, char **argv,
839 int (*testfun)(int, char**),
843 CHECK_INIT (false, "rw_test()");
846 va_start (va, optstr);
849 rw_vtest (argc, argv, fname, clause, comment, testfun, optstr, va);
856 /************************************************************************/
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
866 _rw_escape (char *buf, size_t bufsize, char esc)
868 // handle null buffer
872 // count the number of embedded quotes
877 #pragma diag_suppress 1293
879 while ((quote = strchr (quote, '"'))) {
885 // no quotes found, return the original buffer
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;
895 if (0 /* newbufsize <= bufsize */) {
896 // FIXME: escape embedded quotes in place w/o reallocation
897 _RWSTD_UNUSED (bufsize);
900 newbuf = (char*)malloc (newbufsize);
905 // set the next pointer to the beginning of the new buffer
906 // as the destination where to copy the string argument
909 // set quote to initially point to the beginning of
910 // the source buffer and then just past the last quote
913 for (char *q = buf; ; ++q) {
915 // look for the next (or first) quote
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);
922 memcpy (next, quote, nchars);
925 // append the escape character to the destination buffer
928 // append the quote from the source string
929 next [nchars + 1] = '"';
931 // advance the destination pointer past the quote
934 // advance the source pointer past the embedded quote
938 // NUL-terminate the destination buffer
948 /************************************************************************/
951 _rw_vissue_diag (diag_t diag, int severity, const char *file, int line,
952 const char *fmt, va_list va)
954 CHECK_INIT (true, "_rw_vissue_diag()");
959 static char fmterr[] = "*** formatting error ***";
962 const int nchars = rw_vasnprintf (&usrbuf, 0, fmt, va);
964 if (nchars < 0 || 0 == usrbuf)
967 // compute the number of newline characters in the text
971 #pragma diag_suppress 1293
973 for (const char *nl = usrbuf; (nl = strchr (nl, '\n')); ++nl)
977 static const int use_color = _rw_use_color ();
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
987 const char* const traced_diag =
988 0 == severity && diag_msgs [diag].code ? diag_msgs [diag].code : 0;
990 const char* const slash = file ? strrchr (file, _RWSTD_PATH_SEP) : 0;
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
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) {
1015 rw_sprintfa ("%d, " // severity
1016 "\"%s%s" // diagnostic
1017 "%{?}_%s%{;}%s\", " // traced diagnostic
1018 "\"%s\", " // clause
1021 "\"%s\"", // user text
1023 diagstr [0], diagstr [1],
1024 0 != traced_diag, traced_diag, diagstr [2],
1026 0 != file ? file : "",
1032 nlines += 2 + ('\0' != *clause_id) + (0 != file) + (0 < line);
1035 rw_sprintfa ("# %s" // escape prefix
1037 "%{?}_%s%{;}" // traced diagnostic
1038 "%s " // escape suffix
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
1048 0 != traced_diag, traced_diag,
1051 0 != diagstr [3], diagstr [3],
1054 '\0' != *clause_id, clause_id,
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
1070 "%{?}line %d: %{;}" // if (0 < line) line
1073 diagstr [0], diagstr [1],
1074 0 != traced_diag, traced_diag, diagstr [2],
1076 '\0' != *clause_id, clause_id,
1085 fprintf (ftestout, "%s\n", mybuf);
1087 if (mybuf != fmterr)
1090 if (usrbuf != fmterr)
1094 /************************************************************************/
1097 _rw_vdiag (diag_t diag, int severity, const char *file, int line,
1098 const char *fmt, va_list va)
1100 CHECK_INIT (true, "_rw_vdiag()");
1102 // check if the diagnostic is expected
1103 const int expected = 0 != _rw_expected (line);
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)
1114 severity = diag * severity;
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)
1126 // normalize the severity
1127 severity = diag * severity;
1132 else if (N_DIAG_TYPES <= severity)
1133 severity = N_DIAG_TYPES - 1;
1135 // increment the diagnostic counter
1143 const int sevbit = (1 << severity);
1145 if (0 == (sevbit & _rw_diag_mask)) {
1146 // issue the diagnostic
1147 _rw_vissue_diag (diag, severity, file, line, fmt, va);
1150 if (diag_fatal == diag && severity) {
1151 // fatal error, terminate test
1152 longjmp (test_env, severity);
1156 /************************************************************************/
1159 rw_fatal (int success, const char *file, int line, const char *fmt, ...)
1161 CHECK_INIT (true, "rw_fatal()");
1166 _rw_vdiag (diag_fatal, 0 == success, file, line, fmt, va);
1173 /************************************************************************/
1176 rw_error (int success, const char *file, int line, const char *fmt, ...)
1178 CHECK_INIT (true, "rw_error()");
1183 _rw_vdiag (diag_error, 0 == success, file, line, fmt, va);
1190 /************************************************************************/
1193 rw_assert (int success, const char *file, int line, const char *fmt, ...)
1195 CHECK_INIT (true, "rw_assert()");
1200 _rw_vdiag (diag_assert, 0 == success, file, line, fmt, va);
1207 /************************************************************************/
1210 rw_warn (int success, const char *file, int line, const char *fmt, ...)
1212 CHECK_INIT (true, "rw_warn()");
1217 _rw_vdiag (diag_warn, 0 == success, file, line, fmt, va);
1224 /************************************************************************/
1227 rw_note (int success, const char *file, int line, const char *fmt, ...)
1229 CHECK_INIT (true, "rw_note()");
1234 _rw_vdiag (diag_note, 0 == success, file, line, fmt, va);
1241 /************************************************************************/
1244 rw_info (int success, const char *file, int line, const char *fmt, ...)
1246 CHECK_INIT (true, "rw_info()");
1251 _rw_vdiag (diag_info, 0 == success, file, line, fmt, va);