summaryrefslogblamecommitdiffstats
path: root/bin/grepc
blob: 592306df13190ff93b77fe7e093beda6181edd81 (plain) (tree)
1
2
3
4
5
6
7
8
9
           

 
           


     
     
       
     
       
     
     
     
       
       


          

           


                 

          
         










                    

         

 
           
 
                                                        
               


 
                                           








                                   
                                   


                                   


























































                                                                                      
                                 

                                          
                  

                                                                      
                     

                  
                       








                                                 


                    
                        

















                                    
   

 
























                                                                                                                                                                                                         

 



                                              

























                                                                                      
               

 
                                                                             
                                     


                     
                                              



                                                     
            
                    
            
                                                      
    

                                                                                                                     





                      
#!/bin/bash


# Defaults:
A='';
B='';
C='';
c='';
h='-H';
i='';
k='no';
l='';
m='';
n='';
r='no';
t='no';
t_e='no';
t_fp='no';
t_fd='no';
t_flp='no';
t_fld='no';
t_fgp='no';
t_fgd_libm='no';
t_fgd_libio='no';
t_mf='no';
t_mo='no';
t_r='no';
t_t_braced='no';
t_t_td_simple='no';
t_t_td_braced='no';
t_t_td_func='no';
t_ue='no';
t_uf_def='no';
t_uf_linux_def='no';
t_um='no';
t_ut_su='no';
t_ut_td_simple='no';
t_ut_td_su='no';
t_v='no';
x=''


grepc_err()
{
	>&2 printf '%s\n' "$(basename "$0"): error: $*";
	exit 1;
}


while getopts "A:B:C:chiklm:nrt:x:" opt; do
	case "$opt" in
	A)	A="-A$OPTARG";	;;&
	B)	B="-B$OPTARG";	;;&
	C)	C="-C$OPTARG";	;;&
	c)	c='-c';		;;&
	h)	h='-h';		;;&
	i)	i='-i';		;;&
	k | l)	k='yes';	;;&
	l)	l='-l';		;;&
	m)	m="-m$OPTARG";	;;&
	n)	n='-n';		;;&
	r)	r='yes';	;;&
	t)
		if [ -z "$x" ]; then
			x='c';
		fi;

		case "$x" in
		c)
			case "$OPTARG" in
			e)		t_e='yes';		;;&
			f | fp)		t_fp='yes';		;;&
			f | fd)		t_fd='yes';		;;&
			f | fl | flp)	t_flp='yes';		;;&
			f | fl | fld)	t_fld='yes';		;;&
			f | fg | fgp)	t_fgp='yes';		;;&
			f | fg | fgd)	t_fgd_libm='yes';
					t_fgd_libio='yes';	;;&
			m | mf)		t_mf='yes';		;;&
			m | mo)		t_mo='yes';		;;&
			t)		t_t_braced='yes';
					t_t_td_simple='yes';
					t_t_td_braced='yes';
					t_t_td_func='yes';	;;&
			u | ue)		t_ue='yes';		;;&
			u | uf)		t_uf_def='yes';
					t_uf_linux_def='yes';	;;&
			u | um)		t_um='yes';		;;&
			u | ut)		t_ut_su='yes';
					t_ut_td_simple='yes';
					t_ut_td_su='yes';	;;&
			[efmtu] | f[pdlg] | fl[pd] | fg[pd] | m[fo] | u[efmt])
					t='yes';
					;;
			*)
					grepc_err "-$opt: $OPTARG: Unknown argument.";
					;;
			esac;
			;;

		mk)
			case "$OPTARG" in
			r)		t_r='yes';		;;&
			v)		t_v='yes';		;;&
			[rv])
					t='yes';
					;;
			*)
					grepc_err "-$opt: $OPTARG: Unknown argument.";
					;;
			esac;
			;;
		esac;
		;;
	x)
		if [ "$t" = 'yes' ]; then
			grepc_err "-$opt: This option must come before '-t'.";
		fi;
		if [ -n "$x" ]; then
			grepc_err "-$opt: This option cannot be repeated.";
		fi;

		case "$OPTARG" in
		c)	x='c';		;;
		mk)	x='mk';		;;
		*)
			grepc_err "-$opt: $OPTARG: Unknown argument.";
			;;
		esac;
		;;
	\?)
		exit 1;
		;;
	esac;
done;
shift $((OPTIND-1));

test $# -lt 1 && grepc_err "Missing identifier.";
identifier=$1;
shift;

if [ -z "$x" ]; then
	x='c';
