1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "colorprint.h"
16
17#include <cstdarg>
18#include <cstdio>
19
20#include "commandlineflags.h"
21#include "internal_macros.h"
22
23#ifdef BENCHMARK_OS_WINDOWS
24#include <Windows.h>
25#endif
26
27DECLARE_bool(color_print);
28
29namespace benchmark {
30namespace {
31#ifdef BENCHMARK_OS_WINDOWS
32typedef WORD PlatformColorCode;
33#else
34typedef const char* PlatformColorCode;
35#endif
36
37PlatformColorCode GetPlatformColorCode(LogColor color) {
38#ifdef BENCHMARK_OS_WINDOWS
39  switch (color) {
40    case COLOR_RED:
41      return FOREGROUND_RED;
42    case COLOR_GREEN:
43      return FOREGROUND_GREEN;
44    case COLOR_YELLOW:
45      return FOREGROUND_RED | FOREGROUND_GREEN;
46    case COLOR_BLUE:
47      return FOREGROUND_BLUE;
48    case COLOR_MAGENTA:
49      return FOREGROUND_BLUE | FOREGROUND_RED;
50    case COLOR_CYAN:
51      return FOREGROUND_BLUE | FOREGROUND_GREEN;
52    case COLOR_WHITE:  // fall through to default
53    default:
54      return 0;
55  }
56#else
57  switch (color) {
58    case COLOR_RED:
59      return "1";
60    case COLOR_GREEN:
61      return "2";
62    case COLOR_YELLOW:
63      return "3";
64    case COLOR_BLUE:
65      return "4";
66    case COLOR_MAGENTA:
67      return "5";
68    case COLOR_CYAN:
69      return "6";
70    case COLOR_WHITE:
71      return "7";
72    default:
73      return nullptr;
74  };
75#endif
76}
77}  // end namespace
78
79void ColorPrintf(LogColor color, const char* fmt, ...) {
80  va_list args;
81  va_start(args, fmt);
82
83  if (!FLAGS_color_print) {
84    vprintf(fmt, args);
85    va_end(args);
86    return;
87  }
88
89#ifdef BENCHMARK_OS_WINDOWS
90  const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
91
92  // Gets the current text color.
93  CONSOLE_SCREEN_BUFFER_INFO buffer_info;
94  GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
95  const WORD old_color_attrs = buffer_info.wAttributes;
96
97  // We need to flush the stream buffers into the console before each
98  // SetConsoleTextAttribute call lest it affect the text that is already
99  // printed but has not yet reached the console.
100  fflush(stdout);
101  SetConsoleTextAttribute(stdout_handle,
102                          GetPlatformColorCode(color) | FOREGROUND_INTENSITY);
103  vprintf(fmt, args);
104
105  fflush(stdout);
106  // Restores the text color.
107  SetConsoleTextAttribute(stdout_handle, old_color_attrs);
108#else
109  const char* color_code = GetPlatformColorCode(color);
110  if (color_code) fprintf(stdout, "\033[0;3%sm", color_code);
111  vprintf(fmt, args);
112  printf("\033[m");  // Resets the terminal to default.
113#endif
114  va_end(args);
115}
116}  // end namespace benchmark
117