|
Packit |
709fb3 |
/* Output colorization on MS-Windows.
|
|
Packit |
709fb3 |
Copyright 2011-2017 Free Software Foundation, Inc.
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
709fb3 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
709fb3 |
the Free Software Foundation; either version 3, or (at your option)
|
|
Packit |
709fb3 |
any later version.
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
709fb3 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
709fb3 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
709fb3 |
GNU General Public License for more details.
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
You should have received a copy of the GNU General Public License
|
|
Packit |
709fb3 |
along with this program; if not, write to the Free Software
|
|
Packit |
709fb3 |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
|
|
Packit |
709fb3 |
02110-1301, USA. */
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
/* Written by Eli Zaretskii. */
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
#include <config.h>
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
#include "colorize.h"
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
#include <stdio.h>
|
|
Packit |
709fb3 |
#include <stdlib.h>
|
|
Packit |
709fb3 |
#include <string.h>
|
|
Packit |
709fb3 |
#include <unistd.h>
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
#undef DATADIR /* conflicts with objidl.h, which is included by windows.h */
|
|
Packit |
709fb3 |
#include <windows.h>
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
static HANDLE hstdout = INVALID_HANDLE_VALUE;
|
|
Packit |
709fb3 |
static SHORT norm_attr;
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
/* Initialize the normal text attribute used by the console. */
|
|
Packit |
709fb3 |
void
|
|
Packit |
709fb3 |
init_colorize (void)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
hstdout = GetStdHandle (STD_OUTPUT_HANDLE);
|
|
Packit |
709fb3 |
if (hstdout != INVALID_HANDLE_VALUE
|
|
Packit |
709fb3 |
&& GetConsoleScreenBufferInfo (hstdout, &csbi))
|
|
Packit |
709fb3 |
norm_attr = csbi.wAttributes;
|
|
Packit |
709fb3 |
else
|
|
Packit |
709fb3 |
hstdout = INVALID_HANDLE_VALUE;
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
/* Return non-zero if we should highlight matches in output. */
|
|
Packit |
709fb3 |
int
|
|
Packit |
709fb3 |
should_colorize (void)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
/* $TERM is not normally defined on DOS/Windows, so don't require
|
|
Packit |
709fb3 |
it for highlighting. But some programs, like Emacs, do define
|
|
Packit |
709fb3 |
it when running Grep as a subprocess, so make sure they don't
|
|
Packit |
709fb3 |
set TERM=dumb. */
|
|
Packit |
709fb3 |
char const *t = getenv ("TERM");
|
|
Packit |
709fb3 |
return ! (t && strcmp (t, "dumb") == 0);
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
/* Convert a color spec, a semi-colon separated list of the form
|
|
Packit |
709fb3 |
"NN;MM;KK;...", where each number is a value of the SGR parameter,
|
|
Packit |
709fb3 |
into the corresponding Windows console text attribute.
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
This function supports a subset of the SGR rendition aspects that
|
|
Packit |
709fb3 |
the Windows console can display. */
|
|
Packit |
709fb3 |
static int
|
|
Packit |
709fb3 |
w32_sgr2attr (const char *sgr_seq)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
const char *s, *p;
|
|
Packit |
709fb3 |
int code, fg = norm_attr & 15, bg = norm_attr & (15 << 4);
|
|
Packit |
709fb3 |
int bright = 0, inverse = 0;
|
|
Packit |
709fb3 |
static const int fg_color[] = {
|
|
Packit |
709fb3 |
0, /* black */
|
|
Packit |
709fb3 |
FOREGROUND_RED, /* red */
|
|
Packit |
709fb3 |
FOREGROUND_GREEN, /* green */
|
|
Packit |
709fb3 |
FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */
|
|
Packit |
709fb3 |
FOREGROUND_BLUE, /* blue */
|
|
Packit |
709fb3 |
FOREGROUND_BLUE | FOREGROUND_RED, /* magenta */
|
|
Packit |
709fb3 |
FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */
|
|
Packit |
709fb3 |
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */
|
|
Packit |
709fb3 |
};
|
|
Packit |
709fb3 |
static const int bg_color[] = {
|
|
Packit |
709fb3 |
0, /* black */
|
|
Packit |
709fb3 |
BACKGROUND_RED, /* red */
|
|
Packit |
709fb3 |
BACKGROUND_GREEN, /* green */
|
|
Packit |
709fb3 |
BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */
|
|
Packit |
709fb3 |
BACKGROUND_BLUE, /* blue */
|
|
Packit |
709fb3 |
BACKGROUND_BLUE | BACKGROUND_RED, /* magenta */
|
|
Packit |
709fb3 |
BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */
|
|
Packit |
709fb3 |
BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */
|
|
Packit |
709fb3 |
};
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
for (s = p = sgr_seq; *s; p++)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
if (*p == ';' || *p == '\0')
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
code = strtol (s, NULL, 10);
|
|
Packit |
709fb3 |
s = p + (*p != '\0');
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
switch (code)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
case 0: /* all attributes off */
|
|
Packit |
709fb3 |
fg = norm_attr & 15;
|
|
Packit |
709fb3 |
bg = norm_attr & (15 << 4);
|
|
Packit |
709fb3 |
bright = 0;
|
|
Packit |
709fb3 |
inverse = 0;
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 1: /* intensity on */
|
|
Packit |
709fb3 |
bright = 1;
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 7: /* inverse video */
|
|
Packit |
709fb3 |
inverse = 1;
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 22: /* intensity off */
|
|
Packit |
709fb3 |
bright = 0;
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 27: /* inverse off */
|
|
Packit |
709fb3 |
inverse = 0;
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 30: case 31: case 32: case 33: /* foreground color */
|
|
Packit |
709fb3 |
case 34: case 35: case 36: case 37:
|
|
Packit |
709fb3 |
fg = fg_color[code - 30];
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 39: /* default foreground */
|
|
Packit |
709fb3 |
fg = norm_attr & 15;
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 40: case 41: case 42: case 43: /* background color */
|
|
Packit |
709fb3 |
case 44: case 45: case 46: case 47:
|
|
Packit |
709fb3 |
bg = bg_color[code - 40];
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
case 49: /* default background */
|
|
Packit |
709fb3 |
bg = norm_attr & (15 << 4);
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
default:
|
|
Packit |
709fb3 |
break;
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
if (inverse)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
int t = fg;
|
|
Packit |
709fb3 |
fg = (bg >> 4);
|
|
Packit |
709fb3 |
bg = (t << 4);
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
if (bright)
|
|
Packit |
709fb3 |
fg |= FOREGROUND_INTENSITY;
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
return (bg & (15 << 4)) | (fg & 15);
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
/* Start a colorized text attribute on stdout using the SGR_START
|
|
Packit |
709fb3 |
format; the attribute is specified by SGR_SEQ. */
|
|
Packit |
709fb3 |
void
|
|
Packit |
709fb3 |
print_start_colorize (char const *sgr_start, char const *sgr_seq)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
/* If stdout is connected to a console, set the console text
|
|
Packit |
709fb3 |
attribute directly instead of using SGR_START. Otherwise, use
|
|
Packit |
709fb3 |
SGR_START to emit the SGR escape sequence as on Posix platforms;
|
|
Packit |
709fb3 |
this is needed when Grep is invoked as a subprocess of another
|
|
Packit |
709fb3 |
program, such as Emacs, which will handle the display of the
|
|
Packit |
709fb3 |
matches. */
|
|
Packit |
709fb3 |
if (hstdout != INVALID_HANDLE_VALUE)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
SHORT attr = w32_sgr2attr (sgr_seq);
|
|
Packit |
709fb3 |
SetConsoleTextAttribute (hstdout, attr);
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
else
|
|
Packit |
709fb3 |
printf (sgr_start, sgr_seq);
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
/* Clear to the end of the current line with the default attribute.
|
|
Packit |
709fb3 |
This is needed for reasons similar to those that require the "EL to
|
|
Packit |
709fb3 |
Right after SGR" operation on Posix platforms: if we don't do this,
|
|
Packit |
709fb3 |
setting the 'mt', 'ms', or 'mc' capabilities to use a non-default
|
|
Packit |
709fb3 |
background color spills that color to the empty space at the end of
|
|
Packit |
709fb3 |
the last screen line in a match whose line spans multiple screen
|
|
Packit |
709fb3 |
lines. */
|
|
Packit |
709fb3 |
static void
|
|
Packit |
709fb3 |
w32_clreol (void)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
DWORD nchars;
|
|
Packit |
709fb3 |
COORD start_pos;
|
|
Packit |
709fb3 |
DWORD written;
|
|
Packit |
709fb3 |
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
GetConsoleScreenBufferInfo (hstdout, &csbi);
|
|
Packit |
709fb3 |
start_pos = csbi.dwCursorPosition;
|
|
Packit |
709fb3 |
nchars = csbi.dwSize.X - start_pos.X;
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
FillConsoleOutputAttribute (hstdout, norm_attr, nchars, start_pos,
|
|
Packit |
709fb3 |
&written);
|
|
Packit |
709fb3 |
FillConsoleOutputCharacter (hstdout, ' ', nchars, start_pos, &written);
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
|
|
Packit |
709fb3 |
/* Restore the normal text attribute using the SGR_END string. */
|
|
Packit |
709fb3 |
void
|
|
Packit |
709fb3 |
print_end_colorize (char const *sgr_end)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
if (hstdout != INVALID_HANDLE_VALUE)
|
|
Packit |
709fb3 |
{
|
|
Packit |
709fb3 |
SetConsoleTextAttribute (hstdout, norm_attr);
|
|
Packit |
709fb3 |
w32_clreol ();
|
|
Packit |
709fb3 |
}
|
|
Packit |
709fb3 |
else
|
|
Packit |
709fb3 |
fputs (sgr_end, stdout);
|
|
Packit |
709fb3 |
}
|