| /************************************************************************ |
| * |
| * opt_diags.cpp - definitions of diagnostic option handlers |
| * |
| * $Id$ |
| * |
| ************************************************************************ |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed |
| * with this work for additional information regarding copyright |
| * ownership. The ASF licenses this file to you under the Apache |
| * License, Version 2.0 (the "License"); you may not use this file |
| * except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| * implied. See the License for the specific language governing |
| * permissions and limitations under the License. |
| * |
| * Copyright 1994-2008 Rogue Wave Software, Inc. |
| * |
| **************************************************************************/ |
| |
| // expand _TEST_EXPORT macros |
| #define _RWSTD_TEST_SRC |
| |
| #include "opt_diags.h" |
| |
| #include <assert.h> // for assert() |
| #include <stdio.h> // for fprintf() |
| #include <string.h> // for strlen(), strncmp(), ... |
| |
| |
| #define ESC "\x1b" |
| #define ESC_END ESC "[30;30;0m" |
| #define ESC_CODE(fg, bg, attr) ESC "[" fg bg attr "m", ESC_END |
| |
| |
| // ANSI VT100 terminal codes: |
| #define AT_OFF "0;" // all attributes off |
| #define AT_BLD "1;" // bright/bold |
| #define AT_DIM "2;" // dim |
| // #define AT_??? "3;" // ??? |
| #define AT_UND "4;" // underscore |
| #define AT_BLI "5;" // blink |
| // #define AT_??? "6;" // ??? |
| #define AT_RVS "7;" // reverse video |
| #define AT_HID "8;" // hidden |
| |
| #define FG_BLK "30;" // foreground black |
| #define FG_RED "31;" // foreground red |
| #define FG_GRN "32;" // foreground green |
| #define FG_YLW "33;" // foreground yellow |
| #define FG_BLU "34;" // foreground blue |
| #define FG_MAG "35;" // foreground magenta |
| #define FG_CYN "36;" // foreground cyan |
| #define FG_WHT "37;" // foreground white |
| |
| #define BG_BLK "40;" // background black |
| #define BG_RED "41;" // background red |
| #define BG_GRN "42;" // background green |
| #define BG_YLW "43;" // background yellow |
| #define BG_BLU "44;" // background blue |
| #define BG_MAG "45;" // background magenta |
| #define BG_CYN "46;" // background cyan |
| #define BG_WHT "47;" // background white |
| |
| |
| esc_text_t diag_msgs[] = { |
| /* severity 0 */ { |
| ESC_CODE (FG_CYN, "", AT_DIM), |
| "ITRACE", |
| "inactive diagnostic trace" |
| }, |
| /* severity 1 */ { |
| ESC_CODE (FG_BLK, "", ""), |
| "INFO", |
| "information" |
| }, |
| /* severity 2 */ { |
| ESC_CODE (FG_GRN, "", AT_BLI), |
| "NOTE", |
| "noteworthy event" |
| }, |
| /* severity 3 */ { |
| ESC_CODE (FG_WHT, BG_GRN, AT_BLD), |
| "EXPECT", |
| "expected diagnostic inactive" |
| }, |
| /* severity 4 */ { |
| ESC_CODE (FG_MAG, "", ""), |
| "XWARN", |
| "expected warning" |
| }, |
| /* severity 5 */ { |
| ESC_CODE (FG_MAG, "", AT_BLD AT_UND), |
| "WARNING", |
| "" |
| }, |
| /* severity 6 */ { |
| ESC_CODE (FG_RED, "", ""), |
| "XASSERT", |
| "expected assertion" |
| }, |
| /* severity 7 */ { |
| ESC_CODE (FG_RED, "", AT_BLD AT_UND), |
| "ASSERTION", |
| "" |
| }, |
| /* severity 8 */ { |
| ESC_CODE (FG_WHT, BG_RED, AT_BLD), |
| "ERROR", |
| "test error" |
| }, |
| /* severity 9 */ { |
| ESC_CODE (FG_YLW, BG_RED, AT_BLD), |
| "FATAL", |
| "fatal test error, abort imminent" |
| } |
| }; |
| |
| |
| static const esc_text_t |
| _rw_vt100_colors[] = { |
| // prefix suffix code description |
| { FG_BLK, ESC_END, "black", "" }, |
| { FG_RED, ESC_END, "red", "" }, |
| { FG_GRN, ESC_END, "green", "" }, |
| { FG_YLW, ESC_END, "yellow", "" }, |
| { FG_BLU, ESC_END, "blue", "" }, |
| { FG_MAG, ESC_END, "magenta", "" }, |
| { FG_CYN, ESC_END, "cyan", "" }, |
| { FG_WHT, ESC_END, "white", "" } |
| }; |
| |
| |
| static const esc_text_t |
| _rw_vt100_attribs[] = { |
| // prefix suffix code description |
| { AT_OFF, ESC_END, "off", "" }, |
| { AT_BLD, ESC_END, "bold", "" }, |
| { AT_DIM, ESC_END, "dim", "" }, |
| { AT_UND, ESC_END, "underscore", "" }, |
| { AT_BLI, ESC_END, "blink", "" }, |
| { AT_RVS, ESC_END, "reverse", "" }, |
| { AT_HID, ESC_END, "hidden", "" } |
| }; |
| |
| |
| static int |
| _rw_match_name (const esc_text_t *text, size_t nelems, |
| const char *first, const char *last) |
| { |
| assert (0 != text); |
| assert (0 != first); |
| assert (first <= last); |
| |
| const size_t len = size_t (last - first); |
| |
| if (0 == len) |
| return int (nelems); |
| |
| for (size_t i = 0; i != nelems; ++i) { |
| if ( 0 == strncmp (text [i].code, first, len) |
| && '\0' == text [i].code [len]) |
| return int (i); |
| } |
| |
| return -1; |
| } |
| |
| |
| /* extern */ int |
| _rw_setopt_diags (int argc, char *argv[]) |
| { |
| if (1 == argc && argv && 0 == argv [0]) { |
| static const char helpstr[] = { |
| "Sets the colors and names of the diagnostic messages issued by\n" |
| "the program.\n" |
| "There are 10 different types of diagnostic messages, each with\n" |
| "a unique severity level between 0 (the lowest) and 9. Each\n" |
| "diagnostic message can either be active or inactive. Each\n" |
| "message can have a name of up to 15 characters associated with\n" |
| "it, foreground color, background color, and a video attribute.\n" |
| "These parameters are controlled by the argument to this option.\n" |
| "\nThe syntax of <arg> is as follows:\n" |
| "<arg> ::= <color-list>\n" |
| "<color-list> ::= <color-txt> [ ,<color-list> ]\n" |
| "<color-txt> ::= <sev>:[<color>][:[<color>][:[<attr>][:[<text>]]]]" |
| "\n<sev> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9\n" |
| "<color> ::= black | red | green | yellow\n" |
| " | blue | magenta | cyan | white\n" |
| "<attr> ::= off | bold | dim | underscore\n" |
| " | blink | reverse | hidden\n" |
| "<text> ::= A-Z a-z 0-9 _\n\n" |
| "The first <color> component specifies the foreground color\n" |
| "while the second (optional) <color> component specifies\n" |
| "the background color for the diagnostic of the severity <sev>.\n" |
| "Empty arguments are permitted and denote the default system\n" |
| "color set for the terminal.\n" |
| }; |
| |
| argv [0] = _RWSTD_CONST_CAST (char*, helpstr); |
| |
| return 0; |
| } |
| |
| char *parg = strchr (argv [0], '='); |
| |
| if (0 == parg || '\0' == parg [1]) { |
| fprintf (stderr, "%s:%d: missing argument in %s\n", |
| __FILE__, __LINE__, argv [0]); |
| return 1; |
| } |
| |
| ++parg; |
| |
| // argument syntax: |
| // |
| // <sev-color-list> := <sev-color-text> [ ,<sev-color-list> ] |
| // <sev-color-text> := <sev>:[<color>][:[<color>][:[<attr>][:[<text>]]]] |
| // <sev> := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| // <color> := black | red | green | yellow |
| // | blue | magenta | cyan | white |
| // <attr> := off | bold | dim | underscore |
| // | blink | reverse | hidden |
| // <text> := A-Z a-z 0-9 _ |
| |
| |
| int ret = 0; |
| |
| while (*parg) { |
| |
| int sev = -1; |
| int fgcol = -1; |
| int bgcol = -1; |
| int attr = -1; |
| |
| char diag_code [sizeof diag_msgs [0].code]; |
| *diag_code = '\0'; |
| |
| if ('0' <= *parg && *parg <= '9') { |
| sev = *parg++ - '0'; |
| } |
| else { |
| // digit expected |
| fprintf (stderr, "%s:%d: digit expected at position %d: %s\n", |
| __FILE__, __LINE__, int (parg - argv [0]), argv [0]); |
| |
| ret = 1; |
| break; |
| } |
| |
| if (':' == *parg) { |
| ++parg; |
| } |
| else { |
| // colon expected |
| fprintf (stderr, "%s:%d: colon expected at position %d: %s\n", |
| __FILE__, __LINE__, int (parg - argv [0]), argv [0]); |
| |
| ret = 1; |
| break; |
| } |
| |
| char *end = strpbrk (parg, ":,"); |
| if (0 == end) |
| end = parg + strlen (parg); |
| |
| fgcol = _rw_match_name (_rw_vt100_colors, 8, parg, end); |
| if (fgcol < 0 || 8 < fgcol) { |
| // invalid color |
| fprintf (stderr, "%s:%d: unknown color at position %d: %s\n", |
| __FILE__, __LINE__, int (parg - argv [0]), argv [0]); |
| |
| ret = 1; |
| break; |
| } |
| |
| RW_ASSERT (0 != end); |
| |
| if (':' == *end || '\0' == *end) { |
| parg = end + (0 != *end); |
| end = strpbrk (parg, ":,"); |
| if (0 == end) |
| end = parg + strlen (parg); |
| |
| bgcol = _rw_match_name (_rw_vt100_colors, 8, parg, end); |
| |
| if (bgcol < 0 || 8 < bgcol) { |
| // invalid color |
| fprintf (stderr, "%s:%d: unknown color at position %d: %s\n", |
| __FILE__, __LINE__, int (parg - argv [0]), argv [0]); |
| |
| ret = 1; |
| break; |
| } |
| |
| RW_ASSERT (0 != end); |
| |
| if (':' == *end || '\0' == *end) { |
| parg = end + ('\0' != *end); |
| end = strpbrk (parg, ":,"); |
| if (0 == end) |
| end = parg + strlen (parg); |
| |
| attr = _rw_match_name (_rw_vt100_attribs, 8, parg, end); |
| if (attr < 0 || 8 < attr) { |
| // invalid attribute |
| fprintf (stderr, |
| "%s:%d: unknown attribute at position %d: %s\n", |
| __FILE__, __LINE__, int (parg - argv [0]), |
| argv [0]); |
| |
| ret = 1; |
| break; |
| } |
| |
| RW_ASSERT (0 != end); |
| |
| if (':' == *end || '\0' == *end) { |
| parg = end + (0 != *end); |
| end = strpbrk (parg, ":,"); |
| if (0 == end) |
| end = parg + strlen (parg); |
| |
| size_t len = size_t (end - parg); |
| |
| if (sizeof diag_msgs [sev].code < len) { |
| |
| // name too long |
| fprintf (stderr, |
| "%s:%d: name too long at position %d: %s\n", |
| __FILE__, __LINE__, int (parg - argv [0]), |
| argv [0]); |
| |
| len = strlen (diag_msgs [sev].code); |
| } |
| |
| memcpy (diag_code, parg, len); |
| diag_code [len] = '\0'; |
| } |
| } |
| } |
| |
| strcpy (diag_msgs [sev].esc_pfx, ESC "["); |
| |
| if (-1 < fgcol && fgcol < 8) |
| strcat (diag_msgs [sev].esc_pfx, _rw_vt100_colors [fgcol].esc_pfx); |
| |
| if (-1 < bgcol && bgcol < 8) { |
| strcat (diag_msgs [sev].esc_pfx, _rw_vt100_colors [bgcol].esc_pfx); |
| |
| const size_t bgdiginx = strlen (diag_msgs [sev].esc_pfx) - 3; |
| |
| assert ('3' == diag_msgs [sev].esc_pfx [bgdiginx]); |
| diag_msgs [sev].esc_pfx [bgdiginx] = '4'; |
| } |
| |
| if (-1 < attr && attr < 8) |
| strcat (diag_msgs [sev].esc_pfx, _rw_vt100_attribs [attr].esc_pfx); |
| |
| if (diag_msgs [sev].esc_pfx [2]) { |
| strcat (diag_msgs [sev].esc_pfx, "m"); |
| strcpy (diag_msgs [sev].esc_sfx, ESC_END); |
| } |
| else { |
| diag_msgs [sev].esc_pfx [0] = '\0'; |
| diag_msgs [sev].esc_sfx [0] = '\0'; |
| } |
| |
| if (*diag_code) |
| strcpy (diag_msgs [sev].code, diag_code); |
| |
| parg = end + ('\0' != *end); |
| } |
| |
| return ret; |
| } |