Upgrade grep from 2.12 to 2.14 on the vendor branch avalon/vendor/GREP
authorJohn Marino <draco@marino.st>
Tue, 23 Apr 2013 14:44:50 +0000 (16:44 +0200)
committerJohn Marino <draco@marino.st>
Tue, 23 Apr 2013 17:51:03 +0000 (19:51 +0200)
25 files changed:
contrib/grep/doc/grep.texi
contrib/grep/doc/version.texi
contrib/grep/lib/binary-io.h
contrib/grep/lib/colorize-w32.c
contrib/grep/lib/config.charset
contrib/grep/lib/exclude.c
contrib/grep/lib/fpending.h
contrib/grep/lib/fstat.c
contrib/grep/lib/gettext.h
contrib/grep/lib/gnulib.mk
contrib/grep/lib/ignore-value.h
contrib/grep/lib/localcharset.c
contrib/grep/lib/mbsrtowcs-state.c
contrib/grep/lib/regcomp.c
contrib/grep/lib/regexec.c
contrib/grep/lib/stat.c
contrib/grep/lib/strerror-override.c
contrib/grep/lib/strerror-override.h
contrib/grep/lib/verify.h
contrib/grep/src/dfa.c
contrib/grep/src/dfasearch.c
contrib/grep/src/kwsearch.c
contrib/grep/src/main.c
contrib/grep/src/search.h
contrib/grep/src/searchutils.c

index 000a844..0e519dd 100644 (file)
@@ -261,7 +261,7 @@ for bold red matched text, magenta file names, green line numbers,
 green byte offsets, cyan separators, and default terminal colors otherwise.
 The deprecated environment variable @env{GREP_COLOR} is still supported,
 but its setting does not have priority;
