(root)/
grep-3.11/
lib/
colorize-w32.c
       1  /* Output colorization on MS-Windows.
       2     Copyright 2011-2023 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3, or (at your option)
       7     any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program; if not, write to the Free Software
      16     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
      17     02110-1301, USA.  */
      18  
      19  /* Written by Eli Zaretskii.  */
      20  
      21  #include <config.h>
      22  
      23  #include "colorize.h"
      24  
      25  #include <stdio.h>
      26  #include <stdlib.h>
      27  #include <string.h>
      28  #include <unistd.h>
      29  
      30  #undef DATADIR	/* conflicts with objidl.h, which is included by windows.h */
      31  #include <windows.h>
      32  
      33  static HANDLE hstdout = INVALID_HANDLE_VALUE;
      34  static SHORT norm_attr;
      35  
      36  /* Initialize the normal text attribute used by the console.  */
      37  void
      38  init_colorize (void)
      39  {
      40    CONSOLE_SCREEN_BUFFER_INFO csbi;
      41  
      42    hstdout = GetStdHandle (STD_OUTPUT_HANDLE);
      43    if (hstdout != INVALID_HANDLE_VALUE
      44        && GetConsoleScreenBufferInfo (hstdout, &csbi))
      45       norm_attr = csbi.wAttributes;
      46    else
      47      hstdout = INVALID_HANDLE_VALUE;
      48  }
      49  
      50  /* Return non-zero if we should highlight matches in output.  */
      51  int
      52  should_colorize (void)
      53  {
      54    /* $TERM is not normally defined on DOS/Windows, so don't require
      55       it for highlighting.  But some programs, like Emacs, do define
      56       it when running Grep as a subprocess, so make sure they don't
      57       set TERM=dumb.  */
      58    char const *t = getenv ("TERM");
      59    return ! (t && strcmp (t, "dumb") == 0);
      60  }
      61  
      62  /* Convert a color spec, a semi-colon separated list of the form
      63     "NN;MM;KK;...", where each number is a value of the SGR parameter,
      64     into the corresponding Windows console text attribute.
      65  
      66     This function supports a subset of the SGR rendition aspects that
      67     the Windows console can display.  */
      68  static int
      69  w32_sgr2attr (const char *sgr_seq)
      70  {
      71    const char *s, *p;
      72    int code, fg = norm_attr & 15, bg = norm_attr & (15 << 4);
      73    int bright = 0, inverse = 0;
      74    static const int fg_color[] = {
      75      0,			/* black */
      76      FOREGROUND_RED,	/* red */
      77      FOREGROUND_GREEN,	/* green */
      78      FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */
      79      FOREGROUND_BLUE,		       /* blue */
      80      FOREGROUND_BLUE | FOREGROUND_RED,  /* magenta */
      81      FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */
      82      FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */
      83    };
      84    static const int bg_color[] = {
      85      0,			/* black */
      86      BACKGROUND_RED,	/* red */
      87      BACKGROUND_GREEN,	/* green */
      88      BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */
      89      BACKGROUND_BLUE,		       /* blue */
      90      BACKGROUND_BLUE | BACKGROUND_RED,  /* magenta */
      91      BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */
      92      BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */
      93    };
      94  
      95    for (s = p = sgr_seq; *s; p++)
      96      {
      97        if (*p == ';' || *p == '\0')
      98          {
      99            code = strtol (s, NULL, 10);
     100            s = p + (*p != '\0');
     101  
     102            switch (code)
     103              {
     104              case 0:	/* all attributes off */
     105                fg = norm_attr & 15;
     106                bg = norm_attr & (15 << 4);
     107                bright = 0;
     108                inverse = 0;
     109                break;
     110              case 1:	/* intensity on */
     111                bright = 1;
     112                break;
     113              case 7:	/* inverse video */
     114                inverse = 1;
     115                break;
     116              case 22:	/* intensity off */
     117                bright = 0;
     118                break;
     119              case 27:	/* inverse off */
     120                inverse = 0;
     121                break;
     122              case 30: case 31: case 32: case 33: /* foreground color */
     123              case 34: case 35: case 36: case 37:
     124                fg = fg_color[code - 30];
     125                break;
     126              case 39:	/* default foreground */
     127                fg = norm_attr & 15;
     128                break;
     129              case 40: case 41: case 42: case 43: /* background color */
     130              case 44: case 45: case 46: case 47:
     131                bg = bg_color[code - 40];
     132                break;
     133              case 49:	/* default background */
     134                bg = norm_attr & (15 << 4);
     135                break;
     136              default:
     137                break;
     138              }
     139          }
     140      }
     141    if (inverse)
     142      {
     143        int t = fg;
     144        fg = (bg >> 4);
     145        bg = (t << 4);
     146      }
     147    if (bright)
     148      fg |= FOREGROUND_INTENSITY;
     149  
     150    return (bg & (15 << 4)) | (fg & 15);
     151  }
     152  
     153  /* Start a colorized text attribute on stdout using the SGR_START
     154     format; the attribute is specified by SGR_SEQ.  */
     155  void
     156  print_start_colorize (char const *sgr_start, char const *sgr_seq)
     157  {
     158    /* If stdout is connected to a console, set the console text
     159       attribute directly instead of using SGR_START.  Otherwise, use
     160       SGR_START to emit the SGR escape sequence as on Posix platforms;
     161       this is needed when Grep is invoked as a subprocess of another
     162       program, such as Emacs, which will handle the display of the
     163       matches.  */
     164    if (hstdout != INVALID_HANDLE_VALUE)
     165      {
     166        SHORT attr = w32_sgr2attr (sgr_seq);
     167        SetConsoleTextAttribute (hstdout, attr);
     168      }
     169    else
     170      printf (sgr_start, sgr_seq);
     171  }
     172  
     173  /* Clear to the end of the current line with the default attribute.
     174     This is needed for reasons similar to those that require the "EL to
     175     Right after SGR" operation on Posix platforms: if we don't do this,
     176     setting the 'mt', 'ms', or 'mc' capabilities to use a non-default
     177     background color spills that color to the empty space at the end of
     178     the last screen line in a match whose line spans multiple screen
     179     lines.  */
     180  static void
     181  w32_clreol (void)
     182  {
     183    DWORD nchars;
     184    COORD start_pos;
     185    DWORD written;
     186    CONSOLE_SCREEN_BUFFER_INFO csbi;
     187  
     188    GetConsoleScreenBufferInfo (hstdout, &csbi);
     189    start_pos = csbi.dwCursorPosition;
     190    nchars = csbi.dwSize.X - start_pos.X;
     191  
     192    FillConsoleOutputAttribute (hstdout, norm_attr, nchars, start_pos,
     193                                &written);
     194    FillConsoleOutputCharacter (hstdout, ' ', nchars, start_pos, &written);
     195  }
     196  
     197  /* Restore the normal text attribute using the SGR_END string.  */
     198  void
     199  print_end_colorize (char const *sgr_end)
     200  {
     201    if (hstdout != INVALID_HANDLE_VALUE)
     202      {
     203        SetConsoleTextAttribute (hstdout, norm_attr);
     204        w32_clreol ();
     205      }
     206    else
     207      fputs (sgr_end, stdout);
     208  }