Upgrade grep version 2.9 to 2.12 on the vendor branch
authorJohn Marino <draco@marino.st>
Tue, 8 May 2012 10:48:47 +0000 (12:48 +0200)
committerJohn Marino <draco@marino.st>
Tue, 8 May 2012 21:51:08 +0000 (23:51 +0200)
235 files changed:
contrib/grep/README
contrib/grep/doc/fdl.texi
contrib/grep/doc/grep.texi
contrib/grep/doc/version.texi
contrib/grep/lib/alloca.c
contrib/grep/lib/argmatch.c
contrib/grep/lib/argmatch.h
contrib/grep/lib/at-func.c [new file with mode: 0644]
contrib/grep/lib/basename-lgpl.c
contrib/grep/lib/basename.c [deleted file]
contrib/grep/lib/binary-io.h
contrib/grep/lib/bitrotate.h
contrib/grep/lib/btowc.c
contrib/grep/lib/c-ctype.c
contrib/grep/lib/c-ctype.h
contrib/grep/lib/c-strcase.h
contrib/grep/lib/c-strcasecmp.c
contrib/grep/lib/c-strcaseeq.h [new file with mode: 0644]
contrib/grep/lib/c-strncasecmp.c
contrib/grep/lib/chdir-long.c [new file with mode: 0644]
contrib/grep/lib/chdir-long.h [copied from contrib/grep/lib/mbsrtowcs.c with 62% similarity]
contrib/grep/lib/cloexec.c [new file with mode: 0644]
contrib/grep/lib/cloexec.h [new file with mode: 0644]
contrib/grep/lib/close-stream.c
contrib/grep/lib/close.c [copied from contrib/grep/lib/wcrtomb.c with 50% similarity]
contrib/grep/lib/closedir.c [new file with mode: 0644]
contrib/grep/lib/closeout.c
contrib/grep/lib/closeout.h
contrib/grep/lib/colorize-posix.c [new file with mode: 0644]
contrib/grep/lib/colorize-w32.c [new file with mode: 0644]
contrib/grep/lib/colorize.c [new file with mode: 0644]
contrib/grep/lib/colorize.h [copied from contrib/grep/src/mbsupport.h with 53% similarity]
contrib/grep/lib/config.charset
contrib/grep/lib/creat-safer.c [copied from contrib/grep/lib/exitfail.c with 68% similarity]
contrib/grep/lib/cycle-check.c [new file with mode: 0644]
contrib/grep/lib/cycle-check.h [new file with mode: 0644]
contrib/grep/lib/dev-ino.h [new file with mode: 0644]
contrib/grep/lib/dirent--.h [copied from contrib/grep/lib/exitfail.c with 74% similarity]
contrib/grep/lib/dirent-private.h [new file with mode: 0644]
contrib/grep/lib/dirent-safer.h [copied from contrib/grep/lib/quote.h with 75% similarity]
contrib/grep/lib/dirfd.c [copied from contrib/grep/lib/mbsrtowcs.c with 68% similarity]
contrib/grep/lib/dirname-lgpl.c
contrib/grep/lib/dirname.c [deleted file]
contrib/grep/lib/dirname.h
contrib/grep/lib/dosname.h
contrib/grep/lib/dup-safer.c [copied from contrib/grep/lib/mbrlen.c with 64% similarity]
contrib/grep/lib/dup.c [copied from contrib/grep/lib/mbsrtowcs.c with 53% similarity]
contrib/grep/lib/dup2.c [new file with mode: 0644]
contrib/grep/lib/error.c
contrib/grep/lib/error.h
contrib/grep/lib/exclude.c
contrib/grep/lib/exclude.h
contrib/grep/lib/exitfail.c
contrib/grep/lib/exitfail.h
contrib/grep/lib/fchdir.c [new file with mode: 0644]
contrib/grep/lib/fcntl--.h [copied from contrib/grep/lib/exitfail.c with 65% similarity]
contrib/grep/lib/fcntl-safer.h [copied from contrib/grep/lib/exitfail.c with 66% similarity]
contrib/grep/lib/fcntl.c [new file with mode: 0644]
contrib/grep/lib/fd-hook.c [new file with mode: 0644]
contrib/grep/lib/fd-hook.h [new file with mode: 0644]
contrib/grep/lib/fd-safer.c [new file with mode: 0644]
contrib/grep/lib/fdopendir.c [new file with mode: 0644]
contrib/grep/lib/filename.h [new file with mode: 0644]
contrib/grep/lib/filenamecat-lgpl.c [new file with mode: 0644]
contrib/grep/lib/filenamecat.h [copied from contrib/grep/lib/closeout.h with 64% similarity]
contrib/grep/lib/fnmatch.c
contrib/grep/lib/fnmatch_loop.c
contrib/grep/lib/fpending.c
contrib/grep/lib/fpending.h
contrib/grep/lib/fstat.c [new file with mode: 0644]
contrib/grep/lib/fstatat.c [new file with mode: 0644]
contrib/grep/lib/fts-cycle.c [new file with mode: 0644]
contrib/grep/lib/fts.c [new file with mode: 0644]
contrib/grep/lib/fts_.h [new file with mode: 0644]
contrib/grep/lib/getcwd-lgpl.c [new file with mode: 0644]
contrib/grep/lib/getdtablesize.c [new file with mode: 0644]
contrib/grep/lib/getopt.c
contrib/grep/lib/getopt1.c
contrib/grep/lib/getopt_int.h
contrib/grep/lib/getpagesize.c
contrib/grep/lib/gettext.h
contrib/grep/lib/gnulib.mk
contrib/grep/lib/hard-locale.c
contrib/grep/lib/hard-locale.h
contrib/grep/lib/hash.c
contrib/grep/lib/hash.h
contrib/grep/lib/i-ring.c [new file with mode: 0644]
contrib/grep/lib/i-ring.h [new file with mode: 0644]
contrib/grep/lib/iconv_open.c
contrib/grep/lib/ignore-value.h
contrib/grep/lib/intprops.h
contrib/grep/lib/isatty.c [new file with mode: 0644]
contrib/grep/lib/isblank.c
contrib/grep/lib/isdir.c [deleted file]
contrib/grep/lib/isdir.h [deleted file]
contrib/grep/lib/iswctype-impl.h [copied from contrib/grep/lib/wctomb.c with 76% similarity]
contrib/grep/lib/iswctype.c [copied from contrib/grep/lib/wctomb.c with 79% similarity]
contrib/grep/lib/localcharset.c
contrib/grep/lib/localcharset.h
contrib/grep/lib/localeconv.c [new file with mode: 0644]
contrib/grep/lib/lseek.c
contrib/grep/lib/lstat.c [new file with mode: 0644]
contrib/grep/lib/malloc.c
contrib/grep/lib/malloca.c
contrib/grep/lib/malloca.h
contrib/grep/lib/mbchar.c
contrib/grep/lib/mbchar.h
contrib/grep/lib/mbiter.h
contrib/grep/lib/mbrlen.c
contrib/grep/lib/mbrtowc.c
contrib/grep/lib/mbscasecmp.c
contrib/grep/lib/mbsinit.c
contrib/grep/lib/mbslen.c
contrib/grep/lib/mbsrtowcs-state.c
contrib/grep/lib/mbsrtowcs.c
contrib/grep/lib/mbsstr.c
contrib/grep/lib/mbuiter.h
contrib/grep/lib/memchr.c
contrib/grep/lib/mempcpy.c
contrib/grep/lib/memrchr.c [copied from contrib/grep/lib/memchr.c with 75% similarity]
contrib/grep/lib/minmax.h
contrib/grep/lib/msvc-inval.c [new file with mode: 0644]
contrib/grep/lib/msvc-inval.h [new file with mode: 0644]
contrib/grep/lib/msvc-nothrow.c [new file with mode: 0644]
contrib/grep/lib/msvc-nothrow.h [new file with mode: 0644]
contrib/grep/lib/nl_langinfo.c
contrib/grep/lib/obstack.c
contrib/grep/lib/obstack.h
contrib/grep/lib/open-safer.c [copied from contrib/grep/lib/mbslen.c with 52% similarity]
contrib/grep/lib/open.c
contrib/grep/lib/openat-die.c [new file with mode: 0644]
contrib/grep/lib/openat-priv.h [new file with mode: 0644]
contrib/grep/lib/openat-proc.c [new file with mode: 0644]
contrib/grep/lib/openat-safer.c [copied from contrib/grep/lib/mbslen.c with 50% similarity]
contrib/grep/lib/openat.c [new file with mode: 0644]
contrib/grep/lib/openat.h [new file with mode: 0644]
contrib/grep/lib/opendir-safer.c [new file with mode: 0644]
contrib/grep/lib/opendir.c [new file with mode: 0644]
contrib/grep/lib/pathmax.h [new file with mode: 0644]
contrib/grep/lib/pipe-safer.c [new file with mode: 0644]
contrib/grep/lib/progname.c
contrib/grep/lib/progname.h
contrib/grep/lib/propername.c
contrib/grep/lib/propername.h
contrib/grep/lib/quote.c [deleted file]
contrib/grep/lib/quote.h
contrib/grep/lib/quotearg.c
contrib/grep/lib/quotearg.h
contrib/grep/lib/readdir.c [new file with mode: 0644]
contrib/grep/lib/realloc.c
contrib/grep/lib/ref-add.sin
contrib/grep/lib/ref-del.sin
contrib/grep/lib/regcomp.c
contrib/grep/lib/regex.c
contrib/grep/lib/regex.h
contrib/grep/lib/regex_internal.c
contrib/grep/lib/regex_internal.h
contrib/grep/lib/regexec.c
contrib/grep/lib/same-inode.h [copied from contrib/grep/lib/closeout.h with 57% similarity]
contrib/grep/lib/save-cwd.c [new file with mode: 0644]
contrib/grep/lib/save-cwd.h [copied from contrib/grep/lib/fpending.c with 63% similarity]
contrib/grep/lib/savedir.c [deleted file]
contrib/grep/lib/savedir.h [deleted file]
contrib/grep/lib/stat.c
contrib/grep/lib/stpcpy.c
contrib/grep/lib/str-kmp.h
contrib/grep/lib/strcasecmp.c [copied from contrib/grep/lib/c-strcasecmp.c with 60% similarity]
contrib/grep/lib/strdup.c [new file with mode: 0644]
contrib/grep/lib/streq.h
contrib/grep/lib/strerror-override.c
contrib/grep/lib/strerror-override.h
contrib/grep/lib/strerror.c
contrib/grep/lib/striconv.c
contrib/grep/lib/striconv.h
contrib/grep/lib/stripslash.c
contrib/grep/lib/strncasecmp.c [copied from contrib/grep/lib/c-strncasecmp.c with 65% similarity]
contrib/grep/lib/strndup.c [deleted file]
contrib/grep/lib/strnlen.c
contrib/grep/lib/strnlen1.c
contrib/grep/lib/strnlen1.h
contrib/grep/lib/strtoimax.c
contrib/grep/lib/strtol.c
contrib/grep/lib/strtoll.c [copied from contrib/grep/lib/strtoul.c with 63% similarity]
contrib/grep/lib/strtoul.c
contrib/grep/lib/strtoull.c
contrib/grep/lib/trim.c
contrib/grep/lib/trim.h
contrib/grep/lib/unistd--.h [copied from contrib/grep/lib/hard-locale.h with 65% similarity]
contrib/grep/lib/unistd-safer.h [copied from contrib/grep/lib/closeout.h with 62% similarity]
contrib/grep/lib/unistr/u8-mbtoucr.c
contrib/grep/lib/unistr/u8-uctomb-aux.c
contrib/grep/lib/unistr/u8-uctomb.c
contrib/grep/lib/uniwidth/cjk.h
contrib/grep/lib/uniwidth/width.c
contrib/grep/lib/unlocked-io.h
contrib/grep/lib/verify.h
contrib/grep/lib/version-etc-fsf.c
contrib/grep/lib/version-etc.c
contrib/grep/lib/version-etc.h
contrib/grep/lib/wcrtomb.c
contrib/grep/lib/wcscoll-impl.h [new file with mode: 0644]
contrib/grep/lib/wcscoll.c [copied from contrib/grep/lib/wctomb.c with 81% similarity]
contrib/grep/lib/wctob.c
contrib/grep/lib/wctomb-impl.h
contrib/grep/lib/wctomb.c
contrib/grep/lib/wcwidth.c
contrib/grep/lib/xalloc-die.c
contrib/grep/lib/xalloc-oversized.h
contrib/grep/lib/xalloc.h
contrib/grep/lib/xmalloc.c
contrib/grep/lib/xstriconv.c
contrib/grep/lib/xstriconv.h
contrib/grep/lib/xstrndup.c [deleted file]
contrib/grep/lib/xstrndup.h [deleted file]
contrib/grep/lib/xstrtoimax.c [new file with mode: 0644]
contrib/grep/lib/xstrtol-error.c
contrib/grep/lib/xstrtol.c
contrib/grep/lib/xstrtol.h
contrib/grep/lib/xstrtoumax.c [deleted file]
contrib/grep/src/dfa.c
contrib/grep/src/dfa.h
contrib/grep/src/dfasearch.c
contrib/grep/src/egrep.c
contrib/grep/src/fgrep.c
contrib/grep/src/grep.c
contrib/grep/src/grep.h
contrib/grep/src/kwsearch.c
contrib/grep/src/kwset.c
contrib/grep/src/kwset.h
contrib/grep/src/main.c
contrib/grep/src/mbsupport.h
contrib/grep/src/pcresearch.c
contrib/grep/src/search.h
contrib/grep/src/searchutils.c
contrib/grep/src/system.h

index 9c550ee..36b377b 100644 (file)
@@ -1,4 +1,4 @@
-  Copyright (C) 1992, 1997-2002, 2004-2011 Free Software Foundation, Inc.
+  Copyright (C) 1992, 1997-2002, 2004-2012 Free Software Foundation, Inc.
 
   Copying and distribution of this file, with or without modification,
   are permitted in any medium without royalty provided the copyright
index 2caf58d..2d26c9e 100644 (file)
@@ -5,7 +5,7 @@
 @c hence no sectioning command or @node.
 
 @display