-it defaults to `01;31' (bold red)
+it defaults to @samp{01;31} (bold red)
 which only covers the color for matched text.
 @var{WHEN} is @samp{never}, @samp{always}, or @samp{auto}.
 
@@ -580,7 +580,8 @@ this is equivalent to the @samp{--binary-files=text} option.
 @item --binary-files=@var{type}
 @opindex --binary-files
 @cindex binary files
-If the first few bytes of a file indicate that the file contains binary data,
+If a file's allocation metadata or its first few bytes
+indicate that the file contains binary data,
 assume that the file is of type @var{type}.
 By default, @var{type} is @samp{binary},
 and @command{grep} normally outputs either
@@ -722,8 +723,8 @@ better performance.
 @cindex binary files, MS-DOS/MS-Windows
 Treat the file(s) as binary.
 By default, under MS-DOS and MS-Windows,
-@command{grep} guesses the file type
-by looking at the contents of the first 32kB read from the file.
+@command{grep} guesses whether a file is text or binary
+as described for the @option{--binary-files} option.
 If @command{grep} decides the file is a text file,
 it strips the @code{CR} characters from the original file contents
 (to make regular expressions with @code{^} and @code{$} work correctly).
index 6e38f06..efdb0e5 100644 (file)
@@ -1,4 +1,4 @@
-@set UPDATED 17 April 2012
-@set UPDATED-MONTH April 2012
-@set EDITION 2.12
-@set VERSION 2.12
+@set UPDATED 15 May 2012
+@set UPDATED-MONTH May 2012
+@set EDITION 2.14
+@set VERSION 2.14
index 824ad5b..a33e32a 100644 (file)
    so we include it here first.  */
 #include <stdio.h>
 
-/* SET_BINARY (fd);
-   changes the file descriptor fd to perform binary I/O.  */
+/* set_binary_mode (fd, mode)
+   sets the binary/text I/O mode of file descriptor fd to the given mode
+   (must be O_BINARY or O_TEXT) and returns the previous mode.  */
 #if O_BINARY
 # if defined __EMX__ || defined __DJGPP__ || defined __CYGWIN__
 #  include <io.h> /* declares setmode() */
+#  define set_binary_mode setmode
 # else
-#  define setmode _setmode
+#  define set_binary_mode _setmode
 #  undef fileno
 #  define fileno _fileno
 # endif
-# ifdef __DJGPP__
-#  include <unistd.h> /* declares isatty() */
-   /* Avoid putting stdin/stdout in binary mode if it is connected to
-      the console, because that would make it impossible for the user
-      to interrupt the program through Ctrl-C or Ctrl-Break.  */
-#  define SET_BINARY(fd) ((void) (!isatty (fd) ? (setmode (fd, O_BINARY), 0) : 0))
-# else
-#  define SET_BINARY(fd) ((void) setmode (fd, O_BINARY))
-# endif
 #else
-  /* On reasonable systems, binary I/O is the default.  */
-# define SET_BINARY(fd) /* do nothing */ ((void) 0)
+  /* On reasonable systems, binary I/O is the only choice.  */
+  /* Use an inline function rather than a macro, to avoid gcc warnings
+     "warning: statement with no effect".  */
+static inline int
+set_binary_mode (int fd, int mode)
+{
+  (void) fd;
+  (void) mode;
+  return O_BINARY;
+}
+#endif
+
+/* SET_BINARY (fd);
+   changes the file descriptor fd to perform binary I/O.  */
+#ifdef __DJGPP__
+# include <unistd.h> /* declares isatty() */
+  /* Avoid putting stdin/stdout in binary mode if it is connected to
+     the console, because that would make it impossible for the user
+     to interrupt the program through Ctrl-C or Ctrl-Break.  */
+# define SET_BINARY(fd) ((void) (!isatty (fd) ? (set_binary_mode (fd, O_BINARY), 0) : 0))
+#else
+# define SET_BINARY(fd) ((void) set_binary_mode (fd, O_BINARY))
 #endif
 
 #endif /* _BINARY_H */
index 7341fe2..3fcd317 100644 (file)
@@ -173,7 +173,7 @@ print_start_colorize (char const *sgr_start, char const *sgr_seq)
 /* Clear to the end of the current line with the default attribute.
    This is needed for reasons similar to those that require the "EL to
    Right after SGR" operation on Posix platforms: if we don't do this,
-   setting the `mt', `ms', or `mc' capabilities to use a non-default
+   setting the 'mt', 'ms', or 'mc' capabilities to use a non-default
    background color spills that color to the empty space at the end of
    the last screen line in a match whose line spans multiple screen
    lines.  */
index 89b3017..0a3b343 100644 (file)
@@ -29,7 +29,7 @@
 # The current list of GNU canonical charset names is as follows.
 #
 #       name              MIME?             used by which systems
-#                                    (darwin = MacOS X, woe32 = native Windows)
+#                                    (darwin = Mac OS X, woe32 = native Windows)
 #
 #   ASCII, ANSI_X3.4-1968       glibc solaris freebsd netbsd darwin cygwin
 #   ISO-8859-1              Y   glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin
index bc3e6e6..08a4829 100644 (file)
@@ -104,53 +104,46 @@ struct exclude_segment
     } v;
   };
 
-/* The exclude structure keeps a singly-linked list of exclude segments */
+/* The exclude structure keeps a singly-linked list of exclude segments,
+   maintained in reverse order.  */
 struct exclude
   {
-    struct exclude_segment *head, *tail;
+    struct exclude_segment *head;
   };
 
-/* Return true if str has wildcard characters */
+/* Return true if STR has or may have wildcards, when matched with OPTIONS.
+   Return false if STR definitely does not have wildcards.  */
 bool
 fnmatch_pattern_has_wildcards (const char *str, int options)
 {
-  const char *cset = "\\?*[]";
-  if (options & FNM_NOESCAPE)
-    cset++;
-  while (*str)
+  while (1)
     {
-      size_t n = strcspn (str, cset);
-      if (str[n] == 0)
-        break;
-      else if (str[n] == '\\')
+      switch (*str++)
         {
-          str += n + 1;
-          if (*str)
-            str++;
+        case '\\':
+          str += ! (options & FNM_NOESCAPE) && *str;
+          break;
+
+        case '+': case '@': case '!':
+          if (options & FNM_EXTMATCH && *str == '(')
+            return true;
+          break;
+
+        case '?': case '*': case '[':
+          return true;
+
+        case '\0':
+          return false;
         }
-      else
-        return true;
     }
-  return false;
 }
 
 static void
 unescape_pattern (char *str)
 {
-  int inset = 0;
-  char *q = str;
+  char const *q = str;
   do
-    {
-      if (inset)
-        {
-          if (*q == ']')
-            inset = 0;
-        }
-      else if (*q == '[')
-        inset = 1;
-      else if (*q == '\\')
-        q++;
-    }
+    q += *q == '\\' && q[1];
   while ((*str++ = *q++));
 }
 
@@ -219,8 +212,8 @@ string_free (void *data)
 }
 
 /* Create new exclude segment of given TYPE and OPTIONS, and attach it
-   to the tail of list in EX */
-static struct exclude_segment *
+   to the head of EX.  */
+static void
 new_exclude_segment (struct exclude *ex, enum exclude_type type, int options)
 {
   struct exclude_segment *sp = xzalloc (sizeof (struct exclude_segment));
@@ -242,12 +235,8 @@ new_exclude_segment (struct exclude *ex, enum exclude_type type, int options)
                                      string_free);
       break;
     }
-  if (ex->tail)
-    ex->tail->next = sp;
-  else
-    ex->head = sp;
-  ex->tail = sp;
-  return sp;
+  sp->next = ex->head;
+  ex->head = sp;
 }
 
 /* Free a single exclude segment */
@@ -347,36 +336,33 @@ exclude_fnmatch (char const *pattern, char const *f, int options)
   return matched;
 }
 
-/* Return true if the exclude_pattern segment SEG excludes F.  */
+/* Return true if the exclude_pattern segment SEG matches F.  */
 
 static bool
-excluded_file_pattern_p (struct exclude_segment const *seg, char const *f)
+file_pattern_matches (struct exclude_segment const *seg, char const *f)
 {
   size_t exclude_count = seg->v.pat.exclude_count;
   struct patopts const *exclude = seg->v.pat.exclude;
   size_t i;
-  bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
 
-  /* Scan through the options, until they change excluded */
   for (i = 0; i < exclude_count; i++)
     {
       char const *pattern = exclude[i].pattern;
       int options = exclude[i].options;
       if (exclude_fnmatch (pattern, f, options))
-        return !excluded;
+        return true;
     }
-  return excluded;
+  return false;
 }
 
-/* Return true if the exclude_hash segment SEG excludes F.
+/* Return true if the exclude_hash segment SEG matches F.
    BUFFER is an auxiliary storage of the same length as F (with nul
    terminator included) */
 static bool
-excluded_file_name_p (struct exclude_segment const *seg, char const *f,
-                      char *buffer)
+file_name_matches (struct exclude_segment const *seg, char const *f,
+                   char *buffer)
 {
   int options = seg->options;
-  bool excluded = !! (options & EXCLUDE_INCLUDE);
   Hash_table *table = seg->v.table;
 
   do
@@ -387,7 +373,7 @@ excluded_file_name_p (struct exclude_segment const *seg, char const *f,
       while (1)
         {
           if (hash_lookup (table, buffer))
-            return !excluded;
+            return true;
           if (options & FNM_LEADING_DIR)
             {
               char *p = strrchr (buffer, '/');
@@ -410,7 +396,8 @@ excluded_file_name_p (struct exclude_segment const *seg, char const *f,
         break;
     }
   while (f);
-  return excluded;
+
+  return false;
 }
 
 /* Return true if EX excludes F.  */
@@ -419,44 +406,46 @@ bool
 excluded_file_name (struct exclude const *ex, char const *f)
 {
   struct exclude_segment *seg;
-  bool excluded;
+  bool invert = false;
   char *filename = NULL;
 
   /* If no patterns are given, the default is to include.  */
   if (!ex->head)
     return false;
 
-  /* Otherwise, the default is the opposite of the first option.  */
-  excluded = !! (ex->head->options & EXCLUDE_INCLUDE);
-  /* Scan through the segments, seeing whether they change status from
-     excluded to included or vice versa.  */
-  for (seg = ex->head; seg; seg = seg->next)
+  /* Scan through the segments, reporting the status of the first match.
+     The segments are in reverse order, so this reports the status of
+     the last match in the original option list.  */
+  for (seg = ex->head; ; seg = seg->next)
     {
-      bool rc;
-
-      switch (seg->type)
+      if (seg->type == exclude_hash)
         {
-        case exclude_pattern:
-          rc = excluded_file_pattern_p (seg, f);
-          break;
-
-        case exclude_hash:
           if (!filename)
             filename = xmalloc (strlen (f) + 1);
-          rc = excluded_file_name_p (seg, f, filename);
-          break;
-
-        default:
-          abort ();
+          if (file_name_matches (seg, f, filename))
+            break;
         }
-      if (rc != excluded)
+      else
+        {
+          if (file_pattern_matches (seg, f))
+            break;
+        }
+
+      if (! seg->next)
         {
-          excluded = rc;
+          /* If patterns are given but none match, the default is the
+             opposite of the last segment (i.e., the first in the
+             original option list).  For example, in the command
+             'grep -r --exclude="a*" --include="*b" pat dir', the
+             first option is --exclude so any file name matching
+             neither a* nor *b is included.  */
+          invert = true;
           break;
         }
     }
+
   free (filename);
-  return excluded;
+  return invert ^ ! (seg->options & EXCLUDE_INCLUDE);
 }
 
 /* Append to EX the exclusion PATTERN with OPTIONS.  */
@@ -472,12 +461,11 @@ add_exclude (struct exclude *ex, char const *pattern, int options)
       struct exclude_pattern *pat;
       struct patopts *patopts;
 
-      if (ex->tail && ex->tail->type == exclude_pattern
-          && ((ex->tail->options & EXCLUDE_INCLUDE) ==
-              (options & EXCLUDE_INCLUDE)))
-        seg = ex->tail;
-      else
-        seg = new_exclude_segment (ex, exclude_pattern, options);
+      if (! (ex->head && ex->head->type == exclude_pattern
+             && ((ex->head->options & EXCLUDE_INCLUDE)
+                 == (options & EXCLUDE_INCLUDE))))
+        new_exclude_segment (ex, exclude_pattern, options);
+      seg = ex->head;
 
       pat = &seg->v.pat;
       if (pat->exclude_count == pat->exclude_alloc)
@@ -490,17 +478,16 @@ add_exclude (struct exclude *ex, char const *pattern, int options)
   else
     {
       char *str, *p;
-#define EXCLUDE_HASH_FLAGS (EXCLUDE_INCLUDE|EXCLUDE_ANCHORED|\
-                            FNM_LEADING_DIR|FNM_CASEFOLD)
-      if (ex->tail && ex->tail->type == exclude_hash
-          && ((ex->tail->options & EXCLUDE_HASH_FLAGS) ==
-              (options & EXCLUDE_HASH_FLAGS)))
-        seg = ex->tail;
-      else
-        seg = new_exclude_segment (ex, exclude_hash, options);
+      int exclude_hash_flags = (EXCLUDE_INCLUDE | EXCLUDE_ANCHORED
+                                | FNM_LEADING_DIR | FNM_CASEFOLD);
+      if (! (ex->head && ex->head->type == exclude_hash
+             && ((ex->head->options & exclude_hash_flags)
+                 == (options & exclude_hash_flags))))
+        new_exclude_segment (ex, exclude_hash, options);
+      seg = ex->head;
 
       str = xstrdup (pattern);
-      if (options & EXCLUDE_WILDCARDS)
+      if ((options & (EXCLUDE_WILDCARDS | FNM_NOESCAPE)) == EXCLUDE_WILDCARDS)
         unescape_pattern (str);
       p = hash_insert (seg->v.table, str);
       if (p != str)
index 5b5d71c..0365287 100644 (file)
 #include <stddef.h>
 #include <stdio.h>
 
-#ifndef HAVE_DECL___FPENDING
-"this configure-time declaration test was not run"
-#endif
-
 #if HAVE_DECL___FPENDING
 # if HAVE_STDIO_EXT_H
 #  include <stdio_ext.h>
index ac2b1ef..6d5f5c2 100644 (file)
@@ -24,7 +24,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #if _GL_WINDOWS_64_BIT_ST_SIZE
+# undef stat /* avoid warning on mingw64 with _FILE_OFFSET_BITS=64 */
 # define stat _stati64
+# undef fstat /* avoid warning on mingw64 with _FILE_OFFSET_BITS=64 */
 # define fstat _fstati64
 #endif
 #undef __need_system_sys_stat_h
index 75875cd..65ca1e6 100644 (file)
@@ -183,9 +183,12 @@ npgettext_aux (const char *domain,
 
 #include <string.h>
 
-#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \
-  (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
-   /* || __STDC_VERSION__ >= 199901L */ )
+#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
+     /* || __STDC_VERSION__ >= 199901L */ )
+# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
+#else
+# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
+#endif
 
 #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
 #include <stdlib.h>
index c23a359..c3383f0 100644 (file)
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl --lib=libgreputils --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=gnulib-tests --aux-dir=build-aux --with-tests --avoid=lock-tests --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl alloca announce-gen argmatch binary-io btowc c-ctype closeout do-release-commit-and-tag error exclude fcntl-h fnmatch fstatat fts getopt-gnu getpagesize gettext-h git-version-gen gitlog-to-changelog gnu-web-doc-update gnupload hard-locale ignore-value intprops inttypes isatty isblank iswctype largefile locale lseek maintainer-makefile malloc-gnu manywarnings mbrlen mbrtowc memchr mempcpy minmax obstack openat-safer progname propername quote readme-release realloc-gnu regex same-inode ssize_t stddef stdlib stpcpy strerror string strtoull strtoumax sys_stat unistd unlocked-io update-copyright useless-if-before-free version-etc-fsf wchar wcrtomb wcscoll wctob wctype-h xalloc xstrtoimax
+# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl --lib=libgreputils --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=gnulib-tests --aux-dir=build-aux --with-tests --avoid=lock-tests --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl alloca announce-gen argmatch binary-io btowc c-ctype closeout do-release-commit-and-tag error exclude fcntl-h fnmatch fstatat fts getopt-gnu getpagesize gettext-h git-version-gen gitlog-to-changelog gnu-web-doc-update gnupload ignore-value intprops inttypes isatty isblank iswctype largefile locale lseek maintainer-makefile malloc-gnu manywarnings mbrlen mbrtowc memchr mempcpy minmax obstack openat-safer perl progname propername quote readme-release realloc-gnu regex same-inode ssize_t stddef stdlib stpcpy strerror string strtoull strtoumax sys_stat unistd unlocked-io update-copyright useless-if-before-free version-etc-fsf wchar wcrtomb wcscoll wctob wctype-h xalloc xstrtoimax
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -679,7 +679,7 @@ EXTRA_DIST += $(top_srcdir)/build-aux/gnu-web-doc-update
 
 distclean-local: clean-GNUmakefile
 clean-GNUmakefile:
-       test x'$(VPATH)' != x && rm -f $(top_builddir)/GNUmakefile || :
+       test '$(srcdir)' = . || rm -f $(top_builddir)/GNUmakefile
 
 EXTRA_DIST += $(top_srcdir)/GNUmakefile
 
@@ -698,14 +698,6 @@ GPERF = gperf
 
 ## end   gnulib module gperf
 
-## begin gnulib module hard-locale
-
-libgreputils_a_SOURCES += hard-locale.c
-
-EXTRA_DIST += hard-locale.h
-
-## end   gnulib module hard-locale
-
 ## begin gnulib module hash
 
 libgreputils_a_SOURCES += hash.c
@@ -1737,15 +1729,6 @@ EXTRA_libgreputils_a_SOURCES += stpcpy.c
 
 ## end   gnulib module stpcpy
 
-## begin gnulib module strcase
-
-
-EXTRA_DIST += strcasecmp.c strncasecmp.c
-
-EXTRA_libgreputils_a_SOURCES += strcasecmp.c strncasecmp.c
-
-## end   gnulib module strcase
-
 ## begin gnulib module strdup-posix
 
 
@@ -1888,37 +1871,6 @@ EXTRA_DIST += string.in.h
 
 ## end   gnulib module string
 
-## begin gnulib module strings
-
-BUILT_SOURCES += strings.h
-
-# We need the following in order to create <strings.h> when the system
-# doesn't have one that works with the given compiler.
-strings.h: strings.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H) $(ARG_NONNULL_H)
-       $(AM_V_GEN)rm -f $@-t $@ && \
-       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
-         sed -e 's|@''GUARD_PREFIX''@|GL|g' \
-             -e 's|@''HAVE_STRINGS_H''@|$(HAVE_STRINGS_H)|g' \
-             -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
-             -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
-             -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
-             -e 's|@''NEXT_STRINGS_H''@|$(NEXT_STRINGS_H)|g' \
-             -e 's|@''GNULIB_FFS''@|$(GNULIB_FFS)|g' \
-             -e 's|@''HAVE_FFS''@|$(HAVE_FFS)|g' \
-             -e 's|@''HAVE_STRCASECMP''@|$(HAVE_STRCASECMP)|g' \
-             -e 's|@''HAVE_DECL_STRNCASECMP''@|$(HAVE_DECL_STRNCASECMP)|g' \
-             -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
-             -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
-             -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
-             < $(srcdir)/strings.in.h; \
-       } > $@-t && \
-       mv $@-t $@
-MOSTLYCLEANFILES += strings.h strings.h-t
-
-EXTRA_DIST += strings.in.h
-
-## end   gnulib module strings
-
 ## begin gnulib module strnlen
 
 
index 52919de..2e34435 100644 (file)
 #ifndef _GL_IGNORE_VALUE_H
 # define _GL_IGNORE_VALUE_H
 
-# ifndef _GL_ATTRIBUTE_DEPRECATED
-/* The __attribute__((__deprecated__)) feature
-   is available in gcc versions 3.1 and newer.  */
-#  if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 1)
-#   define _GL_ATTRIBUTE_DEPRECATED /* empty */
-#  else
-#   define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__))
-#  endif
-# endif
-
 /* The __attribute__((__warn_unused_result__)) feature
    is available in gcc versions 3.4 and newer,
    while the typeof feature has been available since 2.7 at least.  */
index 113205d..b5ee2d6 100644 (file)
@@ -29,7 +29,7 @@
 #include <stdlib.h>
 
 #if defined __APPLE__ && defined __MACH__ && HAVE_LANGINFO_CODESET
-# define DARWIN7 /* Darwin 7 or newer, i.e. MacOS X 10.3 or newer */
+# define DARWIN7 /* Darwin 7 or newer, i.e. Mac OS X 10.3 or newer */
 #endif
 
 #if defined _WIN32 || defined __WIN32__
index bf246eb..cca1791 100644 (file)
@@ -22,7 +22,7 @@
 /* Internal state used by the functions mbsrtowcs() and mbsnrtowcs().  */
 mbstate_t _gl_mbsrtowcs_state
 /* The state must initially be in the "initial state"; so, zero-initialize it.
-   On most systems, putting it into BSS is sufficient.  Not so on MacOS X 10.3,
+   On most systems, putting it into BSS is sufficient.  Not so on Mac OS X 10.3,
    see <http://lists.gnu.org/archive/html/bug-gnulib/2009-01/msg00329.html>.
    When it needs an initializer, use 0 or {0} as initializer? 0 only works
    when mbstate_t is a scalar type (such as when gnulib defines it, or on
index 1334f47..81277dc 100644 (file)
@@ -899,8 +899,10 @@ init_dfa (re_dfa_t *dfa, size_t pat_len)
                       != 0);
 #else
   codeset_name = nl_langinfo (CODESET);
-  if (strcasecmp (codeset_name, "UTF-8") == 0
-      || strcasecmp (codeset_name, "UTF8") == 0)
+  if ((codeset_name[0] == 'U' || codeset_name[0] == 'u')
+      && (codeset_name[1] == 'T' || codeset_name[1] == 't')
+      && (codeset_name[2] == 'F' || codeset_name[2] == 'f')
+      && strcmp (codeset_name + 3 + (codeset_name[3] == '-'), "8") == 0)
     dfa->is_utf8 = 1;
 
   /* We check exhaustively in the loop below if this charset is a
@@ -956,18 +958,22 @@ init_word_char (re_dfa_t *dfa)
   int ch = 0;
   if (BE (dfa->map_notascii == 0, 1))
     {
+      bitset_word_t bits0 = 0x00000000;
+      bitset_word_t bits1 = 0x03ff0000;
+      bitset_word_t bits2 = 0x87fffffe;
+      bitset_word_t bits3 = 0x07fffffe;
       if (BITSET_WORD_BITS == 64)
        {
-         dfa->word_char[0] = UINT64_C (0x03ff000000000000);
-         dfa->word_char[1] = UINT64_C (0x07fffffe87fffffe);
+         dfa->word_char[0] = bits1 << 31 << 1 | bits0;
+         dfa->word_char[1] = bits3 << 31 << 1 | bits2;
          i = 2;
        }
       else if (BITSET_WORD_BITS == 32)
        {
-         dfa->word_char[0] = UINT32_C (0x00000000);
-         dfa->word_char[1] = UINT32_C (0x03ff0000);
-         dfa->word_char[2] = UINT32_C (0x87fffffe);
-         dfa->word_char[3] = UINT32_C (0x07fffffe);
+         dfa->word_char[0] = bits0;
+         dfa->word_char[1] = bits1;
+         dfa->word_char[2] = bits2;
+         dfa->word_char[3] = bits3;
          i = 4;
        }
       else
@@ -2617,7 +2623,10 @@ parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
     old_tree = NULL;
 
   if (elem->token.type == SUBEXP)
-    postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx);
+    {
+      uintptr_t subidx = elem->token.opr.idx;
+      postorder (elem, mark_opt_subexp, (void *) subidx);
+    }
 
   tree = create_tree (dfa, elem, NULL,
                      (end == REG_MISSING ? OP_DUP_ASTERISK : OP_ALT));
@@ -3857,7 +3866,7 @@ create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
 static reg_errcode_t
 mark_opt_subexp (void *extra, bin_tree_t *node)
 {
-  Idx idx = (Idx) (long) extra;
+  Idx idx = (uintptr_t) extra;
   if (node->token.type == SUBEXP && node->token.opr.idx == idx)
     node->token.opt_subexp = 1;
 
index 5461bf6..b816f8f 100644 (file)
@@ -481,7 +481,7 @@ re_search_stub (struct re_pattern_buffer *bufp,
 
   rval = 0;
 
-  /* I hope we needn't fill ther regs with -1's when no match was found.  */
+  /* I hope we needn't fill their regs with -1's when no match was found.  */
   if (result != REG_NOERROR)
     rval = result == REG_NOMATCH ? -1 : -2;
   else if (regs != NULL)
index 1fc633e..7599540 100644 (file)
@@ -29,6 +29,7 @@
 
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 # if _GL_WINDOWS_64_BIT_ST_SIZE
+#  undef stat /* avoid warning on mingw64 with _FILE_OFFSET_BITS=64 */
 #  define stat _stati64
 #  define REPLACE_FUNC_STAT_DIR 1
 #  undef REPLACE_FUNC_STAT_FILE
index 9ca6523..9f55cfa 100644 (file)
@@ -89,6 +89,8 @@ strerror_override (int errnum)
       return "No route to host";
     case EWOULDBLOCK:
       return "Operation would block";
+#endif
+#if GNULIB_defined_ESTREAMS /* native Windows platforms with older <errno.h> */
     case ETXTBSY:
       return "Text file busy";
     case ENODATA:
@@ -97,10 +99,6 @@ strerror_override (int errnum)
       return "Out of streams resources";
     case ENOSTR:
       return "Device not a stream";
-    case ENOTRECOVERABLE:
-      return "State not recoverable";
-    case EOWNERDEAD:
-      return "Owner died";
     case ETIME:
       return "Timer expired";
     case EOTHER:
@@ -283,6 +281,16 @@ strerror_override (int errnum)
       return "Operation canceled";
 #endif
 
+#if GNULIB_defined_EOWNERDEAD
+    case EOWNERDEAD:
+      return "Owner died";
+#endif
+
+#if GNULIB_defined_ENOTRECOVERABLE
+    case ENOTRECOVERABLE:
+      return "State not recoverable";
+#endif
+
     default:
       return NULL;
     }
index 09526ea..fe1fb2c 100644 (file)
@@ -30,6 +30,7 @@
    describing the error.  Otherwise return NULL.  */
 # if REPLACE_STRERROR_0 \
      || GNULIB_defined_ESOCK \
+     || GNULIB_defined_ESTREAMS \
      || GNULIB_defined_EWINSOCK \
      || GNULIB_defined_ENOMSG \
      || GNULIB_defined_EIDRM \
@@ -43,7 +44,9 @@
      || GNULIB_defined_ECONNABORTED \
      || GNULIB_defined_ESTALE \
      || GNULIB_defined_EDQUOT \
-     || GNULIB_defined_ECANCELED
+     || GNULIB_defined_ECANCELED \
+     || GNULIB_defined_EOWNERDEAD \
+     || GNULIB_defined_ENOTRECOVERABLE
 extern const char *strerror_override (int errnum);
 # else
 #  define strerror_override(ignored) NULL
index cef14ad..0c320b1 100644 (file)
        extern int (*dummy (void)) [sizeof (struct {...})];
 
    * GCC warns about duplicate declarations of the dummy function if
-     -Wredundant_decls is used.  GCC 4.3 and later have a builtin
+     -Wredundant-decls is used.  GCC 4.3 and later have a builtin
      __COUNTER__ macro that can let us generate unique identifiers for
      each dummy function, to suppress this warning.
 
      which do not support _Static_assert, also do not warn about the
      last declaration mentioned above.
 
+   * GCC warns if -Wnested-externs is enabled and verify() is used
+     within a function body; but inside a function, you can always
+     arrange to use verify_expr() instead.
+
    * In C++, any struct definition inside sizeof is invalid.
      Use a template type to work around the problem.  */
 
index 1cbe537..df73a1a 100644 (file)
@@ -29,6 +29,7 @@
 #include <limits.h>
 #include <string.h>
 #include <locale.h>
+#include <stdbool.h>
 
 #define STREQ(a, b) (strcmp (a, b) == 0)
 
@@ -38,7 +39,7 @@
    - It's typically faster.
    Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
    only '0' through '9' are digits.  Prefer ISASCIIDIGIT to isdigit unless
-   it's important to use the locale's definition of `digit' even when the
+   it's important to use the locale's definition of "digit" even when the
    host does not conform to Posix.  */
 #define ISASCIIDIGIT(c) ((unsigned) (c) - '0' <= 9)
 
