Blame lib/colorize-w32.c

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
}