1a187aa080377f4707bb28690d51f206c0d49f436Eric Fiselier// Copyright 2015 Google Inc. All rights reserved. 25a71bd6e6656bb1610da794489e65ac7d0b13bc6Dominic Hamon// 33fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// Licensed under the Apache License, Version 2.0 (the "License"); 43fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// you may not use this file except in compliance with the License. 53fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// You may obtain a copy of the License at 65a71bd6e6656bb1610da794489e65ac7d0b13bc6Dominic Hamon// 73fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// http://www.apache.org/licenses/LICENSE-2.0 85a71bd6e6656bb1610da794489e65ac7d0b13bc6Dominic Hamon// 93fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// Unless required by applicable law or agreed to in writing, software 103fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// distributed under the License is distributed on an "AS IS" BASIS, 113fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// See the License for the specific language governing permissions and 133fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon// limitations under the License. 143fb8268eab1a0f116f5e690e13d1234265998f2cDominic Hamon 15403f35442375f2ee858981b79421ca321645df0Dominic Hamon#include "colorprint.h" 16403f35442375f2ee858981b79421ca321645df0Dominic Hamon 17a187aa080377f4707bb28690d51f206c0d49f436Eric Fiselier#include <cstdarg> 18a863aead1330bf52d4230667a5aae4b7fa5ef69eryobg#include <cstdio> 19917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson#include <cstdlib> 20917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson#include <cstring> 215686bf1b38f8aa713267097d7c1944140f71b5d3Eric#include <memory> 22917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson#include <string> 23403f35442375f2ee858981b79421ca321645df0Dominic Hamon 245686bf1b38f8aa713267097d7c1944140f71b5d3Eric#include "check.h" 25a187aa080377f4707bb28690d51f206c0d49f436Eric Fiselier#include "internal_macros.h" 26403f35442375f2ee858981b79421ca321645df0Dominic Hamon 27ba141ac0d9f2042c73f57fcf870f2a69030fa8daAnton Danielsson#ifdef BENCHMARK_OS_WINDOWS 28dd61391c5d92353c69f2789d0dabbd3311fb2564Matt Clarkson#include <Windows.h> 29332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamon#include <io.h> 30917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson#else 31917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson#include <unistd.h> 32332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamon#endif // BENCHMARK_OS_WINDOWS 33dd61391c5d92353c69f2789d0dabbd3311fb2564Matt Clarkson 34e390e4ebc3c728e69d335a33c0cb00547dcd0ddeDominic Hamonnamespace benchmark { 35403f35442375f2ee858981b79421ca321645df0Dominic Hamonnamespace { 36ba141ac0d9f2042c73f57fcf870f2a69030fa8daAnton Danielsson#ifdef BENCHMARK_OS_WINDOWS 37403f35442375f2ee858981b79421ca321645df0Dominic Hamontypedef WORD PlatformColorCode; 38403f35442375f2ee858981b79421ca321645df0Dominic Hamon#else 39403f35442375f2ee858981b79421ca321645df0Dominic Hamontypedef const char* PlatformColorCode; 40403f35442375f2ee858981b79421ca321645df0Dominic Hamon#endif 41403f35442375f2ee858981b79421ca321645df0Dominic Hamon 42403f35442375f2ee858981b79421ca321645df0Dominic HamonPlatformColorCode GetPlatformColorCode(LogColor color) { 43ba141ac0d9f2042c73f57fcf870f2a69030fa8daAnton Danielsson#ifdef BENCHMARK_OS_WINDOWS 44403f35442375f2ee858981b79421ca321645df0Dominic Hamon switch (color) { 454ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_RED: 464ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return FOREGROUND_RED; 474ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_GREEN: 484ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return FOREGROUND_GREEN; 494ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_YELLOW: 504ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return FOREGROUND_RED | FOREGROUND_GREEN; 514ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_BLUE: 524ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return FOREGROUND_BLUE; 534ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_MAGENTA: 544ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return FOREGROUND_BLUE | FOREGROUND_RED; 554ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_CYAN: 564ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return FOREGROUND_BLUE | FOREGROUND_GREEN; 574ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_WHITE: // fall through to default 584ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon default: 594ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return 0; 60403f35442375f2ee858981b79421ca321645df0Dominic Hamon } 61403f35442375f2ee858981b79421ca321645df0Dominic Hamon#else 62403f35442375f2ee858981b79421ca321645df0Dominic Hamon switch (color) { 634ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_RED: 644ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return "1"; 654ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_GREEN: 664ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return "2"; 674ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_YELLOW: 684ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return "3"; 694ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_BLUE: 704ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return "4"; 714ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_MAGENTA: 724ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return "5"; 734ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_CYAN: 744ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return "6"; 754ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon case COLOR_WHITE: 764ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon return "7"; 774ce184d86ddefe6170914a4813940dbcbe645207Dominic Hamon default: 78180981716ba7b568820aa21ecf15247b990a8621Eric Fiselier return nullptr; 79403f35442375f2ee858981b79421ca321645df0Dominic Hamon }; 80403f35442375f2ee858981b79421ca321645df0Dominic Hamon#endif 81403f35442375f2ee858981b79421ca321645df0Dominic Hamon} 825686bf1b38f8aa713267097d7c1944140f71b5d3Eric 83403f35442375f2ee858981b79421ca321645df0Dominic Hamon} // end namespace 84403f35442375f2ee858981b79421ca321645df0Dominic Hamon 85332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamonstd::string FormatString(const char* msg, va_list args) { 865686bf1b38f8aa713267097d7c1944140f71b5d3Eric // we might need a second shot at this, so pre-emptivly make a copy 875686bf1b38f8aa713267097d7c1944140f71b5d3Eric va_list args_cp; 885686bf1b38f8aa713267097d7c1944140f71b5d3Eric va_copy(args_cp, args); 895686bf1b38f8aa713267097d7c1944140f71b5d3Eric 905686bf1b38f8aa713267097d7c1944140f71b5d3Eric std::size_t size = 256; 915686bf1b38f8aa713267097d7c1944140f71b5d3Eric char local_buff[256]; 9209b93ccc6a9aed84c269b6f5b8130c878e518ebbDmitry Trifonov auto ret = vsnprintf(local_buff, size, msg, args_cp); 935686bf1b38f8aa713267097d7c1944140f71b5d3Eric 945686bf1b38f8aa713267097d7c1944140f71b5d3Eric va_end(args_cp); 955686bf1b38f8aa713267097d7c1944140f71b5d3Eric 965686bf1b38f8aa713267097d7c1944140f71b5d3Eric // currently there is no error handling for failure, so this is hack. 975686bf1b38f8aa713267097d7c1944140f71b5d3Eric CHECK(ret >= 0); 985686bf1b38f8aa713267097d7c1944140f71b5d3Eric 99332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamon if (ret == 0) // handle empty expansion 1005686bf1b38f8aa713267097d7c1944140f71b5d3Eric return {}; 1015686bf1b38f8aa713267097d7c1944140f71b5d3Eric else if (static_cast<size_t>(ret) < size) 1025686bf1b38f8aa713267097d7c1944140f71b5d3Eric return local_buff; 1035686bf1b38f8aa713267097d7c1944140f71b5d3Eric else { 1045686bf1b38f8aa713267097d7c1944140f71b5d3Eric // we did not provide a long enough buffer on our first attempt. 105332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamon size = (size_t)ret + 1; // + 1 for the null byte 1065686bf1b38f8aa713267097d7c1944140f71b5d3Eric std::unique_ptr<char[]> buff(new char[size]); 10709b93ccc6a9aed84c269b6f5b8130c878e518ebbDmitry Trifonov ret = vsnprintf(buff.get(), size, msg, args); 1085686bf1b38f8aa713267097d7c1944140f71b5d3Eric CHECK(ret > 0 && ((size_t)ret) < size); 1095686bf1b38f8aa713267097d7c1944140f71b5d3Eric return buff.get(); 1105686bf1b38f8aa713267097d7c1944140f71b5d3Eric } 1115686bf1b38f8aa713267097d7c1944140f71b5d3Eric} 1125686bf1b38f8aa713267097d7c1944140f71b5d3Eric 113332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamonstd::string FormatString(const char* msg, ...) { 1145686bf1b38f8aa713267097d7c1944140f71b5d3Eric va_list args; 1155686bf1b38f8aa713267097d7c1944140f71b5d3Eric va_start(args, msg); 1165686bf1b38f8aa713267097d7c1944140f71b5d3Eric auto tmp = FormatString(msg, args); 1175686bf1b38f8aa713267097d7c1944140f71b5d3Eric va_end(args); 1185686bf1b38f8aa713267097d7c1944140f71b5d3Eric return tmp; 1195686bf1b38f8aa713267097d7c1944140f71b5d3Eric} 1205686bf1b38f8aa713267097d7c1944140f71b5d3Eric 1215686bf1b38f8aa713267097d7c1944140f71b5d3Ericvoid ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) { 122403f35442375f2ee858981b79421ca321645df0Dominic Hamon va_list args; 123403f35442375f2ee858981b79421ca321645df0Dominic Hamon va_start(args, fmt); 12444128d87d2846fc20d540ef41eda6da9ffbb6abaEric Fiselier ColorPrintf(out, color, fmt, args); 12544128d87d2846fc20d540ef41eda6da9ffbb6abaEric Fiselier va_end(args); 12644128d87d2846fc20d540ef41eda6da9ffbb6abaEric Fiselier} 127403f35442375f2ee858981b79421ca321645df0Dominic Hamon 128332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamonvoid ColorPrintf(std::ostream& out, LogColor color, const char* fmt, 129332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamon va_list args) { 130ba141ac0d9f2042c73f57fcf870f2a69030fa8daAnton Danielsson#ifdef BENCHMARK_OS_WINDOWS 131332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamon ((void)out); // suppress unused warning 13244128d87d2846fc20d540ef41eda6da9ffbb6abaEric Fiselier 133403f35442375f2ee858981b79421ca321645df0Dominic Hamon const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); 13480093519382ae748d682e3914ef4ccf07da6ce35Dominic Hamon 135403f35442375f2ee858981b79421ca321645df0Dominic Hamon // Gets the current text color. 136403f35442375f2ee858981b79421ca321645df0Dominic Hamon CONSOLE_SCREEN_BUFFER_INFO buffer_info; 137403f35442375f2ee858981b79421ca321645df0Dominic Hamon GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); 138403f35442375f2ee858981b79421ca321645df0Dominic Hamon const WORD old_color_attrs = buffer_info.wAttributes; 139403f35442375f2ee858981b79421ca321645df0Dominic Hamon 140403f35442375f2ee858981b79421ca321645df0Dominic Hamon // We need to flush the stream buffers into the console before each 141403f35442375f2ee858981b79421ca321645df0Dominic Hamon // SetConsoleTextAttribute call lest it affect the text that is already 142403f35442375f2ee858981b79421ca321645df0Dominic Hamon // printed but has not yet reached the console. 143403f35442375f2ee858981b79421ca321645df0Dominic Hamon fflush(stdout); 144403f35442375f2ee858981b79421ca321645df0Dominic Hamon SetConsoleTextAttribute(stdout_handle, 145403f35442375f2ee858981b79421ca321645df0Dominic Hamon GetPlatformColorCode(color) | FOREGROUND_INTENSITY); 146403f35442375f2ee858981b79421ca321645df0Dominic Hamon vprintf(fmt, args); 147403f35442375f2ee858981b79421ca321645df0Dominic Hamon 148403f35442375f2ee858981b79421ca321645df0Dominic Hamon fflush(stdout); 149403f35442375f2ee858981b79421ca321645df0Dominic Hamon // Restores the text color. 150403f35442375f2ee858981b79421ca321645df0Dominic Hamon SetConsoleTextAttribute(stdout_handle, old_color_attrs); 151403f35442375f2ee858981b79421ca321645df0Dominic Hamon#else 152403f35442375f2ee858981b79421ca321645df0Dominic Hamon const char* color_code = GetPlatformColorCode(color); 1535686bf1b38f8aa713267097d7c1944140f71b5d3Eric if (color_code) out << FormatString("\033[0;3%sm", color_code); 1545686bf1b38f8aa713267097d7c1944140f71b5d3Eric out << FormatString(fmt, args) << "\033[m"; 155403f35442375f2ee858981b79421ca321645df0Dominic Hamon#endif 156403f35442375f2ee858981b79421ca321645df0Dominic Hamon} 1575686bf1b38f8aa713267097d7c1944140f71b5d3Eric 158917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinsonbool IsColorTerminal() { 159917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson#if BENCHMARK_OS_WINDOWS 160917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson // On Windows the TERM variable is usually not set, but the 161917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson // console there does support colors. 162917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson return 0 != _isatty(_fileno(stdout)); 163917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson#else 164917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson // On non-Windows platforms, we rely on the TERM variable. This list of 165917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson // supported TERM values is copied from Google Test: 166917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson // <https://github.com/google/googletest/blob/master/googletest/src/gtest.cc#L2925>. 167917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson const char* const SUPPORTED_TERM_VALUES[] = { 168917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson "xterm", "xterm-color", "xterm-256color", 169917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson "screen", "screen-256color", "tmux", 170917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson "tmux-256color", "rxvt-unicode", "rxvt-unicode-256color", 171917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson "linux", "cygwin", 172917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson }; 173917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson 174917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson const char* const term = getenv("TERM"); 175917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson 176917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson bool term_supports_color = false; 177917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson for (const char* candidate : SUPPORTED_TERM_VALUES) { 178917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson if (term && 0 == strcmp(term, candidate)) { 179917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson term_supports_color = true; 180917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson break; 181917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson } 182917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson } 183917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson 184917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson return 0 != isatty(fileno(stdout)) && term_supports_color; 185332f677b8bec401641a2743ab5d741c13cc6811dDominic Hamon#endif // BENCHMARK_OS_WINDOWS 186917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson} 187917b86e615f659d9fb9819d1fa765cd459fc6861Nicholas Hutchinson 188e390e4ebc3c728e69d335a33c0cb00547dcd0ddeDominic Hamon} // end namespace benchmark 189