fi;
if [ "$t" = 'no' ]; then
	if [ "$x" = 'c' ]; then
		t_e='yes';
		t_fp='yes';
		t_fd='yes';
		t_flp='yes';
		t_fld='yes';
		t_fgp='yes';
		t_fgd_libm='yes';
		t_fgd_libio='yes';
		t_mf='yes';
		t_mo='yes';
		t_t_braced='yes';
		t_t_td_simple='yes';
		t_t_td_braced='yes';
		t_t_td_func='yes';
	elif [ "$x" = 'mk' ]; then
		t_v='yes';
	fi;
fi;


grepc_c_e()		{ printf '%s\n' '(?s)^([\w[]+[\w\s]*)?\benum\b[ \t]*([\w \t[\]]|::)*\n*([ \t]*){[^}]*^[ \t]*'"$1"'\b\s*[=,].*?^\3}.*?;'; }
grepc_c_fp()		{ printf '%s\n' '(?s)^[\w[](?:[\w\s\(,\)[\]*]|::)+[\w\s\)*\]]\s+\**\(?'"$1"'\)?\s*(\((?:[\w\s,[\]*]|::|(?1))*(?:\.\.\.)?\))(?:[\w\s\(,\)[\]]|::)*;'; }
grepc_c_fd()		{ printf '%s\n' '(?s)^[\w[](?:[\w\s\(,\)[\]*]|::)*[\w\s\)*\]]\s+\**\(?'"$1"'\)?\s*(\((?:[\w\s,[\]*]|::|(?1))*(?:\.\.\.)?\))[ \t]*\n([ \t]*){.*?^\2}'; }
grepc_c_fgd_libm()	{ grepc_c_fd "M_DECL_FUNC \(__$1\)"; }
grepc_c_fgd_libio()	{ grepc_c_fd "_IO_$1"; }
grepc_c_fgp_libio()	{ grepc_c_fp "_IO_$1"; }
grepc_c_fgp()		{ grepc_c_fgp_libio "$1"; }
grepc_c_flp()		{ printf '%s\n' '(?s)^asmlinkage\s+[\w\s]+\**sys_'"$1"'\s*\(.*?\)'; }
grepc_c_fld()		{ printf '%s\n' '(?s)^(COMPAT_)?SYSCALL_DEFINE.\('"$1"'\b.*?^}'; }
grepc_c_mf()		{ printf '%s\n' '(?s)^[ \t]*#\s*define\s[\s\\]*'"$1"'\(.*?[^\\]$'; }
grepc_c_mo()		{ printf '%s\n' '(?s)^[ \t]*#\s*define\s[\s\\]*'"$1"'\b(?!\().*?(?<!\\)$'; }
grepc_c_t_braced()	{ printf '%s\n' '(?s)^([\w[]([\w\s\(,\)[\]*]|::)*[\w\s\)*\]]\s+)?\b(struct|union|enum)\b([\w \t[\]]|::)+\b'"$1"'\b[ \t]*\n*([ \t]*){.*?^\5}.*?;'; }
grepc_c_t_td_simple()	{ printf '%s\n' '(?s)^[ \t]*typedef\s+[^{};]+'"$1"';'; }
grepc_c_t_td_braced()	{ printf '%s\n' '(?s)^[ \t]*typedef\s+(struct|union|enum)\b(?:(?!\W'"$1"'\W)([\w \t[\]]|::))*\n*([ \t]*){(?:(?!^\3?}).)*?^\3}\s*'"$1"'(\[[\w\(,\)]\])*;'; }
grepc_c_t_td_func()	{ printf '%s\n' '(?s)^[ \t]*typedef\s+[^{};]+\(\**'"$1"'\)\s*\([^{};]+;'; }
grepc_c_ue()		{ printf '%s\n' '(?s)^([\w[]+[\w\s]*)?\benum\b([\w \t[\]]|::)*\n*([ \t]*){[^}]*^\s*\w+[\w\s[\]=]*'"$1"'.*?^\3}.*?;'; }
grepc_c_uf_def()	{ printf '%s\n' '(?s)^[\w[]([\w\s\(,\)[\]*]|::)*[\w\s\)*\]]\s+\**\w+\s*\(([\w\s\(,\)[\]*]|::)+?(\.\.\.)?\)[ \t]*\n*([ \t]*){(?:(?!^\4?}).)*'"$1"'.*?^\4}'; }
grepc_c_uf_linux_def()	{ printf '%s\n' '(?s)^(COMPAT_)?SYSCALL_DEFINE.\(\w+\b(?:(?!^}).)*'"$1"'.?^}'; }
grepc_c_um()		{ printf '%s\n' '(?s)^[ \t]*#\s*define\s[\s\\]*\w+\b(\([^\)]*\))?(?:(?![^\\]$).)*'"$1"'.*?[^\\]$'; }
grepc_c_ut_su()		{ printf '%s\n' '(?s)^(?!^[ \t]*typedef\b)([\w[]([\w\s\(,\)[\]*]|::)*[\w\s\)*\]]\s+)?\b(struct|union)\b([\w \t[\]]|::)*\w+[ \t]*\n*([ \t]*){(?:(?!^\5?}).)*?'"$1"'.*?^\5}.*?;'; }
grepc_c_ut_td_simple()	{ printf '%s\n' '(?s)^[ \t]*typedef\s+[^{};]*'"$1"'[^{};]+;'; }
grepc_c_ut_td_su()	{ printf '%s\n' '(?s)^[ \t]*typedef\s+(struct|union)\b([\w \t[\]]|::)*\n*([ \t]*){(?:(?!^\3?}|^\s*typedef).)*'"$1"'(?:(?!^\3?}|^\s*typedef).)*^\3}\s*\w+;'; }

