From 4f61a0530c565bed2e8d0cf74ac9fd4322313093 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 31 Dec 2011 19:35:58 -0800 Subject: ms: move Microsoft-specific stuff to lib/ms * cfg.mk (exclude_file_name_regexp--sc_prohibit_strcmp) (exclude_file_name_regexp--sc_require_config_h) (exclude_file_name_regexp--sc_require_config_h_first): New rules. * lib/colorize.c, lib/colorize.h, lib/colorize-impl.c: * lib/ms/colorize.h, lib/ms/colorize-impl.c: New files. * configure.ac (GREP_SRC_INCLUDES): New macro. * lib/Makefile.am (libgreputils_a_SOURCES): Add colorize.[ch]. (EXTRA_DIST): New macro. * src/Makefile.am (DEFAULT_INCLUDES): New macro. * src/main.c: Include colorize.h. (PR_SGR_START, PR_SGR_END, PR_SGR_START_IF, PR_SGR_END_IF): Now static functions, not macros. (hstdout, norm_attr, w32_console_init, w32_sgr2attr) (w32_clreol) [__MINGW32__]: Move to lib/ms/colorize-impl.c. (pr_sgr_start, pr_sgr_end): Remove; callers changed to use new print_start_colorize, print_end_colorize from colorize.h. (init_colorize): Rename from w32_console_init and move to colorize module; caller changed. (should_colorize): Move to colorize module. --- cfg.mk | 3 + configure.ac | 6 ++ lib/Makefile.am | 4 +- lib/colorize-impl.c | 39 ++++++++ lib/colorize.c | 1 + lib/colorize.h | 37 ++++++++ lib/ms/colorize-impl.c | 216 ++++++++++++++++++++++++++++++++++++++++++ lib/ms/colorize.h | 4 + src/Makefile.am | 1 + src/main.c | 252 ++++++------------------------------------------- 10 files changed, 337 insertions(+), 226 deletions(-) create mode 100644 lib/colorize-impl.c create mode 100644 lib/colorize.c create mode 100644 lib/colorize.h create mode 100644 lib/ms/colorize-impl.c create mode 100644 lib/ms/colorize.h diff --git a/cfg.mk b/cfg.mk index d7cb9c42..309ee23d 100644 --- a/cfg.mk +++ b/cfg.mk @@ -63,7 +63,10 @@ update-copyright-env = \ UPDATE_COPYRIGHT_MAX_LINE_LENGTH=79 exclude_file_name_regexp--sc_bindtextdomain = ^tests/get-mb-cur-max\.c$$ +exclude_file_name_regexp--sc_prohibit_strcmp = /colorize-impl\.c$$ exclude_file_name_regexp--sc_prohibit_xalloc_without_use = ^src/kwset\.c$$ exclude_file_name_regexp--sc_prohibit_tab_based_indentation = \ (Makefile|\.(am|mk)$$|^gl/lib/.*\.c\.diff$$) +exclude_file_name_regexp--sc_require_config_h = ^lib/colorize\.c$$ +exclude_file_name_regexp--sc_require_config_h_first = ^lib/colorize\.c$$ exclude_file_name_regexp--sc_space_tab = ^gl/lib/.*\.c\.diff$$ diff --git a/configure.ac b/configure.ac index 3eff422d..46e9edb5 100644 --- a/configure.ac +++ b/configure.ac @@ -200,6 +200,12 @@ fi gl_FUNC_PCRE +case $host_os in + mingw*) GREP_SRC_INCLUDES='-I$(top_srcdir)/lib/ms' ;; + *) GREP_SRC_INCLUDES= ;; +esac +AC_SUBST([GREP_SRC_INCLUDES]) + AC_CONFIG_FILES([ Makefile lib/Makefile diff --git a/lib/Makefile.am b/lib/Makefile.am index 3d0c1ba3..239a53fe 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -21,7 +21,9 @@ INCLUDES = -I.. -I$(srcdir) AM_CFLAGS += $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS) libgreputils_a_SOURCES += \ - savedir.c savedir.h + colorize.c colorize.h savedir.c savedir.h + +EXTRA_DIST += colorize-impl.c ms/colorize.h ms/colorize-impl.c libgreputils_a_LIBADD += $(LIBOBJS) $(ALLOCA) libgreputils_a_DEPENDENCIES += $(LIBOBJS) $(ALLOCA) diff --git a/lib/colorize-impl.c b/lib/colorize-impl.c new file mode 100644 index 00000000..48af4d4a --- /dev/null +++ b/lib/colorize-impl.c @@ -0,0 +1,39 @@ +/* Output colorization. + Copyright 2011 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include + +#include "colorize.h" + +#include +#include +#include + +/* Return non-zero if we should highlight matches in output to file + descriptor FD. */ +int +should_colorize (int fd) +{ + if (! isatty (fd)) + return 0; + else + { + char const *t = getenv ("TERM"); + return t && strcmp (t, "dumb") != 0; + } +} diff --git a/lib/colorize.c b/lib/colorize.c new file mode 100644 index 00000000..51b1847d --- /dev/null +++ b/lib/colorize.c @@ -0,0 +1 @@ +#include diff --git a/lib/colorize.h b/lib/colorize.h new file mode 100644 index 00000000..9fdfaa30 --- /dev/null +++ b/lib/colorize.h @@ -0,0 +1,37 @@ +/* Output colorization. + + Copyright 2011 Free Software Foundation, Inc. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include + +static inline void init_colorize (void) { } +extern int should_colorize (int); + +/* Start a colorized text attribute on stdout using the SGR_START + format; the attribute is specified by SGR_SEQ. */ +static inline void +print_start_colorize (char const *sgr_start, char const *sgr_seq) +{ + printf (sgr_start, sgr_seq); +} + +/* Restore the normal text attribute using the SGR_END string. */ +static inline void +print_end_colorize (char const *sgr_end) +{ + printf ("%s", sgr_end); +} diff --git a/lib/ms/colorize-impl.c b/lib/ms/colorize-impl.c new file mode 100644 index 00000000..d5634107 --- /dev/null +++ b/lib/ms/colorize-impl.c @@ -0,0 +1,216 @@ +/* Output colorization on MS-Windows. + Copyright 2011 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* Written by Eli Zaretskii. */ + +#include + +#include "colorize.h" + +#include +#include +#include +#include + +#undef DATADIR /* conflicts with objidl.h, which is included by windows.h */ +#include + +static HANDLE hstdout = INVALID_HANDLE_VALUE; +static SHORT norm_attr; + +/* Initialize the normal text attribute used by the console. */ +void +init_colorize (void) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + hstdout = GetStdHandle (STD_OUTPUT_HANDLE); + if (hstdout != INVALID_HANDLE_VALUE + && GetConsoleScreenBufferInfo (hstdout, &csbi)) + norm_attr = csbi.wAttributes; + else + hstdout = INVALID_HANDLE_VALUE; +} + +/* Return non-zero if we should highlight matches in output. */ +int +should_colorize (int fd) +{ + if (! isatty (fd)) + return 0; + /* Windows isatty returns non-zero for the null device too. */ + else if (lseek (fd, SEEK_CUR, 0) != -1) + return 0; + else + { + /* $TERM is not normally defined on DOS/Windows, so don't require + it for highlighting. But some programs, like Emacs, do define + it when running Grep as a subprocess, so make sure they don't + set TERM=dumb. */ + char const *t = getenv ("TERM"); + return ! (t && strcmp (t, "dumb") == 0); + } +} + +/* Convert a color spec, a semi-colon separated list of the form + "NN;MM;KK;...", where each number is a value of the SGR parameter, + into the corresponding Windows console text attribute. + + This function supports a subset of the SGR rendition aspects that + the Windows console can display. */ +static int +w32_sgr2attr (const char *sgr_seq) +{ + const char *s, *p; + int code, fg = norm_attr & 15, bg = norm_attr & (15 << 4); + int bright = 0, inverse = 0; + static const int fg_color[] = { + 0, /* black */ + FOREGROUND_RED, /* red */ + FOREGROUND_GREEN, /* green */ + FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */ + FOREGROUND_BLUE, /* blue */ + FOREGROUND_BLUE | FOREGROUND_RED, /* magenta */ + FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */ + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */ + }; + static const int bg_color[] = { + 0, /* black */ + BACKGROUND_RED, /* red */ + BACKGROUND_GREEN, /* green */ + BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */ + BACKGROUND_BLUE, /* blue */ + BACKGROUND_BLUE | BACKGROUND_RED, /* magenta */ + BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */ + BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */ + }; + + for (s = p = sgr_seq; *s; p++) + { + if (*p == ';' || *p == '\0') + { + code = strtol (s, NULL, 10); + s = p + (*p != '\0'); + + switch (code) + { + case 0: /* all attributes off */ + fg = norm_attr & 15; + bg = norm_attr & (15 << 4); + bright = 0; + inverse = 0; + break; + case 1: /* intensity on */ + bright = 1; + break; + case 7: /* inverse video */ + inverse = 1; + break; + case 22: /* intensity off */ + bright = 0; + break; + case 27: /* inverse off */ + inverse = 0; + break; + case 30: case 31: case 32: case 33: /* foreground color */ + case 34: case 35: case 36: case 37: + fg = fg_color[code - 30]; + break; + case 39: /* default foreground */ + fg = norm_attr & 15; + break; + case 40: case 41: case 42: case 43: /* background color */ + case 44: case 45: case 46: case 47: + bg = bg_color[code - 40]; + break; + case 49: /* default background */ + bg = norm_attr & (15 << 4); + break; + default: + break; + } + } + } + if (inverse) + { + int t = fg; + fg = (bg >> 4); + bg = (t << 4); + } + if (bright) + fg |= FOREGROUND_INTENSITY; + + return (bg & (15 << 4)) | (fg & 15); +} + +/* Start a colorized text attribute on stdout using the SGR_START + format; the attribute is specified by SGR_SEQ. */ +void +print_start_colorize (char const *sgr_start, char const *sgr_seq) +{ + /* If stdout is connected to a console, set the console text + attribute directly instead of using SGR_START. Otherwise, use + SGR_START to emit the SGR escape sequence as on Posix platforms; + this is needed when Grep is invoked as a subprocess of another + program, such as Emacs, which will handle the display of the + matches. */ + if (hstdout != INVALID_HANDLE_VALUE) + { + SHORT attr = w32_sgr2attr (sgr_seq); + SetConsoleTextAttribute (hstdout, attr); + } + else + printf (sgr_start, sgr_seq); +} + +/* Clear to the end of the current line with the default attribute. + This is needed for reasons similar to those that require the "EL to + Right after SGR" operation on Posix platforms: if we don't do this, + setting the `mt', `ms', or `mc' capabilities to use a non-default + background color spills that color to the empty space at the end of + the last screen line in a match whose line spans multiple screen + lines. */ +static void +w32_clreol (void) +{ + DWORD nchars; + COORD start_pos; + DWORD written; + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (hstdout, &csbi); + start_pos = csbi.dwCursorPosition; + nchars = csbi.dwSize.X - start_pos.X; + + FillConsoleOutputAttribute (hstdout, norm_attr, nchars, start_pos, + &written); + FillConsoleOutputCharacter (hstdout, ' ', nchars, start_pos, &written); +} + +/* Restore the normal text attribute using the SGR_END string. */ +void +print_end_colorize (char const *sgr_end) +{ + if (hstdout != INVALID_HANDLE_VALUE) + { + SetConsoleTextAttribute (hstdout, norm_attr); + w32_clreol (); + } + else + printf ("%s", sgr_end); +} diff --git a/lib/ms/colorize.h b/lib/ms/colorize.h new file mode 100644 index 00000000..c49657d6 --- /dev/null +++ b/lib/ms/colorize.h @@ -0,0 +1,4 @@ +extern void colorize_init (void); +extern int should_colorize (int); +extern void print_start_colorize (char const *, char const *); +extern void print_end_colorize (char const *); diff --git a/src/Makefile.am b/src/Makefile.am index 257472be..6987f664 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,6 +42,7 @@ LDADD = \ grep_LDADD = $(LDADD) $(LIB_PCRE) localedir = $(datadir)/locale +DEFAULT_INCLUDES = $(GREP_SRC_INCLUDES) -I.@am__isrc@ -I$(top_builddir) AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib EXTRA_DIST = dosbuf.c diff --git a/src/main.c b/src/main.c index 3fff5b75..8e4142a0 100644 --- a/src/main.c +++ b/src/main.c @@ -35,6 +35,7 @@ #include "argmatch.h" #include "c-ctype.h" #include "closeout.h" +#include "colorize.h" #include "error.h" #include "exclude.h" #include "exitfail.h" @@ -211,11 +212,31 @@ static const char *context_line_color = ""; /* default color pair */ static const char *sgr_start = "\33[%sm\33[K"; static const char *sgr_end = "\33[m\33[K"; -/* SGR utility macros. */ -#define PR_SGR_START(s) pr_sgr_start (s, 1) -#define PR_SGR_END(s) pr_sgr_end (s, 1) -#define PR_SGR_START_IF(s) pr_sgr_start (s, color_option) -#define PR_SGR_END_IF(s) pr_sgr_end (s, color_option) +/* SGR utility functions. */ +static void +PR_SGR_START (char const *s) +{ + if (*s) + print_start_colorize (sgr_start, s); +} +static void +PR_SGR_END (char const *s) +{ + if (*s) + print_end_colorize (sgr_end); +} +static void +PR_SGR_START_IF (char const *s) +{ + if (color_option) + PR_SGR_START (s); +} +static void +PR_SGR_END_IF (char const *s) +{ + if (color_option) + PR_SGR_END (s); +} struct color_cap { @@ -268,199 +289,6 @@ static const struct color_cap color_dict[] = { NULL, NULL, NULL } }; -#ifdef __MINGW32__ -/* Support for colorization on MS-Windows console. */ - -#undef DATADIR /* conflicts with objidl.h, which is included by windows.h */ -#include - -static HANDLE hstdout = INVALID_HANDLE_VALUE; -static SHORT norm_attr; - -/* Initialize the normal text attribute used by the console. */ -static void -w32_console_init (void) -{ - CONSOLE_SCREEN_BUFFER_INFO csbi; - - hstdout = GetStdHandle (STD_OUTPUT_HANDLE); - if (hstdout != INVALID_HANDLE_VALUE - && GetConsoleScreenBufferInfo (hstdout, &csbi)) - norm_attr = csbi.wAttributes; - else - hstdout = INVALID_HANDLE_VALUE; -} - -/* Convert a color spec, a semi-colon separated list of the form - "NN;MM;KK;...", where each number is a value of the SGR parameter, - into the corresponding Windows console text attribute. - - This function supports a subset of the SGR rendition aspects that - the Windows console can display. */ -static int -w32_sgr2attr (const char *sgr_seq) -{ - const char *s, *p; - int code, fg = norm_attr & 15, bg = norm_attr & (15 << 4); - int bright = 0, inverse = 0; - static const int fg_color[] = { - 0, /* black */ - FOREGROUND_RED, /* red */ - FOREGROUND_GREEN, /* green */ - FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */ - FOREGROUND_BLUE, /* blue */ - FOREGROUND_BLUE | FOREGROUND_RED, /* magenta */ - FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */ - FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */ - }; - static const int bg_color[] = { - 0, /* black */ - BACKGROUND_RED, /* red */ - BACKGROUND_GREEN, /* green */ - BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */ - BACKGROUND_BLUE, /* blue */ - BACKGROUND_BLUE | BACKGROUND_RED, /* magenta */ - BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */ - BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */ - }; - - for (s = p = sgr_seq; *s; p++) - { - if (*p == ';' || *p == '\0') - { - code = strtol (s, NULL, 10); - s = p + (*p != '\0'); - - switch (code) - { - case 0: /* all attributes off */ - fg = norm_attr & 15; - bg = norm_attr & (15 << 4); - bright = 0; - inverse = 0; - break; - case 1: /* intensity on */ - bright = 1; - break; - case 7: /* inverse video */ - inverse = 1; - break; - case 22: /* intensity off */ - bright = 0; - break; - case 27: /* inverse off */ - inverse = 0; - break; - case 30: case 31: case 32: case 33: /* foreground color */ - case 34: case 35: case 36: case 37: - fg = fg_color[code - 30]; - break; - case 39: /* default foreground */ - fg = norm_attr & 15; - break; - case 40: case 41: case 42: case 43: /* background color */ - case 44: case 45: case 46: case 47: - bg = bg_color[code - 40]; - break; - case 49: /* default background */ - bg = norm_attr & (15 << 4); - break; - default: - break; - } - } - } - if (inverse) - { - int t = fg; - fg = (bg >> 4); - bg = (t << 4); - } - if (bright) - fg |= FOREGROUND_INTENSITY; - - return (bg & (15 << 4)) | (fg & 15); -} - -/* Start displaying text according to the spec in SGR_SEQ, but only if - SGR_SEQ is non-empty and COND is non-zero. If stdout is connected - to a console, set the console text attribute; otherwise, emit the - SGR escape sequence as on Posix platforms (this is needed when Grep - is invoked as a subprocess of another program, such as Emacs, which - will handle the display of the matches). */ -static void -pr_sgr_start (const char *sgr_seq, int cond) -{ - if (cond && *sgr_seq) - { - if (hstdout != INVALID_HANDLE_VALUE) - { - SHORT attr = w32_sgr2attr (sgr_seq); - SetConsoleTextAttribute (hstdout, attr); - } - else - printf (sgr_start, sgr_seq); - } -} - -/* Clear to the end of the current line with the default attribute. - This is needed for reasons similar to those that require the "EL to - Right after SGR" operation on Posix platforms: if we don't do this, - setting the `mt', `ms', or `mc' capabilities to use a non-default - background color spills that color to the empty space at the end of - the last screen line in a match whose line spans multiple screen - lines. */ -static void -w32_clreol (void) -{ - DWORD nchars; - COORD start_pos; - DWORD written; - CONSOLE_SCREEN_BUFFER_INFO csbi; - - GetConsoleScreenBufferInfo (hstdout, &csbi); - start_pos = csbi.dwCursorPosition; - nchars = csbi.dwSize.X - start_pos.X; - - FillConsoleOutputAttribute (hstdout, norm_attr, nchars, start_pos, - &written); - FillConsoleOutputCharacter (hstdout, ' ', nchars, start_pos, &written); -} - -/* Restore the normal text attribute. */ -static void -pr_sgr_end (const char *sgr_seq, int cond) -{ - if (cond && *sgr_seq) - { - if (hstdout != INVALID_HANDLE_VALUE) - { - SetConsoleTextAttribute (hstdout, norm_attr); - w32_clreol (); - } - else - printf ("%s", sgr_end); - } -} -#else - -static void -pr_sgr_start (const char *sgr_seq, int cond) -{ - if (cond && *sgr_seq) - printf (sgr_start, sgr_seq); -} - - -/* Restore the normal text attribute. */ -static void -pr_sgr_end (const char *sgr_seq, int cond) -{ - if (cond && *sgr_seq) - printf ("%s", sgr_end); -} -#endif /* __MINGW32__ */ - static struct exclude *excluded_patterns; static struct exclude *included_patterns; static struct exclude *excluded_directory_patterns; @@ -1941,30 +1769,6 @@ parse_grep_colors (void) "at remaining substring \"%s\""), p, q); } -/* Return non-zero if we should highlight matches in output. */ -static int -should_colorize (int fd) -{ - const char *t; - -#if defined __MINGW32__ || defined __DJGPP__ - return - isatty (fd) -#ifdef __MINGW32__ - /* Without the lseek call, Windows isatty returns non-zero for the - null device as well. */ - && lseek (fd, SEEK_CUR, 0) == -1 -#endif - /* $TERM is not normally defined on DOS/Windows, so don't require - it for highlighting. But some programs, like Emacs, do define - it when running Grep as a subprocess, so make sure they don't - set TERM=dumb. */ - && !((t = getenv ("TERM")) && STREQ (t, "dumb")); -#else /* not __MINGW32__, not __DJGPP__ */ - return isatty (fd) && (t = getenv ("TERM")) && !STREQ (t, "dumb"); -#endif -} - int main (int argc, char **argv) { @@ -2297,9 +2101,7 @@ main (int argc, char **argv) if (color_option == 2) color_option = should_colorize (STDOUT_FILENO); -#ifdef __MINGW32__ - w32_console_init (); -#endif + init_colorize (); /* POSIX.2 says that -q overrides -l, which in turn overrides the other output options. */ -- cgit v1.2.1