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

 
           
         
              
          
           




             

 

             
                                                            




                 
                                       
                              


                                  



                                    


                                    




















                                              


                                      







                                        
                             



                                




                             
 

 
                  
 

                                            
                                   
                                    
            
                                    
            
                          




                                  
              


                                        
                
                                             




                                                    


 
                     
 
                      
                     

                                                                             


 
                 
 
                      
                       
               
                                                                                                              


 
                
 
                      
                       
               
                                                                                                      


 
                               
 
                      
                                                 
               
                                                         


 
                              
 
                      
                                   
               
                                                      


 
                  
 

                                           


 
                       




                                              






                                   
 




























                                                     


 
                              
 
                      
                                          
               
                                                                                                                                    


 
                           
 
                      
                              
                   
                                            


 
                                      
 
                      
                                                          
                           
                                                                                                  


 
                                                 
 
                                                                                
                                                                 
                                                                           
                             

                                                     



             
                    
 
                                       

                                                             


 
            
 

                                          


 
                      
 

                                 
                         



                        





















                                                 
      
 
                           
                                       
                                    
                          


 
        
#!/bin/sh


# Defaults:
git='no';
ext='\.[ch]$';
FILES='.';
kflag='no';
tflag='no';
t_enum='no';
t_func='no';
t_macro='no';
t_type='no';


grepc_usage()
{
	echo "Usage: $0 [OPTION ...] IDENTIFIER [FILE ...]";
}