-Copyright @copyright{} 2000-2002, 2007-2008, 2010-2011 Free Software
+Copyright @copyright{} 2000-2002, 2007-2008, 2010-2012 Free Software
 Foundation, Inc.
 @uref{http://fsf.org/}
 
index 7c80f8c..000a844 100644 (file)
@@ -16,7 +16,8 @@
 @copying
 This manual is for @command{grep}, a pattern matching engine.
 
-Copyright @copyright{} 1999-2002, 2005, 2008-2011 Free Software Foundation, Inc.
+Copyright @copyright{} 1999-2002, 2005, 2008-2012 Free Software Foundation,
+Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -49,7 +50,7 @@ Texts.  A copy of the license is included in the section entitled
 @node Top
 @top grep
 
-@command{grep} prints lines that match a pattern.
+@command{grep} prints lines that contain a match for a pattern.
 
 This manual is for version @value{VERSION} of GNU Grep.
 
@@ -72,7 +73,7 @@ This manual is for version @value{VERSION} of GNU Grep.
 
 @cindex searching for a pattern
 
-@command{grep} searches the input files
+@command{grep} searches input files
 for lines containing a match to a given pattern list.
 When it finds a match in a line,
 it copies the line to standard output (by default),
@@ -116,13 +117,13 @@ There can be zero or more @var{input_file_names}.
 @section Command-line Options
 
 @command{grep} comes with a rich set of options:
-some from @sc{posix.2} and some being @sc{gnu} extensions.
-Long option names are always a @sc{gnu} extension,
-even for options that are from @sc{posix} specifications.
-Options that are specified by @sc{posix},
+some from POSIX and some being GNU extensions.
+Long option names are always a GNU extension,
+even for options that are from POSIX specifications.
+Options that are specified by POSIX,
 under their short names,
 are explicitly marked as such
-to facilitate @sc{posix}-portable programming.
+to facilitate POSIX-portable programming.
 A few option names are provided
 for compatibility with older or more exotic implementations.
 
@@ -143,7 +144,7 @@ which variant of the @command{grep} matching engine is used.
 @node Generic Program Information
 @subsection Generic Program Information
 
-@table @samp
+@table @option
 
 @item --help
 @opindex --help
@@ -164,7 +165,7 @@ This version number should be included in all bug reports.
 @node Matching Control
 @subsection Matching Control
 
-@table @samp
+@table @option
 
 @item -e @var{pattern}
 @itemx --regexp=@var{pattern}
@@ -174,7 +175,7 @@ This version number should be included in all bug reports.
 Use @var{pattern} as the pattern.
 This can be used to specify multiple search patterns,
 or to protect a pattern beginning with a @samp{-}.
-(@samp{-e} is specified by @sc{posix}.)
+(@option{-e} is specified by POSIX.)
 
 @item -f @var{file}
 @itemx --file=@var{file}
@@ -183,7 +184,7 @@ or to protect a pattern beginning with a @samp{-}.
 @cindex pattern from file
 Obtain patterns from @var{file}, one per line.
 The empty file contains zero patterns, and therefore matches nothing.
-(@samp{-f} is specified by @sc{posix}.)
+(@option{-f} is specified by POSIX.)
 
 @item -i
 @itemx -y
@@ -193,8 +194,8 @@ The empty file contains zero patterns, and therefore matches nothing.
 @opindex --ignore-case
 @cindex case insensitive search
 Ignore case distinctions in both the pattern and the input files.
-@samp{-y} is an obsolete synonym that is provided for compatibility.
-(@samp{-i} is specified by @sc{posix}.)
+@option{-y} is an obsolete synonym that is provided for compatibility.
+(@option{-i} is specified by POSIX.)
 
 @item -v
 @itemx --invert-match
@@ -203,7 +204,7 @@ Ignore case distinctions in both the pattern and the input files.
 @cindex invert matching
 @cindex print non-matching lines
 Invert the sense of matching, to select non-matching lines.
-(@samp{-v} is specified by @sc{posix}.)
+(@option{-v} is specified by POSIX.)
 
 @item -w
 @itemx --word-regexp
@@ -225,14 +226,14 @@ Word-constituent characters are letters, digits, and the underscore.
 @opindex --line-regexp
 @cindex match the whole line
 Select only those matches that exactly match the whole line.
-(@samp{-x} is specified by @sc{posix}.)
+(@option{-x} is specified by POSIX.)
 
 @end table
 
 @node General Output Control
 @subsection General Output Control
 
-@table @samp
+@table @option
 
 @item -c
 @itemx --count
@@ -241,9 +242,9 @@ Select only those matches that exactly match the whole line.
 @cindex counting lines
 Suppress normal output;
 instead print a count of matching lines for each input file.
-With the @samp{-v}, @samp{--invert-match} option,
+With the @option{-v} (@option{--invert-match}) option,
 count non-matching lines.
-(@samp{-c} is specified by @sc{posix}.)
+(@option{-c} is specified by POSIX.)
 
 @item --color[=@var{WHEN}]
 @itemx --colour[=@var{WHEN}]
@@ -254,11 +255,11 @@ Surround the matched (non-empty) strings, matching lines, context lines,
 file names, line numbers, byte offsets, and separators (for fields and
 groups of context lines) with escape sequences to display them in color
 on the terminal.
-The colors are defined by the environment variable @var{GREP_COLORS}
+The colors are defined by the environment variable @env{GREP_COLORS}
 and default to @samp{ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36}
 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 @var{GREP_COLOR} is still supported,
+The deprecated environment variable @env{GREP_COLOR} is still supported,
 but its setting does not have priority;
 it defaults to `01;31' (bold red)
 which only covers the color for matched text.
@@ -272,7 +273,7 @@ which only covers the color for matched text.
 Suppress normal output;
 instead print the name of each input file from which
 no output would normally have been printed.
-The scanning of every file will stop on the first match.
+The scanning of each file stops on the first match.
 
 @item -l
 @itemx --files-with-matches
@@ -282,8 +283,8 @@ The scanning of every file will stop on the first match.
 Suppress normal output;
 instead print the name of each input file from which
 output would normally have been printed.
-The scanning of every file will stop on the first match.
-(@samp{-l} is specified by @sc{posix}.)
+The scanning of each file stops on the first match.
+(@option{-l} is specified by POSIX.)
 
 @item -m @var{num}
 @itemx --max-count=@var{num}
@@ -322,9 +323,9 @@ When @command{grep} stops after @var{num} matching lines,
 it outputs any trailing context lines.
 Since context does not include matching lines,
 @command{grep} will stop when it encounters another matching line.
-When the @samp{-c} or @samp{--count} option is also used,
+When the @option{-c} or @option{--count} option is also used,
 @command{grep} does not output a count greater than @var{num}.
-When the @samp{-v} or @samp{--invert-match} option is also used,
+When the @option{-v} or @option{--invert-match} option is also used,
 @command{grep} stops after outputting @var{num} non-matching lines.
 
 @item -o
@@ -345,8 +346,8 @@ with each such part on a separate output line.
 Quiet; do not write anything to standard output.
 Exit immediately with zero status if any match is found,
 even if an error was detected.
-Also see the @samp{-s} or @samp{--no-messages} option.
-(@samp{-q} is specified by @sc{posix}.)
+Also see the @option{-s} or @option{--no-messages} option.
+(@option{-q} is specified by POSIX.)
 
 @item -s
 @itemx --no-messages
@@ -355,17 +356,18 @@ Also see the @samp{-s} or @samp{--no-messages} option.
 @cindex suppress error messages
 Suppress error messages about nonexistent or unreadable files.
 Portability note:
-unlike @sc{gnu} @command{grep},
-7th Edition Unix @command{grep} did not conform to @sc{posix},
-because it lacked @samp{-q}
-and its @samp{-s} option behaved like
-@sc{gnu} @command{grep}'s @samp{-q} option.
-@sc{usg}-style @command{grep} also lacked @samp{-q}
-but its @samp{-s} option behaved like @sc{gnu} @command{grep}'s.
+unlike GNU @command{grep},
+7th Edition Unix @command{grep} did not conform to POSIX,
+because it lacked @option{-q}
+and its @option{-s} option behaved like
+GNU @command{grep}'s @option{-q} option.@footnote{Of course, 7th Edition
+Unix predated POSIX by several years!}
+USG-style @command{grep} also lacked @option{-q}
+but its @option{-s} option behaved like GNU @command{grep}'s.
 Portable shell scripts should avoid both
-@samp{-q} and @samp{-s} and should redirect
+@option{-q} and @option{-s} and should redirect
 standard and error output to @file{/dev/null} instead.
-(@samp{-s} is specified by @sc{posix}.)
+(@option{-s} is specified by POSIX.)
 
 @end table
 
@@ -376,7 +378,7 @@ When several prefix fields are to be output,
 the order is always file name, line number, and byte offset,
 regardless of the order in which these options were specified.
 
-@table @samp
+@table @option
 
 @item -b
 @itemx --byte-offset
@@ -385,11 +387,11 @@ regardless of the order in which these options were specified.
 @cindex byte offset
 Print the 0-based byte offset within the input file
 before each line of output.
-If @samp{-o} (@samp{--only-matching}) is specified,
+If @option{-o} (@option{--only-matching}) is specified,
 print the offset of the matching part itself.
-When @command{grep} runs on @sc{ms-dos} or @sc{ms}-Windows,
+When @command{grep} runs on MS-DOS or MS-Windows,
 the printed byte offsets depend on whether
-the @samp{-u} (@samp{--unix-byte-offsets}) option is used;
+the @option{-u} (@option{--unix-byte-offsets}) option is used;
 see below.
 
 @item -H
@@ -427,7 +429,7 @@ gzip -cd foo.gz | grep --label=foo -H something
 @opindex --line-number
 @cindex line numbering
 Prefix each line of output with the 1-based line number within its input file.
-(@samp{-n} is specified by @sc{posix}.)
+(@option{-n} is specified by POSIX.)
 
 @item -T
 @itemx --initial-tab
@@ -437,7 +439,7 @@ Prefix each line of output with the 1-based line number within its input file.
 Make sure that the first character of actual line content lies on a tab stop,
 so that the alignment of tabs looks normal.
 This is useful with options that prefix their output to the actual content:
-@samp{-H}, @samp{-n}, and @samp{-b}.
+@option{-H}, @option{-n}, and @option{-b}.
 In order to improve the probability that lines
 from a single file will all start at the same column,
 this also causes the line number and byte offset (if present)
@@ -447,23 +449,23 @@ to be printed in a minimum-size field width.
 @itemx --unix-byte-offsets
 @opindex -u
 @opindex --unix-byte-offsets
-@cindex @sc{ms-dos}/@sc{ms}-Windows byte offsets
-@cindex byte offsets, on @sc{ms-dos}/@sc{ms}-Windows
+@cindex MS-DOS/MS-Windows byte offsets
+@cindex byte offsets, on MS-DOS/MS-Windows
 Report Unix-style byte offsets.
 This option causes @command{grep} to report byte offsets
 as if the file were a Unix-style text file,
 i.e., the byte offsets ignore the @code{CR} characters that were stripped.
 This will produce results identical
 to running @command{grep} on a Unix machine.
-This option has no effect unless the @samp{-b} option is also used;
-it has no effect on platforms other than @sc{ms-dos} and @sc{ms}-Windows.
+This option has no effect unless the @option{-b} option is also used;
+it has no effect on platforms other than MS-DOS and MS-Windows.
 
 @item -Z
 @itemx --null
 @opindex -Z
 @opindex --null
 @cindex zero-terminated file names
-Output a zero byte (the @sc{ascii} @code{NUL} character)
+Output a zero byte (the ASCII @code{NUL} character)
 instead of the character that normally follows a file name.
 For example,
 @samp{grep -lZ} outputs a zero byte after each file name
@@ -482,10 +484,10 @@ even those that contain newline characters.
 
 Regardless of how these options are set,
 @command{grep} will never print any given line more than once.
-If the @samp{-o} or @samp{--only-matching} option is specified,
+If the @option{-o} (@option{--only-matching}) option is specified,
 these options have no effect and a warning is given upon their use.
 
-@table @samp
+@table @option
 
 @item -A @var{num}
 @itemx --after-context=@var{num}
@@ -516,7 +518,7 @@ Print @var{num} lines of leading and trailing output context.
 @opindex --group-separator
 @cindex group separator
 When @option{-A}, @option{-B} or @option{-C} are in use,
-print @var{string} instead of @samp{--} around disjoint groups
+print @var{string} instead of @option{--} around disjoint groups
 of lines.
 
 @item --no-group-separator
@@ -527,26 +529,44 @@ print disjoint groups of lines adjacent to each other.
 
 @end table
 
+Here are some points about how @command{grep} chooses
+the separator to print between prefix fields and line content:
+
+@itemize @bullet
+@item
 Matching lines normally use @samp{:} as a separator
 between prefix fields and actual line content.
+
+@item
 Context (i.e., non-matching) lines use @samp{-} instead.
+
+@item
 When no context is specified,
 matching lines are simply output one right after another.
+
+@item
 When nonzero context is specified,
 lines that are adjacent in the input form a group
 and are output one right after another, while
 a separator appears by default between disjoint groups on a line
-of its own and without any prefix.  The default separator
+of its own and without any prefix.
+
+@item
+The default separator
 is @samp{--}, however whether to include it and its appearance
-can be changed with the options above.  Each group may contain
+can be changed with the options above.
+
+@item
+Each group may contain
 several matching lines when they are close enough to each other
 that two otherwise adjacent but divided groups connect
 and can just merge into a single contiguous one.
+@end itemize
 
 @node File and Directory Selection
 @subsection File and Directory Selection
 
-@table @samp
+@table @option
 
 @item -a
 @itemx --text
@@ -557,7 +577,7 @@ and can just merge into a single contiguous one.
 Process a binary file as if it were text;
 this is equivalent to the @samp{--binary-files=text} option.
 
-@itemx --binary-files=@var{type}
+@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,
@@ -566,12 +586,15 @@ By default, @var{type} is @samp{binary},
 and @command{grep} normally outputs either
 a one-line message saying that a binary file matches,
 or no message if there is no match.
+
 If @var{type} is @samp{without-match},
 @command{grep} assumes that a binary file does not match;
-this is equivalent to the @samp{-I} option.
+this is equivalent to the @option{-I} option.
+
 If @var{type} is @samp{text},
 @command{grep} processes a binary file as if it were text;
-this is equivalent to the @samp{-a} option.
+this is equivalent to the @option{-a} option.
+
 @emph{Warning:} @samp{--binary-files=text} might output binary garbage,
 which can have nasty side effects
 if the output is a terminal and
@@ -583,16 +606,22 @@ if the terminal driver interprets some of it as commands.
 @opindex --devices
 @cindex device search
 If an input file is a device, FIFO, or socket, use @var{action} to process it.
-By default, @var{action} is @samp{read},
-which means that devices are read just as if they were ordinary files.
+If @var{action} is @samp{read},
+all devices are read just as if they were ordinary files.
 If @var{action} is @samp{skip},
 devices, FIFOs, and sockets are silently skipped.
+By default, devices are read if they are on the command line or if the
+@option{-R} (@option{--dereference-recursive}) option is used, and are
+skipped if they are encountered recursively and the @option{-r}
+(@option{--recursive}) option is used.
+This option has no effect on a file that is read via standard input.
 
 @item -d @var{action}
 @itemx --directories=@var{action}
 @opindex -d
 @opindex --directories
 @cindex directory search
+@cindex symbolic links
 If an input file is a directory, use @var{action} to process it.
 By default, @var{action} is @samp{read},
 which means that directories are read just as if they were ordinary files
@@ -601,8 +630,9 @@ and will cause @command{grep}
 to print error messages for every directory or silently skip them).
 If @var{action} is @samp{skip}, directories are silently skipped.
 If @var{action} is @samp{recurse},
-@command{grep} reads all files under each directory, recursively;
-this is equivalent to the @samp{-r} option.
+@command{grep} reads all files under each directory, recursively,
+following command-line symbolic links and skipping other symlinks;
+this is equivalent to the @option{-r} option.
 
 @item --exclude=@var{glob}
 @opindex --exclude
@@ -620,7 +650,7 @@ and @code{\} to quote a wildcard or backslash character literally.
 @cindex searching directory trees
 Skip files whose base name matches any of the file-name globs
 read from @var{file} (using wildcard matching as described
-under @samp{--exclude}).
+under @option{--exclude}).
 
 @item --exclude-dir=@var{dir}
 @opindex --exclude-dir
@@ -637,25 +667,37 @@ this is equivalent to the @samp{--binary-files=without-match} option.
 @cindex include files
 @cindex searching directory trees
 Search only files whose base name matches @var{glob}
-(using wildcard matching as described under @samp{--exclude}).
+(using wildcard matching as described under @option{--exclude}).
 
 @item -r
-@itemx -R
 @itemx --recursive
 @opindex -r
 @opindex --recursive
 @cindex recursive search
 @cindex searching directory trees
-For each directory mentioned on the command line,
+@cindex symbolic links
+For each directory operand,
 read and process all files in that directory, recursively.
+Follow symbolic links on the command line, but skip symlinks
+that are encountered recursively.
 This is the same as the @samp{--directories=recurse} option.
 
+@item -R
+@itemx --dereference-recursive
+@opindex -R
+@opindex --dereference-recursive
+@cindex recursive search
+@cindex searching directory trees
+@cindex symbolic links
+For each directory operand, read and process all files in that
+directory, recursively, following all symbolic links.
+
 @end table
 
 @node Other Options
 @subsection Other Options
 
-@table @samp
+@table @option
 
 @item --line-buffered
 @opindex --line-buffered
@@ -666,7 +708,8 @@ This can cause a performance penalty.
 @item --mmap
 @opindex --mmap
 @cindex memory mapped input
-This option is ignored for backwards compatibility.  It used to read
+This option is deprecated and now elicits a warning, but is otherwise a no-op.
+It used to make @command{grep} read
 input with the @code{mmap} system call, instead of the default @code{read}
 system call.  On modern systems, @code{mmap} would rarely if ever yield
 better performance.
@@ -675,21 +718,21 @@ better performance.
 @itemx --binary
 @opindex -U
 @opindex --binary
-@cindex @sc{ms-dos}/@sc{ms}-Windows binary files
-@cindex binary files, @sc{ms-dos}/@sc{ms}-Windows
+@cindex MS-DOS/MS-Windows binary files
+@cindex binary files, MS-DOS/MS-Windows
 Treat the file(s) as binary.
-By default, under @sc{ms-dos} and @sc{ms}-Windows,
+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.
 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).
-Specifying @samp{-U} overrules this guesswork,
+Specifying @option{-U} overrules this guesswork,
 causing all files to be read and passed to the matching mechanism verbatim;
 if the file is a text file with @code{CR/LF} pairs at the end of each line,
 this will cause some regular expressions to fail.
 This option has no effect
-on platforms other than @sc{ms-dos} and @sc{ms}-Windows.
+on platforms other than MS-DOS and MS-Windows.
 
 @item -z
 @itemx --null-data
@@ -697,8 +740,8 @@ on platforms other than @sc{ms-dos} and @sc{ms}-Windows.
 @opindex --null-data
 @cindex zero-terminated lines
 Treat the input as a set of lines, each terminated by a zero byte (the
-@sc{ascii} @code{NUL} character) instead of a newline.
-Like the @samp{-Z} or @samp{--null} option,
+ASCII @code{NUL} character) instead of a newline.
+Like the @option{-Z} or @option{--null} option,
 this option can be used with commands like
 @samp{sort -z} to process arbitrary file names.
 
@@ -722,7 +765,41 @@ for the @code{LC_MESSAGES} category.
 The @samp{C} locale is used if none of these environment variables are set,
 if the locale catalog is not installed,
 or if @command{grep} was not compiled
-with national language support (@sc{nls}).
+with national language support (NLS).
+
+Many of the environment variables in the following list let you
+control highlighting using
+Select Graphic Rendition (SGR)
+commands interpreted by the terminal or terminal emulator.
+(See the
+section
+in the documentation of your text terminal
+for permitted values and their meanings as character attributes.)
+These substring values are integers in decimal representation
+and can be concatenated with semicolons.
+@command{grep} takes care of assembling the result
+into a complete SGR sequence (@samp{\33[}...@samp{m}).
+Common values to concatenate include
+@samp{1} for bold,
+@samp{4} for underline,
+@samp{5} for blink,
+@samp{7} for inverse,
+@samp{39} for default foreground color,
+@samp{30} to @samp{37} for foreground colors,
+@samp{90} to @samp{97} for 16-color mode foreground colors,
+@samp{38;5;0} to @samp{38;5;255}
+for 88-color and 256-color modes foreground colors,
+@samp{49} for default background color,
+@samp{40} to @samp{47} for background colors,
+@samp{100} to @samp{107} for 16-color mode background colors,
+and @samp{48;5;0} to @samp{48;5;255}
+for 88-color and 256-color modes background colors.
+
+The two-letter names used in the @env{GREP_COLORS} environment variable
+(and some of the others) refer to terminal ``capabilities,'' the ability
+of a terminal to highlight text, or change its color, and so on.
+These capabilities are stored in an online database and accessed by
+the @code{terminfo} library.
 
 @cindex environment variables
 
@@ -743,17 +820,24 @@ whitespace.
 A backslash escapes the next character, so it can be used to
 specify an option containing whitespace or a backslash.
 
+The @code{GREP_OPTIONS} value does not affect whether @command{grep}
+without file operands searches standard input or the working
+directory; that is affected only by command-line options.  For
+example, the command @samp{grep PAT} searches standard input and the
+command @samp{grep -r PAT} searches the working directory, regardless
+of whether @code{GREP_OPTIONS} contains @option{-r}.
+
 @item GREP_COLOR
 @vindex GREP_COLOR @r{environment variable}
 @cindex highlight markers
 This variable specifies the color used to highlight matched (non-empty) text.
-It is deprecated in favor of @code{GREP_COLORS}, but still supported.
-The @samp{mt}, @samp{ms}, and @samp{mc} capabilities of @code{GREP_COLORS}
+It is deprecated in favor of @env{GREP_COLORS}, but still supported.
+The @samp{mt}, @samp{ms}, and @samp{mc} capabilities of @env{GREP_COLORS}
 have priority over it.
 It can only specify the color used to highlight
 the matching non-empty text in any matching line
-(a selected line when the @samp{-v} command-line option is omitted,
-or a context line when @samp{-v} is specified).
+(a selected line when the @option{-v} command-line option is omitted,
+or a context line when @option{-v} is specified).
 The default is @samp{01;31},
 which means a bold red foreground text on the terminal's default background.
 
@@ -762,7 +846,7 @@ which means a bold red foreground text on the terminal's default background.
 @cindex highlight markers
 This variable specifies the colors and other attributes
 used to highlight various parts of the output.
-Its value is a colon-separated list of capabilities
+Its value is a colon-separated list of @code{terminfo} capabilities
 that defaults to @samp{ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36}
 with the @samp{rv} and @samp{ne} boolean capabilities omitted (i.e., false).
 Supported capabilities are as follows.
@@ -772,10 +856,10 @@ Supported capabilities are as follows.
 @vindex sl GREP_COLORS @r{capability}
 SGR substring for whole selected lines
 (i.e.,
-matching lines when the @samp{-v} command-line option is omitted,
-or non-matching lines when @samp{-v} is specified).
+matching lines when the @option{-v} command-line option is omitted,
+or non-matching lines when @option{-v} is specified).
 If however the boolean @samp{rv} capability
-and the @samp{-v} command-line option are both specified,
+and the @option{-v} command-line option are both specified,
 it applies to context matching lines instead.
 The default is empty (i.e., the terminal's default color pair).
 
@@ -783,10 +867,10 @@ The default is empty (i.e., the terminal's default color pair).
 @vindex cx GREP_COLORS @r{capability}
 SGR substring for whole context lines
 (i.e.,
-non-matching lines when the @samp{-v} command-line option is omitted,
-or matching lines when @samp{-v} is specified).
+non-matching lines when the @option{-v} command-line option is omitted,
+or matching lines when @option{-v} is specified).
 If however the boolean @samp{rv} capability
-and the @samp{-v} command-line option are both specified,
+and the @option{-v} command-line option are both specified,
 it applies to selected non-matching lines instead.
 The default is empty (i.e., the terminal's default color pair).
 
@@ -794,15 +878,15 @@ The default is empty (i.e., the terminal's default color pair).
 @vindex rv GREP_COLORS @r{capability}
 Boolean value that reverses (swaps) the meanings of
 the @samp{sl=} and @samp{cx=} capabilities
-when the @samp{-v} command-line option is specified.
+when the @option{-v} command-line option is specified.
 The default is false (i.e., the capability is omitted).
 
 @item mt=01;31
 @vindex mt GREP_COLORS @r{capability}
 SGR substring for matching non-empty text in any matching line
 (i.e.,
-a selected line when the @samp{-v} command-line option is omitted,
-or a context line when @samp{-v} is specified).
+a selected line when the @option{-v} command-line option is omitted,
+or a context line when @option{-v} is specified).
 Setting this is equivalent to setting both @samp{ms=} and @samp{mc=}
 at once to the same value.
 The default is a bold red text foreground over the current line background.
@@ -810,17 +894,17 @@ The default is a bold red text foreground over the current line background.
 @item ms=01;31
 @vindex ms GREP_COLORS @r{capability}
 SGR substring for matching non-empty text in a selected line.
-(This is only used when the @samp{-v} command-line option is omitted.)
+(This is used only when the @option{-v} command-line option is omitted.)
 The effect of the @samp{sl=} (or @samp{cx=} if @samp{rv}) capability
-remains active when this kicks in.
+remains active when this takes effect.
 The default is a bold red text foreground over the current line background.
 
 @item mc=01;31
 @vindex mc GREP_COLORS @r{capability}
 SGR substring for matching non-empty text in a context line.
-(This is only used when the @samp{-v} command-line option is specified.)
+(This is used only when the @option{-v} command-line option is specified.)
 The effect of the @samp{cx=} (or @samp{sl=} if @samp{rv}) capability
-remains active when this kicks in.
+remains active when this takes effect.
 The default is a bold red text foreground over the current line background.
 
 @item fn=35
@@ -855,7 +939,7 @@ each time a colorized item ends.
 This is needed on terminals on which EL is not supported.
 It is otherwise useful on terminals
 for which the @code{back_color_erase}
-(@code{bce}) boolean terminfo capability does not apply,
+(@code{bce}) boolean @code{terminfo} capability does not apply,
 when the chosen highlight colors do not affect the background,
 or when EL is too slow or causes too much flicker.
 The default is false (i.e., the capability is omitted).
@@ -864,28 +948,6 @@ The default is false (i.e., the capability is omitted).
 Note that boolean capabilities have no @samp{=}... part.
 They are omitted (i.e., false) by default and become true when specified.
 
-See the Select Graphic Rendition (SGR) section
-in the documentation of your text terminal
-for permitted values and their meaning as character attributes.
-These substring values are integers in decimal representation
-and can be concatenated with semicolons.
-@command{grep} takes care of assembling the result
-into a complete SGR sequence (@samp{\33[}...@samp{m}).
-Common values to concatenate include
-@samp{1} for bold,
-@samp{4} for underline,
-@samp{5} for blink,
-@samp{7} for inverse,
-@samp{39} for default foreground color,
-@samp{30} to @samp{37} for foreground colors,
-@samp{90} to @samp{97} for 16-color mode foreground colors,
-@samp{38;5;0} to @samp{38;5;255}
-for 88-color and 256-color modes foreground colors,
-@samp{49} for default background color,
-@samp{40} to @samp{47} for background colors,
-@samp{100} to @samp{107} for 16-color mode background colors,
-and @samp{48;5;0} to @samp{48;5;255}
-for 88-color and 256-color modes background colors.
 
 @item LC_ALL
 @itemx LC_COLLATE
@@ -926,9 +988,9 @@ The default @samp{C} locale uses American English messages.
 
 @item POSIXLY_CORRECT
 @vindex POSIXLY_CORRECT @r{environment variable}
-If set, @command{grep} behaves as @sc{posix.2} requires; otherwise,
-@command{grep} behaves more like other @sc{gnu} programs.
-@sc{posix.2}
+If set, @command{grep} behaves as POSIX requires; otherwise,
+@command{grep} behaves more like other GNU programs.
+POSIX
 requires that options that
 follow file names must be treated as file names;
 by default,
@@ -946,7 +1008,7 @@ even if it appears to be one.
 A shell can put this variable in the environment for each command it runs,
 specifying which operands are the results of file name wildcard expansion
 and therefore should not be treated as options.
-This behavior is available only with the @sc{gnu} C library,
+This behavior is available only with the GNU C library,
 and only when @code{POSIXLY_CORRECT} is not set.
 
 @end table
@@ -961,7 +1023,7 @@ Normally, the exit status is 0 if selected lines are found and 1 otherwise.
 But the exit status is 2 if an error occurred, unless the @option{-q} or
 @option{--quiet} or @option{--silent} option is used and a selected line
 is found.
-Note, however, that @sc{posix} only mandates,
+Note, however, that POSIX only mandates,
 for programs such as @command{grep}, @command{cmp}, and @command{diff},
 that the exit status in case of error be greater than 1;
 it is therefore advisable, for the sake of portability,
@@ -972,17 +1034,19 @@ instead of strict equality with@ 2.
 @node grep Programs
 @section @command{grep} Programs
 @cindex @command{grep} programs
-@cindex variants of @command{gerp}
+@cindex variants of @command{grep}
 
 @command{grep} searches the named input files
-(or standard input if no files are named,
-or the file name @file{-} is given)
 for lines containing a match to the given pattern.
 By default, @command{grep} prints the matching lines.
+A file named @file{-} stands for standard input.
+If no input is specified, @command{grep} searches the working
+directory @file{.} if given a command-line option specifying
+recursion; otherwise, @command{grep} searches standard input.
 There are four major variants of @command{grep},
 controlled by the following options.
 
-@table @samp
+@table @option
 
 @item -G
 @itemx --basic-regexp
@@ -998,7 +1062,7 @@ This is the default.
 @opindex --extended-regexp
 @cindex matching extended regular expressions
 Interpret the pattern as an extended regular expression (ERE).
-(@samp{-E} is specified by @sc{posix}.)
+(@option{-E} is specified by POSIX.)
 
 @item -F
 @itemx --fixed-strings
@@ -1007,7 +1071,7 @@ Interpret the pattern as an extended regular expression (ERE).
 @cindex matching fixed strings
 Interpret the pattern as a list of fixed strings, separated
 by newlines, any of which is to be matched.
-(@samp{-F} is specified by @sc{posix}.)
+(@option{-F} is specified by POSIX.)
 
 @item -P
 @itemx --perl-regexp
@@ -1040,15 +1104,15 @@ by using various operators to combine smaller expressions.
 @command{grep} understands
 three different versions of regular expression syntax:
 ``basic,'' (BRE) ``extended'' (ERE) and ``perl''.
-In @sc{gnu} @command{grep},
-there is no difference in available functionality between basic and
+In GNU @command{grep},
+there is no difference in available functionality between the basic and
 extended syntaxes.
 In other implementations, basic regular expressions are less powerful.
 The following description applies to extended regular expressions;
 differences for basic regular expressions are summarized afterwards.
 Perl regular expressions give additional functionality, and are
-documented in pcresyntax(3) and pcrepattern(3), but may not be
-available on every system.
+documented in the @i{pcresyntax}(3) and @i{pcrepattern}(3) manual pages,
+but may not be available on every system.
 
 @menu
 * Fundamental Structure::
@@ -1125,6 +1189,7 @@ The preceding item is matched at least @var{n} times, but not more than
 
 @end table
 
+The empty regular expression matches the empty string.
 Two regular expressions may be concatenated;
 the resulting regular expression
 matches any string formed by concatenating two substrings
@@ -1132,7 +1197,7 @@ that respectively match the concatenated expressions.
 
 Two regular expressions may be joined by the infix operator @samp{|};
 the resulting regular expression
-matches any string matching either alternalte expression.
+matches any string matching either alternate expression.
 
 Repetition takes precedence over concatenation,
 which in turn takes precedence over alternation.
@@ -1171,8 +1236,8 @@ of bracket expressions, you can use the @samp{C} locale by setting the
 Finally, certain named classes of characters are predefined within
 bracket expressions, as follows.
 Their interpretation depends on the @code{LC_CTYPE} locale;
-the interpretation below is that of the @samp{C} locale,
-which is the default if no @code{LC_CTYPE} locale is specified.
+for example, @samp{[[:alnum:]]} means the character class of numbers and letters
+in the current locale.
 
 @cindex classes of characters
 @cindex character classes
@@ -1182,13 +1247,13 @@ which is the default if no @code{LC_CTYPE} locale is specified.
 @opindex alnum @r{character class}
 @cindex alphanumeric characters
 Alphanumeric characters:
-@samp{[:alpha:]} and @samp{[:digit:]}.
+@samp{[:alpha:]} and @samp{[:digit:]}; in the @samp{C} locale and ASCII character encoding, this is the same as @samp{[0-9A-Za-z]}.
 
 @item [:alpha:]
 @opindex alpha @r{character class}
 @cindex alphabetic characters
 Alphabetic characters:
-@samp{[:lower:]} and @samp{[:upper:]}.
+@samp{[:lower:]} and @samp{[:upper:]}; in the @samp{C} locale and ASCII character encoding, this is the same as @samp{[A-Za-z]}.
 
 @item [:blank:]
 @opindex blank @r{character class}
@@ -1200,7 +1265,7 @@ space and tab.
 @opindex cntrl @r{character class}
 @cindex control characters
 Control characters.
-In @sc{ascii}, these characters have octal codes 000
+In ASCII, these characters have octal codes 000
 through 037, and 177 (@code{DEL}).
 In other character sets, these are
 the equivalent characters, if any.
@@ -1220,7 +1285,8 @@ Graphical characters:
 @item [:lower:]
 @opindex lower @r{character class}
 @cindex lower-case letters
-Lower-case letters:
+Lower-case letters; in the @samp{C} locale and ASCII character
+encoding, this is
 @code{a b c d e f g h i j k l m n o p q r s t u v w x y z}.
 
 @item [:print:]
@@ -1232,21 +1298,23 @@ Printable characters:
 @item [:punct:]
 @opindex punct @r{character class}
 @cindex punctuation characters
-Punctuation characters:
+Punctuation characters; in the @samp{C} locale and ASCII character
+encoding, this is
 @code{!@: " # $ % & ' ( ) * + , - .@: / : ; < = > ?@: @@ [ \ ] ^ _ ` @{ | @} ~}.
 
 @item [:space:]
 @opindex space @r{character class}
 @cindex space characters
 @cindex whitespace characters
-Space characters:
+Space characters: in the @samp{C} locale, this is
 tab, newline, vertical tab, form feed, carriage return, and space.
 @xref{Usage}, for more discussion of matching newlines.
 
 @item [:upper:]
 @opindex upper @r{character class}
 @cindex upper-case letters
-Upper-case letters:
+Upper-case letters: in the @samp{C} locale and ASCII character
+encoding, this is
 @code{A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}.
 
 @item [:xdigit:]
@@ -1257,12 +1325,9 @@ Hexadecimal digits:
 @code{0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f}.
 
 @end table
-For example, @samp{[[:alnum:]]} means @samp{[0-9A-Za-z]}, except the latter
-depends upon the @samp{C} locale and the @sc{ascii} character
-encoding, whereas the former is independent of locale and character set.
-(Note that the brackets in these class names are
+Note that the brackets in these class names are
 part of the symbolic names, and must be included in addition to
-the brackets delimiting the bracket expression.)
+the brackets delimiting the bracket expression.
 
 @anchor{invalid-bracket-expr}
 If you mistakenly omit the outer brackets, and search for say, @samp{[:upper:]},
@@ -1318,28 +1383,28 @@ takes a special meaning:
 
 @table @samp
 
-@item @samp{\b}
+@item \b
 Match the empty string at the edge of a word.
 
-@item @samp{\B}
+@item \B
 Match the empty string provided it's not at the edge of a word.
 
-@item @samp{\<}
+@item \<
 Match the empty string at the beginning of word.
 
-@item @samp{\>}
+@item \>
 Match the empty string at the end of word.
 
-@item @samp{\w}
-Match word constituent, it is a synonym for @samp{[[:alnum:]]}.
+@item \w
+Match word constituent, it is a synonym for @samp{[_[:alnum:]]}.
 
-@item @samp{\W}
-Match non-word constituent, it is a synonym for @samp{[^[:alnum:]]}.
+@item \W
+Match non-word constituent, it is a synonym for @samp{[^_[:alnum:]]}.
 
-@item @samp{\s}
+@item \s
 Match whitespace, it is a synonym for @samp{[[:space:]]}.
 
-@item @samp{\S}
+@item \S
 Match non-whitespace, it is a synonym for @samp{[^[:space:]]}.
 
 @end table
@@ -1353,6 +1418,8 @@ For example, @samp{\brat\b} matches the separate word @samp{rat},
 
 The caret @samp{^} and the dollar sign @samp{$} are meta-characters that
 respectively match the empty string at the beginning and end of a line.
+They are termed @dfn{anchors}, since they force the match to be ``anchored''
+to beginning or end of a line, respectively.
 
 @node Back-references and Subexpressions
 @section Back-references and Subexpressions
@@ -1368,7 +1435,7 @@ the back-reference makes the whole match fail.
 For example, @samp{a(.)|b\1}
 will not match @samp{ba}.
 When multiple regular expressions are given with
-@samp{-e} or from a file (@samp{-f file}),
+@option{-e} or from a file (@samp{-f @var{file}}),
 back-references are local to each expression.
 
 @node Basic vs Extended
