1 /*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2010, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the copyright holder(s) nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *
34 * $Id$
35 *
36 */
37 #include <pcl/console/print.h>
38 #include <algorithm>
39 #include <cstdarg> // for va_list, va_start, va_end
40 #include <cstdlib>
41 #include <cctype> // for toupper
42 #include <map>
43 #include <string>
44 #include <boost/optional.hpp>
45
46 #if defined _WIN32
47 # include <windows.h>
48 # include <io.h>
49
50 #ifndef _MSC_VER
51 # define COMMON_LVB_UNDERSCORE 0
52 # define COMMON_LVB_REVERSE_VIDEO 0
53 #endif
54
55 WORD
convertAttributesColor(int attribute,int fg,int bg=0)56 convertAttributesColor (int attribute, int fg, int bg=0)
57 {
58 static WORD wAttributes[7] = { 0, // TT_RESET
59 FOREGROUND_INTENSITY , // TT_BRIGHT
60 0, // TT_DIM
61 COMMON_LVB_UNDERSCORE, // TT_UNDERLINE
62 0, // TT_BLINK
63 COMMON_LVB_REVERSE_VIDEO, // TT_REVERSE
64 0 // TT_HIDDEN
65 };
66 static WORD wFgColors[8] = { 0, // TT_BLACK
67 FOREGROUND_RED, // TT_RED
68 FOREGROUND_GREEN , // TT_GREEN
69 FOREGROUND_GREEN | FOREGROUND_RED , // TT_YELLOW
70 FOREGROUND_BLUE , // TT_BLUE
71 FOREGROUND_RED | FOREGROUND_BLUE , // TT_MAGENTA
72 FOREGROUND_GREEN | FOREGROUND_BLUE, // TT_CYAN
73 FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED // TT_WHITE
74 };
75 static WORD wBgColors[8] = { 0, // TT_BLACK
76 BACKGROUND_RED, // TT_RED
77 BACKGROUND_GREEN , // TT_GREEN
78 BACKGROUND_GREEN | BACKGROUND_BLUE , // TT_YELLOW
79 BACKGROUND_BLUE , // TT_BLUE
80 BACKGROUND_RED | BACKGROUND_BLUE , // TT_MAGENTA
81 BACKGROUND_GREEN | BACKGROUND_BLUE, // TT_CYAN
82 BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED // TT_WHITE
83 };
84
85 return wAttributes[attribute] | wFgColors[fg] | wBgColors[bg];
86 }
87
88 #else
89 # include <unistd.h>
90 # include <cstdio>
91 #endif
92
93 // Map to store, for each output stream, whether to use colored output
94 static std::map<FILE *, boost::optional<bool> > colored_output;
95
96 ////////////////////////////////////////////////////////////////////////////////
97 inline bool
useColoredOutput(FILE * stream)98 useColoredOutput (FILE *stream)
99 {
100 auto &colored = colored_output[stream];
101 if (!colored)
102 {
103 // Use colored output if PCL_CLICOLOR_FORCE is set or if the output is an interactive terminal
104 #ifdef _WIN32
105 colored = getenv ("PCL_CLICOLOR_FORCE") || _isatty (_fileno (stream));
106 #else
107 colored = getenv ("PCL_CLICOLOR_FORCE") || isatty (fileno (stream));
108 #endif
109 }
110 return colored.get ();
111 }
112
113 ////////////////////////////////////////////////////////////////////////////////
114 void
enableColoredOutput(FILE * stream,bool enable)115 pcl::console::enableColoredOutput (FILE *stream, bool enable)
116 {
117 colored_output[stream] = enable;
118 }
119
120 ////////////////////////////////////////////////////////////////////////////////
121 void
change_text_color(FILE * stream,int attribute,int fg,int bg)122 pcl::console::change_text_color (FILE *stream, int attribute, int fg, int bg)
123 {
124 if (!useColoredOutput (stream)) return;
125
126 #ifdef _WIN32
127 HANDLE h = GetStdHandle ((stream == stdout) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
128 SetConsoleTextAttribute (h, convertAttributesColor (attribute, fg, bg));
129 #else
130 char command[40];
131 // Command is the control command to the terminal
132 sprintf (command, "%c[%d;%d;%dm", 0x1B, attribute, fg + 30, bg + 40);
133 fprintf (stream, "%s", command);
134 #endif
135 }
136
137 ////////////////////////////////////////////////////////////////////////////////
138 void
change_text_color(FILE * stream,int attribute,int fg)139 pcl::console::change_text_color (FILE *stream, int attribute, int fg)
140 {
141 if (!useColoredOutput (stream)) return;
142
143 #ifdef _WIN32
144 HANDLE h = GetStdHandle ((stream == stdout) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
145 SetConsoleTextAttribute (h, convertAttributesColor (attribute, fg));
146 #else
147 char command[17];
148 // Command is the control command to the terminal
149 sprintf (command, "%c[%d;%dm", 0x1B, attribute, fg + 30);
150 fprintf (stream, "%s", command);
151 #endif
152 }
153
154 ////////////////////////////////////////////////////////////////////////////////
155 void
reset_text_color(FILE * stream)156 pcl::console::reset_text_color (FILE *stream)
157 {
158 if (!useColoredOutput (stream)) return;
159
160 #ifdef _WIN32
161 HANDLE h = GetStdHandle ((stream == stdout) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
162 SetConsoleTextAttribute (h, convertAttributesColor (0, TT_WHITE, TT_BLACK));
163 #else
164 char command[13];
165 // Command is the control command to the terminal
166 sprintf (command, "%c[0;m", 0x1B);
167 fprintf (stream, "%s", command);
168 #endif
169 }
170
171 ////////////////////////////////////////////////////////////////////////////////
172 void
print_color(FILE * stream,int attr,int fg,const char * format,...)173 pcl::console::print_color (FILE *stream, int attr, int fg, const char *format, ...)
174 {
175 change_text_color (stream, attr, fg);
176 va_list ap;
177
178 va_start (ap, format);
179 vfprintf (stream, format, ap);
180 va_end (ap);
181
182 reset_text_color (stream);
183 }
184
185 ////////////////////////////////////////////////////////////////////////////////
186 void
print_info(const char * format,...)187 pcl::console::print_info (const char *format, ...)
188 {
189 if (!isVerbosityLevelEnabled (L_INFO)) return;
190
191 reset_text_color (stdout);
192
193 va_list ap;
194
195 va_start (ap, format);
196 vfprintf (stdout, format, ap);
197 va_end (ap);
198 }
199
200 ////////////////////////////////////////////////////////////////////////////////
201 void
print_info(FILE * stream,const char * format,...)202 pcl::console::print_info (FILE *stream, const char *format, ...)
203 {
204 if (!isVerbosityLevelEnabled (L_INFO)) return;
205
206 reset_text_color (stream);
207
208 va_list ap;
209
210 va_start (ap, format);
211 vfprintf (stream, format, ap);
212 va_end (ap);
213 }
214
215 ////////////////////////////////////////////////////////////////////////////////
216 void
print_highlight(const char * format,...)217 pcl::console::print_highlight (const char *format, ...)
218 {
219 //if (!isVerbosityLevelEnabled (L_ALWAYS)) return;
220
221 change_text_color (stdout, TT_BRIGHT, TT_GREEN);
222 fprintf (stdout, "> ");
223 reset_text_color (stdout);
224
225 va_list ap;
226
227 va_start (ap, format);
228 vfprintf (stdout, format, ap);
229 va_end (ap);
230 }
231
232 ////////////////////////////////////////////////////////////////////////////////
233 void
print_highlight(FILE * stream,const char * format,...)234 pcl::console::print_highlight (FILE *stream, const char *format, ...)
235 {
236 //if (!isVerbosityLevelEnabled (L_ALWAYS)) return;
237
238 change_text_color (stream, TT_BRIGHT, TT_GREEN);
239 fprintf (stream, "> ");
240 reset_text_color (stream);
241
242 va_list ap;
243
244 va_start (ap, format);
245 vfprintf (stream, format, ap);
246 va_end (ap);
247 }
248
249 ////////////////////////////////////////////////////////////////////////////////
250 void
print_error(const char * format,...)251 pcl::console::print_error (const char *format, ...)
252 {
253 if (!isVerbosityLevelEnabled (L_ERROR)) return;
254
255 change_text_color (stderr, TT_BRIGHT, TT_RED);
256 va_list ap;
257
258 va_start (ap, format);
259 vfprintf (stderr, format, ap);
260 va_end (ap);
261
262 reset_text_color (stderr);
263 }
264
265 ////////////////////////////////////////////////////////////////////////////////
266 void
print_error(FILE * stream,const char * format,...)267 pcl::console::print_error (FILE *stream, const char *format, ...)
268 {
269 if (!isVerbosityLevelEnabled (L_ERROR)) return;
270
271 change_text_color (stream, TT_BRIGHT, TT_RED);
272 va_list ap;
273
274 va_start (ap, format);
275 vfprintf (stream, format, ap);
276 va_end (ap);
277
278 reset_text_color (stream);
279 }
280
281 ////////////////////////////////////////////////////////////////////////////////
282 void
print_warn(const char * format,...)283 pcl::console::print_warn (const char *format, ...)
284 {
285 if (!isVerbosityLevelEnabled (L_WARN)) return;
286
287 change_text_color (stderr, TT_BRIGHT, TT_YELLOW);
288 va_list ap;
289
290 va_start (ap, format);
291 vfprintf (stderr, format, ap);
292 va_end (ap);
293
294 reset_text_color (stderr);
295 }
296
297 ////////////////////////////////////////////////////////////////////////////////
298 void
print_warn(FILE * stream,const char * format,...)299 pcl::console::print_warn (FILE *stream, const char *format, ...)
300 {
301 if (!isVerbosityLevelEnabled (L_WARN)) return;
302
303 change_text_color (stream, TT_BRIGHT, TT_YELLOW);
304 va_list ap;
305
306 va_start (ap, format);
307 vfprintf (stream, format, ap);
308 va_end (ap);
309
310 reset_text_color (stream);
311 }
312
313 ////////////////////////////////////////////////////////////////////////////////
314 void
print_value(const char * format,...)315 pcl::console::print_value (const char *format, ...)
316 {
317 //if (!isVerbosityLevelEnabled (L_ALWAYS)) return;
318
319 change_text_color (stdout, TT_RESET, TT_CYAN);
320 va_list ap;
321
322 va_start (ap, format);
323 vfprintf (stdout, format, ap);
324 va_end (ap);
325
326 reset_text_color (stdout);
327 }
328
329 ////////////////////////////////////////////////////////////////////////////////
330 void
print_value(FILE * stream,const char * format,...)331 pcl::console::print_value (FILE *stream, const char *format, ...)
332 {
333 //if (!isVerbosityLevelEnabled (L_ALWAYS)) return;
334
335 change_text_color (stream, TT_RESET, TT_CYAN);
336 va_list ap;
337
338 va_start (ap, format);
339 vfprintf (stream, format, ap);
340 va_end (ap);
341
342 reset_text_color (stream);
343 }
344
345 ////////////////////////////////////////////////////////////////////////////////
346 void
print_debug(const char * format,...)347 pcl::console::print_debug (const char *format, ...)
348 {
349 if (!isVerbosityLevelEnabled (L_DEBUG)) return;
350
351 change_text_color (stdout, TT_RESET, TT_GREEN);
352 va_list ap;
353
354 va_start (ap, format);
355 vfprintf (stdout, format, ap);
356 va_end (ap);
357
358 reset_text_color (stdout);
359 }
360
361 ////////////////////////////////////////////////////////////////////////////////
362 void
print_debug(FILE * stream,const char * format,...)363 pcl::console::print_debug (FILE *stream, const char *format, ...)
364 {
365 if (!isVerbosityLevelEnabled (L_DEBUG)) return;
366
367 change_text_color (stream, TT_RESET, TT_GREEN);
368 va_list ap;
369
370 va_start (ap, format);
371 vfprintf (stream, format, ap);
372 va_end (ap);
373
374 reset_text_color (stream);
375 }
376
377 ////////////////////////////////////////////////////////////////////////////////
378 namespace pcl
379 {
380 namespace console
381 {
382 static bool s_NeedVerbosityInit = true;
383 #ifdef VERBOSITY_LEVEL_ALWAYS
384 static VERBOSITY_LEVEL s_VerbosityLevel = pcl::console::L_ALWAYS;
385 #elif defined VERBOSITY_LEVEL_ERROR
386 static VERBOSITY_LEVEL s_VerbosityLevel = pcl::console::L_ERROR;
387 #elif defined VERBOSITY_LEVEL_WARN
388 static VERBOSITY_LEVEL s_VerbosityLevel = pcl::console::L_WARN;
389 #elif defined VERBOSITY_LEVEL_DEBUG
390 static VERBOSITY_LEVEL s_VerbosityLevel = pcl::console::L_DEBUG;
391 #elif defined VERBOSITY_LEVEL_VERBOSE
392 static VERBOSITY_LEVEL s_VerbosityLevel = pcl::console::L_VERBOSE;
393 #else
394 static VERBOSITY_LEVEL s_VerbosityLevel = pcl::console::L_INFO;
395 #endif
396 }
397 }
398
399 ////////////////////////////////////////////////////////////////////////////////
setVerbosityLevel(pcl::console::VERBOSITY_LEVEL level)400 void pcl::console::setVerbosityLevel (pcl::console::VERBOSITY_LEVEL level)
401 {
402 if (s_NeedVerbosityInit) pcl::console::initVerbosityLevel ();
403 s_VerbosityLevel = level;
404 }
405
406 ////////////////////////////////////////////////////////////////////////////////
407 pcl::console::VERBOSITY_LEVEL
getVerbosityLevel()408 pcl::console::getVerbosityLevel ()
409 {
410 if (s_NeedVerbosityInit) pcl::console::initVerbosityLevel ();
411 return s_VerbosityLevel;
412 }
413
414 ////////////////////////////////////////////////////////////////////////////////
415 bool
isVerbosityLevelEnabled(pcl::console::VERBOSITY_LEVEL level)416 pcl::console::isVerbosityLevelEnabled (pcl::console::VERBOSITY_LEVEL level)
417 {
418 if (s_NeedVerbosityInit) pcl::console::initVerbosityLevel ();
419 return level <= s_VerbosityLevel;
420 }
421
422 ////////////////////////////////////////////////////////////////////////////////
423 bool
initVerbosityLevel()424 pcl::console::initVerbosityLevel ()
425 {
426 #ifdef VERBOSITY_LEVEL_ALWAYS
427 s_VerbosityLevel = pcl::console::L_ALWAYS;
428 #elif defined VERBOSITY_LEVEL_ERROR
429 s_VerbosityLevel = pcl::console::L_ERROR;
430 #elif defined VERBOSITY_LEVEL_WARN
431 s_VerbosityLevel = pcl::console::L_WARN;
432 #elif defined VERBOSITY_LEVEL_DEBUG
433 s_VerbosityLevel = pcl::console::L_DEBUG;
434 #elif defined VERBOSITY_LEVEL_VERBOSE
435 s_VerbosityLevel = pcl::console::L_VERBOSE;
436 #else
437 s_VerbosityLevel = pcl::console::L_INFO; // Default value
438 #endif
439
440 char* pcl_verbosity_level = getenv ( "PCL_VERBOSITY_LEVEL");
441 if (pcl_verbosity_level)
442 {
443 std::string s_pcl_verbosity_level (pcl_verbosity_level);
444 std::transform (s_pcl_verbosity_level.begin (), s_pcl_verbosity_level.end (), s_pcl_verbosity_level.begin (), toupper);
445
446 if (s_pcl_verbosity_level.find ("ALWAYS") != std::string::npos) s_VerbosityLevel = L_ALWAYS;
447 else if (s_pcl_verbosity_level.find ("ERROR") != std::string::npos) s_VerbosityLevel = L_ERROR;
448 else if (s_pcl_verbosity_level.find ("WARN") != std::string::npos) s_VerbosityLevel = L_WARN;
449 else if (s_pcl_verbosity_level.find ("INFO") != std::string::npos) s_VerbosityLevel = L_INFO;
450 else if (s_pcl_verbosity_level.find ("DEBUG") != std::string::npos) s_VerbosityLevel = L_DEBUG;
451 else if (s_pcl_verbosity_level.find ("VERBOSE") != std::string::npos) s_VerbosityLevel = L_VERBOSE;
452 else printf ("Warning: invalid PCL_VERBOSITY_LEVEL set (%s)\n", s_pcl_verbosity_level.c_str ());
453 }
454
455 s_NeedVerbosityInit = false;
456 return true;
457 }
458
459 ////////////////////////////////////////////////////////////////////////////////
460 void
print(pcl::console::VERBOSITY_LEVEL level,FILE * stream,const char * format,...)461 pcl::console::print (pcl::console::VERBOSITY_LEVEL level, FILE *stream, const char *format, ...)
462 {
463 if (!isVerbosityLevelEnabled (level)) return;
464 switch (level)
465 {
466 case L_DEBUG:
467 change_text_color (stream, TT_RESET, TT_GREEN);
468 break;
469 case L_WARN:
470 change_text_color (stream, TT_BRIGHT, TT_YELLOW);
471 break;
472 case L_ERROR:
473 change_text_color (stream, TT_BRIGHT, TT_RED);
474 break;
475 case L_ALWAYS:
476 case L_INFO:
477 case L_VERBOSE:
478 default:
479 break;
480 }
481
482 va_list ap;
483
484 va_start (ap, format);
485 vfprintf (stream, format, ap);
486 va_end (ap);
487
488 reset_text_color (stream);
489 }
490
491 ////////////////////////////////////////////////////////////////////////////////
492 void
print(pcl::console::VERBOSITY_LEVEL level,const char * format,...)493 pcl::console::print (pcl::console::VERBOSITY_LEVEL level, const char *format, ...)
494 {
495 if (!isVerbosityLevelEnabled (level)) return;
496 FILE *stream = (level == L_WARN || level == L_ERROR) ? stderr : stdout;
497 switch (level)
498 {
499 case L_DEBUG:
500 change_text_color (stream, TT_RESET, TT_GREEN);
501 break;
502 case L_WARN:
503 change_text_color (stream, TT_BRIGHT, TT_YELLOW);
504 break;
505 case L_ERROR:
506 change_text_color (stream, TT_BRIGHT, TT_RED);
507 break;
508 case L_ALWAYS:
509 case L_INFO:
510 case L_VERBOSE:
511 default:
512 break;
513 }
514
515 va_list ap;
516
517 va_start (ap, format);
518 vfprintf (stream, format, ap);
519 va_end (ap);
520
521 reset_text_color (stream);
522
523 }
524