Dmitry Cherniachenko's patch for colouring pcre2grep output in Windows.

This commit is contained in:
Philip.Hazel 2016-10-14 16:17:48 +00:00
parent 6c72b76a64
commit bd9a70f14d
3 changed files with 102 additions and 26 deletions

View File

@ -74,6 +74,10 @@ this situation and does not try to use JIT.
12. Added some "const" qualifiers to variables in pcre2grep.
13. Added Dmitry Cherniachenko's patch for colouring output in Windows
(untested by me). Also, look for GREP_COLOUR or GREP_COLOR if the environment
variables PCRE2GREP_COLOUR and PCRE2GREP_COLOR are not found.
Version 10.22 29-July-2016
--------------------------

View File

@ -1,4 +1,4 @@
.TH PCRE2GREP 1 "11 October 2016" "PCRE2 10.23"
.TH PCRE2GREP 1 "14 October 2016" "PCRE2 10.23"
.SH NAME
pcre2grep - a grep with Perl-compatible regular expressions.
.SH SYNOPSIS
@ -206,11 +206,12 @@ because \fBpcre2grep\fP has to search for all possible matches in a line, not
just one, in order to colour them all.
.sp
The colour that is used can be specified by setting the environment variable
PCRE2GREP_COLOUR or PCRE2GREP_COLOR. The value of this variable should be a
string of two numbers, separated by a semicolon. They are copied directly into
the control string for setting colour on a terminal, so it is your
responsibility to ensure that they make sense. If neither of the environment
variables is set, the default is "1;31", which gives red.
PCRE2GREP_COLOUR or PCRE2GREP_COLOR. If neither of these are set,
\fBpcre2grep\fP looks for GREP_COLOUR or GREP_COLOR. The value of the variable
should be a string of two numbers, separated by a semicolon. They are copied
directly into the control string for setting colour on a terminal, so it is
your responsibility to ensure that they make sense. If neither of the
environment variables is set, the default is "1;31", which gives red.
.TP
\fB-D\fP \fIaction\fP, \fB--devices=\fP\fIaction\fP
If an input path is not a regular file or a directory, "action" specifies how
@ -525,12 +526,13 @@ It should never be needed in normal use.
Show only the part of the line that matched a pattern instead of the whole
line. In this mode, no context is shown. That is, the \fB-A\fP, \fB-B\fP, and
\fB-C\fP options are ignored. If there is more than one match in a line, each
of them is shown separately. If \fB-o\fP is combined with \fB-v\fP (invert the
sense of the match to find non-matching lines), no output is generated, but the
return code is set appropriately. If the matched portion of the line is empty,
nothing is output unless the file name or line number are being printed, in
which case they are shown on an otherwise empty line. This option is mutually
exclusive with \fB--file-offsets\fP and \fB--line-offsets\fP.
of them is shown separately, on a separate line of output. If \fB-o\fP is
combined with \fB-v\fP (invert the sense of the match to find non-matching
lines), no output is generated, but the return code is set appropriately. If
the matched portion of the line is empty, nothing is output unless the file
name or line number are being printed, in which case they are shown on an
otherwise empty line. This option is mutually exclusive with
\fB--file-offsets\fP and \fB--line-offsets\fP.
.TP
\fB-o\fP\fInumber\fP, \fB--only-matching\fP=\fInumber\fP
Show only the part of the line that matched the capturing parentheses of the
@ -542,10 +544,11 @@ for the non-argument case above also apply to this case. If the specified
capturing parentheses do not exist in the pattern, or were not set in the
match, nothing is output unless the file name or line number are being output.
.sp
If this option is given multiple times, multiple substrings are output, in the
order the options are given. For example, -o3 -o1 -o3 causes the substrings
matched by capturing parentheses 3 and 1 and then 3 again to be output. By
default, there is no separator (but see the next option).
If this option is given multiple times, multiple substrings are output for each
match, in the order the options are given, and all on one line. For example,
-o3 -o1 -o3 causes the substrings matched by capturing parentheses 3 and 1 and
then 3 again to be output. By default, there is no separator (but see the next
option).
.TP
\fB--om-separator\fP=\fItext\fP
Specify a separating string for multiple occurrences of \fB-o\fP. The default
@ -775,6 +778,6 @@ Cambridge, England.
.rs
.sp
.nf
Last updated: 11 October 2016
Last updated: 14 October 2016
Copyright (c) 1997-2016 University of Cambridge.
.fi

