Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_a.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_a.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_a.in (revision 322555) @@ -0,0 +1 @@ +abcd* Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_a.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_a.out =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_a.out (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_a.out (revision 322555) @@ -0,0 +1 @@ +abcd* Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_b.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_b.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_b.in (revision 322555) @@ -0,0 +1,5 @@ +fojeiwuroiuwet +ljfajsljkfabcdddjlfkajlkj +abcaaa +zzzabc + Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_b.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_b.out =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_b.out (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_b.out (revision 322555) @@ -0,0 +1,3 @@ +ljfajsljkfabcdddjlfkajlkj +abcaaa +zzzabc Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_c.out =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_c.out (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_color_c.out (revision 322555) @@ -0,0 +1,3 @@ +ljfajsljkfabcdddjlfkajlkj +abcaaa +zzzabc Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_escmap.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_escmap.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_escmap.in (revision 322555) @@ -0,0 +1 @@ +f.oo Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_escmap.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_f_file_empty.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_f_file_empty.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_f_file_empty.in (revision 322555) @@ -0,0 +1,2 @@ +Fish zebra monkey suits + Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_f_file_empty.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_a.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_a.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_a.in (revision 322555) @@ -0,0 +1 @@ +01:1:01 Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_a.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_a.out =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_a.out (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_a.out (revision 322555) @@ -0,0 +1,3 @@ +0 +: +:0 Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_b.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_b.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_b.in (revision 322555) @@ -0,0 +1 @@ +1:1:01 Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_b.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_b.out =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_b.out (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_b.out (revision 322555) @@ -0,0 +1,2 @@ +: +:0 Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_c.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_c.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_c.in (revision 322555) @@ -0,0 +1 @@ +bla bla Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_c.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_c.out =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_c.out (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_c.out (revision 322555) @@ -0,0 +1,2 @@ +bla +bla Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_d.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_d.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_d.in (revision 322555) @@ -0,0 +1,3 @@ +bla +bla + Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_d.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_e.in =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_e.in (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_e.in (revision 322555) @@ -0,0 +1 @@ +abcdef Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_e.in ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_e.out =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_e.out (nonexistent) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_oflag_zerolen_e.out (revision 322555) @@ -0,0 +1 @@ +ab Index: stable/11/contrib/netbsd-tests/usr.bin/grep/t_grep.sh =================================================================== --- stable/11/contrib/netbsd-tests/usr.bin/grep/t_grep.sh (revision 322554) +++ stable/11/contrib/netbsd-tests/usr.bin/grep/t_grep.sh (revision 322555) @@ -1,248 +1,363 @@ # $NetBSD: t_grep.sh,v 1.3 2017/01/14 20:43:52 christos Exp $ # # Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. # 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. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. # atf_test_case basic basic_head() { atf_set "descr" "Checks basic functionality" } basic_body() { atf_check -o file:"$(atf_get_srcdir)/d_basic.out" -x \ 'jot 10000 | grep 123' } atf_test_case binary binary_head() { atf_set "descr" "Checks handling of binary files" } binary_body() { dd if=/dev/zero count=1 of=test.file echo -n "foobar" >> test.file atf_check -o file:"$(atf_get_srcdir)/d_binary.out" grep foobar test.file } atf_test_case recurse recurse_head() { atf_set "descr" "Checks recursive searching" } recurse_body() { mkdir -p recurse/a/f recurse/d echo -e "cod\ndover sole\nhaddock\nhalibut\npilchard" > recurse/d/fish echo -e "cod\nhaddock\nplaice" > recurse/a/f/favourite-fish atf_check -o file:"$(atf_get_srcdir)/d_recurse.out" -x "grep -r haddock recurse | sort" } atf_test_case recurse_symlink recurse_symlink_head() { atf_set "descr" "Checks symbolic link recursion" } recurse_symlink_body() { mkdir -p test/c/d (cd test/c/d && ln -s ../d .) echo "Test string" > test/c/match atf_check -o file:"$(atf_get_srcdir)/d_recurse_symlink.out" \ -e file:"$(atf_get_srcdir)/d_recurse_symlink.err" \ grep -r string test } atf_test_case word_regexps word_regexps_head() { atf_set "descr" "Checks word-regexps" } word_regexps_body() { atf_check -o file:"$(atf_get_srcdir)/d_word_regexps.out" \ grep -w separated $(atf_get_srcdir)/d_input } atf_test_case begin_end begin_end_head() { atf_set "descr" "Checks handling of line beginnings and ends" } begin_end_body() { atf_check -o file:"$(atf_get_srcdir)/d_begin_end_a.out" \ grep ^Front "$(atf_get_srcdir)/d_input" atf_check -o file:"$(atf_get_srcdir)/d_begin_end_b.out" \ grep ending$ "$(atf_get_srcdir)/d_input" } atf_test_case ignore_case ignore_case_head() { atf_set "descr" "Checks ignore-case option" } ignore_case_body() { atf_check -o file:"$(atf_get_srcdir)/d_ignore_case.out" \ grep -i Upper "$(atf_get_srcdir)/d_input" } atf_test_case invert invert_head() { atf_set "descr" "Checks selecting non-matching lines with -v option" } invert_body() { atf_check -o file:"$(atf_get_srcdir)/d_invert.out" \ grep -v fish "$(atf_get_srcdir)/d_invert.in" } atf_test_case whole_line whole_line_head() { atf_set "descr" "Checks whole-line matching with -x flag" } whole_line_body() { atf_check -o file:"$(atf_get_srcdir)/d_whole_line.out" \ grep -x matchme "$(atf_get_srcdir)/d_input" } atf_test_case negative negative_head() { atf_set "descr" "Checks handling of files with no matches" } negative_body() { atf_check -s ne:0 grep "not a hope in hell" "$(atf_get_srcdir)/d_input" } atf_test_case context context_head() { atf_set "descr" "Checks displaying context with -A, -B and -C flags" } context_body() { cp $(atf_get_srcdir)/d_context_*.* . atf_check -o file:d_context_a.out grep -C2 bamboo d_context_a.in atf_check -o file:d_context_b.out grep -A3 tilt d_context_a.in atf_check -o file:d_context_c.out grep -B4 Whig d_context_a.in atf_check -o file:d_context_d.out grep -C1 pig d_context_a.in d_context_b.in } atf_test_case file_exp file_exp_head() { atf_set "descr" "Checks reading expressions from file" } file_exp_body() { atf_check -o file:"$(atf_get_srcdir)/d_file_exp.out" -x \ 'jot 21 -1 1.00 | grep -f '"$(atf_get_srcdir)"'/d_file_exp.in' } atf_test_case egrep egrep_head() { atf_set "descr" "Checks matching special characters with egrep" } egrep_body() { atf_check -o file:"$(atf_get_srcdir)/d_egrep.out" \ egrep '\?|\*$$' "$(atf_get_srcdir)/d_input" } atf_test_case zgrep zgrep_head() { atf_set "descr" "Checks handling of gzipped files with zgrep" } zgrep_body() { cp "$(atf_get_srcdir)/d_input" . gzip d_input || atf_fail "gzip failed" atf_check -o file:"$(atf_get_srcdir)/d_zgrep.out" zgrep -h line d_input.gz } atf_test_case nonexistent nonexistent_head() { atf_set "descr" "Checks that -s flag suppresses error" \ "messages about nonexistent files" } nonexistent_body() { atf_check -s ne:0 grep -s foobar nonexistent } atf_test_case context2 context2_head() { atf_set "descr" "Checks displaying context with -z flag" } context2_body() { printf "haddock\000cod\000plaice\000" > test1 printf "mackeral\000cod\000crab\000" > test2 atf_check -o file:"$(atf_get_srcdir)/d_context2_a.out" \ grep -z -A1 cod test1 test2 atf_check -o file:"$(atf_get_srcdir)/d_context2_b.out" \ grep -z -B1 cod test1 test2 atf_check -o file:"$(atf_get_srcdir)/d_context2_c.out" \ grep -z -C1 cod test1 test2 } +# Begin FreeBSD +atf_test_case oflag_zerolen +oflag_zerolen_head() +{ + atf_set "descr" "Check behavior of zero-length matches with -o flag (PR 195763)" +} +oflag_zerolen_body() +{ + atf_check -o file:"$(atf_get_srcdir)/d_oflag_zerolen_a.out" \ + grep -Eo '(^|:)0*' "$(atf_get_srcdir)/d_oflag_zerolen_a.in" + atf_check -o file:"$(atf_get_srcdir)/d_oflag_zerolen_b.out" \ + grep -Eo '(^|:)0*' "$(atf_get_srcdir)/d_oflag_zerolen_b.in" + + atf_check -o file:"$(atf_get_srcdir)/d_oflag_zerolen_c.out" \ + grep -Eo '[[:alnum:]]*' "$(atf_get_srcdir)/d_oflag_zerolen_c.in" + + atf_check -o empty grep -Eo '' "$(atf_get_srcdir)/d_oflag_zerolen_d.in" + + atf_check -o file:"$(atf_get_srcdir)/d_oflag_zerolen_e.out" \ + grep -o -e 'ab' -e 'bc' "$(atf_get_srcdir)/d_oflag_zerolen_e.in" + + atf_check -o file:"$(atf_get_srcdir)/d_oflag_zerolen_e.out" \ + grep -o -e 'bc' -e 'ab' "$(atf_get_srcdir)/d_oflag_zerolen_e.in" +} + +atf_test_case xflag +xflag_head() +{ + atf_set "descr" "Check that we actually get a match with -x flag (PR 180990)" +} +xflag_body() +{ + echo 128 > match_file + seq 1 128 > pattern_file + grep -xf pattern_file match_file +} + +atf_test_case color +color_head() +{ + atf_set "descr" "Check --color support" +} +color_body() +{ + echo 'abcd*' > grepfile + echo 'abc$' >> grepfile + echo '^abc' >> grepfile + + atf_check -o file:"$(atf_get_srcdir)/d_color_a.out" \ + grep --color=auto -e '.*' -e 'a' "$(atf_get_srcdir)/d_color_a.in" + + atf_check -o file:"$(atf_get_srcdir)/d_color_b.out" \ + grep --color=auto -f grepfile "$(atf_get_srcdir)/d_color_b.in" + + atf_check -o file:"$(atf_get_srcdir)/d_color_c.out" \ + grep --color=always -f grepfile "$(atf_get_srcdir)/d_color_b.in" +} + +atf_test_case f_file_empty +f_file_empty_head() +{ + atf_set "descr" "Check for handling of a null byte in empty file, specified by -f (PR 202022)" +} +f_file_empty_body() +{ + printf "\0\n" > nulpat + + atf_check -s exit:1 grep -f nulpat "$(atf_get_srcdir)/d_f_file_empty.in" +} + +atf_test_case escmap +escmap_head() +{ + atf_set "descr" "Check proper handling of escaped vs. unescaped dot expressions (PR 175314)" +} +escmap_body() +{ + atf_check -s exit:1 grep -o 'f.o\.' "$(atf_get_srcdir)/d_escmap.in" + atf_check -o not-empty grep -o 'f.o.' "$(atf_get_srcdir)/d_escmap.in" +} + +atf_test_case egrep_empty_invalid +egrep_empty_invalid_head() +{ + atf_set "descr" "Check for handling of an invalid empty pattern (PR 194823)" +} +egrep_empty_invalid_body() +{ + atf_check -s exit:1 egrep '{' /dev/null +} + +atf_test_case zerolen +zerolen_head() +{ + atf_set "descr" "Check for successful zero-length matches with ^$" +} +zerolen_body() +{ + printf "Eggs\n\nCheese" > test1 + + atf_check -o inline:"\n" grep -e "^$" test1 + + atf_check -o inline:"Eggs\nCheese\n" grep -v -e "^$" test1 +} +# End FreeBSD + atf_init_test_cases() { - atf_add_test_case basic + atf_add_test_case basic atf_add_test_case binary atf_add_test_case recurse atf_add_test_case recurse_symlink atf_add_test_case word_regexps atf_add_test_case begin_end atf_add_test_case ignore_case atf_add_test_case invert atf_add_test_case whole_line atf_add_test_case negative atf_add_test_case context atf_add_test_case file_exp atf_add_test_case egrep atf_add_test_case zgrep atf_add_test_case nonexistent atf_add_test_case context2 +# Begin FreeBSD + atf_add_test_case oflag_zerolen + atf_add_test_case xflag + atf_add_test_case color + atf_add_test_case f_file_empty + atf_add_test_case escmap + atf_add_test_case egrep_empty_invalid + atf_add_test_case zerolen +# End FreeBSD } Index: stable/11/usr.bin/grep/tests/Makefile =================================================================== --- stable/11/usr.bin/grep/tests/Makefile (revision 322554) +++ stable/11/usr.bin/grep/tests/Makefile (revision 322555) @@ -1,36 +1,52 @@ # $FreeBSD$ PACKAGE= tests NETBSD_ATF_TESTS_SH= grep_test ${PACKAGE}FILES+= d_basic.out ${PACKAGE}FILES+= d_begin_end_a.out ${PACKAGE}FILES+= d_begin_end_b.out ${PACKAGE}FILES+= d_binary.out +${PACKAGE}FILES+= d_color_a.in +${PACKAGE}FILES+= d_color_a.out +${PACKAGE}FILES+= d_color_b.in +${PACKAGE}FILES+= d_color_b.out +${PACKAGE}FILES+= d_color_c.out ${PACKAGE}FILES+= d_context2_a.out ${PACKAGE}FILES+= d_context2_b.out ${PACKAGE}FILES+= d_context2_c.out ${PACKAGE}FILES+= d_context_a.in ${PACKAGE}FILES+= d_context_a.out ${PACKAGE}FILES+= d_context_b.in ${PACKAGE}FILES+= d_context_b.out ${PACKAGE}FILES+= d_context_c.out ${PACKAGE}FILES+= d_context_d.out ${PACKAGE}FILES+= d_egrep.out +${PACKAGE}FILES+= d_escmap.in +${PACKAGE}FILES+= d_f_file_empty.in ${PACKAGE}FILES+= d_file_exp.in ${PACKAGE}FILES+= d_file_exp.out ${PACKAGE}FILES+= d_ignore_case.out ${PACKAGE}FILES+= d_input ${PACKAGE}FILES+= d_invert.in ${PACKAGE}FILES+= d_invert.out +${PACKAGE}FILES+= d_oflag_zerolen_a.in +${PACKAGE}FILES+= d_oflag_zerolen_a.out +${PACKAGE}FILES+= d_oflag_zerolen_b.in +${PACKAGE}FILES+= d_oflag_zerolen_b.out +${PACKAGE}FILES+= d_oflag_zerolen_c.in +${PACKAGE}FILES+= d_oflag_zerolen_c.out +${PACKAGE}FILES+= d_oflag_zerolen_d.in +${PACKAGE}FILES+= d_oflag_zerolen_e.in +${PACKAGE}FILES+= d_oflag_zerolen_e.out ${PACKAGE}FILES+= d_recurse.out ${PACKAGE}FILES+= d_recurse_symlink.err ${PACKAGE}FILES+= d_recurse_symlink.out ${PACKAGE}FILES+= d_whole_line.out ${PACKAGE}FILES+= d_word_regexps.out ${PACKAGE}FILES+= d_zgrep.out .include .include Index: stable/11/usr.bin/grep/util.c =================================================================== --- stable/11/usr.bin/grep/util.c (revision 322554) +++ stable/11/usr.bin/grep/util.c (revision 322555) @@ -1,492 +1,530 @@ /* $NetBSD: util.c,v 1.9 2011/02/27 17:33:37 joerg Exp $ */ /* $FreeBSD$ */ /* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */ /*- * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav * Copyright (C) 2008-2010 Gabor Kovesdan * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fastmatch.h" #include "grep.h" static int linesqueued; static int procline(struct str *l, int); bool file_matching(const char *fname) { char *fname_base; bool ret; ret = finclude ? false : true; fname_base = basename(fname); for (unsigned int i = 0; i < fpatterns; ++i) { if (fnmatch(fpattern[i].pat, fname, 0) == 0 || fnmatch(fpattern[i].pat, fname_base, 0) == 0) { if (fpattern[i].mode == EXCL_PAT) return (false); else ret = true; } } return (ret); } static inline bool dir_matching(const char *dname) { bool ret; ret = dinclude ? false : true; for (unsigned int i = 0; i < dpatterns; ++i) { if (dname != NULL && fnmatch(dpattern[i].pat, dname, 0) == 0) { if (dpattern[i].mode == EXCL_PAT) return (false); else ret = true; } } return (ret); } /* * Processes a directory when a recursive search is performed with * the -R option. Each appropriate file is passed to procfile(). */ int grep_tree(char **argv) { FTS *fts; FTSENT *p; int c, fts_flags; bool ok; c = fts_flags = 0; switch(linkbehave) { case LINK_EXPLICIT: fts_flags = FTS_COMFOLLOW; break; case LINK_SKIP: fts_flags = FTS_PHYSICAL; break; default: fts_flags = FTS_LOGICAL; } fts_flags |= FTS_NOSTAT | FTS_NOCHDIR; if (!(fts = fts_open(argv, fts_flags, NULL))) err(2, "fts_open"); while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_DNR: /* FALLTHROUGH */ case FTS_ERR: file_err = true; if(!sflag) warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); break; case FTS_D: /* FALLTHROUGH */ case FTS_DP: if (dexclude || dinclude) if (!dir_matching(p->fts_name) || !dir_matching(p->fts_path)) fts_set(fts, p, FTS_SKIP); break; case FTS_DC: /* Print a warning for recursive directory loop */ warnx("warning: %s: recursive directory loop", p->fts_path); break; default: /* Check for file exclusion/inclusion */ ok = true; if (fexclude || finclude) ok &= file_matching(p->fts_path); if (ok) c += procfile(p->fts_path); break; } } fts_close(fts); return (c); } /* * Opens a file and processes it. Each file is processed line-by-line * passing the lines to procline(). */ int procfile(const char *fn) { struct file *f; struct stat sb; struct str ln; mode_t s; int c, t; mcount = mlimit; if (strcmp(fn, "-") == 0) { fn = label != NULL ? label : getstr(1); f = grep_open(NULL); } else { if (!stat(fn, &sb)) { /* Check if we need to process the file */ s = sb.st_mode & S_IFMT; if (s == S_IFDIR && dirbehave == DIR_SKIP) return (0); if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK || s == S_IFSOCK) && devbehave == DEV_SKIP) return (0); } f = grep_open(fn); } if (f == NULL) { file_err = true; if (!sflag) warn("%s", fn); return (0); } ln.file = grep_malloc(strlen(fn) + 1); strcpy(ln.file, fn); ln.line_no = 0; ln.len = 0; linesqueued = 0; tail = 0; ln.off = -1; for (c = 0; c == 0 || !(lflag || qflag); ) { ln.off += ln.len + 1; if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0) { if (ln.line_no == 0 && matchall) exit(0); else break; } if (ln.len > 0 && ln.dat[ln.len - 1] == '\n') --ln.len; ln.line_no++; /* Return if we need to skip a binary file */ if (f->binary && binbehave == BINFILE_SKIP) { grep_close(f); free(ln.file); free(f); return (0); } /* Process the file line-by-line */ if ((t = procline(&ln, f->binary)) == 0 && Bflag > 0) { enqueue(&ln); linesqueued++; } c += t; if (mflag && mcount <= 0) break; } if (Bflag > 0) clearqueue(); grep_close(f); if (cflag) { if (!hflag) printf("%s:", ln.file); printf("%u\n", c); } if (lflag && !qflag && c != 0) printf("%s%c", fn, nullflag ? 0 : '\n'); if (Lflag && !qflag && c == 0) printf("%s%c", fn, nullflag ? 0 : '\n'); if (c && !cflag && !lflag && !Lflag && binbehave == BINFILE_BIN && f->binary && !qflag) printf(getstr(8), fn); free(ln.file); free(f); return (c); } #define iswword(x) (iswalnum((x)) || (x) == L'_') /* * Processes a line comparing it with the specified patterns. Each pattern * is looped to be compared along with the full string, saving each and every * match, which is necessary to colorize the output and to count the * matches. The matching lines are passed to printline() to display the * appropriate output. */ static int procline(struct str *l, int nottext) { regmatch_t matches[MAX_LINE_MATCHES]; - regmatch_t pmatch; - size_t st = 0; + regmatch_t pmatch, lastmatch; + size_t st = 0, nst = 0; unsigned int i; - int c = 0, m = 0, r = 0; + int c = 0, m = 0, r = 0, lastmatches = 0, leflags = eflags; + int startm = 0; + /* Initialize to avoid a false positive warning from GCC. */ + lastmatch.rm_so = lastmatch.rm_eo = 0; + /* Loop to process the whole line */ while (st <= l->len) { - pmatch.rm_so = st; - pmatch.rm_eo = l->len; - + lastmatches = 0; + startm = m; + if (st > 0) + leflags |= REG_NOTBOL; /* Loop to compare with all the patterns */ for (i = 0; i < patterns; i++) { + pmatch.rm_so = st; + pmatch.rm_eo = l->len; if (fg_pattern[i].pattern) r = fastexec(&fg_pattern[i], - l->dat, 1, &pmatch, eflags); + l->dat, 1, &pmatch, leflags); else r = regexec(&r_pattern[i], l->dat, 1, - &pmatch, eflags); + &pmatch, leflags); r = (r == 0) ? 0 : REG_NOMATCH; - st = (cflags & REG_NOSUB) - ? (size_t)l->len - : (size_t)pmatch.rm_eo; if (r == REG_NOMATCH) continue; /* Check for full match */ if (r == 0 && xflag) if (pmatch.rm_so != 0 || (size_t)pmatch.rm_eo != l->len) r = REG_NOMATCH; /* Check for whole word match */ if (r == 0 && (wflag || fg_pattern[i].word)) { wchar_t wbegin, wend; wbegin = wend = L' '; if (pmatch.rm_so != 0 && sscanf(&l->dat[pmatch.rm_so - 1], "%lc", &wbegin) != 1) r = REG_NOMATCH; else if ((size_t)pmatch.rm_eo != l->len && sscanf(&l->dat[pmatch.rm_eo], "%lc", &wend) != 1) r = REG_NOMATCH; else if (iswword(wbegin) || iswword(wend)) r = REG_NOMATCH; } if (r == 0) { + lastmatches++; + lastmatch = pmatch; if (m == 0) c++; - if (m < MAX_LINE_MATCHES) - matches[m++] = pmatch; + + if (m < MAX_LINE_MATCHES) { + /* Replace previous match if the new one is earlier and/or longer */ + if (m > startm) { + if (pmatch.rm_so < matches[m-1].rm_so || + (pmatch.rm_so == matches[m-1].rm_so && (pmatch.rm_eo - pmatch.rm_so) > (matches[m-1].rm_eo - matches[m-1].rm_so))) { + matches[m-1] = pmatch; + nst = pmatch.rm_eo; + } + } else { + /* Advance as normal if not */ + matches[m++] = pmatch; + nst = pmatch.rm_eo; + } + } + /* matches - skip further patterns */ if ((color == NULL && !oflag) || qflag || lflag) break; } } if (vflag) { c = !c; break; } /* One pass if we are not recording matches */ if (!wflag && ((color == NULL && !oflag) || qflag || lflag || Lflag)) break; - if (st == (size_t)pmatch.rm_so) - break; /* No matches */ + /* If we didn't have any matches or REG_NOSUB set */ + if (lastmatches == 0 || (cflags & REG_NOSUB)) + nst = l->len; + + if (lastmatches == 0) + /* No matches */ + break; + else if (st == nst && lastmatch.rm_so == lastmatch.rm_eo) + /* Zero-length match -- advance one more so we don't get stuck */ + nst++; + + /* Advance st based on previous matches */ + st = nst; } /* Count the matches if we have a match limit */ if (mflag) mcount -= c; if (c && binbehave == BINFILE_BIN && nottext) return (c); /* Binary file */ /* Dealing with the context */ if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) { if (c) { if (!first && !prev && !tail && Aflag) printf("--\n"); tail = Aflag; if (Bflag > 0) { if (!first && !prev) printf("--\n"); printqueue(); } linesqueued = 0; printline(l, ':', matches, m); } else { printline(l, '-', matches, m); tail--; } } if (c) { prev = true; first = false; } else prev = false; return (c); } /* * Safe malloc() for internal use. */ void * grep_malloc(size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) err(2, "malloc"); return (ptr); } /* * Safe calloc() for internal use. */ void * grep_calloc(size_t nmemb, size_t size) { void *ptr; if ((ptr = calloc(nmemb, size)) == NULL) err(2, "calloc"); return (ptr); } /* * Safe realloc() for internal use. */ void * grep_realloc(void *ptr, size_t size) { if ((ptr = realloc(ptr, size)) == NULL) err(2, "realloc"); return (ptr); } /* * Safe strdup() for internal use. */ char * grep_strdup(const char *str) { char *ret; if ((ret = strdup(str)) == NULL) err(2, "strdup"); return (ret); } /* * Prints a matching line according to the command line options. */ void printline(struct str *line, int sep, regmatch_t *matches, int m) { size_t a = 0; int i, n = 0; + /* If matchall, everything matches but don't actually print for -o */ + if (oflag && matchall) + return; + if (!hflag) { if (!nullflag) { fputs(line->file, stdout); ++n; } else { printf("%s", line->file); putchar(0); } } if (nflag) { if (n > 0) putchar(sep); printf("%d", line->line_no); ++n; } if (bflag) { if (n > 0) putchar(sep); printf("%lld", (long long)line->off); ++n; } if (n) putchar(sep); /* --color and -o */ if ((oflag || color) && m > 0) { for (i = 0; i < m; i++) { + /* Don't output zero length matches */ + if (matches[i].rm_so == matches[i].rm_eo) + continue; if (!oflag) fwrite(line->dat + a, matches[i].rm_so - a, 1, stdout); if (color) fprintf(stdout, "\33[%sm\33[K", color); fwrite(line->dat + matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so, 1, stdout); if (color) fprintf(stdout, "\33[m\33[K"); a = matches[i].rm_eo; if (oflag) putchar('\n'); } if (!oflag) { if (line->len - a > 0) fwrite(line->dat + a, line->len - a, 1, stdout); putchar('\n'); } } else { fwrite(line->dat, line->len, 1, stdout); putchar('\n'); } } Index: stable/11 =================================================================== --- stable/11 (revision 322554) +++ stable/11 (revision 322555) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r316477,316489,316491,316536,317052