1 /*=========================================================================
3 Program: KWSys - Kitware System Library
4 Module: $RCSfile: Terminal.c,v $
6 Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
7 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notices for more information.
13 =========================================================================*/
14 #include "kwsysPrivate.h"
15 #include KWSYS_HEADER(Terminal.h)
17 /* Work-around CMake dependency scanning limitation. This must
18 duplicate the above list of headers. */
20 # include "Terminal.h.in"
23 /*--------------------------------------------------------------------------*/
24 /* Configure support for this platform. */
25 #if defined(_WIN32) || defined(__CYGWIN__)
26 # define KWSYS_TERMINAL_SUPPORT_CONSOLE
29 # define KWSYS_TERMINAL_ISATTY_WORKS
32 /*--------------------------------------------------------------------------*/
33 /* Include needed system APIs. */
35 #include <stdlib.h> /* getenv */
36 #include <string.h> /* strcmp */
37 #include <stdarg.h> /* va_list */
39 #if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
40 # include <windows.h> /* SetConsoleTextAttribute */
41 # include <io.h> /* _get_osfhandle */
44 #if defined(KWSYS_TERMINAL_ISATTY_WORKS)
45 # include <unistd.h> /* isatty */
47 # include <sys/stat.h> /* fstat */
50 /*--------------------------------------------------------------------------*/
51 static int kwsysTerminalStreamIsVT100(FILE* stream
, int default_vt100
,
53 static void kwsysTerminalSetVT100Color(FILE* stream
, int color
);
54 #if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
55 static HANDLE
kwsysTerminalGetStreamHandle(FILE* stream
);
56 static void kwsysTerminalSetConsoleColor(HANDLE hOut
,
57 CONSOLE_SCREEN_BUFFER_INFO
* hOutInfo
,
62 /*--------------------------------------------------------------------------*/
63 void kwsysTerminal_cfprintf(int color
, FILE* stream
, const char* format
, ...)
65 /* Setup the stream with the given color if possible. */
66 int pipeIsConsole
= 0;
68 int default_vt100
= color
& kwsysTerminal_Color_AssumeVT100
;
69 int default_tty
= color
& kwsysTerminal_Color_AssumeTTY
;
70 #if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
71 CONSOLE_SCREEN_BUFFER_INFO hOutInfo
;
72 HANDLE hOut
= kwsysTerminalGetStreamHandle(stream
);
73 if(GetConsoleScreenBufferInfo(hOut
, &hOutInfo
))
76 kwsysTerminalSetConsoleColor(hOut
, &hOutInfo
, stream
, color
);
79 if(!pipeIsConsole
&& kwsysTerminalStreamIsVT100(stream
,
80 default_vt100
, default_tty
))
83 kwsysTerminalSetVT100Color(stream
, color
);
86 /* Format the text into the stream. */
89 va_start(var_args
, format
);
90 vfprintf(stream
, format
, var_args
);
94 /* Restore the normal color state for the stream. */
95 #if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
98 kwsysTerminalSetConsoleColor(hOut
, &hOutInfo
, stream
,
99 kwsysTerminal_Color_Normal
);
104 kwsysTerminalSetVT100Color(stream
, kwsysTerminal_Color_Normal
);
108 /*--------------------------------------------------------------------------*/
109 /* Detect cases when a stream is definately not interactive. */
110 #if !defined(KWSYS_TERMINAL_ISATTY_WORKS)
111 static int kwsysTerminalStreamIsNotInteractive(FILE* stream
)
113 /* The given stream is definately not interactive if it is a regular
115 struct stat stream_stat
;
116 if(fstat(fileno(stream
), &stream_stat
) == 0)
118 if(stream_stat
.st_mode
& S_IFREG
)
127 /*--------------------------------------------------------------------------*/
128 /* List of terminal names known to support VT100 color escape sequences. */
129 static const char* kwsysTerminalVT100Names
[] =
162 "rxvt-cygwin-native",
179 /*--------------------------------------------------------------------------*/
180 /* Detect whether a stream is displayed in a VT100-compatible terminal. */
181 static int kwsysTerminalStreamIsVT100(FILE* stream
, int default_vt100
,
184 /* If running inside emacs the terminal is not VT100. Some emacs
185 seem to claim the TERM is xterm even though they do not support
187 const char* emacs
= getenv("EMACS");
188 if(emacs
&& *emacs
== 't')
193 /* Check for a valid terminal. */
197 const char* term
= getenv("TERM");
200 for(t
= kwsysTerminalVT100Names
; *t
&& strcmp(term
, *t
) != 0; ++t
) {}
208 #if defined(KWSYS_TERMINAL_ISATTY_WORKS)
209 /* Make sure the stream is a tty. */
211 return isatty(fileno(stream
))? 1:0;
213 /* Check for cases in which the stream is definately not a tty. */
214 if(kwsysTerminalStreamIsNotInteractive(stream
))
219 /* Use the provided default for whether this is a tty. */
224 /*--------------------------------------------------------------------------*/
225 /* VT100 escape sequence strings. */
226 #define KWSYS_TERMINAL_VT100_NORMAL "\33[0m"
227 #define KWSYS_TERMINAL_VT100_BOLD "\33[1m"
228 #define KWSYS_TERMINAL_VT100_UNDERLINE "\33[4m"
229 #define KWSYS_TERMINAL_VT100_BLINK "\33[5m"
230 #define KWSYS_TERMINAL_VT100_INVERSE "\33[7m"
231 #define KWSYS_TERMINAL_VT100_FOREGROUND_BLACK "\33[30m"
232 #define KWSYS_TERMINAL_VT100_FOREGROUND_RED "\33[31m"
233 #define KWSYS_TERMINAL_VT100_FOREGROUND_GREEN "\33[32m"
234 #define KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW "\33[33m"
235 #define KWSYS_TERMINAL_VT100_FOREGROUND_BLUE "\33[34m"
236 #define KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA "\33[35m"
237 #define KWSYS_TERMINAL_VT100_FOREGROUND_CYAN "\33[36m"
238 #define KWSYS_TERMINAL_VT100_FOREGROUND_WHITE "\33[37m"
239 #define KWSYS_TERMINAL_VT100_BACKGROUND_BLACK "\33[40m"
240 #define KWSYS_TERMINAL_VT100_BACKGROUND_RED "\33[41m"
241 #define KWSYS_TERMINAL_VT100_BACKGROUND_GREEN "\33[42m"
242 #define KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW "\33[43m"
243 #define KWSYS_TERMINAL_VT100_BACKGROUND_BLUE "\33[44m"
244 #define KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA "\33[45m"
245 #define KWSYS_TERMINAL_VT100_BACKGROUND_CYAN "\33[46m"
246 #define KWSYS_TERMINAL_VT100_BACKGROUND_WHITE "\33[47m"
248 /*--------------------------------------------------------------------------*/
249 /* Write VT100 escape sequences to the stream for the given color. */
250 static void kwsysTerminalSetVT100Color(FILE* stream
, int color
)
252 if(color
== kwsysTerminal_Color_Normal
)
254 fprintf(stream
, KWSYS_TERMINAL_VT100_NORMAL
);
258 switch(color
& kwsysTerminal_Color_ForegroundMask
)
260 case kwsysTerminal_Color_Normal
:
261 fprintf(stream
, KWSYS_TERMINAL_VT100_NORMAL
);
263 case kwsysTerminal_Color_ForegroundBlack
:
264 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_BLACK
);
266 case kwsysTerminal_Color_ForegroundRed
:
267 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_RED
);
269 case kwsysTerminal_Color_ForegroundGreen
:
270 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_GREEN
);
272 case kwsysTerminal_Color_ForegroundYellow
:
273 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_YELLOW
);
275 case kwsysTerminal_Color_ForegroundBlue
:
276 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_BLUE
);
278 case kwsysTerminal_Color_ForegroundMagenta
:
279 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_MAGENTA
);
281 case kwsysTerminal_Color_ForegroundCyan
:
282 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_CYAN
);
284 case kwsysTerminal_Color_ForegroundWhite
:
285 fprintf(stream
, KWSYS_TERMINAL_VT100_FOREGROUND_WHITE
);
288 switch(color
& kwsysTerminal_Color_BackgroundMask
)
290 case kwsysTerminal_Color_BackgroundBlack
:
291 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_BLACK
);
293 case kwsysTerminal_Color_BackgroundRed
:
294 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_RED
);
296 case kwsysTerminal_Color_BackgroundGreen
:
297 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_GREEN
);
299 case kwsysTerminal_Color_BackgroundYellow
:
300 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_YELLOW
);
302 case kwsysTerminal_Color_BackgroundBlue
:
303 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_BLUE
);
305 case kwsysTerminal_Color_BackgroundMagenta
:
306 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_MAGENTA
);
308 case kwsysTerminal_Color_BackgroundCyan
:
309 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_CYAN
);
311 case kwsysTerminal_Color_BackgroundWhite
:
312 fprintf(stream
, KWSYS_TERMINAL_VT100_BACKGROUND_WHITE
);
315 if(color
& kwsysTerminal_Color_ForegroundBold
)
317 fprintf(stream
, KWSYS_TERMINAL_VT100_BOLD
);
321 /*--------------------------------------------------------------------------*/
322 #if defined(KWSYS_TERMINAL_SUPPORT_CONSOLE)
324 # define KWSYS_TERMINAL_MASK_FOREGROUND \
325 (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
326 # define KWSYS_TERMINAL_MASK_BACKGROUND \
327 (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
329 /* Get the Windows handle for a FILE stream. */
330 static HANDLE
kwsysTerminalGetStreamHandle(FILE* stream
)
332 /* Get the C-library file descriptor from the stream. */
333 int fd
= fileno(stream
);
335 # if defined(__CYGWIN__)
336 /* Cygwin seems to have an extra pipe level. If the file descriptor
337 corresponds to stdout or stderr then obtain the matching windows
339 if(fd
== fileno(stdout
))
341 return GetStdHandle(STD_OUTPUT_HANDLE
);
343 else if(fd
== fileno(stderr
))
345 return GetStdHandle(STD_ERROR_HANDLE
);
349 /* Get the underlying Windows handle for the descriptor. */
350 return (HANDLE
)_get_osfhandle(fd
);
353 /* Set color attributes in a Windows console. */
354 static void kwsysTerminalSetConsoleColor(HANDLE hOut
,
355 CONSOLE_SCREEN_BUFFER_INFO
* hOutInfo
,
360 switch(color
& kwsysTerminal_Color_ForegroundMask
)
362 case kwsysTerminal_Color_Normal
:
363 attributes
|= hOutInfo
->wAttributes
& KWSYS_TERMINAL_MASK_FOREGROUND
;
365 case kwsysTerminal_Color_ForegroundBlack
:
368 case kwsysTerminal_Color_ForegroundRed
:
369 attributes
|= FOREGROUND_RED
;
371 case kwsysTerminal_Color_ForegroundGreen
:
372 attributes
|= FOREGROUND_GREEN
;
374 case kwsysTerminal_Color_ForegroundYellow
:
375 attributes
|= FOREGROUND_RED
| FOREGROUND_GREEN
;
377 case kwsysTerminal_Color_ForegroundBlue
:
378 attributes
|= FOREGROUND_BLUE
;
380 case kwsysTerminal_Color_ForegroundMagenta
:
381 attributes
|= FOREGROUND_RED
| FOREGROUND_BLUE
;
383 case kwsysTerminal_Color_ForegroundCyan
:
384 attributes
|= FOREGROUND_BLUE
| FOREGROUND_GREEN
;
386 case kwsysTerminal_Color_ForegroundWhite
:
387 attributes
|= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
390 switch(color
& kwsysTerminal_Color_BackgroundMask
)
392 case kwsysTerminal_Color_Normal
:
393 attributes
|= hOutInfo
->wAttributes
& KWSYS_TERMINAL_MASK_BACKGROUND
;
395 case kwsysTerminal_Color_BackgroundBlack
:
398 case kwsysTerminal_Color_BackgroundRed
:
399 attributes
|= BACKGROUND_RED
;
401 case kwsysTerminal_Color_BackgroundGreen
:
402 attributes
|= BACKGROUND_GREEN
;
404 case kwsysTerminal_Color_BackgroundYellow
:
405 attributes
|= BACKGROUND_RED
| BACKGROUND_GREEN
;
407 case kwsysTerminal_Color_BackgroundBlue
:
408 attributes
|= BACKGROUND_BLUE
;
410 case kwsysTerminal_Color_BackgroundMagenta
:
411 attributes
|= BACKGROUND_RED
| BACKGROUND_BLUE
;
413 case kwsysTerminal_Color_BackgroundCyan
:
414 attributes
|= BACKGROUND_BLUE
| BACKGROUND_GREEN
;
416 case kwsysTerminal_Color_BackgroundWhite
:
417 attributes
|= BACKGROUND_BLUE
| BACKGROUND_GREEN
| BACKGROUND_RED
;
420 if(color
& kwsysTerminal_Color_ForegroundBold
)
422 attributes
|= FOREGROUND_INTENSITY
;
424 if(color
& kwsysTerminal_Color_BackgroundBold
)
426 attributes
|= BACKGROUND_INTENSITY
;
429 SetConsoleTextAttribute(hOut
, attributes
);