Blame src/grep.c

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