#!/bin/ash -efu
#
# Copyright (C) 2008-2009  Alexey Gladkov <legion@altlinux.org>
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#

. shell-quote
. shell-args
. shell-getopt

all_lines=
extend=

grep_patterns=
grep_icase=

sed_patterns=
sed_icase=
sed_matches=g

show_help() {
	cat <<-EOF
	Usage: $PROG [options] PATTERN [--] [FILE...]
	   or: $PROG [options] -e PATTERN [-e PATTERN1...] [--] [FILE...]

	Pattern format:

	PATTERN := '/GREP-PATTERN/ [[TYPE] MODIFICATOR COLOR]...'

	You can use any character instead of '/'.

	TYPE    := {foreground|background} or {fg|bg}

	COLOR   := {gray|black|blue|green|cyan|red|magenta|yellow|white}

	MODIFICATORS := {bold|italic|underline|reverse} or {b|i|u|rev}

	Options:
	  -e, --pattern=PATTERN   use PATTERN as the pattern;
	  -f, --file=FILE         obtain patterns from FILE, one per line;
	  -i, --ignore-case       ignore case distinctions in the PATTERN;
	  -a, --all-lines         don't suppress unmatched lines;
	  -o, --one-match         highlight only first match of PATTERN;
	  -E, --regexp-extended   use extended regular expressions
	                          in the PATTERN;
	  -v, --verbose           print a message for each action;
	  -V, --version           print program version and exit;
	  -h, --help              show this text and exit.

	Report bugs to http://bugzilla.altlinux.org/

	EOF
	exit
}

show_version() {
	cat <<EOF
$PROG version 1.0
Written by Alexey Gladkov <legion@altlinux.org>

Copyright (C) 2008  Alexey Gladkov <legion@altlinux.org>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
	exit
}

colors_order=
setup_term_caps() {
	local cap_pair var cap

	for cap_pair in \
		set_bg:setab \
		set_bg:setb \
		set_fg:setaf \
		set_fg:setf \
		set_bold:bold \
		set_italic:sitm \
		set_uline:smul \
		set_reverse:rev \
		unset_italic:ritm \
		unset_uline:rmul \
		;
	do
		var="${cap_pair%:*}"
		cap="${cap_pair#*:}"

		eval "
		cap_$var=\"\${cap_$var-}\";
		[ -n \"\$cap_$var\" ] ||
				! tput $cap >/dev/null 2>&1 ||
				cap_$var='$cap';
		[ -n \"\$cap_$var\" ] ||
			verbose \"Capability '$cap' is not defined for this terminal.\""
	done

	[ "$cap_set_fg" = 'setf' ] &&
		colors_order='black blue green cyan red magenta yellow white' ||
		colors_order='black red green yellow blue magenta cyan white'
}

get_delim() {
	local l="$1" m=
	while [ ${#m} -lt $((${#l}-1)) ]; do
		m="$m?"
	done
	delim="${l%$m}"
}

set_color() {
	local name i=0 ctype="$1" color="$2"

	if [ -z "${color##gr[ae]y}" ]; then
		bold=1
		eval "${ctype}_color=$i"
		return
	fi

	for name in $colors_order; do
		if [ "$color" = "$name" ]; then
			eval "${ctype}_color=$i"
		fi
		i=$(($i + 1))
	done
}

parse_pattern() {
	local ctl= delim= pattern="$1"

	get_delim "$pattern"
	ctl="${pattern##*$delim}"

	local c ctype='fg'
	local bg_color= fg_color= bold= italic= uline= reverse=
	local start_color= stop_color=

	for c in $ctl; do
		case "$c" in
			fg|foreground)	ctype='fg'		;;
			bg|background)	ctype='bg'		;;
			rev|reverse)	reverse=1		;;
			b|bold)		bold=1			;;
			i|italic)	italic=1		;;
			u|underline)	uline=1			;;
			*)		set_color $ctype $c	;;
		esac
	done

	[ -z "${bold}${italic}${uline}${fg_color}${bg_color}" ] ||
		start_color="`tput -S <<EOF
${reverse:+$cap_set_reverse
}${bold:+$cap_set_bold
}${italic:+$cap_set_italic
}${uline:+$cap_set_uline
}${fg_color:+$cap_set_fg $fg_color
}${bg_color:+$cap_set_bg $bg_color
}
EOF`"
	[ -z "${start_color}" ] ||
		stop_color="`tput -S <<EOF
${italic:+$cap_unset_italic
}${uline:+$cap_unset_uline
}sgr0
EOF`"
	pattern="${pattern#$delim}"
	pattern="${pattern%$delim*}"
	pattern="$(quote_shell "$pattern")"

	[ -n "$all_lines" ] ||
		grep_patterns="$grep_patterns -e \"$pattern\""

	sed_patterns="$sed_patterns -e \"s${delim}${pattern}${delim}${start_color}&${stop_color}${delim}${sed_matches}${sed_icase}\""
}

parse_cmdline_patterns() {
	while [ "$#" -gt 0 ]; do
		parse_pattern "$1"
		shift
	done
}

pattern_strings=
read_file() {
	local l fn="$1"
	while read -r l; do
		case "$l" in
			''|'#'*) continue ;;
		esac
		pattern_strings="$pattern_strings \"$(quote_shell "$l")\""
	done < "$1"
}

TEMP=`getopt -n $PROG -o e:,a,f:,i,o,E,v,V,h -l pattern:,file:,ignore-case,all-lines,one-match,extended-regexp,verbose,version,help -- "$@"` ||
	show_usage
eval set -- "$TEMP"

while :; do
	case "$1" in
		-e|--pattern) shift
			pattern_strings="$pattern_strings \"$(quote_shell "$1")\""
			;;
		-f|--file) shift
			fn="$(opt_check_read file "$1")"
			read_file "$fn"
			;;
		-i|--ignore-case)
			sed_icase=i
			grep_icase=-i
			;;
		-a|--all-lines) all_lines=1
			;;
		-o|--one-match) sed_matches=
			;;
		-E|--extended-regexp) extend=1
			;;
		-v|--verbose) verbose=-v
			;;
		-V|--version) show_version
			;;
		-h|--help) show_help
			;;
		--) shift; break
			;;
		*) fatal "Unrecognized option: $1"
			;;
	esac
	shift
done

setup_term_caps

[ -z "$pattern_strings" ] ||
	eval parse_cmdline_patterns $pattern_strings

if [ -z "$sed_patterns" ]; then
	if [ "$#" -gt 0 ]; then
		parse_pattern "$1"; shift
	else
		show_usage
	fi
fi

if [ -n "$grep_patterns" ]; then
	eval exec grep ${extend:+-E} $grep_icase $grep_patterns ${1:+"$@"} '|' \
		sed ${extend:+-r} -n $sed_patterns -e 'p' \
		${COLOR_VIEWER:+|$COLOR_VIEWER}
else
	eval exec sed ${extend:+-r} -n $sed_patterns -e 'p' ${1:+"$@"} \
		${COLOR_VIEWER:+|$COLOR_VIEWER}
fi

exit
# 'sh --rpm-requires' need this:
ash; tput; grep; sed