grepc_mk_r()		{ printf '%s\n' '(?s)^(\$\()?'"$1"'\)?\s*:[^=].*?(?<!\\)$(?:(?!^[^\t]).)*'; }
grepc_mk_v()		{ printf '%s\n' '(?s)^'"$1"'\s*[:?+]*=.*?(?<!\\)$'; }


patterns="$(mktemp -t grepc.patterns.XXXXXX)";


(
	if [ "$x" = 'c' ]; then
		test $t_e = yes			&& grepc_c_e "$identifier";
		test $t_fp = yes		&& grepc_c_fp "$identifier";
		test $t_fd = yes		&& grepc_c_fd "$identifier";
		test $t_flp = yes		&& grepc_c_flp "$identifier";
		test $t_fld = yes		&& grepc_c_fld "$identifier";
		test $t_fgp = yes		&& grepc_c_fgp "$identifier";
		test $t_fgd_libm = yes		&& grepc_c_fgd_libm "$identifier";
		test $t_fgd_libio = yes		&& grepc_c_fgd_libio "$identifier";
		test $t_mf = yes		&& grepc_c_mf "$identifier";
		test $t_mo = yes		&& grepc_c_mo "$identifier";
		test $t_t_braced = yes		&& grepc_c_t_braced "$identifier";
		test $t_t_td_simple = yes	&& grepc_c_t_td_simple "$identifier";
		test $t_t_td_braced = yes	&& grepc_c_t_td_braced "$identifier";
		test $t_t_td_func = yes		&& grepc_c_t_td_func "$identifier";
		test $t_ue = yes		&& grepc_c_ue "$identifier";
		test $t_uf_def = yes		&& grepc_c_uf_def "$identifier";
		test $t_uf_linux_def = yes	&& grepc_c_uf_linux_def "$identifier";
		test $t_um = yes		&& grepc_c_um "$identifier";
		test $t_ut_su = yes		&& grepc_c_ut_su "$identifier";
		test $t_ut_td_simple = yes	&& grepc_c_ut_td_simple "$identifier";
		test $t_ut_td_su = yes		&& grepc_c_ut_td_su "$identifier";
	elif [ "$x" = 'mk' ]; then
		test $t_r = yes			&& grepc_mk_r "$identifier";
		test $t_v = yes			&& grepc_mk_v "$identifier";
	fi;
) >"$patterns";


# shellcheck disable=SC2206  # We want only non-empty variables in the array.
opts=($A $B $C $c $h $i $l -M $m $n);


if test -z "$*"; then
	pcre2grep "${opts[@]}" -f "$patterns";
else
	find "$@" -type f \
	| if test -z "$c"; then
		xargs grep -${i}lPI -- "$identifier";
	else
		cat;
	fi \
	| xargs pcre2grep "${opts[@]}" -f "$patterns";
fi \
| sed -E -f <(test "$k" = 'no' && printf '%s\n' 's/^[^: ]+:[0-9]+:/\n\n&\n/') \
| perl -pe "$(test "$r" = 'yes' && printf '%s\n' 's/('"$identifier"')/\033[32m\1\033[0m/' || printf '%s\n' 's///')" \
| if [ -n "$l" ]; then
	sort \
	| uniq;
else
	cat;
fi;