Commit db0d1bae by Liu Hao Committed by Jonathan Yong

pretty-print.c [_WIN32] (colorize_init): Remove.

2017-10-11  Liu Hao  <lh_mouse@126.com>

	* pretty-print.c [_WIN32] (colorize_init): Remove.  Use
	the generic version below instead.
	(should_colorize): Recognize Windows consoles as terminals
	for MinGW targets.
	* pretty-print.c [__MINGW32__] (write_all): New function.
	[__MINGW32__] (find_esc_head): Likewise.
	[__MINGW32__] (find_esc_terminator): Likewise.
	[__MINGW32__] (eat_esc_sequence): Likewise.
	[__MINGW32__] (mingw_ansi_fputs): New function that handles
	ANSI escape codes.
	(pp_write_text_to_stream): Use mingw_ansi_fputs instead of fputs
	for MinGW targets.

From-SVN: r253645
parent 85866209
2017-10-11 Liu Hao <lh_mouse@126.com>
* pretty-print.c [_WIN32] (colorize_init): Remove. Use
the generic version below instead.
(should_colorize): Recognize Windows consoles as terminals
for MinGW targets.
* pretty-print.c [__MINGW32__] (write_all): New function.
[__MINGW32__] (find_esc_head): Likewise.
[__MINGW32__] (find_esc_terminator): Likewise.
[__MINGW32__] (eat_esc_sequence): Likewise.
[__MINGW32__] (mingw_ansi_fputs): New function that handles
ANSI escape codes.
(pp_write_text_to_stream): Use mingw_ansi_fputs instead of fputs
for MinGW targets.
2017-10-11 Richard Biener <rguenther@suse.de> 2017-10-11 Richard Biener <rguenther@suse.de>
* tree-ssa-loop-niter.c (infer_loop_bounds_from_pointer_arith): * tree-ssa-loop-niter.c (infer_loop_bounds_from_pointer_arith):
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#include "system.h" #include "system.h"
#include "diagnostic-color.h" #include "diagnostic-color.h"
#ifdef __MINGW32__
# include <windows.h>
#endif
/* Select Graphic Rendition (SGR, "\33[...m") strings. */ /* Select Graphic Rendition (SGR, "\33[...m") strings. */
/* Also Erase in Line (EL) to Right ("\33[K") by default. */ /* Also Erase in Line (EL) to Right ("\33[K") by default. */
/* Why have EL to Right after SGR? /* Why have EL to Right after SGR?
...@@ -275,23 +279,28 @@ parse_gcc_colors (void) ...@@ -275,23 +279,28 @@ parse_gcc_colors (void)
return true; return true;
} }
#if defined(_WIN32)
bool
colorize_init (diagnostic_color_rule_t)
{
return false;
}
#else
/* Return true if we should use color when in auto mode, false otherwise. */ /* Return true if we should use color when in auto mode, false otherwise. */
static bool static bool
should_colorize (void) should_colorize (void)
{ {
#ifdef __MINGW32__
/* For consistency reasons, one should check the handle returned by
_get_osfhandle(_fileno(stderr)) because the function
pp_write_text_to_stream() in pretty-print.c calls fputs() on
that stream. However, the code below for non-Windows doesn't seem
to care about it either... */
HANDLE h;
DWORD m;
h = GetStdHandle (STD_ERROR_HANDLE);
return (h != INVALID_HANDLE_VALUE) && (h != NULL)
&& GetConsoleMode (h, &m);
#else
char const *t = getenv ("TERM"); char const *t = getenv ("TERM");
return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO); return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO);
#endif
} }
bool bool
colorize_init (diagnostic_color_rule_t rule) colorize_init (diagnostic_color_rule_t rule)
{ {
...@@ -310,4 +319,3 @@ colorize_init (diagnostic_color_rule_t rule) ...@@ -310,4 +319,3 @@ colorize_init (diagnostic_color_rule_t rule)
gcc_unreachable (); gcc_unreachable ();
} }
} }
#endif
...@@ -30,6 +30,666 @@ along with GCC; see the file COPYING3. If not see ...@@ -30,6 +30,666 @@ along with GCC; see the file COPYING3. If not see
#include <iconv.h> #include <iconv.h>
#endif #endif
#ifdef __MINGW32__
/* Replacement for fputs() that handles ANSI escape codes on Windows NT.
Contributed by: Liu Hao (lh_mouse at 126 dot com)
XXX: This file is compiled into libcommon.a that will be self-contained.
It looks like that these functions can be put nowhere else. */
#include <io.h>
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
/* Write all bytes in [s,s+n) into the specified stream.
Errors are ignored. */
static void
write_all (HANDLE h, const char *s, size_t n)
{
size_t rem = n;
DWORD step;
while (rem != 0)
{
if (rem <= UINT_MAX)
step = rem;
else
step = UINT_MAX;
if (!WriteFile (h, s + n - rem, step, &step, NULL))
break;
rem -= step;
}
}
/* Find the beginning of an escape sequence.
There are two cases:
1. If the sequence begins with an ESC character (0x1B) and a second
character X in [0x40,0x5F], returns X and stores a pointer to
the third character into *head.
2. If the sequence begins with a character X in [0x80,0x9F], returns
(X-0x40) and stores a pointer to the second character into *head.
Stores the number of ESC character(s) in *prefix_len.
Returns 0 if no such sequence can be found. */
static int
find_esc_head (int *prefix_len, const char **head, const char *str)
{
int c;
const char *r = str;
int escaped = 0;
for (;;)
{
c = (unsigned char) *r;
if (c == 0)
{
/* Not found. */
return 0;
}
if (escaped && 0x40 <= c && c <= 0x5F)
{
/* Found (case 1). */
*prefix_len = 2;
*head = r + 1;
return c;
}
if (0x80 <= c && c <= 0x9F)
{
/* Found (case 2). */
*prefix_len = 1;
*head = r + 1;
return c - 0x40;
}
++r;
escaped = c == 0x1B;
}
}
/* Find the terminator of an escape sequence.
str should be the value stored in *head by a previous successful
call to find_esc_head().
Returns 0 if no such sequence can be found. */
static int
find_esc_terminator (const char **term, const char *str)
{
int c;
const char *r = str;
for (;;)
{
c = (unsigned char) *r;
if (c == 0)
{
/* Not found. */
return 0;
}
if (0x40 <= c && c <= 0x7E)
{
/* Found. */
*term = r;
return c;
}
++r;
}
}
/* Handle a sequence of codes. Sequences that are invalid, reserved,
unrecognized or unimplemented are ignored silently.
There isn't much we can do because of lameness of Windows consoles. */
static void
eat_esc_sequence (HANDLE h, int esc_code,
const char *esc_head, const char *esc_term)
{
/* Numbers in an escape sequence cannot be negative, because
a minus sign in the middle of it would have terminated it. */
long n1, n2;
char *eptr, *delim;
CONSOLE_SCREEN_BUFFER_INFO sb;
COORD cr;
/* ED and EL parameters. */
DWORD cnt, step;
long rows;
/* SGR parameters. */
WORD attrib_add, attrib_rm;
const char *param;
switch (MAKEWORD (esc_code, *esc_term))
{
/* ESC [ n1 'A'
Move the cursor up by n1 characters. */
case MAKEWORD ('[', 'A'):
if (esc_head == esc_term)
n1 = 1;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
/* Stop at the topmost boundary. */
if (cr.Y > n1)
cr.Y -= n1;
else
cr.Y = 0;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 'B'
Move the cursor down by n1 characters. */
case MAKEWORD ('[', 'B'):
if (esc_head == esc_term)
n1 = 1;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
/* Stop at the bottommost boundary. */
if (sb.dwSize.Y - cr.Y > n1)
cr.Y += n1;
else
cr.Y = sb.dwSize.Y;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 'C'
Move the cursor right by n1 characters. */
case MAKEWORD ('[', 'C'):
if (esc_head == esc_term)
n1 = 1;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
/* Stop at the rightmost boundary. */
if (sb.dwSize.X - cr.X > n1)
cr.X += n1;
else
cr.X = sb.dwSize.X;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 'D'
Move the cursor left by n1 characters. */
case MAKEWORD ('[', 'D'):
if (esc_head == esc_term)
n1 = 1;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
/* Stop at the leftmost boundary. */
if (cr.X > n1)
cr.X -= n1;
else
cr.X = 0;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 'E'
Move the cursor to the beginning of the n1-th line downwards. */
case MAKEWORD ('[', 'E'):
if (esc_head == esc_term)
n1 = 1;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
cr.X = 0;
/* Stop at the bottommost boundary. */
if (sb.dwSize.Y - cr.Y > n1)
cr.Y += n1;
else
cr.Y = sb.dwSize.Y;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 'F'
Move the cursor to the beginning of the n1-th line upwards. */
case MAKEWORD ('[', 'F'):
if (esc_head == esc_term)
n1 = 1;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
cr.X = 0;
/* Stop at the topmost boundary. */
if (cr.Y > n1)
cr.Y -= n1;
else
cr.Y = 0;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 'G'
Move the cursor to the (1-based) n1-th column. */
case MAKEWORD ('[', 'G'):
if (esc_head == esc_term)
n1 = 1;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
n1 -= 1;
/* Stop at the leftmost or rightmost boundary. */
if (n1 < 0)
cr.X = 0;
else if (n1 > sb.dwSize.X)
cr.X = sb.dwSize.X;
else
cr.X = n1;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 ';' n2 'H'
ESC [ n1 ';' n2 'f'
Move the cursor to the (1-based) n1-th row and
(also 1-based) n2-th column. */
case MAKEWORD ('[', 'H'):
case MAKEWORD ('[', 'f'):
if (esc_head == esc_term)
{
/* Both parameters are omitted and set to 1 by default. */
n1 = 1;
n2 = 1;
}
else if (!(delim = (char *) memchr (esc_head, ';',
esc_term - esc_head)))
{
/* Only the first parameter is given. The second one is
set to 1 by default. */
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
n2 = 1;
}
else
{
/* Both parameters are given. The first one shall be
terminated by the semicolon. */
n1 = strtol (esc_head, &eptr, 10);
if (eptr != delim)
break;
n2 = strtol (delim + 1, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
cr = sb.dwCursorPosition;
n1 -= 1;
n2 -= 1;
/* The cursor position shall be relative to the view coord of
the console window, which is usually smaller than the actual
buffer. FWIW, the 'appropriate' solution will be shrinking
the buffer to match the size of the console window,
destroying scrollback in the process. */
n1 += sb.srWindow.Top;
n2 += sb.srWindow.Left;
/* Stop at the topmost or bottommost boundary. */
if (n1 < 0)
cr.Y = 0;
else if (n1 > sb.dwSize.Y)
cr.Y = sb.dwSize.Y;
else
cr.Y = n1;
/* Stop at the leftmost or rightmost boundary. */
if (n2 < 0)
cr.X = 0;
else if (n2 > sb.dwSize.X)
cr.X = sb.dwSize.X;
else
cr.X = n2;
SetConsoleCursorPosition (h, cr);
}
break;
/* ESC [ n1 'J'
Erase display. */
case MAKEWORD ('[', 'J'):
if (esc_head == esc_term)
/* This is one of the very few codes whose parameters have
a default value of zero. */
n1 = 0;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
/* The cursor is not necessarily in the console window, which
makes the behavior of this code harder to define. */
switch (n1)
{
case 0:
/* If the cursor is in or above the window, erase from
it to the bottom of the window; otherwise, do nothing. */
cr = sb.dwCursorPosition;
cnt = sb.dwSize.X - sb.dwCursorPosition.X;
rows = sb.srWindow.Bottom - sb.dwCursorPosition.Y;
break;
case 1:
/* If the cursor is in or under the window, erase from
it to the top of the window; otherwise, do nothing. */
cr.X = 0;
cr.Y = sb.srWindow.Top;
cnt = sb.dwCursorPosition.X + 1;
rows = sb.dwCursorPosition.Y - sb.srWindow.Top;
break;
case 2:
/* Erase the entire window. */
cr.X = sb.srWindow.Left;
cr.Y = sb.srWindow.Top;
cnt = 0;
rows = sb.srWindow.Bottom - sb.srWindow.Top + 1;
break;
default:
/* Erase the entire buffer. */
cr.X = 0;
cr.Y = 0;
cnt = 0;
rows = sb.dwSize.Y;
break;
}
if (rows < 0)
break;
cnt += rows * sb.dwSize.X;
FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
}
break;
/* ESC [ n1 'K'
Erase line. */
case MAKEWORD ('[', 'K'):
if (esc_head == esc_term)
/* This is one of the very few codes whose parameters have
a default value of zero. */
n1 = 0;
else
{
n1 = strtol (esc_head, &eptr, 10);
if (eptr != esc_term)
break;
}
if (GetConsoleScreenBufferInfo (h, &sb))
{
switch (n1)
{
case 0:
/* Erase from the cursor to the end. */
cr = sb.dwCursorPosition;
cnt = sb.dwSize.X - sb.dwCursorPosition.X;
break;
case 1:
/* Erase from the cursor to the beginning. */
cr = sb.dwCursorPosition;
cr.X = 0;
cnt = sb.dwCursorPosition.X + 1;
break;
default:
/* Erase the entire line. */
cr = sb.dwCursorPosition;
cr.X = 0;
cnt = sb.dwSize.X;
break;
}
FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
}
break;
/* ESC [ n1 ';' n2 'm'
Set SGR parameters. Zero or more parameters will follow. */
case MAKEWORD ('[', 'm'):
attrib_add = 0;
attrib_rm = 0;
if (esc_head == esc_term)
{
/* When no parameter is given, reset the console. */
attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE);
attrib_rm = -1; /* Removes everything. */
goto sgr_set_it;
}
param = esc_head;
do
{
/* Parse a parameter. */
n1 = strtol (param, &eptr, 10);
if (*eptr != ';' && eptr != esc_term)
goto sgr_set_it;
switch (n1)
{
case 0:
/* Reset. */
attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE);
attrib_rm = -1; /* Removes everything. */
break;
case 1:
/* Bold. */
attrib_add |= FOREGROUND_INTENSITY;
break;
case 4:
/* Underline. */
attrib_add |= COMMON_LVB_UNDERSCORE;
break;
case 5:
/* Blink. */
/* XXX: It is not BLINKING at all! */
attrib_add |= BACKGROUND_INTENSITY;
break;
case 7:
/* Reverse. */
attrib_add |= COMMON_LVB_REVERSE_VIDEO;
break;
case 22:
/* No bold. */
attrib_add &= ~FOREGROUND_INTENSITY;
attrib_rm |= FOREGROUND_INTENSITY;
break;
case 24:
/* No underline. */
attrib_add &= ~COMMON_LVB_UNDERSCORE;
attrib_rm |= COMMON_LVB_UNDERSCORE;
break;
case 25:
/* No blink. */
/* XXX: It is not BLINKING at all! */
attrib_add &= ~BACKGROUND_INTENSITY;
attrib_rm |= BACKGROUND_INTENSITY;
break;
case 27:
/* No reverse. */
attrib_add &= ~COMMON_LVB_REVERSE_VIDEO;
attrib_rm |= COMMON_LVB_REVERSE_VIDEO;
break;
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
/* Foreground color. */
attrib_add &= ~(FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE);
n1 -= 30;
if (n1 & 1)
attrib_add |= FOREGROUND_RED;
if (n1 & 2)
attrib_add |= FOREGROUND_GREEN;
if (n1 & 4)
attrib_add |= FOREGROUND_BLUE;
attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE);
break;
case 38:
/* Reserved for extended foreground color.
Don't know how to handle parameters remaining.
Bail out. */
goto sgr_set_it;
case 39:
/* Reset foreground color. */
/* Set to grey. */
attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE);
attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
| FOREGROUND_BLUE);
break;
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
/* Background color. */
attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
| BACKGROUND_BLUE);
n1 -= 40;
if (n1 & 1)
attrib_add |= BACKGROUND_RED;
if (n1 & 2)
attrib_add |= BACKGROUND_GREEN;
if (n1 & 4)
attrib_add |= BACKGROUND_BLUE;
attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
| BACKGROUND_BLUE);
break;
case 48:
/* Reserved for extended background color.
Don't know how to handle parameters remaining.
Bail out. */
goto sgr_set_it;
case 49:
/* Reset background color. */
/* Set to black. */
attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
| BACKGROUND_BLUE);
attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
| BACKGROUND_BLUE);
break;
}
/* Prepare the next parameter. */
param = eptr + 1;
}
while (param != esc_term);
sgr_set_it:
/* 0xFFFF removes everything. If it is not the case,
care must be taken to preserve old attributes. */
if (attrib_rm != 0xFFFF && GetConsoleScreenBufferInfo (h, &sb))
{
attrib_add |= sb.wAttributes & ~attrib_rm;
}
SetConsoleTextAttribute (h, attrib_add);
break;
}
}
int
mingw_ansi_fputs (const char *str, FILE *fp)
{
const char *read = str;
HANDLE h;
DWORD mode;
int esc_code, prefix_len;
const char *esc_head, *esc_term;
h = (HANDLE) _get_osfhandle (_fileno (fp));
if (h == INVALID_HANDLE_VALUE)
return EOF;
/* Don't mess up stdio functions with Windows APIs. */
fflush (fp);
if (GetConsoleMode (h, &mode))
/* If it is a console, translate ANSI escape codes as needed. */
for (;;)
{
if ((esc_code = find_esc_head (&prefix_len, &esc_head, read)) == 0)
{
/* Write all remaining characters, then exit. */
write_all (h, read, strlen (read));
break;
}
if (find_esc_terminator (&esc_term, esc_head) == 0)
/* Ignore incomplete escape sequences at the moment.
FIXME: The escape state shall be cached for further calls
to this function. */
break;
write_all (h, read, esc_head - prefix_len - read);
eat_esc_sequence (h, esc_code, esc_head, esc_term);
read = esc_term + 1;
}
else
/* If it is not a console, write everything as-is. */
write_all (h, read, strlen (read));
_close ((intptr_t) h);
return 1;
}
#endif /* __MINGW32__ */
static void pp_quoted_string (pretty_printer *, const char *, size_t = -1); static void pp_quoted_string (pretty_printer *, const char *, size_t = -1);
/* Overwrite the given location/range within this text_info's rich_location. /* Overwrite the given location/range within this text_info's rich_location.
...@@ -140,7 +800,11 @@ void ...@@ -140,7 +800,11 @@ void
pp_write_text_to_stream (pretty_printer *pp) pp_write_text_to_stream (pretty_printer *pp)
{ {
const char *text = pp_formatted_text (pp); const char *text = pp_formatted_text (pp);
#ifdef __MINGW32__
mingw_ansi_fputs (text, pp_buffer (pp)->stream);
#else
fputs (text, pp_buffer (pp)->stream); fputs (text, pp_buffer (pp)->stream);
#endif
pp_clear_output_area (pp); pp_clear_output_area (pp);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment