Blame src/grep.c.man-fix-gs

Packit cb4c47
/* grep.c - main driver file for grep.
Packit cb4c47
   Copyright (C) 1992, 1997-2002, 2004-2017 Free Software Foundation, Inc.
Packit cb4c47
Packit cb4c47
   This program is free software; you can redistribute it and/or modify
Packit cb4c47
   it under the terms of the GNU General Public License as published by
Packit cb4c47
   the Free Software Foundation; either version 3, or (at your option)
Packit cb4c47
   any later version.
Packit cb4c47
Packit cb4c47
   This program is distributed in the hope that it will be useful,
Packit cb4c47
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cb4c47
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit cb4c47
   GNU General Public License for more details.
Packit cb4c47
Packit cb4c47
   You should have received a copy of the GNU General Public License
Packit cb4c47
   along with this program; if not, write to the Free Software
Packit cb4c47
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
Packit cb4c47
   02110-1301, USA.  */
Packit cb4c47
Packit cb4c47
/* Written July 1992 by Mike Haertel.  */
Packit cb4c47
Packit cb4c47
#include <config.h>
Packit cb4c47
#include <sys/types.h>
Packit cb4c47
#include <sys/stat.h>
Packit cb4c47
#include <wchar.h>
Packit cb4c47
#include <fcntl.h>
Packit cb4c47
#include <inttypes.h>
Packit cb4c47
#include <stdarg.h>
Packit cb4c47
#include <stdio.h>
Packit cb4c47
#include "system.h"
Packit cb4c47
Packit cb4c47
#include "argmatch.h"
Packit cb4c47
#include "c-ctype.h"
Packit cb4c47
#include "closeout.h"
Packit cb4c47
#include "colorize.h"
Packit cb4c47
#include "die.h"
Packit cb4c47
#include "error.h"
Packit cb4c47
#include "exclude.h"
Packit cb4c47
#include "exitfail.h"
Packit cb4c47
#include "fcntl-safer.h"
Packit cb4c47
#include "fts_.h"
Packit cb4c47
#include "getopt.h"
Packit cb4c47
#include "getprogname.h"
Packit cb4c47
#include "grep.h"
Packit cb4c47
#include "intprops.h"
Packit cb4c47
#include "propername.h"
Packit cb4c47
#include "quote.h"
Packit cb4c47
#include "safe-read.h"
Packit cb4c47
#include "search.h"
Packit cb4c47
#include "version-etc.h"
Packit cb4c47
#include "xalloc.h"
Packit cb4c47
#include "xbinary-io.h"
Packit cb4c47
#include "xstrtol.h"
Packit cb4c47
Packit cb4c47
enum { SEP_CHAR_SELECTED = ':' };
Packit cb4c47
enum { SEP_CHAR_REJECTED = '-' };
Packit cb4c47
static char const SEP_STR_GROUP[] = "--";
Packit cb4c47
Packit cb4c47
#define AUTHORS \
Packit cb4c47
  proper_name ("Mike Haertel"), \
Packit cb4c47
  _("others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>")
Packit cb4c47
Packit cb4c47
/* When stdout is connected to a regular file, save its stat
Packit cb4c47
   information here, so that we can automatically skip it, thus
Packit cb4c47
   avoiding a potential (racy) infinite loop.  */
Packit cb4c47
static struct stat out_stat;
Packit cb4c47
Packit cb4c47
/* if non-zero, display usage information and exit */
Packit cb4c47
static int show_help;
Packit cb4c47
Packit cb4c47
/* Print the version on standard output and exit.  */
Packit cb4c47
static bool show_version;
Packit cb4c47
Packit cb4c47
/* Suppress diagnostics for nonexistent or unreadable files.  */
Packit cb4c47
static bool suppress_errors;
Packit cb4c47
Packit cb4c47
/* If nonzero, use color markers.  */
Packit cb4c47
static int color_option;
Packit cb4c47
Packit cb4c47
/* Show only the part of a line matching the expression. */
Packit cb4c47
static bool only_matching;
Packit cb4c47
Packit cb4c47
/* If nonzero, make sure first content char in a line is on a tab stop. */
Packit cb4c47
static bool align_tabs;
Packit cb4c47
Packit cb4c47
/* Print width of line numbers and byte offsets.  Nonzero if ALIGN_TABS.  */
Packit cb4c47
static int offset_width;
Packit cb4c47
Packit cb4c47
/* See below */
Packit cb4c47
struct FL_pair
Packit cb4c47
  {
Packit cb4c47
    char const *filename;
Packit cb4c47
    size_t lineno;
Packit cb4c47
  };
Packit cb4c47
Packit cb4c47
/* A list of lineno,filename pairs corresponding to -f FILENAME
Packit cb4c47
   arguments. Since we store the concatenation of all patterns in
Packit cb4c47
   a single array, KEYS, be they from the command line via "-e PAT"
Packit cb4c47
   or read from one or more -f-specified FILENAMES.  Given this
Packit cb4c47
   invocation, grep -f <(seq 5) -f <(seq 2) -f <(seq 3) FILE, there
Packit cb4c47
   will be three entries in LF_PAIR: {1, x} {6, y} {8, z}, where
Packit cb4c47
   x, y and z are just place-holders for shell-generated names.  */
Packit cb4c47
static struct FL_pair *fl_pair;
Packit cb4c47
static size_t n_fl_pair_slots;
Packit cb4c47
/* Count not only -f-specified files, but also individual -e operands
Packit cb4c47
   and any command-line argument that serves as a regular expression.  */
Packit cb4c47
static size_t n_pattern_files;
Packit cb4c47
Packit cb4c47
/* The number of patterns seen so far.
Packit cb4c47
   It is advanced by fl_add and, when needed, used in pattern_file_name
Packit cb4c47
   to derive a file-relative line number.  */
Packit cb4c47
static size_t n_patterns;
Packit cb4c47
Packit cb4c47
/* Return the number of newline bytes in BUF with size SIZE.  */
Packit cb4c47
static size_t _GL_ATTRIBUTE_PURE
Packit cb4c47
count_nl_bytes (char const *buf, size_t size)
Packit cb4c47
{
Packit cb4c47
  char const *p = buf;
Packit cb4c47
  char const *end_p = buf + size;
Packit cb4c47
  size_t n = 0;
Packit cb4c47
  while ((p = memchr (p, '\n', end_p - p)))
Packit cb4c47
    p++, n++;
Packit cb4c47
  return n;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Append a FILENAME,line-number pair to FL_PAIR, and update
Packit cb4c47
   pattern-related counts from the contents of BUF with SIZE bytes.  */
Packit cb4c47
static void
Packit cb4c47
fl_add (char const *buf, size_t size, char const *filename)
Packit cb4c47
{
Packit cb4c47
  if (n_fl_pair_slots <= n_pattern_files)
Packit cb4c47
    fl_pair = x2nrealloc (fl_pair, &n_fl_pair_slots, sizeof *fl_pair);
Packit cb4c47
Packit cb4c47
  fl_pair[n_pattern_files].lineno = n_patterns + 1;
Packit cb4c47
  fl_pair[n_pattern_files].filename = filename;
Packit cb4c47
  n_pattern_files++;
Packit cb4c47
  n_patterns += count_nl_bytes (buf, size);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Map the line number, LINENO, of one of the input patterns to the
Packit cb4c47
   name of the file from which it came.  If it was read from stdin
Packit cb4c47
   or if it was specified on the command line, return "-".  */
Packit cb4c47
char const * _GL_ATTRIBUTE_PURE
Packit cb4c47
pattern_file_name (size_t lineno, size_t *new_lineno)
Packit cb4c47
{
Packit cb4c47
  size_t i;
Packit cb4c47
  for (i = 1; i < n_pattern_files; i++)
Packit cb4c47
    {
Packit cb4c47
      if (lineno < fl_pair[i].lineno)
Packit cb4c47
        break;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  *new_lineno = lineno - fl_pair[i - 1].lineno + 1;
Packit cb4c47
  return fl_pair[i - 1].filename;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
#if HAVE_ASAN
Packit cb4c47
/* Record the starting address and length of the sole poisoned region,
Packit cb4c47
   so that we can unpoison it later, just before each following read.  */
Packit cb4c47
static void const *poison_buf;
Packit cb4c47
static size_t poison_len;
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
clear_asan_poison (void)
Packit cb4c47
{
Packit cb4c47
  if (poison_buf)
Packit cb4c47
    __asan_unpoison_memory_region (poison_buf, poison_len);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
asan_poison (void const *addr, size_t size)
Packit cb4c47
{
Packit cb4c47
  poison_buf = addr;
Packit cb4c47
  poison_len = size;
Packit cb4c47
Packit cb4c47
  __asan_poison_memory_region (poison_buf, poison_len);
Packit cb4c47
}
Packit cb4c47
#else
Packit cb4c47
static void clear_asan_poison (void) { }
Packit cb4c47
static void asan_poison (void const volatile *addr, size_t size) { }
Packit cb4c47
#endif
Packit cb4c47
Packit cb4c47
/* The group separator used when context is requested. */
Packit cb4c47
static const char *group_separator = SEP_STR_GROUP;
Packit cb4c47
Packit cb4c47
/* The context and logic for choosing default --color screen attributes
Packit cb4c47
   (foreground and background colors, etc.) are the following.
Packit cb4c47
      -- There are eight basic colors available, each with its own
Packit cb4c47
         nominal luminosity to the human eye and foreground/background
Packit cb4c47
         codes (black [0 %, 30/40], blue [11 %, 34/44], red [30 %, 31/41],
Packit cb4c47
         magenta [41 %, 35/45], green [59 %, 32/42], cyan [70 %, 36/46],
Packit cb4c47
         yellow [89 %, 33/43], and white [100 %, 37/47]).
Packit cb4c47
      -- Sometimes, white as a background is actually implemented using
Packit cb4c47
         a shade of light gray, so that a foreground white can be visible
Packit cb4c47
         on top of it (but most often not).
Packit cb4c47
      -- Sometimes, black as a foreground is actually implemented using
Packit cb4c47
         a shade of dark gray, so that it can be visible on top of a
Packit cb4c47
         background black (but most often not).
Packit cb4c47
      -- Sometimes, more colors are available, as extensions.
Packit cb4c47
      -- Other attributes can be selected/deselected (bold [1/22],
Packit cb4c47
         underline [4/24], standout/inverse [7/27], blink [5/25], and
Packit cb4c47
         invisible/hidden [8/28]).  They are sometimes implemented by
Packit cb4c47
         using colors instead of what their names imply; e.g., bold is
Packit cb4c47
         often achieved by using brighter colors.  In practice, only bold
Packit cb4c47
         is really available to us, underline sometimes being mapped by
Packit cb4c47
         the terminal to some strange color choice, and standout best
Packit cb4c47
         being left for use by downstream programs such as less(1).
Packit cb4c47
      -- We cannot assume that any of the extensions or special features
Packit cb4c47
         are available for the purpose of choosing defaults for everyone.
Packit cb4c47
      -- The most prevalent default terminal backgrounds are pure black
Packit cb4c47
         and pure white, and are not necessarily the same shades of
Packit cb4c47
         those as if they were selected explicitly with SGR sequences.
Packit cb4c47
         Some terminals use dark or light pictures as default background,
Packit cb4c47
         but those are covered over by an explicit selection of background
Packit cb4c47
         color with an SGR sequence; their users will appreciate their
Packit cb4c47
         background pictures not be covered like this, if possible.
Packit cb4c47
      -- Some uses of colors attributes is to make some output items
Packit cb4c47
         more understated (e.g., context lines); this cannot be achieved
Packit cb4c47
         by changing the background color.
Packit cb4c47
      -- For these reasons, the grep color defaults should strive not
Packit cb4c47
         to change the background color from its default, unless it's
Packit cb4c47
         for a short item that should be highlighted, not understated.
Packit cb4c47
      -- The grep foreground color defaults (without an explicitly set
Packit cb4c47
         background) should provide enough contrast to be readable on any
Packit cb4c47
         terminal with either a black (dark) or white (light) background.
Packit cb4c47
         This only leaves red, magenta, green, and cyan (and their bold
Packit cb4c47
         counterparts) and possibly bold blue.  */
Packit cb4c47
/* The color strings used for matched text.
Packit cb4c47
   The user can overwrite them using the deprecated
Packit cb4c47
   environment variable GREP_COLOR or the new GREP_COLORS.  */
Packit cb4c47
static const char *selected_match_color = "01;31";	/* bold red */
Packit cb4c47
static const char *context_match_color  = "01;31";	/* bold red */
Packit cb4c47
Packit cb4c47
/* Other colors.  Defaults look damn good.  */
Packit cb4c47
static const char *filename_color = "35";	/* magenta */
Packit cb4c47
static const char *line_num_color = "32";	/* green */
Packit cb4c47
static const char *byte_num_color = "32";	/* green */
Packit cb4c47
static const char *sep_color      = "36";	/* cyan */
Packit cb4c47
static const char *selected_line_color = "";	/* default color pair */
Packit cb4c47
static const char *context_line_color  = "";	/* default color pair */
Packit cb4c47
Packit cb4c47
/* Select Graphic Rendition (SGR, "\33[...m") strings.  */
Packit cb4c47
/* Also Erase in Line (EL) to Right ("\33[K") by default.  */
Packit cb4c47
/*    Why have EL to Right after SGR?
Packit cb4c47
         -- The behavior of line-wrapping when at the bottom of the
Packit cb4c47
            terminal screen and at the end of the current line is often
Packit cb4c47
            such that a new line is introduced, entirely cleared with
Packit cb4c47
            the current background color which may be different from the
Packit cb4c47
            default one (see the boolean back_color_erase terminfo(5)
Packit cb4c47
            capability), thus scrolling the display by one line.
Packit cb4c47
            The end of this new line will stay in this background color
Packit cb4c47
            even after reverting to the default background color with
Packit cb4c47
            "\33[m', unless it is explicitly cleared again with "\33[K"
Packit cb4c47
            (which is the behavior the user would instinctively expect
Packit cb4c47
            from the whole thing).  There may be some unavoidable
Packit cb4c47
            background-color flicker at the end of this new line because
Packit cb4c47
            of this (when timing with the monitor's redraw is just right).
Packit cb4c47
         -- The behavior of HT (tab, "\t") is usually the same as that of
Packit cb4c47
            Cursor Forward Tabulation (CHT) with a default parameter
Packit cb4c47
            of 1 ("\33[I"), i.e., it performs pure movement to the next
Packit cb4c47
            tab stop, without any clearing of either content or screen
Packit cb4c47
            attributes (including background color); try
Packit cb4c47
               printf 'asdfqwerzxcv\rASDF\tZXCV\n'
Packit cb4c47
            in a bash(1) shell to demonstrate this.  This is not what the
Packit cb4c47
            user would instinctively expect of HT (but is ok for CHT).
Packit cb4c47
            The instinctive behavior would include clearing the terminal
Packit cb4c47
            cells that are skipped over by HT with blank cells in the
Packit cb4c47
            current screen attributes, including background color;
Packit cb4c47
            the boolean dest_tabs_magic_smso terminfo(5) capability
Packit cb4c47
            indicates this saner behavior for HT, but only some rare
Packit cb4c47
            terminals have it (although it also indicates a special
Packit cb4c47
            glitch with standout mode in the Teleray terminal for which
Packit cb4c47
            it was initially introduced).  The remedy is to add "\33K"
Packit cb4c47
            after each SGR sequence, be it START (to fix the behavior
Packit cb4c47
            of any HT after that before another SGR) or END (to fix the
Packit cb4c47
            behavior of an HT in default background color that would
Packit cb4c47
            follow a line-wrapping at the bottom of the screen in another
Packit cb4c47
            background color, and to complement doing it after START).
Packit cb4c47
            Piping grep's output through a pager such as less(1) avoids
Packit cb4c47
            any HT problems since the pager performs tab expansion.
Packit cb4c47
Packit cb4c47
      Generic disadvantages of this remedy are:
Packit cb4c47
         -- Some very rare terminals might support SGR but not EL (nobody
Packit cb4c47
            will use "grep --color" on a terminal that does not support
Packit cb4c47
            SGR in the first place).
Packit cb4c47
         -- Having these extra control sequences might somewhat complicate
Packit cb4c47
            the task of any program trying to parse "grep --color"
Packit cb4c47
            output in order to extract structuring information from it.
Packit cb4c47
      A specific disadvantage to doing it after SGR START is:
Packit cb4c47
         -- Even more possible background color flicker (when timing
Packit cb4c47
            with the monitor's redraw is just right), even when not at the
Packit cb4c47
            bottom of the screen.
Packit cb4c47
      There are no additional disadvantages specific to doing it after
Packit cb4c47
      SGR END.
Packit cb4c47
Packit cb4c47
      It would be impractical for GNU grep to become a full-fledged
Packit cb4c47
      terminal program linked against ncurses or the like, so it will
Packit cb4c47
      not detect terminfo(5) capabilities.  */
Packit cb4c47
static const char *sgr_start = "\33[%sm\33[K";
Packit cb4c47
static const char *sgr_end   = "\33[m\33[K";
Packit cb4c47
Packit cb4c47
/* SGR utility functions.  */
Packit cb4c47
static void
Packit cb4c47
pr_sgr_start (char const *s)
Packit cb4c47
{
Packit cb4c47
  if (*s)
Packit cb4c47
    print_start_colorize (sgr_start, s);
Packit cb4c47
}
Packit cb4c47
static void
Packit cb4c47
pr_sgr_end (char const *s)
Packit cb4c47
{
Packit cb4c47
  if (*s)
Packit cb4c47
    print_end_colorize (sgr_end);
Packit cb4c47
}
Packit cb4c47
static void
Packit cb4c47
pr_sgr_start_if (char const *s)
Packit cb4c47
{
Packit cb4c47
  if (color_option)
Packit cb4c47
    pr_sgr_start (s);
Packit cb4c47
}
Packit cb4c47
static void
Packit cb4c47
pr_sgr_end_if (char const *s)
Packit cb4c47
{
Packit cb4c47
  if (color_option)
Packit cb4c47
    pr_sgr_end (s);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
struct color_cap
Packit cb4c47
  {
Packit cb4c47
    const char *name;
Packit cb4c47
    const char **var;
Packit cb4c47
    void (*fct) (void);
Packit cb4c47
  };
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
color_cap_mt_fct (void)
Packit cb4c47
{
Packit cb4c47
  /* Our caller just set selected_match_color.  */
Packit cb4c47
  context_match_color = selected_match_color;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
color_cap_rv_fct (void)
Packit cb4c47
{
Packit cb4c47
  /* By this point, it was 1 (or already -1).  */
Packit cb4c47
  color_option = -1;  /* That's still != 0.  */
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
color_cap_ne_fct (void)
Packit cb4c47
{
Packit cb4c47
  sgr_start = "\33[%sm";
Packit cb4c47
  sgr_end   = "\33[m";
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* For GREP_COLORS.  */
Packit cb4c47
static const struct color_cap color_dict[] =
Packit cb4c47
  {
Packit cb4c47
    { "mt", &selected_match_color, color_cap_mt_fct }, /* both ms/mc */
Packit cb4c47
    { "ms", &selected_match_color, NULL }, /* selected matched text */
Packit cb4c47
    { "mc", &context_match_color,  NULL }, /* context matched text */
Packit cb4c47
    { "fn", &filename_color,       NULL }, /* filename */
Packit cb4c47
    { "ln", &line_num_color,       NULL }, /* line number */
Packit cb4c47
    { "bn", &byte_num_color,       NULL }, /* byte (sic) offset */
Packit cb4c47
    { "se", &sep_color,            NULL }, /* separator */
Packit cb4c47
    { "sl", &selected_line_color,  NULL }, /* selected lines */
Packit cb4c47
    { "cx", &context_line_color,   NULL }, /* context lines */
Packit cb4c47
    { "rv", NULL,                  color_cap_rv_fct }, /* -v reverses sl/cx */
Packit cb4c47
    { "ne", NULL,                  color_cap_ne_fct }, /* no EL on SGR_* */
Packit cb4c47
    { NULL, NULL,                  NULL }
Packit cb4c47
  };
Packit cb4c47
Packit cb4c47
/* Saved errno value from failed output functions on stdout.  */
Packit cb4c47
static int stdout_errno;
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
putchar_errno (int c)
Packit cb4c47
{
Packit cb4c47
  if (putchar (c) < 0)
Packit cb4c47
    stdout_errno = errno;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
fputs_errno (char const *s)
Packit cb4c47
{
Packit cb4c47
  if (fputs (s, stdout) < 0)
Packit cb4c47
    stdout_errno = errno;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void _GL_ATTRIBUTE_FORMAT_PRINTF (1, 2)
Packit cb4c47
printf_errno (char const *format, ...)
Packit cb4c47
{
Packit cb4c47
  va_list ap;
Packit cb4c47
  va_start (ap, format);
Packit cb4c47
  if (vfprintf (stdout, format, ap) < 0)
Packit cb4c47
    stdout_errno = errno;
Packit cb4c47
  va_end (ap);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
fwrite_errno (void const *ptr, size_t size, size_t nmemb)
Packit cb4c47
{
Packit cb4c47
  if (fwrite (ptr, size, nmemb, stdout) != nmemb)
Packit cb4c47
    stdout_errno = errno;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
fflush_errno (void)
Packit cb4c47
{
Packit cb4c47
  if (fflush (stdout) != 0)
Packit cb4c47
    stdout_errno = errno;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static struct exclude *excluded_patterns[2];
Packit cb4c47
static struct exclude *excluded_directory_patterns[2];
Packit cb4c47
/* Short options.  */
Packit cb4c47
static char const short_options[] =
Packit cb4c47
"0123456789A:B:C:D:EFGHIPTUVX:abcd:e:f:hiLlm:noqRrsuvwxyZz";
Packit cb4c47
Packit cb4c47
/* Non-boolean long options that have no corresponding short equivalents.  */
Packit cb4c47
enum
Packit cb4c47
{
Packit cb4c47
  BINARY_FILES_OPTION = CHAR_MAX + 1,
Packit cb4c47
  COLOR_OPTION,
Packit cb4c47
  EXCLUDE_DIRECTORY_OPTION,
Packit cb4c47
  EXCLUDE_OPTION,
Packit cb4c47
  EXCLUDE_FROM_OPTION,
Packit cb4c47
  GROUP_SEPARATOR_OPTION,
Packit cb4c47
  INCLUDE_OPTION,
Packit cb4c47
  LINE_BUFFERED_OPTION,
Packit cb4c47
  LABEL_OPTION
Packit cb4c47
};
Packit cb4c47
Packit cb4c47
/* Long options equivalences. */
Packit cb4c47
static struct option const long_options[] =
Packit cb4c47
{
Packit cb4c47
  {"basic-regexp",    no_argument, NULL, 'G'},
Packit cb4c47
  {"extended-regexp", no_argument, NULL, 'E'},
Packit cb4c47
  {"fixed-regexp",    no_argument, NULL, 'F'},
Packit cb4c47
  {"fixed-strings",   no_argument, NULL, 'F'},
Packit cb4c47
  {"perl-regexp",     no_argument, NULL, 'P'},
Packit cb4c47
  {"after-context", required_argument, NULL, 'A'},
Packit cb4c47
  {"before-context", required_argument, NULL, 'B'},
Packit cb4c47
  {"binary-files", required_argument, NULL, BINARY_FILES_OPTION},
Packit cb4c47
  {"byte-offset", no_argument, NULL, 'b'},
Packit cb4c47
  {"context", required_argument, NULL, 'C'},
Packit cb4c47
  {"color", optional_argument, NULL, COLOR_OPTION},
Packit cb4c47
  {"colour", optional_argument, NULL, COLOR_OPTION},
Packit cb4c47
  {"count", no_argument, NULL, 'c'},
Packit cb4c47
  {"devices", required_argument, NULL, 'D'},
Packit cb4c47
  {"directories", required_argument, NULL, 'd'},
Packit cb4c47
  {"exclude", required_argument, NULL, EXCLUDE_OPTION},
Packit cb4c47
  {"exclude-from", required_argument, NULL, EXCLUDE_FROM_OPTION},
Packit cb4c47
  {"exclude-dir", required_argument, NULL, EXCLUDE_DIRECTORY_OPTION},
Packit cb4c47
  {"file", required_argument, NULL, 'f'},
Packit cb4c47
  {"files-with-matches", no_argument, NULL, 'l'},
Packit cb4c47
  {"files-without-match", no_argument, NULL, 'L'},
Packit cb4c47
  {"group-separator", required_argument, NULL, GROUP_SEPARATOR_OPTION},
Packit cb4c47
  {"help", no_argument, &show_help, 1},
Packit cb4c47
  {"include", required_argument, NULL, INCLUDE_OPTION},
Packit cb4c47
  {"ignore-case", no_argument, NULL, 'i'},
Packit cb4c47
  {"initial-tab", no_argument, NULL, 'T'},
Packit cb4c47
  {"label", required_argument, NULL, LABEL_OPTION},
Packit cb4c47
  {"line-buffered", no_argument, NULL, LINE_BUFFERED_OPTION},
Packit cb4c47
  {"line-number", no_argument, NULL, 'n'},
Packit cb4c47
  {"line-regexp", no_argument, NULL, 'x'},
Packit cb4c47
  {"max-count", required_argument, NULL, 'm'},
Packit cb4c47
Packit cb4c47
  {"no-filename", no_argument, NULL, 'h'},
Packit cb4c47
  {"no-group-separator", no_argument, NULL, GROUP_SEPARATOR_OPTION},
Packit cb4c47
  {"no-messages", no_argument, NULL, 's'},
Packit cb4c47
  {"null", no_argument, NULL, 'Z'},
Packit cb4c47
  {"null-data", no_argument, NULL, 'z'},
Packit cb4c47
  {"only-matching", no_argument, NULL, 'o'},
Packit cb4c47
  {"quiet", no_argument, NULL, 'q'},
Packit cb4c47
  {"recursive", no_argument, NULL, 'r'},
Packit cb4c47
  {"dereference-recursive", no_argument, NULL, 'R'},
Packit cb4c47
  {"regexp", required_argument, NULL, 'e'},
Packit cb4c47
  {"invert-match", no_argument, NULL, 'v'},
Packit cb4c47
  {"silent", no_argument, NULL, 'q'},
Packit cb4c47
  {"text", no_argument, NULL, 'a'},
Packit cb4c47
  {"binary", no_argument, NULL, 'U'},
Packit cb4c47
  {"unix-byte-offsets", no_argument, NULL, 'u'},
Packit cb4c47
  {"version", no_argument, NULL, 'V'},
Packit cb4c47
  {"with-filename", no_argument, NULL, 'H'},
Packit cb4c47
  {"word-regexp", no_argument, NULL, 'w'},
Packit cb4c47
  {0, 0, 0, 0}
Packit cb4c47
};
Packit cb4c47
Packit cb4c47
/* Define flags declared in grep.h. */
Packit cb4c47
bool match_icase;
Packit cb4c47
bool match_words;
Packit cb4c47
bool match_lines;
Packit cb4c47
char eolbyte;
Packit cb4c47
Packit cb4c47
/* For error messages. */
Packit cb4c47
/* The input file name, or (if standard input) null or a --label argument.  */
Packit cb4c47
static char const *filename;
Packit cb4c47
/* Omit leading "./" from file names in diagnostics.  */
Packit cb4c47
static bool omit_dot_slash;
Packit cb4c47
static bool errseen;
Packit cb4c47
Packit cb4c47
/* True if output from the current input file has been suppressed
Packit cb4c47
   because an output line had an encoding error.  */
Packit cb4c47
static bool encoding_error_output;
Packit cb4c47
Packit cb4c47
enum directories_type
Packit cb4c47
  {
Packit cb4c47
    READ_DIRECTORIES = 2,
Packit cb4c47
    RECURSE_DIRECTORIES,
Packit cb4c47
    SKIP_DIRECTORIES
Packit cb4c47
  };
Packit cb4c47
Packit cb4c47
/* How to handle directories.  */
Packit cb4c47
static char const *const directories_args[] =
Packit cb4c47
{
Packit cb4c47
  "read", "recurse", "skip", NULL
Packit cb4c47
};
Packit cb4c47
static enum directories_type const directories_types[] =
Packit cb4c47
{
Packit cb4c47
  READ_DIRECTORIES, RECURSE_DIRECTORIES, SKIP_DIRECTORIES
Packit cb4c47
};
Packit cb4c47
ARGMATCH_VERIFY (directories_args, directories_types);
Packit cb4c47
Packit cb4c47
static enum directories_type directories = READ_DIRECTORIES;
Packit cb4c47
Packit cb4c47
enum { basic_fts_options = FTS_CWDFD | FTS_NOSTAT | FTS_TIGHT_CYCLE_CHECK };
Packit cb4c47
static int fts_options = basic_fts_options | FTS_COMFOLLOW | FTS_PHYSICAL;
Packit cb4c47
Packit cb4c47
/* How to handle devices. */
Packit cb4c47
static enum
Packit cb4c47
  {
Packit cb4c47
    READ_COMMAND_LINE_DEVICES,
Packit cb4c47
    READ_DEVICES,
Packit cb4c47
    SKIP_DEVICES
Packit cb4c47
  } devices = READ_COMMAND_LINE_DEVICES;
Packit cb4c47
Packit cb4c47
static bool grepfile (int, char const *, bool, bool);
Packit cb4c47
static bool grepdesc (int, bool);
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
is_device_mode (mode_t m)
Packit cb4c47
{
Packit cb4c47
  return S_ISCHR (m) || S_ISBLK (m) || S_ISSOCK (m) || S_ISFIFO (m);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
skip_devices (bool command_line)
Packit cb4c47
{
Packit cb4c47
  return (devices == SKIP_DEVICES
Packit cb4c47
          || ((devices == READ_COMMAND_LINE_DEVICES) & !command_line));
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return if ST->st_size is defined.  Assume the file is not a
Packit cb4c47
   symbolic link.  */
Packit cb4c47
static bool
Packit cb4c47
usable_st_size (struct stat const *st)
Packit cb4c47
{
Packit cb4c47
  return S_ISREG (st->st_mode) || S_TYPEISSHM (st) || S_TYPEISTMO (st);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Lame substitutes for SEEK_DATA and SEEK_HOLE on platforms lacking them.
Packit cb4c47
   Do not rely on these finding data or holes if they equal SEEK_SET.  */
Packit cb4c47
#ifndef SEEK_DATA
Packit cb4c47
enum { SEEK_DATA = SEEK_SET };
Packit cb4c47
#endif
Packit cb4c47
#ifndef SEEK_HOLE
Packit cb4c47
enum { SEEK_HOLE = SEEK_SET };
Packit cb4c47
#endif
Packit cb4c47
Packit cb4c47
/* True if lseek with SEEK_CUR or SEEK_DATA failed on the current input.  */
Packit cb4c47
static bool seek_failed;
Packit cb4c47
static bool seek_data_failed;
Packit cb4c47
Packit cb4c47
/* Functions we'll use to search. */
Packit cb4c47
typedef void *(*compile_fp_t) (char *, size_t, reg_syntax_t);
Packit cb4c47
typedef size_t (*execute_fp_t) (void *, char const *, size_t, size_t *,
Packit cb4c47
                                char const *);
Packit cb4c47
static execute_fp_t execute;
Packit cb4c47
static void *compiled_pattern;
Packit cb4c47
Packit cb4c47
static char const *
Packit cb4c47
input_filename (void)
Packit cb4c47
{
Packit cb4c47
  if (!filename)
Packit cb4c47
    filename = _("(standard input)");
Packit cb4c47
  return filename;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Unless requested, diagnose an error about the input file.  */
Packit cb4c47
static void
Packit cb4c47
suppressible_error (int errnum)
Packit cb4c47
{
Packit cb4c47
  if (! suppress_errors)
Packit cb4c47
    error (0, errnum, "%s", input_filename ());
Packit cb4c47
  errseen = true;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* If there has already been a write error, don't bother closing
Packit cb4c47
   standard output, as that might elicit a duplicate diagnostic.  */
Packit cb4c47
static void
Packit cb4c47
clean_up_stdout (void)
Packit cb4c47
{
Packit cb4c47
  if (! stdout_errno)
Packit cb4c47
    close_stdout ();
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* A cast to TYPE of VAL.  Use this when TYPE is a pointer type, VAL
Packit cb4c47
   is properly aligned for TYPE, and 'gcc -Wcast-align' cannot infer
Packit cb4c47
   the alignment and would otherwise complain about the cast.  */
Packit cb4c47
#if 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
Packit cb4c47
# define CAST_ALIGNED(type, val)                           \
Packit cb4c47
    ({ __typeof__ (val) val_ = val;                        \
Packit cb4c47
       _Pragma ("GCC diagnostic push")                     \
Packit cb4c47
       _Pragma ("GCC diagnostic ignored \"-Wcast-align\"") \
Packit cb4c47
       (type) val_;                                        \
Packit cb4c47
       _Pragma ("GCC diagnostic pop")                      \
Packit cb4c47
    })
Packit cb4c47
#else
Packit cb4c47
# define CAST_ALIGNED(type, val) ((type) (val))
Packit cb4c47
#endif
Packit cb4c47
Packit cb4c47
/* An unsigned type suitable for fast matching.  */
Packit cb4c47
typedef uintmax_t uword;
Packit cb4c47
Packit cb4c47
struct localeinfo localeinfo;
Packit cb4c47
Packit cb4c47
/* A mask to test for unibyte characters, with the pattern repeated to
Packit cb4c47
   fill a uword.  For a multibyte character encoding where
Packit cb4c47
   all bytes are unibyte characters, this is 0.  For UTF-8, this is
Packit cb4c47
   0x808080....  For encodings where unibyte characters have no discerned
Packit cb4c47
   pattern, this is all 1s.  The unsigned char C is a unibyte
Packit cb4c47
   character if C & UNIBYTE_MASK is zero.  If the uword W is the
Packit cb4c47
   concatenation of bytes, the bytes are all unibyte characters
Packit cb4c47
   if W & UNIBYTE_MASK is zero.  */
Packit cb4c47
static uword unibyte_mask;
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
initialize_unibyte_mask (void)
Packit cb4c47
{
Packit cb4c47
  /* For each encoding error I that MASK does not already match,
Packit cb4c47
     accumulate I's most significant 1 bit by ORing it into MASK.
Packit cb4c47
     Although any 1 bit of I could be used, in practice high-order
Packit cb4c47
     bits work better.  */
Packit cb4c47
  unsigned char mask = 0;
Packit cb4c47
  int ms1b = 1;
Packit cb4c47
  for (int i = 1; i <= UCHAR_MAX; i++)
Packit cb4c47
    if ((localeinfo.sbclen[i] != 1) & ! (mask & i))
Packit cb4c47
      {
Packit cb4c47
        while (ms1b * 2 <= i)
Packit cb4c47
          ms1b *= 2;
Packit cb4c47
        mask |= ms1b;
Packit cb4c47
      }
Packit cb4c47
Packit cb4c47
  /* Now MASK will detect any encoding-error byte, although it may
Packit cb4c47
     cry wolf and it may not be optimal.  Build a uword-length mask by
Packit cb4c47
     repeating MASK.  */
Packit cb4c47
  uword uword_max = -1;
Packit cb4c47
  unibyte_mask = uword_max / UCHAR_MAX * mask;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Skip the easy bytes in a buffer that is guaranteed to have a sentinel
Packit cb4c47
   that is not easy, and return a pointer to the first non-easy byte.
Packit cb4c47
   The easy bytes all have UNIBYTE_MASK off.  */
Packit cb4c47
static char const * _GL_ATTRIBUTE_PURE
Packit cb4c47
skip_easy_bytes (char const *buf)
Packit cb4c47
{
Packit cb4c47
  /* Search a byte at a time until the pointer is aligned, then a
Packit cb4c47
     uword at a time until a match is found, then a byte at a time to
Packit cb4c47
     identify the exact byte.  The uword search may go slightly past
Packit cb4c47
     the buffer end, but that's benign.  */
Packit cb4c47
  char const *p;
Packit cb4c47
  uword const *s;
Packit cb4c47
  for (p = buf; (uintptr_t) p % sizeof (uword) != 0; p++)
Packit cb4c47
    if (to_uchar (*p) & unibyte_mask)
Packit cb4c47
      return p;
Packit cb4c47
  for (s = CAST_ALIGNED (uword const *, p); ! (*s & unibyte_mask); s++)
Packit cb4c47
    continue;
Packit cb4c47
  for (p = (char const *) s; ! (to_uchar (*p) & unibyte_mask); p++)
Packit cb4c47
    continue;
Packit cb4c47
  return p;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return true if BUF, of size SIZE, has an encoding error.
Packit cb4c47
   BUF must be followed by at least sizeof (uword) bytes,
Packit cb4c47
   the first of which may be modified.  */
Packit cb4c47
static bool
Packit cb4c47
buf_has_encoding_errors (char *buf, size_t size)
Packit cb4c47
{
Packit cb4c47
  if (! unibyte_mask)
Packit cb4c47
    return false;
Packit cb4c47
Packit cb4c47
  mbstate_t mbs = { 0 };
Packit cb4c47
  size_t clen;
Packit cb4c47
Packit cb4c47
  buf[size] = -1;
Packit cb4c47
  for (char const *p = buf; (p = skip_easy_bytes (p)) < buf + size; p += clen)
Packit cb4c47
    {
Packit cb4c47
      clen = mbrlen (p, buf + size - p, &mbs);
Packit cb4c47
      if ((size_t) -2 <= clen)
Packit cb4c47
        return true;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return false;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
Packit cb4c47
/* Return true if BUF, of size SIZE, has a null byte.
Packit cb4c47
   BUF must be followed by at least one byte,
Packit cb4c47
   which may be arbitrarily written to or read from.  */
Packit cb4c47
static bool
Packit cb4c47
buf_has_nulls (char *buf, size_t size)
Packit cb4c47
{
Packit cb4c47
  buf[size] = 0;
Packit cb4c47
  return strlen (buf) != size;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return true if a file is known to contain null bytes.
Packit cb4c47
   SIZE bytes have already been read from the file
Packit cb4c47
   with descriptor FD and status ST.  */
Packit cb4c47
static bool
Packit cb4c47
file_must_have_nulls (size_t size, int fd, struct stat const *st)
Packit cb4c47
{
Packit cb4c47
  /* If the file has holes, it must contain a null byte somewhere.  */
Packit cb4c47
  if (SEEK_HOLE != SEEK_SET && !seek_failed
Packit cb4c47
      && usable_st_size (st) && size < st->st_size)
Packit cb4c47
    {
Packit cb4c47
      off_t cur = size;
Packit cb4c47
      if (O_BINARY || fd == STDIN_FILENO)
Packit cb4c47
        {
Packit cb4c47
          cur = lseek (fd, 0, SEEK_CUR);
Packit cb4c47
          if (cur < 0)
Packit cb4c47
            return false;
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      /* Look for a hole after the current location.  */
Packit cb4c47
      off_t hole_start = lseek (fd, cur, SEEK_HOLE);
Packit cb4c47
      if (0 <= hole_start)
Packit cb4c47
        {
Packit cb4c47
          if (lseek (fd, cur, SEEK_SET) < 0)
Packit cb4c47
            suppressible_error (errno);
Packit cb4c47
          if (hole_start < st->st_size)
Packit cb4c47
            return true;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return false;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Convert STR to a nonnegative integer, storing the result in *OUT.
Packit cb4c47
   STR must be a valid context length argument; report an error if it
Packit cb4c47
   isn't.  Silently ceiling *OUT at the maximum value, as that is
Packit cb4c47
   practically equivalent to infinity for grep's purposes.  */
Packit cb4c47
static void
Packit cb4c47
context_length_arg (char const *str, intmax_t *out)
Packit cb4c47
{
Packit cb4c47
  switch (xstrtoimax (str, 0, 10, out, ""))
Packit cb4c47
    {
Packit cb4c47
    case LONGINT_OK:
Packit cb4c47
    case LONGINT_OVERFLOW:
Packit cb4c47
      if (0 <= *out)
Packit cb4c47
        break;
Packit cb4c47
      FALLTHROUGH;
Packit cb4c47
    default:
Packit cb4c47
      die (EXIT_TROUBLE, 0, "%s: %s", str,
Packit cb4c47
           _("invalid context length argument"));
Packit cb4c47
    }
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return the add_exclude options suitable for excluding a file name.
Packit cb4c47
   If COMMAND_LINE, it is a command-line file name.  */
Packit cb4c47
static int
Packit cb4c47
exclude_options (bool command_line)
Packit cb4c47
{
Packit cb4c47
  return EXCLUDE_WILDCARDS | (command_line ? 0 : EXCLUDE_ANCHORED);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return true if the file with NAME should be skipped.
Packit cb4c47
   If COMMAND_LINE, it is a command-line argument.
Packit cb4c47
   If IS_DIR, it is a directory.  */
Packit cb4c47
static bool
Packit cb4c47
skipped_file (char const *name, bool command_line, bool is_dir)
Packit cb4c47
{
Packit cb4c47
  struct exclude **pats;
Packit cb4c47
  if (! is_dir)
Packit cb4c47
    pats = excluded_patterns;
Packit cb4c47
  else if (directories == SKIP_DIRECTORIES)
Packit cb4c47
    return true;
Packit cb4c47
  else if (command_line && omit_dot_slash)
Packit cb4c47
    return false;
Packit cb4c47
  else
Packit cb4c47
    pats = excluded_directory_patterns;
Packit cb4c47
  return pats[command_line] && excluded_file_name (pats[command_line], name);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Hairy buffering mechanism for grep.  The intent is to keep
Packit cb4c47
   all reads aligned on a page boundary and multiples of the
Packit cb4c47
   page size, unless a read yields a partial page.  */
Packit cb4c47
Packit cb4c47
static char *buffer;		/* Base of buffer. */
Packit cb4c47
static size_t bufalloc;		/* Allocated buffer size, counting slop. */
Packit cb4c47
enum { INITIAL_BUFSIZE = 32768 }; /* Initial buffer size, not counting slop. */
Packit cb4c47
static int bufdesc;		/* File descriptor. */
Packit cb4c47
static char *bufbeg;		/* Beginning of user-visible stuff. */
Packit cb4c47
static char *buflim;		/* Limit of user-visible stuff. */
Packit cb4c47
static size_t pagesize;		/* alignment of memory pages */
Packit cb4c47
static off_t bufoffset;		/* Read offset.  */
Packit cb4c47
static off_t after_last_match;	/* Pointer after last matching line that
Packit cb4c47
                                   would have been output if we were
Packit cb4c47
                                   outputting characters. */
Packit cb4c47
static bool skip_nuls;		/* Skip '\0' in data.  */
Packit cb4c47
static bool skip_empty_lines;	/* Skip empty lines in data.  */
Packit cb4c47
static uintmax_t totalnl;	/* Total newline count before lastnl. */
Packit cb4c47
Packit cb4c47
/* Return VAL aligned to the next multiple of ALIGNMENT.  VAL can be
Packit cb4c47
   an integer or a pointer.  Both args must be free of side effects.  */
Packit cb4c47
#define ALIGN_TO(val, alignment) \
Packit cb4c47
  ((size_t) (val) % (alignment) == 0 \
Packit cb4c47
   ? (val) \
Packit cb4c47
   : (val) + ((alignment) - (size_t) (val) % (alignment)))
Packit cb4c47
Packit cb4c47
/* Add two numbers that count input bytes or lines, and report an
Packit cb4c47
   error if the addition overflows.  */
Packit cb4c47
static uintmax_t
Packit cb4c47
add_count (uintmax_t a, uintmax_t b)
Packit cb4c47
{
Packit cb4c47
  uintmax_t sum = a + b;
Packit cb4c47
  if (sum < a)
Packit cb4c47
    die (EXIT_TROUBLE, 0, _("input is too large to count"));
Packit cb4c47
  return sum;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return true if BUF (of size SIZE) is all zeros.  */
Packit cb4c47
static bool
Packit cb4c47
all_zeros (char const *buf, size_t size)
Packit cb4c47
{
Packit cb4c47
  for (char const *p = buf; p < buf + size; p++)
Packit cb4c47
    if (*p)
Packit cb4c47
      return false;
Packit cb4c47
  return true;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Reset the buffer for a new file, returning false if we should skip it.
Packit cb4c47
   Initialize on the first time through. */
Packit cb4c47
static bool
Packit cb4c47
reset (int fd, struct stat const *st)
Packit cb4c47
{
Packit cb4c47
  bufbeg = buflim = ALIGN_TO (buffer + 1, pagesize);
Packit cb4c47
  bufbeg[-1] = eolbyte;
Packit cb4c47
  bufdesc = fd;
Packit cb4c47
  bufoffset = fd == STDIN_FILENO ? lseek (fd, 0, SEEK_CUR) : 0;
Packit cb4c47
  seek_failed = bufoffset < 0;
Packit cb4c47
Packit cb4c47
  /* Assume SEEK_DATA fails if SEEK_CUR does.  */
Packit cb4c47
  seek_data_failed = seek_failed;
Packit cb4c47
Packit cb4c47
  if (seek_failed)
Packit cb4c47
    {
Packit cb4c47
      if (errno != ESPIPE)
Packit cb4c47
        {
Packit cb4c47
          suppressible_error (errno);
Packit cb4c47
          return false;
Packit cb4c47
        }
Packit cb4c47
      bufoffset = 0;
Packit cb4c47
    }
Packit cb4c47
  return true;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Read new stuff into the buffer, saving the specified
Packit cb4c47
   amount of old stuff.  When we're done, 'bufbeg' points
Packit cb4c47
   to the beginning of the buffer contents, and 'buflim'
Packit cb4c47
   points just after the end.  Return false if there's an error.  */
Packit cb4c47
static bool
Packit cb4c47
fillbuf (size_t save, struct stat const *st)
Packit cb4c47
{
Packit cb4c47
  size_t fillsize;
Packit cb4c47
  bool cc = true;
Packit cb4c47
  char *readbuf;
Packit cb4c47
  size_t readsize;
Packit cb4c47
Packit cb4c47
  /* Offset from start of buffer to start of old stuff
Packit cb4c47
     that we want to save.  */
Packit cb4c47
  size_t saved_offset = buflim - save - buffer;
Packit cb4c47
Packit cb4c47
  if (pagesize <= buffer + bufalloc - sizeof (uword) - buflim)
Packit cb4c47
    {
Packit cb4c47
      readbuf = buflim;
Packit cb4c47
      bufbeg = buflim - save;
Packit cb4c47
    }
Packit cb4c47
  else
Packit cb4c47
    {
Packit cb4c47
      size_t minsize = save + pagesize;
Packit cb4c47
      size_t newsize;
Packit cb4c47
      size_t newalloc;
Packit cb4c47
      char *newbuf;
Packit cb4c47
Packit cb4c47
      /* Grow newsize until it is at least as great as minsize.  */
Packit cb4c47
      for (newsize = bufalloc - pagesize - sizeof (uword);
Packit cb4c47
           newsize < minsize;
Packit cb4c47
           newsize *= 2)
Packit cb4c47
        if ((SIZE_MAX - pagesize - sizeof (uword)) / 2 < newsize)
Packit cb4c47
          xalloc_die ();
Packit cb4c47
Packit cb4c47
      /* Try not to allocate more memory than the file size indicates,
Packit cb4c47
         as that might cause unnecessary memory exhaustion if the file
Packit cb4c47
         is large.  However, do not use the original file size as a
Packit cb4c47
         heuristic if we've already read past the file end, as most
Packit cb4c47
         likely the file is growing.  */
Packit cb4c47
      if (usable_st_size (st))
Packit cb4c47
        {
Packit cb4c47
          off_t to_be_read = st->st_size - bufoffset;
Packit cb4c47
          off_t maxsize_off = save + to_be_read;
Packit cb4c47
          if (0 <= to_be_read && to_be_read <= maxsize_off
Packit cb4c47
              && maxsize_off == (size_t) maxsize_off
Packit cb4c47
              && minsize <= (size_t) maxsize_off
Packit cb4c47
              && (size_t) maxsize_off < newsize)
Packit cb4c47
            newsize = maxsize_off;
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      /* Add enough room so that the buffer is aligned and has room
Packit cb4c47
         for byte sentinels fore and aft, and so that a uword can
Packit cb4c47
         be read aft.  */
Packit cb4c47
      newalloc = newsize + pagesize + sizeof (uword);
Packit cb4c47
Packit cb4c47
      newbuf = bufalloc < newalloc ? xmalloc (bufalloc = newalloc) : buffer;
Packit cb4c47
      readbuf = ALIGN_TO (newbuf + 1 + save, pagesize);
Packit cb4c47
      bufbeg = readbuf - save;
Packit cb4c47
      memmove (bufbeg, buffer + saved_offset, save);
Packit cb4c47
      bufbeg[-1] = eolbyte;
Packit cb4c47
      if (newbuf != buffer)
Packit cb4c47
        {
Packit cb4c47
          free (buffer);
Packit cb4c47
          buffer = newbuf;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  clear_asan_poison ();
Packit cb4c47
Packit cb4c47
  readsize = buffer + bufalloc - sizeof (uword) - readbuf;
Packit cb4c47
  readsize -= readsize % pagesize;
Packit cb4c47
Packit cb4c47
  while (true)
Packit cb4c47
    {
Packit cb4c47
      fillsize = safe_read (bufdesc, readbuf, readsize);
Packit cb4c47
      if (fillsize == SAFE_READ_ERROR)
Packit cb4c47
        {
Packit cb4c47
          fillsize = 0;
Packit cb4c47
          cc = false;
Packit cb4c47
        }
Packit cb4c47
      bufoffset += fillsize;
Packit cb4c47
Packit cb4c47
      if (((fillsize == 0) | !skip_nuls) || !all_zeros (readbuf, fillsize))
Packit cb4c47
        break;
Packit cb4c47
      totalnl = add_count (totalnl, fillsize);
Packit cb4c47
Packit cb4c47
      if (SEEK_DATA != SEEK_SET && !seek_data_failed)
Packit cb4c47
        {
Packit cb4c47
          /* Solaris SEEK_DATA fails with errno == ENXIO in a hole at EOF.  */
Packit cb4c47
          off_t data_start = lseek (bufdesc, bufoffset, SEEK_DATA);
Packit cb4c47
          if (data_start < 0 && errno == ENXIO
Packit cb4c47
              && usable_st_size (st) && bufoffset < st->st_size)
Packit cb4c47
            data_start = lseek (bufdesc, 0, SEEK_END);
Packit cb4c47
Packit cb4c47
          if (data_start < 0)
Packit cb4c47
            seek_data_failed = true;
Packit cb4c47
          else
Packit cb4c47
            {
Packit cb4c47
              totalnl = add_count (totalnl, data_start - bufoffset);
Packit cb4c47
              bufoffset = data_start;
Packit cb4c47
            }
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  buflim = readbuf + fillsize;
Packit cb4c47
Packit cb4c47
  /* Initialize the following word, because skip_easy_bytes and some
Packit cb4c47
     matchers read (but do not use) those bytes.  This avoids false
Packit cb4c47
     positive reports of these bytes being used uninitialized.  */
Packit cb4c47
  memset (buflim, 0, sizeof (uword));
Packit cb4c47
Packit cb4c47
  /* Mark the part of the buffer not filled by the read or set by
Packit cb4c47
     the above memset call as ASAN-poisoned.  */
Packit cb4c47
  asan_poison (buflim + sizeof (uword),
Packit cb4c47
               bufalloc - (buflim - buffer) - sizeof (uword));
Packit cb4c47
Packit cb4c47
  return cc;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Flags controlling the style of output. */
Packit cb4c47
static enum
Packit cb4c47
{
Packit cb4c47
  BINARY_BINARY_FILES,
Packit cb4c47
  TEXT_BINARY_FILES,
Packit cb4c47
  WITHOUT_MATCH_BINARY_FILES
Packit cb4c47
} binary_files;		/* How to handle binary files.  */
Packit cb4c47
Packit cb4c47
/* Options for output as a list of matching/non-matching files */
Packit cb4c47
static enum
Packit cb4c47
{
Packit cb4c47
  LISTFILES_NONE,
Packit cb4c47
  LISTFILES_MATCHING,
Packit cb4c47
  LISTFILES_NONMATCHING,
Packit cb4c47
} list_files;
Packit cb4c47
Packit cb4c47
static int filename_mask;	/* If zero, output nulls after filenames.  */
Packit cb4c47
static bool out_quiet;		/* Suppress all normal output. */
Packit cb4c47
static bool out_invert;		/* Print nonmatching stuff. */
Packit cb4c47
static int out_file;		/* Print filenames. */
Packit cb4c47
static bool out_line;		/* Print line numbers. */
Packit cb4c47
static bool out_byte;		/* Print byte offsets. */
Packit cb4c47
static intmax_t out_before;	/* Lines of leading context. */
Packit cb4c47
static intmax_t out_after;	/* Lines of trailing context. */
Packit cb4c47
static bool count_matches;	/* Count matching lines.  */
Packit cb4c47
static bool no_filenames;	/* Suppress file names.  */
Packit cb4c47
static intmax_t max_count;	/* Max number of selected
Packit cb4c47
                                   lines from an input file.  */
Packit cb4c47
static bool line_buffered;	/* Use line buffering.  */
Packit cb4c47
static char *label = NULL;      /* Fake filename for stdin */
Packit cb4c47
Packit cb4c47
Packit cb4c47
/* Internal variables to keep track of byte count, context, etc. */
Packit cb4c47
static uintmax_t totalcc;	/* Total character count before bufbeg. */
Packit cb4c47
static char const *lastnl;	/* Pointer after last newline counted. */
Packit cb4c47
static char *lastout;		/* Pointer after last character output;
Packit cb4c47
                                   NULL if no character has been output
Packit cb4c47
                                   or if it's conceptually before bufbeg. */
Packit cb4c47
static intmax_t outleft;	/* Maximum number of selected lines.  */
Packit cb4c47
static intmax_t pending;	/* Pending lines of output.
Packit cb4c47
                                   Always kept 0 if out_quiet is true.  */
Packit cb4c47
static bool done_on_match;	/* Stop scanning file on first match.  */
Packit cb4c47
static bool exit_on_match;	/* Exit on first match.  */
Packit cb4c47
static bool dev_null_output;	/* Stdout is known to be /dev/null.  */
Packit cb4c47
static bool binary;		/* Use binary rather than text I/O.  */
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
nlscan (char const *lim)
Packit cb4c47
{
Packit cb4c47
  size_t newlines = 0;
Packit cb4c47
  char const *beg;
Packit cb4c47
  for (beg = lastnl; beg < lim; beg++)
Packit cb4c47
    {
Packit cb4c47
      beg = memchr (beg, eolbyte, lim - beg);
Packit cb4c47
      if (!beg)
Packit cb4c47
        break;
Packit cb4c47
      newlines++;
Packit cb4c47
    }
Packit cb4c47
  totalnl = add_count (totalnl, newlines);
Packit cb4c47
  lastnl = lim;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Print the current filename.  */
Packit cb4c47
static void
Packit cb4c47
print_filename (void)
Packit cb4c47
{
Packit cb4c47
  pr_sgr_start_if (filename_color);
Packit cb4c47
  fputs_errno (input_filename ());
Packit cb4c47
  pr_sgr_end_if (filename_color);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Print a character separator.  */
Packit cb4c47
static void
Packit cb4c47
print_sep (char sep)
Packit cb4c47
{
Packit cb4c47
  pr_sgr_start_if (sep_color);
Packit cb4c47
  putchar_errno (sep);
Packit cb4c47
  pr_sgr_end_if (sep_color);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Print a line number or a byte offset.  */
Packit cb4c47
static void
Packit cb4c47
print_offset (uintmax_t pos, const char *color)
Packit cb4c47
{
Packit cb4c47
  pr_sgr_start_if (color);
Packit cb4c47
  printf_errno ("%*"PRIuMAX, offset_width, pos);
Packit cb4c47
  pr_sgr_end_if (color);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Print a whole line head (filename, line, byte).  The output data
Packit cb4c47
   starts at BEG and contains LEN bytes; it is followed by at least
Packit cb4c47
   sizeof (uword) bytes, the first of which may be temporarily modified.
Packit cb4c47
   The output data comes from what is perhaps a larger input line that
Packit cb4c47
   goes until LIM, where LIM[-1] is an end-of-line byte.  Use SEP as
Packit cb4c47
   the separator on output.
Packit cb4c47
Packit cb4c47
   Return true unless the line was suppressed due to an encoding error.  */
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
print_line_head (char *beg, size_t len, char const *lim, char sep)
Packit cb4c47
{
Packit cb4c47
  if (binary_files != TEXT_BINARY_FILES)
Packit cb4c47
    {
Packit cb4c47
      char ch = beg[len];
Packit cb4c47
      bool encoding_errors = buf_has_encoding_errors (beg, len);
Packit cb4c47
      beg[len] = ch;
Packit cb4c47
      if (encoding_errors)
Packit cb4c47
        {
Packit cb4c47
          encoding_error_output = true;
Packit cb4c47
          return false;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (out_file)
Packit cb4c47
    {
Packit cb4c47
      print_filename ();
Packit cb4c47
      if (filename_mask)
Packit cb4c47
        print_sep (sep);
Packit cb4c47
      else
Packit cb4c47
        putchar_errno (0);
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (out_line)
Packit cb4c47
    {
Packit cb4c47
      if (lastnl < lim)
Packit cb4c47
        {
Packit cb4c47
          nlscan (beg);
Packit cb4c47
          totalnl = add_count (totalnl, 1);
Packit cb4c47
          lastnl = lim;
Packit cb4c47
        }
Packit cb4c47
      print_offset (totalnl, line_num_color);
Packit cb4c47
      print_sep (sep);
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (out_byte)
Packit cb4c47
    {
Packit cb4c47
      uintmax_t pos = add_count (totalcc, beg - bufbeg);
Packit cb4c47
      print_offset (pos, byte_num_color);
Packit cb4c47
      print_sep (sep);
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (align_tabs && (out_file | out_line | out_byte) && len != 0)
Packit cb4c47
    putchar_errno ('\t');
Packit cb4c47
Packit cb4c47
  return true;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static char *
Packit cb4c47
print_line_middle (char *beg, char *lim,
Packit cb4c47
                   const char *line_color, const char *match_color)
Packit cb4c47
{
Packit cb4c47
  size_t match_size;
Packit cb4c47
  size_t match_offset;
Packit cb4c47
  char *cur;
Packit cb4c47
  char *mid = NULL;
Packit cb4c47
  char *b;
Packit cb4c47
Packit cb4c47
  for (cur = beg;
Packit cb4c47
       (cur < lim
Packit cb4c47
        && ((match_offset = execute (compiled_pattern, beg, lim - beg,
Packit cb4c47
                                     &match_size, cur)) != (size_t) -1));
Packit cb4c47
       cur = b + match_size)
Packit cb4c47
    {
Packit cb4c47
      b = beg + match_offset;
Packit cb4c47
Packit cb4c47
      /* Avoid matching the empty line at the end of the buffer. */
Packit cb4c47
      if (b == lim)
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      /* Avoid hanging on grep --color "" foo */
Packit cb4c47
      if (match_size == 0)
Packit cb4c47
        {
Packit cb4c47
          /* Make minimal progress; there may be further non-empty matches.  */
Packit cb4c47
          /* XXX - Could really advance by one whole multi-octet character.  */
Packit cb4c47
          match_size = 1;
Packit cb4c47
          if (!mid)
Packit cb4c47
            mid = cur;
Packit cb4c47
        }
Packit cb4c47
      else
Packit cb4c47
        {
Packit cb4c47
          /* This function is called on a matching line only,
Packit cb4c47
             but is it selected or rejected/context?  */
Packit cb4c47
          if (only_matching)
Packit cb4c47
            {
Packit cb4c47
              char sep = out_invert ? SEP_CHAR_REJECTED : SEP_CHAR_SELECTED;
Packit cb4c47
              if (! print_line_head (b, match_size, lim, sep))
Packit cb4c47
                return NULL;
Packit cb4c47
            }
Packit cb4c47
          else
Packit cb4c47
            {
Packit cb4c47
              pr_sgr_start (line_color);
Packit cb4c47
              if (mid)
Packit cb4c47
                {
Packit cb4c47
                  cur = mid;
Packit cb4c47
                  mid = NULL;
Packit cb4c47
                }
Packit cb4c47
              fwrite_errno (cur, 1, b - cur);
Packit cb4c47
            }
Packit cb4c47
Packit cb4c47
          pr_sgr_start_if (match_color);
Packit cb4c47
          fwrite_errno (b, 1, match_size);
Packit cb4c47
          pr_sgr_end_if (match_color);
Packit cb4c47
          if (only_matching)
Packit cb4c47
            putchar_errno (eolbyte);
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (only_matching)
Packit cb4c47
    cur = lim;
Packit cb4c47
  else if (mid)
Packit cb4c47
    cur = mid;
Packit cb4c47
Packit cb4c47
  return cur;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static char *
Packit cb4c47
print_line_tail (char *beg, const char *lim, const char *line_color)
Packit cb4c47
{
Packit cb4c47
  size_t eol_size;
Packit cb4c47
  size_t tail_size;
Packit cb4c47
Packit cb4c47
  eol_size   = (lim > beg && lim[-1] == eolbyte);
Packit cb4c47
  eol_size  += (lim - eol_size > beg && lim[-(1 + eol_size)] == '\r');
Packit cb4c47
  tail_size  =  lim - eol_size - beg;
Packit cb4c47
Packit cb4c47
  if (tail_size > 0)
Packit cb4c47
    {
Packit cb4c47
      pr_sgr_start (line_color);
Packit cb4c47
      fwrite_errno (beg, 1, tail_size);
Packit cb4c47
      beg += tail_size;
Packit cb4c47
      pr_sgr_end (line_color);
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return beg;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
prline (char *beg, char *lim, char sep)
Packit cb4c47
{
Packit cb4c47
  bool matching;
Packit cb4c47
  const char *line_color;
Packit cb4c47
  const char *match_color;
Packit cb4c47
Packit cb4c47
  if (!only_matching)
Packit cb4c47
    if (! print_line_head (beg, lim - beg - 1, lim, sep))
Packit cb4c47
      return;
Packit cb4c47
Packit cb4c47
  matching = (sep == SEP_CHAR_SELECTED) ^ out_invert;
Packit cb4c47
Packit cb4c47
  if (color_option)
Packit cb4c47
    {
Packit cb4c47
      line_color = (((sep == SEP_CHAR_SELECTED)
Packit cb4c47
                     ^ (out_invert && (color_option < 0)))
Packit cb4c47
                    ? selected_line_color  : context_line_color);
Packit cb4c47
      match_color = (sep == SEP_CHAR_SELECTED
Packit cb4c47
                     ? selected_match_color : context_match_color);
Packit cb4c47
    }
Packit cb4c47
  else
Packit cb4c47
    line_color = match_color = NULL; /* Shouldn't be used.  */
Packit cb4c47
Packit cb4c47
  if ((only_matching && matching)
Packit cb4c47
      || (color_option && (*line_color || *match_color)))
Packit cb4c47
    {
Packit cb4c47
      /* We already know that non-matching lines have no match (to colorize). */
Packit cb4c47
      if (matching && (only_matching || *match_color))
Packit cb4c47
        {
Packit cb4c47
          beg = print_line_middle (beg, lim, line_color, match_color);
Packit cb4c47
          if (! beg)
Packit cb4c47
            return;
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      if (!only_matching && *line_color)
Packit cb4c47
        {
Packit cb4c47
          /* This code is exercised at least when grep is invoked like this:
Packit cb4c47
             echo k| GREP_COLORS='sl=01;32' src/grep k --color=always  */
Packit cb4c47
          beg = print_line_tail (beg, lim, line_color);
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (!only_matching && lim > beg)
Packit cb4c47
    fwrite_errno (beg, 1, lim - beg);
Packit cb4c47
Packit cb4c47
  if (line_buffered)
Packit cb4c47
    fflush_errno ();
Packit cb4c47
Packit cb4c47
  if (stdout_errno)
Packit cb4c47
    die (EXIT_TROUBLE, stdout_errno, _("write error"));
Packit cb4c47
Packit cb4c47
  lastout = lim;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Print pending lines of trailing context prior to LIM.  */
Packit cb4c47
static void
Packit cb4c47
prpending (char const *lim)
Packit cb4c47
{
Packit cb4c47
  if (!lastout)
Packit cb4c47
    lastout = bufbeg;
Packit cb4c47
  for (; 0 < pending && lastout < lim; pending--)
Packit cb4c47
    {
Packit cb4c47
      char *nl = memchr (lastout, eolbyte, lim - lastout);
Packit cb4c47
      prline (lastout, nl + 1, SEP_CHAR_REJECTED);
Packit cb4c47
    }
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Output the lines between BEG and LIM.  Deal with context.  */
Packit cb4c47
static void
Packit cb4c47
prtext (char *beg, char *lim)
Packit cb4c47
{
Packit cb4c47
  static bool used;	/* Avoid printing SEP_STR_GROUP before any output.  */
Packit cb4c47
  char eol = eolbyte;
Packit cb4c47
Packit cb4c47
  if (!out_quiet && pending > 0)
Packit cb4c47
    prpending (beg);
Packit cb4c47
Packit cb4c47
  char *p = beg;
Packit cb4c47
Packit cb4c47
  if (!out_quiet)
Packit cb4c47
    {
Packit cb4c47
      /* Deal with leading context.  */
Packit cb4c47
      char const *bp = lastout ? lastout : bufbeg;
Packit cb4c47
      intmax_t i;
Packit cb4c47
      for (i = 0; i < out_before; ++i)
Packit cb4c47
        if (p > bp)
Packit cb4c47
          do
Packit cb4c47
            --p;
Packit cb4c47
          while (p[-1] != eol);
Packit cb4c47
Packit cb4c47
      /* Print the group separator unless the output is adjacent to
Packit cb4c47
         the previous output in the file.  */
Packit cb4c47
      if ((0 <= out_before || 0 <= out_after) && used
Packit cb4c47
          && p != lastout && group_separator)
Packit cb4c47
        {
Packit cb4c47
          pr_sgr_start_if (sep_color);
Packit cb4c47
          fputs_errno (group_separator);
Packit cb4c47
          pr_sgr_end_if (sep_color);
Packit cb4c47
          putchar_errno ('\n');
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      while (p < beg)
Packit cb4c47
        {
Packit cb4c47
          char *nl = memchr (p, eol, beg - p);
Packit cb4c47
          nl++;
Packit cb4c47
          prline (p, nl, SEP_CHAR_REJECTED);
Packit cb4c47
          p = nl;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  intmax_t n;
Packit cb4c47
  if (out_invert)
Packit cb4c47
    {
Packit cb4c47
      /* One or more lines are output.  */
Packit cb4c47
      for (n = 0; p < lim && n < outleft; n++)
Packit cb4c47
        {
Packit cb4c47
          char *nl = memchr (p, eol, lim - p);
Packit cb4c47
          nl++;
Packit cb4c47
          if (!out_quiet)
Packit cb4c47
            prline (p, nl, SEP_CHAR_SELECTED);
Packit cb4c47
          p = nl;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
  else
Packit cb4c47
    {
Packit cb4c47
      /* Just one line is output.  */
Packit cb4c47
      if (!out_quiet)
Packit cb4c47
        prline (beg, lim, SEP_CHAR_SELECTED);
Packit cb4c47
      n = 1;
Packit cb4c47
      p = lim;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  after_last_match = bufoffset - (buflim - p);
Packit cb4c47
  pending = out_quiet ? 0 : MAX (0, out_after);
Packit cb4c47
  used = true;
Packit cb4c47
  outleft -= n;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Replace all NUL bytes in buffer P (which ends at LIM) with EOL.
Packit cb4c47
   This avoids running out of memory when binary input contains a long
Packit cb4c47
   sequence of zeros, which would otherwise be considered to be part
Packit cb4c47
   of a long line.  P[LIM] should be EOL.  */
Packit cb4c47
static void
Packit cb4c47
zap_nuls (char *p, char *lim, char eol)
Packit cb4c47
{
Packit cb4c47
  if (eol)
Packit cb4c47
    while (true)
Packit cb4c47
      {
Packit cb4c47
        *lim = '\0';
Packit cb4c47
        p += strlen (p);
Packit cb4c47
        *lim = eol;
Packit cb4c47
        if (p == lim)
Packit cb4c47
          break;
Packit cb4c47
        do
Packit cb4c47
          *p++ = eol;
Packit cb4c47
        while (!*p);
Packit cb4c47
      }
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Scan the specified portion of the buffer, matching lines (or
Packit cb4c47
   between matching lines if OUT_INVERT is true).  Return a count of
Packit cb4c47
   lines printed.  Replace all NUL bytes with NUL_ZAPPER as we go.  */
Packit cb4c47
static intmax_t
Packit cb4c47
grepbuf (char *beg, char const *lim)
Packit cb4c47
{
Packit cb4c47
  intmax_t outleft0 = outleft;
Packit cb4c47
  char *endp;
Packit cb4c47
Packit cb4c47
  for (char *p = beg; p < lim; p = endp)
Packit cb4c47
    {
Packit cb4c47
      size_t match_size;
Packit cb4c47
      size_t match_offset = execute (compiled_pattern, p, lim - p,
Packit cb4c47
                                     &match_size, NULL);
Packit cb4c47
      if (match_offset == (size_t) -1)
Packit cb4c47
        {
Packit cb4c47
          if (!out_invert)
Packit cb4c47
            break;
Packit cb4c47
          match_offset = lim - p;
Packit cb4c47
          match_size = 0;
Packit cb4c47
        }
Packit cb4c47
      char *b = p + match_offset;
Packit cb4c47
      endp = b + match_size;
Packit cb4c47
      /* Avoid matching the empty line at the end of the buffer. */
Packit cb4c47
      if (!out_invert && b == lim)
Packit cb4c47
        break;
Packit cb4c47
      if (!out_invert || p < b)
Packit cb4c47
        {
Packit cb4c47
          char *prbeg = out_invert ? p : b;
Packit cb4c47
          char *prend = out_invert ? b : endp;
Packit cb4c47
          prtext (prbeg, prend);
Packit cb4c47
          if (!outleft || done_on_match)
Packit cb4c47
            {
Packit cb4c47
              if (exit_on_match)
Packit cb4c47
                exit (errseen ? exit_failure : EXIT_SUCCESS);
Packit cb4c47
              break;
Packit cb4c47
            }
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return outleft0 - outleft;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Search a given (non-directory) file.  Return a count of lines printed.
Packit cb4c47
   Set *INEOF to true if end-of-file reached.  */
Packit cb4c47
static intmax_t
Packit cb4c47
grep (int fd, struct stat const *st, bool *ineof)
Packit cb4c47
{
Packit cb4c47
  intmax_t nlines, i;
Packit cb4c47
  size_t residue, save;
Packit cb4c47
  char oldc;
Packit cb4c47
  char *beg;
Packit cb4c47
  char *lim;
Packit cb4c47
  char eol = eolbyte;
Packit cb4c47
  char nul_zapper = '\0';
Packit cb4c47
  bool done_on_match_0 = done_on_match;
Packit cb4c47
  bool out_quiet_0 = out_quiet;
Packit cb4c47
Packit cb4c47
  /* The value of NLINES when nulls were first deduced in the input;
Packit cb4c47
     this is not necessarily the same as the number of matching lines
Packit cb4c47
     before the first null.  -1 if no input nulls have been deduced.  */
Packit cb4c47
  intmax_t nlines_first_null = -1;
Packit cb4c47
Packit cb4c47
  if (! reset (fd, st))
Packit cb4c47
    return 0;
Packit cb4c47
Packit cb4c47
  totalcc = 0;
Packit cb4c47
  lastout = 0;
Packit cb4c47
  totalnl = 0;
Packit cb4c47
  outleft = max_count;
Packit cb4c47
  after_last_match = 0;
Packit cb4c47
  pending = 0;
Packit cb4c47
  skip_nuls = skip_empty_lines && !eol;
Packit cb4c47
  encoding_error_output = false;
Packit cb4c47
Packit cb4c47
  nlines = 0;
Packit cb4c47
  residue = 0;
Packit cb4c47
  save = 0;
Packit cb4c47
Packit cb4c47
  if (! fillbuf (save, st))
Packit cb4c47
    {
Packit cb4c47
      suppressible_error (errno);
Packit cb4c47
      return 0;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  offset_width = 0;
Packit cb4c47
  if (align_tabs)
Packit cb4c47
    {
Packit cb4c47
      /* Width is log of maximum number.  Line numbers are origin-1.  */
Packit cb4c47
      uintmax_t num = usable_st_size (st) ? st->st_size : UINTMAX_MAX;
Packit cb4c47
      num += out_line && num < UINTMAX_MAX;
Packit cb4c47
      do
Packit cb4c47
        offset_width++;
Packit cb4c47
      while ((num /= 10) != 0);
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  for (bool firsttime = true; ; firsttime = false)
Packit cb4c47
    {
Packit cb4c47
      if (nlines_first_null < 0 && eol && binary_files != TEXT_BINARY_FILES
Packit cb4c47
          && (buf_has_nulls (bufbeg, buflim - bufbeg)
Packit cb4c47
              || (firsttime && file_must_have_nulls (buflim - bufbeg, fd, st))))
Packit cb4c47
        {
Packit cb4c47
          if (binary_files == WITHOUT_MATCH_BINARY_FILES)
Packit cb4c47
            return 0;
Packit cb4c47
          if (!count_matches)
Packit cb4c47
            done_on_match = out_quiet = true;
Packit cb4c47
          nlines_first_null = nlines;
Packit cb4c47
          nul_zapper = eol;
Packit cb4c47
          skip_nuls = skip_empty_lines;
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      lastnl = bufbeg;
Packit cb4c47
      if (lastout)
Packit cb4c47
        lastout = bufbeg;
Packit cb4c47
Packit cb4c47
      beg = bufbeg + save;
Packit cb4c47
Packit cb4c47
      /* no more data to scan (eof) except for maybe a residue -> break */
Packit cb4c47
      if (beg == buflim)
Packit cb4c47
        {
Packit cb4c47
          *ineof = true;
Packit cb4c47
          break;
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      zap_nuls (beg, buflim, nul_zapper);
Packit cb4c47
Packit cb4c47
      /* Determine new residue (the length of an incomplete line at the end of
Packit cb4c47
         the buffer, 0 means there is no incomplete last line).  */
Packit cb4c47
      oldc = beg[-1];
Packit cb4c47
      beg[-1] = eol;
Packit cb4c47
      /* FIXME: use rawmemrchr if/when it exists, since we have ensured
Packit cb4c47
         that this use of memrchr is guaranteed never to return NULL.  */
Packit cb4c47
      lim = memrchr (beg - 1, eol, buflim - beg + 1);
Packit cb4c47
      ++lim;
Packit cb4c47
      beg[-1] = oldc;
Packit cb4c47
      if (lim == beg)
Packit cb4c47
        lim = beg - residue;
Packit cb4c47
      beg -= residue;
Packit cb4c47
      residue = buflim - lim;
Packit cb4c47
Packit cb4c47
      if (beg < lim)
Packit cb4c47
        {
Packit cb4c47
          if (outleft)
Packit cb4c47
            nlines += grepbuf (beg, lim);
Packit cb4c47
          if (pending)
Packit cb4c47
            prpending (lim);
Packit cb4c47
          if ((!outleft && !pending)
Packit cb4c47
              || (done_on_match && MAX (0, nlines_first_null) < nlines))
Packit cb4c47
            goto finish_grep;
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      /* The last OUT_BEFORE lines at the end of the buffer will be needed as
Packit cb4c47
         leading context if there is a matching line at the begin of the
Packit cb4c47
         next data. Make beg point to their begin.  */
Packit cb4c47
      i = 0;
Packit cb4c47
      beg = lim;
Packit cb4c47
      while (i < out_before && beg > bufbeg && beg != lastout)
Packit cb4c47
        {
Packit cb4c47
          ++i;
Packit cb4c47
          do
Packit cb4c47
            --beg;
Packit cb4c47
          while (beg[-1] != eol);
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      /* Detect whether leading context is adjacent to previous output.  */
Packit cb4c47
      if (beg != lastout)
Packit cb4c47
        lastout = 0;
Packit cb4c47
Packit cb4c47
      /* Handle some details and read more data to scan.  */
Packit cb4c47
      save = residue + lim - beg;
Packit cb4c47
      if (out_byte)
Packit cb4c47
        totalcc = add_count (totalcc, buflim - bufbeg - save);
Packit cb4c47
      if (out_line)
Packit cb4c47
        nlscan (beg);
Packit cb4c47
      if (! fillbuf (save, st))
Packit cb4c47
        {
Packit cb4c47
          suppressible_error (errno);
Packit cb4c47
          goto finish_grep;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
  if (residue)
Packit cb4c47
    {
Packit cb4c47
      *buflim++ = eol;
Packit cb4c47
      if (outleft)
Packit cb4c47
        nlines += grepbuf (bufbeg + save - residue, buflim);
Packit cb4c47
      if (pending)
Packit cb4c47
        prpending (buflim);
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
 finish_grep:
Packit cb4c47
  done_on_match = done_on_match_0;
Packit cb4c47
  out_quiet = out_quiet_0;
Packit cb4c47
  if (!out_quiet && (encoding_error_output
Packit cb4c47
                     || (0 <= nlines_first_null && nlines_first_null < nlines)))
Packit cb4c47
    {
Packit cb4c47
      printf_errno (_("Binary file %s matches\n"), input_filename ());
Packit cb4c47
      if (line_buffered)
Packit cb4c47
        fflush_errno ();
Packit cb4c47
    }
Packit cb4c47
  return nlines;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
grepdirent (FTS *fts, FTSENT *ent, bool command_line)
Packit cb4c47
{
Packit cb4c47
  bool follow;
Packit cb4c47
  command_line &= ent->fts_level == FTS_ROOTLEVEL;
Packit cb4c47
Packit cb4c47
  if (ent->fts_info == FTS_DP)
Packit cb4c47
    {
Packit cb4c47
      if (directories == RECURSE_DIRECTORIES && command_line)
Packit cb4c47
        out_file &= ~ (2 * !no_filenames);
Packit cb4c47
      return true;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (!command_line
Packit cb4c47
      && skipped_file (ent->fts_name, false,
Packit cb4c47
                       (ent->fts_info == FTS_D || ent->fts_info == FTS_DC
Packit cb4c47
                        || ent->fts_info == FTS_DNR)))
Packit cb4c47
    {
Packit cb4c47
      fts_set (fts, ent, FTS_SKIP);
Packit cb4c47
      return true;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  filename = ent->fts_path;
Packit cb4c47
  if (omit_dot_slash && filename[1])
Packit cb4c47
    filename += 2;
Packit cb4c47
  follow = (fts->fts_options & FTS_LOGICAL
Packit cb4c47
            || (fts->fts_options & FTS_COMFOLLOW && command_line));
Packit cb4c47
Packit cb4c47
  switch (ent->fts_info)
Packit cb4c47
    {
Packit cb4c47
    case FTS_D:
Packit cb4c47
      if (directories == RECURSE_DIRECTORIES)
Packit cb4c47
        {
Packit cb4c47
          out_file |= 2 * !no_filenames;
Packit cb4c47
          return true;
Packit cb4c47
        }
Packit cb4c47
      fts_set (fts, ent, FTS_SKIP);
Packit cb4c47
      break;
Packit cb4c47
Packit cb4c47
    case FTS_DC:
Packit cb4c47
      if (!suppress_errors)
Packit cb4c47
        error (0, 0, _("warning: %s: %s"), filename,
Packit cb4c47
               _("recursive directory loop"));
Packit cb4c47
      return true;
Packit cb4c47
Packit cb4c47
    case FTS_DNR:
Packit cb4c47
    case FTS_ERR:
Packit cb4c47
    case FTS_NS:
Packit cb4c47
      suppressible_error (ent->fts_errno);
Packit cb4c47
      return true;
Packit cb4c47
Packit cb4c47
    case FTS_DEFAULT:
Packit cb4c47
    case FTS_NSOK:
Packit cb4c47
      if (skip_devices (command_line))
Packit cb4c47
        {
Packit cb4c47
          struct stat *st = ent->fts_statp;
Packit cb4c47
          struct stat st1;
Packit cb4c47
          if (! st->st_mode)
Packit cb4c47
            {
Packit cb4c47
              /* The file type is not already known.  Get the file status
Packit cb4c47
                 before opening, since opening might have side effects
Packit cb4c47
                 on a device.  */
Packit cb4c47
              int flag = follow ? 0 : AT_SYMLINK_NOFOLLOW;
Packit cb4c47
              if (fstatat (fts->fts_cwd_fd, ent->fts_accpath, &st1, flag) != 0)
Packit cb4c47
                {
Packit cb4c47
                  suppressible_error (errno);
Packit cb4c47
                  return true;
Packit cb4c47
                }
Packit cb4c47
              st = &st1;
Packit cb4c47
            }
Packit cb4c47
          if (is_device_mode (st->st_mode))
Packit cb4c47
            return true;
Packit cb4c47
        }
Packit cb4c47
      break;
Packit cb4c47
Packit cb4c47
    case FTS_F:
Packit cb4c47
    case FTS_SLNONE:
Packit cb4c47
      break;
Packit cb4c47
Packit cb4c47
    case FTS_SL:
Packit cb4c47
    case FTS_W:
Packit cb4c47
      return true;
Packit cb4c47
Packit cb4c47
    default:
Packit cb4c47
      abort ();
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return grepfile (fts->fts_cwd_fd, ent->fts_accpath, follow, command_line);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* True if errno is ERR after 'open ("symlink", ... O_NOFOLLOW ...)'.
Packit cb4c47
   POSIX specifies ELOOP, but it's EMLINK on FreeBSD and EFTYPE on NetBSD.  */
Packit cb4c47
static bool
Packit cb4c47
open_symlink_nofollow_error (int err)
Packit cb4c47
{
Packit cb4c47
  if (err == ELOOP || err == EMLINK)
Packit cb4c47
    return true;
Packit cb4c47
#ifdef EFTYPE
Packit cb4c47
  if (err == EFTYPE)
Packit cb4c47
    return true;
Packit cb4c47
#endif
Packit cb4c47
  return false;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
grepfile (int dirdesc, char const *name, bool follow, bool command_line)
Packit cb4c47
{
Packit cb4c47
  int oflag = (O_RDONLY | O_NOCTTY
Packit cb4c47
               | (IGNORE_DUPLICATE_BRANCH_WARNING
Packit cb4c47
                  (binary ? O_BINARY : 0))
Packit cb4c47
               | (follow ? 0 : O_NOFOLLOW)
Packit cb4c47
               | (skip_devices (command_line) ? O_NONBLOCK : 0));
Packit cb4c47
  int desc = openat_safer (dirdesc, name, oflag);
Packit cb4c47
  if (desc < 0)
Packit cb4c47
    {
Packit cb4c47
      if (follow || ! open_symlink_nofollow_error (errno))
Packit cb4c47
        suppressible_error (errno);
Packit cb4c47
      return true;
Packit cb4c47
    }
Packit cb4c47
  return grepdesc (desc, command_line);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Read all data from FD, with status ST.  Return true if successful,
Packit cb4c47
   false (setting errno) otherwise.  */
Packit cb4c47
static bool
Packit cb4c47
drain_input (int fd, struct stat const *st)
Packit cb4c47
{
Packit cb4c47
  ssize_t nbytes;
Packit cb4c47
  if (S_ISFIFO (st->st_mode) && dev_null_output)
Packit cb4c47
    {
Packit cb4c47
#ifdef SPLICE_F_MOVE
Packit cb4c47
      /* Should be faster, since it need not copy data to user space.  */
Packit cb4c47
      nbytes = splice (fd, NULL, STDOUT_FILENO, NULL,
Packit cb4c47
                       INITIAL_BUFSIZE, SPLICE_F_MOVE);
Packit cb4c47
      if (0 <= nbytes || errno != EINVAL)
Packit cb4c47
        {
Packit cb4c47
          while (0 < nbytes)
Packit cb4c47
            nbytes = splice (fd, NULL, STDOUT_FILENO, NULL,
Packit cb4c47
                             INITIAL_BUFSIZE, SPLICE_F_MOVE);
Packit cb4c47
          return nbytes == 0;
Packit cb4c47
        }
Packit cb4c47
#endif
Packit cb4c47
    }
Packit cb4c47
  while ((nbytes = safe_read (fd, buffer, bufalloc)))
Packit cb4c47
    if (nbytes == SAFE_READ_ERROR)
Packit cb4c47
      return false;
Packit cb4c47
  return true;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Finish reading from FD, with status ST and where end-of-file has
Packit cb4c47
   been seen if INEOF.  Typically this is a no-op, but when reading
Packit cb4c47
   from standard input this may adjust the file offset or drain a
Packit cb4c47
   pipe.  */
Packit cb4c47
Packit cb4c47
static void
Packit cb4c47
finalize_input (int fd, struct stat const *st, bool ineof)
Packit cb4c47
{
Packit cb4c47
  if (fd == STDIN_FILENO
Packit cb4c47
      && (outleft
Packit cb4c47
          ? (!ineof
Packit cb4c47
             && (seek_failed
Packit cb4c47
                 || (lseek (fd, 0, SEEK_END) < 0
Packit cb4c47
                     /* Linux proc file system has EINVAL (Bug#25180).  */
Packit cb4c47
                     && errno != EINVAL))
Packit cb4c47
             && ! drain_input (fd, st))
Packit cb4c47
          : (bufoffset != after_last_match && !seek_failed
Packit cb4c47
             && lseek (fd, after_last_match, SEEK_SET) < 0)))
Packit cb4c47
    suppressible_error (errno);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
grepdesc (int desc, bool command_line)
Packit cb4c47
{
Packit cb4c47
  intmax_t count;
Packit cb4c47
  bool status = true;
Packit cb4c47
  bool ineof = false;
Packit cb4c47
  struct stat st;
Packit cb4c47
Packit cb4c47
  /* Get the file status, possibly for the second time.  This catches
Packit cb4c47
     a race condition if the directory entry changes after the
Packit cb4c47
     directory entry is read and before the file is opened.  For
Packit cb4c47
     example, normally DESC is a directory only at the top level, but
Packit cb4c47
     there is an exception if some other process substitutes a
Packit cb4c47
     directory for a non-directory while 'grep' is running.  */
Packit cb4c47
  if (fstat (desc, &st) != 0)
Packit cb4c47
    {
Packit cb4c47
      suppressible_error (errno);
Packit cb4c47
      goto closeout;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (desc != STDIN_FILENO && skip_devices (command_line)
Packit cb4c47
      && is_device_mode (st.st_mode))
Packit cb4c47
    goto closeout;
Packit cb4c47
Packit cb4c47
  if (desc != STDIN_FILENO && command_line
Packit cb4c47
      && skipped_file (filename, true, S_ISDIR (st.st_mode) != 0))
Packit cb4c47
    goto closeout;
Packit cb4c47
Packit cb4c47
  if (desc != STDIN_FILENO
Packit cb4c47
      && directories == RECURSE_DIRECTORIES && S_ISDIR (st.st_mode))
Packit cb4c47
    {
Packit cb4c47
      /* Traverse the directory starting with its full name, because
Packit cb4c47
         unfortunately fts provides no way to traverse the directory
Packit cb4c47
         starting from its file descriptor.  */
Packit cb4c47
Packit cb4c47
      FTS *fts;
Packit cb4c47
      FTSENT *ent;
Packit cb4c47
      int opts = fts_options & ~(command_line ? 0 : FTS_COMFOLLOW);
Packit cb4c47
      char *fts_arg[2];
Packit cb4c47
Packit cb4c47
      /* Close DESC now, to conserve file descriptors if the race
Packit cb4c47
         condition occurs many times in a deep recursion.  */
Packit cb4c47
      if (close (desc) != 0)
Packit cb4c47
        suppressible_error (errno);
Packit cb4c47
Packit cb4c47
      fts_arg[0] = (char *) filename;
Packit cb4c47
      fts_arg[1] = NULL;
Packit cb4c47
      fts = fts_open (fts_arg, opts, NULL);
Packit cb4c47
Packit cb4c47
      if (!fts)
Packit cb4c47
        xalloc_die ();
Packit cb4c47
      while ((ent = fts_read (fts)))
Packit cb4c47
        status &= grepdirent (fts, ent, command_line);
Packit cb4c47
      if (errno)
Packit cb4c47
        suppressible_error (errno);
Packit cb4c47
      if (fts_close (fts) != 0)
Packit cb4c47
        suppressible_error (errno);
Packit cb4c47
      return status;
Packit cb4c47
    }
Packit cb4c47
  if (desc != STDIN_FILENO
Packit cb4c47
      && ((directories == SKIP_DIRECTORIES && S_ISDIR (st.st_mode))
Packit cb4c47
          || ((devices == SKIP_DEVICES
Packit cb4c47
               || (devices == READ_COMMAND_LINE_DEVICES && !command_line))
Packit cb4c47
              && is_device_mode (st.st_mode))))
Packit cb4c47
    goto closeout;
Packit cb4c47
Packit cb4c47
  /* If there is a regular file on stdout and the current file refers
Packit cb4c47
     to the same i-node, we have to report the problem and skip it.
Packit cb4c47
     Otherwise when matching lines from some other input reach the
Packit cb4c47
     disk before we open this file, we can end up reading and matching
Packit cb4c47
     those lines and appending them to the file from which we're reading.
Packit cb4c47
     Then we'd have what appears to be an infinite loop that'd terminate
Packit cb4c47
     only upon filling the output file system or reaching a quota.
Packit cb4c47
     However, there is no risk of an infinite loop if grep is generating
Packit cb4c47
     no output, i.e., with --silent, --quiet, -q.
Packit cb4c47
     Similarly, with any of these:
Packit cb4c47
       --max-count=N (-m) (for N >= 2)
Packit cb4c47
       --files-with-matches (-l)
Packit cb4c47
       --files-without-match (-L)
Packit cb4c47
     there is no risk of trouble.
Packit cb4c47
     For --max-count=1, grep stops after printing the first match,
Packit cb4c47
     so there is no risk of malfunction.  But even --max-count=2, with
Packit cb4c47
     input==output, while there is no risk of infloop, there is a race
Packit cb4c47
     condition that could result in "alternate" output.  */
Packit cb4c47
  if (!out_quiet && list_files == LISTFILES_NONE && 1 < max_count
Packit cb4c47
      && S_ISREG (st.st_mode) && SAME_INODE (st, out_stat))
Packit cb4c47
    {
Packit cb4c47
      if (! suppress_errors)
Packit cb4c47
        error (0, 0, _("input file %s is also the output"),
Packit cb4c47
               quote (input_filename ()));
Packit cb4c47
      errseen = true;
Packit cb4c47
      goto closeout;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  count = grep (desc, &st, &ineof);
Packit cb4c47
  if (count_matches)
Packit cb4c47
    {
Packit cb4c47
      if (out_file)
Packit cb4c47
        {
Packit cb4c47
          print_filename ();
Packit cb4c47
          if (filename_mask)
Packit cb4c47
            print_sep (SEP_CHAR_SELECTED);
Packit cb4c47
          else
Packit cb4c47
            putchar_errno (0);
Packit cb4c47
        }
Packit cb4c47
      printf_errno ("%" PRIdMAX "\n", count);
Packit cb4c47
      if (line_buffered)
Packit cb4c47
        fflush_errno ();
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  status = !count;
Packit cb4c47
Packit cb4c47
  if (list_files == LISTFILES_NONE)
Packit cb4c47
    finalize_input (desc, &st, ineof);
Packit cb4c47
  else if (list_files == (status ? LISTFILES_NONMATCHING : LISTFILES_MATCHING))
Packit cb4c47
    {
Packit cb4c47
      print_filename ();
Packit cb4c47
      putchar_errno ('\n' & filename_mask);
Packit cb4c47
      if (line_buffered)
Packit cb4c47
        fflush_errno ();
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
 closeout:
Packit cb4c47
  if (desc != STDIN_FILENO && close (desc) != 0)
Packit cb4c47
    suppressible_error (errno);
Packit cb4c47
  return status;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
grep_command_line_arg (char const *arg)
Packit cb4c47
{
Packit cb4c47
  if (STREQ (arg, "-"))
Packit cb4c47
    {
Packit cb4c47
      filename = label;
Packit cb4c47
      if (binary)
Packit cb4c47
        xset_binary_mode (STDIN_FILENO, O_BINARY);
Packit cb4c47
      return grepdesc (STDIN_FILENO, true);
Packit cb4c47
    }
Packit cb4c47
  else
Packit cb4c47
    {
Packit cb4c47
      filename = arg;
Packit cb4c47
      return grepfile (AT_FDCWD, arg, true, true);
Packit cb4c47
    }
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
_Noreturn void usage (int);
Packit cb4c47
void
Packit cb4c47
usage (int status)
Packit cb4c47
{
Packit cb4c47
  if (status != 0)
Packit cb4c47
    {
Packit cb4c47
      fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"),
Packit cb4c47
               getprogname ());
Packit cb4c47
      fprintf (stderr, _("Try '%s --help' for more information.\n"),
Packit cb4c47
               getprogname ());
Packit cb4c47
    }
Packit cb4c47
  else
Packit cb4c47
    {
Packit cb4c47
      printf (_("Usage: %s [OPTION]... PATTERN [FILE]...\n"), getprogname ());
Packit cb4c47
      printf (_("Search for PATTERN in each FILE.\n"));
Packit cb4c47
      printf (_("\
Packit cb4c47
Example: %s -i 'hello world' menu.h main.c\n\
Packit cb4c47
\n\
Packit cb4c47
Pattern selection and interpretation:\n"), getprogname ());
Packit cb4c47
      printf (_("\
Packit cb4c47
  -E, --extended-regexp     PATTERN is an extended regular expression\n\
Packit cb4c47
  -F, --fixed-strings       PATTERN is a set of newline-separated strings\n\
Packit cb4c47
  -G, --basic-regexp        PATTERN is a basic regular expression (default)\n\
Packit cb4c47
  -P, --perl-regexp         PATTERN is a Perl regular expression\n"));
Packit cb4c47
  /* -X is deliberately undocumented.  */
Packit cb4c47
      printf (_("\
Packit cb4c47
  -e, --regexp=PATTERN      use PATTERN for matching\n\
Packit cb4c47
  -f, --file=FILE           obtain PATTERN from FILE\n\
Packit cb4c47
  -i, --ignore-case         ignore case distinctions\n\
Packit cb4c47
  -w, --word-regexp         force PATTERN to match only whole words\n\
Packit cb4c47
  -x, --line-regexp         force PATTERN to match only whole lines\n\
Packit cb4c47
  -z, --null-data           a data line ends in 0 byte, not newline\n"));
Packit cb4c47
      printf (_("\
Packit cb4c47
\n\
Packit cb4c47
Miscellaneous:\n\
Packit cb4c47
  -s, --no-messages         suppress error messages\n\
Packit cb4c47
  -v, --invert-match        select non-matching lines\n\
Packit cb4c47
  -V, --version             display version information and exit\n\
Packit cb4c47
      --help                display this help text and exit\n"));
Packit cb4c47
      printf (_("\
Packit cb4c47
\n\
Packit cb4c47
Output control:\n\
Packit cb4c47
  -m, --max-count=NUM       stop after NUM selected lines\n\
Packit cb4c47
  -b, --byte-offset         print the byte offset with output lines\n\
Packit cb4c47
  -n, --line-number         print line number with output lines\n\
Packit cb4c47
      --line-buffered       flush output on every line\n\
Packit cb4c47
  -H, --with-filename       print file name with output lines\n\
Packit cb4c47
  -h, --no-filename         suppress the file name prefix on output\n\
Packit cb4c47
      --label=LABEL         use LABEL as the standard input file name prefix\n\
Packit cb4c47
"));
Packit cb4c47
      printf (_("\
Packit cb4c47
  -o, --only-matching       show only the part of a line matching PATTERN\n\
Packit cb4c47
  -q, --quiet, --silent     suppress all normal output\n\
Packit cb4c47
      --binary-files=TYPE   assume that binary files are TYPE;\n\
Packit cb4c47
                            TYPE is 'binary', 'text', or 'without-match'\n\
Packit cb4c47
  -a, --text                equivalent to --binary-files=text\n\
Packit cb4c47
"));
Packit cb4c47
      printf (_("\
Packit cb4c47
  -I                        equivalent to --binary-files=without-match\n\
Packit cb4c47
  -d, --directories=ACTION  how to handle directories;\n\
Packit cb4c47
                            ACTION is 'read', 'recurse', or 'skip'\n\
Packit cb4c47
  -D, --devices=ACTION      how to handle devices, FIFOs and sockets;\n\
Packit cb4c47
                            ACTION is 'read' or 'skip'\n\
Packit cb4c47
  -r, --recursive           like --directories=recurse\n\
Packit cb4c47
  -R, --dereference-recursive  likewise, but follow all symlinks\n\
Packit cb4c47
"));
Packit cb4c47
      printf (_("\
Packit cb4c47
      --include=FILE_PATTERN  search only files that match FILE_PATTERN\n\
Packit cb4c47
      --exclude=FILE_PATTERN  skip files and directories matching\
Packit cb4c47
 FILE_PATTERN\n\
Packit cb4c47
      --exclude-from=FILE   skip files matching any file pattern from FILE\n\
Packit cb4c47
      --exclude-dir=PATTERN  directories that match PATTERN will be skipped.\n\
Packit cb4c47
"));
Packit cb4c47
      printf (_("\
Packit cb4c47
  -L, --files-without-match  print only names of FILEs with no selected lines\n\
Packit cb4c47
  -l, --files-with-matches  print only names of FILEs with selected lines\n\
Packit cb4c47
  -c, --count               print only a count of selected lines per FILE\n\
Packit cb4c47
  -T, --initial-tab         make tabs line up (if needed)\n\
Packit cb4c47
  -Z, --null                print 0 byte after FILE name\n"));
Packit cb4c47
      printf (_("\
Packit cb4c47
\n\
Packit cb4c47
Context control:\n\
Packit cb4c47
  -B, --before-context=NUM  print NUM lines of leading context\n\
Packit cb4c47
  -A, --after-context=NUM   print NUM lines of trailing context\n\
Packit cb4c47
  -C, --context=NUM         print NUM lines of output context\n\
Packit cb4c47
"));
Packit cb4c47
      printf (_("\
Packit cb4c47
  -NUM                      same as --context=NUM\n\
Packit cb4c47
      --color[=WHEN],\n\
Packit cb4c47
      --colour[=WHEN]       use markers to highlight the matching strings;\n\
Packit cb4c47
                            WHEN is 'always', 'never', or 'auto'\n\
Packit cb4c47
  -U, --binary              do not strip CR characters at EOL (MSDOS/Windows)\n\
Packit cb4c47
\n"));
Packit cb4c47
      printf (_("\
Packit cb4c47
When FILE is '-', read standard input.  With no FILE, read '.' if\n\
Packit cb4c47
recursive, '-' otherwise.  With fewer than two FILEs, assume -h.\n\
Packit cb4c47
Exit status is 0 if any line is selected, 1 otherwise;\n\
Packit cb4c47
if any error occurs and -q is not given, the exit status is 2.\n"));
Packit cb4c47
      emit_bug_reporting_address ();
Packit cb4c47
    }
Packit cb4c47
  exit (status);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Pattern compilers and matchers.  */
Packit cb4c47
Packit cb4c47
static struct
Packit cb4c47
{
Packit cb4c47
  char const name[12];
Packit cb4c47
  int syntax; /* used if compile == GEAcompile */
Packit cb4c47
  compile_fp_t compile;
Packit cb4c47
  execute_fp_t execute;
Packit cb4c47
} const matchers[] = {
Packit cb4c47
  { "grep", RE_SYNTAX_GREP, GEAcompile, EGexecute },
Packit cb4c47
  { "egrep", RE_SYNTAX_EGREP, GEAcompile, EGexecute },
Packit cb4c47
  { "fgrep", 0, Fcompile, Fexecute, },
Packit cb4c47
  { "awk", RE_SYNTAX_AWK, GEAcompile, EGexecute },
Packit cb4c47
  { "gawk", RE_SYNTAX_GNU_AWK, GEAcompile, EGexecute },
Packit cb4c47
  { "posixawk", RE_SYNTAX_POSIX_AWK, GEAcompile, EGexecute },
Packit cb4c47
  { "perl", 0, Pcompile, Pexecute, },
Packit cb4c47
};
Packit cb4c47
/* Keep these in sync with the 'matchers' table.  */
Packit cb4c47
enum { E_MATCHER_INDEX = 1, F_MATCHER_INDEX = 2, G_MATCHER_INDEX = 0 };
Packit cb4c47
Packit cb4c47
/* Return the index of the matcher corresponding to M if available.
Packit cb4c47
   MATCHER is the index of the previous matcher, or -1 if none.
Packit cb4c47
   Exit in case of conflicts or if M is not available.  */
Packit cb4c47
static int
Packit cb4c47
setmatcher (char const *m, int matcher)
Packit cb4c47
{
Packit cb4c47
  for (int i = 0; i < sizeof matchers / sizeof *matchers; i++)
Packit cb4c47
    if (STREQ (m, matchers[i].name))
Packit cb4c47
      {
Packit cb4c47
        if (0 <= matcher && matcher != i)
Packit cb4c47
          die (EXIT_TROUBLE, 0, _("conflicting matchers specified"));
Packit cb4c47
        return i;
Packit cb4c47
      }
Packit cb4c47
Packit cb4c47
  die (EXIT_TROUBLE, 0, _("invalid matcher %s"), m);
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Find the white-space-separated options specified by OPTIONS, and
Packit cb4c47
   using BUF to store copies of these options, set ARGV[0], ARGV[1],
Packit cb4c47
   etc. to the option copies.  Return the number N of options found.
Packit cb4c47
   Do not set ARGV[N] to NULL.  If ARGV is NULL, do not store ARGV[0]
Packit cb4c47
   etc.  Backslash can be used to escape whitespace (and backslashes).  */
Packit cb4c47
static size_t
Packit cb4c47
prepend_args (char const *options, char *buf, char **argv)
Packit cb4c47
{
Packit cb4c47
  char const *o = options;
Packit cb4c47
  char *b = buf;
Packit cb4c47
  size_t n = 0;
Packit cb4c47
Packit cb4c47
  for (;;)
Packit cb4c47
    {
Packit cb4c47
      while (c_isspace (to_uchar (*o)))
Packit cb4c47
        o++;
Packit cb4c47
      if (!*o)
Packit cb4c47
        return n;
Packit cb4c47
      if (argv)
Packit cb4c47
        argv[n] = b;
Packit cb4c47
      n++;
Packit cb4c47
Packit cb4c47
      do
Packit cb4c47
        if ((*b++ = *o++) == '\\' && *o)
Packit cb4c47
          b[-1] = *o++;
Packit cb4c47
      while (*o && ! c_isspace (to_uchar (*o)));
Packit cb4c47
Packit cb4c47
      *b++ = '\0';
Packit cb4c47
    }
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Prepend the whitespace-separated options in OPTIONS to the argument
Packit cb4c47
   vector of a main program with argument count *PARGC and argument
Packit cb4c47
   vector *PARGV.  Return the number of options prepended.  */
Packit cb4c47
static int
Packit cb4c47
prepend_default_options (char const *options, int *pargc, char ***pargv)
Packit cb4c47
{
Packit cb4c47
  if (options && *options)
Packit cb4c47
    {
Packit cb4c47
      char *buf = xmalloc (strlen (options) + 1);
Packit cb4c47
      size_t prepended = prepend_args (options, buf, NULL);
Packit cb4c47
      int argc = *pargc;
Packit cb4c47
      char *const *argv = *pargv;
Packit cb4c47
      char **pp;
Packit cb4c47
      enum { MAX_ARGS = MIN (INT_MAX, SIZE_MAX / sizeof *pp - 1) };
Packit cb4c47
      if (MAX_ARGS - argc < prepended)
Packit cb4c47
        xalloc_die ();
Packit cb4c47
      pp = xmalloc ((prepended + argc + 1) * sizeof *pp);
Packit cb4c47
      *pargc = prepended + argc;
Packit cb4c47
      *pargv = pp;
Packit cb4c47
      *pp++ = *argv++;
Packit cb4c47
      pp += prepend_args (options, buf, pp);
Packit cb4c47
      while ((*pp++ = *argv++))
Packit cb4c47
        continue;
Packit cb4c47
      return prepended;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return 0;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Get the next non-digit option from ARGC and ARGV.
Packit cb4c47
   Return -1 if there are no more options.
Packit cb4c47
   Process any digit options that were encountered on the way,
Packit cb4c47
   and store the resulting integer into *DEFAULT_CONTEXT.  */
Packit cb4c47
static int
Packit cb4c47
get_nondigit_option (int argc, char *const *argv, intmax_t *default_context)
Packit cb4c47
{
Packit cb4c47
  static int prev_digit_optind = -1;
Packit cb4c47
  int this_digit_optind;
Packit cb4c47
  bool was_digit;
Packit cb4c47
  char buf[INT_BUFSIZE_BOUND (intmax_t) + 4];
Packit cb4c47
  char *p = buf;
Packit cb4c47
  int opt;
Packit cb4c47
Packit cb4c47
  was_digit = false;
Packit cb4c47
  this_digit_optind = optind;
Packit cb4c47
  while (true)
Packit cb4c47
    {
Packit cb4c47
      opt = getopt_long (argc, (char **) argv, short_options,
Packit cb4c47
                         long_options, NULL);
Packit cb4c47
      if (! c_isdigit (opt))
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      if (prev_digit_optind != this_digit_optind || !was_digit)
Packit cb4c47
        {
Packit cb4c47
          /* Reset to start another context length argument.  */
Packit cb4c47
          p = buf;
Packit cb4c47
        }
Packit cb4c47
      else
Packit cb4c47
        {
Packit cb4c47
          /* Suppress trivial leading zeros, to avoid incorrect
Packit cb4c47
             diagnostic on strings like 00000000000.  */
Packit cb4c47
          p -= buf[0] == '0';
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      if (p == buf + sizeof buf - 4)
Packit cb4c47
        {
Packit cb4c47
          /* Too many digits.  Append "..." to make context_length_arg
Packit cb4c47
             complain about "X...", where X contains the digits seen
Packit cb4c47
             so far.  */
Packit cb4c47
          strcpy (p, "...");
Packit cb4c47
          p += 3;
Packit cb4c47
          break;
Packit cb4c47
        }
Packit cb4c47
      *p++ = opt;
Packit cb4c47
Packit cb4c47
      was_digit = true;
Packit cb4c47
      prev_digit_optind = this_digit_optind;
Packit cb4c47
      this_digit_optind = optind;
Packit cb4c47
    }
Packit cb4c47
  if (p != buf)
Packit cb4c47
    {
Packit cb4c47
      *p = '\0';
Packit cb4c47
      context_length_arg (buf, default_context);
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return opt;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Parse GREP_COLORS.  The default would look like:
Packit cb4c47
     GREP_COLORS='ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36'
Packit cb4c47
   with boolean capabilities (ne and rv) unset (i.e., omitted).
Packit cb4c47
   No character escaping is needed or supported.  */
Packit cb4c47
static void
Packit cb4c47
parse_grep_colors (void)
Packit cb4c47
{
Packit cb4c47
  const char *p;
Packit cb4c47
  char *q;
Packit cb4c47
  char *name;
Packit cb4c47
  char *val;
Packit cb4c47
Packit cb4c47
  p = getenv ("GREP_COLORS"); /* Plural! */
Packit cb4c47
  if (p == NULL || *p == '\0')
Packit cb4c47
    return;
Packit cb4c47
Packit cb4c47
  /* Work off a writable copy.  */
Packit cb4c47
  q = xstrdup (p);
Packit cb4c47
Packit cb4c47
  name = q;
Packit cb4c47
  val = NULL;
Packit cb4c47
  /* From now on, be well-formed or you're gone.  */
Packit cb4c47
  for (;;)
Packit cb4c47
    if (*q == ':' || *q == '\0')
Packit cb4c47
      {
Packit cb4c47
        char c = *q;
Packit cb4c47
        struct color_cap const *cap;
Packit cb4c47
Packit cb4c47
        *q++ = '\0'; /* Terminate name or val.  */
Packit cb4c47
        /* Empty name without val (empty cap)
Packit cb4c47
         * won't match and will be ignored.  */
Packit cb4c47
        for (cap = color_dict; cap->name; cap++)
Packit cb4c47
          if (STREQ (cap->name, name))
Packit cb4c47
            break;
Packit cb4c47
        /* If name unknown, go on for forward compatibility.  */
Packit cb4c47
        if (cap->var && val)
Packit cb4c47
          *(cap->var) = val;
Packit cb4c47
        if (cap->fct)
Packit cb4c47
          cap->fct ();
Packit cb4c47
        if (c == '\0')
Packit cb4c47
          return;
Packit cb4c47
        name = q;
Packit cb4c47
        val = NULL;
Packit cb4c47
      }
Packit cb4c47
    else if (*q == '=')
Packit cb4c47
      {
Packit cb4c47
        if (q == name || val)
Packit cb4c47
          return;
Packit cb4c47
        *q++ = '\0'; /* Terminate name.  */
Packit cb4c47
        val = q; /* Can be the empty string.  */
Packit cb4c47
      }
Packit cb4c47
    else if (val == NULL)
Packit cb4c47
      q++; /* Accumulate name.  */
Packit cb4c47
    else if (*q == ';' || c_isdigit (*q))
Packit cb4c47
      q++; /* Accumulate val.  Protect the terminal from being sent crap.  */
Packit cb4c47
    else
Packit cb4c47
      return;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return true if PAT (of length PATLEN) contains an encoding error.  */
Packit cb4c47
static bool
Packit cb4c47
contains_encoding_error (char const *pat, size_t patlen)
Packit cb4c47
{
Packit cb4c47
  mbstate_t mbs = { 0 };
Packit cb4c47
  size_t i, charlen;
Packit cb4c47
Packit cb4c47
  for (i = 0; i < patlen; i += charlen)
Packit cb4c47
    {
Packit cb4c47
      charlen = mb_clen (pat + i, patlen - i, &mbs);
Packit cb4c47
      if ((size_t) -2 <= charlen)
Packit cb4c47
        return true;
Packit cb4c47
    }
Packit cb4c47
  return false;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return the number of bytes in the initial character of PAT, of size
Packit cb4c47
   PATLEN, if Fcompile can handle that character.  Return -1 if
Packit cb4c47
   Fcompile cannot handle it.  MBS is the multibyte conversion state.
Packit cb4c47
Packit cb4c47
   Fcompile can handle a character C if C is single-byte, or if C has no
Packit cb4c47
   case folded counterparts and toupper translates none of its bytes.  */
Packit cb4c47
Packit cb4c47
static int
Packit cb4c47
fgrep_icase_charlen (char const *pat, size_t patlen, mbstate_t *mbs)
Packit cb4c47
{
Packit cb4c47
  int n = localeinfo.sbclen[to_uchar (*pat)];
Packit cb4c47
  if (n < 0)
Packit cb4c47
    {
Packit cb4c47
      wchar_t wc;
Packit cb4c47
      wchar_t folded[CASE_FOLDED_BUFSIZE];
Packit cb4c47
      size_t wn = mbrtowc (&wc, pat, patlen, mbs);
Packit cb4c47
      if (MB_LEN_MAX < wn || case_folded_counterparts (wc, folded))
Packit cb4c47
        return -1;
Packit cb4c47
      for (int i = wn; 0 < --i; )
Packit cb4c47
        {
Packit cb4c47
          unsigned char c = pat[i];
Packit cb4c47
          if (toupper (c) != c)
Packit cb4c47
            return -1;
Packit cb4c47
        }
Packit cb4c47
      n = wn;
Packit cb4c47
    }
Packit cb4c47
  return n;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Return true if the -F patterns PAT, of size PATLEN, contain only
Packit cb4c47
   single-byte characters or characters not subject to case folding,
Packit cb4c47
   and so can be processed by Fcompile.  */
Packit cb4c47
Packit cb4c47
static bool
Packit cb4c47
fgrep_icase_available (char const *pat, size_t patlen)
Packit cb4c47
{
Packit cb4c47
  mbstate_t mbs = {0,};
Packit cb4c47
Packit cb4c47
  for (size_t i = 0; i < patlen; )
Packit cb4c47
    {
Packit cb4c47
      int n = fgrep_icase_charlen (pat + i, patlen - i, &mbs);
Packit cb4c47
      if (n < 0)
Packit cb4c47
        return false;
Packit cb4c47
      i += n;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  return true;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* Change the pattern *KEYS_P, of size *LEN_P, from fgrep to grep style.  */
Packit cb4c47
Packit cb4c47
void
Packit cb4c47
fgrep_to_grep_pattern (char **keys_p, size_t *len_p)
Packit cb4c47
{
Packit cb4c47
  size_t len = *len_p;
Packit cb4c47
  char *keys = *keys_p;
Packit cb4c47
  mbstate_t mb_state = { 0 };
Packit cb4c47
  char *new_keys = xnmalloc (len + 1, 2);
Packit cb4c47
  char *p = new_keys;
Packit cb4c47
  size_t n;
Packit cb4c47
Packit cb4c47
  for (; len; keys += n, len -= n)
Packit cb4c47
    {
Packit cb4c47
      n = mb_clen (keys, len, &mb_state);
Packit cb4c47
      switch (n)
Packit cb4c47
        {
Packit cb4c47
        case (size_t) -2:
Packit cb4c47
          n = len;
Packit cb4c47
          FALLTHROUGH;
Packit cb4c47
        default:
Packit cb4c47
          p = mempcpy (p, keys, n);
Packit cb4c47
          break;
Packit cb4c47
Packit cb4c47
        case (size_t) -1:
Packit cb4c47
          memset (&mb_state, 0, sizeof mb_state);
Packit cb4c47
          n = 1;
Packit cb4c47
          FALLTHROUGH;
Packit cb4c47
        case 1:
Packit cb4c47
          switch (*keys)
Packit cb4c47
            {
Packit cb4c47
            case '$': case '*': case '.': case '[': case '\\': case '^':
Packit cb4c47
              *p++ = '\\'; break;
Packit cb4c47
            }
Packit cb4c47
          *p++ = *keys;
Packit cb4c47
          break;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  free (*keys_p);
Packit cb4c47
  *keys_p = new_keys;
Packit cb4c47
  *len_p = p - new_keys;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
/* If it is easy, convert the MATCHER-style patterns KEYS (of size
Packit cb4c47
   *LEN_P) to -F style, update *LEN_P to a possibly-smaller value, and
Packit cb4c47
   return F_MATCHER_INDEX.  If not, leave KEYS and *LEN_P alone and
Packit cb4c47
   return MATCHER.  This function is conservative and sometimes misses
Packit cb4c47
   conversions, e.g., it does not convert the -E pattern "(a|a|[aa])"
Packit cb4c47
   to the -F pattern "a".  */
Packit cb4c47
Packit cb4c47
static int
Packit cb4c47
try_fgrep_pattern (int matcher, char *keys, size_t *len_p)
Packit cb4c47
{
Packit cb4c47
  int result = matcher;
Packit cb4c47
  size_t len = *len_p;
Packit cb4c47
  char *new_keys = xmalloc (len + 1);
Packit cb4c47
  char *p = new_keys;
Packit cb4c47
  char const *q = keys;
Packit cb4c47
  mbstate_t mb_state = { 0 };
Packit cb4c47
Packit cb4c47
  while (len != 0)
Packit cb4c47
    {
Packit cb4c47
      switch (*q)
Packit cb4c47
        {
Packit cb4c47
        case '$': case '*': case '.': case '[': case '^':
Packit cb4c47
          goto fail;
Packit cb4c47
Packit cb4c47
        case '(': case '+': case '?': case '{': case '|':
Packit cb4c47
          if (matcher != G_MATCHER_INDEX)
Packit cb4c47
            goto fail;
Packit cb4c47
          break;
Packit cb4c47
Packit cb4c47
        case '\\':
Packit cb4c47
          if (1 < len)
Packit cb4c47
            switch (q[1])
Packit cb4c47
              {
Packit cb4c47
              case '\n':
Packit cb4c47
              case 'B': case 'S': case 'W': case'\'': case '<':
Packit cb4c47
              case 'b': case 's': case 'w': case '`': case '>':
Packit cb4c47
              case '1': case '2': case '3': case '4':
Packit cb4c47
              case '5': case '6': case '7': case '8': case '9':
Packit cb4c47
                goto fail;
Packit cb4c47
Packit cb4c47
              case '(': case '+': case '?': case '{': case '|':
Packit cb4c47
                if (matcher == G_MATCHER_INDEX)
Packit cb4c47
                  goto fail;
Packit cb4c47
                FALLTHROUGH;
Packit cb4c47
              default:
Packit cb4c47
                q++, len--;
Packit cb4c47
                break;
Packit cb4c47
              }
Packit cb4c47
          break;
Packit cb4c47
        }
Packit cb4c47
Packit cb4c47
      {
Packit cb4c47
        size_t n;
Packit cb4c47
        if (match_icase)
Packit cb4c47
          {
Packit cb4c47
            int ni = fgrep_icase_charlen (q, len, &mb_state);
Packit cb4c47
            if (ni < 0)
Packit cb4c47
              goto fail;
Packit cb4c47
            n = ni;
Packit cb4c47
          }
Packit cb4c47
        else
Packit cb4c47
          {
Packit cb4c47
            n = mb_clen (q, len, &mb_state);
Packit cb4c47
            if (MB_LEN_MAX < n)
Packit cb4c47
              goto fail;
Packit cb4c47
          }
Packit cb4c47
Packit cb4c47
        p = mempcpy (p, q, n);
Packit cb4c47
        q += n;
Packit cb4c47
        len -= n;
Packit cb4c47
      }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (*len_p != p - new_keys)
Packit cb4c47
    {
Packit cb4c47
      *len_p = p - new_keys;
Packit cb4c47
      memcpy (keys, new_keys, p - new_keys);
Packit cb4c47
    }
Packit cb4c47
  result = F_MATCHER_INDEX;
Packit cb4c47
Packit cb4c47
 fail:
Packit cb4c47
  free (new_keys);
Packit cb4c47
  return result;
Packit cb4c47
}
Packit cb4c47
Packit cb4c47
int
Packit cb4c47
main (int argc, char **argv)
Packit cb4c47
{
Packit cb4c47
  char *keys = NULL;
Packit cb4c47
  size_t keycc = 0, oldcc, keyalloc = 0;
Packit cb4c47
  int matcher = -1;
Packit cb4c47
  bool with_filenames = false;
Packit cb4c47
  size_t cc;
Packit cb4c47
  int opt, prepended;
Packit cb4c47
  int prev_optind, last_recursive;
Packit cb4c47
  int fread_errno;
Packit cb4c47
  intmax_t default_context;
Packit cb4c47
  FILE *fp;
Packit cb4c47
  exit_failure = EXIT_TROUBLE;
Packit cb4c47
  initialize_main (&argc, &argv);
Packit cb4c47
Packit cb4c47
  eolbyte = '\n';
Packit cb4c47
  filename_mask = ~0;
Packit cb4c47
Packit cb4c47
  max_count = INTMAX_MAX;
Packit cb4c47
Packit cb4c47
  /* The value -1 means to use DEFAULT_CONTEXT. */
Packit cb4c47
  out_after = out_before = -1;
Packit cb4c47
  /* Default before/after context: changed by -C/-NUM options */
Packit cb4c47
  default_context = -1;
Packit cb4c47
  /* Changed by -o option */
Packit cb4c47
  only_matching = false;
Packit cb4c47
Packit cb4c47
  /* Internationalization. */
Packit cb4c47
#if defined HAVE_SETLOCALE
Packit cb4c47
  setlocale (LC_ALL, "");
Packit cb4c47
#endif
Packit cb4c47
#if defined ENABLE_NLS
Packit cb4c47
  bindtextdomain (PACKAGE, LOCALEDIR);
Packit cb4c47
  textdomain (PACKAGE);
Packit cb4c47
#endif
Packit cb4c47
Packit cb4c47
  init_localeinfo (&localeinfo);
Packit cb4c47
Packit cb4c47
  atexit (clean_up_stdout);
Packit cb4c47
Packit cb4c47
  last_recursive = 0;
Packit cb4c47
Packit cb4c47
  prepended = prepend_default_options (getenv ("GREP_OPTIONS"), &argc, &argv);
Packit cb4c47
  if (prepended)
Packit cb4c47
    error (0, 0, _("warning: GREP_OPTIONS is deprecated;"
Packit cb4c47
                   " please use an alias or script"));
Packit cb4c47
Packit cb4c47
  while (prev_optind = optind,
Packit cb4c47
         (opt = get_nondigit_option (argc, argv, &default_context)) != -1)
Packit cb4c47
    switch (opt)
Packit cb4c47
      {
Packit cb4c47
      case 'A':
Packit cb4c47
        context_length_arg (optarg, &out_after);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'B':
Packit cb4c47
        context_length_arg (optarg, &out_before);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'C':
Packit cb4c47
        /* Set output match context, but let any explicit leading or
Packit cb4c47
           trailing amount specified with -A or -B stand. */
Packit cb4c47
        context_length_arg (optarg, &default_context);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'D':
Packit cb4c47
        if (STREQ (optarg, "read"))
Packit cb4c47
          devices = READ_DEVICES;
Packit cb4c47
        else if (STREQ (optarg, "skip"))
Packit cb4c47
          devices = SKIP_DEVICES;
Packit cb4c47
        else
Packit cb4c47
          die (EXIT_TROUBLE, 0, _("unknown devices method"));
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'E':
Packit cb4c47
        matcher = setmatcher ("egrep", matcher);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'F':
Packit cb4c47
        matcher = setmatcher ("fgrep", matcher);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'P':
Packit cb4c47
        matcher = setmatcher ("perl", matcher);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'G':
Packit cb4c47
        matcher = setmatcher ("grep", matcher);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'X': /* undocumented on purpose */
Packit cb4c47
        matcher = setmatcher (optarg, matcher);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'H':
Packit cb4c47
        with_filenames = true;
Packit cb4c47
        no_filenames = false;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'I':
Packit cb4c47
        binary_files = WITHOUT_MATCH_BINARY_FILES;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'T':
Packit cb4c47
        align_tabs = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'U':
Packit cb4c47
        if (O_BINARY)
Packit cb4c47
          binary = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'u':
Packit cb4c47
        /* Obsolete option; it has no effect.  FIXME: Diagnose use of
Packit cb4c47
           this option starting in (say) the year 2020.  */
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'V':
Packit cb4c47
        show_version = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'a':
Packit cb4c47
        binary_files = TEXT_BINARY_FILES;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'b':
Packit cb4c47
        out_byte = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'c':
Packit cb4c47
        count_matches = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'd':
Packit cb4c47
        directories = XARGMATCH ("--directories", optarg,
Packit cb4c47
                                 directories_args, directories_types);
Packit cb4c47
        if (directories == RECURSE_DIRECTORIES)
Packit cb4c47
          last_recursive = prev_optind;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'e':
Packit cb4c47
        cc = strlen (optarg);
Packit cb4c47
        if (keyalloc < keycc + cc + 1)
Packit cb4c47
          {
Packit cb4c47
            keyalloc = keycc + cc + 1;
Packit cb4c47
            keys = x2realloc (keys, &keyalloc);
Packit cb4c47
          }
Packit cb4c47
        oldcc = keycc;
Packit cb4c47
        memcpy (keys + oldcc, optarg, cc);
Packit cb4c47
        keycc += cc;
Packit cb4c47
        keys[keycc++] = '\n';
Packit cb4c47
        fl_add (keys + oldcc, cc + 1, "");
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'f':
Packit cb4c47
        if (STREQ (optarg, "-"))
Packit cb4c47
          {
Packit cb4c47
            if (binary)
Packit cb4c47
              xset_binary_mode (STDIN_FILENO, O_BINARY);
Packit cb4c47
            fp = stdin;
Packit cb4c47
          }
Packit cb4c47
        else
Packit cb4c47
          {
Packit cb4c47
            fp = fopen (optarg, binary ? "rb" : "r");
Packit cb4c47
            if (!fp)
Packit cb4c47
              die (EXIT_TROUBLE, errno, "%s", optarg);
Packit cb4c47
          }
Packit cb4c47
        oldcc = keycc;
Packit cb4c47
        for (;; keycc += cc)
Packit cb4c47
          {
Packit cb4c47
            if (keyalloc <= keycc + 1)
Packit cb4c47
              keys = x2realloc (keys, &keyalloc);
Packit cb4c47
            cc = fread (keys + keycc, 1, keyalloc - (keycc + 1), fp);
Packit cb4c47
            if (cc == 0)
Packit cb4c47
              break;
Packit cb4c47
          }
Packit cb4c47
        fread_errno = errno;
Packit cb4c47
        if (ferror (fp))
Packit cb4c47
          die (EXIT_TROUBLE, fread_errno, "%s", optarg);
Packit cb4c47
        if (fp != stdin)
Packit cb4c47
          fclose (fp);
Packit cb4c47
        /* Append final newline if file ended in non-newline. */
Packit cb4c47
        if (oldcc != keycc && keys[keycc - 1] != '\n')
Packit cb4c47
          keys[keycc++] = '\n';
Packit cb4c47
        fl_add (keys + oldcc, keycc - oldcc, optarg);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'h':
Packit cb4c47
        with_filenames = false;
Packit cb4c47
        no_filenames = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'i':
Packit cb4c47
      case 'y':			/* For old-timers . . . */
Packit cb4c47
        match_icase = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'L':
Packit cb4c47
        /* Like -l, except list files that don't contain matches.
Packit cb4c47
           Inspired by the same option in Hume's gre. */
Packit cb4c47
        list_files = LISTFILES_NONMATCHING;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'l':
Packit cb4c47
        list_files = LISTFILES_MATCHING;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'm':
Packit cb4c47
        switch (xstrtoimax (optarg, 0, 10, &max_count, ""))
Packit cb4c47
          {
Packit cb4c47
          case LONGINT_OK:
Packit cb4c47
          case LONGINT_OVERFLOW:
Packit cb4c47
            break;
Packit cb4c47
Packit cb4c47
          default:
Packit cb4c47
            die (EXIT_TROUBLE, 0, _("invalid max count"));
Packit cb4c47
          }
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'n':
Packit cb4c47
        out_line = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'o':
Packit cb4c47
        only_matching = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'q':
Packit cb4c47
        exit_on_match = true;
Packit cb4c47
        exit_failure = 0;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'R':
Packit cb4c47
        fts_options = basic_fts_options | FTS_LOGICAL;
Packit cb4c47
        FALLTHROUGH;
Packit cb4c47
      case 'r':
Packit cb4c47
        directories = RECURSE_DIRECTORIES;
Packit cb4c47
        last_recursive = prev_optind;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 's':
Packit cb4c47
        suppress_errors = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'v':
Packit cb4c47
        out_invert = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'w':
Packit cb4c47
        wordinit ();
Packit cb4c47
        match_words = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'x':
Packit cb4c47
        match_lines = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'Z':
Packit cb4c47
        filename_mask = 0;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 'z':
Packit cb4c47
        eolbyte = '\0';
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case BINARY_FILES_OPTION:
Packit cb4c47
        if (STREQ (optarg, "binary"))
Packit cb4c47
          binary_files = BINARY_BINARY_FILES;
Packit cb4c47
        else if (STREQ (optarg, "text"))
Packit cb4c47
          binary_files = TEXT_BINARY_FILES;
Packit cb4c47
        else if (STREQ (optarg, "without-match"))
Packit cb4c47
          binary_files = WITHOUT_MATCH_BINARY_FILES;
Packit cb4c47
        else
Packit cb4c47
          die (EXIT_TROUBLE, 0, _("unknown binary-files type"));
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case COLOR_OPTION:
Packit cb4c47
        if (optarg)
Packit cb4c47
          {
Packit cb4c47
            if (!strcasecmp (optarg, "always") || !strcasecmp (optarg, "yes")
Packit cb4c47
                || !strcasecmp (optarg, "force"))
Packit cb4c47
              color_option = 1;
Packit cb4c47
            else if (!strcasecmp (optarg, "never") || !strcasecmp (optarg, "no")
Packit cb4c47
                     || !strcasecmp (optarg, "none"))
Packit cb4c47
              color_option = 0;
Packit cb4c47
            else if (!strcasecmp (optarg, "auto") || !strcasecmp (optarg, "tty")
Packit cb4c47
                     || !strcasecmp (optarg, "if-tty"))
Packit cb4c47
              color_option = 2;
Packit cb4c47
            else
Packit cb4c47
              show_help = 1;
Packit cb4c47
          }
Packit cb4c47
        else
Packit cb4c47
          color_option = 2;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case EXCLUDE_OPTION:
Packit cb4c47
      case INCLUDE_OPTION:
Packit cb4c47
        for (int cmd = 0; cmd < 2; cmd++)
Packit cb4c47
          {
Packit cb4c47
            if (!excluded_patterns[cmd])
Packit cb4c47
              excluded_patterns[cmd] = new_exclude ();
Packit cb4c47
            add_exclude (excluded_patterns[cmd], optarg,
Packit cb4c47
                         ((opt == INCLUDE_OPTION ? EXCLUDE_INCLUDE : 0)
Packit cb4c47
                          | exclude_options (cmd)));
Packit cb4c47
          }
Packit cb4c47
        break;
Packit cb4c47
      case EXCLUDE_FROM_OPTION:
Packit cb4c47
        for (int cmd = 0; cmd < 2; cmd++)
Packit cb4c47
          {
Packit cb4c47
            if (!excluded_patterns[cmd])
Packit cb4c47
              excluded_patterns[cmd] = new_exclude ();
Packit cb4c47
            if (add_exclude_file (add_exclude, excluded_patterns[cmd],
Packit cb4c47
                                  optarg, exclude_options (cmd), '\n')
Packit cb4c47
                != 0)
Packit cb4c47
              die (EXIT_TROUBLE, errno, "%s", optarg);
Packit cb4c47
          }
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case EXCLUDE_DIRECTORY_OPTION:
Packit cb4c47
        strip_trailing_slashes (optarg);
Packit cb4c47
        for (int cmd = 0; cmd < 2; cmd++)
Packit cb4c47
          {
Packit cb4c47
            if (!excluded_directory_patterns[cmd])
Packit cb4c47
              excluded_directory_patterns[cmd] = new_exclude ();
Packit cb4c47
            add_exclude (excluded_directory_patterns[cmd], optarg,
Packit cb4c47
                         exclude_options (cmd));
Packit cb4c47
          }
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case GROUP_SEPARATOR_OPTION:
Packit cb4c47
        group_separator = optarg;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case LINE_BUFFERED_OPTION:
Packit cb4c47
        line_buffered = true;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case LABEL_OPTION:
Packit cb4c47
        label = optarg;
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      case 0:
Packit cb4c47
        /* long options */
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      default:
Packit cb4c47
        usage (EXIT_TROUBLE);
Packit cb4c47
        break;
Packit cb4c47
Packit cb4c47
      }
Packit cb4c47
Packit cb4c47
  if (show_version)
Packit cb4c47
    {
Packit cb4c47
      version_etc (stdout, getprogname (), PACKAGE_NAME, VERSION, AUTHORS,
Packit cb4c47
                   (char *) NULL);
Packit cb4c47
      return EXIT_SUCCESS;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  if (show_help)
Packit cb4c47
    usage (EXIT_SUCCESS);
Packit cb4c47
Packit cb4c47
  if (keys)
Packit cb4c47
    {
Packit cb4c47
      if (keycc == 0)
Packit cb4c47
        {
Packit cb4c47
          /* No keys were specified (e.g. -f /dev/null).  Match nothing.  */
Packit cb4c47
          out_invert ^= true;
Packit cb4c47
          match_lines = match_words = false;
Packit cb4c47
        }
Packit cb4c47
      else
Packit cb4c47
        /* Strip trailing newline. */
Packit cb4c47
        --keycc;
Packit cb4c47
    }
Packit cb4c47
  else if (optind < argc)
Packit cb4c47
    {
Packit cb4c47
      /* Make a copy so that it can be reallocated or freed later.  */
Packit cb4c47
      keycc = strlen (argv[optind]);
Packit cb4c47
      keys = xmemdup (argv[optind++], keycc + 1);
Packit cb4c47
      fl_add (keys, keycc, "");
Packit cb4c47
      n_patterns++;
Packit cb4c47
    }
Packit cb4c47
  else
Packit cb4c47
    usage (EXIT_TROUBLE);
Packit cb4c47
Packit cb4c47
  bool possibly_tty = false;
Packit cb4c47
  struct stat tmp_stat;
Packit cb4c47
  if (! exit_on_match && fstat (STDOUT_FILENO, &tmp_stat) == 0)
Packit cb4c47
    {
Packit cb4c47
      if (S_ISREG (tmp_stat.st_mode))
Packit cb4c47
        out_stat = tmp_stat;
Packit cb4c47
      else if (S_ISCHR (tmp_stat.st_mode))
Packit cb4c47
        {
Packit cb4c47
          struct stat null_stat;
Packit cb4c47
          if (stat ("/dev/null", &null_stat) == 0
Packit cb4c47
              && SAME_INODE (tmp_stat, null_stat))
Packit cb4c47
            dev_null_output = true;
Packit cb4c47
          else
Packit cb4c47
            possibly_tty = true;
Packit cb4c47
        }
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  /* POSIX says -c, -l and -q are mutually exclusive.  In this
Packit cb4c47
     implementation, -q overrides -l and -L, which in turn override -c.  */
Packit cb4c47
  if (exit_on_match | dev_null_output)
Packit cb4c47
    list_files = LISTFILES_NONE;
Packit cb4c47
  if ((exit_on_match | dev_null_output) || list_files != LISTFILES_NONE)
Packit cb4c47
    {
Packit cb4c47
      count_matches = false;
Packit cb4c47
      done_on_match = true;
Packit cb4c47
    }
Packit cb4c47
  out_quiet = count_matches | done_on_match;
Packit cb4c47
Packit cb4c47
  if (out_after < 0)
Packit cb4c47
    out_after = default_context;
Packit cb4c47
  if (out_before < 0)
Packit cb4c47
    out_before = default_context;
Packit cb4c47
Packit cb4c47
  /* If it is easy to see that matching cannot succeed (e.g., 'grep -f
Packit cb4c47
     /dev/null'), fail without reading the input.  */
Packit cb4c47
  if ((max_count == 0
Packit cb4c47
       || (keycc == 0 && out_invert && !match_lines && !match_words))
Packit cb4c47
      && list_files != LISTFILES_NONMATCHING)
Packit cb4c47
    return EXIT_FAILURE;
Packit cb4c47
Packit cb4c47
  if (color_option == 2)
Packit cb4c47
    color_option = possibly_tty && should_colorize () && isatty (STDOUT_FILENO);
Packit cb4c47
  init_colorize ();
Packit cb4c47
Packit cb4c47
  if (color_option)
Packit cb4c47
    {
Packit cb4c47
      /* Legacy.  */
Packit cb4c47
      char *userval = getenv ("GREP_COLOR");
Packit cb4c47
      if (userval != NULL && *userval != '\0')
Packit cb4c47
        selected_match_color = context_match_color = userval;
Packit cb4c47
Packit cb4c47
      /* New GREP_COLORS has priority.  */
Packit cb4c47
      parse_grep_colors ();
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  initialize_unibyte_mask ();
Packit cb4c47
Packit cb4c47
  if (matcher < 0)
Packit cb4c47
    matcher = G_MATCHER_INDEX;
Packit cb4c47
Packit cb4c47
  /* In a single-byte locale, switch from -F to -G if it is a single
Packit cb4c47
     pattern that matches words, where -G is typically faster.  In a
Packit cb4c47
     multi-byte locale, switch if the patterns have an encoding error
Packit cb4c47
     (where -F does not work) or if -i and the patterns will not work
Packit cb4c47
     for -iF.  */
Packit cb4c47
  if (matcher == F_MATCHER_INDEX
Packit cb4c47
      && (! localeinfo.multibyte
Packit cb4c47
          ? n_patterns == 1 && match_words
Packit cb4c47
          : (contains_encoding_error (keys, keycc)
Packit cb4c47
             || (match_icase && !fgrep_icase_available (keys, keycc)))))
Packit cb4c47
    {
Packit cb4c47
      fgrep_to_grep_pattern (&keys, &keycc);
Packit cb4c47
      matcher = G_MATCHER_INDEX;
Packit cb4c47
    }
Packit cb4c47
  /* With two or more patterns, if -F works then switch from either -E
Packit cb4c47
     or -G, as -F is probably faster then.  */
Packit cb4c47
  else if ((matcher == G_MATCHER_INDEX || matcher == E_MATCHER_INDEX)
Packit cb4c47
           && 1 < n_patterns)
Packit cb4c47
    matcher = try_fgrep_pattern (matcher, keys, &keycc);
Packit cb4c47
Packit cb4c47
  execute = matchers[matcher].execute;
Packit cb4c47
  compiled_pattern = matchers[matcher].compile (keys, keycc,
Packit cb4c47
                                                matchers[matcher].syntax);
Packit cb4c47
  /* We need one byte prior and one after.  */
Packit cb4c47
  char eolbytes[3] = { 0, eolbyte, 0 };
Packit cb4c47
  size_t match_size;
Packit cb4c47
  skip_empty_lines = ((execute (compiled_pattern, eolbytes + 1, 1,
Packit cb4c47
                                &match_size, NULL) == 0)
Packit cb4c47
                      == out_invert);
Packit cb4c47
Packit cb4c47
  if ((argc - optind > 1 && !no_filenames) || with_filenames)
Packit cb4c47
    out_file = 1;
Packit cb4c47
Packit cb4c47
  if (binary)
Packit cb4c47
    xset_binary_mode (STDOUT_FILENO, O_BINARY);
Packit cb4c47
Packit cb4c47
  /* Prefer sysconf for page size, as getpagesize typically returns int.  */
Packit cb4c47
#ifdef _SC_PAGESIZE
Packit cb4c47
  long psize = sysconf (_SC_PAGESIZE);
Packit cb4c47
#else
Packit cb4c47
  long psize = getpagesize ();
Packit cb4c47
#endif
Packit cb4c47
  if (! (0 < psize && psize <= (SIZE_MAX - sizeof (uword)) / 2))
Packit cb4c47
    abort ();
Packit cb4c47
  pagesize = psize;
Packit cb4c47
  bufalloc = ALIGN_TO (INITIAL_BUFSIZE, pagesize) + pagesize + sizeof (uword);
Packit cb4c47
  buffer = xmalloc (bufalloc);
Packit cb4c47
Packit cb4c47
  if (fts_options & FTS_LOGICAL && devices == READ_COMMAND_LINE_DEVICES)
Packit cb4c47
    devices = READ_DEVICES;
Packit cb4c47
Packit cb4c47
  char *const *files;
Packit cb4c47
  if (optind < argc)
Packit cb4c47
    {
Packit cb4c47
      files = argv + optind;
Packit cb4c47
    }
Packit cb4c47
  else if (directories == RECURSE_DIRECTORIES && prepended < last_recursive)
Packit cb4c47
    {
Packit cb4c47
      static char *const cwd_only[] = { (char *) ".", NULL };
Packit cb4c47
      files = cwd_only;
Packit cb4c47
      omit_dot_slash = true;
Packit cb4c47
    }
Packit cb4c47
  else
Packit cb4c47
    {
Packit cb4c47
      static char *const stdin_only[] = { (char *) "-", NULL };
Packit cb4c47
      files = stdin_only;
Packit cb4c47
    }
Packit cb4c47
Packit cb4c47
  bool status = true;
Packit cb4c47
  do
Packit cb4c47
    status &= grep_command_line_arg (*files++);
Packit cb4c47
  while (*files != NULL);
Packit cb4c47
Packit cb4c47
  /* We register via atexit to test stdout.  */
Packit cb4c47
  return errseen ? EXIT_TROUBLE : status;
Packit cb4c47
}