@@ -56,7 +57,6 @@
 
 #include "regex.h"
 #include "dfa.h"
-#include "hard-locale.h"
 #include "xalloc.h"
 
 /* HPUX, define those as macros in sys/param.h */
@@ -634,7 +634,7 @@ static charclass newline;
 # define is_valid_unibyte_character(c) (! (MBS_SUPPORT && btowc (c) == WEOF))
 #endif
 
-/* Return non-zero if C is a 'word-constituent' byte; zero otherwise.  */
+/* Return non-zero if C is a "word-constituent" byte; zero otherwise.  */
 #define IS_WORD_CONSTITUENT(C) \
   (is_valid_unibyte_character (C) && (isalnum (C) || (C) == '_'))
 
@@ -777,7 +777,6 @@ static int laststart;           /* True if we're separated from beginning or (,
                                    only by zero-width characters. */
 static size_t parens;           /* Count of outstanding left parens. */
 static int minrep, maxrep;      /* Repeat counts for {m,n}. */
-static int hard_LC_COLLATE;     /* Nonzero if LC_COLLATE is hard.  */
 
 static int cur_mb_len = 1;      /* Length of the multibyte representation of
                                    wctok.  */
@@ -975,9 +974,9 @@ parse_bracket_exp (void)
           char str[BRACKET_BUFFER_SIZE];
           FETCH_WC (c1, wc1, _("unbalanced ["));
 
