diff --git a/ChangeLog b/ChangeLog index 97355c4..8b6401e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 -------------------------- diff --git a/doc/pcre2grep.1 b/doc/pcre2grep.1 index 82be375..b5cc1da 100644 --- a/doc/pcre2grep.1 +++ b/doc/pcre2grep.1 @@ -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 diff --git a/src/pcre2grep.c b/src/pcre2grep.c index 8d847ed..fe87022 100644 --- a/src/pcre2grep.c +++ b/src/pcre2grep.c @@ -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 } }