1*f58316a4SAndrew Jones#!/usr/bin/env perl 2*f58316a4SAndrew Jones# SPDX-License-Identifier: GPL-2.0 3*f58316a4SAndrew Jones 4*f58316a4SAndrew Jonesuse warnings; 5*f58316a4SAndrew Jonesuse strict; 6*f58316a4SAndrew Jones 7*f58316a4SAndrew Jonesmy $srctree = shift @ARGV; 8*f58316a4SAndrew Jonesunless (defined $srctree) { 9*f58316a4SAndrew Jones $srctree = `git rev-parse --show-toplevel 2>/dev/null`; 10*f58316a4SAndrew Jones chomp $srctree; 11*f58316a4SAndrew Jones my $msg = "Usage: $0 <srctree> [excludes file]\n"; 12*f58316a4SAndrew Jones $msg .= "Please provide <srctree>."; 13*f58316a4SAndrew Jones $msg .= " Is it '$srctree'?" if $srctree; 14*f58316a4SAndrew Jones $msg .= "\n"; 15*f58316a4SAndrew Jones die $msg; 16*f58316a4SAndrew Jones} 17*f58316a4SAndrew Jonesmy $kconfig_sym_check_excludes = defined $ARGV[0] ? $ARGV[0] : undef; 18*f58316a4SAndrew Jones 19*f58316a4SAndrew Jonessub indent_depth { 20*f58316a4SAndrew Jones my ($ws) = @_; 21*f58316a4SAndrew Jones my $col = 0; 22*f58316a4SAndrew Jones for my $c (split //, $ws) { 23*f58316a4SAndrew Jones $col = $c eq "\t" ? int($col / 8) * 8 + 8 : $col + 1; 24*f58316a4SAndrew Jones } 25*f58316a4SAndrew Jones return $col; 26*f58316a4SAndrew Jones} 27*f58316a4SAndrew Jones 28*f58316a4SAndrew Jonesmy @files = `git -C \Q$srctree\E ls-files '*Kconfig*' 2>/dev/null`; 29*f58316a4SAndrew Jonesif (@files) { 30*f58316a4SAndrew Jones chomp @files; 31*f58316a4SAndrew Jones @files = map { "$srctree/$_" } @files; 32*f58316a4SAndrew Jones} else { 33*f58316a4SAndrew Jones @files = `find \Q$srctree\E -name '*Kconfig*'`; 34*f58316a4SAndrew Jones chomp @files; 35*f58316a4SAndrew Jones} 36*f58316a4SAndrew Jones 37*f58316a4SAndrew Jones@files = grep { !m{/scripts/kconfig/tests/} } @files; 38*f58316a4SAndrew Jones 39*f58316a4SAndrew Jonesmy %configs = (); 40*f58316a4SAndrew Jonesmy %refs = (); 41*f58316a4SAndrew Jones 42*f58316a4SAndrew Jonesforeach my $file (@files) { 43*f58316a4SAndrew Jones open F, $file or die "Cannot open $file: $!"; 44*f58316a4SAndrew Jones 45*f58316a4SAndrew Jones my $help = 0; 46*f58316a4SAndrew Jones my $help_level; 47*f58316a4SAndrew Jones my $level; 48*f58316a4SAndrew Jones 49*f58316a4SAndrew Jones while (<F>) { 50*f58316a4SAndrew Jones chomp; 51*f58316a4SAndrew Jones 52*f58316a4SAndrew Jones while (/\\\s*$/) { 53*f58316a4SAndrew Jones s/\\\s*$/ /; 54*f58316a4SAndrew Jones my $cont = <F> // last; 55*f58316a4SAndrew Jones chomp $cont; 56*f58316a4SAndrew Jones $_ .= $cont; 57*f58316a4SAndrew Jones } 58*f58316a4SAndrew Jones 59*f58316a4SAndrew Jones next if /^\s*$/; 60*f58316a4SAndrew Jones next if /^\s*#/; 61*f58316a4SAndrew Jones 62*f58316a4SAndrew Jones /^(\s*)/; 63*f58316a4SAndrew Jones $level = indent_depth($1); 64*f58316a4SAndrew Jones 65*f58316a4SAndrew Jones if ($help && $level < $help_level) { 66*f58316a4SAndrew Jones $help = 0; 67*f58316a4SAndrew Jones } 68*f58316a4SAndrew Jones 69*f58316a4SAndrew Jones next if ($help); 70*f58316a4SAndrew Jones 71*f58316a4SAndrew Jones if (/^\s*(help|\-\-\-help\-\-\-)$/) { 72*f58316a4SAndrew Jones $help = 1; 73*f58316a4SAndrew Jones my $next; 74*f58316a4SAndrew Jones while (defined($next = <F>)) { 75*f58316a4SAndrew Jones last unless $next =~ /^\s*(?:#.*)?$/; 76*f58316a4SAndrew Jones } 77*f58316a4SAndrew Jones last unless defined $next; 78*f58316a4SAndrew Jones $next =~ /^(\s*)/; 79*f58316a4SAndrew Jones if (indent_depth($1) >= $level) { 80*f58316a4SAndrew Jones $help_level = indent_depth($1); 81*f58316a4SAndrew Jones } else { 82*f58316a4SAndrew Jones $help = 0; 83*f58316a4SAndrew Jones } 84*f58316a4SAndrew Jones $_ = $next; 85*f58316a4SAndrew Jones redo; 86*f58316a4SAndrew Jones } 87*f58316a4SAndrew Jones 88*f58316a4SAndrew Jones if (/^\s*(config|menuconfig)\s+([a-zA-Z0-9_]+)\s*(#.*)?$/) { 89*f58316a4SAndrew Jones $configs{$2}++; 90*f58316a4SAndrew Jones next; 91*f58316a4SAndrew Jones } 92*f58316a4SAndrew Jones 93*f58316a4SAndrew Jones if (/^\s*(default|def_bool|def_tristate|select|depends\s+on|imply|visible\s+if|range|if|bool|tristate|int|hex|string|prompt)\s+(.+)\s*$/) { 94*f58316a4SAndrew Jones my $s = $2; 95*f58316a4SAndrew Jones $s =~ s/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'//g; 96*f58316a4SAndrew Jones $s =~ s/#.*//; 97*f58316a4SAndrew Jones $s =~ s/\$\((?:[^()]*|\((?:[^()]*|\([^()]*\))*\))*\)//g; 98*f58316a4SAndrew Jones $s =~ s/%%[^%]*%%//g; 99*f58316a4SAndrew Jones my @syms = split /[^a-zA-Z0-9_]+/, $s; 100*f58316a4SAndrew Jones map { 101*f58316a4SAndrew Jones $refs{$_}++ if (/[a-zA-Z]/ && $_ ne "if" && $_ ne "y" && $_ ne "n" && $_ ne "m" && !/^0[xX][0-9a-fA-F]+$/); 102*f58316a4SAndrew Jones } @syms 103*f58316a4SAndrew Jones } 104*f58316a4SAndrew Jones } 105*f58316a4SAndrew Jones 106*f58316a4SAndrew Jones close F; 107*f58316a4SAndrew Jones} 108*f58316a4SAndrew Jones 109*f58316a4SAndrew Jonesmy %known_syms = (); 110*f58316a4SAndrew Jonesif (defined $kconfig_sym_check_excludes) { 111*f58316a4SAndrew Jones my $file = $kconfig_sym_check_excludes; 112*f58316a4SAndrew Jones open(F, "<", $file) or die "Cannot open $file: $!"; 113*f58316a4SAndrew Jones while (<F>) { 114*f58316a4SAndrew Jones chomp; 115*f58316a4SAndrew Jones next if /^\s*$/; 116*f58316a4SAndrew Jones next if /^\s*#/; 117*f58316a4SAndrew Jones $known_syms{$1}++ if (/^\s*([a-zA-Z0-9_]+)\s*(#.*)?$/); 118*f58316a4SAndrew Jones } 119*f58316a4SAndrew Jones} 120*f58316a4SAndrew Jones 121*f58316a4SAndrew Jonesmy $ret = 0; 122*f58316a4SAndrew Jonesforeach my $k (sort keys %refs) { 123*f58316a4SAndrew Jones next if (exists $configs{$k} || exists $known_syms{$k}); 124*f58316a4SAndrew Jones 125*f58316a4SAndrew Jones print "$k"; 126*f58316a4SAndrew Jones print " - warning: '$k' is probably not what you want; Kconfig tristate literals are always lowercase ('n', 'y', 'm')" if ($k eq "N" || $k eq "Y" || $k eq "M"); 127*f58316a4SAndrew Jones print "\n"; 128*f58316a4SAndrew Jones 129*f58316a4SAndrew Jones $ret = 1; 130*f58316a4SAndrew Jones} 131*f58316a4SAndrew Jones 132*f58316a4SAndrew Jonesexit $ret; 133