-          /* If pattern contains `[[:', `[[.', or `[[='.  */
+          /* If pattern contains '[[:', '[[.', or '[[='.  */
           if (c1 == ':'
-              /* TODO: handle `[[.' and `[[=' also for MB_CUR_MAX == 1.  */
+              /* TODO: handle '[[.' and '[[=' also for MB_CUR_MAX == 1.  */
               || (MB_CUR_MAX > 1 && (c1 == '.' || c1 == '=')))
             {
               size_t len = 0;
@@ -1105,32 +1104,31 @@ parse_bracket_exp (void)
             }
           else
             {
+              /* Defer to the system regex library about the meaning
+                 of range expressions.  */
+              regex_t re;
+              char pattern[6] = { '[', 0, '-', 0, ']', 0 };
+              char subject[2] = { 0, 0 };
               c1 = c;
               if (case_fold)
                 {
                   c1 = tolower (c1);
                   c2 = tolower (c2);
                 }
-              if (!hard_LC_COLLATE)
-                for (c = c1; c <= c2; c++)
-                  setbit_case_fold_c (c, ccl);
-              else
+
+              pattern[1] = c1;
+              pattern[3] = c2;
+              regcomp (&re, pattern, REG_NOSUB);
+              for (c = 0; c < NOTCHAR; ++c)
                 {
-                  /* Defer to the system regex library about the meaning
-                     of range expressions.  */
-                  regex_t re;
-                  char pattern[6] = { '[', c1, '-', c2, ']', 0 };
-                  char subject[2] = { 0, 0 };
-                  regcomp (&re, pattern, REG_NOSUB);
-                  for (c = 0; c < NOTCHAR; ++c)
-                    {
-                      subject[0] = c;
-                      if (!(case_fold && isupper (c))
-                          && regexec (&re, subject, 0, NULL, 0) != REG_NOMATCH)
-                        setbit_case_fold_c (c, ccl);
-                    }
-                  regfree (&re);
+                  if ((case_fold && isupper (c))
+                      || (MB_CUR_MAX > 1 && btowc (c) == WEOF))
+                    continue;
+                  subject[0] = c;
+                  if (regexec (&re, subject, 0, NULL, 0) != REG_NOMATCH)
+                    setbit_case_fold_c (c, ccl);
                 }
+              regfree (&re);
             }
 
           colon_warning_state |= 8;
