1a8c51b3fSopenharmony_ci// Copyright 2015 Google Inc. All rights reserved. 2a8c51b3fSopenharmony_ci// 3a8c51b3fSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4a8c51b3fSopenharmony_ci// you may not use this file except in compliance with the License. 5a8c51b3fSopenharmony_ci// You may obtain a copy of the License at 6a8c51b3fSopenharmony_ci// 7a8c51b3fSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8a8c51b3fSopenharmony_ci// 9a8c51b3fSopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10a8c51b3fSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11a8c51b3fSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12a8c51b3fSopenharmony_ci// See the License for the specific language governing permissions and 13a8c51b3fSopenharmony_ci// limitations under the License. 14a8c51b3fSopenharmony_ci 15a8c51b3fSopenharmony_ci#include "colorprint.h" 16a8c51b3fSopenharmony_ci 17a8c51b3fSopenharmony_ci#include <cstdarg> 18a8c51b3fSopenharmony_ci#include <cstdio> 19a8c51b3fSopenharmony_ci#include <cstdlib> 20a8c51b3fSopenharmony_ci#include <cstring> 21a8c51b3fSopenharmony_ci#include <memory> 22a8c51b3fSopenharmony_ci#include <string> 23a8c51b3fSopenharmony_ci 24a8c51b3fSopenharmony_ci#include "check.h" 25a8c51b3fSopenharmony_ci#include "internal_macros.h" 26a8c51b3fSopenharmony_ci 27a8c51b3fSopenharmony_ci#ifdef BENCHMARK_OS_WINDOWS 28a8c51b3fSopenharmony_ci#include <io.h> 29a8c51b3fSopenharmony_ci#include <windows.h> 30a8c51b3fSopenharmony_ci#else 31a8c51b3fSopenharmony_ci#include <unistd.h> 32a8c51b3fSopenharmony_ci#endif // BENCHMARK_OS_WINDOWS 33a8c51b3fSopenharmony_ci 34a8c51b3fSopenharmony_cinamespace benchmark { 35a8c51b3fSopenharmony_cinamespace { 36a8c51b3fSopenharmony_ci#ifdef BENCHMARK_OS_WINDOWS 37a8c51b3fSopenharmony_citypedef WORD PlatformColorCode; 38a8c51b3fSopenharmony_ci#else 39a8c51b3fSopenharmony_citypedef const char* PlatformColorCode; 40a8c51b3fSopenharmony_ci#endif 41a8c51b3fSopenharmony_ci 42a8c51b3fSopenharmony_ciPlatformColorCode GetPlatformColorCode(LogColor color) { 43a8c51b3fSopenharmony_ci#ifdef BENCHMARK_OS_WINDOWS 44a8c51b3fSopenharmony_ci switch (color) { 45a8c51b3fSopenharmony_ci case COLOR_RED: 46a8c51b3fSopenharmony_ci return FOREGROUND_RED; 47a8c51b3fSopenharmony_ci case COLOR_GREEN: 48a8c51b3fSopenharmony_ci return FOREGROUND_GREEN; 49a8c51b3fSopenharmony_ci case COLOR_YELLOW: 50a8c51b3fSopenharmony_ci return FOREGROUND_RED | FOREGROUND_GREEN; 51a8c51b3fSopenharmony_ci case COLOR_BLUE: 52a8c51b3fSopenharmony_ci return FOREGROUND_BLUE; 53a8c51b3fSopenharmony_ci case COLOR_MAGENTA: 54a8c51b3fSopenharmony_ci return FOREGROUND_BLUE | FOREGROUND_RED; 55a8c51b3fSopenharmony_ci case COLOR_CYAN: 56a8c51b3fSopenharmony_ci return FOREGROUND_BLUE | FOREGROUND_GREEN; 57a8c51b3fSopenharmony_ci case COLOR_WHITE: // fall through to default 58a8c51b3fSopenharmony_ci default: 59a8c51b3fSopenharmony_ci return 0; 60a8c51b3fSopenharmony_ci } 61a8c51b3fSopenharmony_ci#else 62a8c51b3fSopenharmony_ci switch (color) { 63a8c51b3fSopenharmony_ci case COLOR_RED: 64a8c51b3fSopenharmony_ci return "1"; 65a8c51b3fSopenharmony_ci case COLOR_GREEN: 66a8c51b3fSopenharmony_ci return "2"; 67a8c51b3fSopenharmony_ci case COLOR_YELLOW: 68a8c51b3fSopenharmony_ci return "3"; 69a8c51b3fSopenharmony_ci case COLOR_BLUE: 70a8c51b3fSopenharmony_ci return "4"; 71a8c51b3fSopenharmony_ci case COLOR_MAGENTA: 72a8c51b3fSopenharmony_ci return "5"; 73a8c51b3fSopenharmony_ci case COLOR_CYAN: 74a8c51b3fSopenharmony_ci return "6"; 75a8c51b3fSopenharmony_ci case COLOR_WHITE: 76a8c51b3fSopenharmony_ci return "7"; 77a8c51b3fSopenharmony_ci default: 78a8c51b3fSopenharmony_ci return nullptr; 79a8c51b3fSopenharmony_ci }; 80a8c51b3fSopenharmony_ci#endif 81a8c51b3fSopenharmony_ci} 82a8c51b3fSopenharmony_ci 83a8c51b3fSopenharmony_ci} // end namespace 84a8c51b3fSopenharmony_ci 85a8c51b3fSopenharmony_cistd::string FormatString(const char* msg, va_list args) { 86a8c51b3fSopenharmony_ci // we might need a second shot at this, so pre-emptivly make a copy 87a8c51b3fSopenharmony_ci va_list args_cp; 88a8c51b3fSopenharmony_ci va_copy(args_cp, args); 89a8c51b3fSopenharmony_ci 90a8c51b3fSopenharmony_ci std::size_t size = 256; 91a8c51b3fSopenharmony_ci char local_buff[256]; 92a8c51b3fSopenharmony_ci auto ret = vsnprintf(local_buff, size, msg, args_cp); 93a8c51b3fSopenharmony_ci 94a8c51b3fSopenharmony_ci va_end(args_cp); 95a8c51b3fSopenharmony_ci 96a8c51b3fSopenharmony_ci // currently there is no error handling for failure, so this is hack. 97a8c51b3fSopenharmony_ci BM_CHECK(ret >= 0); 98a8c51b3fSopenharmony_ci 99a8c51b3fSopenharmony_ci if (ret == 0) { // handle empty expansion 100a8c51b3fSopenharmony_ci return {}; 101a8c51b3fSopenharmony_ci } 102a8c51b3fSopenharmony_ci if (static_cast<size_t>(ret) < size) { 103a8c51b3fSopenharmony_ci return local_buff; 104a8c51b3fSopenharmony_ci } 105a8c51b3fSopenharmony_ci // we did not provide a long enough buffer on our first attempt. 106a8c51b3fSopenharmony_ci size = static_cast<size_t>(ret) + 1; // + 1 for the null byte 107a8c51b3fSopenharmony_ci std::unique_ptr<char[]> buff(new char[size]); 108a8c51b3fSopenharmony_ci ret = vsnprintf(buff.get(), size, msg, args); 109a8c51b3fSopenharmony_ci BM_CHECK(ret > 0 && (static_cast<size_t>(ret)) < size); 110a8c51b3fSopenharmony_ci return buff.get(); 111a8c51b3fSopenharmony_ci} 112a8c51b3fSopenharmony_ci 113a8c51b3fSopenharmony_cistd::string FormatString(const char* msg, ...) { 114a8c51b3fSopenharmony_ci va_list args; 115a8c51b3fSopenharmony_ci va_start(args, msg); 116a8c51b3fSopenharmony_ci auto tmp = FormatString(msg, args); 117a8c51b3fSopenharmony_ci va_end(args); 118a8c51b3fSopenharmony_ci return tmp; 119a8c51b3fSopenharmony_ci} 120a8c51b3fSopenharmony_ci 121a8c51b3fSopenharmony_civoid ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) { 122a8c51b3fSopenharmony_ci va_list args; 123a8c51b3fSopenharmony_ci va_start(args, fmt); 124a8c51b3fSopenharmony_ci ColorPrintf(out, color, fmt, args); 125a8c51b3fSopenharmony_ci va_end(args); 126a8c51b3fSopenharmony_ci} 127a8c51b3fSopenharmony_ci 128a8c51b3fSopenharmony_civoid ColorPrintf(std::ostream& out, LogColor color, const char* fmt, 129a8c51b3fSopenharmony_ci va_list args) { 130a8c51b3fSopenharmony_ci#ifdef BENCHMARK_OS_WINDOWS 131a8c51b3fSopenharmony_ci ((void)out); // suppress unused warning 132a8c51b3fSopenharmony_ci 133a8c51b3fSopenharmony_ci const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); 134a8c51b3fSopenharmony_ci 135a8c51b3fSopenharmony_ci // Gets the current text color. 136a8c51b3fSopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO buffer_info; 137a8c51b3fSopenharmony_ci GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); 138a8c51b3fSopenharmony_ci const WORD old_color_attrs = buffer_info.wAttributes; 139a8c51b3fSopenharmony_ci 140a8c51b3fSopenharmony_ci // We need to flush the stream buffers into the console before each 141a8c51b3fSopenharmony_ci // SetConsoleTextAttribute call lest it affect the text that is already 142a8c51b3fSopenharmony_ci // printed but has not yet reached the console. 143a8c51b3fSopenharmony_ci fflush(stdout); 144a8c51b3fSopenharmony_ci SetConsoleTextAttribute(stdout_handle, 145a8c51b3fSopenharmony_ci GetPlatformColorCode(color) | FOREGROUND_INTENSITY); 146a8c51b3fSopenharmony_ci vprintf(fmt, args); 147a8c51b3fSopenharmony_ci 148a8c51b3fSopenharmony_ci fflush(stdout); 149a8c51b3fSopenharmony_ci // Restores the text color. 150a8c51b3fSopenharmony_ci SetConsoleTextAttribute(stdout_handle, old_color_attrs); 151a8c51b3fSopenharmony_ci#else 152a8c51b3fSopenharmony_ci const char* color_code = GetPlatformColorCode(color); 153a8c51b3fSopenharmony_ci if (color_code) out << FormatString("\033[0;3%sm", color_code); 154a8c51b3fSopenharmony_ci out << FormatString(fmt, args) << "\033[m"; 155a8c51b3fSopenharmony_ci#endif 156a8c51b3fSopenharmony_ci} 157a8c51b3fSopenharmony_ci 158a8c51b3fSopenharmony_cibool IsColorTerminal() { 159a8c51b3fSopenharmony_ci#if BENCHMARK_OS_WINDOWS 160a8c51b3fSopenharmony_ci // On Windows the TERM variable is usually not set, but the 161a8c51b3fSopenharmony_ci // console there does support colors. 162a8c51b3fSopenharmony_ci return 0 != _isatty(_fileno(stdout)); 163a8c51b3fSopenharmony_ci#else 164a8c51b3fSopenharmony_ci // On non-Windows platforms, we rely on the TERM variable. This list of 165a8c51b3fSopenharmony_ci // supported TERM values is copied from Google Test: 166a8c51b3fSopenharmony_ci // <https://github.com/google/googletest/blob/v1.13.0/googletest/src/gtest.cc#L3225-L3259>. 167a8c51b3fSopenharmony_ci const char* const SUPPORTED_TERM_VALUES[] = { 168a8c51b3fSopenharmony_ci "xterm", 169a8c51b3fSopenharmony_ci "xterm-color", 170a8c51b3fSopenharmony_ci "xterm-256color", 171a8c51b3fSopenharmony_ci "screen", 172a8c51b3fSopenharmony_ci "screen-256color", 173a8c51b3fSopenharmony_ci "tmux", 174a8c51b3fSopenharmony_ci "tmux-256color", 175a8c51b3fSopenharmony_ci "rxvt-unicode", 176a8c51b3fSopenharmony_ci "rxvt-unicode-256color", 177a8c51b3fSopenharmony_ci "linux", 178a8c51b3fSopenharmony_ci "cygwin", 179a8c51b3fSopenharmony_ci "xterm-kitty", 180a8c51b3fSopenharmony_ci "alacritty", 181a8c51b3fSopenharmony_ci "foot", 182a8c51b3fSopenharmony_ci "foot-extra", 183a8c51b3fSopenharmony_ci "wezterm", 184a8c51b3fSopenharmony_ci }; 185a8c51b3fSopenharmony_ci 186a8c51b3fSopenharmony_ci const char* const term = getenv("TERM"); 187a8c51b3fSopenharmony_ci 188a8c51b3fSopenharmony_ci bool term_supports_color = false; 189a8c51b3fSopenharmony_ci for (const char* candidate : SUPPORTED_TERM_VALUES) { 190a8c51b3fSopenharmony_ci if (term && 0 == strcmp(term, candidate)) { 191a8c51b3fSopenharmony_ci term_supports_color = true; 192a8c51b3fSopenharmony_ci break; 193a8c51b3fSopenharmony_ci } 194a8c51b3fSopenharmony_ci } 195a8c51b3fSopenharmony_ci 196a8c51b3fSopenharmony_ci return 0 != isatty(fileno(stdout)) && term_supports_color; 197a8c51b3fSopenharmony_ci#endif // BENCHMARK_OS_WINDOWS 198a8c51b3fSopenharmony_ci} 199a8c51b3fSopenharmony_ci 200a8c51b3fSopenharmony_ci} // end namespace benchmark 201