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 
27 DECLARE_bool(color_print);
28 
29 namespace benchmark {
30 namespace {
31 #ifdef BENCHMARK_OS_WINDOWS
32 typedef WORD PlatformColorCode;
33 #else
34 typedef const char* PlatformColorCode;
35 #endif
36 
GetPlatformColorCode(LogColor color)37 PlatformColorCode 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 
ColorPrintf(LogColor color,const char * fmt,...)79 void 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