@@ -1632,7 +1630,7 @@ add_utf8_anychar (void)
   static const charclass utf8_classes[5] = {
     {0, 0, 0, 0, ~0, ~0, 0, 0}, /* 80-bf: non-lead bytes */
     {~0, ~0, ~0, ~0, 0, 0, 0, 0},       /* 00-7f: 1-byte sequence */
-    {0, 0, 0, 0, 0, 0, 0xfffffffcU, 0}, /* c2-df: 2-byte sequence */
+    {0, 0, 0, 0, 0, 0, ~3, 0},          /* c2-df: 2-byte sequence */
     {0, 0, 0, 0, 0, 0, 0, 0xffff},      /* e0-ef: 3-byte sequence */
     {0, 0, 0, 0, 0, 0, 0, 0xff0000}     /* f0-f7: 4-byte sequence */
   };
@@ -1878,9 +1876,6 @@ dfaparse (char const *s, size_t len, struct dfa *d)
   lasttok = END;
   laststart = 1;
   parens = 0;
-#ifdef LC_COLLATE
-  hard_LC_COLLATE = hard_locale (LC_COLLATE);
-#endif
   if (MB_CUR_MAX > 1)
     {
       cur_mb_len = 0;
@@ -2966,7 +2961,6 @@ match_mb_charset (struct dfa *d, state_num s, position pos, size_t idx)
                                    with which this operator match.  */
   int op_len;                   /* Length of the operator.  */
   char buffer[128];
-  wchar_t wcbuf[6];
 
   /* Pointer to the structure to which we are currently referring.  */
   struct mb_char_classes *work_mbc;
@@ -3039,16 +3033,10 @@ match_mb_charset (struct dfa *d, state_num s, position pos, size_t idx)
         }
     }
 
-  wcbuf[0] = wc;
-  wcbuf[1] = wcbuf[3] = wcbuf[5] = '\0';
-
   /* match with a range?  */
   for (i = 0; i < work_mbc->nranges; i++)
     {
-      wcbuf[2] = work_mbc->range_sts[i];
-      wcbuf[4] = work_mbc->range_ends[i];
-
-      if (wcscoll (wcbuf, wcbuf + 2) >= 0 && wcscoll (wcbuf + 4, wcbuf) >= 0)
+      if (work_mbc->range_sts[i] <= wc && wc <= work_mbc->range_ends[i])
         goto charset_matched;
     }
 
@@ -3065,11 +3053,11 @@ charset_matched:
   return match ? match_len : 0;
 }
 
-/* Check each of `d->states[s].mbps.elem' can match or not. Then return the
-   array which corresponds to `d->states[s].mbps.elem' and each element of
+/* Check each of 'd->states[s].mbps.elem' can match or not. Then return the
+   array which corresponds to 'd->states[s].mbps.elem' and each element of
    the array contains the amount of the bytes with which the element can
    match.
-   `idx' is the index from the buf_begin, and it is the current position
+   'idx' is the index from the buf_begin, and it is the current position
    in the buffer.
    Caller MUST free the array which this function return.  */
 static int *