View File

@ -681,6 +681,17 @@ return isatty(fileno(f));
}
#endif
/************* Print optionally coloured match Unix-style and z/OS **********/
static void
print_match(const char* buf, int length)
{
if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
FWRITE(buf, 1, length, stdout);
if (do_colour) fprintf(stdout, "%c[00m", 0x1b);
}
/* End of Unix-style or native z/OS environment functions. */
@ -814,6 +825,65 @@ is_file_tty(FILE *f)
return FALSE;
}
/************* Print optionally coloured match in Windows **********/
static HANDLE hstdout;
static CONSOLE_SCREEN_BUFFER_INFO csbi;
static WORD match_colour;
static void
print_match(const char* buf, int length)
{
if (do_colour) SetConsoleTextAttribute(hstdout, match_colour);
FWRITE(buf, 1, length, stdout);
if (do_colour) SetConsoleTextAttribute(hstdout, csbi.wAttributes);
}
/* Convert ANSI BGR format to RGB used by Windows */
#define BGR_RGB(x) ((x & 1 ? 4 : 0) | (x & 2) | (x & 4 ? 1 : 0))
static WORD
decode_ANSI_colour(char *cs)
{
WORD result = 0;
while (*cs)
{
if (isdigit(*cs))
{
int code = atoi(cs);
if (code == 1) result |= 0x08;
else if (code >= 30 && code <= 37) result = (result & 0xF8) | BGR_RGB(code - 30);
else if (code == 39) result = (result & 0xF0) | (csbi.wAttributes & 0x0F);
else if (code >= 40 && code <= 47) result = (result & 0x8F) | (BGR_RGB(code - 40) << 4);
else if (code == 49) result = (result & 0x0F) | (csbi.wAttributes & 0xF0);
/* aixterm high intensity colour codes */
else if (code >= 90 && code <= 97) result = (result & 0xF0) | BGR_RGB(code - 90) | 0x08;
else if (code >= 100 && code <= 107) result = (result & 0x0F) | (BGR_RGB(code - 100) << 4) | 0x80;
while (isdigit(*cs)) cs++;
}
if (*cs) cs++;
}
return result;
}
static void
init_colour_output()
{
if (do_colour)
{
hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hstdout, &csbi);
match_colour = decode_ANSI_colour(colour_string);
/* No valid colour found - turn off colouring */
if (!match_colour) do_colour = FALSE;
}
}
/* End of Windows functions */
@ -2113,9 +2183,7 @@ while (ptr < endptr)
if (plen > 0)
{
if (printed) fprintf(stdout, "%s", om_separator);
if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
FWRITE(matchptr + offsets[n*2], 1, plen, stdout);
if (do_colour) fprintf(stdout, "%c[00m", 0x1b);
print_match(matchptr + offsets[n*2], plen);
printed = TRUE;
}
}
@ -2283,9 +2351,7 @@ while (ptr < endptr)
{
int plength;
FWRITE(ptr, 1, offsets[0], stdout);
fprintf(stdout, "%c[%sm", 0x1b, colour_string);
FWRITE(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
fprintf(stdout, "%c[00m", 0x1b);
print_match(ptr + offsets[0], offsets[1] - offsets[0]);
for (;;)
{
startoffset = offsets[1];
@ -2293,9 +2359,7 @@ while (ptr < endptr)
!match_patterns(matchptr, length, options, startoffset, &mrc))
break;
FWRITE(matchptr + startoffset, 1, offsets[0] - startoffset, stdout);
fprintf(stdout, "%c[%sm", 0x1b, colour_string);
FWRITE(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
fprintf(stdout, "%c[00m", 0x1b);
print_match(matchptr + offsets[0], offsets[1] - offsets[0]);
}
/* In multiline mode, we may have already printed the complete line
@ -3391,7 +3455,12 @@ if (colour_option != NULL && strcmp(colour_option, "never") != 0)
{
char *cs = getenv("PCRE2GREP_COLOUR");
if (cs == NULL) cs = getenv("PCRE2GREP_COLOR");
if (cs == NULL) cs = getenv("GREP_COLOUR");
if (cs == NULL) cs = getenv("GREP_COLOR");
if (cs != NULL) colour_string = cs;
#if defined HAVE_WINDOWS_H && HAVE_WINDOWS_H
init_colour_output();
#endif
}
}