Index: third_party/google_benchmark/src/colorprint.cc |
diff --git a/third_party/google_benchmark/src/colorprint.cc b/third_party/google_benchmark/src/colorprint.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2dec4a8b28ba8d3056574a1e2d2af18f0b58636c |
--- /dev/null |
+++ b/third_party/google_benchmark/src/colorprint.cc |
@@ -0,0 +1,188 @@ |
+// Copyright 2015 Google Inc. All rights reserved. |
+// |
+// Licensed 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. |
+ |
+#include "colorprint.h" |
+ |
+#include <cstdarg> |
+#include <cstdio> |
+#include <cstdlib> |
+#include <cstring> |
+#include <memory> |
+#include <string> |
+ |
+#include "check.h" |
+#include "internal_macros.h" |
+ |
+#ifdef BENCHMARK_OS_WINDOWS |
+#include <Windows.h> |
+#include <io.h> |
+#else |
+#include <unistd.h> |
+#endif // BENCHMARK_OS_WINDOWS |
+ |
+namespace benchmark { |
+namespace { |
+#ifdef BENCHMARK_OS_WINDOWS |
+typedef WORD PlatformColorCode; |
+#else |
+typedef const char* PlatformColorCode; |
+#endif |
+ |
+PlatformColorCode GetPlatformColorCode(LogColor color) { |
+#ifdef BENCHMARK_OS_WINDOWS |
+ switch (color) { |
+ case COLOR_RED: |
+ return FOREGROUND_RED; |
+ case COLOR_GREEN: |
+ return FOREGROUND_GREEN; |
+ case COLOR_YELLOW: |
+ return FOREGROUND_RED | FOREGROUND_GREEN; |
+ case COLOR_BLUE: |
+ return FOREGROUND_BLUE; |
+ case COLOR_MAGENTA: |
+ return FOREGROUND_BLUE | FOREGROUND_RED; |
+ case COLOR_CYAN: |
+ return FOREGROUND_BLUE | FOREGROUND_GREEN; |
+ case COLOR_WHITE: // fall through to default |
+ default: |
+ return 0; |
+ } |
+#else |
+ switch (color) { |
+ case COLOR_RED: |
+ return "1"; |
+ case COLOR_GREEN: |
+ return "2"; |
+ case COLOR_YELLOW: |
+ return "3"; |
+ case COLOR_BLUE: |
+ return "4"; |
+ case COLOR_MAGENTA: |
+ return "5"; |
+ case COLOR_CYAN: |
+ return "6"; |
+ case COLOR_WHITE: |
+ return "7"; |
+ default: |
+ return nullptr; |
+ }; |
+#endif |
+} |
+ |
+} // end namespace |
+ |
+std::string FormatString(const char* msg, va_list args) { |
+ // we might need a second shot at this, so pre-emptivly make a copy |
+ va_list args_cp; |
+ va_copy(args_cp, args); |
+ |
+ std::size_t size = 256; |
+ char local_buff[256]; |
+ auto ret = vsnprintf(local_buff, size, msg, args_cp); |
+ |
+ va_end(args_cp); |
+ |
+ // currently there is no error handling for failure, so this is hack. |
+ CHECK(ret >= 0); |
+ |
+ if (ret == 0) // handle empty expansion |
+ return {}; |
+ else if (static_cast<size_t>(ret) < size) |
+ return local_buff; |
+ else { |
+ // we did not provide a long enough buffer on our first attempt. |
+ size = (size_t)ret + 1; // + 1 for the null byte |
+ std::unique_ptr<char[]> buff(new char[size]); |
+ ret = vsnprintf(buff.get(), size, msg, args); |
+ CHECK(ret > 0 && ((size_t)ret) < size); |
+ return buff.get(); |
+ } |
+} |
+ |
+std::string FormatString(const char* msg, ...) { |
+ va_list args; |
+ va_start(args, msg); |
+ auto tmp = FormatString(msg, args); |
+ va_end(args); |
+ return tmp; |
+} |
+ |
+void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, ...) { |
+ va_list args; |
+ va_start(args, fmt); |
+ ColorPrintf(out, color, fmt, args); |
+ va_end(args); |
+} |
+ |
+void ColorPrintf(std::ostream& out, LogColor color, const char* fmt, |
+ va_list args) { |
+#ifdef BENCHMARK_OS_WINDOWS |
+ ((void)out); // suppress unused warning |
+ |
+ const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); |
+ |
+ // Gets the current text color. |
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info; |
+ GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); |
+ const WORD old_color_attrs = buffer_info.wAttributes; |
+ |
+ // We need to flush the stream buffers into the console before each |
+ // SetConsoleTextAttribute call lest it affect the text that is already |
+ // printed but has not yet reached the console. |
+ fflush(stdout); |
+ SetConsoleTextAttribute(stdout_handle, |
+ GetPlatformColorCode(color) | FOREGROUND_INTENSITY); |
+ vprintf(fmt, args); |
+ |
+ fflush(stdout); |
+ // Restores the text color. |
+ SetConsoleTextAttribute(stdout_handle, old_color_attrs); |
+#else |
+ const char* color_code = GetPlatformColorCode(color); |
+ if (color_code) out << FormatString("\033[0;3%sm", color_code); |
+ out << FormatString(fmt, args) << "\033[m"; |
+#endif |
+} |
+ |
+bool IsColorTerminal() { |
+#if BENCHMARK_OS_WINDOWS |
+ // On Windows the TERM variable is usually not set, but the |
+ // console there does support colors. |
+ return 0 != _isatty(_fileno(stdout)); |
+#else |
+ // On non-Windows platforms, we rely on the TERM variable. This list of |
+ // supported TERM values is copied from Google Test: |
+ // <https://github.com/google/googletest/blob/master/googletest/src/gtest.cc#L2925>. |
+ const char* const SUPPORTED_TERM_VALUES[] = { |
+ "xterm", "xterm-color", "xterm-256color", |
+ "screen", "screen-256color", "tmux", |
+ "tmux-256color", "rxvt-unicode", "rxvt-unicode-256color", |
+ "linux", "cygwin", |
+ }; |
+ |
+ const char* const term = getenv("TERM"); |
+ |
+ bool term_supports_color = false; |
+ for (const char* candidate : SUPPORTED_TERM_VALUES) { |
+ if (term && 0 == strcmp(term, candidate)) { |
+ term_supports_color = true; |
+ break; |
+ } |
+ } |
+ |
+ return 0 != isatty(fileno(stdout)) && term_supports_color; |
+#endif // BENCHMARK_OS_WINDOWS |
+} |
+ |
+} // end namespace benchmark |