Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F140057273
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
68 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rS FreeBSD src repository - subversion
Attached
Detach File
Event Timeline
Log In to Comment