1 // (C) Copyright Gennadiy Rozental 2001. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 // See http://www.boost.org/libs/test for the library home page. 7 // 8 // File : $RCSfile$ 9 // 10 // Version : $Revision$ 11 // 12 // Description : contains definition for setcolor iostream manipulator 13 // *************************************************************************** 14 15 #ifndef BOOST_TEST_UTILS_SETCOLOR_HPP 16 #define BOOST_TEST_UTILS_SETCOLOR_HPP 17 18 // Boost.Test 19 #include <boost/test/detail/config.hpp> 20 21 #include <boost/core/ignore_unused.hpp> 22 23 // STL 24 #include <iostream> 25 #include <cstdio> 26 #include <cassert> 27 28 #include <boost/test/detail/suppress_warnings.hpp> 29 30 #ifdef _WIN32 31 #include <windows.h> 32 33 #if defined(__MINGW32__) && !defined(COMMON_LVB_UNDERSCORE) 34 // mingw badly mimicking windows.h 35 #define COMMON_LVB_UNDERSCORE 0x8000 36 #endif 37 #endif 38 39 //____________________________________________________________________________// 40 41 namespace boost { 42 namespace unit_test { 43 namespace utils { 44 45 // ************************************************************************** // 46 // ************** term_attr ************** // 47 // ************************************************************************** // 48 49 struct term_attr { enum _ { 50 NORMAL = 0, 51 BRIGHT = 1, 52 DIM = 2, 53 UNDERLINE = 4, 54 BLINK = 5, 55 REVERSE = 7, 56 CROSSOUT = 9 57 }; }; 58 59 // ************************************************************************** // 60 // ************** term_color ************** // 61 // ************************************************************************** // 62 63 struct term_color { enum _ { 64 BLACK = 0, 65 RED = 1, 66 GREEN = 2, 67 YELLOW = 3, 68 BLUE = 4, 69 MAGENTA = 5, 70 CYAN = 6, 71 WHITE = 7, 72 ORIGINAL = 9 73 }; }; 74 75 // ************************************************************************** // 76 // ************** setcolor ************** // 77 // ************************************************************************** // 78 79 #ifndef _WIN32 80 class setcolor { 81 public: 82 typedef int state; 83 84 // Constructor setcolor(bool is_color_output=false,term_attr::_ attr=term_attr::NORMAL,term_color::_ fg=term_color::ORIGINAL,term_color::_ bg=term_color::ORIGINAL,state * =NULL)85 explicit setcolor( bool is_color_output = false, 86 term_attr::_ attr = term_attr::NORMAL, 87 term_color::_ fg = term_color::ORIGINAL, 88 term_color::_ bg = term_color::ORIGINAL, 89 state* /* unused */= NULL) 90 : m_is_color_output(is_color_output) 91 { 92 m_command_size = std::sprintf( m_control_command, "%c[%c;3%c;4%cm", 93 0x1B, 94 static_cast<char>(attr + '0'), 95 static_cast<char>(fg + '0'), 96 static_cast<char>(bg + '0')); 97 } 98 setcolor(bool is_color_output,state *)99 explicit setcolor(bool is_color_output, 100 state* /* unused */) 101 : m_is_color_output(is_color_output) 102 { 103 m_command_size = std::sprintf(m_control_command, "%c[%c;3%c;4%cm", 104 0x1B, 105 static_cast<char>(term_attr::NORMAL + '0'), 106 static_cast<char>(term_color::ORIGINAL + '0'), 107 static_cast<char>(term_color::ORIGINAL + '0')); 108 } 109 110 friend std::ostream& operator <<(std::ostream & os,setcolor const & sc)111 operator<<( std::ostream& os, setcolor const& sc ) 112 { 113 if (sc.m_is_color_output && (&os == &std::cout || &os == &std::cerr)) { 114 return os.write( sc.m_control_command, sc.m_command_size ); 115 } 116 return os; 117 } 118 119 private: 120 // Data members 121 bool m_is_color_output; 122 char m_control_command[13]; 123 int m_command_size; 124 }; 125 126 #else 127 128 class setcolor { 129 130 protected: set_console_color(std::ostream & os,WORD * attributes=NULL) const131 void set_console_color(std::ostream& os, WORD *attributes = NULL) const { 132 if (!m_is_color_output || m_state_saved) { 133 return; 134 } 135 DWORD console_type; 136 if (&os == &std::cout) { 137 console_type = STD_OUTPUT_HANDLE; 138 } 139 else if (&os == &std::cerr) { 140 console_type = STD_ERROR_HANDLE; 141 } 142 else { 143 return; 144 } 145 HANDLE hConsole = GetStdHandle(console_type); 146 147 if(hConsole == INVALID_HANDLE_VALUE || hConsole == NULL ) 148 return; 149 150 state console_attributes; 151 if(attributes != NULL || (m_restore_state && m_s)) { 152 if (attributes != NULL) { 153 console_attributes = *attributes; 154 } 155 else { 156 console_attributes = *m_s; 157 *m_s = state(); 158 } 159 SetConsoleTextAttribute(hConsole, console_attributes); 160 return; 161 } 162 163 CONSOLE_SCREEN_BUFFER_INFO consoleInfo; 164 GetConsoleScreenBufferInfo(hConsole, &consoleInfo); 165 console_attributes = consoleInfo.wAttributes; 166 167 if (!m_state_saved && m_s) { 168 assert(!m_restore_state); 169 // we can save the state only the first time this object is used 170 // for modifying the console. 171 *m_s = console_attributes; 172 m_state_saved = true; 173 } 174 175 WORD fg_attr = 0; 176 switch(m_fg) 177 { 178 case term_color::WHITE: 179 fg_attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; 180 break; 181 case term_color::BLACK: 182 fg_attr = 0; 183 break; 184 case term_color::RED: 185 fg_attr = FOREGROUND_RED; 186 break; 187 case term_color::GREEN: 188 fg_attr = FOREGROUND_GREEN; 189 break; 190 case term_color::CYAN: 191 fg_attr = FOREGROUND_GREEN | FOREGROUND_BLUE; 192 break; 193 case term_color::MAGENTA: 194 fg_attr = FOREGROUND_RED | FOREGROUND_BLUE; 195 break; 196 case term_color::BLUE: 197 fg_attr = FOREGROUND_BLUE; 198 break; 199 case term_color::YELLOW: 200 fg_attr = FOREGROUND_RED | FOREGROUND_GREEN; 201 break; 202 case term_color::ORIGINAL: 203 default: 204 fg_attr = console_attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 205 break; 206 } 207 208 WORD bg_attr = 0; 209 switch(m_bg) 210 { 211 case term_color::BLACK: 212 bg_attr = 0; 213 break; 214 case term_color::WHITE: 215 bg_attr = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; 216 break; 217 case term_color::RED: 218 bg_attr = BACKGROUND_RED; 219 break; 220 case term_color::GREEN: 221 bg_attr = BACKGROUND_GREEN; 222 break; 223 case term_color::BLUE: 224 bg_attr = BACKGROUND_BLUE; 225 break; 226 case term_color::ORIGINAL: 227 default: 228 bg_attr = console_attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); 229 break; 230 } 231 232 WORD text_attr = 0; 233 switch(m_attr) 234 { 235 case term_attr::BRIGHT: 236 text_attr = FOREGROUND_INTENSITY; 237 break; 238 case term_attr::UNDERLINE: 239 text_attr = COMMON_LVB_UNDERSCORE; 240 break; 241 default: 242 break; 243 } 244 245 SetConsoleTextAttribute(hConsole, fg_attr | bg_attr | text_attr); 246 return; 247 } 248 249 public: 250 typedef WORD state; 251 252 // Constructor setcolor(bool is_color_output=false,term_attr::_ attr=term_attr::NORMAL,term_color::_ fg=term_color::ORIGINAL,term_color::_ bg=term_color::ORIGINAL,state * s=NULL)253 explicit setcolor( 254 bool is_color_output = false, 255 term_attr::_ attr = term_attr::NORMAL, 256 term_color::_ fg = term_color::ORIGINAL, 257 term_color::_ bg = term_color::ORIGINAL, 258 state* s = NULL) 259 : m_is_color_output(is_color_output) 260 , m_attr(attr) 261 , m_fg(fg) 262 , m_bg(bg) 263 , m_s(s) 264 , m_restore_state(false) 265 , m_state_saved(false) 266 {} 267 setcolor(bool is_color_output,state * s)268 explicit setcolor( 269 bool is_color_output, 270 state* s) 271 : m_is_color_output(is_color_output) 272 , m_attr(term_attr::NORMAL) 273 , m_fg(term_color::ORIGINAL) 274 , m_bg(term_color::ORIGINAL) 275 , m_s(s) 276 , m_restore_state(true) 277 , m_state_saved(false) 278 {} 279 280 friend std::ostream& operator <<(std::ostream & os,setcolor const & sc)281 operator<<( std::ostream& os, setcolor const& sc ) 282 { 283 sc.set_console_color(os); 284 return os; 285 } 286 287 private: 288 bool m_is_color_output; 289 term_attr::_ m_attr; 290 term_color::_ m_fg; 291 term_color::_ m_bg; 292 state* m_s; 293 // indicates that the instance has been initialized to restore a previously 294 // stored state 295 bool m_restore_state; 296 // indicates the first time we pull and set the console information. 297 mutable bool m_state_saved; 298 }; 299 300 #endif 301 // ************************************************************************** // 302 // ************** scope_setcolor ************** // 303 // ************************************************************************** // 304 305 struct scope_setcolor { scope_setcolorboost::unit_test::utils::scope_setcolor306 scope_setcolor() 307 : m_os( 0 ) 308 , m_state() 309 , m_is_color_output(false) 310 {} 311 scope_setcolorboost::unit_test::utils::scope_setcolor312 explicit scope_setcolor( 313 bool is_color_output, 314 std::ostream& os, 315 term_attr::_ attr = term_attr::NORMAL, 316 term_color::_ fg = term_color::ORIGINAL, 317 term_color::_ bg = term_color::ORIGINAL ) 318 : m_os( &os ) 319 , m_is_color_output(is_color_output) 320 { 321 os << setcolor(is_color_output, attr, fg, bg, &m_state); 322 } 323 ~scope_setcolorboost::unit_test::utils::scope_setcolor324 ~scope_setcolor() 325 { 326 if (m_os) { 327 *m_os << setcolor(m_is_color_output, &m_state); 328 } 329 } 330 private: 331 scope_setcolor(const scope_setcolor& r); 332 scope_setcolor& operator=(const scope_setcolor& r); 333 // Data members 334 std::ostream* m_os; 335 setcolor::state m_state; 336 bool m_is_color_output; 337 }; 338 339 340 #define BOOST_TEST_SCOPE_SETCOLOR( is_color_output, os, attr, color ) \ 341 utils::scope_setcolor const sc(is_color_output, os, utils::attr, utils::color); \ 342 boost::ignore_unused( sc ) \ 343 /**/ 344 345 } // namespace utils 346 } // namespace unit_test 347 } // namespace boost 348 349 #include <boost/test/detail/enable_warnings.hpp> 350 351 #endif // BOOST_TEST_UTILS_SETCOLOR_HPP 352