Page MenuHomeFreeBSD

No OneTemporary

Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_e.in
===================================================================
--- stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_e.in (nonexistent)
+++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_e.in (revision 322587)
@@ -0,0 +1,10 @@
+monkey
+banana
+apple
+fruit
+monkey
+banna
+apple
+fruit
+apple
+monkey
Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_e.in
___________________________________________________________________
Added: fbsd:nokeywords
## -0,0 +1 ##
+yes
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ 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_context_e.out
===================================================================
--- stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_e.out (nonexistent)
+++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_e.out (revision 322587)
@@ -0,0 +1,9 @@
+monkey
+banana
+apple
+fruit
+monkey
+banna
+--
+apple
+monkey
Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_e.out
___________________________________________________________________
Added: fbsd:nokeywords
## -0,0 +1 ##
+yes
\ No newline at end of property
Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_f.out
===================================================================
--- stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_f.out (nonexistent)
+++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_f.out (revision 322587)
@@ -0,0 +1,9 @@
+monkey
+banana
+apple
+fruit
+monkey
+banna
+apple
+fruit
+apple
Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_f.out
___________________________________________________________________
Added: fbsd:nokeywords
## -0,0 +1 ##
+yes
\ No newline at end of property
Index: stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_g.out
===================================================================
--- stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_g.out (nonexistent)
+++ stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_g.out (revision 322587)
@@ -0,0 +1,8 @@
+apple
+fruit
+--
+banna
+apple
+fruit
+apple
+monkey
Property changes on: stable/11/contrib/netbsd-tests/usr.bin/grep/d_context_g.out
___________________________________________________________________
Added: fbsd:nokeywords
## -0,0 +1 ##
+yes
\ No newline at end of property
Index: stable/11/contrib/netbsd-tests/usr.bin/grep/t_grep.sh
===================================================================
--- stable/11/contrib/netbsd-tests/usr.bin/grep/t_grep.sh (revision 322586)
+++ stable/11/contrib/netbsd-tests/usr.bin/grep/t_grep.sh (revision 322587)
@@ -1,498 +1,560 @@
# $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()
{
# Begin FreeBSD
grep_type
if [ $? -eq $GREP_TYPE_GNU ]; then
atf_expect_fail "this test doesn't pass with gnu grep from ports"
fi
# End FreeBSD
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
# Begin FreeBSD
printf "xmatch pmatch\n" > test1
atf_check -o inline:"pmatch\n" grep -Eow "(match )?pmatch" test1
# End FreeBSD
}
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_check -o file:d_context_e.out \
+ grep -E -C1 '(banana|monkey)' d_context_e.in
+ atf_check -o file:d_context_f.out \
+ grep -Ev -B2 '(banana|monkey|fruit)' d_context_e.in
+ atf_check -o file:d_context_g.out \
+ grep -Ev -A1 '(banana|monkey|fruit)' d_context_e.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
# What grep(1) are we working with?
# - 0 : bsdgrep
# - 1 : gnu grep 2.51 (base)
# - 2 : gnu grep (ports)
GREP_TYPE_BSD=0
GREP_TYPE_GNU_FREEBSD=1
GREP_TYPE_GNU=2
GREP_TYPE_UNKNOWN=3
grep_type()
{
local grep_version=$(grep --version)
case "$grep_version" in
*"BSD grep"*)
return $GREP_TYPE_BSD
;;
*"GNU grep"*)
case "$grep_version" in
*2.5.1-FreeBSD*)
return $GREP_TYPE_GNU_FREEBSD
;;
*)
return $GREP_TYPE_GNU
;;
esac
;;
esac
atf_fail "unknown grep type: $grep_version"
}
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()
{
grep_type
if [ $? -eq $GREP_TYPE_GNU_FREEBSD ]; then
atf_expect_fail "this test doesn't pass with gnu grep in base"
fi
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()
{
grep_type
if [ $? -eq $GREP_TYPE_GNU_FREEBSD ]; then
atf_expect_fail "this test doesn't pass with gnu grep in base"
fi
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 -e ignore -s not-exit:0 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
}
+atf_test_case wflag_emptypat
+wflag_emptypat_head()
+{
+ atf_set "descr" "Check for proper handling of -w with an empty pattern (PR 105221)"
+}
+wflag_emptypat_body()
+{
+ grep_type
+ if [ $? -eq $GREP_TYPE_GNU_FREEBSD ]; then
+ atf_expect_fail "this test does not pass with GNU grep in base"
+ fi
+
+ printf "" > test1
+ printf "\n" > test2
+ printf "qaz" > test3
+ printf " qaz\n" > test4
+
+ atf_check -s exit:1 -o empty grep -w -e "" test1
+
+ atf_check -o file:test2 grep -w -e "" test2
+
+ atf_check -s exit:1 -o empty grep -w -e "" test3
+
+ atf_check -o file:test4 grep -w -e "" test4
+}
+
atf_test_case fgrep_sanity
fgrep_sanity_head()
{
atf_set "descr" "Check for fgrep sanity, literal expressions only"
}
fgrep_sanity_body()
{
printf "Foo" > test1
atf_check -o inline:"Foo\n" fgrep -e "Foo" test1
atf_check -s exit:1 -o empty fgrep -e "Fo." test1
}
atf_test_case egrep_sanity
egrep_sanity_head()
{
atf_set "descr" "Check for egrep sanity, EREs only"
}
egrep_sanity_body()
{
printf "Foobar(ed)" > test1
printf "M{1}" > test2
atf_check -o inline:"Foo\n" egrep -o -e "F.." test1
atf_check -o inline:"Foobar\n" egrep -o -e "F[a-z]*" test1
atf_check -o inline:"Fo\n" egrep -o -e "F(o|p)" test1
atf_check -o inline:"(ed)\n" egrep -o -e "\(ed\)" test1
atf_check -o inline:"M\n" egrep -o -e "M{1}" test2
atf_check -o inline:"M{1}\n" egrep -o -e "M\{1\}" test2
}
atf_test_case grep_sanity
grep_sanity_head()
{
atf_set "descr" "Check for basic grep sanity, BREs only"
}
grep_sanity_body()
{
printf "Foobar(ed)" > test1
printf "M{1}" > test2
atf_check -o inline:"Foo\n" grep -o -e "F.." test1
atf_check -o inline:"Foobar\n" grep -o -e "F[a-z]*" test1
atf_check -o inline:"Fo\n" grep -o -e "F\(o\)" test1
atf_check -o inline:"(ed)\n" grep -o -e "(ed)" test1
atf_check -o inline:"M{1}\n" grep -o -e "M{1}" test2
atf_check -o inline:"M\n" grep -o -e "M\{1\}" test2
}
atf_test_case wv_combo_break
wv_combo_break_head()
{
atf_set "descr" "Check for incorrectly matching lines with both -w and -v flags (PR 218467)"
}
wv_combo_break_body()
{
printf "x xx\n" > test1
printf "xx x\n" > test2
atf_check -o file:test1 grep -w "x" test1
atf_check -o file:test2 grep -w "x" test2
atf_check -s exit:1 grep -v -w "x" test1
atf_check -s exit:1 grep -v -w "x" test2
}
+
+atf_test_case grep_nomatch_flags
+grep_nomatch_flags_head()
+{
+ atf_set "descr" "Check for no match (-c, -l, -L, -q) flags not producing line matches or context (PR 219077)"
+}
+
+grep_nomatch_flags_body()
+{
+ printf "A\nB\nC\n" > test1
+
+ atf_check -o inline:"1\n" grep -c -C 1 -e "B" test1
+ atf_check -o inline:"1\n" grep -c -B 1 -e "B" test1
+ atf_check -o inline:"1\n" grep -c -A 1 -e "B" test1
+ atf_check -o inline:"1\n" grep -c -C 1 -e "B" test1
+
+ atf_check -o inline:"test1\n" grep -l -e "B" test1
+ atf_check -o inline:"test1\n" grep -l -B 1 -e "B" test1
+ atf_check -o inline:"test1\n" grep -l -A 1 -e "B" test1
+ atf_check -o inline:"test1\n" grep -l -C 1 -e "B" test1
+
+ atf_check -s exit:1 -o inline:"test1\n" grep -L -e "D" test1
+
+ atf_check -o empty grep -q -e "B" test1
+ atf_check -o empty grep -q -B 1 -e "B" test1
+ atf_check -o empty grep -q -A 1 -e "B" test1
+ atf_check -o empty grep -q -C 1 -e "B" test1
+}
# End FreeBSD
atf_init_test_cases()
{
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
+ atf_add_test_case wflag_emptypat
atf_add_test_case wv_combo_break
atf_add_test_case fgrep_sanity
atf_add_test_case egrep_sanity
atf_add_test_case grep_sanity
+ atf_add_test_case grep_nomatch_flags
# End FreeBSD
}
Index: stable/11/usr.bin/grep/grep.c
===================================================================
--- stable/11/usr.bin/grep/grep.c (revision 322586)
+++ stable/11/usr.bin/grep/grep.c (revision 322587)
@@ -1,775 +1,783 @@
/* $NetBSD: grep.c,v 1.6 2011/04/18 03:48:23 joerg Exp $ */
/* $FreeBSD$ */
/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
/*-
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
* Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <libgen.h>
#include <locale.h>
#include <stdbool.h>
#define _WITH_GETLINE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef WITHOUT_FASTMATCH
#include "fastmatch.h"
#endif
#include "grep.h"
#ifndef WITHOUT_NLS
#include <nl_types.h>
nl_catd catalog;
#endif
/*
* Default messags to use when NLS is disabled or no catalogue
* is found.
*/
const char *errstr[] = {
"",
/* 1*/ "(standard input)",
/* 2*/ "cannot read bzip2 compressed file",
/* 3*/ "unknown %s option",
/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n",
/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
/* 7*/ "\t[--null] [pattern] [file ...]\n",
/* 8*/ "Binary file %s matches\n",
/* 9*/ "%s (BSD grep) %s\n",
/* 10*/ "%s (BSD grep, GNU compatible) %s\n",
};
/* Flags passed to regcomp() and regexec() */
int cflags = REG_NOSUB;
int eflags = REG_STARTEND;
-/* Shortcut for matching all cases like empty regex */
+/* XXX TODO: Get rid of this flag.
+ * matchall is a gross hack that means that an empty pattern was passed to us.
+ * It is a necessary evil at the moment because our regex(3) implementation
+ * does not allow for empty patterns, as supported by POSIX's definition of
+ * grammar for BREs/EREs. When libregex becomes available, it would be wise
+ * to remove this and let regex(3) handle the dirty details of empty patterns.
+ */
bool matchall;
/* Searching patterns */
unsigned int patterns;
static unsigned int pattern_sz;
struct pat *pattern;
regex_t *r_pattern;
#ifndef WITHOUT_FASTMATCH
fastmatch_t *fg_pattern;
#endif
/* Filename exclusion/inclusion patterns */
unsigned int fpatterns, dpatterns;
static unsigned int fpattern_sz, dpattern_sz;
struct epat *dpattern, *fpattern;
/* For regex errors */
char re_error[RE_ERROR_BUF + 1];
/* Command-line flags */
unsigned long long Aflag; /* -A x: print x lines trailing each match */
unsigned long long Bflag; /* -B x: print x lines leading each match */
bool Hflag; /* -H: always print file name */
bool Lflag; /* -L: only show names of files with no matches */
bool bflag; /* -b: show block numbers for each match */
bool cflag; /* -c: only show a count of matching lines */
bool hflag; /* -h: don't print filename headers */
bool iflag; /* -i: ignore case */
bool lflag; /* -l: only show names of files with matches */
bool mflag; /* -m x: stop reading the files after x matches */
long long mcount; /* count for -m */
long long mlimit; /* requested value for -m */
char fileeol; /* indicator for eol */
bool nflag; /* -n: show line numbers in front of matching lines */
bool oflag; /* -o: print only matching part */
bool qflag; /* -q: quiet mode (don't output anything) */
bool sflag; /* -s: silent mode (ignore errors) */
bool vflag; /* -v: only show non-matching lines */
bool wflag; /* -w: pattern must start and end on word boundaries */
bool xflag; /* -x: pattern must match entire line */
bool lbflag; /* --line-buffered */
bool nullflag; /* --null */
char *label; /* --label */
const char *color; /* --color */
int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */
int devbehave = DEV_READ; /* -D: handling of devices */
int dirbehave = DIR_READ; /* -dRr: handling of directories */
int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
bool dexclude, dinclude; /* --exclude-dir and --include-dir */
bool fexclude, finclude; /* --exclude and --include */
enum {
BIN_OPT = CHAR_MAX + 1,
COLOR_OPT,
HELP_OPT,
MMAP_OPT,
LINEBUF_OPT,
LABEL_OPT,
NULL_OPT,
R_EXCLUDE_OPT,
R_INCLUDE_OPT,
R_DEXCLUDE_OPT,
R_DINCLUDE_OPT
};
static inline const char *init_color(const char *);
/* Housekeeping */
-bool first = true; /* flag whether we are processing the first match */
-bool prev; /* flag whether or not the previous line matched */
-int tail; /* lines left to print */
bool file_err; /* file reading error */
/*
* Prints usage information and returns 2.
*/
static void
usage(void)
{
fprintf(stderr, getstr(4), getprogname());
fprintf(stderr, "%s", getstr(5));
fprintf(stderr, "%s", getstr(6));
fprintf(stderr, "%s", getstr(7));
exit(2);
}
static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXyz";
static const struct option long_options[] =
{
{"binary-files", required_argument, NULL, BIN_OPT},
{"help", no_argument, NULL, HELP_OPT},
{"mmap", no_argument, NULL, MMAP_OPT},
{"line-buffered", no_argument, NULL, LINEBUF_OPT},
{"label", required_argument, NULL, LABEL_OPT},
{"null", no_argument, NULL, NULL_OPT},
{"color", optional_argument, NULL, COLOR_OPT},
{"colour", optional_argument, NULL, COLOR_OPT},
{"exclude", required_argument, NULL, R_EXCLUDE_OPT},
{"include", required_argument, NULL, R_INCLUDE_OPT},
{"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
{"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
{"after-context", required_argument, NULL, 'A'},
{"text", no_argument, NULL, 'a'},
{"before-context", required_argument, NULL, 'B'},
{"byte-offset", no_argument, NULL, 'b'},
{"context", optional_argument, NULL, 'C'},
{"count", no_argument, NULL, 'c'},
{"devices", required_argument, NULL, 'D'},
{"directories", required_argument, NULL, 'd'},
{"extended-regexp", no_argument, NULL, 'E'},
{"regexp", required_argument, NULL, 'e'},
{"fixed-strings", no_argument, NULL, 'F'},
{"file", required_argument, NULL, 'f'},
{"basic-regexp", no_argument, NULL, 'G'},
{"no-filename", no_argument, NULL, 'h'},
{"with-filename", no_argument, NULL, 'H'},
{"ignore-case", no_argument, NULL, 'i'},
{"bz2decompress", no_argument, NULL, 'J'},
{"files-with-matches", no_argument, NULL, 'l'},
{"files-without-match", no_argument, NULL, 'L'},
{"max-count", required_argument, NULL, 'm'},
{"lzma", no_argument, NULL, 'M'},
{"line-number", no_argument, NULL, 'n'},
{"only-matching", no_argument, NULL, 'o'},
{"quiet", no_argument, NULL, 'q'},
{"silent", no_argument, NULL, 'q'},
{"recursive", no_argument, NULL, 'r'},
{"no-messages", no_argument, NULL, 's'},
{"binary", no_argument, NULL, 'U'},
{"unix-byte-offsets", no_argument, NULL, 'u'},
{"invert-match", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"word-regexp", no_argument, NULL, 'w'},
{"line-regexp", no_argument, NULL, 'x'},
{"xz", no_argument, NULL, 'X'},
{"null-data", no_argument, NULL, 'z'},
{"decompress", no_argument, NULL, 'Z'},
{NULL, no_argument, NULL, 0}
};
/*
* Adds a searching pattern to the internal array.
*/
static void
add_pattern(char *pat, size_t len)
{
/* Do not add further pattern is we already match everything */
if (matchall)
return;
/* Check if we can do a shortcut */
if (len == 0) {
matchall = true;
for (unsigned int i = 0; i < patterns; i++) {
free(pattern[i].pat);
}
pattern = grep_realloc(pattern, sizeof(struct pat));
pattern[0].pat = NULL;
pattern[0].len = 0;
patterns = 1;
return;
}
/* Increase size if necessary */
if (patterns == pattern_sz) {
pattern_sz *= 2;
pattern = grep_realloc(pattern, ++pattern_sz *
sizeof(struct pat));
}
if (len > 0 && pat[len - 1] == '\n')
--len;
/* pat may not be NUL-terminated */
pattern[patterns].pat = grep_malloc(len + 1);
memcpy(pattern[patterns].pat, pat, len);
pattern[patterns].len = len;
pattern[patterns].pat[len] = '\0';
++patterns;
}
/*
* Adds a file include/exclude pattern to the internal array.
*/
static void
add_fpattern(const char *pat, int mode)
{
/* Increase size if necessary */
if (fpatterns == fpattern_sz) {
fpattern_sz *= 2;
fpattern = grep_realloc(fpattern, ++fpattern_sz *
sizeof(struct epat));
}
fpattern[fpatterns].pat = grep_strdup(pat);
fpattern[fpatterns].mode = mode;
++fpatterns;
}
/*
* Adds a directory include/exclude pattern to the internal array.
*/
static void
add_dpattern(const char *pat, int mode)
{
/* Increase size if necessary */
if (dpatterns == dpattern_sz) {
dpattern_sz *= 2;
dpattern = grep_realloc(dpattern, ++dpattern_sz *
sizeof(struct epat));
}
dpattern[dpatterns].pat = grep_strdup(pat);
dpattern[dpatterns].mode = mode;
++dpatterns;
}
/*
* Reads searching patterns from a file and adds them with add_pattern().
*/
static void
read_patterns(const char *fn)
{
struct stat st;
FILE *f;
char *line;
size_t len;
ssize_t rlen;
if ((f = fopen(fn, "r")) == NULL)
err(2, "%s", fn);
if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
fclose(f);
return;
}
len = 0;
line = NULL;
while ((rlen = getline(&line, &len, f)) != -1) {
if (line[0] == '\0')
continue;
add_pattern(line, line[0] == '\n' ? 0 : (size_t)rlen);
}
free(line);
if (ferror(f))
err(2, "%s", fn);
fclose(f);
}
static inline const char *
init_color(const char *d)
{
char *c;
c = getenv("GREP_COLOR");
return (c != NULL && c[0] != '\0' ? c : d);
}
int
main(int argc, char *argv[])
{
char **aargv, **eargv, *eopts;
char *ep;
const char *pn;
unsigned long long l;
unsigned int aargc, eargc, i;
int c, lastc, needpattern, newarg, prevoptind;
setlocale(LC_ALL, "");
#ifndef WITHOUT_NLS
catalog = catopen("grep", NL_CAT_LOCALE);
#endif
/* Check what is the program name of the binary. In this
way we can have all the funcionalities in one binary
without the need of scripting and using ugly hacks. */
pn = getprogname();
if (pn[0] == 'b' && pn[1] == 'z') {
filebehave = FILE_BZIP;
pn += 2;
} else if (pn[0] == 'x' && pn[1] == 'z') {
filebehave = FILE_XZ;
pn += 2;
} else if (pn[0] == 'l' && pn[1] == 'z') {
filebehave = FILE_LZMA;
pn += 2;
} else if (pn[0] == 'r') {
dirbehave = DIR_RECURSE;
Hflag = true;
} else if (pn[0] == 'z') {
filebehave = FILE_GZIP;
pn += 1;
}
switch (pn[0]) {
case 'e':
grepbehave = GREP_EXTENDED;
break;
case 'f':
grepbehave = GREP_FIXED;
break;
}
lastc = '\0';
newarg = 1;
prevoptind = 1;
needpattern = 1;
fileeol = '\n';
eopts = getenv("GREP_OPTIONS");
/* support for extra arguments in GREP_OPTIONS */
eargc = 0;
if (eopts != NULL && eopts[0] != '\0') {
char *str;
/* make an estimation of how many extra arguments we have */
for (unsigned int j = 0; j < strlen(eopts); j++)
if (eopts[j] == ' ')
eargc++;
eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
eargc = 0;
/* parse extra arguments */
while ((str = strsep(&eopts, " ")) != NULL)
if (str[0] != '\0')
eargv[eargc++] = grep_strdup(str);
aargv = (char **)grep_calloc(eargc + argc + 1,
sizeof(char *));
aargv[0] = argv[0];
for (i = 0; i < eargc; i++)
aargv[i + 1] = eargv[i];
for (int j = 1; j < argc; j++, i++)
aargv[i + 1] = argv[j];
aargc = eargc + argc;
} else {
aargv = argv;
aargc = argc;
}
while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
-1)) {
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (newarg || !isdigit(lastc))
Aflag = 0;
else if (Aflag > LLONG_MAX / 10) {
errno = ERANGE;
err(2, NULL);
}
Aflag = Bflag = (Aflag * 10) + (c - '0');
break;
case 'C':
if (optarg == NULL) {
Aflag = Bflag = 2;
break;
}
/* FALLTHROUGH */
case 'A':
/* FALLTHROUGH */
case 'B':
errno = 0;
l = strtoull(optarg, &ep, 10);
if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
((errno == EINVAL) && (l == 0)))
err(2, NULL);
else if (ep[0] != '\0') {
errno = EINVAL;
err(2, NULL);
}
if (c == 'A')
Aflag = l;
else if (c == 'B')
Bflag = l;
else
Aflag = Bflag = l;
break;
case 'a':
binbehave = BINFILE_TEXT;
break;
case 'b':
bflag = true;
break;
case 'c':
cflag = true;
break;
case 'D':
if (strcasecmp(optarg, "skip") == 0)
devbehave = DEV_SKIP;
else if (strcasecmp(optarg, "read") == 0)
devbehave = DEV_READ;
else
errx(2, getstr(3), "--devices");
break;
case 'd':
if (strcasecmp("recurse", optarg) == 0) {
Hflag = true;
dirbehave = DIR_RECURSE;
} else if (strcasecmp("skip", optarg) == 0)
dirbehave = DIR_SKIP;
else if (strcasecmp("read", optarg) == 0)
dirbehave = DIR_READ;
else
errx(2, getstr(3), "--directories");
break;
case 'E':
grepbehave = GREP_EXTENDED;
break;
case 'e':
{
char *token;
char *string = optarg;
while ((token = strsep(&string, "\n")) != NULL)
add_pattern(token, strlen(token));
}
needpattern = 0;
break;
case 'F':
grepbehave = GREP_FIXED;
break;
case 'f':
read_patterns(optarg);
needpattern = 0;
break;
case 'G':
grepbehave = GREP_BASIC;
break;
case 'H':
Hflag = true;
break;
case 'h':
Hflag = false;
hflag = true;
break;
case 'I':
binbehave = BINFILE_SKIP;
break;
case 'i':
case 'y':
iflag = true;
cflags |= REG_ICASE;
break;
case 'J':
#ifdef WITHOUT_BZIP2
errno = EOPNOTSUPP;
err(2, "bzip2 support was disabled at compile-time");
#endif
filebehave = FILE_BZIP;
break;
case 'L':
lflag = false;
Lflag = true;
break;
case 'l':
Lflag = false;
lflag = true;
break;
case 'm':
mflag = true;
errno = 0;
mlimit = mcount = strtoll(optarg, &ep, 10);
if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
((errno == EINVAL) && (mcount == 0)))
err(2, NULL);
else if (ep[0] != '\0') {
errno = EINVAL;
err(2, NULL);
}
break;
case 'M':
filebehave = FILE_LZMA;
break;
case 'n':
nflag = true;
break;
case 'O':
linkbehave = LINK_EXPLICIT;
break;
case 'o':
oflag = true;
cflags &= ~REG_NOSUB;
break;
case 'p':
linkbehave = LINK_SKIP;
break;
case 'q':
qflag = true;
break;
case 'S':
linkbehave = LINK_READ;
break;
case 'R':
case 'r':
dirbehave = DIR_RECURSE;
Hflag = true;
break;
case 's':
sflag = true;
break;
case 'U':
binbehave = BINFILE_BIN;
break;
case 'u':
case MMAP_OPT:
filebehave = FILE_MMAP;
break;
case 'V':
#ifdef WITH_GNU
printf(getstr(10), getprogname(), VERSION);
#else
printf(getstr(9), getprogname(), VERSION);
#endif
exit(0);
case 'v':
vflag = true;
break;
case 'w':
wflag = true;
cflags &= ~REG_NOSUB;
break;
case 'x':
xflag = true;
cflags &= ~REG_NOSUB;
break;
case 'X':
filebehave = FILE_XZ;
break;
case 'z':
fileeol = '\0';
break;
case 'Z':
filebehave = FILE_GZIP;
break;
case BIN_OPT:
if (strcasecmp("binary", optarg) == 0)
binbehave = BINFILE_BIN;
else if (strcasecmp("without-match", optarg) == 0)
binbehave = BINFILE_SKIP;
else if (strcasecmp("text", optarg) == 0)
binbehave = BINFILE_TEXT;
else
errx(2, getstr(3), "--binary-files");
break;
case COLOR_OPT:
color = NULL;
if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
strcasecmp("tty", optarg) == 0 ||
strcasecmp("if-tty", optarg) == 0) {
char *term;
term = getenv("TERM");
if (isatty(STDOUT_FILENO) && term != NULL &&
strcasecmp(term, "dumb") != 0)
color = init_color("01;31");
} else if (strcasecmp("always", optarg) == 0 ||
strcasecmp("yes", optarg) == 0 ||
strcasecmp("force", optarg) == 0) {
color = init_color("01;31");
} else if (strcasecmp("never", optarg) != 0 &&
strcasecmp("none", optarg) != 0 &&
strcasecmp("no", optarg) != 0)
errx(2, getstr(3), "--color");
cflags &= ~REG_NOSUB;
break;
case LABEL_OPT:
label = optarg;
break;
case LINEBUF_OPT:
lbflag = true;
break;
case NULL_OPT:
nullflag = true;
break;
case R_INCLUDE_OPT:
finclude = true;
add_fpattern(optarg, INCL_PAT);
break;
case R_EXCLUDE_OPT:
fexclude = true;
add_fpattern(optarg, EXCL_PAT);
break;
case R_DINCLUDE_OPT:
dinclude = true;
add_dpattern(optarg, INCL_PAT);
break;
case R_DEXCLUDE_OPT:
dexclude = true;
add_dpattern(optarg, EXCL_PAT);
break;
case HELP_OPT:
default:
usage();
}
lastc = c;
newarg = optind != prevoptind;
prevoptind = optind;
}
aargc -= optind;
aargv += optind;
/* Empty pattern file matches nothing */
if (!needpattern && (patterns == 0))
exit(1);
/* Fail if we don't have any pattern */
if (aargc == 0 && needpattern)
usage();
/* Process patterns from command line */
if (aargc != 0 && needpattern) {
char *token;
char *string = *aargv;
while ((token = strsep(&string, "\n")) != NULL)
add_pattern(token, strlen(token));
--aargc;
++aargv;
}
switch (grepbehave) {
case GREP_BASIC:
break;
case GREP_FIXED:
/* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */
cflags |= 0020;
break;
case GREP_EXTENDED:
cflags |= REG_EXTENDED;
break;
default:
/* NOTREACHED */
usage();
}
#ifndef WITHOUT_FASTMATCH
fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
#endif
r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
- /* Check if cheating is allowed (always is for fgrep). */
- for (i = 0; i < patterns; ++i) {
+ /* Don't process any patterns if we have a blank one */
+ if (!matchall) {
+ /* Check if cheating is allowed (always is for fgrep). */
+ for (i = 0; i < patterns; ++i) {
#ifndef WITHOUT_FASTMATCH
- /* Attempt compilation with fastmatch regex and fallback to
- regex(3) if it fails. */
- if (fastncomp(&fg_pattern[i], pattern[i].pat,
- pattern[i].len, cflags) == 0)
- continue;
+ /*
+ * Attempt compilation with fastmatch regex and
+ * fallback to regex(3) if it fails.
+ */
+ if (fastncomp(&fg_pattern[i], pattern[i].pat,
+ pattern[i].len, cflags) == 0)
+ continue;
#endif
- c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
- if (c != 0) {
- regerror(c, &r_pattern[i], re_error,
- RE_ERROR_BUF);
- errx(2, "%s", re_error);
+ c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
+ if (c != 0) {
+ regerror(c, &r_pattern[i], re_error,
+ RE_ERROR_BUF);
+ errx(2, "%s", re_error);
+ }
}
}
if (lbflag)
setlinebuf(stdout);
if ((aargc == 0 || aargc == 1) && !Hflag)
hflag = true;
if (aargc == 0 && dirbehave != DIR_RECURSE)
exit(!procfile("-"));
if (dirbehave == DIR_RECURSE)
c = grep_tree(aargv);
else
for (c = 0; aargc--; ++aargv) {
if ((finclude || fexclude) && !file_matching(*aargv))
continue;
c+= procfile(*aargv);
}
#ifndef WITHOUT_NLS
catclose(catalog);
#endif
/* Find out the correct return value according to the
results and the command line option. */
exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
}
Index: stable/11/usr.bin/grep/grep.h
===================================================================
--- stable/11/usr.bin/grep/grep.h (revision 322586)
+++ stable/11/usr.bin/grep/grep.h (revision 322587)
@@ -1,158 +1,157 @@
/* $NetBSD: grep.h,v 1.5 2011/02/27 17:33:37 joerg Exp $ */
/* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */
/* $FreeBSD$ */
/*-
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
* Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
* 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 <bzlib.h>
#include <limits.h>
#include <regex.h>
#include <stdbool.h>
#include <stdio.h>
#include <zlib.h>
#ifndef WITHOUT_FASTMATCH
#include "fastmatch.h"
#endif
#ifdef WITHOUT_NLS
#define getstr(n) errstr[n]
#else
#include <nl_types.h>
extern nl_catd catalog;
#define getstr(n) catgets(catalog, 1, n, errstr[n])
#endif
extern const char *errstr[];
#define VERSION "2.5.1-FreeBSD"
#define GREP_FIXED 0
#define GREP_BASIC 1
#define GREP_EXTENDED 2
#define BINFILE_BIN 0
#define BINFILE_SKIP 1
#define BINFILE_TEXT 2
#define FILE_STDIO 0
#define FILE_MMAP 1
#define FILE_GZIP 2
#define FILE_BZIP 3
#define FILE_XZ 4
#define FILE_LZMA 5
#define DIR_READ 0
#define DIR_SKIP 1
#define DIR_RECURSE 2
#define DEV_READ 0
#define DEV_SKIP 1
#define LINK_READ 0
#define LINK_EXPLICIT 1
#define LINK_SKIP 2
#define EXCL_PAT 0
#define INCL_PAT 1
#define MAX_LINE_MATCHES 32
struct file {
int fd;
bool binary;
};
struct str {
off_t off;
size_t len;
char *dat;
char *file;
int line_no;
};
struct pat {
char *pat;
int len;
};
struct epat {
char *pat;
int mode;
};
/* Flags passed to regcomp() and regexec() */
extern int cflags, eflags;
/* Command line flags */
extern bool Eflag, Fflag, Gflag, Hflag, Lflag,
bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
qflag, sflag, vflag, wflag, xflag;
extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag;
extern unsigned long long Aflag, Bflag;
extern long long mcount;
extern long long mlimit;
extern char fileeol;
extern char *label;
extern const char *color;
extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
-extern bool file_err, first, matchall, prev;
-extern int tail;
+extern bool file_err, matchall;
extern unsigned int dpatterns, fpatterns, patterns;
extern struct pat *pattern;
extern struct epat *dpattern, *fpattern;
extern regex_t *er_pattern, *r_pattern;
#ifndef WITHOUT_FASTMATCH
extern fastmatch_t *fg_pattern;
#endif
/* For regex errors */
#define RE_ERROR_BUF 512
extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */
/* util.c */
bool file_matching(const char *fname);
int procfile(const char *fn);
int grep_tree(char **argv);
void *grep_malloc(size_t size);
void *grep_calloc(size_t nmemb, size_t size);
void *grep_realloc(void *ptr, size_t size);
char *grep_strdup(const char *str);
-void printline(struct str *line, int sep, regmatch_t *matches, int m);
+void grep_printline(struct str *line, int sep);
/* queue.c */
-void enqueue(struct str *x);
+bool enqueue(struct str *x);
void printqueue(void);
void clearqueue(void);
/* file.c */
void grep_close(struct file *f);
struct file *grep_open(const char *path);
char *grep_fgetln(struct file *f, size_t *len);
Index: stable/11/usr.bin/grep/queue.c
===================================================================
--- stable/11/usr.bin/grep/queue.c (revision 322586)
+++ stable/11/usr.bin/grep/queue.c (revision 322587)
@@ -1,113 +1,118 @@
/* $NetBSD: queue.c,v 1.5 2011/08/31 16:24:57 plunky Exp $ */
/* $FreeBSD$ */
/*-
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
* 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.
*/
/*
* A really poor man's queue. It does only what it has to and gets out of
* Dodge. It is used in place of <sys/queue.h> to get a better performance.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/queue.h>
#include <stdlib.h>
#include <string.h>
#include "grep.h"
struct qentry {
STAILQ_ENTRY(qentry) list;
struct str data;
};
static STAILQ_HEAD(, qentry) queue = STAILQ_HEAD_INITIALIZER(queue);
static unsigned long long count;
static struct qentry *dequeue(void);
-void
+/*
+ * Enqueue another line; return true if we've dequeued a line as a result
+ */
+bool
enqueue(struct str *x)
{
struct qentry *item;
item = grep_malloc(sizeof(struct qentry));
item->data.dat = grep_malloc(sizeof(char) * x->len);
item->data.len = x->len;
item->data.line_no = x->line_no;
item->data.off = x->off;
memcpy(item->data.dat, x->dat, x->len);
item->data.file = x->file;
STAILQ_INSERT_TAIL(&queue, item, list);
if (++count > Bflag) {
item = dequeue();
free(item->data.dat);
free(item);
+ return (true);
}
+ return (false);
}
static struct qentry *
dequeue(void)
{
struct qentry *item;
item = STAILQ_FIRST(&queue);
if (item == NULL)
return (NULL);
STAILQ_REMOVE_HEAD(&queue, list);
--count;
return (item);
}
void
printqueue(void)
{
struct qentry *item;
while ((item = dequeue()) != NULL) {
- printline(&item->data, '-', NULL, 0);
+ grep_printline(&item->data, '-');
free(item->data.dat);
free(item);
}
}
void
clearqueue(void)
{
struct qentry *item;
while ((item = dequeue()) != NULL) {
free(item->data.dat);
free(item);
}
}
Index: stable/11/usr.bin/grep/tests/Makefile
===================================================================
--- stable/11/usr.bin/grep/tests/Makefile (revision 322586)
+++ stable/11/usr.bin/grep/tests/Makefile (revision 322587)
@@ -1,53 +1,57 @@
# $FreeBSD$
PACKAGE= tests
ATF_TESTS_SH+= grep_freebsd_test
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_e.in
${PACKAGE}FILES+= d_context_b.out
${PACKAGE}FILES+= d_context_c.out
${PACKAGE}FILES+= d_context_d.out
+${PACKAGE}FILES+= d_context_e.out
+${PACKAGE}FILES+= d_context_f.out
+${PACKAGE}FILES+= d_context_g.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 <netbsd-tests.test.mk>
.include <bsd.test.mk>
Index: stable/11/usr.bin/grep/util.c
===================================================================
--- stable/11/usr.bin/grep/util.c (revision 322586)
+++ stable/11/usr.bin/grep/util.c (revision 322587)
@@ -1,588 +1,645 @@
/* $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 <gabor@FreeBSD.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fnmatch.h>
#include <fts.h>
#include <libgen.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
#ifndef WITHOUT_FASTMATCH
#include "fastmatch.h"
#endif
#include "grep.h"
-static int linesqueued;
-static int procline(struct str *l, int);
+static bool first_match = true;
-static int lasta;
-static bool ctxover;
+/*
+ * Parsing context; used to hold things like matches made and
+ * other useful bits
+ */
+struct parsec {
+ regmatch_t matches[MAX_LINE_MATCHES]; /* Matches made */
+ struct str ln; /* Current line */
+ size_t matchidx; /* Latest used match index */
+ bool binary; /* Binary file? */
+};
+
+static int procline(struct parsec *pc);
+static void printline(struct parsec *pc, int sep);
+static void printline_metadata(struct str *line, int sep);
+
bool
file_matching(const char *fname)
{
char *fname_base, *fname_buf;
bool ret;
ret = finclude ? false : true;
fname_buf = strdup(fname);
if (fname_buf == NULL)
err(2, "strdup");
fname_base = basename(fname_buf);
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) {
ret = false;
break;
} else
ret = true;
}
}
free(fname_buf);
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;
const char *wd[] = { ".", NULL };
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;
fts = fts_open((argv[0] == NULL) ?
__DECONST(char * const *, wd) : argv, fts_flags, NULL);
if (fts == 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 parsec pc;
struct file *f;
struct stat sb;
- struct str ln;
+ struct str *ln;
mode_t s;
- int c, t;
+ int c, last_outed, t, tail;
+ bool doctx, printmatch, same_file;
- 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;
- ctxover = false;
- linesqueued = 0;
+ /* Convenience */
+ ln = &pc.ln;
+ pc.ln.file = grep_malloc(strlen(fn) + 1);
+ strcpy(pc.ln.file, fn);
+ pc.ln.line_no = 0;
+ pc.ln.len = 0;
+ pc.ln.off = -1;
+ pc.binary = f->binary;
tail = 0;
- lasta = 0;
- ln.off = -1;
+ last_outed = 0;
+ same_file = false;
+ doctx = false;
+ printmatch = true;
+ if ((pc.binary && binbehave == BINFILE_BIN) || cflag || qflag ||
+ lflag || Lflag)
+ printmatch = false;
+ if (printmatch && (Aflag != 0 || Bflag != 0))
+ doctx = true;
+ mcount = mlimit;
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);
+ /* Reset match count for every line processed */
+ pc.matchidx = 0;
+ pc.ln.off += pc.ln.len + 1;
+ if ((pc.ln.dat = grep_fgetln(f, &pc.ln.len)) == NULL ||
+ pc.ln.len == 0) {
+ if (pc.ln.line_no == 0 && matchall)
+ /*
+ * An empty file with an empty pattern and the
+ * -w flag does not match
+ */
+ exit(matchall && wflag ? 1 : 0);
else
break;
}
- if (ln.len > 0 && ln.dat[ln.len - 1] == fileeol)
- --ln.len;
- ln.line_no++;
+ if (pc.ln.len > 0 && pc.ln.dat[pc.ln.len - 1] == fileeol)
+ --pc.ln.len;
+ pc.ln.line_no++;
+
/* Return if we need to skip a binary file */
- if (f->binary && binbehave == BINFILE_SKIP) {
+ if (pc.binary && binbehave == BINFILE_SKIP) {
grep_close(f);
- free(ln.file);
+ free(pc.ln.file);
free(f);
return (0);
}
- /* Process the file line-by-line, enqueue non-matching lines */
- if ((t = procline(&ln, f->binary)) == 0 && Bflag > 0) {
- /* Except don't enqueue lines that appear in -A ctx */
- if (ln.line_no == 0 || lasta != ln.line_no) {
- /* queue is maxed to Bflag number of lines */
- enqueue(&ln);
- linesqueued++;
- ctxover = false;
+ if ((t = procline(&pc)) == 0)
+ ++c;
+
+ /* Deal with any -B context or context separators */
+ if (t == 0 && doctx) {
+ if (!first_match && (!same_file || last_outed > 0))
+ printf("--\n");
+ if (Bflag > 0)
+ printqueue();
+ tail = Aflag;
+ }
+ /* Print the matching line, but only if not quiet/binary */
+ if (t == 0 && printmatch) {
+ printline(&pc, ':');
+ first_match = false;
+ same_file = true;
+ last_outed = 0;
+ }
+ if (t != 0 && doctx) {
+ /* Deal with any -A context */
+ if (tail > 0) {
+ printline(&pc, '-');
+ tail--;
+ if (Bflag > 0)
+ clearqueue();
} else {
/*
- * Indicate to procline() that we have ctx
- * overlap and make sure queue is empty.
+ * Enqueue non-matching lines for -B context.
+ * If we're not actually doing -B context or if
+ * the enqueue resulted in a line being rotated
+ * out, then go ahead and increment last_outed
+ * to signify a gap between context/match.
*/
- if (!ctxover)
- clearqueue();
- ctxover = true;
+ if (Bflag == 0 || (Bflag > 0 && enqueue(ln)))
+ ++last_outed;
}
}
- c += t;
- if (mflag && mcount <= 0)
- break;
+
+ /* Count the matches if we have a match limit */
+ if (t == 0 && mflag) {
+ --mcount;
+ if (mflag && mcount <= 0)
+ break;
+ }
+
}
if (Bflag > 0)
clearqueue();
grep_close(f);
if (cflag) {
if (!hflag)
- printf("%s:", ln.file);
+ printf("%s:", pc.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(pc.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)
+procline(struct parsec *pc)
{
- regmatch_t matches[MAX_LINE_MATCHES];
- regmatch_t pmatch, lastmatch;
+ regmatch_t pmatch, lastmatch, chkmatch;
+ wchar_t wbegin, wend;
size_t st = 0, nst = 0;
unsigned int i;
- int c = 0, m = 0, r = 0, lastmatches = 0, leflags = eflags;
- int startm = 0;
+ int c = 0, r = 0, lastmatches = 0, leflags = eflags;
+ size_t startm = 0, matchidx;
int retry;
+ matchidx = pc->matchidx;
+
+ /* Special case: empty pattern with -w flag, check first character */
+ if (matchall && wflag) {
+ if (pc->ln.len == 0)
+ return (0);
+ wend = L' ';
+ if (sscanf(&pc->ln.dat[0], "%lc", &wend) != 1 || iswword(wend))
+ return (1);
+ else
+ return (0);
+ } else if (matchall)
+ return (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) {
+ while (st <= pc->ln.len) {
lastmatches = 0;
- startm = m;
+ startm = matchidx;
retry = 0;
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;
+ pmatch.rm_eo = pc->ln.len;
#ifndef WITHOUT_FASTMATCH
if (fg_pattern[i].pattern)
r = fastexec(&fg_pattern[i],
- l->dat, 1, &pmatch, leflags);
+ pc->ln.dat, 1, &pmatch, leflags);
else
#endif
- r = regexec(&r_pattern[i], l->dat, 1,
+ r = regexec(&r_pattern[i], pc->ln.dat, 1,
&pmatch, leflags);
- r = (r == 0) ? 0 : REG_NOMATCH;
- if (r == REG_NOMATCH)
+ if (r != 0)
continue;
/* Check for full match */
- if (r == 0 && xflag)
- if (pmatch.rm_so != 0 ||
- (size_t)pmatch.rm_eo != l->len)
- r = REG_NOMATCH;
+ if (xflag && (pmatch.rm_so != 0 ||
+ (size_t)pmatch.rm_eo != pc->ln.len))
+ continue;
/* Check for whole word match */
#ifndef WITHOUT_FASTMATCH
- if (r == 0 && (wflag || fg_pattern[i].word)) {
+ if (wflag || fg_pattern[i].word) {
#else
- if (r == 0 && wflag) {
+ if (wflag) {
#endif
- wchar_t wbegin, wend;
-
wbegin = wend = L' ';
if (pmatch.rm_so != 0 &&
- sscanf(&l->dat[pmatch.rm_so - 1],
+ sscanf(&pc->ln.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],
+ pc->ln.len &&
+ sscanf(&pc->ln.dat[pmatch.rm_eo],
"%lc", &wend) != 1)
r = REG_NOMATCH;
else if (iswword(wbegin) ||
iswword(wend))
r = REG_NOMATCH;
/*
* If we're doing whole word matching and we
* matched once, then we should try the pattern
- * again after advancing just past the start of
+ * again after advancing just past the start of
* the earliest match. This allows the pattern
* to match later on in the line and possibly
* still match a whole word.
*/
if (r == REG_NOMATCH &&
(retry == 0 || pmatch.rm_so + 1 < retry))
retry = pmatch.rm_so + 1;
+ if (r == REG_NOMATCH)
+ continue;
}
- if (r == 0) {
- lastmatches++;
- lastmatch = pmatch;
- if (m == 0)
- c++;
- 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;
- }
- }
+ lastmatches++;
+ lastmatch = pmatch;
- /* matches - skip further patterns */
- if ((color == NULL && !oflag) ||
- qflag || lflag)
- break;
+ if (matchidx == 0)
+ c++;
+
+ /*
+ * Replace previous match if the new one is earlier
+ * and/or longer. This will lead to some amount of
+ * extra work if -o/--color are specified, but it's
+ * worth it from a correctness point of view.
+ */
+ if (matchidx > startm) {
+ chkmatch = pc->matches[matchidx - 1];
+ if (pmatch.rm_so < chkmatch.rm_so ||
+ (pmatch.rm_so == chkmatch.rm_so &&
+ (pmatch.rm_eo - pmatch.rm_so) >
+ (chkmatch.rm_eo - chkmatch.rm_so))) {
+ pc->matches[matchidx - 1] = pmatch;
+ nst = pmatch.rm_eo;
+ }
+ } else {
+ /* Advance as normal if not */
+ pc->matches[matchidx++] = pmatch;
+ nst = pmatch.rm_eo;
}
+ /* avoid excessive matching - skip further patterns */
+ if ((color == NULL && !oflag) || qflag || lflag ||
+ matchidx >= MAX_LINE_MATCHES)
+ break;
}
/*
* Advance to just past the start of the earliest match, try
* again just in case we still have a chance to match later in
* the string.
*/
if (lastmatches == 0 && retry > 0) {
st = retry;
continue;
}
/* One pass if we are not recording matches */
if (!wflag && ((color == NULL && !oflag) || qflag || lflag || Lflag))
break;
/* If we didn't have any matches or REG_NOSUB set */
if (lastmatches == 0 || (cflags & REG_NOSUB))
- nst = l->len;
+ nst = pc->ln.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;
}
-
+ /* Reflect the new matchidx in the context */
+ pc->matchidx = matchidx;
if (vflag)
c = !c;
-
- /* 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 && (Bflag || Aflag) &&
- !ctxover)
- printf("--\n");
- tail = Aflag;
- if (Bflag > 0) {
- printqueue();
- ctxover = false;
- }
- linesqueued = 0;
- printline(l, ':', matches, m);
- } else {
- /* Print -A lines following matches */
- lasta = l->line_no;
- printline(l, '-', matches, m);
- tail--;
- }
- }
-
- if (c) {
- prev = true;
- first = false;
- } else
- prev = false;
-
- return (c);
+ return (c ? 0 : 1);
}
/*
* 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.
+ * Print an entire line as-is, there are no inline matches to consider. This is
+ * used for printing context.
*/
-void
-printline(struct str *line, int sep, regmatch_t *matches, int m)
+void grep_printline(struct str *line, int sep) {
+ printline_metadata(line, sep);
+ fwrite(line->dat, line->len, 1, stdout);
+ putchar(fileeol);
+}
+
+static void
+printline_metadata(struct str *line, int sep)
{
- size_t a = 0;
- int i, n = 0;
+ bool printsep;
- /* If matchall, everything matches but don't actually print for -o */
- if (oflag && matchall)
- return;
-
+ printsep = false;
if (!hflag) {
if (!nullflag) {
fputs(line->file, stdout);
- ++n;
+ printsep = true;
} else {
printf("%s", line->file);
putchar(0);
}
}
if (nflag) {
- if (n > 0)
+ if (printsep)
putchar(sep);
printf("%d", line->line_no);
- ++n;
+ printsep = true;
}
if (bflag) {
- if (n > 0)
+ if (printsep)
putchar(sep);
printf("%lld", (long long)line->off);
- ++n;
+ printsep = true;
}
- if (n)
+ if (printsep)
putchar(sep);
+}
+
+/*
+ * Prints a matching line according to the command line options.
+ */
+static void
+printline(struct parsec *pc, int sep)
+{
+ size_t a = 0;
+ size_t i, matchidx;
+ regmatch_t match;
+
+ /* If matchall, everything matches but don't actually print for -o */
+ if (oflag && matchall)
+ return;
+
+ matchidx = pc->matchidx;
+
/* --color and -o */
- if ((oflag || color) && m > 0) {
- for (i = 0; i < m; i++) {
+ if ((oflag || color) && matchidx > 0) {
+ printline_metadata(&pc->ln, sep);
+ for (i = 0; i < matchidx; i++) {
+ match = pc->matches[i];
/* Don't output zero length matches */
- if (matches[i].rm_so == matches[i].rm_eo)
+ if (match.rm_so == match.rm_eo)
continue;
if (!oflag)
- fwrite(line->dat + a, matches[i].rm_so - a, 1,
+ fwrite(pc->ln.dat + a, match.rm_so - a, 1,
stdout);
- if (color)
+ 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)
+ fwrite(pc->ln.dat + match.rm_so,
+ match.rm_eo - match.rm_so, 1, stdout);
+ if (color)
fprintf(stdout, "\33[m\33[K");
- a = matches[i].rm_eo;
+ a = match.rm_eo;
if (oflag)
putchar('\n');
}
if (!oflag) {
- if (line->len - a > 0)
- fwrite(line->dat + a, line->len - a, 1, stdout);
+ if (pc->ln.len - a > 0)
+ fwrite(pc->ln.dat + a, pc->ln.len - a, 1,
+ stdout);
putchar('\n');
}
- } else {
- fwrite(line->dat, line->len, 1, stdout);
- putchar(fileeol);
- }
+ } else
+ grep_printline(&pc->ln, sep);
}
Index: stable/11
===================================================================
--- stable/11 (revision 322586)
+++ stable/11 (revision 322587)
Property changes on: stable/11
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head:r317703,317741,317842

File Metadata

Mime Type
text/x-diff
Expires
Sun, Dec 21, 3:59 PM (1 d, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27098606
Default Alt Text
(68 KB)

Event Timeline