[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: MS-Windows build of Grep [2/4]
From: |
Eli Zaretskii |
Subject: |
Re: MS-Windows build of Grep [2/4] |
Date: |
Sat, 24 Dec 2011 14:59:34 +0200 |
This changeset implements color highlighting of Grep matches on the
MS-Windows console (which does not directly support SGR sequences).
The code which produces SGR sequences is still present in the
MS-Windows build, and executed when stdout is not a console device,
because various programs, such as Emacs, need that when they invoke
Grep as a subprocess.
Support color highlighting on MS-Windows.
* src/main.c <is_tty>: New static var.
(w32_console_init, w32_sgr2attr, w32_sgr_start, w32_clreol)
(w32_sgr_end) [__MINGW32__]: New functions.
(PR_SGR_START, PR_SGR_END, PR_SGR_START_IF, PR_SGR_END_IF)
[__MINGW32__]: Use them in Windows-specific definitions of these
macros.
(should_colorize): New function, with __MINGW32__ specific code to
determine whether stdout is a console device.
diff -up -r grep-2.10.orig/src/main.c grep-2.10.MinGW/src/main.c
--- grep-2.10.orig/src/main.c 2011-09-10 13:17:04.000000000 +0300
+++ grep-2.10.MinGW/src/main.c 2011-12-20 11:41:49.498911300 +0200
@@ -151,6 +151,8 @@ static const char *sep_color = "36"
static const char *selected_line_color = ""; /* default color pair */
static const char *context_line_color = ""; /* default color pair */
+static int is_tty;
+
/* Select Graphic Rendition (SGR, "\33[...m") strings. */
/* Also Erase in Line (EL) to Right ("\33[K") by default. */
/* Why have EL to Right after SGR?
@@ -217,10 +219,17 @@ static const char *sgr_end = "\33[m\33
#define PR_SGR_FMT(fmt, s) do { if (*(s)) printf((fmt), (s)); } while (0)
#define PR_SGR_FMT_IF(fmt, s) \
do { if (color_option && *(s)) printf((fmt), (s)); } while (0)
+#ifndef __MINGW32__
#define PR_SGR_START(s) PR_SGR_FMT( SGR_START, (s))
#define PR_SGR_END(s) PR_SGR_FMT( SGR_END, (s))
#define PR_SGR_START_IF(s) PR_SGR_FMT_IF(SGR_START, (s))
#define PR_SGR_END_IF(s) PR_SGR_FMT_IF(SGR_END, (s))
+#else /* __MINGW32__ */
+#define PR_SGR_START(s) w32_sgr_start(s, 1)
+#define PR_SGR_END(s) w32_sgr_end(s, 1)
+#define PR_SGR_START_IF(s) w32_sgr_start(s, color_option)
+#define PR_SGR_END_IF(s) w32_sgr_end(s, color_option)
+#endif /* __MINGW32__ */
struct color_cap
{
@@ -273,6 +282,191 @@ static struct color_cap color_dict[] =
{ NULL, NULL, NULL }
};
+#ifdef __MINGW32__
+/* Support for colorization on MS-Windows console. */
+
+#undef DATADIR /* conflicts with objidl.h, which is included by windows.h */
+#include <windows.h>
+
+static HANDLE hstdout = INVALID_HANDLE_VALUE;
+static SHORT norm_attr;
+static int w32_console_initialized;
+
+/* Initialize the normal text attribute used by the console. */
+static void
+w32_console_init (void)
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ if (!w32_console_initialized && is_tty)
+ {
+ hstdout = GetStdHandle (STD_OUTPUT_HANDLE);
+ if (hstdout != INVALID_HANDLE_VALUE
+ && GetConsoleScreenBufferInfo (hstdout, &csbi))
+ {
+ norm_attr = csbi.wAttributes;
+ w32_console_initialized = 1;
+ }
+ }
+}
+
+/* Convert a color spec, a semi-colon separated list of the form
+ "NN;MM;KK;...", where each number is a value of the SGR parameter,
+ into the corresponding Windows console text attribute.
+
+ This function supports a subset of the SGR rendition aspects that
+ the Windows console can display. */
+static int
+w32_sgr2attr (const char *sgr_seq)
+{
+ const char *s, *p;
+ int code, fg = norm_attr & 15, bg = norm_attr & (15 << 4);
+ int bright = 0, inverse = 0;
+ static int fg_color[] = {
+ 0, /* black */
+ FOREGROUND_RED, /* red */
+ FOREGROUND_GREEN, /* green */
+ FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */
+ FOREGROUND_BLUE, /* blue */
+ FOREGROUND_BLUE | FOREGROUND_RED, /* magenta */
+ FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */
+ };
+ static int bg_color[] = {
+ 0, /* black */
+ BACKGROUND_RED, /* red */
+ BACKGROUND_GREEN, /* green */
+ BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */
+ BACKGROUND_BLUE, /* blue */
+ BACKGROUND_BLUE | BACKGROUND_RED, /* magenta */
+ BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */
+ BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */
+ };
+
+ for (s = p = sgr_seq; *s; p++)
+ {
+
+ if (*p == ';' || *p == '\0')
+ {
+ code = strtol (s, NULL, 10);
+ s = p + (*p != '\0');
+
+ switch (code)
+ {
+ case 0: /* all attributes off */
+ fg = norm_attr & 15;
+ bg = norm_attr & (15 << 4);
+ bright = 0;
+ inverse = 0;
+ break;
+ case 1: /* intensity on */
+ bright = 1;
+ break;
+ case 7: /* inverse video */
+ inverse = 1;
+ break;
+ case 22: /* intensity off */
+ bright = 0;
+ break;
+ case 27: /* inverse off */
+ inverse = 0;
+ break;
+ case 30: case 31: case 32: case 33: /* foreground color */
+ case 34: case 35: case 36: case 37:
+ fg = fg_color[code - 30];
+ break;
+ case 39: /* default foreground */
+ fg = norm_attr & 15;
+ break;
+ case 40: case 41: case 42: case 43: /* background color */
+ case 44: case 45: case 46: case 47:
+ bg = bg_color[code - 40];
+ break;
+ case 49: /* default background */
+ bg = norm_attr & (15 << 4);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (inverse)
+ {
+ int t = fg;
+ fg = (bg >> 4);
+ bg = (t << 4);
+ }
+ if (bright)
+ fg |= FOREGROUND_INTENSITY;
+
+ return (bg & (15 << 4)) | (fg & 15);
+}
+
+/* Start displaying text according to the spec in SGR_SEQ, but only if
+ SGR_SEQ is non-empty and COND is non-zero. If stdout is connected
+ to a console, set the console text attribute; otherwise, emit the
+ SGR escape sequence as on Posix platforms (this is needed when Grep
+ is invoked as a subprocess of another program, such as Emacs, which
+ will handle the display of the matches). */
+static void
+w32_sgr_start (const char *sgr_seq, int cond)
+{
+ if (cond && *sgr_seq)
+ {
+ if (is_tty
+ && (!w32_console_initialized
+ ? (w32_console_init (), w32_console_initialized)
+ : 1))
+ {
+ SHORT attr = w32_sgr2attr (sgr_seq);
+ SetConsoleTextAttribute (hstdout, attr);
+ }
+ else
+ PR_SGR_FMT (SGR_START, sgr_seq);
+ }
+}
+
+/* Clear to the end of the current line with the default attribute.
+ This is needed for reasons similar to those that require the "EL to
+ Right after SGR" operation on Posix platforms: if we don't do this,
+ setting the `mt', `ms', or `mc' capabilities to use a non-default
+ background color spills that color to the empty space at the end of
+ the last screen line in a match whose line spans multiple screen
+ lines. */
+static void
+w32_clreol (void)
+{
+ DWORD nchars;
+ COORD start_pos;
+ DWORD written;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ GetConsoleScreenBufferInfo (hstdout, &csbi);
+ start_pos = csbi.dwCursorPosition;
+ nchars = csbi.dwSize.X - start_pos.X;
+
+ FillConsoleOutputAttribute (hstdout, norm_attr, nchars, start_pos,
+ &written);
+ FillConsoleOutputCharacter (hstdout, ' ', nchars, start_pos, &written);
+}
+
+/* Restore the normal text attribute. */
+static void
+w32_sgr_end (const char *sgr_seq, int cond)
+{
+ if (cond && *sgr_seq)
+ {
+ if (is_tty && w32_console_initialized)
+ {
+ SetConsoleTextAttribute (hstdout, norm_attr);
+ w32_clreol ();
+ }
+ else
+ PR_SGR_FMT (SGR_END, sgr_seq);
+ }
+}
+#endif /* __MINGW32__ */
+
static struct exclude *excluded_patterns;
static struct exclude *included_patterns;
static struct exclude *excluded_directory_patterns;
@@ -1769,6 +1964,30 @@ parse_grep_colors (void)
"at remaining substring \"%s\""), p, q);
}
+/* Return non-zero if we should highlight matches in output. */
+static int
+should_colorize (int fd)
+{
+ const char *t;
+
+#if defined(__MINGW32__) || defined(__DJGPP__)
+ return
+ isatty (fd)
+#ifdef __MINGW32__
+ /* Without the lseek call, Windows isatty returns non-zero for the
+ null device as well. */
+ && lseek (fd, SEEK_CUR, 0) == -1
+#endif
+ /* $TERM is not normally defined on DOS/Windows, so don't require
+ it for highlighting. But some programs, like Emacs, do define
+ it when running Grep as a subprocess, so make sure they don't
+ set TERM=dumb. */
+ && !((t = getenv ("TERM")) && STREQ (t, "dumb"));
+#else /* not __MINGW32__, not __DJGPP__ */
+ return isatty (fd) && (t = getenv ("TERM")) && !STREQ (t, "dumb");
+#endif
+}
+
int
main (int argc, char **argv)
{
@@ -2047,8 +2266,9 @@ main (int argc, char **argv)
if (color_option == 2)
{
char const *t;
- if (isatty (STDOUT_FILENO) && (t = getenv ("TERM"))
- && !STREQ (t, "dumb"))
+
+ is_tty = should_colorize (STDOUT_FILENO);
+ if (is_tty)
color_option = 1;
else
color_option = 0;
- Re: MS-Windows build of Grep [2/4],
Eli Zaretskii <=
- Re: MS-Windows build of Grep [2/4], Paul Eggert, 2011/12/24
- Re: MS-Windows build of Grep [2/4], Paolo Bonzini, 2011/12/28
- Re: MS-Windows build of Grep [2/4], Paolo Bonzini, 2011/12/28
- Re: MS-Windows build of Grep [2/4], Jim Meyering, 2011/12/28
- Re: MS-Windows build of Grep [2/4], Eli Zaretskii, 2011/12/28
- Re: MS-Windows build of Grep [2/4], Jim Meyering, 2011/12/28
- Re: MS-Windows build of Grep [2/4], Eli Zaretskii, 2011/12/28
- Re: MS-Windows build of Grep [2/4], Jim Meyering, 2011/12/30
- Re: MS-Windows build of Grep [2/4], Eli Zaretskii, 2011/12/31