@@ -1386,13 +1453,13 @@ and some @command{egrep} implementations support @samp{\@{} instead, so
 portable scripts should avoid @samp{@{} in @samp{grep@ -E} patterns and
 should use @samp{[@{]} to match a literal @samp{@{}.
 
-@sc{gnu} @command{grep@ -E} attempts to support traditional usage by
+GNU @command{grep@ -E} attempts to support traditional usage by
 assuming that @samp{@{} is not special if it would be the start of an
 invalid interval specification.
 For example, the command
 @samp{grep@ -E@ '@{1'} searches for the two-character string @samp{@{1}
 instead of reporting a syntax error in the regular expression.
-@sc{posix.2} allows this behavior as an extension, but portable scripts
+POSIX allows this behavior as an extension, but portable scripts
 should avoid it.
 
 
@@ -1400,7 +1467,7 @@ should avoid it.
 @chapter Usage
 
 @cindex usage, examples
-Here is an example command that invokes @sc{gnu} @command{grep}:
+Here is an example command that invokes GNU @command{grep}:
 
 @example
 grep -i 'hello.*world' menu.h main.c
@@ -1411,7 +1478,7 @@ This lists all lines in the files @file{menu.h} and @file{main.c} that
 contain the string @samp{hello} followed by the string @samp{world};
 this is because @samp{.*} matches zero or more characters within a line.
 @xref{Regular Expressions}.
-The @samp{-i} option causes @command{grep}
+The @option{-i} option causes @command{grep}
 to ignore case, causing it to match the line @samp{Hello, world!}, which
 it would not otherwise match.
 @xref{Invoking}, for more details about
@@ -1455,14 +1522,11 @@ find /home/gigi -name '*.c' -print0 | xargs -0r grep -H 'hello'
 This differs from the command:
 
 @example
-grep -rH 'hello' *.c
+grep -H 'hello' *.c
 @end example
 
 which merely looks for @samp{hello} in all files in the current
 directory whose names end in @samp{.c}.
-Here the @option{-r} is
-probably unnecessary, as recursion occurs only in the unlikely event
-that one of @samp{.c} files is a directory.
 The @samp{find ...} command line above is more similar to the command:
 
 @example
@@ -1478,7 +1542,7 @@ grep -e '--cut here--' *
 
 @noindent
 searches for all lines matching @samp{--cut here--}.
-Without @samp{-e},
+Without @option{-e},
 @command{grep} would attempt to parse @samp{--cut here--} as a list of
 options.
 
@@ -1529,7 +1593,7 @@ gets you:
 /etc/passwd:eli:x:2098:1000:Eli Smith:/home/eli:/bin/bash
 @end example
 
-Alternatively, use @samp{-H}, which is a @sc{gnu} extension:
+Alternatively, use @option{-H}, which is a GNU extension:
 
 @example
 grep -H 'eli' /etc/passwd
@@ -1556,13 +1620,13 @@ Why does @command{grep} report ``Binary file matches''?
 If @command{grep} listed all matching ``lines'' from a binary file, it
 would probably generate output that is not useful, and it might even
 muck up your display.
-So @sc{gnu} @command{grep} suppresses output from
+So GNU @command{grep} suppresses output from
 files that appear to be binary files.
-To force @sc{gnu} @command{grep}
+To force GNU @command{grep}
 to output lines even from files that appear to be binary, use the
-@samp{-a} or @samp{--binary-files=text} option.
+@option{-a} or @samp{--binary-files=text} option.
 To eliminate the
-``Binary file matches'' messages, use the @samp{-I} or
+``Binary file matches'' messages, use the @option{-I} or
 @samp{--binary-files=without-match} option.
 
 @item
@@ -1571,11 +1635,11 @@ Why doesn't @samp{grep -lv} print non-matching file names?
 @samp{grep -lv} lists the names of all files containing one or more
 lines that do not match.
 To list the names of all files that contain no
-matching lines, use the @samp{-L} or @samp{--files-without-match}
+matching lines, use the @option{-L} or @option{--files-without-match}
 option.
 
 @item
-I can do @sc{or} with @samp{|}, but what about @sc{and}?
+I can do ``OR'' with @samp{|}, but what about ``AND''?
 
 @example
 grep 'paul' /etc/motd | grep 'franc,ois'
@@ -1584,6 +1648,19 @@ grep 'paul' /etc/motd | grep 'franc,ois'
 @noindent
 finds all lines that contain both @samp{paul} and @samp{franc,ois}.
 
+@item
+Why does the empty pattern match every input line?
+
+The @command{grep} command searches for lines that contain strings
+that match a pattern.  Every line contains the empty string, so an
+empty pattern causes @command{grep} to find a match on each line.  It
+is not the only such pattern: @samp{^}, @samp{$}, @samp{.*}, and many
+other patterns cause @command{grep} to match every line.
+
+To match empty lines, use the pattern @samp{^$}.  To match blank
+lines, use the pattern @samp{^[[:blank:]]*$}.  To match no lines at
+all, use the command @samp{grep -f /dev/null}.
+
 @item
 How can I search in both standard input and in files?
 
@@ -1605,7 +1682,7 @@ a palindrome of 4 characters can be written with a BRE:
 grep -w -e '\(.\)\(.\).\2\1' file
 @end example
 
-It matches the word "radar" or "civic".
+It matches the word ``radar'' or ``civic.''
 
 Guglielmo Bondioni proposed a single RE
 that finds all palindromes up to 19 characters long
@@ -1615,7 +1692,7 @@ using @w{9 subexpressions} and @w{9 back-references}:
 grep -E -e '^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\9\8\7\6\5\4\3\2\1$' file
 @end smallexample
 
-Note this is done by using @sc{gnu} ERE extensions;
+Note this is done by using GNU ERE extensions;
 it might not be portable to other implementations of @command{grep}.
 
 @item
@@ -1704,13 +1781,13 @@ Back-references are very slow, and may require exponential time.
 @chapter Copying
 @cindex copying
 
-GNU grep is licensed under the GNU GPL, which makes it @dfn{free
+GNU @command{grep} is licensed under the GNU GPL, which makes it @dfn{free
 software}.
 
 The ``free'' in ``free software'' refers to liberty, not price. As
 some GNU project advocates like to point out, think of ``free speech''
 rather than ``free beer''.  In short, you have the right (freedom) to
-run and change grep and distribute it to other people, and---if you
+run and change @command{grep} and distribute it to other people, and---if you
 want---charge money for doing either.  The important restriction is
 that you have to grant your recipients the same rights and impose the
 same restrictions.
index 9d76d05..6e38f06 100644 (file)
@@ -1,4 +1,4 @@
-@set UPDATED 7 May 2011
-@set UPDATED-MONTH May 2011
-@set EDITION 2.9
-@set VERSION 2.9
+@set UPDATED 17 April 2012
+@set UPDATED-MONTH April 2012
+@set EDITION 2.12
+@set VERSION 2.12
index 9c87b92..ee0f018 100644 (file)
@@ -1,5 +1,3 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* alloca.c -- allocate automatically reclaimed memory
    (Mostly) portable public-domain implementation -- D A Gwyn
 
@@ -477,4 +475,4 @@ i00afunc (long address)
 #  endif /* CRAY */
 
 # endif /* no alloca */
-#endif /* not GCC version 3 */
+#endif /* not GCC 2 */
index 9a3eca4..a713364 100644 (file)
@@ -1,6 +1,6 @@
 /* argmatch.c -- find a match for a string in an array
 
-   Copyright (C) 1990, 1998-1999, 2001-2007, 2009-2011 Free Software
+   Copyright (C) 1990, 1998-1999, 2001-2007, 2009-2012 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -77,7 +77,7 @@ argmatch_exit_fn argmatch_die = __argmatch_die;
    synonyms, i.e., for
      "yes", "yop" -> 0
      "no", "nope" -> 1
-   "y" is a valid argument, for `0', and "n" for `1'.  */
+   "y" is a valid argument, for 0, and "n" for 1.  */
 
 ptrdiff_t
 argmatch (const char *arg, const char *const *arglist,
@@ -150,17 +150,17 @@ argmatch_valid (const char *const *arglist,
 
   /* We try to put synonyms on the same line.  The assumption is that
      synonyms follow each other */
-  fprintf (stderr, _("Valid arguments are:"));
+  fputs (_("Valid arguments are:"), stderr);
   for (i = 0; arglist[i]; i++)
     if ((i == 0)
         || memcmp (last_val, vallist + valsize * i, valsize))
       {
-        fprintf (stderr, "\n  - `%s'", arglist[i]);
+        fprintf (stderr, "\n  - %s", quote (arglist[i]));
         last_val = vallist + valsize * i;
       }
     else
       {
-        fprintf (stderr, ", `%s'", arglist[i]);
+        fprintf (stderr, ", %s", quote (arglist[i]));
       }
   putc ('\n', stderr);
 }
@@ -269,7 +269,7 @@ main (int argc, const char *const *argv)
     backup_type = XARGMATCH (program_name, argv[1],
                              backup_args, backup_vals);
 
-  printf ("The version control is `%s'\n",
+  printf ("The version control is '%s'\n",
           ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
 
   return 0;
index f87729d..7e88696 100644 (file)
@@ -1,6 +1,6 @@
 /* argmatch.h -- definitions and prototypes for argmatch.c
 
-   Copyright (C) 1990, 1998-1999, 2001-2002, 2004-2005, 2009-2011 Free Software
+   Copyright (C) 1990, 1998-1999, 2001-2002, 2004-2005, 2009-2012 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    to the same values in VALLIST).  */
 
 ptrdiff_t argmatch (char const *arg, char const *const *arglist,
-                    char const *vallist, size_t valsize);
+                    char const *vallist, size_t valsize) _GL_ATTRIBUTE_PURE;
 
 # define ARGMATCH(Arg, Arglist, Vallist) \
   argmatch (Arg, Arglist, (char const *) (Vallist), sizeof *(Vallist))
 
 /* xargmatch calls this function when it fails.  This function should not
    return.  By default, this is a function that calls ARGMATCH_DIE which
-   in turn defaults to `exit (exit_failure)'.  */
+   in turn defaults to 'exit (exit_failure)'.  */
 typedef void (*argmatch_exit_fn) (void);
 extern argmatch_exit_fn argmatch_die;
 
@@ -93,7 +93,8 @@ ptrdiff_t __xargmatch_internal (char const *context,
 
 char const *argmatch_to_argument (char const *value,
                                   char const *const *arglist,
-                                  char const *vallist, size_t valsize);
+                                  char const *vallist, size_t valsize)
+  _GL_ATTRIBUTE_PURE;
 
 # define ARGMATCH_TO_ARGUMENT(Value, Arglist, Vallist)                  \
   argmatch_to_argument (Value, Arglist,                                 \
diff --git a/contrib/grep/lib/at-func.c b/contrib/grep/lib/at-func.c
new file mode 100644 (file)
index 0000000..b25bc4d
--- /dev/null
@@ -0,0 +1,131 @@
+/* Define at-style functions like fstatat, unlinkat, fchownat, etc.
+   Copyright (C) 2006, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* written by Jim Meyering */
+
+#include "dosname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
+#include "openat.h"
+#include "openat-priv.h"
+#include "save-cwd.h"
+
+#ifdef AT_FUNC_USE_F1_COND
+# define CALL_FUNC(F)                           \
+  (flag == AT_FUNC_USE_F1_COND                  \
+    ? AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS)     \
+    : AT_FUNC_F2 (F AT_FUNC_POST_FILE_ARGS))
+# define VALIDATE_FLAG(F)                       \
+  if (flag & ~AT_FUNC_USE_F1_COND)              \
+    {                                           \
+      errno = EINVAL;                           \
+      return FUNC_FAIL;                         \
+    }
+#else
+# define CALL_FUNC(F) (AT_FUNC_F1 (F AT_FUNC_POST_FILE_ARGS))
+# define VALIDATE_FLAG(F) /* empty */
+#endif
+
+#ifdef AT_FUNC_RESULT
+# define FUNC_RESULT AT_FUNC_RESULT
+#else
+# define FUNC_RESULT int
+#endif
+
+#ifdef AT_FUNC_FAIL
+# define FUNC_FAIL AT_FUNC_FAIL
+#else
+# define FUNC_FAIL -1
+#endif
+
+/* Call AT_FUNC_F1 to operate on FILE, which is in the directory
+   open on descriptor FD.  If AT_FUNC_USE_F1_COND is defined to a value,
+   AT_FUNC_POST_FILE_PARAM_DECLS must include a parameter named flag;
+   call AT_FUNC_F2 if FLAG is 0 or fail if FLAG contains more bits than
+   AT_FUNC_USE_F1_COND.  Return int and fail with -1 unless AT_FUNC_RESULT
+   or AT_FUNC_FAIL are defined.  If possible, do it without changing the
+   working directory.  Otherwise, resort to using save_cwd/fchdir,
+   then AT_FUNC_F?/restore_cwd.  If either the save_cwd or the restore_cwd
+   fails, then give a diagnostic and exit nonzero.  */
+FUNC_RESULT
+AT_FUNC_NAME (int fd, char const *file AT_FUNC_POST_FILE_PARAM_DECLS)
+{
+  /* Be careful to choose names unlikely to conflict with
+     AT_FUNC_POST_FILE_PARAM_DECLS.  */
+  struct saved_cwd saved_cwd;
+  int saved_errno;
+  FUNC_RESULT err;
+
+  VALIDATE_FLAG (flag);
+
+  if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
+    return CALL_FUNC (file);
+
+  {
+    char proc_buf[OPENAT_BUFFER_SIZE];
+    char *proc_file = openat_proc_name (proc_buf, fd, file);
+    if (proc_file)
+      {
+        FUNC_RESULT proc_result = CALL_FUNC (proc_file);
+        int proc_errno = errno;
+        if (proc_file != proc_buf)
+          free (proc_file);
+        /* If the syscall succeeds, or if it fails with an unexpected
+           errno value, then return right away.  Otherwise, fall through
+           and resort to using save_cwd/restore_cwd.  */
+        if (FUNC_FAIL != proc_result)
+          return proc_result;
+        if (! EXPECTED_ERRNO (proc_errno))
+          {
+            errno = proc_errno;
+            return proc_result;
+          }
+      }
+  }
+
+  if (save_cwd (&saved_cwd) != 0)
+    openat_save_fail (errno);
+  if (0 <= fd && fd == saved_cwd.desc)
+    {
+      /* If saving the working directory collides with the user's
+         requested fd, then the user's fd must have been closed to
+         begin with.  */
+      free_cwd (&saved_cwd);
+      errno = EBADF;
+      return FUNC_FAIL;
+    }
+
+  if (fchdir (fd) != 0)
+    {
+      saved_errno = errno;
+      free_cwd (&saved_cwd);
+      errno = saved_errno;
+      return FUNC_FAIL;
+    }
+
+  err = CALL_FUNC (file);
+  saved_errno = (err == FUNC_FAIL ? errno : 0);
+
+  if (restore_cwd (&saved_cwd) != 0)
+    openat_restore_fail (errno);
+
+  free_cwd (&saved_cwd);
+
+  if (saved_errno)
+    errno = saved_errno;
+  return err;
+}
+#undef CALL_FUNC
+#undef FUNC_RESULT
+#undef FUNC_FAIL
index 529bc35..43ef8c2 100644 (file)
@@ -1,6 +1,6 @@
 /* basename.c -- return the last element in a file name
 
-   Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2011 Free Software
+   Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2012 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
diff --git a/contrib/grep/lib/basename.c b/contrib/grep/lib/basename.c
deleted file mode 100644 (file)
index 90ac501..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* basename.c -- return the last element in a file name
-
-   Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2011 Free Software
-   Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include <config.h>
-
-#include "dirname.h"
-
-#include <string.h>
-#include "xalloc.h"
-#include "xstrndup.h"
-
-char *
-base_name (char const *name)
-{
-  char const *base = last_component (name);
-  size_t length;
-
-  /* If there is no last component, then name is a file system root or the
-     empty string.  */
-  if (! *base)
-    return xstrndup (name, base_len (name));
-
-  /* Collapse a sequence of trailing slashes into one.  */
-  length = base_len (base);
-  if (ISSLASH (base[length]))
-    length++;
-
-  /* On systems with drive letters, `a/b:c' must return `./b:c' rather
-     than `b:c' to avoid confusion with a drive letter.  On systems
-     with pure POSIX semantics, this is not an issue.  */
-  if (FILE_SYSTEM_PREFIX_LEN (base))
-    {
-      char *p = xmalloc (length + 3);
-      p[0] = '.';
-      p[1] = '/';
-      memcpy (p + 2, base, length);
-      p[length + 2] = '\0';
-      return p;
-    }
-
-  /* Finally, copy the basename.  */
-  return xstrndup (base, length);
-}
index c09dbf5..824ad5b 100644 (file)
@@ -1,5 +1,5 @@
 /* Binary mode I/O.
-   Copyright (C) 2001, 2003, 2005, 2008-2011 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2003, 2005, 2008-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
index c3a5e1a..5fb8f9b 100644 (file)
@@ -1,5 +1,5 @@
 /* bitrotate.h - Rotate bits in integers
-   Copyright (C) 2008-2011 Free Software Foundation, Inc.
+   Copyright (C) 2008-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
index 9b3908d..cec9eca 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert unibyte character to wide character.
-   Copyright (C) 2008, 2010-2011 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010-2012 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2008.
 
    This program is free software: you can redistribute it and/or modify
index 835f4e1..952d7a8 100644 (file)
@@ -1,8 +1,6 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* Character handling in C locale.
 
-   Copyright 2000-2003, 2006, 2009-2011 Free Software Foundation, Inc.
+   Copyright 2000-2003, 2006, 2009-2012 Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -15,8 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software Foundation,
-Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
index a58913e..0b31309 100644 (file)
@@ -1,5 +1,3 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* Character handling in C locale.
 
    These functions work like the corresponding functions in <ctype.h>,
@@ -7,7 +5,7 @@
    <ctype.h> functions' behaviour depends on the current locale set via
    setlocale.
 
-   Copyright (C) 2000-2003, 2006, 2008-2011 Free Software Foundation, Inc.
+   Copyright (C) 2000-2003, 2006, 2008-2012 Free Software Foundation, Inc.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -20,8 +18,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software Foundation,
-Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #ifndef C_CTYPE_H
 #define C_CTYPE_H
@@ -120,23 +117,23 @@ extern "C" {
          if (c_isalpha (*s)) ...
  */
 
-extern bool c_isascii (int c); /* not locale dependent */
-
-extern bool c_isalnum (int c);
-extern bool c_isalpha (int c);
-extern bool c_isblank (int c);
-extern bool c_iscntrl (int c);
-extern bool c_isdigit (int c);
-extern bool c_islower (int c);
-extern bool c_isgraph (int c);
-extern bool c_isprint (int c);
-extern bool c_ispunct (int c);
-extern bool c_isspace (int c);
-extern bool c_isupper (int c);
-extern bool c_isxdigit (int c);
-
-extern int c_tolower (int c);
-extern int c_toupper (int c);
+extern bool c_isascii (int c) _GL_ATTRIBUTE_CONST; /* not locale dependent */
+
+extern bool c_isalnum (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isalpha (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isblank (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_iscntrl (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isdigit (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_islower (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isgraph (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isprint (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_ispunct (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isspace (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isupper (int c) _GL_ATTRIBUTE_CONST;
+extern bool c_isxdigit (int c) _GL_ATTRIBUTE_CONST;
+
+extern int c_tolower (int c) _GL_ATTRIBUTE_CONST;
+extern int c_toupper (int c) _GL_ATTRIBUTE_CONST;
 
 
 #if defined __GNUC__ && defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ && !defined NO_C_CTYPE_MACROS
index 09e9e9c..fdef238 100644 (file)
@@ -1,7 +1,5 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* Case-insensitive string comparison functions in C locale.
-   Copyright (C) 1995-1996, 2001, 2003, 2005, 2009-2011 Free Software
+   Copyright (C) 1995-1996, 2001, 2003, 2005, 2009-2012 Free Software
    Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -15,8 +13,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #ifndef C_STRCASE_H
 #define C_STRCASE_H
@@ -42,12 +39,13 @@ extern "C" {
 /* Compare strings S1 and S2, ignoring case, returning less than, equal to or
    greater than zero if S1 is lexicographically less than, equal to or greater
    than S2.  */
-extern int c_strcasecmp (const char *s1, const char *s2);
+extern int c_strcasecmp (const char *s1, const char *s2) _GL_ATTRIBUTE_PURE;
 
 /* Compare no more than N characters of strings S1 and S2, ignoring case,
    returning less than, equal to or greater than zero if S1 is
    lexicographically less than, equal to or greater than S2.  */
-extern int c_strncasecmp (const char *s1, const char *s2, size_t n);
+extern int c_strncasecmp (const char *s1, const char *s2, size_t n)
+  _GL_ATTRIBUTE_PURE;
 
 
 #ifdef __cplusplus
index 928c5e6..d8332ca 100644 (file)
@@ -1,7 +1,5 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* c-strcasecmp.c -- case insensitive string comparator in C locale
-   Copyright (C) 1998-1999, 2005-2006, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 1998-1999, 2005-2006, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -14,8 +12,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
diff --git a/contrib/grep/lib/c-strcaseeq.h b/contrib/grep/lib/c-strcaseeq.h
new file mode 100644 (file)
index 0000000..5c4bdff
--- /dev/null
@@ -0,0 +1,184 @@
+/* Optimized case-insensitive string comparison in C locale.
+   Copyright (C) 2001-2002, 2007, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>.  */
+
+#include "c-strcase.h"
+#include "c-ctype.h"
+
+/* STRCASEEQ allows to optimize string comparison with a small literal string.
+     STRCASEEQ (s, "UTF-8", 'U','T','F','-','8',0,0,0,0)
+   is semantically equivalent to
+     c_strcasecmp (s, "UTF-8") == 0
+   just faster.  */
+
+/* Help GCC to generate good code for string comparisons with
+   immediate strings. */
+#if defined (__GNUC__) && defined (__OPTIMIZE__)
+
+/* Case insensitive comparison of ASCII characters.  */
+# if C_CTYPE_ASCII
+#  define CASEEQ(other,upper) \
+     (c_isupper (upper) ? ((other) & ~0x20) == (upper) : (other) == (upper))
+# elif C_CTYPE_CONSECUTIVE_UPPERCASE && C_CTYPE_CONSECUTIVE_LOWERCASE
+#  define CASEEQ(other,upper) \
+     (c_isupper (upper) ? (other) == (upper) || (other) == (upper) - 'A' + 'a' : (other) == (upper))
+# else
+#  define CASEEQ(other,upper) \
+     (c_toupper (other) == (upper))
+# endif
+
+static inline int
+strcaseeq9 (const char *s1, const char *s2)
+{
+  return c_strcasecmp (s1 + 9, s2 + 9) == 0;
+}
+
+static inline int
+strcaseeq8 (const char *s1, const char *s2, char s28)
+{
+  if (CASEEQ (s1[8], s28))
+    {
+      if (s28 == 0)
+        return 1;
+      else
+        return strcaseeq9 (s1, s2);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq7 (const char *s1, const char *s2, char s27, char s28)
+{
+  if (CASEEQ (s1[7], s27))
+    {
+      if (s27 == 0)
+        return 1;
+      else
+        return strcaseeq8 (s1, s2, s28);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq6 (const char *s1, const char *s2, char s26, char s27, char s28)
+{
+  if (CASEEQ (s1[6], s26))
+    {
+      if (s26 == 0)
+        return 1;
+      else
+        return strcaseeq7 (s1, s2, s27, s28);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq5 (const char *s1, const char *s2, char s25, char s26, char s27, char s28)
+{
+  if (CASEEQ (s1[5], s25))
+    {
+      if (s25 == 0)
+        return 1;
+      else
+        return strcaseeq6 (s1, s2, s26, s27, s28);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq4 (const char *s1, const char *s2, char s24, char s25, char s26, char s27, char s28)
+{
+  if (CASEEQ (s1[4], s24))
+    {
+      if (s24 == 0)
+        return 1;
+      else
+        return strcaseeq5 (s1, s2, s25, s26, s27, s28);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq3 (const char *s1, const char *s2, char s23, char s24, char s25, char s26, char s27, char s28)
+{
+  if (CASEEQ (s1[3], s23))
+    {
+      if (s23 == 0)
+        return 1;
+      else
+        return strcaseeq4 (s1, s2, s24, s25, s26, s27, s28);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq2 (const char *s1, const char *s2, char s22, char s23, char s24, char s25, char s26, char s27, char s28)
+{
+  if (CASEEQ (s1[2], s22))
+    {
+      if (s22 == 0)
+        return 1;
+      else
+        return strcaseeq3 (s1, s2, s23, s24, s25, s26, s27, s28);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq1 (const char *s1, const char *s2, char s21, char s22, char s23, char s24, char s25, char s26, char s27, char s28)
+{
+  if (CASEEQ (s1[1], s21))
+    {
+      if (s21 == 0)
+        return 1;
+      else
+        return strcaseeq2 (s1, s2, s22, s23, s24, s25, s26, s27, s28);
+    }
+  else
+    return 0;
+}
+
+static inline int
+strcaseeq0 (const char *s1, const char *s2, char s20, char s21, char s22, char s23, char s24, char s25, char s26, char s27, char s28)
+{
+  if (CASEEQ (s1[0], s20))
+    {
+      if (s20 == 0)
+        return 1;
+      else
+        return strcaseeq1 (s1, s2, s21, s22, s23, s24, s25, s26, s27, s28);
+    }
+  else
+    return 0;
+}
+
+#define STRCASEEQ(s1,s2,s20,s21,s22,s23,s24,s25,s26,s27,s28) \
+  strcaseeq0 (s1, s2, s20, s21, s22, s23, s24, s25, s26, s27, s28)
+
+#else
+
+#define STRCASEEQ(s1,s2,s20,s21,s22,s23,s24,s25,s26,s27,s28) \
+  (c_strcasecmp (s1, s2) == 0)
+
+#endif
index 810bf56..47fb5fd 100644 (file)
@@ -1,7 +1,5 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* c-strncasecmp.c -- case insensitive string comparator in C locale
-   Copyright (C) 1998-1999, 2005-2006, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 1998-1999, 2005-2006, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -14,8 +12,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
diff --git a/contrib/grep/lib/chdir-long.c b/contrib/grep/lib/chdir-long.c
new file mode 100644 (file)
index 0000000..599d141
--- /dev/null
@@ -0,0 +1,266 @@
+/* provide a chdir function that tries not to fail due to ENAMETOOLONG
+   Copyright (C) 2004-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* written by Jim Meyering */
+
+#include <config.h>
+
+#include "chdir-long.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef PATH_MAX
+# error "compile this file only if your system defines PATH_MAX"
+#endif
+
+/* The results of openat() in this file are not leaked to any
+   single-threaded code that could use stdio.
+   FIXME - if the kernel ever adds support for multi-thread safety for
+   avoiding standard fds, then we should use openat_safer.  */
+
+struct cd_buf
+{
+  int fd;
+};
+
+static inline void
+cdb_init (struct cd_buf *cdb)
+{
+  cdb->fd = AT_FDCWD;
+}
+
+static inline int
+cdb_fchdir (struct cd_buf const *cdb)
+{
+  return fchdir (cdb->fd);
+}
+
+static inline void
+cdb_free (struct cd_buf const *cdb)
+{
+  if (0 <= cdb->fd)
+    {
+      bool close_fail = close (cdb->fd);
+      assert (! close_fail);
+    }
+}
+
+/* Given a file descriptor of an open directory (or AT_FDCWD), CDB->fd,
+   try to open the CDB->fd-relative directory, DIR.  If the open succeeds,
+   update CDB->fd with the resulting descriptor, close the incoming file
+   descriptor, and return zero.  Upon failure, return -1 and set errno.  */
+static int
+cdb_advance_fd (struct cd_buf *cdb, char const *dir)
+{
+  int new_fd = openat (cdb->fd, dir,
+                       O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
+  if (new_fd < 0)
+    return -1;
+
+  cdb_free (cdb);
+  cdb->fd = new_fd;
+
+  return 0;
+}
+
+/* Return a pointer to the first non-slash in S.  */
+static inline char * _GL_ATTRIBUTE_PURE
+find_non_slash (char const *s)
+{
+  size_t n_slash = strspn (s, "/");
+  return (char *) s + n_slash;
+}
+
+/* This is a function much like chdir, but without the PATH_MAX limitation
+   on the length of the directory name.  A significant difference is that
+   it must be able to modify (albeit only temporarily) the directory
+   name.  It handles an arbitrarily long directory name by operating
+   on manageable portions of the name.  On systems without the openat
+   syscall, this means changing the working directory to more and more
+   "distant" points along the long directory name and then restoring
+   the working directory.  If any of those attempts to save or restore
+   the working directory fails, this function exits nonzero.
+
+   Note that this function may still fail with errno == ENAMETOOLONG, but
+   only if the specified directory name contains a component that is long
+   enough to provoke such a failure all by itself (e.g. if the component
+   has length PATH_MAX or greater on systems that define PATH_MAX).  */
+
+int
+chdir_long (char *dir)
+{
+  int e = chdir (dir);
+  if (e == 0 || errno != ENAMETOOLONG)
+    return e;
+
+  {
+    size_t len = strlen (dir);
+    char *dir_end = dir + len;
+    struct cd_buf cdb;
+    size_t n_leading_slash;
+
+    cdb_init (&cdb);
+
+    /* If DIR is the empty string, then the chdir above
+       must have failed and set errno to ENOENT.  */
+    assert (0 < len);
+    assert (PATH_MAX <= len);
+
+    /* Count leading slashes.  */
+    n_leading_slash = strspn (dir, "/");
+
+    /* Handle any leading slashes as well as any name that matches
+       the regular expression, m!^//hostname[/]*! .  Handling this
+       prefix separately usually results in a single additional
+       cdb_advance_fd call, but it's worthwhile, since it makes the
+       code in the following loop cleaner.  */
+    if (n_leading_slash == 2)
+      {
+        int err;
+        /* Find next slash.
+           We already know that dir[2] is neither a slash nor '\0'.  */
+        char *slash = memchr (dir + 3, '/', dir_end - (dir + 3));
+        if (slash == NULL)
+          {
+            errno = ENAMETOOLONG;
+            return -1;
+          }
+        *slash = '\0';
+        err = cdb_advance_fd (&cdb, dir);
+        *slash = '/';
+        if (err != 0)
+          goto Fail;
+        dir = find_non_slash (slash + 1);
+      }
+    else if (n_leading_slash)
+      {
+        if (cdb_advance_fd (&cdb, "/") != 0)
+          goto Fail;
+        dir += n_leading_slash;
+      }
+
+    assert (*dir != '/');
+    assert (dir <= dir_end);
+
+    while (PATH_MAX <= dir_end - dir)
+      {
+        int err;
+        /* Find a slash that is PATH_MAX or fewer bytes away from dir.
+           I.e. see if there is a slash that will give us a name of
+           length PATH_MAX-1 or less.  */
+        char *slash = memrchr (dir, '/', PATH_MAX);
+        if (slash == NULL)
+          {
+            errno = ENAMETOOLONG;
+            return -1;
+          }
+
+        *slash = '\0';
+        assert (slash - dir < PATH_MAX);
+        err = cdb_advance_fd (&cdb, dir);
+        *slash = '/';
+        if (err != 0)
+          goto Fail;
+
+        dir = find_non_slash (slash + 1);
+      }
+
+    if (dir < dir_end)
+      {
+        if (cdb_advance_fd (&cdb, dir) != 0)
+          goto Fail;
+      }
+
+    if (cdb_fchdir (&cdb) != 0)
+      goto Fail;
+
+    cdb_free (&cdb);
+    return 0;
+
+   Fail:
+    {
+      int saved_errno = errno;
+      cdb_free (&cdb);
+      errno = saved_errno;
+      return -1;
+    }
+  }
+}
+
+#if TEST_CHDIR
+
+# include "closeout.h"
+# include "error.h"
+
+char *program_name;
+
+int
+main (int argc, char *argv[])
+{
+  char *line = NULL;
+  size_t n = 0;
+  int len;
+
+  program_name = argv[0];
+  atexit (close_stdout);
+
+  len = getline (&line, &n, stdin);
+  if (len < 0)
+    {
+      int saved_errno = errno;
+      if (feof (stdin))
+        exit (0);
+
+      error (EXIT_FAILURE, saved_errno,
+             "reading standard input");
+    }
+  else if (len == 0)
+    exit (0);
+
+  if (line[len-1] == '\n')
+    line[len-1] = '\0';
+
+  if (chdir_long (line) != 0)
+    error (EXIT_FAILURE, errno,
+           "chdir_long failed: %s", line);
+
+  if (argc <= 1)
+    {
+      /* Using 'pwd' here makes sense only if it is a robust implementation,
+         like the one in coreutils after the 2004-04-19 changes.  */
+      char const *cmd = "pwd";
+      execlp (cmd, (char *) NULL);
+      error (EXIT_FAILURE, errno, "%s", cmd);
+    }
+
+  fclose (stdin);
+  fclose (stderr);
+
+  exit (EXIT_SUCCESS);
+}
+#endif
+
+/*
+Local Variables:
+compile-command: "gcc -DTEST_CHDIR=1 -g -O -W -Wall chdir-long.c libcoreutils.a"
+End:
+*/
similarity index 62%
copy from contrib/grep/lib/mbsrtowcs.c
copy to contrib/grep/lib/chdir-long.h
index 69e6dff..51db5a8 100644 (file)
@@ -1,6 +1,5 @@
-/* Convert string to wide string.
-   Copyright (C) 2008-2011 Free Software Foundation, Inc.
-   Written by Bruno Haible <bruno@clisp.org>, 2008.
+/* provide a chdir function that tries not to fail due to ENAMETOOLONG
+   Copyright (C) 2004-2005, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <config.h>
+/* Written by Jim Meyering.  */
 
-/* Specification.  */
-#include <wchar.h>
-
-#include <errno.h>
+#include <unistd.h>
 #include <limits.h>
-#include <stdlib.h>
-
-#include "strnlen1.h"
-
 
-extern mbstate_t _gl_mbsrtowcs_state;
+#include "pathmax.h"
 
-#include "mbsrtowcs-impl.h"
+/* On systems without PATH_MAX, presume that chdir accepts
+   arbitrarily long directory names.  */
+#ifndef PATH_MAX
+# define chdir_long(Dir) chdir (Dir)
+#else
+int chdir_long (char *dir);
+#endif
diff --git a/contrib/grep/lib/cloexec.c b/contrib/grep/lib/cloexec.c
new file mode 100644 (file)
index 0000000..7919e86
--- /dev/null
@@ -0,0 +1,83 @@
+/* closexec.c - set or clear the close-on-exec descriptor flag
+
+   Copyright (C) 1991, 2004-2006, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   The code is taken from glibc/manual/llio.texi  */
+
+#include <config.h>
+
+#include "cloexec.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* Set the 'FD_CLOEXEC' flag of DESC if VALUE is true,
+   or clear the flag if VALUE is false.
+   Return 0 on success, or -1 on error with 'errno' set.
+
+   Note that on MingW, this function does NOT protect DESC from being
+   inherited into spawned children.  Instead, either use dup_cloexec
+   followed by closing the original DESC, or use interfaces such as
+   open or pipe2 that accept flags like O_CLOEXEC to create DESC
+   non-inheritable in the first place.  */
+
+int
+set_cloexec_flag (int desc, bool value)
+{
+#ifdef F_SETFD
+
+  int flags = fcntl (desc, F_GETFD, 0);
+
+  if (0 <= flags)
+    {
+      int newflags = (value ? flags | FD_CLOEXEC : flags & ~FD_CLOEXEC);
+
+      if (flags == newflags
+          || fcntl (desc, F_SETFD, newflags) != -1)
+        return 0;
+    }
+
+  return -1;
+
+#else /* !F_SETFD */
+
+  /* Use dup2 to reject invalid file descriptors; the cloexec flag
+     will be unaffected.  */
+  if (desc < 0)
+    {
+      errno = EBADF;
+      return -1;
+    }
+  if (dup2 (desc, desc) < 0)
+    /* errno is EBADF here.  */
+    return -1;
+
+  /* There is nothing we can do on this kind of platform.  Punt.  */
+  return 0;
+#endif /* !F_SETFD */
+}
+
+
+/* Duplicates a file handle FD, while marking the copy to be closed
+   prior to exec or spawn.  Returns -1 and sets errno if FD could not
+   be duplicated.  */
+
+int
+dup_cloexec (int fd)
+{
+  return fcntl (fd, F_DUPFD_CLOEXEC, 0);
+}
diff --git a/contrib/grep/lib/cloexec.h b/contrib/grep/lib/cloexec.h
new file mode 100644 (file)
index 0000000..92e9f81
--- /dev/null
@@ -0,0 +1,38 @@
+/* closexec.c - set or clear the close-on-exec descriptor flag
+
+   Copyright (C) 2004, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <stdbool.h>
+
+/* Set the 'FD_CLOEXEC' flag of DESC if VALUE is true,
+   or clear the flag if VALUE is false.
+   Return 0 on success, or -1 on error with 'errno' set.
+
+   Note that on MingW, this function does NOT protect DESC from being
+   inherited into spawned children.  Instead, either use dup_cloexec
+   followed by closing the original DESC, or use interfaces such as
+   open or pipe2 that accept flags like O_CLOEXEC to create DESC
+   non-inheritable in the first place.  */
+
+int set_cloexec_flag (int desc, bool value);
+
+/* Duplicates a file handle FD, while marking the copy to be closed
+   prior to exec or spawn.  Returns -1 and sets errno if FD could not
+   be duplicated.  */
+
+int dup_cloexec (int fd);
index 8819b58..04fa5ec 100644 (file)
@@ -1,6 +1,6 @@
 /* Close a stream, with nicer error checking than fclose's.
 
-   Copyright (C) 1998-2002, 2004, 2006-2011 Free Software Foundation, Inc.
+   Copyright (C) 1998-2002, 2004, 2006-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -63,7 +63,7 @@ close_stream (FILE *stream)
      fclose failed, with one exception: ignore an fclose failure if
      there was no previous error, no data remains to be flushed, and
      fclose failed with EBADF.  That can happen when a program like cp
-     is invoked like this `cp a b >&-' (i.e., with standard output
+     is invoked like this 'cp a b >&-' (i.e., with standard output
      closed) and doesn't generate any output (hence no previous error
      and nothing to be flushed).  */
 
similarity index 50%
copy from contrib/grep/lib/wcrtomb.c
copy to contrib/grep/lib/close.c
index 6632589..4b7accb 100644 (file)
@@ -1,6 +1,5 @@
-/* Convert wide character to multibyte character.
-   Copyright (C) 2008-2011 Free Software Foundation, Inc.
-   Written by Bruno Haible <bruno@clisp.org>, 2008.
+/* close replacement.
+   Copyright (C) 2008-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <config.h>
 
 /* Specification.  */
-#include <wchar.h>
+#include <unistd.h>
 
 #include <errno.h>
-#include <stdlib.h>
 
+#include "fd-hook.h"
+#include "msvc-inval.h"
 
-size_t
-wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
+#undef close
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static int
+close_nothrow (int fd)
 {
-  /* This implementation of wcrtomb on top of wctomb() supports only
-     stateless encodings.  ps must be in the initial state.  */
-  if (ps != NULL && !mbsinit (ps))
+  int result;
+
+  TRY_MSVC_INVAL
     {
-      errno = EINVAL;
-      return (size_t)(-1);
+      result = close (fd);
     }
-
-  if (s == NULL)
-    /* We know the NUL wide character corresponds to the NUL character.  */
-    return 1;
-  else
+  CATCH_MSVC_INVAL
     {
-      int ret = wctomb (s, wc);
-
-      if (ret >= 0)
-        return ret;
-      else
-        {
-          errno = EILSEQ;
-          return (size_t)(-1);
-        }
+      result = -1;
+      errno = EBADF;
     }
+  DONE_MSVC_INVAL;
+
+  return result;
+}
+#else
+# define close_nothrow close
+#endif
+
+/* Override close() to call into other gnulib modules.  */
+
+int
+rpl_close (int fd)
+{
+#if WINDOWS_SOCKETS
+  int retval = execute_all_close_hooks (close_nothrow, fd);
+#else
+  int retval = close_nothrow (fd);
+#endif
+
+#if REPLACE_FCHDIR
+  if (retval >= 0)
+    _gl_unregister_fd (fd);
+#endif
+
+  return retval;
 }
diff --git a/contrib/grep/lib/closedir.c b/contrib/grep/lib/closedir.c
new file mode 100644 (file)
index 0000000..df31e86
--- /dev/null
@@ -0,0 +1,67 @@
+/* Stop reading the entries of a directory.
+   Copyright (C) 2006-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <dirent.h>
+
+#if REPLACE_FCHDIR
+# include <unistd.h>
+#endif
+
+#if HAVE_CLOSEDIR
+
+/* Override closedir(), to keep track of the open file descriptors.
+   Needed because there is a function dirfd().  */
+
+#else
+
+# include <stdlib.h>
+
+# include "dirent-private.h"
+
+#endif
+
+int
+closedir (DIR *dirp)
+{
+# if REPLACE_FCHDIR
+  int fd = dirfd (dirp);
+# endif
+  int retval;
+
+#if HAVE_CLOSEDIR
+# undef closedir
+
+  retval = closedir (dirp);
+
+#else
+
+  if (dirp->current != INVALID_HANDLE_VALUE)
+    FindClose (dirp->current);
+  free (dirp);
+
+  retval = 0;
+
+#endif
+
+#if REPLACE_FCHDIR
+  if (retval >= 0)
+    _gl_unregister_fd (fd);
+#endif
+  return retval;
+}
index f6cdd3f..eea4024 100644 (file)
@@ -1,6 +1,6 @@
 /* Close standard output and standard error, exiting with a diagnostic on error.
 
-   Copyright (C) 1998-2002, 2004, 2006, 2008-2011 Free Software Foundation,
+   Copyright (C) 1998-2002, 2004, 2006, 2008-2012 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -100,7 +100,7 @@ close_stdout_set_ignore_EPIPE (bool ignore)
    can bypass the removal of these files.
 
    It's important to detect such failures and exit nonzero because many
-   tools (most notably `make' and other build-management systems) depend
+   tools (most notably 'make' and other build-management systems) depend
    on being able to detect failure in other tools via their exit status.  */
 
 void
index ec8d7a6..5310b28 100644 (file)
@@ -1,6 +1,6 @@
 /* Close standard output and standard error.
 
-   Copyright (C) 1998, 2000, 2003-2004, 2006, 2008-2011 Free Software
+   Copyright (C) 1998, 2000, 2003-2004, 2006, 2008-2012 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
diff --git a/contrib/grep/lib/colorize-posix.c b/contrib/grep/lib/colorize-posix.c
new file mode 100644 (file)
index 0000000..116bbb2
--- /dev/null
@@ -0,0 +1,58 @@
+/* Output colorization.
+   Copyright 2011-2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* Without this pragma, gcc 4.7.0 20120102 suggests that the
+   init_colorize function might be candidate for attribute 'const'  */
+#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
+#endif
+
+#include <config.h>
+
+#include "colorize.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Return non-zero if we should highlight matches in output to file
+   descriptor FD.  */
+int
+should_colorize (void)
+{
+  char const *t = getenv ("TERM");
+  return t && strcmp (t, "dumb") != 0;
+}
+
+void init_colorize (void) { }
+
+/* Start a colorized text attribute on stdout using the SGR_START
+   format; the attribute is specified by SGR_SEQ.  */
+void
+print_start_colorize (char const *sgr_start, char const *sgr_seq)
+{
+  printf (sgr_start, sgr_seq);
+}
+
+/* Restore the normal text attribute using the SGR_END string.  */
+void
+print_end_colorize (char const *sgr_end)
+{
+  fputs (sgr_end, stdout);
+}
diff --git a/contrib/grep/lib/colorize-w32.c b/contrib/grep/lib/colorize-w32.c
new file mode 100644 (file)
index 0000000..7341fe2
--- /dev/null
@@ -0,0 +1,208 @@
+/* Output colorization on MS-Windows.
+   Copyright 2011-2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* Written by Eli Zaretskii.  */
+
+#include <config.h>
+
+#include "colorize.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#undef DATADIR /* conflicts with objidl.h, which is included by windows.h */
+#include <windows.h>
+
+static HANDLE hstdout = INVALID_HANDLE_VALUE;
+static SHORT norm_attr;
+
+/* Initialize the normal text attribute used by the console.  */
+void
+init_colorize (void)
+{
+  CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+  hstdout = GetStdHandle (STD_OUTPUT_HANDLE);
+  if (hstdout != INVALID_HANDLE_VALUE
+      && GetConsoleScreenBufferInfo (hstdout, &csbi))
+     norm_attr = csbi.wAttributes;
+  else
+    hstdout = INVALID_HANDLE_VALUE;
+}
+
+/* Return non-zero if we should highlight matches in output.  */
+int
+should_colorize (void)
+{
+  /* $TERM is not normally defined on DOS/Windows, so don't require
+     it for highlighting.  But some programs, like Emacs, do define
+     it when running Grep as a subprocess, so make sure they don't
+     set TERM=dumb.  */
+  char const *t = getenv ("TERM");
+  return ! (t && strcmp (t, "dumb") == 0);
+}
+
+/* Convert a color spec, a semi-colon separated list of the form
+   "NN;MM;KK;...", where each number is a value of the SGR parameter,
+   into the corresponding Windows console text attribute.
+
+   This function supports a subset of the SGR rendition aspects that
+   the Windows console can display.  */
+static int
+w32_sgr2attr (const char *sgr_seq)
+{
+  const char *s, *p;
+  int code, fg = norm_attr & 15, bg = norm_attr & (15 << 4);
+  int bright = 0, inverse = 0;
+  static const int fg_color[] = {
+    0,                 /* black */
+    FOREGROUND_RED,    /* red */
+    FOREGROUND_GREEN,  /* green */
+    FOREGROUND_GREEN | FOREGROUND_RED, /* yellow */
+    FOREGROUND_BLUE,                  /* blue */
+    FOREGROUND_BLUE | FOREGROUND_RED,  /* magenta */
+    FOREGROUND_BLUE | FOREGROUND_GREEN, /* cyan */
+    FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE /* gray */
+  };
+  static const int bg_color[] = {
+    0,                 /* black */
+    BACKGROUND_RED,    /* red */
+    BACKGROUND_GREEN,  /* green */
+    BACKGROUND_GREEN | BACKGROUND_RED, /* yellow */
+    BACKGROUND_BLUE,                  /* blue */
+    BACKGROUND_BLUE | BACKGROUND_RED,  /* magenta */
+    BACKGROUND_BLUE | BACKGROUND_GREEN, /* cyan */
+    BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE /* gray */
+  };
+
+  for (s = p = sgr_seq; *s; p++)
+    {
+      if (*p == ';' || *p == '\0')
+        {
+          code = strtol (s, NULL, 10);
+          s = p + (*p != '\0');
+
+          switch (code)
+            {
+            case 0:    /* all attributes off */
+              fg = norm_attr & 15;
+              bg = norm_attr & (15 << 4);
+              bright = 0;
+              inverse = 0;
+              break;
+            case 1:    /* intensity on */
+              bright = 1;
+              break;
+            case 7:    /* inverse video */
+              inverse = 1;
+              break;
+            case 22:   /* intensity off */
+              bright = 0;
+              break;
+            case 27:   /* inverse off */
+              inverse = 0;
+              break;
+            case 30: case 31: case 32: case 33: /* foreground color */
+            case 34: case 35: case 36: case 37:
+              fg = fg_color[code - 30];
+              break;
+            case 39:   /* default foreground */
+              fg = norm_attr & 15;
+              break;
+            case 40: case 41: case 42: case 43: /* background color */
+            case 44: case 45: case 46: case 47:
+              bg = bg_color[code - 40];
+              break;
+            case 49:   /* default background */
+              bg = norm_attr & (15 << 4);
+              break;
+            default:
+              break;
+            }
+        }
+    }
+  if (inverse)
+    {
+      int t = fg;
+      fg = (bg >> 4);
+      bg = (t << 4);
+    }
+  if (bright)
+    fg |= FOREGROUND_INTENSITY;
+
+  return (bg & (15 << 4)) | (fg & 15);
+}
+
+/* Start a colorized text attribute on stdout using the SGR_START
+   format; the attribute is specified by SGR_SEQ.  */
+void
+print_start_colorize (char const *sgr_start, char const *sgr_seq)
+{
+  /* If stdout is connected to a console, set the console text
+     attribute directly instead of using SGR_START.  Otherwise, use
+     SGR_START to emit the SGR escape sequence as on Posix platforms;
+     this is needed when Grep is invoked as a subprocess of another
+     program, such as Emacs, which will handle the display of the
+     matches.  */
+  if (hstdout != INVALID_HANDLE_VALUE)
+    {
+      SHORT attr = w32_sgr2attr (sgr_seq);
+      SetConsoleTextAttribute (hstdout, attr);
+    }
+  else
+    printf (sgr_start, sgr_seq);
+}
+
+/* Clear to the end of the current line with the default attribute.
+   This is needed for reasons similar to those that require the "EL to
+   Right after SGR" operation on Posix platforms: if we don't do this,
+   setting the `mt', `ms', or `mc' capabilities to use a non-default
+   background color spills that color to the empty space at the end of
+   the last screen line in a match whose line spans multiple screen
+   lines.  */
+static void
+w32_clreol (void)
+{
+  DWORD nchars;
+  COORD start_pos;
+  DWORD written;
+  CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+  GetConsoleScreenBufferInfo (hstdout, &csbi);
+  start_pos = csbi.dwCursorPosition;
+  nchars = csbi.dwSize.X - start_pos.X;
+
+  FillConsoleOutputAttribute (hstdout, norm_attr, nchars, start_pos,
+                              &written);
+  FillConsoleOutputCharacter (hstdout, ' ', nchars, start_pos, &written);
+}
+
+/* Restore the normal text attribute using the SGR_END string.  */
+void
+print_end_colorize (char const *sgr_end)
+{
+  if (hstdout != INVALID_HANDLE_VALUE)
+    {
+      SetConsoleTextAttribute (hstdout, norm_attr);
+      w32_clreol ();
+    }
+  else
+    fputs (sgr_end, stdout);
+}
diff --git a/contrib/grep/lib/colorize.c b/contrib/grep/lib/colorize.c
new file mode 100644 (file)
index 0000000..116bbb2
--- /dev/null
@@ -0,0 +1,58 @@
+/* Output colorization.
+   Copyright 2011-2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+/* Without this pragma, gcc 4.7.0 20120102 suggests that the
+   init_colorize function might be candidate for attribute 'const'  */
+#if (__GNUC__ == 4 && 6 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
+#endif
+
+#include <config.h>
+
+#include "colorize.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Return non-zero if we should highlight matches in output to file
+   descriptor FD.  */
+int
+should_colorize (void)
+{
+  char const *t = getenv ("TERM");
+  return t && strcmp (t, "dumb") != 0;
+}
+
+void init_colorize (void) { }
+
+/* Start a colorized text attribute on stdout using the SGR_START
+   format; the attribute is specified by SGR_SEQ.  */
+void
+print_start_colorize (char const *sgr_start, char const *sgr_seq)
+{
+  printf (sgr_start, sgr_seq);
+}
+
+/* Restore the normal text attribute using the SGR_END string.  */
+void
+print_end_colorize (char const *sgr_end)
+{
+  fputs (sgr_end, stdout);
+}
similarity index 53%
copy from contrib/grep/src/mbsupport.h
copy to contrib/grep/lib/colorize.h
index 007f412..23687d0 100644 (file)
@@ -1,7 +1,6 @@
-/* mbsupport.h --- Localize determination of whether we have multibyte stuff.
-
-   Copyright (C) 2004-2005, 2007, 2009-2011 Free Software Foundation, Inc.
+/* Output colorization.
 
+   Copyright 2011-2012 Free Software Foundation, Inc.
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3, or (at your option)
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
-
-/* This file is needed so that we test for i18n support in just one place.
-   This gives us a consistent definition for all uses of MBS_SUPPORT. This
-   follows the ``Don't Repeat Yourself'' principle from "The Pragmatic
-   Programmer".
-
-   The tests should be *all* the ones that are needed for an individual
-   application.  */
-
-#include <stdlib.h>
-
-#if defined HAVE_WCSCOLL && defined HAVE_ISWCTYPE
-# define MBS_SUPPORT 1
-#else
-# define MBS_SUPPORT 0
-#endif
+extern int should_colorize (void);
+extern void init_colorize (void);
+extern void print_start_colorize (char const *sgr_start, char const *sgr_seq);
+extern void print_end_colorize (char const *sgr_end);
index 93b5a5d..89b3017 100644 (file)
@@ -1,7 +1,7 @@
 #! /bin/sh
 # Output a system dependent table of character encoding aliases.
 #
-#   Copyright (C) 2000-2004, 2006-2011 Free Software Foundation, Inc.
+#   Copyright (C) 2000-2004, 2006-2012 Free Software Foundation, Inc.
 #
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
@@ -14,8 +14,7 @@
 #   GNU General Public License for more details.
 #
 #   You should have received a copy of the GNU General Public License along
-#   with this program; if not, write to the Free Software Foundation,
-#   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#   with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 # The table consists of lines of the form
 #    ALIAS  CANONICAL
@@ -30,6 +29,8 @@
 # The current list of GNU canonical charset names is as follows.
 #
 #       name              MIME?             used by which systems
+#                                    (darwin = MacOS 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
 #   ISO-8859-2              Y   glibc aix hpux irix osf solaris freebsd netbsd openbsd darwin cygwin
similarity index 68%
copy from contrib/grep/lib/exitfail.c
copy to contrib/grep/lib/creat-safer.c
index 953aa02..f0f9a22 100644 (file)
@@ -1,6 +1,6 @@
-/* Failure exit status
+/* Invoke creat, but avoid some glitches.
 
-   Copyright (C) 2002-2003, 2005-2007, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2005-2006, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+/* Written by Jim Meyering.  */
+
 #include <config.h>
 
-#include "exitfail.h"
+#include "fcntl-safer.h"
 
-#include <stdlib.h>
+#include <fcntl.h>
+#include "unistd-safer.h"
 
-int volatile exit_failure = EXIT_FAILURE;
+int
+creat_safer (char const *file, mode_t mode)
+{
+  return fd_safer (creat (file, mode));
+}
diff --git a/contrib/grep/lib/cycle-check.c b/contrib/grep/lib/cycle-check.c
new file mode 100644 (file)
index 0000000..011cae9
--- /dev/null
@@ -0,0 +1,85 @@
+/* help detect directory cycles efficiently
+
+   Copyright (C) 2003-2006, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Jim Meyering */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <stdbool.h>
+
+#include "cycle-check.h"
+
+#define CC_MAGIC 9827862
+
+/* Return true if I is a power of 2, or is zero.  */
+
+static inline bool
+is_zero_or_power_of_two (uintmax_t i)
+{
+  return (i & (i - 1)) == 0;
+}
+
+void
+cycle_check_init (struct cycle_check_state *state)
+{
+  state->chdir_counter = 0;
+  state->magic = CC_MAGIC;
+}
+
+/* In traversing a directory hierarchy, call this function once for each
+   descending chdir call, with SB corresponding to the chdir operand.
+   If SB corresponds to a directory that has already been seen,
+   return true to indicate that there is a directory cycle.
+   Note that this is done "lazily", which means that some of
+   the directories in the cycle may be processed twice before
+   the cycle is detected.  */
+
+bool
+cycle_check (struct cycle_check_state *state, struct stat const *sb)
+{
+  assert (state->magic == CC_MAGIC);
+
+  /* If the current directory ever happens to be the same
+     as the one we last recorded for the cycle detection,
+     then it's obviously part of a cycle.  */
+  if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino))
+    return true;
+
+  /* If the number of "descending" chdir calls is a power of two,
+     record the dev/ino of the current directory.  */
+  if (is_zero_or_power_of_two (++(state->chdir_counter)))
+    {
+      /* On all architectures that we know about, if the counter
+         overflows then there is a directory cycle here somewhere,
+         even if we haven't detected it yet.  Typically this happens
+         only after the counter is incremented 2**64 times, so it's a
+         fairly theoretical point.  */
+      if (state->chdir_counter == 0)
+        return true;
+
+      state->dev_ino.st_dev = sb->st_dev;
+      state->dev_ino.st_ino = sb->st_ino;
+    }
+
+  return false;
+}
diff --git a/contrib/grep/lib/cycle-check.h b/contrib/grep/lib/cycle-check.h
new file mode 100644 (file)
index 0000000..8886476
--- /dev/null
@@ -0,0 +1,52 @@
+/* help detect directory cycles efficiently
+
+   Copyright (C) 2003-2004, 2006, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Jim Meyering */
+
+#ifndef CYCLE_CHECK_H
+# define CYCLE_CHECK_H 1
+
+# include <stdint.h>
+# include <stdbool.h>
+# include "dev-ino.h"
+# include "same-inode.h"
+
+struct cycle_check_state
+{
+  struct dev_ino dev_ino;
+  uintmax_t chdir_counter;
+  int magic;
+};
+
+void cycle_check_init (struct cycle_check_state *state);
+bool cycle_check (struct cycle_check_state *state, struct stat const *sb);
+
+# define CYCLE_CHECK_REFLECT_CHDIR_UP(State, SB_dir, SB_subdir) \
+  do                                                            \
+    {                                                           \
+      /* You must call cycle_check at least once before using this macro.  */ \
+      if ((State)->chdir_counter == 0)                          \
+        abort ();                                               \
+      if (SAME_INODE ((State)->dev_ino, SB_subdir))             \
+        {                                                       \
+          (State)->dev_ino.st_dev = (SB_dir).st_dev;            \
+          (State)->dev_ino.st_ino = (SB_dir).st_ino;            \
+        }                                                       \
+    }                                                           \
+  while (0)
+
+#endif
diff --git a/contrib/grep/lib/dev-ino.h b/contrib/grep/lib/dev-ino.h
new file mode 100644 (file)
index 0000000..695d38c
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef DEV_INO_H
+# define DEV_INO_H 1
+
+# include <sys/types.h>
+# include <sys/stat.h>
+
+struct dev_ino
+{
+  ino_t st_ino;
+  dev_t st_dev;
+};
+
+#endif
similarity index 74%
copy from contrib/grep/lib/exitfail.c
copy to contrib/grep/lib/dirent--.h
index 953aa02..1b75793 100644 (file)
@@ -1,6 +1,6 @@
-/* Failure exit status
+/* Like dirent.h, but redefine some names to avoid glitches.
 
-   Copyright (C) 2002-2003, 2005-2007, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <config.h>
+/* Written by Eric Blake.  */
 
-#include "exitfail.h"
+#include "dirent-safer.h"
 
-#include <stdlib.h>
-
-int volatile exit_failure = EXIT_FAILURE;
+#undef opendir
+#define opendir opendir_safer
diff --git a/contrib/grep/lib/dirent-private.h b/contrib/grep/lib/dirent-private.h
new file mode 100644 (file)
index 0000000..b60203c
--- /dev/null
@@ -0,0 +1,40 @@
+/* Private details of the DIR type.
+   Copyright (C) 2011-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _DIRENT_PRIVATE_H
+#define _DIRENT_PRIVATE_H 1
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+struct gl_directory
+{
+  /* Status, or error code to produce in next readdir() call.
+     -2 means the end of the directory is already reached,
+     -1 means the entry was already filled by FindFirstFile,
+     0 means the entry needs to be filled using FindNextFile.
+     A positive value is an error code.  */
+  int status;
+  /* Handle, reading the directory, at current position.  */
+  HANDLE current;
+  /* Found directory entry.  */
+  WIN32_FIND_DATA entry;
+  /* Argument to pass to FindFirstFile.  It consists of the absolutized
+     directory name, followed by a directory separator and the wildcards.  */
+  char dir_name_mask[1];
+};
+
+#endif /* _DIRENT_PRIVATE_H */
similarity index 75%
copy from contrib/grep/lib/quote.h
copy to contrib/grep/lib/dirent-safer.h
index d0acb51..861ea93 100644 (file)
@@ -1,6 +1,6 @@
-/* quote.h - prototypes for quote.c
+/* Invoke dirent-like functions, but avoid some glitches.
 
-   Copyright (C) 1998-2001, 2003, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -15,6 +15,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+/* Written by Eric Blake.  */
 
-char const *quote_n (int n, char const *name);
-char const *quote (char const *name);
+#include <dirent.h>
+
+DIR *opendir_safer (const char *name);
similarity index 68%
copy from contrib/grep/lib/mbsrtowcs.c
copy to contrib/grep/lib/dirfd.c
index 69e6dff..2f4d424 100644 (file)
@@ -1,6 +1,6 @@
-/* Convert string to wide string.
-   Copyright (C) 2008-2011 Free Software Foundation, Inc.
-   Written by Bruno Haible <bruno@clisp.org>, 2008.
+/* dirfd.c -- return the file descriptor associated with an open DIR*
+
+   Copyright (C) 2001, 2006, 2008-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <config.h>
+/* Written by Jim Meyering. */
 
-/* Specification.  */
-#include <wchar.h>
+#include <config.h>
 
+#include <dirent.h>
 #include <errno.h>
-#include <limits.h>
-#include <stdlib.h>
-
-#include "strnlen1.h"
-
-
-extern mbstate_t _gl_mbsrtowcs_state;
 
-#include "mbsrtowcs-impl.h"
+int
+dirfd (DIR *dir_p)
+{
+  int fd = DIR_TO_FD (dir_p);
+  if (fd == -1)
+    errno = ENOTSUP;
+  return fd;
+}
index f5b0c0f..2895cbc 100644 (file)
@@ -1,6 +1,6 @@
 /* dirname.c -- return all but the last element in a file name
 
-   Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2011 Free Software
+   Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2012 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -25,7 +25,7 @@
 
 /* Return the length of the prefix of FILE that will be used by
    dir_name.  If FILE is in the working directory, this returns zero
-   even though `dir_name (FILE)' will return ".".  Works properly even
+   even though 'dir_name (FILE)' will return ".".  Works properly even
    if there are trailing slashes (by effectively ignoring them).  */
 
 size_t
@@ -53,9 +53,9 @@ dir_len (char const *file)
 }
 
 
-/* In general, we can't use the builtin `dirname' function if available,
+/* In general, we can't use the builtin 'dirname' function if available,
    since it has different meanings in different environments.
-   In some environments the builtin `dirname' modifies its argument.
+   In some environments the builtin 'dirname' modifies its argument.
 
    Return the leading directories part of FILE, allocated with malloc.
    Works properly even if there are trailing slashes (by effectively
diff --git a/contrib/grep/lib/dirname.c b/contrib/grep/lib/dirname.c
deleted file mode 100644 (file)
index 411ded3..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* dirname.c -- return all but the last element in a file name
-
-   Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2011 Free Software
-   Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include <config.h>
-
-#include "dirname.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include "xalloc.h"
-
-/* Just like mdir_name (dirname-lgpl.c), except, rather than
-   returning NULL upon malloc failure, here, we report the
-   "memory exhausted" condition and exit.  */
-
-char *
-dir_name (char const *file)
-{
-  char *result = mdir_name (file);
-  if (!result)
-    xalloc_die ();
-  return result;
-}
index 2ef9882..51a685c 100644 (file)
@@ -1,6 +1,6 @@
 /*  Take file names apart into directory and base names.
 
-    Copyright (C) 1998, 2001, 2003-2006, 2009-2011 Free Software Foundation,
+    Copyright (C) 1998, 2001, 2003-2006, 2009-2012 Free Software Foundation,
     Inc.
 
     This program is free software: you can redistribute it and/or modify
@@ -37,9 +37,9 @@ char *dir_name (char const *file);
 # endif
 
 char *mdir_name (char const *file);
-size_t base_len (char const *file);
-size_t dir_len (char const *file);
-char *last_component (char const *file);
+size_t base_len (char const *file) _GL_ATTRIBUTE_PURE;
+size_t dir_len (char const *file) _GL_ATTRIBUTE_PURE;
+char *last_component (char const *file) _GL_ATTRIBUTE_PURE;
 
 bool strip_trailing_slashes (char *file);
 
index acdd03b..0468ce4 100644 (file)
@@ -1,6 +1,6 @@
 /* File names on MS-DOS/Windows systems.
 
-   Copyright (C) 2000-2001, 2004-2006, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2000-2001, 2004-2006, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
similarity index 64%
copy from contrib/grep/lib/mbrlen.c
copy to contrib/grep/lib/dup-safer.c
index 54d2c88..0f5d3be 100644 (file)
@@ -1,6 +1,6 @@
-/* Recognize multibyte character.
-   Copyright (C) 1999-2000, 2008-2011 Free Software Foundation, Inc.
-   Written by Bruno Haible <bruno@clisp.org>, 2008.
+/* Invoke dup, but avoid some glitches.
+
+   Copyright (C) 2001, 2004-2006, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+/* Written by Paul Eggert.  */
+
 #include <config.h>
 
-/* Specification.  */
-#include <wchar.h>
+#include "unistd-safer.h"
 
+#include <fcntl.h>
+#include <unistd.h>
 
-static mbstate_t internal_state;
+/* Like dup, but do not return STDIN_FILENO, STDOUT_FILENO, or
+   STDERR_FILENO.  */
 
-size_t
-mbrlen (const char *s, size_t n, mbstate_t *ps)
+int
+dup_safer (int fd)
 {
-  if (ps == NULL)
-    ps = &internal_state;
-  return mbrtowc (NULL, s, n, ps);
+  return fcntl (fd, F_DUPFD, STDERR_FILENO + 1);
 }
similarity index 53%
copy from contrib/grep/lib/mbsrtowcs.c
copy to contrib/grep/lib/dup.c
index 69e6dff..0a0b69e 100644 (file)
@@ -1,6 +1,6 @@
-/* Convert string to wide string.
-   Copyright (C) 2008-2011 Free Software Foundation, Inc.
-   Written by Bruno Haible <bruno@clisp.org>, 2008.
+/* Duplicate an open file descriptor.
+
+   Copyright (C) 2011-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include <config.h>
 
 /* Specification.  */
-#include <wchar.h>
+#include <unistd.h>
 
 #include <errno.h>
-#include <limits.h>
-#include <stdlib.h>
-
-#include "strnlen1.h"
-
-
-extern mbstate_t _gl_mbsrtowcs_state;
 
-#include "mbsrtowcs-impl.h"
+#include "msvc-inval.h"
+
+#undef dup
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static inline int
+dup_nothrow (int fd)
+{
+  int result;
+
+  TRY_MSVC_INVAL
+    {
+      result = dup (fd);
+    }
+  CATCH_MSVC_INVAL
+    {
+      result = -1;
+      errno = EBADF;
+    }
+  DONE_MSVC_INVAL;
+
+  return result;
+}
+#else
+# define dup_nothrow dup
+#endif
+
+int
+rpl_dup (int fd)
+{
+  int result = dup_nothrow (fd);
+#if REPLACE_FCHDIR
+  if (result >= 0)
+    result = _gl_register_dup (fd, result);
+#endif
+  return result;
+}
diff --git a/contrib/grep/lib/dup2.c b/contrib/grep/lib/dup2.c
new file mode 100644 (file)
index 0000000..f6d0f1c
--- /dev/null
@@ -0,0 +1,157 @@
+/* Duplicate an open file descriptor to a specified file descriptor.
+
+   Copyright (C) 1999, 2004-2007, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* written by Paul Eggert */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+#if HAVE_DUP2
+
+# undef dup2
+
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+/* Get declarations of the native Windows API functions.  */
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+
+#  include "msvc-inval.h"
+
+/* Get _get_osfhandle.  */
+#  include "msvc-nothrow.h"
+
+static int
+ms_windows_dup2 (int fd, int desired_fd)
+{
+  int result;
+
+  /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
+     dup2 (fd, fd) returns 0, but all further attempts to use fd in
+     future dup2 calls will hang.  */
+  if (fd == desired_fd)
+    {
+      if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
+        {
+          errno = EBADF;
+          return -1;
+        }
+      return fd;
+    }
+
+  /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
+     http://bugs.winehq.org/show_bug.cgi?id=21289 */
+  if (desired_fd < 0)
+    {
+      errno = EBADF;
+      return -1;
+    }
+
+  TRY_MSVC_INVAL
+    {
+      result = dup2 (fd, desired_fd);
+    }
+  CATCH_MSVC_INVAL
+    {
+      errno = EBADF;
+      result = -1;
+    }
+  DONE_MSVC_INVAL;
+
+  if (result == 0)
+    result = desired_fd;
+
+  return result;
+}
+
+#  define dup2 ms_windows_dup2
+
+# endif
+
+int
+rpl_dup2 (int fd, int desired_fd)
+{
+  int result;
+
+# ifdef F_GETFL
+  /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
+     On Cygwin 1.5.x, dup2 (1, 1) returns 0.
+     On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
+  if (fd == desired_fd)
+    return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
+# endif
+
+  result = dup2 (fd, desired_fd);
+
+  /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
+  if (result == -1 && errno == EMFILE)
+    errno = EBADF;
+# if REPLACE_FCHDIR
+  if (fd != desired_fd && result != -1)
+    result = _gl_register_dup (fd, result);
+# endif
+  return result;
+}
+
+#else /* !HAVE_DUP2 */
+
+/* On older platforms, dup2 did not exist.  */
+
+# ifndef F_DUPFD
+static int
+dupfd (int fd, int desired_fd)
+{
+  int duplicated_fd = dup (fd);
+  if (duplicated_fd < 0 || duplicated_fd == desired_fd)
+    return duplicated_fd;
+  else
+    {
+      int r = dupfd (fd, desired_fd);
+      int e = errno;
+      close (duplicated_fd);
+      errno = e;
+      return r;
+    }
+}
+# endif
+
+int
+dup2 (int fd, int desired_fd)
+{
+  int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd;
+  if (result == -1 || fd == desired_fd)
+    return result;
+  close (desired_fd);
+# ifdef F_DUPFD
+  result = fcntl (fd, F_DUPFD, desired_fd);
+#  if REPLACE_FCHDIR
+  if (0 <= result)
+    result = _gl_register_dup (fd, result);
+#  endif
+# else
+  result = dupfd (fd, desired_fd);
+# endif
+  if (result == -1 && (errno == EMFILE || errno == EINVAL))
+    errno = EBADF;
+  return result;
+}
+#endif /* !HAVE_DUP2 */
index 7482baa..dc8c65f 100644 (file)
@@ -1,5 +1,5 @@
 /* Error handler for noninteractive utilities
-   Copyright (C) 1990-1998, 2000-2007, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 1990-1998, 2000-2007, 2009-2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    This program is free software: you can redistribute it and/or modify
@@ -54,7 +54,7 @@
    function without parameters instead.  */
 void (*error_print_progname) (void);
 
-/* This variable is incremented each time `error' is called.  */
+/* This variable is incremented each time 'error' is called.  */
 unsigned int error_message_count;
 
 #ifdef _LIBC
@@ -65,7 +65,7 @@ unsigned int error_message_count;
 # include <limits.h>
 # include <libio/libioP.h>
 
-/* In GNU libc we want do not want to use the common name `error' directly.
+/* In GNU libc we want do not want to use the common name 'error' directly.
    Instead make it a weak alias.  */
 extern void __error (int status, int errnum, const char *message, ...)
      __attribute__ ((__format__ (__printf__, 3, 4)));
@@ -89,9 +89,11 @@ extern void __error_at_line (int status, int errnum, const char *file_name,
 # include <unistd.h>
 
 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-/* Get declarations of the Win32 API functions.  */
+/* Get declarations of the native Windows API functions.  */
 #  define WIN32_LEAN_AND_MEAN
 #  include <windows.h>
+/* Get _get_osfhandle.  */
+#  include "msvc-nothrow.h"
 # endif
 
 /* The gnulib override of fcntl is not needed in this file.  */
@@ -123,9 +125,10 @@ static inline int
 is_open (int fd)
 {
 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-  /* On Win32: The initial state of unassigned standard file descriptors is
-     that they are open but point to an INVALID_HANDLE_VALUE.  There is no
-     fcntl, and the gnulib replacement fcntl does not support F_GETFL.  */
+  /* On native Windows: The initial state of unassigned standard file
+     descriptors is that they are open but point to an INVALID_HANDLE_VALUE.
+     There is no fcntl, and the gnulib replacement fcntl does not support
+     F_GETFL.  */
   return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
 # else
 #  ifndef F_GETFL
index 80f81bc..9c2cb8b 100644 (file)
@@ -1,5 +1,5 @@
 /* Declaration for error-reporting function
-   Copyright (C) 1995-1997, 2003, 2006, 2008-2011 Free Software Foundation,
+   Copyright (C) 1995-1997, 2003, 2006, 2008-2012 Free Software Foundation,
    Inc.
    This file is part of the GNU C Library.
 
@@ -35,9 +35,9 @@
 extern "C" {
 #endif
 
-/* Print a message with `fprintf (stderr, FORMAT, ...)';
+/* Print a message with 'fprintf (stderr, FORMAT, ...)';
    if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
-   If STATUS is nonzero, terminate the program with `exit (STATUS)'.  */
+   If STATUS is nonzero, terminate the program with 'exit (STATUS)'.  */
 
 extern void error (int __status, int __errnum, const char *__format, ...)
      _GL_ATTRIBUTE_FORMAT ((__printf__, 3, 4));
@@ -51,7 +51,7 @@ extern void error_at_line (int __status, int __errnum, const char *__fname,
    function without parameters instead.  */
 extern void (*error_print_progname) (void);
 
-/* This variable is incremented each time `error' is called.  */
+/* This variable is incremented each time 'error' is called.  */
 extern unsigned int error_message_count;
 
 /* Sometimes we want to have at most one error per line.  This
index df49714..bc3e6e6 100644 (file)
@@ -1,6 +1,6 @@
 /* exclude.c -- exclude file names
 
-   Copyright (C) 1992-1994, 1997, 1999-2007, 2009-2011 Free Software
+   Copyright (C) 1992-1994, 1997, 1999-2007, 2009-2012 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
index 0a314a9..50e8a63 100644 (file)
@@ -1,6 +1,6 @@
 /* exclude.h -- declarations for excluding file names
 
-   Copyright (C) 1992-1994, 1997, 1999, 2001-2003, 2005-2006, 2009-2011 Free
+   Copyright (C) 1992-1994, 1997, 1999, 2001-2003, 2005-2006, 2009-2012 Free
    Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -39,7 +39,7 @@
 
 struct exclude;
 
-bool fnmatch_pattern_has_wildcards (const char *, int);
+bool fnmatch_pattern_has_wildcards (const char *, int) _GL_ATTRIBUTE_PURE;
 
 struct exclude *new_exclude (void);
 void free_exclude (struct exclude *);
index 953aa02..fdd674c 100644 (file)
@@ -1,6 +1,6 @@
 /* Failure exit status
 
-   Copyright (C) 2002-2003, 2005-2007, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2002-2003, 2005-2007, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
index 6d01d4f..074f212 100644 (file)
@@ -1,6 +1,6 @@
 /* Failure exit status
 
-   Copyright (C) 2002, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
diff --git a/contrib/grep/lib/fchdir.c b/contrib/grep/lib/fchdir.c
new file mode 100644 (file)
index 0000000..2e07553
--- /dev/null
@@ -0,0 +1,208 @@
+/* fchdir replacement.
+   Copyright (C) 2006-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "dosname.h"
+#include "filenamecat.h"
+
+#ifndef REPLACE_OPEN_DIRECTORY
+# define REPLACE_OPEN_DIRECTORY 0
+#endif
+
+/* This replacement assumes that a directory is not renamed while opened
+   through a file descriptor.
+
+   FIXME: On mingw, this would be possible to enforce if we were to
+   also open a HANDLE to each directory currently visited by a file
+   descriptor, since mingw refuses to rename any in-use file system
+   object.  */
+
+/* Array of file descriptors opened.  If REPLACE_OPEN_DIRECTORY or if it points
+   to a directory, it stores info about this directory.  */
+typedef struct
+{
+  char *name;       /* Absolute name of the directory, or NULL.  */
+  /* FIXME - add a DIR* member to make dirfd possible on mingw?  */
+} dir_info_t;
+static dir_info_t *dirs;
+static size_t dirs_allocated;
+
+/* Try to ensure dirs has enough room for a slot at index fd; free any
+   contents already in that slot.  Return false and set errno to
+   ENOMEM on allocation failure.  */
+static bool
+ensure_dirs_slot (size_t fd)
+{
+  if (fd < dirs_allocated)
+    free (dirs[fd].name);
+  else
+    {
+      size_t new_allocated;
+      dir_info_t *new_dirs;
+
+      new_allocated = 2 * dirs_allocated + 1;
+      if (new_allocated <= fd)
+        new_allocated = fd + 1;
+      new_dirs =
+        (dirs != NULL
+         ? (dir_info_t *) realloc (dirs, new_allocated * sizeof *dirs)
+         : (dir_info_t *) malloc (new_allocated * sizeof *dirs));
+      if (new_dirs == NULL)
+        return false;
+      memset (new_dirs + dirs_allocated, 0,
+              (new_allocated - dirs_allocated) * sizeof *dirs);
+      dirs = new_dirs;
+      dirs_allocated = new_allocated;
+    }
+  return true;
+}
+
+/* Return an absolute name of DIR in malloc'd storage.  */
+static char *
+get_name (char const *dir)
+{
+  char *cwd;
+  char *result;
+  int saved_errno;
+
+  if (IS_ABSOLUTE_FILE_NAME (dir))
+    return strdup (dir);
+
+  /* We often encounter "."; treat it as a special case.  */
+  cwd = getcwd (NULL, 0);
+  if (!cwd || (dir[0] == '.' && dir[1] == '\0'))
+    return cwd;
+
+  result = mfile_name_concat (cwd, dir, NULL);
+  saved_errno = errno;
+  free (cwd);
+  errno = saved_errno;
+  return result;
+}
+
+/* Hook into the gnulib replacements for open() and close() to keep track
+   of the open file descriptors.  */
+
+/* Close FD, cleaning up any fd to name mapping if fd was visiting a
+   directory.  */
+void
+_gl_unregister_fd (int fd)
+{
+  if (fd >= 0 && fd < dirs_allocated)
+    {
+      free (dirs[fd].name);
+      dirs[fd].name = NULL;
+    }
+}
+
+/* Mark FD as visiting FILENAME.  FD must be non-negative, and refer
+   to an open file descriptor.  If REPLACE_OPEN_DIRECTORY is non-zero,
+   this should only be called if FD is visiting a directory.  Close FD
+   and return -1 if there is insufficient memory to track the
+   directory name; otherwise return FD.  */
+int
+_gl_register_fd (int fd, const char *filename)
+{
+  struct stat statbuf;
+
+  assert (0 <= fd);
+  if (REPLACE_OPEN_DIRECTORY
+      || (fstat (fd, &statbuf) == 0 && S_ISDIR (statbuf.st_mode)))
+    {
+      if (!ensure_dirs_slot (fd)
+          || (dirs[fd].name = get_name (filename)) == NULL)
+        {
+          int saved_errno = errno;
+          close (fd);
+          errno = saved_errno;
+          return -1;
+        }
+    }
+  return fd;
+}
+
+/* Mark NEWFD as a duplicate of OLDFD; useful from dup, dup2, dup3,
+   and fcntl.  Both arguments must be valid and distinct file
+   descriptors.  Close NEWFD and return -1 if OLDFD is tracking a
+   directory, but there is insufficient memory to track the same
+   directory in NEWFD; otherwise return NEWFD.  */
+int
+_gl_register_dup (int oldfd, int newfd)
+{
+  assert (0 <= oldfd && 0 <= newfd && oldfd != newfd);
+  if (oldfd < dirs_allocated && dirs[oldfd].name)
+    {
+      /* Duplicated a directory; must ensure newfd is allocated.  */
+      if (!ensure_dirs_slot (newfd)
+          || (dirs[newfd].name = strdup (dirs[oldfd].name)) == NULL)
+        {
+          int saved_errno = errno;
+          close (newfd);
+          errno = saved_errno;
+          newfd = -1;
+        }
+    }
+  else if (newfd < dirs_allocated)
+    {
+      /* Duplicated a non-directory; ensure newfd is cleared.  */
+      free (dirs[newfd].name);
+      dirs[newfd].name = NULL;
+    }
+  return newfd;
+}
+
+/* If FD is currently visiting a directory, then return the name of
+   that directory.  Otherwise, return NULL and set errno.  */
+const char *
+_gl_directory_name (int fd)
+{
+  if (0 <= fd && fd < dirs_allocated && dirs[fd].name != NULL)
+    return dirs[fd].name;
+  /* At this point, fd is either invalid, or open but not a directory.
+     If dup2 fails, errno is correctly EBADF.  */
+  if (0 <= fd)
+    {
+      if (dup2 (fd, fd) == fd)
+        errno = ENOTDIR;
+    }
+  else
+    errno = EBADF;
+  return NULL;
+}
+
+
+/* Implement fchdir() in terms of chdir().  */
+
+int
+fchdir (int fd)
+{
+  const char *name = _gl_directory_name (fd);
+  return name ? chdir (name) : -1;
+}
similarity index 65%
copy from contrib/grep/lib/exitfail.c
copy to contrib/grep/lib/fcntl--.h
index 953aa02..8fde6c1 100644 (file)
@@ -1,6 +1,6 @@
-/* Failure exit status
+/* Like fcntl.h, but redefine some names to avoid glitches.
 
-   Copyright (C) 2002-2003, 2005-2007, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <config.h>
+/* Written by Paul Eggert.  */
 
-#include "exitfail.h"
+#include <fcntl.h>
+#include "fcntl-safer.h"
 
-#include <stdlib.h>
+#undef open
+#define open open_safer
 
-int volatile exit_failure = EXIT_FAILURE;
+#undef creat
+#define creat creat_safer
+
+#if GNULIB_OPENAT_SAFER
+# undef openat
+# define openat openat_safer
+#endif
similarity index 66%
copy from contrib/grep/lib/exitfail.c
copy to contrib/grep/lib/fcntl-safer.h
index 953aa02..440a2ff 100644 (file)
@@ -1,6 +1,6 @@
-/* Failure exit status
+/* Invoke fcntl-like functions, but avoid some glitches.
 
-   Copyright (C) 2002-2003, 2005-2007, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <config.h>
+/* Written by Paul Eggert.  */
 
-#include "exitfail.h"
+#include <sys/types.h>
 
-#include <stdlib.h>
+int open_safer (char const *, int, ...);
+int creat_safer (char const *, mode_t);
 
-int volatile exit_failure = EXIT_FAILURE;
+#if GNULIB_OPENAT_SAFER
+int openat_safer (int, char const *, int, ...);
+#endif
diff --git a/contrib/grep/lib/fcntl.c b/contrib/grep/lib/fcntl.c
new file mode 100644 (file)
index 0000000..3dfb6b7
--- /dev/null
@@ -0,0 +1,311 @@
+/* Provide file descriptor control.
+
+   Copyright (C) 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <ebb9@byu.net>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <fcntl.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#if !HAVE_FCNTL
+# define rpl_fcntl fcntl
+#endif
+#undef fcntl
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Get declarations of the native Windows API functions.  */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+/* Get _get_osfhandle.  */
+# include "msvc-nothrow.h"
+
+/* Upper bound on getdtablesize().  See lib/getdtablesize.c.  */
+# define OPEN_MAX_MAX 0x10000
+
+/* Duplicate OLDFD into the first available slot of at least NEWFD,
+   which must be positive, with FLAGS determining whether the duplicate
+   will be inheritable.  */
+static int
+dupfd (int oldfd, int newfd, int flags)
+{
+  /* Mingw has no way to create an arbitrary fd.  Iterate until all
+     file descriptors less than newfd are filled up.  */
+  HANDLE curr_process = GetCurrentProcess ();
+  HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
+  unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
+  unsigned int fds_to_close_bound = 0;
+  int result;
+  BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
+  int mode;
+
+  if (newfd < 0 || getdtablesize () <= newfd)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  if (old_handle == INVALID_HANDLE_VALUE
+      || (mode = setmode (oldfd, O_BINARY)) == -1)
+    {
+      /* oldfd is not open, or is an unassigned standard file
+         descriptor.  */
+      errno = EBADF;
+      return -1;
+    }
+  setmode (oldfd, mode);
+  flags |= mode;
+
+  for (;;)
+    {
+      HANDLE new_handle;
+      int duplicated_fd;
+      unsigned int index;
+
+      if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
+                            old_handle,             /* SourceHandle */
+                            curr_process,           /* TargetProcessHandle */
+                            (PHANDLE) &new_handle,  /* TargetHandle */
+                            (DWORD) 0,              /* DesiredAccess */
+                            inherit,                /* InheritHandle */
+                            DUPLICATE_SAME_ACCESS)) /* Options */
+        {
+          /* TODO: Translate GetLastError () into errno.  */
+          errno = EMFILE;
+          result = -1;
+          break;
+        }
+      duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
+      if (duplicated_fd < 0)
+        {
+          CloseHandle (new_handle);
+          errno = EMFILE;
+          result = -1;
+          break;
+        }
+      if (newfd <= duplicated_fd)
+        {
+          result = duplicated_fd;
+          break;
+        }
+
+      /* Set the bit duplicated_fd in fds_to_close[].  */
+      index = (unsigned int) duplicated_fd / CHAR_BIT;
+      if (fds_to_close_bound <= index)
+        {
+          if (sizeof fds_to_close <= index)
+            /* Need to increase OPEN_MAX_MAX.  */
+            abort ();
+          memset (fds_to_close + fds_to_close_bound, '\0',
+                  index + 1 - fds_to_close_bound);
+          fds_to_close_bound = index + 1;
+        }
+      fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
+    }
+
+  /* Close the previous fds that turned out to be too small.  */
+  {
+    int saved_errno = errno;
+    unsigned int duplicated_fd;
+
+    for (duplicated_fd = 0;
+         duplicated_fd < fds_to_close_bound * CHAR_BIT;
+         duplicated_fd++)
+      if ((fds_to_close[duplicated_fd / CHAR_BIT]
+           >> (duplicated_fd % CHAR_BIT))
+          & 1)
+        close (duplicated_fd);
+
+    errno = saved_errno;
+  }
+
+# if REPLACE_FCHDIR
+  if (0 <= result)
+    result = _gl_register_dup (oldfd, result);
+# endif
+  return result;
+}
+#endif /* W32 */
+
+/* Perform the specified ACTION on the file descriptor FD, possibly
+   using the argument ARG further described below.  This replacement
+   handles the following actions, and forwards all others on to the
+   native fcntl.  An unrecognized ACTION returns -1 with errno set to
+   EINVAL.
+
+   F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
+   If successful, return the duplicate, which will be inheritable;
+   otherwise return -1 and set errno.
+
+   F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
+   target fd.  If successful, return the duplicate, which will not be
+   inheritable; otherwise return -1 and set errno.
+
+   F_GETFD - ARG need not be present.  If successful, return a
+   non-negative value containing the descriptor flags of FD (only
+   FD_CLOEXEC is portable, but other flags may be present); otherwise
+   return -1 and set errno.  */
+
+int
+rpl_fcntl (int fd, int action, /* arg */...)
+{
+  va_list arg;
+  int result = -1;
+  va_start (arg, action);
+  switch (action)
+    {
+
+#if !HAVE_FCNTL
+    case F_DUPFD:
+      {
+        int target = va_arg (arg, int);
+        result = dupfd (fd, target, 0);
+        break;
+      }
+#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
+    case F_DUPFD:
+      {
+        int target = va_arg (arg, int);
+        /* Detect invalid target; needed for cygwin 1.5.x.  */
+        if (target < 0 || getdtablesize () <= target)
+          errno = EINVAL;
+        else
+          {
+            /* Haiku alpha 2 loses fd flags on original.  */
+            int flags = fcntl (fd, F_GETFD);
+            if (flags < 0)
+              {
+                result = -1;
+                break;
+              }
+            result = fcntl (fd, action, target);
+            if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
+              {
+                int saved_errno = errno;
+                close (result);
+                result = -1;
+                errno = saved_errno;
+              }
+# if REPLACE_FCHDIR
+            if (0 <= result)
+              result = _gl_register_dup (fd, result);
+# endif
+          }
+        break;
+      } /* F_DUPFD */
+#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
+
+    case F_DUPFD_CLOEXEC:
+      {
+        int target = va_arg (arg, int);
+
+#if !HAVE_FCNTL
+        result = dupfd (fd, target, O_CLOEXEC);
+        break;
+#else /* HAVE_FCNTL */
+        /* Try the system call first, if the headers claim it exists
+           (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
+           may be running with a glibc that has the macro but with an
+           older kernel that does not support it.  Cache the
+           information on whether the system call really works, but
+           avoid caching failure if the corresponding F_DUPFD fails
+           for any reason.  0 = unknown, 1 = yes, -1 = no.  */
+        static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
+        if (0 <= have_dupfd_cloexec)
+          {
+            result = fcntl (fd, action, target);
+            if (0 <= result || errno != EINVAL)
+              {
+                have_dupfd_cloexec = 1;
+# if REPLACE_FCHDIR
+                if (0 <= result)
+                  result = _gl_register_dup (fd, result);
+# endif
+              }
+            else
+              {
+                result = rpl_fcntl (fd, F_DUPFD, target);
+                if (result < 0)
+                  break;
+                have_dupfd_cloexec = -1;
+              }
+          }
+        else
+          result = rpl_fcntl (fd, F_DUPFD, target);
+        if (0 <= result && have_dupfd_cloexec == -1)
+          {
+            int flags = fcntl (result, F_GETFD);
+            if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
+              {
+                int saved_errno = errno;
+                close (result);
+                errno = saved_errno;
+                result = -1;
+              }
+          }
+        break;
+#endif /* HAVE_FCNTL */
+      } /* F_DUPFD_CLOEXEC */
+
+#if !HAVE_FCNTL
+    case F_GETFD:
+      {
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+        HANDLE handle = (HANDLE) _get_osfhandle (fd);
+        DWORD flags;
+        if (handle == INVALID_HANDLE_VALUE
+            || GetHandleInformation (handle, &flags) == 0)
+          errno = EBADF;
+        else
+          result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
+# else /* !W32 */
+        /* Use dup2 to reject invalid file descriptors.  No way to
+           access this information, so punt.  */
+        if (0 <= dup2 (fd, fd))
+          result = 0;
+# endif /* !W32 */
+        break;
+      } /* F_GETFD */
+#endif /* !HAVE_FCNTL */
+
+      /* Implementing F_SETFD on mingw is not trivial - there is no
+         API for changing the O_NOINHERIT bit on an fd, and merely
+         changing the HANDLE_FLAG_INHERIT bit on the underlying handle
+         can lead to odd state.  It may be possible by duplicating the
+         handle, using _open_osfhandle with the right flags, then
+         using dup2 to move the duplicate onto the original, but that
+         is not supported for now.  */
+
+    default:
+      {
+#if HAVE_FCNTL
+        void *p = va_arg (arg, void *);
+        result = fcntl (fd, action, p);
+#else
+        errno = EINVAL;
+#endif
+        break;
+      }
+    }
+  va_end (arg);
+  return result;
+}
diff --git a/contrib/grep/lib/fd-hook.c b/contrib/grep/lib/fd-hook.c
new file mode 100644 (file)
index 0000000..8f4ffe2
--- /dev/null
@@ -0,0 +1,116 @@
+/* Hook for making making file descriptor functions close(), ioctl() extensible.
+   Copyright (C) 2009-2012 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2009.
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "fd-hook.h"
+
+#include <stdlib.h>
+
+/* Currently, this entire code is only needed for the handling of sockets
+   on native Windows platforms.  */
+#if WINDOWS_SOCKETS
+
+/* The first and last link in the doubly linked list.
+   Initially the list is empty.  */
+static struct fd_hook anchor = { &anchor, &anchor, NULL, NULL };
+
+int
+execute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary,
+                     int fd)
+{
+  if (remaining_list == &anchor)
+    /* End of list reached.  */
+    return primary (fd);
+  else
+    return remaining_list->private_close_fn (remaining_list->private_next,
+                                             primary, fd);
+}
+
+int
+execute_all_close_hooks (gl_close_fn primary, int fd)
+{
+  return execute_close_hooks (anchor.private_next, primary, fd);
+}
+
+int
+execute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary,
+                     int fd, int request, void *arg)
+{
+  if (remaining_list == &anchor)
+    /* End of list reached.  */
+    return primary (fd, request, arg);
+  else
+    return remaining_list->private_ioctl_fn (remaining_list->private_next,
+                                             primary, fd, request, arg);
+}
+
+int
+execute_all_ioctl_hooks (gl_ioctl_fn primary,
+                         int fd, int request, void *arg)
+{
+  return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg);
+}
+
+void
+register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link)
+{
+  if (close_hook == NULL)
+    close_hook = execute_close_hooks;
+  if (ioctl_hook == NULL)
+    ioctl_hook = execute_ioctl_hooks;
+
+  if (link->private_next == NULL && link->private_prev == NULL)
+    {
+      /* Add the link to the doubly linked list.  */
+      link->private_next = anchor.private_next;
+      link->private_prev = &anchor;
+      link->private_close_fn = close_hook;
+      link->private_ioctl_fn = ioctl_hook;
+      anchor.private_next->private_prev = link;
+      anchor.private_next = link;
+    }
+  else
+    {
+      /* The link is already in use.  */
+      if (link->private_close_fn != close_hook
+          || link->private_ioctl_fn != ioctl_hook)
+        abort ();
+    }
+}
+
+void
+unregister_fd_hook (struct fd_hook *link)
+{
+  struct fd_hook *next = link->private_next;
+  struct fd_hook *prev = link->private_prev;
+
+  if (next != NULL && prev != NULL)
+    {
+      /* The link is in use.  Remove it from the doubly linked list.  */
+      prev->private_next = next;
+      next->private_prev = prev;
+      /* Clear the link, to mark it unused.  */
+      link->private_next = NULL;
+      link->private_prev = NULL;
+      link->private_close_fn = NULL;
+      link->private_ioctl_fn = NULL;
+    }
+}
+
+#endif
diff --git a/contrib/grep/lib/fd-hook.h b/contrib/grep/lib/fd-hook.h
new file mode 100644 (file)
index 0000000..721e9ad
--- /dev/null
@@ -0,0 +1,119 @@
+/* Hook for making making file descriptor functions close(), ioctl() extensible.
+   Copyright (C) 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#ifndef FD_HOOK_H
+#define FD_HOOK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Currently, this entire code is only needed for the handling of sockets
+   on native Windows platforms.  */
+#if WINDOWS_SOCKETS
+
+
+/* Type of function that closes FD.  */
+typedef int (*gl_close_fn) (int fd);
+
+/* Type of function that applies a control request to FD.  */
+typedef int (*gl_ioctl_fn) (int fd, int request, void *arg);
+
+/* An element of the list of file descriptor hooks.
+   In CLOS (Common Lisp Object System) speak, it consists of an "around"
+   method for the close() function and an "around" method for the ioctl()
+   function.
+   The fields of this structure are considered private.  */
+struct fd_hook
+{
+  /* Doubly linked list.  */
+  struct fd_hook *private_next;
+  struct fd_hook *private_prev;
+  /* Function that treats the types of FD that it knows about and calls
+     execute_close_hooks (REMAINING_LIST, PRIMARY, FD) as a fallback.  */
+  int (*private_close_fn) (const struct fd_hook *remaining_list,
+                           gl_close_fn primary,
+                           int fd);
+  /* Function that treats the types of FD that it knows about and calls
+     execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG) as a
+     fallback.  */
+  int (*private_ioctl_fn) (const struct fd_hook *remaining_list,
+                           gl_ioctl_fn primary,
+                           int fd, int request, void *arg);
+};
+
+/* This type of function closes FD, applying special knowledge for the FD
+   types it knows about, and calls
+   execute_close_hooks (REMAINING_LIST, PRIMARY, FD)
+   for the other FD types.
+   In CLOS speak, REMAINING_LIST is the remaining list of "around" methods,
+   and PRIMARY is the "primary" method for close().  */
+typedef int (*close_hook_fn) (const struct fd_hook *remaining_list,
+                              gl_close_fn primary,
+                              int fd);
+
+/* Execute the close hooks in REMAINING_LIST, with PRIMARY as "primary" method.
+   Return 0 or -1, like close() would do.  */
+extern int execute_close_hooks (const struct fd_hook *remaining_list,
+                                gl_close_fn primary,
+                                int fd);
+
+/* Execute all close hooks, with PRIMARY as "primary" method.
+   Return 0 or -1, like close() would do.  */
+extern int execute_all_close_hooks (gl_close_fn primary, int fd);
+
+/* This type of function applies a control request to FD, applying special
+   knowledge for the FD types it knows about, and calls
+   execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG)
+   for the other FD types.
+   In CLOS speak, REMAINING_LIST is the remaining list of "around" methods,
+   and PRIMARY is the "primary" method for ioctl().  */
+typedef int (*ioctl_hook_fn) (const struct fd_hook *remaining_list,
+                              gl_ioctl_fn primary,
+                              int fd, int request, void *arg);
+
+/* Execute the ioctl hooks in REMAINING_LIST, with PRIMARY as "primary" method.
+   Return 0 or -1, like ioctl() would do.  */
+extern int execute_ioctl_hooks (const struct fd_hook *remaining_list,
+                                gl_ioctl_fn primary,
+                                int fd, int request, void *arg);
+
+/* Execute all ioctl hooks, with PRIMARY as "primary" method.
+   Return 0 or -1, like ioctl() would do.  */
+extern int execute_all_ioctl_hooks (gl_ioctl_fn primary,
+                                    int fd, int request, void *arg);
+
+/* Add a function pair to the list of file descriptor hooks.
+   CLOSE_HOOK and IOCTL_HOOK may be NULL, indicating no change.
+   The LINK variable points to a piece of memory which is guaranteed to be
+   accessible until the corresponding call to unregister_fd_hook.  */
+extern void register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook,
+                              struct fd_hook *link);
+
+/* Removes a hook from the list of file descriptor hooks.  */
+extern void unregister_fd_hook (struct fd_hook *link);
+
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FD_HOOK_H */
diff --git a/contrib/grep/lib/fd-safer.c b/contrib/grep/lib/fd-safer.c
new file mode 100644 (file)
index 0000000..052837b
--- /dev/null
@@ -0,0 +1,49 @@
+/* Return a safer copy of a file descriptor.
+
+   Copyright (C) 2005-2006, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Paul Eggert.  */
+
+#include <config.h>
+
+#include "unistd-safer.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Return FD, unless FD would be a copy of standard input, output, or
+   error; in that case, return a duplicate of FD, closing FD.  On
+   failure to duplicate, close FD, set errno, and return -1.  Preserve
+   errno if FD is negative, so that the caller can always inspect
+   errno when the returned value is negative.
+
+   This function is usefully wrapped around functions that return file
+   descriptors, e.g., fd_safer (open ("file", O_RDONLY)).  */
+
+int
+fd_safer (int fd)
+{
+  if (STDIN_FILENO <= fd && fd <= STDERR_FILENO)
+    {
+      int f = dup_safer (fd);
+      int e = errno;
+      close (fd);
+      errno = e;
+      fd = f;
+    }
+
+  return fd;
+}
diff --git a/contrib/grep/lib/fdopendir.c b/contrib/grep/lib/fdopendir.c
new file mode 100644 (file)
index 0000000..4ae7d05
--- /dev/null
@@ -0,0 +1,204 @@
+/* provide a replacement fdopendir function
+   Copyright (C) 2004-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* written by Jim Meyering */
+
+#include <config.h>
+
+#include <dirent.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#if !HAVE_FDOPENDIR
+
+# include "openat.h"
+# include "openat-priv.h"
+# include "save-cwd.h"
+
+# if GNULIB_DIRENT_SAFER
+#  include "dirent--.h"
+# endif
+
+# ifndef REPLACE_FCHDIR
+#  define REPLACE_FCHDIR 0
+# endif
+
+static DIR *fdopendir_with_dup (int, int, struct saved_cwd const *);
+static DIR *fd_clone_opendir (int, struct saved_cwd const *);
+
+/* Replacement for POSIX fdopendir.
+
+   First, try to simulate it via opendir ("/proc/self/fd/...").  Failing
+   that, simulate it by using fchdir metadata, or by doing
+   save_cwd/fchdir/opendir(".")/restore_cwd.
+   If either the save_cwd or the restore_cwd fails (relatively unlikely),
+   then give a diagnostic and exit nonzero.
+
+   If successful, the resulting stream is based on FD in
+   implementations where streams are based on file descriptors and in
+   applications where no other thread or signal handler allocates or
+   frees file descriptors.  In other cases, consult dirfd on the result
+   to find out whether FD is still being used.
+
+   Otherwise, this function works just like POSIX fdopendir.
+
+   W A R N I N G:
+
+   Unlike other fd-related functions, this one places constraints on FD.
+   If this function returns successfully, FD is under control of the
+   dirent.h system, and the caller should not close or modify the state of
+   FD other than by the dirent.h functions.  */
+DIR *
+fdopendir (int fd)
+{
+  DIR *dir = fdopendir_with_dup (fd, -1, NULL);
+
+  if (! REPLACE_FCHDIR && ! dir)
+    {
+      int saved_errno = errno;
+      if (EXPECTED_ERRNO (saved_errno))
+        {
+          struct saved_cwd cwd;
+          if (save_cwd (&cwd) != 0)
+            openat_save_fail (errno);
+          dir = fdopendir_with_dup (fd, -1, &cwd);
+          saved_errno = errno;
+          free_cwd (&cwd);
+          errno = saved_errno;
+        }
+    }
+
+  return dir;
+}
+
+/* Like fdopendir, except that if OLDER_DUPFD is not -1, it is known
+   to be a dup of FD which is less than FD - 1 and which will be
+   closed by the caller and not otherwise used by the caller.  This
+   function makes sure that FD is closed and all file descriptors less
+   than FD are open, and then calls fd_clone_opendir on a dup of FD.
+   That way, barring race conditions, fd_clone_opendir returns a
+   stream whose file descriptor is FD.
+
+   If REPLACE_CHDIR or CWD is null, use opendir ("/proc/self/fd/...",
+   falling back on fchdir metadata.  Otherwise, CWD is a saved version
+   of the working directory; use fchdir/opendir(".")/restore_cwd(CWD).  */
+static DIR *
+fdopendir_with_dup (int fd, int older_dupfd, struct saved_cwd const *cwd)
+{
+  int dupfd = dup (fd);
+  if (dupfd < 0 && errno == EMFILE)
+    dupfd = older_dupfd;
+  if (dupfd < 0)
+    return NULL;
+  else
+    {
+      DIR *dir;
+      int saved_errno;
+      if (dupfd < fd - 1 && dupfd != older_dupfd)
+        {
+          dir = fdopendir_with_dup (fd, dupfd, cwd);
+          saved_errno = errno;
+        }
+      else
+        {
+          close (fd);
+          dir = fd_clone_opendir (dupfd, cwd);
+          saved_errno = errno;
+          if (! dir)
+            {
+              int fd1 = dup (dupfd);
+              if (fd1 != fd)
+                openat_save_fail (fd1 < 0 ? errno : EBADF);
+            }
+        }
+
+      if (dupfd != older_dupfd)
+        close (dupfd);
+      errno = saved_errno;
+      return dir;
+    }
+}
+
+/* Like fdopendir, except the result controls a clone of FD.  It is
+   the caller's responsibility both to close FD and (if the result is
+   not null) to closedir the result.  */
+static DIR *
+fd_clone_opendir (int fd, struct saved_cwd const *cwd)
+{
+  if (REPLACE_FCHDIR || ! cwd)
+    {
+      DIR *dir = NULL;
+      int saved_errno = EOPNOTSUPP;
+      char buf[OPENAT_BUFFER_SIZE];
+      char *proc_file = openat_proc_name (buf, fd, ".");
+      if (proc_file)
+        {
+          dir = opendir (proc_file);
+          saved_errno = errno;
+          if (proc_file != buf)
+            free (proc_file);
+        }
+# if REPLACE_FCHDIR
+      if (! dir && EXPECTED_ERRNO (saved_errno))
+        {
+          char const *name = _gl_directory_name (fd);
+          return (name ? opendir (name) : NULL);
+        }
+# endif
+      errno = saved_errno;
+      return dir;
+    }
+  else
+    {
+      if (fchdir (fd) != 0)
+        return NULL;
+      else
+        {
+          DIR *dir = opendir (".");
+          int saved_errno = errno;
+          if (restore_cwd (cwd) != 0)
+            openat_restore_fail (errno);
+          errno = saved_errno;
+          return dir;
+        }
+    }
+}
+
+#else /* HAVE_FDOPENDIR */
+
+# include <errno.h>
+# include <sys/stat.h>
+
+# undef fdopendir
+
+/* Like fdopendir, but work around GNU/Hurd bug by validating FD.  */
+
+DIR *
+rpl_fdopendir (int fd)
+{
+  struct stat st;
+  if (fstat (fd, &st))
+    return NULL;
+  if (!S_ISDIR (st.st_mode))
+    {
+      errno = ENOTDIR;
+      return NULL;
+    }
+  return fdopendir (fd);
+}
+
+#endif /* HAVE_FDOPENDIR */
diff --git a/contrib/grep/lib/filename.h b/contrib/grep/lib/filename.h
new file mode 100644 (file)
index 0000000..7b89d0d
--- /dev/null
@@ -0,0 +1,54 @@
+/* Basic filename support macros.
+   Copyright (C) 2001-2004, 2007-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _FILENAME_H
+#define _FILENAME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Pathname support.
+   ISSLASH(C)           tests whether C is a directory separator character.
+   IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
+                        it may be concatenated to a directory pathname.
+   IS_PATH_WITH_DIR(P)  tests whether P contains a directory specification.
+ */
+#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
+  /* Native Windows, Cygwin, OS/2, DOS */
+# define ISSLASH(C) ((C) == '/' || (C) == '\\')
+# define HAS_DEVICE(P) \
+    ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
+     && (P)[1] == ':')
+# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
+# define IS_PATH_WITH_DIR(P) \
+    (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
+# define FILE_SYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
+#else
+  /* Unix */
+# define ISSLASH(C) ((C) == '/')
+# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
+# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
+# define FILE_SYSTEM_PREFIX_LEN(P) 0
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FILENAME_H */
diff --git a/contrib/grep/lib/filenamecat-lgpl.c b/contrib/grep/lib/filenamecat-lgpl.c
new file mode 100644 (file)
index 0000000..c7c4617
--- /dev/null
@@ -0,0 +1,88 @@
+/* Concatenate two arbitrary file names.
+
+   Copyright (C) 1996-2007, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Jim Meyering.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "filenamecat.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dirname.h"
+
+#if ! HAVE_MEMPCPY && ! defined mempcpy
+# define mempcpy(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
+#endif
+
+/* Return the longest suffix of F that is a relative file name.
+   If it has no such suffix, return the empty string.  */
+
+static char const * _GL_ATTRIBUTE_PURE
+longest_relative_suffix (char const *f)
+{
+  for (f += FILE_SYSTEM_PREFIX_LEN (f); ISSLASH (*f); f++)
+    continue;
+  return f;
+}
+
+/* Concatenate two file name components, DIR and ABASE, in
+   newly-allocated storage and return the result.
+   The resulting file name F is such that the commands "ls F" and "(cd
+   DIR; ls BASE)" refer to the same file, where BASE is ABASE with any
+   file system prefixes and leading separators removed.
+   Arrange for a directory separator if necessary between DIR and BASE
+   in the result, removing any redundant separators.
+   In any case, if BASE_IN_RESULT is non-NULL, set
+   *BASE_IN_RESULT to point to the copy of ABASE in the returned
+   concatenation.  However, if ABASE begins with more than one slash,
+   set *BASE_IN_RESULT to point to the sole corresponding slash that
+   is copied into the result buffer.
+
+   Return NULL if malloc fails.  */
+
+char *
+mfile_name_concat (char const *dir, char const *abase, char **base_in_result)
+{
+  char const *dirbase = last_component (dir);
+  size_t dirbaselen = base_len (dirbase);
+  size_t dirlen = dirbase - dir + dirbaselen;
+  size_t needs_separator = (dirbaselen && ! ISSLASH (dirbase[dirbaselen - 1]));
+
+  char const *base = longest_relative_suffix (abase);
+  size_t baselen = strlen (base);
+
+  char *p_concat = malloc (dirlen + needs_separator + baselen + 1);
+  char *p;
+
+  if (p_concat == NULL)
+    return NULL;
+
+  p = mempcpy (p_concat, dir, dirlen);
+  *p = DIRECTORY_SEPARATOR;
+  p += needs_separator;
+
+  if (base_in_result)
+    *base_in_result = p - IS_ABSOLUTE_FILE_NAME (abase);
+
+  p = mempcpy (p, base, baselen);
+  *p = '\0';
+
+  return p_concat;
+}
similarity index 64%
copy from contrib/grep/lib/closeout.h
copy to contrib/grep/lib/filenamecat.h
index ec8d7a6..e7b2e30 100644 (file)
@@ -1,6 +1,6 @@
-/* Close standard output and standard error.
+/* Concatenate two arbitrary file names.
 
-   Copyright (C) 1998, 2000, 2003-2004, 2006, 2008-2011 Free Software
+   Copyright (C) 1996-1997, 2003, 2005, 2007, 2009-2012 Free Software
    Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#ifndef CLOSEOUT_H
-# define CLOSEOUT_H 1
-
-# include <stdbool.h>
-
-# ifdef __cplusplus
-extern "C" {
-# endif
-
-void close_stdout_set_file_name (const char *file);
-void close_stdout_set_ignore_EPIPE (bool ignore);
-void close_stdout (void);
-
-# ifdef __cplusplus
-}
-# endif
+/* Written by Jim Meyering.  */
 
+#if GNULIB_FILENAMECAT
+char *file_name_concat (char const *dir, char const *base,
+                        char **base_in_result);
 #endif
+
+char *mfile_name_concat (char const *dir, char const *base,
+                         char **base_in_result);
index ecfc8fb..842182b 100644 (file)
@@ -1,6 +1,4 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
-/* Copyright (C) 1991-1993, 1996-2007, 2009-2011 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1993, 1996-2007, 2009-2012 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -13,8 +11,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 #ifndef _LIBC
 # include <config.h>
@@ -44,7 +41,7 @@
   (HAVE_WCTYPE_H && HAVE_BTOWC && HAVE_ISWCTYPE \
    && HAVE_WMEMCHR && (HAVE_WMEMCPY || HAVE_WMEMPCPY))
 
-/* For platform which support the ISO C amendement 1 functionality we
+/* For platform which support the ISO C amendment 1 functionality we
    support user defined character classes.  */
 #if defined _LIBC || WIDE_CHAR_SUPPORT
 # include <wctype.h>
@@ -80,7 +77,7 @@ extern int fnmatch (const char *pattern, const char *string, int flags);
    Library, but also included in many other GNU distributions.  Compiling
    and linking in this code is a waste when using the GNU C library
    (especially if it is a shared library).  Rather than having every GNU
-   program understand `configure --with-gnu-libc' and omit the object files,
+   program understand 'configure --with-gnu-libc' and omit the object files,
    it is simpler to just do this in the source for each such file.  */
 
 #if defined _LIBC || !defined __GNU_LIBRARY__ || !HAVE_FNMATCH_GNU
@@ -94,7 +91,7 @@ extern int fnmatch (const char *pattern, const char *string, int flags);
 
 # if defined _LIBC || WIDE_CHAR_SUPPORT
 /* The GNU C library provides support for user-defined character classes
-   and the functions from ISO C amendement 1.  */
+   and the functions from ISO C amendment 1.  */
 #  ifdef CHARCLASS_NAME_MAX
 #   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
 #  else
@@ -121,7 +118,7 @@ extern int fnmatch (const char *pattern, const char *string, int flags);
 #  endif
 
 # else
-#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, 'xdigit'.  */
 
 #  define IS_CHAR_CLASS(string)                                               \
    (STREQ (string, "alpha") || STREQ (string, "upper")                        \
@@ -170,7 +167,6 @@ static int posixly_correct;
 #  endif
 # endif
 # define MEMCHR(S, C, N) memchr (S, C, N)
-# define STRCOLL(S1, S2) strcoll (S1, S2)
 # include "fnmatch_loop.c"
 
 
@@ -198,7 +194,6 @@ static int posixly_correct;
 #   endif
 #  endif
 #  define MEMCHR(S, C, N) wmemchr (S, C, N)
-#  define STRCOLL(S1, S2) wcscoll (S1, S2)
 #  define WIDE_CHAR_VERSION 1
 
 #  undef IS_CHAR_CLASS
index 06e7d8b..048079e 100644 (file)
@@ -1,6 +1,4 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
-/* Copyright (C) 1991-1993, 1996-2006, 2009-2011 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1993, 1996-2006, 2009-2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    This program is free software; you can redistribute it and/or modify
@@ -14,8 +12,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
 /* Match STRING against the file name pattern PATTERN, returning zero if
    it matches, nonzero if not.  */
@@ -218,7 +215,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
               return FNM_NOMATCH;
 
             if (*n == L_('/') && (flags & FNM_FILE_NAME))
-              /* `/' cannot be matched.  */
+              /* '/' cannot be matched.  */
               return FNM_NOMATCH;
 
             not = (*p == L_('!') || (posixly_correct < 0 && *p == L_('^')));
@@ -384,7 +381,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
                           {
                             /* We found a table entry.  Now see whether the
                                character we are currently at has the same
-                               equivalance class value.  */
+                               equivalence class value.  */
                             int len = weights[idx & 0xffffff];
                             int32_t idx2;
                             const UCHAR *np = (const UCHAR *) n;
@@ -638,7 +635,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
                         UCHAR cend = *p++;
 
 # ifdef WIDE_CHAR_VERSION
-                        /* Search in the `names' array for the characters.  */
+                        /* Search in the 'names' array for the characters.  */
                         fcollseq = __collseq_table_lookup (collseq, fn);
                         if (fcollseq == ~((uint32_t) 0))
                           /* XXX We don't know anything about the character
@@ -841,7 +838,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end,
 #else
                         /* We use a boring value comparison of the character
                            values.  This is better than comparing using
-                           `strcoll' since the latter would have surprising
+                           'strcoll' since the latter would have surprising
                            and sometimes fatal consequences.  */
                         UCHAR cend = *p++;
 
@@ -1158,7 +1155,7 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
 
     case L_('@'):
       do
-        /* I cannot believe it but `strcat' is actually acceptable
+        /* I cannot believe it but 'strcat' is actually acceptable
            here.  Match the entire string with the prefix from the
            pattern list and the rest of the pattern following the
            pattern list.  */
@@ -1216,7 +1213,6 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
 #undef END
 #undef MEMPCPY
 #undef MEMCHR
-#undef STRCOLL
 #undef STRLEN
 #undef STRCAT
 #undef L_
index 5ec38cb..2591d53 100644 (file)
@@ -1,5 +1,5 @@
 /* fpending.c -- return the number of pending output bytes on a stream
-   Copyright (C) 2000, 2004, 2006-2007, 2009-2011 Free Software Foundation,
+   Copyright (C) 2000, 2004, 2006-2007, 2009-2012 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
index d7994f7..5b5d71c 100644 (file)
@@ -1,6 +1,6 @@
 /* Declare __fpending.
 
-   Copyright (C) 2000, 2003, 2005-2006, 2009-2011 Free Software Foundation,
+   Copyright (C) 2000, 2003, 2005-2006, 2009-2012 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
diff --git a/contrib/grep/lib/fstat.c b/contrib/grep/lib/fstat.c
new file mode 100644 (file)
index 0000000..ac2b1ef
--- /dev/null
@@ -0,0 +1,86 @@
+/* fstat() replacement.
+   Copyright (C) 2011-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* If the user's config.h happens to include <sys/stat.h>, let it include only
+   the system's <sys/stat.h> here, so that orig_fstat doesn't recurse to
+   rpl_fstat.  */
+#define __need_system_sys_stat_h
+#include <config.h>
+
+/* Get the original definition of fstat.  It might be defined as a macro.  */
+#include <sys/types.h>
+#include <sys/stat.h>
+#if _GL_WINDOWS_64_BIT_ST_SIZE
+# define stat _stati64
+# define fstat _fstati64
+#endif
+#undef __need_system_sys_stat_h
+
+static inline int
+orig_fstat (int fd, struct stat *buf)
+{
+  return fstat (fd, buf);
+}
+
+/* Specification.  */
+/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
+   eliminates this include because of the preliminary #include <sys/stat.h>
+   above.  */
+#include "sys/stat.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+# include "msvc-inval.h"
+#endif
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static inline int
+fstat_nothrow (int fd, struct stat *buf)
+{
+  int result;
+
+  TRY_MSVC_INVAL
+    {
+      result = orig_fstat (fd, buf);
+    }
+  CATCH_MSVC_INVAL
+    {
+      result = -1;
+      errno = EBADF;
+    }
+  DONE_MSVC_INVAL;
+
+  return result;
+}
+#else
+# define fstat_nothrow orig_fstat
+#endif
+
+int
+rpl_fstat (int fd, struct stat *buf)
+{
+#if REPLACE_FCHDIR && REPLACE_OPEN_DIRECTORY
+  /* Handle the case when rpl_open() used a dummy file descriptor to work
+     around an open() that can't normally visit directories.  */
+  const char *name = _gl_directory_name (fd);
+  if (name != NULL)
+    return stat (name, buf);
+#endif
+
+  return fstat_nothrow (fd, buf);
+}
diff --git a/contrib/grep/lib/fstatat.c b/contrib/grep/lib/fstatat.c
new file mode 100644 (file)
index 0000000..9b701c4
--- /dev/null
@@ -0,0 +1,135 @@
+/* Work around an fstatat bug on Solaris 9.
+
+   Copyright (C) 2006, 2009-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Paul Eggert and Jim Meyering.  */
+
+/* If the user's config.h happens to include <sys/stat.h>, let it include only
+   the system's <sys/stat.h> here, so that orig_fstatat doesn't recurse to
+   rpl_fstatat.  */
+#define __need_system_sys_stat_h
+#include <config.h>
+
+/* Get the original definition of fstatat.  It might be defined as a macro.  */
+#include <sys/types.h>
+#include <sys/stat.h>
+#undef __need_system_sys_stat_h
+
+#if HAVE_FSTATAT
+static inline int
+orig_fstatat (int fd, char const *filename, struct stat *buf, int flags)
+{
+  return fstatat (fd, filename, buf, flags);
+}
+#endif
+
+/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
+   eliminates this include because of the preliminary #include <sys/stat.h>
+   above.  */
+#include "sys/stat.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#if HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG
+
+# ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK
+#  define LSTAT_FOLLOWS_SLASHED_SYMLINK 0
+# endif
+
+/* fstatat should always follow symbolic links that end in /, but on
+   Solaris 9 it doesn't if AT_SYMLINK_NOFOLLOW is specified.
+   Likewise, trailing slash on a non-directory should be an error.
+   These are the same problems that lstat.c and stat.c address, so
+   solve it in a similar way.
+
+   AIX 7.1 fstatat (AT_FDCWD, ..., 0) always fails, which is a bug.
+   Work around this bug if FSTATAT_AT_FDCWD_0_BROKEN is nonzero.  */
+
+int
+rpl_fstatat (int fd, char const *file, struct stat *st, int flag)
+{
+  int result = orig_fstatat (fd, file, st, flag);
+  size_t len;
+
+  if (LSTAT_FOLLOWS_SLASHED_SYMLINK || result != 0)
+    return result;
+  len = strlen (file);
+  if (flag & AT_SYMLINK_NOFOLLOW)
+    {
+      /* Fix lstat behavior.  */
+      if (file[len - 1] != '/' || S_ISDIR (st->st_mode))
+        return 0;
+      if (!S_ISLNK (st->st_mode))
+        {
+          errno = ENOTDIR;
+          return -1;
+        }
+      result = orig_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW);
+    }
+  /* Fix stat behavior.  */
+  if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/')
+    {
+      errno = ENOTDIR;
+      return -1;
+    }
+  return result;
+}
+
+#else /* ! (HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG) */
+
+/* On mingw, the gnulib <sys/stat.h> defines 'stat' as a function-like
+   macro; but using it in AT_FUNC_F2 causes compilation failure
+   because the preprocessor sees a use of a macro that requires two
+   arguments but is only given one.  Hence, we need an inline
+   forwarder to get past the preprocessor.  */
+static inline int
+stat_func (char const *name, struct stat *st)
+{
+  return stat (name, st);
+}
+
+/* Likewise, if there is no native 'lstat', then the gnulib
+   <sys/stat.h> defined it as stat, which also needs adjustment.  */
+# if !HAVE_LSTAT
+#  undef lstat
+#  define lstat stat_func
+# endif
+
+/* Replacement for Solaris' function by the same name.
+   <http://www.google.com/search?q=fstatat+site:docs.sun.com>
+   First, try to simulate it via l?stat ("/proc/self/fd/FD/FILE").
+   Failing that, simulate it via save_cwd/fchdir/(stat|lstat)/restore_cwd.
+   If either the save_cwd or the restore_cwd fails (relatively unlikely),
+   then give a diagnostic and exit nonzero.
+   Otherwise, this function works just like Solaris' fstatat.  */
+
+# define AT_FUNC_NAME fstatat
+# define AT_FUNC_F1 lstat
+# define AT_FUNC_F2 stat_func
+# define AT_FUNC_USE_F1_COND AT_SYMLINK_NOFOLLOW
+# define AT_FUNC_POST_FILE_PARAM_DECLS , struct stat *st, int flag
+# define AT_FUNC_POST_FILE_ARGS        , st
+# include "at-func.c"
+# undef AT_FUNC_NAME
+# undef AT_FUNC_F1
+# undef AT_FUNC_F2
+# undef AT_FUNC_USE_F1_COND
+# undef AT_FUNC_POST_FILE_PARAM_DECLS
+# undef AT_FUNC_POST_FILE_ARGS
+
+#endif /* !HAVE_FSTATAT */
diff --git a/contrib/grep/lib/fts-cycle.c b/contrib/grep/lib/fts-cycle.c
new file mode 100644 (file)
index 0000000..bdb090f
--- /dev/null
@@ -0,0 +1,160 @@
+/* Detect cycles in file tree walks.
+
+   Copyright (C) 2003-2006, 2009-2012 Free Software Foundation, Inc.
+
+   Written by Jim Meyering.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "cycle-check.h"
+#include "hash.h"
+
+/* Use each of these to map a device/inode pair to an FTSENT.  */
+struct Active_dir
+{
+  dev_t dev;
+  ino_t ino;
+  FTSENT *fts_ent;
+};
+
+static bool
+AD_compare (void const *x, void const *y)
+{
+  struct Active_dir const *ax = x;
+  struct Active_dir const *ay = y;
+  return ax->ino == ay->ino
+      && ax->dev == ay->dev;
+}
+
+static size_t
+AD_hash (void const *x, size_t table_size)
+{
+  struct Active_dir const *ax = x;
+  return (uintmax_t) ax->ino % table_size;
+}
+
+/* Set up the cycle-detection machinery.  */
+
+static bool
+setup_dir (FTS *fts)
+{
+  if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
+    {
+      enum { HT_INITIAL_SIZE = 31 };
+      fts->fts_cycle.ht = hash_initialize (HT_INITIAL_SIZE, NULL, AD_hash,
+                                           AD_compare, free);
+      if (! fts->fts_cycle.ht)
+        return false;
+    }
+  else
+    {
+      fts->fts_cycle.state = malloc (sizeof *fts->fts_cycle.state);
+      if (! fts->fts_cycle.state)
+        return false;
+      cycle_check_init (fts->fts_cycle.state);
+    }
+
+  return true;
+}
+
+/* Enter a directory during a file tree walk.  */
+
+static bool
+enter_dir (FTS *fts, FTSENT *ent)
+{
+  if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
+    {
+      struct stat const *st = ent->fts_statp;
+      struct Active_dir *ad = malloc (sizeof *ad);
+      struct Active_dir *ad_from_table;
+
+      if (!ad)
+        return false;
+
+      ad->dev = st->st_dev;
+      ad->ino = st->st_ino;
+      ad->fts_ent = ent;
+
+      /* See if we've already encountered this directory.
+         This can happen when following symlinks as well as
+         with a corrupted directory hierarchy. */
+      ad_from_table = hash_insert (fts->fts_cycle.ht, ad);
+
+      if (ad_from_table != ad)
+        {
+          free (ad);
+          if (!ad_from_table)
+            return false;
+
+          /* There was an entry with matching dev/inode already in the table.
+             Record the fact that we've found a cycle.  */
+          ent->fts_cycle = ad_from_table->fts_ent;
+          ent->fts_info = FTS_DC;
+        }
+    }
+  else
+    {
+      if (cycle_check (fts->fts_cycle.state, ent->fts_statp))
+        {
+          /* FIXME: setting fts_cycle like this isn't proper.
+             To do what the documentation requires, we'd have to
+             go around the cycle again and find the right entry.
+             But no callers in coreutils use the fts_cycle member. */
+          ent->fts_cycle = ent;
+          ent->fts_info = FTS_DC;
+        }
+    }
+
+  return true;
+}
+
+/* Leave a directory during a file tree walk.  */
+
+static void
+leave_dir (FTS *fts, FTSENT *ent)
+{
+  struct stat const *st = ent->fts_statp;
+  if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
+    {
+      struct Active_dir obj;
+      void *found;
+      obj.dev = st->st_dev;
+      obj.ino = st->st_ino;
+      found = hash_delete (fts->fts_cycle.ht, &obj);
+      if (!found)
+        abort ();
+      free (found);
+    }
+  else
+    {
+      FTSENT *parent = ent->fts_parent;
+      if (parent != NULL && 0 <= parent->fts_level)
+        CYCLE_CHECK_REFLECT_CHDIR_UP (fts->fts_cycle.state,
+                                      *(parent->fts_statp), *st);
+    }
+}
+
+/* Free any memory used for cycle detection.  */
+
+static void
+free_dir (FTS *sp)
+{
+  if (sp->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
+    {
+      if (sp->fts_cycle.ht)
+        hash_free (sp->fts_cycle.ht);
+    }
+  else
+    free (sp->fts_cycle.state);
+}
diff --git a/contrib/grep/lib/fts.c b/contrib/grep/lib/fts.c
new file mode 100644 (file)
index 0000000..42c8067
--- /dev/null
@@ -0,0 +1,2095 @@
+/* Traverse a file hierarchy.
+
+   Copyright (C) 2004-2012 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include "fts_.h"
+
+#if HAVE_SYS_PARAM_H || defined _LIBC
+# include <sys/param.h>
+#endif
+#ifdef _LIBC
+# include <include/sys/stat.h>
+#else
+# include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if ! _LIBC
+# include "fcntl--.h"
+# include "dirent--.h"
+# include "unistd--.h"
+/* FIXME - use fcntl(F_DUPFD_CLOEXEC)/openat(O_CLOEXEC) once they are
+   supported.  */
+# include "cloexec.h"
+# include "openat.h"
+# include "same-inode.h"
+#endif
+
+#include <dirent.h>
+#ifndef _D_EXACT_NAMLEN
+# define _D_EXACT_NAMLEN(dirent) strlen ((dirent)->d_name)
+#endif
+
+#if HAVE_STRUCT_DIRENT_D_TYPE
+/* True if the type of the directory entry D is known.  */
+# define DT_IS_KNOWN(d) ((d)->d_type != DT_UNKNOWN)
+/* True if the type of the directory entry D must be T.  */
+# define DT_MUST_BE(d, t) ((d)->d_type == (t))
+# define D_TYPE(d) ((d)->d_type)
+#else
+# define DT_IS_KNOWN(d) false
+# define DT_MUST_BE(d, t) false
+# define D_TYPE(d) DT_UNKNOWN
+
+# undef DT_UNKNOWN
+# define DT_UNKNOWN 0
+
+/* Any nonzero values will do here, so long as they're distinct.
+   Undef any existing macros out of the way.  */
+# undef DT_BLK
+# undef DT_CHR
+# undef DT_DIR
+# undef DT_FIFO
+# undef DT_LNK
+# undef DT_REG
+# undef DT_SOCK
+# define DT_BLK 1
+# define DT_CHR 2
+# define DT_DIR 3
+# define DT_FIFO 4
+# define DT_LNK 5
+# define DT_REG 6
+# define DT_SOCK 7
+#endif
+
+#ifndef S_IFLNK
+# define S_IFLNK 0
+#endif
+#ifndef S_IFSOCK
+# define S_IFSOCK 0
+#endif
+
+enum
+{
+  NOT_AN_INODE_NUMBER = 0
+};
+
+#ifdef D_INO_IN_DIRENT
+# define D_INO(dp) (dp)->d_ino
+#else
+/* Some systems don't have inodes, so fake them to avoid lots of ifdefs.  */
+# define D_INO(dp) NOT_AN_INODE_NUMBER
+#endif
+
+/* If possible (see max_entries, below), read no more than this many directory
+   entries at a time.  Without this limit (i.e., when using non-NULL
+   fts_compar), processing a directory with 4,000,000 entries requires ~1GiB
+   of memory, and handling 64M entries would require 16GiB of memory.  */
+#ifndef FTS_MAX_READDIR_ENTRIES
+# define FTS_MAX_READDIR_ENTRIES 100000
+#endif
+
+/* If there are more than this many entries in a directory,
+   and the conditions mentioned below are satisfied, then sort
+   the entries on inode number before any further processing.  */
+#ifndef FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
+# define FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD 10000
+#endif
+
+enum
+{
+  _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD = FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
+};
+
+enum Fts_stat
+{
+  FTS_NO_STAT_REQUIRED = 1,
+  FTS_STAT_REQUIRED = 2
+};
+
+#ifdef _LIBC
+# undef close
+# define close __close
+# undef closedir
+# define closedir __closedir
+# undef fchdir
+# define fchdir __fchdir
+# undef open
+# define open __open
+# undef readdir
+# define readdir __readdir
+#else
+# undef internal_function
+# define internal_function /* empty */
+#endif
+
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+/* If this host provides the openat function, then we can avoid
+   attempting to open "." in some initialization code below.  */
+#ifdef HAVE_OPENAT
+# define HAVE_OPENAT_SUPPORT 1
+#else
+# define HAVE_OPENAT_SUPPORT 0
+#endif
+
+#ifdef NDEBUG
+# define fts_assert(expr) ((void) 0)
+#else
+# define fts_assert(expr)       \
+    do                          \
+      {                         \
+        if (!(expr))            \
+          abort ();             \
+      }                         \
+    while (false)
+#endif
+
+static FTSENT   *fts_alloc (FTS *, const char *, size_t) internal_function;
+static FTSENT   *fts_build (FTS *, int) internal_function;
+static void      fts_lfree (FTSENT *) internal_function;
+static void      fts_load (FTS *, FTSENT *) internal_function;
+static size_t    fts_maxarglen (char * const *) internal_function;
+static void      fts_padjust (FTS *, FTSENT *) internal_function;
+static bool      fts_palloc (FTS *, size_t) internal_function;
+static FTSENT   *fts_sort (FTS *, FTSENT *, size_t) internal_function;
+static unsigned short int fts_stat (FTS *, FTSENT *, bool) internal_function;
+static int      fts_safe_changedir (FTS *, FTSENT *, int, const char *)
+     internal_function;
+
+#include "fts-cycle.c"
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+#define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+#define STREQ(a, b)     (strcmp (a, b) == 0)
+
+#define CLR(opt)        (sp->fts_options &= ~(opt))
+#define ISSET(opt)      (sp->fts_options & (opt))
+#define SET(opt)        (sp->fts_options |= (opt))
+
+/* FIXME: FTS_NOCHDIR is now misnamed.
+   Call it FTS_USE_FULL_RELATIVE_FILE_NAMES instead. */
+#define FCHDIR(sp, fd)                                  \
+  (!ISSET(FTS_NOCHDIR) && (ISSET(FTS_CWDFD)             \
+                           ? (cwd_advance_fd ((sp), (fd), true), 0) \
+                           : fchdir (fd)))
+
+
+/* fts_build flags */
+/* FIXME: make this an enum */
+#define BCHILD          1               /* fts_children */
+#define BNAMES          2               /* fts_children, names only */
+#define BREAD           3               /* fts_read */
+
+#if FTS_DEBUG
+# include <inttypes.h>
+# include <stdint.h>
+# include <stdio.h>
+# include "getcwdat.h"
+bool fts_debug = false;
+# define Dprintf(x) do { if (fts_debug) printf x; } while (false)
+#else
+# define Dprintf(x)
+# define fd_ring_check(x)
+# define fd_ring_print(a, b, c)
+#endif
+
+#define LEAVE_DIR(Fts, Ent, Tag)                                \
+  do                                                            \
+    {                                                           \
+      Dprintf (("  %s-leaving: %s\n", Tag, (Ent)->fts_path));   \
+      leave_dir (Fts, Ent);                                     \
+      fd_ring_check (Fts);                                      \
+    }                                                           \
+  while (false)
+
+static void
+fd_ring_clear (I_ring *fd_ring)
+{
+  while ( ! i_ring_empty (fd_ring))
+    {
+      int fd = i_ring_pop (fd_ring);
+      if (0 <= fd)
+        close (fd);
+    }
+}
+
+/* Overload the fts_statp->st_size member (otherwise unused, when
+   fts_info is FTS_NSOK) to indicate whether fts_read should stat
+   this entry or not.  */
+static void
+fts_set_stat_required (FTSENT *p, bool required)
+{
+  fts_assert (p->fts_info == FTS_NSOK);
+  p->fts_statp->st_size = (required
+                           ? FTS_STAT_REQUIRED
+                           : FTS_NO_STAT_REQUIRED);
+}
+
+/* file-descriptor-relative opendir.  */
+/* FIXME: if others need this function, move it into lib/openat.c */
+static inline DIR *
+internal_function
+opendirat (int fd, char const *dir, int extra_flags, int *pdir_fd)
+{
+  int new_fd = openat (fd, dir,
+                       (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
+                        | extra_flags));
+  DIR *dirp;
+
+  if (new_fd < 0)
+    return NULL;
+  set_cloexec_flag (new_fd, true);
+  dirp = fdopendir (new_fd);
+  if (dirp)
+    *pdir_fd = new_fd;
+  else
+    {
+      int saved_errno = errno;
+      close (new_fd);
+      errno = saved_errno;
+    }
+  return dirp;
+}
+
+/* Virtual fchdir.  Advance SP's working directory file descriptor,
+   SP->fts_cwd_fd, to FD, and push the previous value onto the fd_ring.
+   CHDIR_DOWN_ONE is true if FD corresponds to an entry in the directory
+   open on sp->fts_cwd_fd; i.e., to move the working directory one level
+   down.  */
+static void
+internal_function
+cwd_advance_fd (FTS *sp, int fd, bool chdir_down_one)
+{
+  int old = sp->fts_cwd_fd;
+  fts_assert (old != fd || old == AT_FDCWD);
+
+  if (chdir_down_one)
+    {
+      /* Push "old" onto the ring.
+         If the displaced file descriptor is non-negative, close it.  */
+      int prev_fd_in_slot = i_ring_push (&sp->fts_fd_ring, old);
+      fd_ring_print (sp, stderr, "post-push");
+      if (0 <= prev_fd_in_slot)
+        close (prev_fd_in_slot); /* ignore any close failure */
+    }
+  else if ( ! ISSET (FTS_NOCHDIR))
+    {
+      if (0 <= old)
+        close (old); /* ignore any close failure */
+    }
+
+  sp->fts_cwd_fd = fd;
+}
+
+/* Restore the initial, pre-traversal, "working directory".
+   In FTS_CWDFD mode, we merely call cwd_advance_fd, otherwise,
+   we may actually change the working directory.
+   Return 0 upon success. Upon failure, set errno and return nonzero.  */
+static int
+restore_initial_cwd (FTS *sp)
+{
+  int fail = FCHDIR (sp, ISSET (FTS_CWDFD) ? AT_FDCWD : sp->fts_rfd);
+  fd_ring_clear (&(sp->fts_fd_ring));
+  return fail;
+}
+
+/* Open the directory DIR if possible, and return a file
+   descriptor.  Return -1 and set errno on failure.  It doesn't matter
+   whether the file descriptor has read or write access.  */
+
+static inline int
+internal_function
+diropen (FTS const *sp, char const *dir)
+{
+  int open_flags = (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
+                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0)
+                    | (ISSET (FTS_NOATIME) ? O_NOATIME : 0));
+
+  int fd = (ISSET (FTS_CWDFD)
+            ? openat (sp->fts_cwd_fd, dir, open_flags)
+            : open (dir, open_flags));
+  if (0 <= fd)
+    set_cloexec_flag (fd, true);
+  return fd;
+}
+
+FTS *
+fts_open (char * const *argv,
+          register int options,
+          int (*compar) (FTSENT const **, FTSENT const **))
+{
+        register FTS *sp;
+        register FTSENT *p, *root;
+        register size_t nitems;
+        FTSENT *parent = NULL;
+        FTSENT *tmp = NULL;     /* pacify gcc */
+        bool defer_stat;
+
+        /* Options check. */
+        if (options & ~FTS_OPTIONMASK) {
+                __set_errno (EINVAL);
+                return (NULL);
+        }
+        if ((options & FTS_NOCHDIR) && (options & FTS_CWDFD)) {
+                __set_errno (EINVAL);
+                return (NULL);
+        }
+        if ( ! (options & (FTS_LOGICAL | FTS_PHYSICAL))) {
+                __set_errno (EINVAL);
+                return (NULL);
+        }
+
+        /* Allocate/initialize the stream */
+        if ((sp = malloc(sizeof(FTS))) == NULL)
+                return (NULL);
+        memset(sp, 0, sizeof(FTS));
+        sp->fts_compar = compar;
+        sp->fts_options = options;
+
+        /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
+        if (ISSET(FTS_LOGICAL)) {
+                SET(FTS_NOCHDIR);
+                CLR(FTS_CWDFD);
+        }
+
+        /* Initialize fts_cwd_fd.  */
+        sp->fts_cwd_fd = AT_FDCWD;
+        if ( ISSET(FTS_CWDFD) && ! HAVE_OPENAT_SUPPORT)
+          {
+            /* While it isn't technically necessary to open "." this
+               early, doing it here saves us the trouble of ensuring
+               later (where it'd be messier) that "." can in fact
+               be opened.  If not, revert to FTS_NOCHDIR mode.  */
+            int fd = open (".",
+                           O_SEARCH | (ISSET (FTS_NOATIME) ? O_NOATIME : 0));
+            if (fd < 0)
+              {
+                /* Even if "." is unreadable, don't revert to FTS_NOCHDIR mode
+                   on systems like Linux+PROC_FS, where our openat emulation
+                   is good enough.  Note: on a system that emulates
+                   openat via /proc, this technique can still fail, but
+                   only in extreme conditions, e.g., when the working
+                   directory cannot be saved (i.e. save_cwd fails) --
+                   and that happens on Linux only when "." is unreadable
+                   and the CWD would be longer than PATH_MAX.
+                   FIXME: once Linux kernel openat support is well established,
+                   replace the above open call and this entire if/else block
+                   with the body of the if-block below.  */
+                if ( openat_needs_fchdir ())
+                  {
+                    SET(FTS_NOCHDIR);
+                    CLR(FTS_CWDFD);
+                  }
+              }
+            else
+              {
+                close (fd);
+              }
+          }
+
+        /*
+         * Start out with 1K of file name space, and enough, in any case,
+         * to hold the user's file names.
+         */
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+        {
+          size_t maxarglen = fts_maxarglen(argv);
+          if (! fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
+                  goto mem1;
+        }
+
+        /* Allocate/initialize root's parent. */
+        if (*argv != NULL) {
+                if ((parent = fts_alloc(sp, "", 0)) == NULL)
+                        goto mem2;
+                parent->fts_level = FTS_ROOTPARENTLEVEL;
+          }
+
+        /* The classic fts implementation would call fts_stat with
+           a new entry for each iteration of the loop below.
+           If the comparison function is not specified or if the
+           FTS_DEFER_STAT option is in effect, don't stat any entry
+           in this loop.  This is an attempt to minimize the interval
+           between the initial stat/lstat/fstatat and the point at which
+           a directory argument is first opened.  This matters for any
+           directory command line argument that resides on a file system
+           without genuine i-nodes.  If you specify FTS_DEFER_STAT along
+           with a comparison function, that function must not access any
+           data via the fts_statp pointer.  */
+        defer_stat = (compar == NULL || ISSET(FTS_DEFER_STAT));
+
+        /* Allocate/initialize root(s). */
+        for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
+                /* *Do* allow zero-length file names. */
+                size_t len = strlen(*argv);
+                if ((p = fts_alloc(sp, *argv, len)) == NULL)
+                        goto mem3;
+                p->fts_level = FTS_ROOTLEVEL;
+                p->fts_parent = parent;
+                p->fts_accpath = p->fts_name;
+                /* Even when defer_stat is true, be sure to stat the first
+                   command line argument, since fts_read (at least with
+                   FTS_XDEV) requires that.  */
+                if (defer_stat && root != NULL) {
+                        p->fts_info = FTS_NSOK;
+                        fts_set_stat_required(p, true);
+                } else {
+                        p->fts_info = fts_stat(sp, p, false);
+                }
+
+                /*
+                 * If comparison routine supplied, traverse in sorted
+                 * order; otherwise traverse in the order specified.
+                 */
+                if (compar) {
+                        p->fts_link = root;
+                        root = p;
+                } else {
+                        p->fts_link = NULL;
+                        if (root == NULL)
+                                tmp = root = p;
+                        else {
+                                tmp->fts_link = p;
+                                tmp = p;
+                        }
+                }
+        }
+        if (compar && nitems > 1)
+                root = fts_sort(sp, root, nitems);
+
+        /*
+         * Allocate a dummy pointer and make fts_read think that we've just
+         * finished the node before the root(s); set p->fts_info to FTS_INIT
+         * so that everything about the "current" node is ignored.
+         */
+        if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+                goto mem3;
+        sp->fts_cur->fts_link = root;
+        sp->fts_cur->fts_info = FTS_INIT;
+        if (! setup_dir (sp))
+                goto mem3;
+
+        /*
+         * If using chdir(2), grab a file descriptor pointing to dot to ensure
+         * that we can get back here; this could be avoided for some file names,
+         * but almost certainly not worth the effort.  Slashes, symbolic links,
+         * and ".." are all fairly nasty problems.  Note, if we can't get the
+         * descriptor we run anyway, just more slowly.
+         */
+        if (!ISSET(FTS_NOCHDIR) && !ISSET(FTS_CWDFD)
+            && (sp->fts_rfd = diropen (sp, ".")) < 0)
+                SET(FTS_NOCHDIR);
+
+        i_ring_init (&sp->fts_fd_ring, -1);
+        return (sp);
+
+mem3:   fts_lfree(root);
+        free(parent);
+mem2:   free(sp->fts_path);
+mem1:   free(sp);
+        return (NULL);
+}
+
+static void
+internal_function
+fts_load (FTS *sp, register FTSENT *p)
+{
+        register size_t len;
+        register char *cp;
+
+        /*
+         * Load the stream structure for the next traversal.  Since we don't
+         * actually enter the directory until after the preorder visit, set
+         * the fts_accpath field specially so the chdir gets done to the right
+         * place and the user can access the first node.  From fts_open it's
+         * known that the file name will fit.
+         */
+        len = p->fts_pathlen = p->fts_namelen;
+        memmove(sp->fts_path, p->fts_name, len + 1);
+        if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+                len = strlen(++cp);
+                memmove(p->fts_name, cp, len + 1);
+                p->fts_namelen = len;
+        }
+        p->fts_accpath = p->fts_path = sp->fts_path;
+}
+
+int
+fts_close (FTS *sp)
+{
+        register FTSENT *freep, *p;
+        int saved_errno = 0;
+
+        /*
+         * This still works if we haven't read anything -- the dummy structure
+         * points to the root list, so we step through to the end of the root
+         * list which has a valid parent pointer.
+         */
+        if (sp->fts_cur) {
+                for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+                        freep = p;
+                        p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
+                        free(freep);
+                }
+                free(p);
+        }
+
+        /* Free up child linked list, sort array, file name buffer. */
+        if (sp->fts_child)
+                fts_lfree(sp->fts_child);
+        free(sp->fts_array);
+        free(sp->fts_path);
+
+        if (ISSET(FTS_CWDFD))
+          {
+            if (0 <= sp->fts_cwd_fd)
+              if (close (sp->fts_cwd_fd))
+                saved_errno = errno;
+          }
+        else if (!ISSET(FTS_NOCHDIR))
+          {
+            /* Return to original directory, save errno if necessary. */
+            if (fchdir(sp->fts_rfd))
+              saved_errno = errno;
+
+            /* If close fails, record errno only if saved_errno is zero,
+               so that we report the probably-more-meaningful fchdir errno.  */
+            if (close (sp->fts_rfd))
+              if (saved_errno == 0)
+                saved_errno = errno;
+          }
+
+        fd_ring_clear (&sp->fts_fd_ring);
+
+        if (sp->fts_leaf_optimization_works_ht)
+          hash_free (sp->fts_leaf_optimization_works_ht);
+
+        free_dir (sp);
+
+        /* Free up the stream pointer. */
+        free(sp);
+
+        /* Set errno and return. */
+        if (saved_errno) {
+                __set_errno (saved_errno);
+                return (-1);
+        }
+
+        return (0);
+}
+
+#if defined __linux__ \
+  && HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE
+
+# include <sys/vfs.h>
+
+/* Linux-specific constants from coreutils' src/fs.h */
+# define S_MAGIC_TMPFS 0x1021994
+# define S_MAGIC_NFS 0x6969
+# define S_MAGIC_REISERFS 0x52654973
+# define S_MAGIC_PROC 0x9FA0
+
+/* Return false if it is easy to determine the file system type of
+   the directory on which DIR_FD is open, and sorting dirents on
+   inode numbers is known not to improve traversal performance with
+   that type of file system.  Otherwise, return true.  */
+static bool
+dirent_inode_sort_may_be_useful (int dir_fd)
+{
+  /* Skip the sort only if we can determine efficiently
+     that skipping it is the right thing to do.
+     The cost of performing an unnecessary sort is negligible,
+     while the cost of *not* performing it can be O(N^2) with
+     a very large constant.  */
+  struct statfs fs_buf;
+
+  /* If fstatfs fails, assume sorting would be useful.  */
+  if (fstatfs (dir_fd, &fs_buf) != 0)
+    return true;
+
+  /* FIXME: what about when f_type is not an integral type?
+     deal with that if/when it's encountered.  */
+  switch (fs_buf.f_type)
+    {
+    case S_MAGIC_TMPFS:
+    case S_MAGIC_NFS:
+      /* On a file system of any of these types, sorting
+         is unnecessary, and hence wasteful.  */
+      return false;
+
+    default:
+      return true;
+    }
+}
+
+/* Given a file descriptor DIR_FD open on a directory D,
+   return true if it is valid to apply the leaf-optimization
+   technique of counting directories in D via stat.st_nlink.  */
+static bool
+leaf_optimization_applies (int dir_fd)
+{
+  struct statfs fs_buf;
+
+  /* If fstatfs fails, assume we can't use the optimization.  */
+  if (fstatfs (dir_fd, &fs_buf) != 0)
+    return false;
+
+  /* FIXME: do we need to detect AFS mount points?  I doubt it,
+     unless fstatfs can report S_MAGIC_REISERFS for such a directory.  */
+
+  switch (fs_buf.f_type)
+    {
+      /* List here the file system types that lack usable dirent.d_type
+         info, yet for which the optimization does apply.  */
+    case S_MAGIC_REISERFS:
+      return true;
+
+    case S_MAGIC_PROC:
+      /* Explicitly listing this or any other file system type for which
+         the optimization is not applicable is not necessary, but we leave
+         it here to document the risk.  Per http://bugs.debian.org/143111,
+         /proc may have bogus stat.st_nlink values.  */
+      /* fall through */
+    default:
+      return false;
+    }
+}
+
+#else
+static bool
+dirent_inode_sort_may_be_useful (int dir_fd _GL_UNUSED) { return true; }
+static bool
+leaf_optimization_applies (int dir_fd _GL_UNUSED) { return false; }
+#endif
+
+/* link-count-optimization entry:
+   map a stat.st_dev number to a boolean: leaf_optimization_works */
+struct LCO_ent
+{
+  dev_t st_dev;
+  bool opt_ok;
+};
+
+/* Use a tiny initial size.  If a traversal encounters more than
+   a few devices, the cost of growing/rehashing this table will be
+   rendered negligible by the number of inodes processed.  */
+enum { LCO_HT_INITIAL_SIZE = 13 };
+
+static size_t
+LCO_hash (void const *x, size_t table_size)
+{
+  struct LCO_ent const *ax = x;
+  return (uintmax_t) ax->st_dev % table_size;
+}
+
+static bool
+LCO_compare (void const *x, void const *y)
+{
+  struct LCO_ent const *ax = x;
+  struct LCO_ent const *ay = y;
+  return ax->st_dev == ay->st_dev;
+}
+
+/* Ask the same question as leaf_optimization_applies, but query
+   the cache first (FTS.fts_leaf_optimization_works_ht), and if necessary,
+   update that cache.  */
+static bool
+link_count_optimize_ok (FTSENT const *p)
+{
+  FTS *sp = p->fts_fts;
+  Hash_table *h = sp->fts_leaf_optimization_works_ht;
+  struct LCO_ent tmp;
+  struct LCO_ent *ent;
+  bool opt_ok;
+  struct LCO_ent *t2;
+
+  /* If we're not in CWDFD mode, don't bother with this optimization,
+     since the caller is not serious about performance. */
+  if (!ISSET(FTS_CWDFD))
+    return false;
+
+  /* map st_dev to the boolean, leaf_optimization_works */
+  if (h == NULL)
+    {
+      h = sp->fts_leaf_optimization_works_ht
+        = hash_initialize (LCO_HT_INITIAL_SIZE, NULL, LCO_hash,
+                           LCO_compare, free);
+      if (h == NULL)
+        return false;
+    }
+  tmp.st_dev = p->fts_statp->st_dev;
+  ent = hash_lookup (h, &tmp);
+  if (ent)
+    return ent->opt_ok;
+
+  /* Look-up failed.  Query directly and cache the result.  */
+  t2 = malloc (sizeof *t2);
+  if (t2 == NULL)
+    return false;
+
+  /* Is it ok to perform the optimization in the dir, FTS_CWD_FD?  */
+  opt_ok = leaf_optimization_applies (sp->fts_cwd_fd);
+  t2->opt_ok = opt_ok;
+  t2->st_dev = p->fts_statp->st_dev;
+
+  ent = hash_insert (h, t2);
+  if (ent == NULL)
+    {
+      /* insertion failed */
+      free (t2);
+      return false;
+    }
+  fts_assert (ent == t2);
+
+  return opt_ok;
+}
+
+/*
+ * Special case of "/" at the end of the file name so that slashes aren't
+ * appended which would cause file names to be written as "....//foo".
+ */
+#define NAPPEND(p)                                                      \
+        (p->fts_path[p->fts_pathlen - 1] == '/'                         \
+            ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+FTSENT *
+fts_read (register FTS *sp)
+{
+        register FTSENT *p, *tmp;
+        register unsigned short int instr;
+        register char *t;
+
+        /* If finished or unrecoverable error, return NULL. */
+        if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+                return (NULL);
+
+        /* Set current node pointer. */
+        p = sp->fts_cur;
+
+        /* Save and zero out user instructions. */
+        instr = p->fts_instr;
+        p->fts_instr = FTS_NOINSTR;
+
+        /* Any type of file may be re-visited; re-stat and re-turn. */
+        if (instr == FTS_AGAIN) {
+                p->fts_info = fts_stat(sp, p, false);
+                return (p);
+        }
+        Dprintf (("fts_read: p=%s\n",
+                  p->fts_info == FTS_INIT ? "" : p->fts_path));
+
+        /*
+         * Following a symlink -- SLNONE test allows application to see
+         * SLNONE and recover.  If indirecting through a symlink, have
+         * keep a pointer to current location.  If unable to get that
+         * pointer, follow fails.
+         */
+        if (instr == FTS_FOLLOW &&
+            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+                p->fts_info = fts_stat(sp, p, true);
+                if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+                        if ((p->fts_symfd = diropen (sp, ".")) < 0) {
+                                p->fts_errno = errno;
+                                p->fts_info = FTS_ERR;
+                        } else
+                                p->fts_flags |= FTS_SYMFOLLOW;
+                }
+                goto check_for_dir;
+        }
+
+        /* Directory in pre-order. */
+        if (p->fts_info == FTS_D) {
+                /* If skipped or crossed mount point, do post-order visit. */
+                if (instr == FTS_SKIP ||
+                    (ISSET(FTS_XDEV) && p->fts_statp->st_dev != sp->fts_dev)) {
+                        if (p->fts_flags & FTS_SYMFOLLOW)
+                                (void)close(p->fts_symfd);
+                        if (sp->fts_child) {
+                                fts_lfree(sp->fts_child);
+                                sp->fts_child = NULL;
+                        }
+                        p->fts_info = FTS_DP;
+                        LEAVE_DIR (sp, p, "1");
+                        return (p);
+                }
+
+                /* Rebuild if only read the names and now traversing. */
+                if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
+                        CLR(FTS_NAMEONLY);
+                        fts_lfree(sp->fts_child);
+                        sp->fts_child = NULL;
+                }
+
+                /*
+                 * Cd to the subdirectory.
+                 *
+                 * If have already read and now fail to chdir, whack the list
+                 * to make the names come out right, and set the parent errno
+                 * so the application will eventually get an error condition.
+                 * Set the FTS_DONTCHDIR flag so that when we logically change
+                 * directories back to the parent we don't do a chdir.
+                 *
+                 * If haven't read do so.  If the read fails, fts_build sets
+                 * FTS_STOP or the fts_info field of the node.
+                 */
+                if (sp->fts_child != NULL) {
+                        if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
+                                p->fts_errno = errno;
+                                p->fts_flags |= FTS_DONTCHDIR;
+                                for (p = sp->fts_child; p != NULL;
+                                     p = p->fts_link)
+                                        p->fts_accpath =
+                                            p->fts_parent->fts_accpath;
+                        }
+                } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+                        if (ISSET(FTS_STOP))
+                                return (NULL);
+                        /* If fts_build's call to fts_safe_changedir failed
+                           because it was not able to fchdir into a
+                           subdirectory, tell the caller.  */
+                        if (p->fts_errno && p->fts_info != FTS_DNR)
+                                p->fts_info = FTS_ERR;
+                        LEAVE_DIR (sp, p, "2");
+                        return (p);
+                }
+                p = sp->fts_child;
+                sp->fts_child = NULL;
+                goto name;
+        }
+
+        /* Move to the next node on this level. */
+next:   tmp = p;
+
+        /* If we have so many directory entries that we're reading them
+           in batches, and we've reached the end of the current batch,
+           read in a new batch.  */
+        if (p->fts_link == NULL && p->fts_parent->fts_dirp)
+          {
+            p = tmp->fts_parent;
+            sp->fts_cur = p;
+            sp->fts_path[p->fts_pathlen] = '\0';
+
+            if ((p = fts_build (sp, BREAD)) == NULL)
+              {
+                if (ISSET(FTS_STOP))
+                  return NULL;
+                goto cd_dot_dot;
+              }
+
+            free(tmp);
+            goto name;
+          }
+
+        if ((p = p->fts_link) != NULL) {
+                sp->fts_cur = p;
+                free(tmp);
+
+                /*
+                 * If reached the top, return to the original directory (or
+                 * the root of the tree), and load the file names for the next
+                 * root.
+                 */
+                if (p->fts_level == FTS_ROOTLEVEL) {
+                        if (restore_initial_cwd(sp)) {
+                                SET(FTS_STOP);
+                                return (NULL);
+                        }
+                        free_dir(sp);
+                        fts_load(sp, p);
+                        setup_dir(sp);
+                        goto check_for_dir;
+                }
+
+                /*
+                 * User may have called fts_set on the node.  If skipped,
+                 * ignore.  If followed, get a file descriptor so we can
+                 * get back if necessary.
+                 */
+                if (p->fts_instr == FTS_SKIP)
+                        goto next;
+                if (p->fts_instr == FTS_FOLLOW) {
+                        p->fts_info = fts_stat(sp, p, true);
+                        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+                                if ((p->fts_symfd = diropen (sp, ".")) < 0) {
+                                        p->fts_errno = errno;
+                                        p->fts_info = FTS_ERR;
+                                } else
+                                        p->fts_flags |= FTS_SYMFOLLOW;
+                        }
+                        p->fts_instr = FTS_NOINSTR;
+                }
+
+name:           t = sp->fts_path + NAPPEND(p->fts_parent);
+                *t++ = '/';
+                memmove(t, p->fts_name, p->fts_namelen + 1);
+check_for_dir:
+                sp->fts_cur = p;
+                if (p->fts_info == FTS_NSOK)
+                  {
+                    if (p->fts_statp->st_size == FTS_STAT_REQUIRED)
+                      {
+                        FTSENT *parent = p->fts_parent;
+                        if (FTS_ROOTLEVEL < p->fts_level
+                            /* ->fts_n_dirs_remaining is not valid
+                               for command-line-specified names.  */
+                            && parent->fts_n_dirs_remaining == 0
+                            && ISSET(FTS_NOSTAT)
+                            && ISSET(FTS_PHYSICAL)
+                            && link_count_optimize_ok (parent))
+                          {
+                            /* nothing more needed */
+                          }
+                        else
+                          {
+                            p->fts_info = fts_stat(sp, p, false);
+                            if (S_ISDIR(p->fts_statp->st_mode)
+                                && p->fts_level != FTS_ROOTLEVEL
+                                && parent->fts_n_dirs_remaining)
+                                  parent->fts_n_dirs_remaining--;
+                          }
+                      }
+                    else
+                      fts_assert (p->fts_statp->st_size == FTS_NO_STAT_REQUIRED);
+                  }
+
+                if (p->fts_info == FTS_D)
+                  {
+                    /* Now that P->fts_statp is guaranteed to be valid,
+                       if this is a command-line directory, record its
+                       device number, to be used for FTS_XDEV.  */
+                    if (p->fts_level == FTS_ROOTLEVEL)
+                      sp->fts_dev = p->fts_statp->st_dev;
+                    Dprintf (("  entering: %s\n", p->fts_path));
+                    if (! enter_dir (sp, p))
+                      {
+                        __set_errno (ENOMEM);
+                        return NULL;
+                      }
+                  }
+                return p;
+        }
+cd_dot_dot:
+
+        /* Move up to the parent node. */
+        p = tmp->fts_parent;
+        sp->fts_cur = p;
+        free(tmp);
+
+        if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+                /*
+                 * Done; free everything up and set errno to 0 so the user
+                 * can distinguish between error and EOF.
+                 */
+                free(p);
+                __set_errno (0);
+                return (sp->fts_cur = NULL);
+        }
+
+        fts_assert (p->fts_info != FTS_NSOK);
+
+        /* NUL terminate the file name.  */
+        sp->fts_path[p->fts_pathlen] = '\0';
+
+        /*
+         * Return to the parent directory.  If at a root node, restore
+         * the initial working directory.  If we came through a symlink,
+         * go back through the file descriptor.  Otherwise, move up
+         * one level, via "..".
+         */
+        if (p->fts_level == FTS_ROOTLEVEL) {
+                if (restore_initial_cwd(sp)) {
+                        p->fts_errno = errno;
+                        SET(FTS_STOP);
+                }
+        } else if (p->fts_flags & FTS_SYMFOLLOW) {
+                if (FCHDIR(sp, p->fts_symfd)) {
+                        int saved_errno = errno;
+                        (void)close(p->fts_symfd);
+                        __set_errno (saved_errno);
+                        p->fts_errno = errno;
+                        SET(FTS_STOP);
+                }
+                (void)close(p->fts_symfd);
+        } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
+                   fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+                p->fts_errno = errno;
+                SET(FTS_STOP);
+        }
+        p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+        if (p->fts_errno == 0)
+                LEAVE_DIR (sp, p, "3");
+        return ISSET(FTS_STOP) ? NULL : p;
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set.  An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int
+fts_set(FTS *sp _GL_UNUSED, FTSENT *p, int instr)
+{
+        if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+            instr != FTS_NOINSTR && instr != FTS_SKIP) {
+                __set_errno (EINVAL);
+                return (1);
+        }
+        p->fts_instr = instr;
+        return (0);
+}
+
+FTSENT *
+fts_children (register FTS *sp, int instr)
+{
+        register FTSENT *p;
+        int fd;
+
+        if (instr != 0 && instr != FTS_NAMEONLY) {
+                __set_errno (EINVAL);
+                return (NULL);
+        }
+
+        /* Set current node pointer. */
+        p = sp->fts_cur;
+
+        /*
+         * Errno set to 0 so user can distinguish empty directory from
+         * an error.
+         */
+        __set_errno (0);
+
+        /* Fatal errors stop here. */
+        if (ISSET(FTS_STOP))
+                return (NULL);
+
+        /* Return logical hierarchy of user's arguments. */
+        if (p->fts_info == FTS_INIT)
+                return (p->fts_link);
+
+        /*
+         * If not a directory being visited in pre-order, stop here.  Could
+         * allow FTS_DNR, assuming the user has fixed the problem, but the
+         * same effect is available with FTS_AGAIN.
+         */
+        if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+                return (NULL);
+
+        /* Free up any previous child list. */
+        if (sp->fts_child != NULL)
+                fts_lfree(sp->fts_child);
+
+        if (instr == FTS_NAMEONLY) {
+                SET(FTS_NAMEONLY);
+                instr = BNAMES;
+        } else
+                instr = BCHILD;
+
+        /*
+         * If using chdir on a relative file name and called BEFORE fts_read
+         * does its chdir to the root of a traversal, we can lose -- we need to
+         * chdir into the subdirectory, and we don't know where the current
+         * directory is, so we can't get back so that the upcoming chdir by
+         * fts_read will work.
+         */
+        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
+            ISSET(FTS_NOCHDIR))
+                return (sp->fts_child = fts_build(sp, instr));
+
+        if ((fd = diropen (sp, ".")) < 0)
+                return (sp->fts_child = NULL);
+        sp->fts_child = fts_build(sp, instr);
+        if (ISSET(FTS_CWDFD))
+          {
+            cwd_advance_fd (sp, fd, true);
+          }
+        else
+          {
+            if (fchdir(fd))
+              {
+                int saved_errno = errno;
+                close (fd);
+                __set_errno (saved_errno);
+                return NULL;
+              }
+            close (fd);
+          }
+        return (sp->fts_child);
+}
+
+/* A comparison function to sort on increasing inode number.
+   For some file system types, sorting either way makes a huge
+   performance difference for a directory with very many entries,
+   but sorting on increasing values is slightly better than sorting
+   on decreasing values.  The difference is in the 5% range.  */
+static int
+fts_compare_ino (struct _ftsent const **a, struct _ftsent const **b)
+{
+  return (a[0]->fts_statp->st_ino < b[0]->fts_statp->st_ino ? -1
+          : b[0]->fts_statp->st_ino < a[0]->fts_statp->st_ino ? 1 : 0);
+}
+
+/* Map the dirent.d_type value, DTYPE, to the corresponding stat.st_mode
+   S_IF* bit and set ST.st_mode, thus clearing all other bits in that field.  */
+static void
+set_stat_type (struct stat *st, unsigned int dtype)
+{
+  mode_t type;
+  switch (dtype)
+    {
+    case DT_BLK:
+      type = S_IFBLK;
+      break;
+    case DT_CHR:
+      type = S_IFCHR;
+      break;
+    case DT_DIR:
+      type = S_IFDIR;
+      break;
+    case DT_FIFO:
+      type = S_IFIFO;
+      break;
+    case DT_LNK:
+      type = S_IFLNK;
+      break;
+    case DT_REG:
+      type = S_IFREG;
+      break;
+    case DT_SOCK:
+      type = S_IFSOCK;
+      break;
+    default:
+      type = 0;
+    }
+  st->st_mode = type;
+}
+
+#define closedir_and_clear(dirp)                \
+  do                                            \
+    {                                           \
+      closedir (dirp);                          \
+      dirp = NULL;                              \
+    }                                           \
+  while (0)
+
+#define fts_opendir(file, Pdir_fd)                              \
+        opendirat((! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD)     \
+                   ? sp->fts_cwd_fd : AT_FDCWD),                \
+                  file,                                         \
+                  (((ISSET(FTS_PHYSICAL)                        \
+                     && ! (ISSET(FTS_COMFOLLOW)                 \
+                           && cur->fts_level == FTS_ROOTLEVEL)) \
+                    ? O_NOFOLLOW : 0)                           \
+                   | (ISSET (FTS_NOATIME) ? O_NOATIME : 0)),    \
+                  Pdir_fd)
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here.  The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read.  There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly.  First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry.  Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls.  The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ */
+static FTSENT *
+internal_function
+fts_build (register FTS *sp, int type)
+{
+        register FTSENT *p, *head;
+        register size_t nitems;
+        FTSENT *tail;
+        void *oldaddr;
+        int saved_errno;
+        bool descend;
+        bool doadjust;
+        ptrdiff_t level;
+        nlink_t nlinks;
+        bool nostat;
+        size_t len, maxlen, new_len;
+        char *cp;
+        int dir_fd;
+        FTSENT *cur = sp->fts_cur;
+        bool continue_readdir = !!cur->fts_dirp;
+
+        /* When cur->fts_dirp is non-NULL, that means we should
+           continue calling readdir on that existing DIR* pointer
+           rather than opening a new one.  */
+        if (continue_readdir)
+          {
+            DIR *dp = cur->fts_dirp;
+            dir_fd = dirfd (dp);
+            if (dir_fd < 0)
+              {
+                closedir_and_clear (cur->fts_dirp);
+                if (type == BREAD)
+                  {
+                    cur->fts_info = FTS_DNR;
+                    cur->fts_errno = errno;
+                  }
+                return NULL;
+              }
+          }
+        else
+          {
+            /* Open the directory for reading.  If this fails, we're done.
+               If being called from fts_read, set the fts_info field. */
+            if ((cur->fts_dirp = fts_opendir(cur->fts_accpath, &dir_fd)) == NULL)
+              {
+                if (type == BREAD)
+                  {
+                    cur->fts_info = FTS_DNR;
+                    cur->fts_errno = errno;
+                  }
+                return NULL;
+              }
+            /* Rather than calling fts_stat for each and every entry encountered
+               in the readdir loop (below), stat each directory only right after
+               opening it.  */
+            if (cur->fts_info == FTS_NSOK)
+              cur->fts_info = fts_stat(sp, cur, false);
+            else if (sp->fts_options & FTS_TIGHT_CYCLE_CHECK)
+              {
+                /* Now read the stat info again after opening a directory to
+                   reveal eventual changes caused by a submount triggered by
+                   the traversal.  But do it only for utilities which use
+                   FTS_TIGHT_CYCLE_CHECK.  Therefore, only find and du
+                   benefit/suffer from this feature for now.  */
+                LEAVE_DIR (sp, cur, "4");
+                fts_stat (sp, cur, false);
+                if (! enter_dir (sp, cur))
+                  {
+                    __set_errno (ENOMEM);
+                    return NULL;
+                  }
+              }
+          }
+
+        /* Maximum number of readdir entries to read at one time.  This
+           limitation is to avoid reading millions of entries into memory
+           at once.  When an fts_compar function is specified, we have no
+           choice: we must read all entries into memory before calling that
+           function.  But when no such function is specified, we can read
+           entries in batches that are large enough to help us with inode-
+           sorting, yet not so large that we risk exhausting memory.  */
+        size_t max_entries = (sp->fts_compar == NULL
+                              ? FTS_MAX_READDIR_ENTRIES : SIZE_MAX);
+
+        /*
+         * Nlinks is the number of possible entries of type directory in the
+         * directory if we're cheating on stat calls, 0 if we're not doing
+         * any stat calls at all, (nlink_t) -1 if we're statting everything.
+         */
+        if (type == BNAMES) {
+                nlinks = 0;
+                /* Be quiet about nostat, GCC. */
+                nostat = false;
+        } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
+                nlinks = (cur->fts_statp->st_nlink
+                          - (ISSET(FTS_SEEDOT) ? 0 : 2));
+                nostat = true;
+        } else {
+                nlinks = -1;
+                nostat = false;
+        }
+
+        /*
+         * If we're going to need to stat anything or we want to descend
+         * and stay in the directory, chdir.  If this fails we keep going,
+         * but set a flag so we don't chdir after the post-order visit.
+         * We won't be able to stat anything, but we can still return the
+         * names themselves.  Note, that since fts_read won't be able to
+         * chdir into the directory, it will have to return different file
+         * names than before, i.e. "a/b" instead of "b".  Since the node
+         * has already been visited in pre-order, have to wait until the
+         * post-order visit to return the error.  There is a special case
+         * here, if there was nothing to stat then it's not an error to
+         * not be able to stat.  This is all fairly nasty.  If a program
+         * needed sorted entries or stat information, they had better be
+         * checking FTS_NS on the returned nodes.
+         */
+        if (continue_readdir)
+          {
+            /* When resuming a short readdir run, we already have
+               the required dirp and dir_fd.  */
+            descend = true;
+          }
+        else if (nlinks || type == BREAD) {
+                if (ISSET(FTS_CWDFD))
+                  {
+                    dir_fd = dup (dir_fd);
+                    if (0 <= dir_fd)
+                      set_cloexec_flag (dir_fd, true);
+                  }
+                if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) {
+                        if (nlinks && type == BREAD)
+                                cur->fts_errno = errno;
+                        cur->fts_flags |= FTS_DONTCHDIR;
+                        descend = false;
+                        closedir_and_clear(cur->fts_dirp);
+                        if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
+                                close (dir_fd);
+                        cur->fts_dirp = NULL;
+                } else
+                        descend = true;
+        } else
+                descend = false;
+
+        /*
+         * Figure out the max file name length that can be stored in the
+         * current buffer -- the inner loop allocates more space as necessary.
+         * We really wouldn't have to do the maxlen calculations here, we
+         * could do them in fts_read before returning the name, but it's a
+         * lot easier here since the length is part of the dirent structure.
+         *
+         * If not changing directories set a pointer so that can just append
+         * each new component into the file name.
+         */
+        len = NAPPEND(cur);
+        if (ISSET(FTS_NOCHDIR)) {
+                cp = sp->fts_path + len;
+                *cp++ = '/';
+        } else {
+                /* GCC, you're too verbose. */
+                cp = NULL;
+        }
+        len++;
+        maxlen = sp->fts_pathlen - len;
+
+        level = cur->fts_level + 1;
+
+        /* Read the directory, attaching each entry to the "link" pointer. */
+        doadjust = false;
+        head = NULL;
+        tail = NULL;
+        nitems = 0;
+        while (cur->fts_dirp) {
+                bool is_dir;
+                struct dirent *dp = readdir(cur->fts_dirp);
+                if (dp == NULL)
+                        break;
+                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+                        continue;
+
+                if ((p = fts_alloc (sp, dp->d_name,
+                                    _D_EXACT_NAMLEN (dp))) == NULL)
+                        goto mem1;
+                if (_D_EXACT_NAMLEN (dp) >= maxlen) {
+                        /* include space for NUL */
+                        oldaddr = sp->fts_path;
+                        if (! fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
+                                /*
+                                 * No more memory.  Save
+                                 * errno, free up the current structure and the
+                                 * structures already allocated.
+                                 */
+mem1:                           saved_errno = errno;
+                                free(p);
+                                fts_lfree(head);
+                                closedir_and_clear(cur->fts_dirp);
+                                cur->fts_info = FTS_ERR;
+                                SET(FTS_STOP);
+                                __set_errno (saved_errno);
+                                return (NULL);
+                        }
+                        /* Did realloc() change the pointer? */
+                        if (oldaddr != sp->fts_path) {
+                                doadjust = true;
+                                if (ISSET(FTS_NOCHDIR))
+                                        cp = sp->fts_path + len;
+                        }
+                        maxlen = sp->fts_pathlen - len;
+                }
+
+                new_len = len + _D_EXACT_NAMLEN (dp);
+                if (new_len < len) {
+                        /*
+                         * In the unlikely event that we would end up
+                         * with a file name longer than SIZE_MAX, free up
+                         * the current structure and the structures already
+                         * allocated, then error out with ENAMETOOLONG.
+                         */
+                        free(p);
+                        fts_lfree(head);
+                        closedir_and_clear(cur->fts_dirp);
+                        cur->fts_info = FTS_ERR;
+                        SET(FTS_STOP);
+                        __set_errno (ENAMETOOLONG);
+                        return (NULL);
+                }
+                p->fts_level = level;
+                p->fts_parent = sp->fts_cur;
+                p->fts_pathlen = new_len;
+
+                /* Store dirent.d_ino, in case we need to sort
+                   entries before processing them.  */
+                p->fts_statp->st_ino = D_INO (dp);
+
+                /* Build a file name for fts_stat to stat. */
+                if (ISSET(FTS_NOCHDIR)) {
+                        p->fts_accpath = p->fts_path;
+                        memmove(cp, p->fts_name, p->fts_namelen + 1);
+                } else
+                        p->fts_accpath = p->fts_name;
+
+                if (sp->fts_compar == NULL || ISSET(FTS_DEFER_STAT)) {
+                        /* Record what fts_read will have to do with this
+                           entry. In many cases, it will simply fts_stat it,
+                           but we can take advantage of any d_type information
+                           to optimize away the unnecessary stat calls.  I.e.,
+                           if FTS_NOSTAT is in effect and we're not following
+                           symlinks (FTS_PHYSICAL) and d_type indicates this
+                           is *not* a directory, then we won't have to stat it
+                           at all.  If it *is* a directory, then (currently)
+                           we stat it regardless, in order to get device and
+                           inode numbers.  Some day we might optimize that
+                           away, too, for directories where d_ino is known to
+                           be valid.  */
+                        bool skip_stat = (ISSET(FTS_PHYSICAL)
+                                          && ISSET(FTS_NOSTAT)
+                                          && DT_IS_KNOWN(dp)
+                                          && ! DT_MUST_BE(dp, DT_DIR));
+                        p->fts_info = FTS_NSOK;
+                        /* Propagate dirent.d_type information back
+                           to caller, when possible.  */
+                        set_stat_type (p->fts_statp, D_TYPE (dp));
+                        fts_set_stat_required(p, !skip_stat);
+                        is_dir = (ISSET(FTS_PHYSICAL)
+                                  && DT_MUST_BE(dp, DT_DIR));
+                } else {
+                        p->fts_info = fts_stat(sp, p, false);
+                        is_dir = (p->fts_info == FTS_D
+                                  || p->fts_info == FTS_DC
+                                  || p->fts_info == FTS_DOT);
+                }
+
+                /* Decrement link count if applicable. */
+                if (nlinks > 0 && is_dir)
+                        nlinks -= nostat;
+
+                /* We walk in directory order so "ls -f" doesn't get upset. */
+                p->fts_link = NULL;
+                if (head == NULL)
+                        head = tail = p;
+                else {
+                        tail->fts_link = p;
+                        tail = p;
+                }
+                ++nitems;
+                if (max_entries <= nitems) {
+                        /* When there are too many dir entries, leave
+                           fts_dirp open, so that a subsequent fts_read
+                           can take up where we leave off.  */
+                        goto break_without_closedir;
+                }
+        }
+
+        if (cur->fts_dirp)
+                closedir_and_clear(cur->fts_dirp);
+
+ break_without_closedir:
+
+        /*
+         * If realloc() changed the address of the file name, adjust the
+         * addresses for the rest of the tree and the dir list.
+         */
+        if (doadjust)
+                fts_padjust(sp, head);
+
+        /*
+         * If not changing directories, reset the file name back to original
+         * state.
+         */
+        if (ISSET(FTS_NOCHDIR)) {
+                if (len == sp->fts_pathlen || nitems == 0)
+                        --cp;
+                *cp = '\0';
+        }
+
+        /*
+         * If descended after called from fts_children or after called from
+         * fts_read and nothing found, get back.  At the root level we use
+         * the saved fd; if one of fts_open()'s arguments is a relative name
+         * to an empty directory, we wind up here with no other way back.  If
+         * can't get back, we're done.
+         */
+        if (!continue_readdir && descend && (type == BCHILD || !nitems) &&
+            (cur->fts_level == FTS_ROOTLEVEL
+             ? restore_initial_cwd(sp)
+             : fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+                cur->fts_info = FTS_ERR;
+                SET(FTS_STOP);
+                fts_lfree(head);
+                return (NULL);
+        }
+
+        /* If didn't find anything, return NULL. */
+        if (!nitems) {
+                if (type == BREAD)
+                        cur->fts_info = FTS_DP;
+                fts_lfree(head);
+                return (NULL);
+        }
+
+        /* If there are many entries, no sorting function has been specified,
+           and this file system is of a type that may be slow with a large
+           number of entries, then sort the directory entries on increasing
+           inode numbers.  */
+        if (nitems > _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
+            && !sp->fts_compar
+            && ISSET (FTS_CWDFD)
+            && dirent_inode_sort_may_be_useful (sp->fts_cwd_fd)) {
+                sp->fts_compar = fts_compare_ino;
+                head = fts_sort (sp, head, nitems);
+                sp->fts_compar = NULL;
+        }
+
+        /* Sort the entries. */
+        if (sp->fts_compar && nitems > 1)
+                head = fts_sort(sp, head, nitems);
+        return (head);
+}
+
+#if FTS_DEBUG
+
+/* Walk ->fts_parent links starting at E_CURR, until the root of the
+   current hierarchy.  There should be a directory with dev/inode
+   matching those of AD.  If not, print a lot of diagnostics.  */
+static void
+find_matching_ancestor (FTSENT const *e_curr, struct Active_dir const *ad)
+{
+  FTSENT const *ent;
+  for (ent = e_curr; ent->fts_level >= FTS_ROOTLEVEL; ent = ent->fts_parent)
+    {
+      if (ad->ino == ent->fts_statp->st_ino
+          && ad->dev == ent->fts_statp->st_dev)
+        return;
+    }
+  printf ("ERROR: tree dir, %s, not active\n", ad->fts_ent->fts_accpath);
+  printf ("active dirs:\n");
+  for (ent = e_curr;
+       ent->fts_level >= FTS_ROOTLEVEL; ent = ent->fts_parent)
+    printf ("  %s(%"PRIuMAX"/%"PRIuMAX") to %s(%"PRIuMAX"/%"PRIuMAX")...\n",
+            ad->fts_ent->fts_accpath,
+            (uintmax_t) ad->dev,
+            (uintmax_t) ad->ino,
+            ent->fts_accpath,
+            (uintmax_t) ent->fts_statp->st_dev,
+            (uintmax_t) ent->fts_statp->st_ino);
+}
+
+void
+fts_cross_check (FTS const *sp)
+{
+  FTSENT const *ent = sp->fts_cur;
+  FTSENT const *t;
+  if ( ! ISSET (FTS_TIGHT_CYCLE_CHECK))
+    return;
+
+  Dprintf (("fts-cross-check cur=%s\n", ent->fts_path));
+  /* Make sure every parent dir is in the tree.  */
+  for (t = ent->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+    {
+      struct Active_dir ad;
+      ad.ino = t->fts_statp->st_ino;
+      ad.dev = t->fts_statp->st_dev;
+      if ( ! hash_lookup (sp->fts_cycle.ht, &ad))
+        printf ("ERROR: active dir, %s, not in tree\n", t->fts_path);
+    }
+
+  /* Make sure every dir in the tree is an active dir.
+     But ENT is not necessarily a directory.  If so, just skip this part. */
+  if (ent->fts_parent->fts_level >= FTS_ROOTLEVEL
+      && (ent->fts_info == FTS_DP
+          || ent->fts_info == FTS_D))
+    {
+      struct Active_dir *ad;
+      for (ad = hash_get_first (sp->fts_cycle.ht); ad != NULL;
+           ad = hash_get_next (sp->fts_cycle.ht, ad))
+        {
+          find_matching_ancestor (ent, ad);
+        }
+    }
+}
+
+static bool
+same_fd (int fd1, int fd2)
+{
+  struct stat sb1, sb2;
+  return (fstat (fd1, &sb1) == 0
+          && fstat (fd2, &sb2) == 0
+          && SAME_INODE (sb1, sb2));
+}
+
+static void
+fd_ring_print (FTS const *sp, FILE *stream, char const *msg)
+{
+  I_ring const *fd_ring = &sp->fts_fd_ring;
+  unsigned int i = fd_ring->fts_front;
+  char *cwd = getcwdat (sp->fts_cwd_fd, NULL, 0);
+  fprintf (stream, "=== %s ========== %s\n", msg, cwd);
+  free (cwd);
+  if (i_ring_empty (fd_ring))
+    return;
+
+  while (true)
+    {
+      int fd = fd_ring->fts_fd_ring[i];
+      if (fd < 0)
+        fprintf (stream, "%d: %d:\n", i, fd);
+      else
+        {
+          char *wd = getcwdat (fd, NULL, 0);
+          fprintf (stream, "%d: %d: %s\n", i, fd, wd);
+          free (wd);
+        }
+      if (i == fd_ring->fts_back)
+        break;
+      i = (i + I_RING_SIZE - 1) % I_RING_SIZE;
+    }
+}
+
+/* Ensure that each file descriptor on the fd_ring matches a
+   parent, grandparent, etc. of the current working directory.  */
+static void
+fd_ring_check (FTS const *sp)
+{
+  if (!fts_debug)
+    return;
+
+  /* Make a writable copy.  */
+  I_ring fd_w = sp->fts_fd_ring;
+
+  int cwd_fd = sp->fts_cwd_fd;
+  cwd_fd = dup (cwd_fd);
+  char *dot = getcwdat (cwd_fd, NULL, 0);
+  error (0, 0, "===== check ===== cwd: %s", dot);
+  free (dot);
+  while ( ! i_ring_empty (&fd_w))
+    {
+      int fd = i_ring_pop (&fd_w);
+      if (0 <= fd)
+        {
+          int parent_fd = openat (cwd_fd, "..", O_SEARCH | O_NOATIME);
+          if (parent_fd < 0)
+            {
+              // Warn?
+              break;
+            }
+          if (!same_fd (fd, parent_fd))
+            {
+              char *cwd = getcwdat (fd, NULL, 0);
+              error (0, errno, "ring  : %s", cwd);
+              char *c2 = getcwdat (parent_fd, NULL, 0);
+              error (0, errno, "parent: %s", c2);
+              free (cwd);
+              free (c2);
+              fts_assert (0);
+            }
+          close (cwd_fd);
+          cwd_fd = parent_fd;
+        }
+    }
+  close (cwd_fd);
+}
+#endif
+
+static unsigned short int
+internal_function
+fts_stat(FTS *sp, register FTSENT *p, bool follow)
+{
+        struct stat *sbp = p->fts_statp;
+        int saved_errno;
+
+        if (p->fts_level == FTS_ROOTLEVEL && ISSET(FTS_COMFOLLOW))
+                follow = true;
+
+        /*
+         * If doing a logical walk, or application requested FTS_FOLLOW, do
+         * a stat(2).  If that fails, check for a non-existent symlink.  If
+         * fail, set the errno from the stat call.
+         */
+        if (ISSET(FTS_LOGICAL) || follow) {
+                if (stat(p->fts_accpath, sbp)) {
+                        saved_errno = errno;
+                        if (errno == ENOENT
+                            && lstat(p->fts_accpath, sbp) == 0) {
+                                __set_errno (0);
+                                return (FTS_SLNONE);
+                        }
+                        p->fts_errno = saved_errno;
+                        goto err;
+                }
+        } else if (fstatat(sp->fts_cwd_fd, p->fts_accpath, sbp,
+                           AT_SYMLINK_NOFOLLOW)) {
+                p->fts_errno = errno;
+err:            memset(sbp, 0, sizeof(struct stat));
+                return (FTS_NS);
+        }
+
+        if (S_ISDIR(sbp->st_mode)) {
+                p->fts_n_dirs_remaining = (sbp->st_nlink
+                                           - (ISSET(FTS_SEEDOT) ? 0 : 2));
+                if (ISDOT(p->fts_name)) {
+                        /* Command-line "." and ".." are real directories. */
+                        return (p->fts_level == FTS_ROOTLEVEL ? FTS_D : FTS_DOT);
+                }
+
+                return (FTS_D);
+        }
+        if (S_ISLNK(sbp->st_mode))
+                return (FTS_SL);
+        if (S_ISREG(sbp->st_mode))
+                return (FTS_F);
+        return (FTS_DEFAULT);
+}
+
+static int
+fts_compar (void const *a, void const *b)
+{
+  /* Convert A and B to the correct types, to pacify the compiler, and
+     for portability to bizarre hosts where "void const *" and "FTSENT
+     const **" differ in runtime representation.  The comparison
+     function cannot modify *a and *b, but there is no compile-time
+     check for this.  */
+  FTSENT const **pa = (FTSENT const **) a;
+  FTSENT const **pb = (FTSENT const **) b;
+  return pa[0]->fts_fts->fts_compar (pa, pb);
+}
+
+static FTSENT *
+internal_function
+fts_sort (FTS *sp, FTSENT *head, register size_t nitems)
+{
+        register FTSENT **ap, *p;
+
+        /* On most modern hosts, void * and FTSENT ** have the same
+           run-time representation, and one can convert sp->fts_compar to
+           the type qsort expects without problem.  Use the heuristic that
+           this is OK if the two pointer types are the same size, and if
+           converting FTSENT ** to long int is the same as converting
+           FTSENT ** to void * and then to long int.  This heuristic isn't
+           valid in general but we don't know of any counterexamples.  */
+        FTSENT *dummy;
+        int (*compare) (void const *, void const *) =
+          ((sizeof &dummy == sizeof (void *)
+            && (long int) &dummy == (long int) (void *) &dummy)
+           ? (int (*) (void const *, void const *)) sp->fts_compar
+           : fts_compar);
+
+        /*
+         * Construct an array of pointers to the structures and call qsort(3).
+         * Reassemble the array in the order returned by qsort.  If unable to
+         * sort for memory reasons, return the directory entries in their