@@ -3098,11 +3086,11 @@ check_matching_with_multibyte_ops (struct dfa *d, state_num s, size_t idx)
 }
 
 /* Consume a single character and enumerate all of the positions which can
-   be next position from the state `s'.
-   `match_lens' is the input. It can be NULL, but it can also be the output
+   be next position from the state 's'.
+   'match_lens' is the input. It can be NULL, but it can also be the output
    of check_matching_with_multibyte_ops() for optimization.
-   `mbclen' and `pps' are the output.  `mbclen' is the length of the
-   character consumed, and `pps' is the set this function enumerate.  */
+   'mbclen' and 'pps' are the output.  'mbclen' is the length of the
+   character consumed, and 'pps' is the set this function enumerate.  */
 static status_transit_state
 transit_state_consume_1char (struct dfa *d, state_num s,
                              unsigned char const **pp,
@@ -3118,15 +3106,15 @@ transit_state_consume_1char (struct dfa *d, state_num s,
      to which p points.  */
   *mbclen = (mblen_buf[*pp - buf_begin] == 0) ? 1 : mblen_buf[*pp - buf_begin];
 
-  /* Calculate the state which can be reached from the state `s' by
-     consuming `*mbclen' single bytes from the buffer.  */
+  /* Calculate the state which can be reached from the state 's' by
+     consuming '*mbclen' single bytes from the buffer.  */
   s1 = s;
   for (k = 0; k < *mbclen; k++)
     {
       s2 = s1;
       rs = transit_state_singlebyte (d, s2, (*pp)++, &s1);
     }
-  /* Copy the positions contained by `s1' to the set `pps'.  */
+  /* Copy the positions contained by 's1' to the set 'pps'.  */
   copy (&(d->states[s1].elems), pps);
 
   /* Check (input) match_lens, and initialize if it is NULL.  */
@@ -3135,7 +3123,7 @@ transit_state_consume_1char (struct dfa *d, state_num s,
   else
     work_mbls = match_lens;
 
-  /* Add all of the positions which can be reached from `s' by consuming
+  /* Add all of the positions which can be reached from 's' by consuming
      a single character.  */
   for (i = 0; i < d->states[s].mbps.nelem; i++)
     {
@@ -3202,10 +3190,10 @@ transit_state (struct dfa *d, state_num s, unsigned char const **pp)
   /* This state has some operators which can match a multibyte character.  */
   alloc_position_set (&follows, d->nleaves);
 
-  /* `maxlen' may be longer than the length of a character, because it may
+  /* 'maxlen' may be longer than the length of a character, because it may
      not be a character but a (multi character) collating element.
-     We enumerate all of the positions which `s' can reach by consuming
-     `maxlen' bytes.  */
+     We enumerate all of the positions which 's' can reach by consuming
+     'maxlen' bytes.  */
   transit_state_consume_1char (d, s, pp, match_lens, &mbclen, &follows);
 
   wc = inputwcs[*pp - mbclen - buf_begin];
index bd09aa6..eaf783e 100644 (file)
@@ -78,8 +78,9 @@ static char const *
 kwsincr_case (const char *must)
 {
   size_t n = strlen (must);
+  mb_len_map_t *map = NULL;
   const char *buf = (match_icase && MB_CUR_MAX > 1
-                     ? mbtolower (must, &n)
+                     ? mbtolower (must, &n, &map)
                      : must);
   return kwsincr (kwset, buf, n);
 }
@@ -214,16 +215,18 @@ EGexecute (char const *buf, size_t size, size_t *match_size,
   char eol = eolbyte;
   int backref;
   regoff_t start;
-  ptrdiff_t len, best_len;
+  size_t len, best_len;
   struct kwsmatch kwsm;
   size_t i, ret_val;
+  mb_len_map_t *map = NULL;
+
   if (MB_CUR_MAX > 1)
     {
       if (match_icase)
         {
           /* mbtolower adds a NUL byte at the end.  That will provide
              space for the sentinel byte dfaexec may add.  */
-          char *case_buf = mbtolower (buf, &size);
+          char *case_buf = mbtolower (buf, &size, &map);
           if (start_ptr)
             start_ptr = case_buf + (start_ptr - buf);
           buf = case_buf;
@@ -274,7 +277,9 @@ EGexecute (char const *buf, size_t size, size_t *match_size,
               /* No good fixed strings; start with DFA. */
               char const *next_beg = dfaexec (dfa, beg, (char *) buflim,
                                               0, NULL, &backref);
-              if (next_beg == NULL)
+              /* If there's no match, or if we've matched the sentinel,
+                 we're done.  */
+              if (next_beg == NULL || next_beg == buflim)
                 break;
               /* Narrow down to the line we've found. */
               beg = next_beg;
@@ -340,6 +345,7 @@ EGexecute (char const *buf, size_t size, size_t *match_size,
               if (match_words)
                 while (match <= best_match)
                   {
+                    regoff_t shorter_len = 0;
                     if ((match == buf || !WCHAR ((unsigned char) match[-1]))
                         && (start + len == end - buf - 1
                             || !WCHAR ((unsigned char) match[len])))
@@ -349,13 +355,16 @@ EGexecute (char const *buf, size_t size, size_t *match_size,
                         /* Try a shorter length anchored at the same place. */
                         --len;
                         patterns[i].regexbuf.not_eol = 1;
-                        len = re_match (&(patterns[i].regexbuf),
-                                        buf, match + len - beg, match - buf,
-                                        &(patterns[i].regs));
-                        if (len < -1)
+                        shorter_len = re_match (&(patterns[i].regexbuf),
+                                                buf, match + len - beg,
+                                                match - buf,
+                                                &(patterns[i].regs));
+                        if (shorter_len < -1)
                           xalloc_die ();
                       }
-                    if (len <= 0)
+                    if (0 < shorter_len)
+                      len = shorter_len;
+                    else
                       {
                         /* Try looking further on. */
                         if (match == end - 1)
@@ -408,9 +417,11 @@ EGexecute (char const *buf, size_t size, size_t *match_size,
 
  success:
   len = end - beg;
- success_in_len:
+ success_in_len:;
+  size_t off = beg - buf;
+  mb_case_map_apply (map, &off, &len);
   *match_size = len;
-  ret_val = beg - buf;
+  ret_val = off;
  out:
   return ret_val;
 }
index f1a802e..b56b465 100644 (file)
@@ -34,8 +34,9 @@ Fcompile (char const *pattern, size_t size)
 {
   char const *err;
   size_t psize = size;
+  mb_len_map_t *map = NULL;
   char const *pat = (match_icase && MB_CUR_MAX > 1
-                     ? mbtolower (pattern, &psize)
+                     ? mbtolower (pattern, &psize, &map)
                      : pattern);
 
   kwsinit (&kwset);
@@ -83,11 +84,13 @@ Fexecute (char const *buf, size_t size, size_t *match_size,
   char eol = eolbyte;
   struct kwsmatch kwsmatch;
   size_t ret_val;
+  mb_len_map_t *map = NULL;
+
   if (MB_CUR_MAX > 1)
     {
       if (match_icase)
         {
-          char *case_buf = mbtolower (buf, &size);
+          char *case_buf = mbtolower (buf, &size, &map);
           if (start_ptr)
             start_ptr = case_buf + (start_ptr - buf);
           buf = case_buf;
@@ -162,9 +165,12 @@ Fexecute (char const *buf, size_t size, size_t *match_size,
   while (buf < beg && beg[-1] != eol)
     --beg;
   len = end - beg;
- success_in_beg_and_len:
+ success_in_beg_and_len:;
+  size_t off = beg - buf;
+  mb_case_map_apply (map, &off, &len);
+
   *match_size = len;
-  ret_val = beg - buf;
+  ret_val = off;
  out:
   return ret_val;
 }
index c5a8489..e3b5186 100644 (file)
@@ -272,11 +272,10 @@ static const struct color_cap color_dict[] =
   };
 
 static struct exclude *excluded_patterns;
-static struct exclude *included_patterns;
 static struct exclude *excluded_directory_patterns;
 /* Short options.  */
 static char const short_options[] =
-"0123456789A:B:C:D:EFGHIPTUVX:abcd:e:f:hiKLlm:noqRrsuvwxyZz";
+"0123456789A:B:C:D:EFGHIPTUVX:abcd:e:f:hiLlm:noqRrsuvwxyZz";
 
 /* Non-boolean long options that have no corresponding short equivalents.  */
 enum
@@ -407,6 +406,14 @@ is_device_mode (mode_t m)
   return S_ISCHR (m) || S_ISBLK (m) || S_ISSOCK (m) || S_ISFIFO (m);
 }
 
+/* Return nonzero if ST->st_size is defined.  Assume the file is not a
+   symbolic link.  */
+static int
+usable_st_size (struct stat const *st)
+{
+  return S_ISREG (st->st_mode) || S_TYPEISSHM (st) || S_TYPEISTMO (st);
+}
+
 /* Functions we'll use to search. */
 static compile_fp_t compile;
 static execute_fp_t execute;
@@ -429,6 +436,52 @@ clean_up_stdout (void)
     close_stdout ();
 }
 
+/* Return 1 if a file is known to be binary for the purpose of 'grep'.
+   BUF, of size BUFSIZE, is the initial buffer read from the file with
+   descriptor FD and status ST.  */
+static int
+file_is_binary (char const *buf, size_t bufsize, int fd, struct stat const *st)
+{
+  #ifndef SEEK_HOLE
+  enum { SEEK_HOLE = SEEK_END };
+  #endif
+
+  /* If -z, test only whether the initial buffer contains '\200';
+     knowing about holes won't help.  */
+  if (! eolbyte)
+    return memchr (buf, '\200', bufsize) != 0;
+
+  /* If the initial buffer contains a null byte, guess that the file
+     is binary.  */
+  if (memchr (buf, '\0', bufsize))
+    return 1;
+
+  /* If the file has holes, it must contain a null byte somewhere.  */
+  if (SEEK_HOLE != SEEK_END && usable_st_size (st))
+    {
+      off_t cur = bufsize;
+      if (O_BINARY || fd == STDIN_FILENO)
+        {
+          cur = lseek (fd, 0, SEEK_CUR);
+          if (cur < 0)
+            return 0;
+        }
+
+      /* Look for a hole after the current location.  */
+      off_t hole_start = lseek (fd, cur, SEEK_HOLE);
+      if (0 <= hole_start)
+        {
+          if (lseek (fd, cur, SEEK_SET) < 0)
+            suppressible_error (filename, errno);
+          if (hole_start < st->st_size)
+            return 1;
+        }
+    }
+
+  /* Guess that the file does not contain binary data.  */
+  return 0;
+}
+
 /* Convert STR to a nonnegative integer, storing the result in *OUT.
    STR must be a valid context length argument; report an error if it
    isn't.  Silently ceiling *OUT at the maximum value, as that is
@@ -449,6 +502,20 @@ context_length_arg (char const *str, intmax_t *out)
     }
 }
 
+/* Return nonzero if the file with NAME should be skipped.
+   If COMMAND_LINE is nonzero, it is a command-line argument.
+   If IS_DIR is nonzero, it is a directory.  */
+static int
+skipped_file (char const *name, int command_line, int is_dir)
+{
+  return (is_dir
+          ? (directories == SKIP_DIRECTORIES
+             || (! (command_line && filename_prefix_len != 0)
+                 && excluded_directory_patterns
+                 && excluded_file_name (excluded_directory_patterns, name)))
+          : (excluded_patterns
+             && excluded_file_name (excluded_patterns, name)));
+}
 
 /* Hairy buffering mechanism for grep.  The intent is to keep
    all reads aligned on a page boundary and multiples of the
@@ -515,7 +582,7 @@ reset (int fd, struct stat const *st)
 static int
 fillbuf (size_t save, struct stat const *st)
 {
-  size_t fillsize = 0;
+  ssize_t fillsize;
   int cc = 1;
   char *readbuf;
   size_t readsize;
@@ -546,7 +613,7 @@ fillbuf (size_t save, struct stat const *st)
          is large.  However, do not use the original file size as a
          heuristic if we've already read past the file end, as most
          likely the file is growing.  */
-      if (S_ISREG (st->st_mode))
+      if (usable_st_size (st))
         {
           off_t to_be_read = st->st_size - bufoffset;
           off_t maxsize_off = save + to_be_read;
@@ -576,18 +643,9 @@ fillbuf (size_t save, struct stat const *st)
   readsize = buffer + bufalloc - readbuf;
   readsize -= readsize % pagesize;
 
-  if (! fillsize)
-    {
-      ssize_t bytesread;
-      while ((bytesread = read (bufdesc, readbuf, readsize)) < 0
-             && errno == EINTR)
-        continue;
-      if (bytesread < 0)
-        cc = 0;
-      else
-        fillsize = bytesread;
-    }
-
+  fillsize = read (bufdesc, readbuf, readsize);
+  if (fillsize < 0)
+    fillsize = cc = 0;
   bufoffset += fillsize;
 #if defined HAVE_DOS_FILE_CONTENTS
   if (fillsize)
@@ -1120,7 +1178,7 @@ grep (int fd, struct stat const *st)
 
   not_text = (((binary_files == BINARY_BINARY_FILES && !out_quiet)
                || binary_files == WITHOUT_MATCH_BINARY_FILES)
-              && memchr (bufbeg, eol ? '\0' : '\200', buflim - bufbeg));
+              && file_is_binary (bufbeg, buflim - bufbeg, fd, st));
   if (not_text && binary_files == WITHOUT_MATCH_BINARY_FILES)
     return 0;
   done_on_match += not_text;
@@ -1142,8 +1200,10 @@ grep (int fd, struct stat const *st)
          the buffer, 0 means there is no incomplete last line).  */
       oldc = beg[-1];
       beg[-1] = eol;
-      for (lim = buflim; lim[-1] != eol; lim--)
-        continue;
+      /* FIXME: use rawmemrchr if/when it exists, since we have ensured
+         that this use of memrchr is guaranteed never to return NULL.  */
+      lim = memrchr (beg - 1, eol, buflim - beg + 1);
+      ++lim;
       beg[-1] = oldc;
       if (lim == beg)
         lim = beg - residue;
@@ -1207,11 +1267,11 @@ grep (int fd, struct stat const *st)
 }
 
 static int
-grepdirent (FTS *fts, FTSENT *ent)
+grepdirent (FTS *fts, FTSENT *ent, int command_line)
 {
   int follow, dirdesc;
-  int command_line = ent->fts_level == FTS_ROOTLEVEL;
   struct stat *st = ent->fts_statp;
+  command_line &= ent->fts_level == FTS_ROOTLEVEL;
 
   if (ent->fts_info == FTS_DP)
     {
@@ -1220,17 +1280,9 @@ grepdirent (FTS *fts, FTSENT *ent)
       return 1;
     }
 
-  if ((ent->fts_info == FTS_D || ent->fts_info == FTS_DC
-       || ent->fts_info == FTS_DNR)
-      ? (directories == SKIP_DIRECTORIES
-         || (! (command_line && filename_prefix_len != 0)
-             && excluded_directory_patterns
-             && excluded_file_name (excluded_directory_patterns,
-                                    ent->fts_name)))
-      : ((included_patterns
-          && excluded_file_name (included_patterns, ent->fts_name))
-         || (excluded_patterns
-             && excluded_file_name (excluded_patterns, ent->fts_name))))
+  if (skipped_file (ent->fts_name, command_line,
+                    (ent->fts_info == FTS_D || ent->fts_info == FTS_DC
+                     || ent->fts_info == FTS_DNR)))
     {
       fts_set (fts, ent, FTS_SKIP);
       return 1;
@@ -1336,6 +1388,11 @@ grepdesc (int desc, int command_line)
       suppressible_error (filename, errno);
       goto closeout;
     }
+
+  if (desc != STDIN_FILENO && command_line
+      && skipped_file (filename, 1, S_ISDIR (st.st_mode)))
+    goto closeout;
+
   if (desc != STDIN_FILENO
       && directories == RECURSE_DIRECTORIES && S_ISDIR (st.st_mode))
     {
@@ -1360,7 +1417,7 @@ grepdesc (int desc, int command_line)
       if (!fts)
         xalloc_die ();
       while ((ent = fts_read (fts)))
-        status &= grepdirent (fts, ent);
+        status &= grepdirent (fts, ent, command_line);
       if (errno)
         suppressible_error (filename, errno);
       if (fts_close (fts) != 0)
@@ -1523,15 +1580,15 @@ Output control:\n\
   -o, --only-matching       show only the part of a line matching PATTERN\n\
   -q, --quiet, --silent     suppress all normal output\n\
       --binary-files=TYPE   assume that binary files are TYPE;\n\
-                            TYPE is `binary', `text', or `without-match'\n\
+                            TYPE is 'binary', 'text', or 'without-match'\n\
   -a, --text                equivalent to --binary-files=text\n\
 "));
       printf (_("\
   -I                        equivalent to --binary-files=without-match\n\
   -d, --directories=ACTION  how to handle directories;\n\
-                            ACTION is `read', `recurse', or `skip'\n\
+                            ACTION is 'read', 'recurse', or 'skip'\n\
   -D, --devices=ACTION      how to handle devices, FIFOs and sockets;\n\
-                            ACTION is `read' or `skip'\n\
+                            ACTION is 'read' or 'skip'\n\
   -r, --recursive           like --directories=recurse\n\
   -R, --dereference-recursive  likewise, but follow all symlinks\n\
 "));
@@ -1558,7 +1615,7 @@ Context control:\n\
   -NUM                      same as --context=NUM\n\
       --color[=WHEN],\n\
       --colour[=WHEN]       use markers to highlight the matching strings;\n\
-                            WHEN is `always', `never', or `auto'\n\
+                            WHEN is 'always', 'never', or 'auto'\n\
   -U, --binary              do not strip CR characters at EOL (MSDOS/Windows)\n\
   -u, --unix-byte-offsets   report offsets as if CRs were not there\n\
                             (MSDOS/Windows)\n\
@@ -2076,9 +2133,12 @@ main (int argc, char **argv)
         break;
 
       case EXCLUDE_OPTION:
+      case INCLUDE_OPTION:
         if (!excluded_patterns)
           excluded_patterns = new_exclude ();
-        add_exclude (excluded_patterns, optarg, EXCLUDE_WILDCARDS);
+        add_exclude (excluded_patterns, optarg,
+                     (EXCLUDE_WILDCARDS
+                      | (opt == INCLUDE_OPTION ? EXCLUDE_INCLUDE : 0)));
         break;
       case EXCLUDE_FROM_OPTION:
         if (!excluded_patterns)
@@ -2096,13 +2156,6 @@ main (int argc, char **argv)
         add_exclude (excluded_directory_patterns, optarg, EXCLUDE_WILDCARDS);
         break;
 
-      case INCLUDE_OPTION:
-        if (!included_patterns)
-          included_patterns = new_exclude ();
-        add_exclude (included_patterns, optarg,
-                     EXCLUDE_WILDCARDS | EXCLUDE_INCLUDE);
-        break;
-
       case GROUP_SEPARATOR_OPTION:
         group_separator = optarg;
         break;
index 3074407..3820d7a 100644 (file)
@@ -22,6 +22,7 @@
 #include <config.h>
 
 #include <sys/types.h>
+#include <stdint.h>
 
 #include "mbsupport.h"
 
 #include "kwset.h"
 #include "xalloc.h"
 
+/* This must be a signed type.  Each value is the difference in the size
+   of a character (in bytes) induced by converting to lower case.
+   The vast majority of values are 0, but a few are 1 or -1, so
+   technically, two bits may be sufficient.  */
+typedef signed char mb_len_map_t;
+
 /* searchutils.c */
 extern void kwsinit (kwset_t *);
 
-extern char *mbtolower (const char *, size_t *);
+extern char *mbtolower (const char *, size_t *, mb_len_map_t **);
 extern bool is_mb_middle (const char **, const char *, const char *, size_t);
 
 /* dfasearch.c */
@@ -53,4 +60,23 @@ extern size_t Fexecute (char const *, size_t, size_t *, char const *);
 extern void Pcompile (char const *, size_t);
 extern size_t Pexecute (char const *, size_t, size_t *, char const *);
 
+/* Apply the MAP (created by mbtolower) to the lowercase-buffer-relative
+   *OFF and *LEN, converting them to be relative to the original buffer.  */
+static inline void
+mb_case_map_apply (mb_len_map_t const *map, size_t *off, size_t *len)
+{
+  if (map)
+    {
+      intmax_t off_incr = 0;
+      intmax_t len_incr = 0;
+      size_t k;
+      for (k = 0; k < *off; k++)
+        off_incr += map[k];
+      for (k = *off; k < *off + *len; k++)
+        len_incr += map[k];
+      *off += off_incr;
+      *len += len_incr;
+    }
+}
+
 #endif /* GREP_SEARCH_H */
index b787fe6..ca30134 100644 (file)
@@ -43,35 +43,59 @@ kwsinit (kwset_t *kwset)
 }
 
 #if MBS_SUPPORT
-/* Convert the *N-byte string, BEG, to lowercase, and write the
+/* Convert the *N-byte string, BEG, to lower-case, and write the
    NUL-terminated result into malloc'd storage.  Upon success, set *N
    to the length (in bytes) of the resulting string (not including the
-   trailing NUL byte), and return a pointer to the lowercase string.
+   trailing NUL byte), and return a pointer to the lower-case string.
    Upon memory allocation failure, this function exits.
    Note that on input, *N must be larger than zero.
 
    Note that while this function returns a pointer to malloc'd storage,
    the caller must not free it, since this function retains a pointer
    to the buffer and reuses it on any subsequent call.  As a consequence,
-   this function is not thread-safe.  */
+   this function is not thread-safe.
+
+   When each character in the lower-case result string has the same length
+   as the corresponding character in the input string, set *LEN_MAP_P
+   to NULL.  Otherwise, set it to a malloc'd buffer (like the returned
+   buffer, this must not be freed by caller) of the same length as the
+   result string.  (*LEN_MAP_P)[J] is the change in byte-length of the
+   character in BEG that formed byte J of the result as it was converted to
+   lower-case.  It is usually zero.  For the upper-case Turkish I-with-dot
+   it is -1, since the upper-case character occupies two bytes, while the
+   lower-case one occupies only one byte.  For the Turkish-I-without-dot
+   in the tr_TR.utf8 locale, it is 1 because the lower-case representation
+   is one byte longer than the original.  When that happens, we have two
+   or more slots in *LEN_MAP_P for each such character.  We store the
+   difference in the first one and 0's in any remaining slots.
+
+   This map is used by the caller to convert offset,length pairs that
+   reference the lower-case result to numbers that refer to the matched
+   part of the original buffer.  */
+
 char *
-mbtolower (const char *beg, size_t *n)
+mbtolower (const char *beg, size_t *n, mb_len_map_t **len_map_p)
 {
   static char *out;
+  static mb_len_map_t *len_map;
   static size_t outalloc;
   size_t outlen, mb_cur_max;
   mbstate_t is, os;
   const char *end;
   char *p;
+  mb_len_map_t *m;
+  bool lengths_differ = false;
 
   if (*n > outalloc || outalloc == 0)
     {
       outalloc = MAX(1, *n);
       out = xrealloc (out, outalloc);
+      len_map = xrealloc (len_map, outalloc);
     }
 
   /* appease clang-2.6 */
   assert (out);
+  assert (len_map);
   if (*n == 0)
     return out;
 
@@ -81,21 +105,26 @@ mbtolower (const char *beg, size_t *n)
 
   mb_cur_max = MB_CUR_MAX;
   p = out;
+  m = len_map;
   outlen = 0;
   while (beg < end)
     {
       wchar_t wc;
-      size_t mbclen = mbrtowc(&wc, beg, end - beg, &is);
+      size_t mbclen = mbrtowc (&wc, beg, end - beg, &is);
       if (outlen + mb_cur_max >= outalloc)
         {
+          size_t dm = m - len_map;
           out = x2nrealloc (out, &outalloc, 1);
+          len_map = xrealloc (len_map, outalloc);
           p = out + outlen;
+          m = len_map + dm;
         }
 
       if (mbclen == (size_t) -1 || mbclen == (size_t) -2 || mbclen == 0)
         {
           /* An invalid sequence, or a truncated multi-octet character.
              We treat it as a single-octet character.  */
+          *m++ = 0;
           *p++ = *beg++;
           outlen++;
           memset (&is, 0, sizeof (is));
@@ -104,12 +133,17 @@ mbtolower (const char *beg, size_t *n)
       else
         {
           beg += mbclen;
-          mbclen = wcrtomb (p, towlower ((wint_t) wc), &os);
-          p += mbclen;
-          outlen += mbclen;
+          size_t ombclen = wcrtomb (p, towlower ((wint_t) wc), &os);
+          *m = mbclen - ombclen;
+          memset (m + 1, 0, ombclen - 1);
+          m += ombclen;
+          p += ombclen;
+          outlen += ombclen;
+          lengths_differ |= (mbclen != ombclen);
         }
     }
 
+  *len_map_p = lengths_differ ? len_map : NULL;
   *n = p - out;
   *p = 0;
   return out;