grepc_parse_cmd()
{
	while getopts "ghkt:x:" opt; do
		case "$opt" in
		g)
			git='yes';
			;;
		h)
			grepc_usage;
			exit 0;
			;;
		k)
			kflag='yes';
			;;
		t)
			case "$OPTARG" in
			e)
				t_enum='yes';
				;;
			f)
				t_func='yes';
				;;
			m)
				t_macro='yes';
				;;
			t)
				t_type='yes';
				;;
			*)
				grepc_usage;
				exit 1;
				;;
			esac;
			tflag='yes';
			;;
		x)
			ext="$OPTARG";
			;;
		?)
			grepc_usage >&2;
			exit 1;
			;;
		esac;
	done;
	shift $(($OPTIND-1));

	if [ $# -lt 1 ]; then
		grepc_usage >&2;
		exit 1;
	fi;
	identifier=$1;
	shift;

	if [ $# -gt 0 ]; then
		FILES=$@;
	fi;
}


grepc_find_files()
{
	files="$(mktemp -t 'grepc.XXXXXX')";

	if [ "$git" = 'yes' ]; then
		git ls-files $FILES;
	else
		find $FILES -type f;
	fi \
	| grep -P "$ext" \
	| xargs grep -lPI "$1\b" \
	>"$files";
}


grepc_helper()
{
	xargs grep -lPI "$1" <"$files" \
	| xargs grep -lP  "$2" \
	| sort \
	| xargs pcregrep -Mn "$3" /dev/null \
	| if [ "$kflag" = 'no' ]; then
		sed -E 's/^[^: ]+:[0-9]+:/\n\n&\n/';
	else
		cat;
	fi;
}


grepc_enum_constant()
{
	grepc_helper \
	  '^enum\s' \
	  "^[ \t]*$1\s*[,=]" \
	  "(?s)\benum\b\s*([\w\s[\]]|::)*\s*{[^}]*^[ \t]*$1\s*[=,].*?^}.*?;";
}


grepc_func_decl()
{
	grepc_helper \
	  "\b$1\s*\(" \
	  '.' \
	  "(?s)^[\w[]([\w\s\(,\)[\]*]|::)+[\w\s\)*\]]\s+\**$1\s*\([\w\s\(,\)[\]*]+?(...)?\)[\w\s\(,\)[:\]]*;";
}


grepc_func_def()
{
	grepc_helper \
	  "\b$1\s*\(" \
	  '.' \
	  "(?s)^[\w[]([\w\s\(,\)[\]*]|::)*[\w\s\)*\]]\s+\**$1\s*\([\w\s\(,\)[\]*]+?(...)?\)\s*{.*?^}";
}


grepc_linux_func_syscall_decl()
{
	grepc_helper \
	  "^asmlinkage\s+[\w\s]+\**sys_$1\s*\(" \
	  '.' \
	  "(?s)^asmlinkage\s+[\w\s]+\**sys_$1\s*\(.*?\)";
}


grepc_linux_func_syscall_def()
{
	grepc_helper \
	  "SYSCALL_DEFINE.\($1\b" \
	  '.' \
	  "(?s)^(COMPAT_)?SYSCALL_DEFINE.\($1\b.*?^}";
}


grepc_linux_func()
{
	grepc_linux_func_syscall_decl "$1";
	grepc_linux_func_syscall_def "$1";
}


grepc_glibc_func_math()
{
	grepc_func_def "M_DECL_FUNC \(__$1\)";
}


grepc_glibc_func()
{
	grepc_glibc_func_math "$1";
}


grepc_func()
{
	grepc_func_decl "$1";
	grepc_func_def "$1";
	grepc_linux_func "$1";
	grepc_glibc_func "$1";
}


grepc_macro_simple()
{
	grepc_helper \
	  "#\s*define\s+$1\b[^(]" \
	  '.' \
	  '(?s)#\s*define\s+'"$1"'\b(?!\().*?[^\\]$';
}


grepc_macro_func()
{
	grepc_helper \
	  "#\s*define\s+$1\(" \
	  '.' \
	  '(?s)#\s*define\s+'"$1"'\(.*?[^\\]$';
}


grepc_macro()
{
	grepc_macro_simple "$1";
	grepc_macro_func "$1";
}


grepc_type_struct_union_enum()
{
	grepc_helper \
	  "\b(struct|union|enum)\s+$1\b" \
	  '.' \
	  "(?s)^(?!^[ \t]*typedef\b)([\w[]([\w\s\(,\)[\]*]|::)*[\w\s\)*\]]\s+)?\b(struct|union|enum)\s+$1\b\s*[\w\s[\]]*{.*?^}.*?;";
}


grepc_type_typedef_simple()
{
	grepc_helper \
	  '^[ \t]*typedef\s' \
	  "\b$1;" \
	  "(?s)^[ \t]*typedef\s+[^{};]+$1;";
}


grepc_type_typedef_struct_union_enum()
{
	grepc_helper \
	  '^[ \t]*typedef\s+(struct|union|enum)\b[^;]*$' \
	  "^(  )?}\s*$1;" \
	  "(?s)^[ \t]*typedef\s+(struct|union|enum)\s+(?:(?!^(  )?}|^\s*typedef).)*^(  )?}\s*$1;";
}


grepc_type_typedef_underlying_struct_union_enum()
{
	xargs grep -hP "^\s*typedef\s+(struct|union|enum)\s+.*\b$1;" <"$files" \
	| sed -E -e 's/^\s*typedef\s+//' -e "s/\s*\**\b$1;.*//" \
	| sed -E -e 's/^struct\s+//' -e 's/^union\s+//' -e 's/^enum\s+//' \
	| while read -r t; do
		test "$1" != "$t" \
		&& grepc_type_struct_union_enum "$t";
	done;
}


grepc_type_typedef()
{
	grepc_type_typedef_simple "$1";
	grepc_type_typedef_struct_union_enum "$1";
	grepc_type_typedef_underlying_struct_union_enum "$1";
}


grepc_type()
{
	grepc_type_struct_union_enum "$1";
	grepc_type_typedef "$1";
}


grepc_search_default()
{
	grepc_enum_constant "$1";
	grepc_func "$1";
	grepc_macro "$1";
	grepc_type "$1";
}


grepc_search()
{
	if [ "$tflag" = 'no' ]; then
		grepc_search_default "$1";

	else
		if [ "$t_enum" = 'yes' ]; then
			grepc_enum_constant "$1";
		fi;
		if [ "$t_func" = 'yes' ]; then
			grepc_func "$1";
		fi;
		if [ "$t_macro" = 'yes' ]; then
			grepc_macro "$1";
		fi;
		if [ "$t_type" = 'yes' ]; then
			grepc_type "$1";
		fi;
	fi;
}


main()
{
	grepc_parse_cmd $@;
	grepc_find_files "$identifier";
	grepc_search "$identifier" \
	| sed -n '/./,$p';
}


main $@;