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. 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 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 .SH NAME
pcre2grep - a grep with Perl-compatible regular expressions. pcre2grep - a grep with Perl-compatible regular expressions.
.SH SYNOPSIS .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. just one, in order to colour them all.
.sp .sp
The colour that is used can be specified by setting the environment variable 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 PCRE2GREP_COLOUR or PCRE2GREP_COLOR. If neither of these are set,
string of two numbers, separated by a semicolon. They are copied directly into \fBpcre2grep\fP looks for GREP_COLOUR or GREP_COLOR. The value of the variable
the control string for setting colour on a terminal, so it is your should be a string of two numbers, separated by a semicolon. They are copied
responsibility to ensure that they make sense. If neither of the environment directly into the control string for setting colour on a terminal, so it is
variables is set, the default is "1;31", which gives red. 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 .TP
\fB-D\fP \fIaction\fP, \fB--devices=\fP\fIaction\fP \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 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 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 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 \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 of them is shown separately, on a separate line of output. If \fB-o\fP is
sense of the match to find non-matching lines), no output is generated, but the combined with \fB-v\fP (invert the sense of the match to find non-matching
return code is set appropriately. If the matched portion of the line is empty, lines), no output is generated, but the return code is set appropriately. If
nothing is output unless the file name or line number are being printed, in the matched portion of the line is empty, nothing is output unless the file
which case they are shown on an otherwise empty line. This option is mutually name or line number are being printed, in which case they are shown on an
exclusive with \fB--file-offsets\fP and \fB--line-offsets\fP. otherwise empty line. This option is mutually exclusive with
\fB--file-offsets\fP and \fB--line-offsets\fP.
.TP .TP
\fB-o\fP\fInumber\fP, \fB--only-matching\fP=\fInumber\fP \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 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 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. match, nothing is output unless the file name or line number are being output.
.sp .sp
If this option is given multiple times, multiple substrings are output, in the If this option is given multiple times, multiple substrings are output for each
order the options are given. For example, -o3 -o1 -o3 causes the substrings match, in the order the options are given, and all on one line. For example,
matched by capturing parentheses 3 and 1 and then 3 again to be output. By -o3 -o1 -o3 causes the substrings matched by capturing parentheses 3 and 1 and
default, there is no separator (but see the next option). then 3 again to be output. By default, there is no separator (but see the next
option).
.TP .TP
\fB--om-separator\fP=\fItext\fP \fB--om-separator\fP=\fItext\fP
Specify a separating string for multiple occurrences of \fB-o\fP. The default Specify a separating string for multiple occurrences of \fB-o\fP. The default
@ -775,6 +778,6 @@ Cambridge, England.
.rs .rs
.sp .sp
.nf .nf
Last updated: 11 October 2016 Last updated: 14 October 2016
Copyright (c) 1997-2016 University of Cambridge. Copyright (c) 1997-2016 University of Cambridge.
.fi .fi

View File

@ -681,6 +681,17 @@ return isatty(fileno(f));
} }
#endif #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. */ /* End of Unix-style or native z/OS environment functions. */
@ -814,6 +825,65 @@ is_file_tty(FILE *f)
return FALSE; 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 */ /* End of Windows functions */
@ -2113,9 +2183,7 @@ while (ptr < endptr)
if (plen > 0) if (plen > 0)
{ {
if (printed) fprintf(stdout, "%s", om_separator); if (printed) fprintf(stdout, "%s", om_separator);
if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string); print_match(matchptr + offsets[n*2], plen);
FWRITE(matchptr + offsets[n*2], 1, plen, stdout);
if (do_colour) fprintf(stdout, "%c[00m", 0x1b);
printed = TRUE; printed = TRUE;
} }
} }
@ -2283,9 +2351,7 @@ while (ptr < endptr)
{ {
int plength; int plength;
FWRITE(ptr, 1, offsets[0], stdout); FWRITE(ptr, 1, offsets[0], stdout);
fprintf(stdout, "%c[%sm", 0x1b, colour_string); print_match(ptr + offsets[0], offsets[1] - offsets[0]);
FWRITE(ptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
fprintf(stdout, "%c[00m", 0x1b);
for (;;) for (;;)
{ {
startoffset = offsets[1]; startoffset = offsets[1];
@ -2293,9 +2359,7 @@ while (ptr < endptr)
!match_patterns(matchptr, length, options, startoffset, &mrc)) !match_patterns(matchptr, length, options, startoffset, &mrc))
break; break;
FWRITE(matchptr + startoffset, 1, offsets[0] - startoffset, stdout); FWRITE(matchptr + startoffset, 1, offsets[0] - startoffset, stdout);
fprintf(stdout, "%c[%sm", 0x1b, colour_string); print_match(matchptr + offsets[0], offsets[1] - offsets[0]);
FWRITE(matchptr + offsets[0], 1, offsets[1] - offsets[0], stdout);
fprintf(stdout, "%c[00m", 0x1b);
} }
/* In multiline mode, we may have already printed the complete line /* 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"); char *cs = getenv("PCRE2GREP_COLOUR");
if (cs == NULL) cs = getenv("PCRE2GREP_COLOR"); 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 (cs != NULL) colour_string = cs;
#if defined HAVE_WINDOWS_H && HAVE_WINDOWS_H
init_colour_output();
#endif
} }
} }