blob: 9c9a8a926de27fd4ba3c2f54c63e6414c34d07e5 [file] [log] [blame]
Yegor Timoshenkoc2e49412018-10-07 01:58:27 +00001#!/usr/bin/env perl
Martin Rothbcaaad12015-10-18 11:16:25 -06002#
Patrick Georgi7333a112020-05-08 20:48:04 +02003# SPDX-License-Identifier: GPL-2.0-only
4
Martin Roth1b44f7e2016-01-11 14:31:38 -07005# perltidy -l=123
Martin Rothbcaaad12015-10-18 11:16:25 -06006
7package kconfig_lint;
8
9use strict;
10use warnings;
11use English qw( -no_match_vars );
12use File::Find;
13use Getopt::Long;
14use Getopt::Std;
15
Martin Rothabf7d4d2016-02-19 10:24:25 -070016# If taint mode is enabled, Untaint the path - git and grep must be in /bin, /usr/bin or /usr/local/bin
17if ( ${^TAINT} ) {
18 $ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
19 delete @ENV{ 'IFS', 'CDPATH', 'ENV', 'BASH_ENV' };
20}
21
Martin Roth1b44f7e2016-01-11 14:31:38 -070022my $suppress_error_output = 0; # flag to prevent error text
23my $suppress_warning_output = 0; # flag to prevent warning text
24my $show_note_output = 0; # flag to show minor notes text
25my $print_full_output = 0; # flag to print wholeconfig output
26my $output_file = "-"; # filename of output - set stdout by default
Martin Rothd8080172015-11-26 19:12:44 -070027my $dont_use_git_grep = 0;
Martin Rothbcaaad12015-10-18 11:16:25 -060028
Martin Rothabf7d4d2016-02-19 10:24:25 -070029# Globals
Martin Roth1b44f7e2016-01-11 14:31:38 -070030my $top_dir = "."; # Directory where Kconfig is run
31my $root_dir = "src"; # Directory of the top level Kconfig file
32my $errors_found = 0; # count of errors
Martin Rothd8080172015-11-26 19:12:44 -070033my $warnings_found = 0;
Martin Roth63ea4932016-01-25 16:08:27 -070034my $exclude_dirs_and_files =
Martin Rothab273d32016-11-23 17:28:00 -070035 '^build/\|^coreboot-builds/\|^configs/\|^util/\|^\.git/\|^payloads\|^Documentation\|^3rdparty'
Martin Roth63ea4932016-01-25 16:08:27 -070036 . '\|' . # directories to exclude when searching for used symbols
Martin Rothb357e532022-11-22 14:47:12 -070037 '\.config\|\.txt$\|\.tex$\|\.tags\|/kconfig.h\|\.fmd'; #files to exclude when looking for symbols
Martin Rothe69c58d2016-11-15 21:08:42 -070038my $payload_files_to_check='payloads/Makefile.inc payloads/external/Makefile.inc';
Martin Roth08cf90f2016-01-25 19:54:16 -070039my $config_file = ""; # name of config file to load symbol values from.
40my @wholeconfig; # document the entire kconfig structure
41my %loaded_files; # list of each Kconfig file loaded
42my %symbols; # main structure of all symbols declared
43my %referenced_symbols; # list of symbols referenced by expressions or select statements
44my %used_symbols; # structure of symbols used in the tree, and where they're found
45my @collected_symbols; #
46my %selected_symbols; # list of symbols that are enabled by a select statement
Martin Rothbcaaad12015-10-18 11:16:25 -060047
Martin Roth6bfbf1c2016-01-25 16:12:49 -070048my $exclude_unused = '_SPECIFIC_OPTIONS|SOUTH_BRIDGE_OPTIONS';
49
Martin Rothbcaaad12015-10-18 11:16:25 -060050Main();
51
52#-------------------------------------------------------------------------------
53# Main
54#
55# Start by loading and parsing the top level Kconfig, this pulls in the other
56# files. Parsing the tree creates several arrays and hashes that can be used
57# to check for errors
58#-------------------------------------------------------------------------------
59sub Main {
60
Solomon Alan-Deia6e60f02022-08-11 11:13:28 -060061 check_arguments();
62 if ( !($dont_use_git_grep || `git rev-parse --is-inside-work-tree`) ) {
63 $dont_use_git_grep = 1;
64 print STDERR "\nGit grep unavailable, falling back to regular grep...\n";
65 }
66
Martin Rothbcaaad12015-10-18 11:16:25 -060067 open( STDOUT, "> $output_file" ) or die "Can't open $output_file for output: $!\n";
68
Martin Roth1b44f7e2016-01-11 14:31:38 -070069 if ( defined $top_dir ) {
70 chdir $top_dir or die "Error: can't cd to $top_dir\n";
Martin Rothbcaaad12015-10-18 11:16:25 -060071 }
72
Martin Roth1b44f7e2016-01-11 14:31:38 -070073 die "Error: $top_dir/$root_dir does not exist.\n" unless ( -d $root_dir );
Martin Rothbcaaad12015-10-18 11:16:25 -060074
75 #load the Kconfig tree, checking what we can and building up all the hash tables
76 build_and_parse_kconfig_tree("$root_dir/Kconfig");
77
Martin Rothbcaaad12015-10-18 11:16:25 -060078 load_config($config_file) if ($config_file);
79
Martin Roth08705f12016-11-09 14:27:00 -070080 check_type();
Martin Rothbcaaad12015-10-18 11:16:25 -060081 check_defaults();
82 check_referenced_symbols();
83
84 collect_used_symbols();
85 check_used_symbols();
86 check_for_ifdef();
87 check_for_def();
Nico Huberec017592019-04-06 16:09:46 +020088 check_config_macro();
Martin Rothb7c39b22016-01-14 09:04:53 -070089 check_selected_symbols();
Martin Rothbcaaad12015-10-18 11:16:25 -060090
Martin Rothabf7d4d2016-02-19 10:24:25 -070091 # Run checks based on the data that was found
92 if ( ( !$suppress_warning_output ) && ( ${^TAINT} == 0 ) ) {
93
94 # The find function is tainted - only run it if taint checking
95 # is disabled and warnings are enabled.
96 find( \&check_if_file_referenced, $root_dir );
97 }
98
Martin Rothbcaaad12015-10-18 11:16:25 -060099 print_wholeconfig();
100
Martin Rothd8080172015-11-26 19:12:44 -0700101 if ($errors_found) {
102 print "# $errors_found errors";
Martin Roth1b44f7e2016-01-11 14:31:38 -0700103 if ($warnings_found) {
Martin Rothd8080172015-11-26 19:12:44 -0700104 print ", $warnings_found warnings";
105 }
Martin Roth1b44f7e2016-01-11 14:31:38 -0700106 print "\n";
Martin Rothd8080172015-11-26 19:12:44 -0700107 }
108
Martin Roth1b44f7e2016-01-11 14:31:38 -0700109 exit( $errors_found + $warnings_found );
Martin Rothd8080172015-11-26 19:12:44 -0700110}
111
112#-------------------------------------------------------------------------------
113# Print and count errors
114#-------------------------------------------------------------------------------
115sub show_error {
116 my ($error_msg) = @_;
117 unless ($suppress_error_output) {
118 print "#!!!!! Error: $error_msg\n";
119 $errors_found++;
120 }
121}
122
123#-------------------------------------------------------------------------------
124# Print and count warnings
125#-------------------------------------------------------------------------------
126sub show_warning {
127 my ($warning_msg) = @_;
128 unless ($suppress_warning_output) {
129 print "#!!!!! Warning: $warning_msg\n";
130 $warnings_found++;
131 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600132}
133
134#-------------------------------------------------------------------------------
Martin Rothb7c39b22016-01-14 09:04:53 -0700135# check selected symbols for validity
136# they must be bools
137# they cannot select symbols created in 'choice' blocks
138#-------------------------------------------------------------------------------
139sub check_selected_symbols {
140
141 #loop through symbols found in expressions and used by 'select' keywords
142 foreach my $symbol ( sort ( keys %selected_symbols ) ) {
143 my $type_failure = 0;
144 my $choice_failure = 0;
145
146 #errors selecting symbols that don't exist are already printed, so we
147 #don't need to print them again here
148
149 #make sure the selected symbols are bools
150 if ( ( exists $symbols{$symbol} ) && ( $symbols{$symbol}{type} ne "bool" ) ) {
151 $type_failure = 1;
152 }
153
154 #make sure we're not selecting choice symbols
155 if ( ( exists $symbols{$symbol} ) && ( $symbols{$symbol}{choice} ) ) {
156 $choice_failure = 1;
157 }
158
159 #loop through each instance of the symbol to print out all of the failures
160 for ( my $i = 0 ; $i <= $referenced_symbols{$symbol}{count} ; $i++ ) {
161 next if ( !exists $selected_symbols{$symbol}{$i} );
162 my $file = $referenced_symbols{$symbol}{$i}{filename};
163 my $lineno = $referenced_symbols{$symbol}{$i}{line_no};
164 if ($type_failure) {
165 show_error(
166 "CONFIG_$symbol' selected at $file:$lineno." . " Selects only work on symbols of type bool." );
167 }
168 if ($choice_failure) {
169 show_error(
170 "'CONFIG_$symbol' selected at $file:$lineno." . " Symbols created in a choice cannot be selected." );
171 }
172 }
173 }
174}
175
176#-------------------------------------------------------------------------------
Martin Rothbcaaad12015-10-18 11:16:25 -0600177# check_for_ifdef - Look for instances of #ifdef CONFIG_[symbol_name] and
178# #if defined(CONFIG_[symbol_name]).
179#
180# #ifdef symbol is valid for strings, but bool, hex, and INT are always defined.
181# #if defined(symbol) && symbol is also a valid construct.
182#-------------------------------------------------------------------------------
183sub check_for_ifdef {
184 my @ifdef_symbols = @collected_symbols;
185
186 #look for #ifdef SYMBOL
187 while ( my $line = shift @ifdef_symbols ) {
Julius Werneref7a3262019-03-05 16:57:52 -0800188 if ( $line =~ /^([^:]+):(\d+):\s*#\s*ifn?def\s*\(?\s*CONFIG(?:_|\()(\w+)/ ) {
Martin Roth5b883012017-06-25 20:27:36 -0600189 my $file = $1;
190 my $lineno = $2;
191 my $symbol = $3;
192
193 if ( ( exists $symbols{$symbol} ) && ( $symbols{$symbol}{type} ne "string" ) ) {
Julius Wernere5eb2de2019-03-05 17:10:19 -0800194 show_error( "#ifdef 'CONFIG_$symbol' used at $file:$lineno."
Martin Roth5b883012017-06-25 20:27:36 -0600195 . " Symbols of type '$symbols{$symbol}{type}' are always defined." );
196 }
Julius Wernere5eb2de2019-03-05 17:10:19 -0800197 } elsif ( $line =~ /^([^:]+):(\d+):.+defined\s*\(?\s*CONFIG(?:_|\()(\w+)/ ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -0700198 my $file = $1;
Martin Rothbcaaad12015-10-18 11:16:25 -0600199 my $lineno = $2;
200 my $symbol = $3;
201
Martin Roth1b44f7e2016-01-11 14:31:38 -0700202 if ( ( exists $symbols{$symbol} ) && ( $symbols{$symbol}{type} ne "string" ) ) {
Julius Wernere5eb2de2019-03-05 17:10:19 -0800203 show_error( "defined(CONFIG_$symbol) used at $file:$lineno."
Martin Roth1b44f7e2016-01-11 14:31:38 -0700204 . " Symbols of type '$symbols{$symbol}{type}' are always defined." );
Martin Rothbcaaad12015-10-18 11:16:25 -0600205 }
206 }
207 }
208}
209
210#-------------------------------------------------------------------------------
211# check_for_def - Look for instances of #define CONFIG_[symbol_name]
212#
213# Symbols should not be redefined outside of Kconfig, and #defines should not
214# look like symbols
215#-------------------------------------------------------------------------------
216sub check_for_def {
217 my @def_symbols = @collected_symbols;
218
219 #look for #ifdef SYMBOL
220 while ( my $line = shift @def_symbols ) {
221 if ( $line =~ /^([^:]+):(\d+):\s*#\s*define\s+CONFIG_(\w+)/ ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -0700222 my $file = $1;
Martin Rothbcaaad12015-10-18 11:16:25 -0600223 my $lineno = $2;
224 my $symbol = $3;
225
Martin Roth1b44f7e2016-01-11 14:31:38 -0700226 if ( ( exists $symbols{$symbol} ) ) {
Julius Wernere5eb2de2019-03-05 17:10:19 -0800227 show_error("#define of symbol 'CONFIG_$symbol' used at $file:$lineno.");
Martin Roth1b44f7e2016-01-11 14:31:38 -0700228 }
229 else {
Julius Wernere5eb2de2019-03-05 17:10:19 -0800230 show_error( "#define 'CONFIG_$symbol' used at $file:$lineno."
Martin Roth1b44f7e2016-01-11 14:31:38 -0700231 . " Other #defines should not look like Kconfig symbols." );
232 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600233 }
234 }
235}
236
237#-------------------------------------------------------------------------------
Martin Roth08705f12016-11-09 14:27:00 -0700238# check_type - Make sure that all symbols have a type defined.
239#
240# Conflicting types are found when parsing the Kconfig tree.
241#-------------------------------------------------------------------------------
242sub check_type {
243
244 # loop through each defined symbol
245 foreach my $sym ( sort ( keys %symbols ) ) {
246
247 # Make sure there's a type set for the symbol
248 if (!defined $symbols{$sym}{type}) {
249
250 #loop through each instance of that symbol
251 for ( my $sym_num = 0 ; $sym_num <= $symbols{$sym}{count} ; $sym_num++ ) {
252
253 my $filename = $symbols{$sym}{$sym_num}{file};
254 my $line_no = $symbols{$sym}{$sym_num}{line_no};
255
256 show_error("No type defined for symbol $sym defined at $filename:$line_no.");
257 }
258 }
259 }
260}
261
262#-------------------------------------------------------------------------------
Nico Huberec017592019-04-06 16:09:46 +0200263# check_config_macro - The CONFIG() macro is only valid for symbols of type
264# bool. It would probably work on type hex or int if the value was 0 or 1,
265# but this seems like a bad plan. Using it on strings is dead out.
266#
267# The IS_ENABLED() macro is forbidden in coreboot now. Though, as long as
268# we keep its definition in libpayload for compatibility, we have to check
269# that it doesn't sneak back in.
Martin Rothbcaaad12015-10-18 11:16:25 -0600270#-------------------------------------------------------------------------------
Nico Huberec017592019-04-06 16:09:46 +0200271sub check_config_macro {
Martin Rothb6acc302015-11-27 18:51:19 -0700272 my @is_enabled_symbols = @collected_symbols;
Martin Rothbcaaad12015-10-18 11:16:25 -0600273
274 #sort through symbols found by grep and store them in a hash for easy access
275 while ( my $line = shift @is_enabled_symbols ) {
Julius Werneref7a3262019-03-05 16:57:52 -0800276 if ( $line =~ /^([^:]+):(\d+):(.+\bCONFIG\(.*)/ ) {
277 my $file = $1;
278 my $lineno = $2;
279 $line = $3;
280 while ( $line =~ /(.*)\bCONFIG\(([^)]*)\)(.*)/ ) {
281 my $symbol = $2;
282 $line = $1 . $3;
283
284 #make sure that the type is bool
285 if ( exists $symbols{$symbol} ) {
286 if ( $symbols{$symbol}{type} ne "bool" ) {
287 show_error( "CONFIG($symbol) used at $file:$lineno."
288 . " CONFIG() is only valid for type 'bool', not '$symbols{$symbol}{type}'." );
289 }
290 }
291 else {
Julius Wernerf0286042019-04-09 15:57:07 -0700292 show_error("CONFIG() used on unknown value ($symbol) at $file:$lineno.");
Julius Werneref7a3262019-03-05 16:57:52 -0800293 }
294 }
295 } elsif ( $line =~ /^([^:]+):(\d+):(.+IS_ENABLED.*)/ ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -0700296 my $file = $1;
Martin Rothbcaaad12015-10-18 11:16:25 -0600297 my $lineno = $2;
Martin Rothb6acc302015-11-27 18:51:19 -0700298 $line = $3;
Martin Roth572a8562016-01-25 16:14:09 -0700299 if ( ( $line !~ /(.*)IS_ENABLED\s*\(\s*CONFIG_(\w+)(.*)/ ) && ( $line !~ /(\/[\*\/])(.*)IS_ENABLED/ ) ) {
Nico Huberec017592019-04-06 16:09:46 +0200300 show_error("# uninterpreted IS_ENABLED at $file:$lineno: $line");
Martin Rothb6acc302015-11-27 18:51:19 -0700301 next;
Martin Rothbcaaad12015-10-18 11:16:25 -0600302 }
Martin Rothb6acc302015-11-27 18:51:19 -0700303 while ( $line =~ /(.*)IS_ENABLED\s*\(\s*CONFIG_(\w+)(.*)/ ) {
304 my $symbol = $2;
Martin Roth1b44f7e2016-01-11 14:31:38 -0700305 $line = $1 . $3;
Nico Huberec017592019-04-06 16:09:46 +0200306 show_error("IS_ENABLED(CONFIG_$symbol) at $file:$lineno is deprecated. Use CONFIG($symbol) instead.");
Martin Rothb6acc302015-11-27 18:51:19 -0700307 }
Martin Roth5b883012017-06-25 20:27:36 -0600308 } elsif ( $line =~ /^([^:]+):(\d+):\s*#\s*(?:el)?if\s+!?\s*\(?\s*CONFIG_(\w+)\)?(\s*==\s*1)?.*?$/ ) {
309 my $file = $1;
310 my $lineno = $2;
311 my $symbol = $3;
Nico Huberec017592019-04-06 16:09:46 +0200312 # If the type is bool, give a warning that CONFIG() should be used
Martin Roth5b883012017-06-25 20:27:36 -0600313 if ( exists $symbols{$symbol} ) {
314 if ( $symbols{$symbol}{type} eq "bool" ) {
315 show_error( "#if CONFIG_$symbol used at $file:$lineno."
Julius Werneref7a3262019-03-05 16:57:52 -0800316 . " CONFIG($symbol) should be used for type 'bool'" );
Martin Roth5b883012017-06-25 20:27:36 -0600317 }
318 }
Julius Werneref7a3262019-03-05 16:57:52 -0800319 } elsif ( $line =~ /^([^:]+):(\d+):\s*#\s*(?:el)?if.*(?:&&|\|\|)\s+!?\s*\(?\s*CONFIG_(\w+)\)?(\s*==\s*1)?$/ ) {
Martin Roth5b883012017-06-25 20:27:36 -0600320 my $file = $1;
321 my $lineno = $2;
322 my $symbol = $3;
Nico Huberec017592019-04-06 16:09:46 +0200323 # If the type is bool, give a warning that CONFIG() should be used
Martin Roth5b883012017-06-25 20:27:36 -0600324 if ( exists $symbols{$symbol} ) {
325 if ( $symbols{$symbol}{type} eq "bool" ) {
326 show_error( "#if CONFIG_$symbol used at $file:$lineno."
Julius Werneref7a3262019-03-05 16:57:52 -0800327 . " CONFIG($symbol) should be used for type 'bool'" );
Martin Roth5b883012017-06-25 20:27:36 -0600328 }
329 }
Julius Wernere5eb2de2019-03-05 17:10:19 -0800330 } elsif ( $line =~ /^([^:]+):(\d+):(.+\bCONFIG_.+)/ ) {
331 my $file = $1;
332 my $lineno = $2;
333 $line = $3;
334 if ( $file =~ /.*\.(c|h|asl|ld)/ ) {
335 while ( $line =~ /(.*)\bCONFIG_(\w+)(.*)/ && $1 !~ /\/\/|\/\*/ ) {
336 my $symbol = $2;
337 $line = $1 . $3;
338 if ( exists $symbols{$symbol} ) {
339 if ( $symbols{$symbol}{type} eq "bool" ) {
Martin Rotha0209032020-07-24 12:42:59 -0600340 show_error( "Naked reference to CONFIG_$symbol used at $file:$lineno."
Julius Wernere5eb2de2019-03-05 17:10:19 -0800341 . " A 'bool' Kconfig should always be accessed through CONFIG($symbol)." );
342 }
343 } else {
344 show_warning( "Unknown config option CONFIG_$symbol used at $file:$lineno." );
345 }
346 }
347 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600348 }
349 }
350}
351
352#-------------------------------------------------------------------------------
353# check_defaults - Look for defaults that come after a default with no
354# dependencies.
355#
356# TODO - check for defaults with the same dependencies
357#-------------------------------------------------------------------------------
358sub check_defaults {
359
360 # loop through each defined symbol
361 foreach my $sym ( sort ( keys %symbols ) ) {
362 my $default_set = 0;
363 my $default_filename = "";
364 my $default_line_no = "";
365
366 #loop through each instance of that symbol
367 for ( my $sym_num = 0 ; $sym_num <= $symbols{$sym}{count} ; $sym_num++ ) {
368
369 #loop through any defaults for that instance of that symbol, if there are any
370 next unless ( exists $symbols{$sym}{$sym_num}{default_max} );
371 for ( my $def_num = 0 ; $def_num <= $symbols{$sym}{$sym_num}{default_max} ; $def_num++ ) {
372
Martin Rothfa956252016-09-30 15:51:32 -0600373 my $filename = $symbols{$sym}{$sym_num}{file};
374 my $line_no = $symbols{$sym}{$sym_num}{default}{$def_num}{default_line_no};
375
Martin Roth08705f12016-11-09 14:27:00 -0700376 # Make sure there's a type set for the symbol
377 next if (!defined $symbols{$sym}{type});
378
Michael Niewöhner90fcffb2021-09-16 17:56:14 +0200379 # Symbols created/used inside a choice must not have a default set. The default is set by the choice itself.
380 if ($symbols{$sym}{choice}) {
381 show_error("Defining a default for symbol '$sym' at $filename:$line_no, used inside choice at "
Michael Niewöhner43963582021-10-17 17:48:50 +0200382 . "$symbols{$sym}{choice}, is not allowed.");
Michael Niewöhner90fcffb2021-09-16 17:56:14 +0200383 }
384
Martin Rothfa956252016-09-30 15:51:32 -0600385 # skip good defaults
386 if (! ((($symbols{$sym}{type} eq "hex") && ($symbols{$sym}{$sym_num}{default}{$def_num}{default} =~ /^0x/)) ||
387 (($symbols{$sym}{type} eq "int") && ($symbols{$sym}{$sym_num}{default}{$def_num}{default} =~ /^[-0-9]+$/)) ||
388 (($symbols{$sym}{type} eq "string") && ($symbols{$sym}{$sym_num}{default}{$def_num}{default} =~ /^".*"$/)) ||
389 (($symbols{$sym}{type} eq "bool") && ($symbols{$sym}{$sym_num}{default}{$def_num}{default} =~ /^[yn]$/)))
390 ) {
391
392 my ($checksym) = $symbols{$sym}{$sym_num}{default}{$def_num}{default} =~ /(\w+)/;
393
394 if (! exists $symbols{$checksym}) {
395
396 # verify the symbol type against the default value
397 if ($symbols{$sym}{type} eq "hex") {
398 show_error("non hex default value ($symbols{$sym}{$sym_num}{default}{$def_num}{default}) used for hex symbol $sym at $filename:$line_no.");
399 } elsif ($symbols{$sym}{type} eq "int") {
400 show_error("non int default value ($symbols{$sym}{$sym_num}{default}{$def_num}{default}) used for int symbol $sym at $filename:$line_no.");
401 } elsif ($symbols{$sym}{type} eq "string") {
402 # TODO: Remove special MAINBOARD_DIR check
403 if ($sym ne "MAINBOARD_DIR") {
404 show_error("no quotes around default value ($symbols{$sym}{$sym_num}{default}{$def_num}{default}) used for string symbol $sym at $filename:$line_no.");
405 }
406 } elsif ($symbols{$sym}{type} eq "bool") {
407 if ($symbols{$sym}{$sym_num}{default}{$def_num}{default} =~ /[01YN]/) {
Julius Wernere5eb2de2019-03-05 17:10:19 -0800408 show_error("default value ($symbols{$sym}{$sym_num}{default}{$def_num}{default}) for bool symbol $sym uses value other than y/n at $filename:$line_no.");
Martin Rothfa956252016-09-30 15:51:32 -0600409 } else {
410 show_error("non bool default value ($symbols{$sym}{$sym_num}{default}{$def_num}{default}) used for bool symbol $sym at $filename:$line_no.");
411 }
412 }
413 }
414 }
415
Martin Rothbcaaad12015-10-18 11:16:25 -0600416 #if a default is already set, display an error
417 if ($default_set) {
Julius Wernere5eb2de2019-03-05 17:10:19 -0800418 show_error( "Default for '$sym' referenced at $filename:$line_no will never be set"
Martin Roth1b44f7e2016-01-11 14:31:38 -0700419 . " - overridden by default set at $default_filename:$default_line_no" );
Martin Rothbcaaad12015-10-18 11:16:25 -0600420 }
421 else {
422 #if no default is set, see if this is a default with no dependencies
423 unless ( ( exists $symbols{$sym}{$sym_num}{default}{$def_num}{default_depends_on} )
424 || ( exists $symbols{$sym}{$sym_num}{max_dependency} ) )
425 {
426 $default_set = 1;
427 $default_filename = $symbols{$sym}{$sym_num}{file};
428 $default_line_no = $symbols{$sym}{$sym_num}{default}{$def_num}{default_line_no};
429 }
430 }
431 }
432 }
433 }
434}
435
436#-------------------------------------------------------------------------------
437# check_referenced_symbols - Make sure the symbols referenced by expressions and
438# select statements are actually valid symbols.
439#-------------------------------------------------------------------------------
440sub check_referenced_symbols {
441
442 #loop through symbols found in expressions and used by 'select' keywords
443 foreach my $key ( sort ( keys %referenced_symbols ) ) {
444
445 #make sure the symbol was defined by a 'config' or 'choice' keyword
446 next if ( exists $symbols{$key} );
447
Martin Rothd8080172015-11-26 19:12:44 -0700448 #loop through each instance of the symbol to print out all of the invalid references
449 for ( my $i = 0 ; $i <= $referenced_symbols{$key}{count} ; $i++ ) {
450 my $filename = $referenced_symbols{$key}{$i}{filename};
451 my $line_no = $referenced_symbols{$key}{$i}{line_no};
Martin Roth7aa3cea2015-11-27 18:45:45 -0700452 show_error("Undefined Symbol '$key' used at $filename:$line_no.");
Martin Rothbcaaad12015-10-18 11:16:25 -0600453 }
454 }
455}
456
457#-------------------------------------------------------------------------------
458#-------------------------------------------------------------------------------
459sub collect_used_symbols {
460 # find all references to CONFIG_ statements in the tree
461
462 if ($dont_use_git_grep) {
Julius Werneref7a3262019-03-05 16:57:52 -0800463 @collected_symbols = `grep -Irn -- "CONFIG\\(_\\|(\\)" | grep -v '$exclude_dirs_and_files'; grep -In -- "CONFIG\\(_\\|(\\)" $payload_files_to_check`;
Martin Roth1b44f7e2016-01-11 14:31:38 -0700464 }
465 else {
Julius Werneref7a3262019-03-05 16:57:52 -0800466 @collected_symbols = `git grep -In -- "CONFIG\\(_\\|(\\)" | grep -v '$exclude_dirs_and_files'; git grep -In -- "CONFIG\\(_\\|(\\)" $payload_files_to_check`;
Martin Rothbcaaad12015-10-18 11:16:25 -0600467 }
468
469 my @used_symbols = @collected_symbols;
470
471 #sort through symbols found by grep and store them in a hash for easy access
472 while ( my $line = shift @used_symbols ) {
Julius Werneref7a3262019-03-05 16:57:52 -0800473 while ( $line =~ /[^A-Za-z0-9_]CONFIG(?:_|\()([A-Za-z0-9_]+)/g ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -0700474 my $symbol = $1;
Martin Rothbcaaad12015-10-18 11:16:25 -0600475 my $filename = "";
Martin Roth1b44f7e2016-01-11 14:31:38 -0700476 if ( $line =~ /^([^:]+):/ ) {
Martin Rothbcaaad12015-10-18 11:16:25 -0600477 $filename = $1;
478 }
479
Martin Roth1b44f7e2016-01-11 14:31:38 -0700480 if ( exists $used_symbols{$symbol}{count} ) {
Martin Rothbcaaad12015-10-18 11:16:25 -0600481 $used_symbols{$symbol}{count}++;
Martin Roth1b44f7e2016-01-11 14:31:38 -0700482 }
483 else {
484 $used_symbols{$symbol}{count} = 0;
Martin Rothbcaaad12015-10-18 11:16:25 -0600485 }
486 $used_symbols{$symbol}{"num_$used_symbols{$symbol}{count}"} = $filename;
Martin Roth1b44f7e2016-01-11 14:31:38 -0700487 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600488 }
489}
490
491#-------------------------------------------------------------------------------
492# check_used_symbols - Checks to see whether or not the created symbols are
493# actually used.
494#-------------------------------------------------------------------------------
495sub check_used_symbols {
496 # loop through all defined symbols and see if they're used anywhere
497 foreach my $key ( sort ( keys %symbols ) ) {
498
Martin Roth6bfbf1c2016-01-25 16:12:49 -0700499 if ( $key =~ /$exclude_unused/ ) {
500 next;
501 }
502
Martin Rothbcaaad12015-10-18 11:16:25 -0600503 #see if they're used internal to Kconfig
504 next if ( exists $referenced_symbols{$key} );
505
506 #see if they're used externally
507 next if exists $used_symbols{$key};
508
509 #loop through the definitions to print out all the places the symbol is defined.
510 for ( my $i = 0 ; $i <= $symbols{$key}{count} ; $i++ ) {
511 my $filename = $symbols{$key}{$i}{file};
512 my $line_no = $symbols{$key}{$i}{line_no};
Martin Rotha7d00272016-10-03 23:00:04 +0200513 show_warning("Unused symbol '$key' referenced at $filename:$line_no.");
Martin Rothbcaaad12015-10-18 11:16:25 -0600514 }
515 }
516}
517
518#-------------------------------------------------------------------------------
519# build_and_parse_kconfig_tree
520#-------------------------------------------------------------------------------
521#load the initial file and start parsing it
522sub build_and_parse_kconfig_tree {
523 my ($top_level_kconfig) = @_;
524 my @config_to_parse;
525 my @parseline;
526 my $inside_help = 0; # set to line number of 'help' keyword if this line is inside a help block
527 my @inside_if = (); # stack of if dependencies
528 my $inside_config = ""; # set to symbol name of the config section
529 my @inside_menu = (); # stack of menu names
530 my $inside_choice = "";
Patrick Georgicbc5b992018-11-23 15:55:56 +0100531 my $choice_symbol = "";
Martin Rothbcaaad12015-10-18 11:16:25 -0600532 my $configs_inside_choice;
Martin Roth0e6c0e12016-03-02 12:16:13 -0700533 my %fileinfo;
Martin Rothbcaaad12015-10-18 11:16:25 -0600534
535 #start the tree off by loading the top level kconfig
536 @config_to_parse = load_kconfig_file( $top_level_kconfig, "", 0, 0, "", 0 );
537
Martin Rothbcaaad12015-10-18 11:16:25 -0600538 while ( ( @parseline = shift(@config_to_parse) ) && ( exists $parseline[0]{text} ) ) {
539 my $line = $parseline[0]{text};
540 my $filename = $parseline[0]{filename};
541 my $line_no = $parseline[0]{file_line_no};
542
543 #handle help - help text: "help" or "---help---"
Martin Roth811d93a2017-04-06 11:06:00 -0600544 my $lastline_was_help = $inside_help;
Martin Rothbcaaad12015-10-18 11:16:25 -0600545 $inside_help = handle_help( $line, $inside_help, $inside_config, $inside_choice, $filename, $line_no );
546 $parseline[0]{inside_help} = $inside_help;
547
548 #look for basic issues in the line, strip crlf
549 $line = simple_line_checks( $line, $filename, $line_no );
550
551 #strip comments
552 $line =~ s/\s*#.*$//;
553
554 #don't parse any more if we're inside a help block
555 if ($inside_help) {
556 #do nothing
557 }
558
559 #handle config
Martin Roth811d93a2017-04-06 11:06:00 -0600560 elsif ( $line =~ /^\s*config\s+/ ) {
Martin Rothbcaaad12015-10-18 11:16:25 -0600561 $line =~ /^\s*config\s+([^"\s]+)\s*(?>#.*)?$/;
562 my $symbol = $1;
563 $inside_config = $symbol;
564 if ($inside_choice) {
565 $configs_inside_choice++;
566 }
Martin Rothb7c39b22016-01-14 09:04:53 -0700567 add_symbol( $symbol, \@inside_menu, $filename, $line_no, \@inside_if, $inside_choice );
Martin Rothbcaaad12015-10-18 11:16:25 -0600568 }
569
570 #bool|hex|int|string|tristate <expr> [if <expr>]
571 elsif ( $line =~ /^\s*(bool|string|hex|int|tristate)/ ) {
572 $line =~ /^\s*(bool|string|hex|int|tristate)\s*(.*)/;
573 my ( $type, $prompt ) = ( $1, $2 );
574 handle_type( $type, $inside_config, $filename, $line_no );
575 handle_prompt( $prompt, $type, \@inside_menu, $inside_config, $inside_choice, $filename, $line_no );
576 }
577
578 # def_bool|def_tristate <expr> [if <expr>]
579 elsif ( $line =~ /^\s*(def_bool|def_tristate)/ ) {
580 $line =~ /^\s*(def_bool|def_tristate)\s+(.*)/;
581 my ( $orgtype, $default ) = ( $1, $2 );
582 ( my $type = $orgtype ) =~ s/def_//;
583 handle_type( $type, $inside_config, $filename, $line_no );
584 handle_default( $default, $orgtype, $inside_config, $inside_choice, $filename, $line_no );
585 }
586
587 #prompt <prompt> [if <expr>]
588 elsif ( $line =~ /^\s*prompt/ ) {
589 $line =~ /^\s*prompt\s+(.+)/;
590 handle_prompt( $1, "prompt", \@inside_menu, $inside_config, $inside_choice, $filename, $line_no );
591 }
592
593 # default <expr> [if <expr>]
594 elsif ( $line =~ /^\s*default/ ) {
595 $line =~ /^\s*default\s+(.*)/;
596 my $default = $1;
597 handle_default( $default, "default", $inside_config, $inside_choice, $filename, $line_no );
598 }
599
600 # depends on <expr>
601 elsif ( $line =~ /^\s*depends\s+on/ ) {
602 $line =~ /^\s*depends\s+on\s+(.*)$/;
603 my $expr = $1;
604 handle_depends( $expr, $inside_config, $inside_choice, $filename, $line_no );
605 handle_expressions( $expr, $inside_config, $filename, $line_no );
606 }
607
608 # comment <prompt>
609 elsif ( $line =~ /^\s*comment/ ) {
610 $inside_config = "";
611 }
612
613 # choice [symbol]
614 elsif ( $line =~ /^\s*choice/ ) {
615 if ( $line =~ /^\s*choice\s*([A-Za-z0-9_]+)$/ ) {
616 my $symbol = $1;
617 add_symbol( $symbol, \@inside_menu, $filename, $line_no, \@inside_if );
618 handle_type( "bool", $symbol, $filename, $line_no );
Patrick Georgicbc5b992018-11-23 15:55:56 +0100619 $choice_symbol = $symbol;
Martin Rothbcaaad12015-10-18 11:16:25 -0600620 }
621 $inside_config = "";
Michael Niewöhner70fb5cb2021-10-17 17:43:53 +0200622 $inside_choice = "$filename:$line_no";
Martin Rothbcaaad12015-10-18 11:16:25 -0600623 $configs_inside_choice = 0;
Martin Roth08cf90f2016-01-25 19:54:16 -0700624
625 # Kconfig verifies that choice blocks have a prompt
Martin Rothbcaaad12015-10-18 11:16:25 -0600626 }
627
628 # endchoice
629 elsif ( $line =~ /^\s*endchoice/ ) {
630 $inside_config = "";
631 if ( !$inside_choice ) {
Martin Roth7aa3cea2015-11-27 18:45:45 -0700632 show_error("'endchoice' keyword not within a choice block at $filename:$line_no.");
Martin Rothbcaaad12015-10-18 11:16:25 -0600633 }
634
635 $inside_choice = "";
Patrick Georgicbc5b992018-11-23 15:55:56 +0100636 if (( $configs_inside_choice == 0 ) &&
637 ( $choice_symbol eq "" )) {
638 show_error("unnamed choice block has no symbols at $filename:$line_no.");
Martin Rothbcaaad12015-10-18 11:16:25 -0600639 }
640 $configs_inside_choice = 0;
Patrick Georgicbc5b992018-11-23 15:55:56 +0100641 $choice_symbol="";
Martin Rothbcaaad12015-10-18 11:16:25 -0600642 }
643
644 # [optional]
645 elsif ( $line =~ /^\s*optional/ ) {
646 if ($inside_config) {
Martin Roth1b44f7e2016-01-11 14:31:38 -0700647 show_error( "Keyword 'optional' appears inside config for '$inside_config'"
648 . " at $filename:$line_no. This is not valid." );
Martin Rothbcaaad12015-10-18 11:16:25 -0600649 }
650 if ( !$inside_choice ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -0700651 show_error( "Keyword 'optional' appears outside of a choice block"
652 . " at $filename:$line_no. This is not valid." );
Martin Rothbcaaad12015-10-18 11:16:25 -0600653 }
654 }
655
656 # mainmenu <prompt>
657 elsif ( $line =~ /^\s*mainmenu/ ) {
658 $inside_config = "";
Martin Roth08cf90f2016-01-25 19:54:16 -0700659
660 # Kconfig alread checks for multiple 'mainmenu' entries and mainmenu entries with no prompt
661 # Possible check: look for 'mainmenu ""'
662 # Possible check: verify that a mainmenu has been specified
Martin Rothbcaaad12015-10-18 11:16:25 -0600663 }
664
665 # menu <prompt>
666 elsif ( $line =~ /^\s*menu/ ) {
667 $line =~ /^\s*menu\s+(.*)/;
668 my $menu = $1;
669 if ( $menu =~ /^\s*"([^"]*)"\s*$/ ) {
670 $menu = $1;
671 }
672
673 $inside_config = "";
674 $inside_choice = "";
675 push( @inside_menu, $menu );
676 }
677
Patrick Georgifcc29502018-09-16 21:35:46 +0200678 # visible if <expr>
679 elsif ( $line =~ /^\s*visible if.*$/ ) {
Julius Werneref7a3262019-03-05 16:57:52 -0800680 # Must come directly after menu line (and on a separate line)
681 # but kconfig already checks for that.
682 # Ignore it.
Patrick Georgifcc29502018-09-16 21:35:46 +0200683 }
684
Martin Rothbcaaad12015-10-18 11:16:25 -0600685 # endmenu
686 elsif ( $line =~ /^\s*endmenu/ ) {
687 $inside_config = "";
688 $inside_choice = "";
689 pop @inside_menu;
690 }
691
692 # "if" <expr>
693 elsif ( $line =~ /^\s*if/ ) {
694 $inside_config = "";
695 $line =~ /^\s*if\s+(.*)$/;
696 my $expr = $1;
697 push( @inside_if, $expr );
698 handle_expressions( $expr, $inside_config, $filename, $line_no );
Martin Roth0e6c0e12016-03-02 12:16:13 -0700699 $fileinfo{$filename}{iflevel}++;
Martin Rothbcaaad12015-10-18 11:16:25 -0600700 }
701
702 # endif
703 elsif ( $line =~ /^\s*endif/ ) {
704 $inside_config = "";
705 pop(@inside_if);
Martin Roth0e6c0e12016-03-02 12:16:13 -0700706 $fileinfo{$filename}{iflevel}--;
Martin Rothbcaaad12015-10-18 11:16:25 -0600707 }
708
709 #range <symbol> <symbol> [if <expr>]
710 elsif ( $line =~ /^\s*range/ ) {
711 $line =~ /^\s*range\s+(\S+)\s+(.*)$/;
712 handle_range( $1, $2, $inside_config, $filename, $line_no );
713 }
714
715 # select <symbol> [if <expr>]
716 elsif ( $line =~ /^\s*select/ ) {
717 unless ($inside_config) {
Martin Roth7aa3cea2015-11-27 18:45:45 -0700718 show_error("Keyword 'select' appears outside of config at $filename:$line_no. This is not valid.");
Martin Rothbcaaad12015-10-18 11:16:25 -0600719 }
720
721 if ( $line =~ /^\s*select\s+(.*)$/ ) {
722 $line = $1;
723 my $expression;
724 ( $line, $expression ) = handle_if_line( $line, $inside_config, $filename, $line_no );
725 if ($line) {
Martin Rothb7c39b22016-01-14 09:04:53 -0700726 add_referenced_symbol( $line, $filename, $line_no, 'select' );
Martin Rothbcaaad12015-10-18 11:16:25 -0600727 }
728 }
729 }
730
731 # source <prompt>
732 elsif ( $line =~ /^\s*source\s+"?([^"\s]+)"?\s*(?>#.*)?$/ ) {
733 my @newfile = load_kconfig_file( $1, $filename, $line_no, 0, $filename, $line_no );
734 unshift( @config_to_parse, @newfile );
735 $parseline[0]{text} = "# '$line'\n";
736 }
737 elsif (
738 ( $line =~ /^\s*#/ ) || #comments
739 ( $line =~ /^\s*$/ ) #blank lines
740 )
741 {
742 # do nothing
743 }
744 else {
Martin Roth811d93a2017-04-06 11:06:00 -0600745 if ($lastline_was_help) {
746 show_error("The line \"$line\" ($filename:$line_no) wasn't recognized - supposed to be inside help?");
747 }
748 else {
749 show_error("The line \"$line\" ($filename:$line_no) wasn't recognized");
750 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600751 }
752
Martin Roth819e6722016-01-25 16:38:05 -0700753 if ( defined $inside_menu[0] ) {
754 $parseline[0]{menus} = "";
755 }
756 else {
757 $parseline[0]{menus} = "top";
758 }
759
760 my $i = 0;
761 while ( defined $inside_menu[$i] ) {
762 $parseline[0]{menus} .= "$inside_menu[$i]";
763 $i++;
764 if ( defined $inside_menu[$i] ) {
765 $parseline[0]{menus} .= "->";
766 }
767 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600768 push @wholeconfig, @parseline;
769 }
Martin Roth0e6c0e12016-03-02 12:16:13 -0700770
771 foreach my $file ( keys %fileinfo ) {
772 if ( $fileinfo{$file}{iflevel} > 0 ) {
773 show_error("$file has $fileinfo{$file}{iflevel} more 'if' statement(s) than 'endif' statements.");
774 }
775 elsif ( $fileinfo{$file}{iflevel} < 0 ) {
776 show_error(
777 "$file has " . ( $fileinfo{$file}{iflevel} * -1 ) . " more 'endif' statement(s) than 'if' statements." );
778 }
779 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600780}
781
782#-------------------------------------------------------------------------------
783#-------------------------------------------------------------------------------
784sub handle_depends {
785 my ( $expr, $inside_config, $inside_choice, $filename, $line_no ) = @_;
786
787 if ($inside_config) {
788 my $sym_num = $symbols{$inside_config}{count};
789 if ( exists $symbols{$inside_config}{$sym_num}{max_dependency} ) {
790 $symbols{$inside_config}{$sym_num}{max_dependency}++;
791 }
792 else {
793 $symbols{$inside_config}{$sym_num}{max_dependency} = 0;
794 }
795
796 my $dep_num = $symbols{$inside_config}{$sym_num}{max_dependency};
797 $symbols{$inside_config}{$sym_num}{dependency}{$dep_num} = $expr;
798 }
799}
800
801#-------------------------------------------------------------------------------
802#-------------------------------------------------------------------------------
803sub add_symbol {
Martin Rothb7c39b22016-01-14 09:04:53 -0700804 my ( $symbol, $menu_array_ref, $filename, $line_no, $ifref, $inside_choice ) = @_;
Martin Rothbcaaad12015-10-18 11:16:25 -0600805 my @inside_if = @{$ifref};
806
807 #initialize the symbol or increment the use count.
Martin Roth1b44f7e2016-01-11 14:31:38 -0700808 if ( ( !exists $symbols{$symbol} ) || ( !exists $symbols{$symbol}{count} ) ) {
Martin Rothbcaaad12015-10-18 11:16:25 -0600809 $symbols{$symbol}{count} = 0;
Michael Niewöhner43963582021-10-17 17:48:50 +0200810 # remember the location of the choice (or "")
811 $symbols{$symbol}{choice} = $inside_choice;
Martin Rothbcaaad12015-10-18 11:16:25 -0600812 }
813 else {
814 $symbols{$symbol}{count}++;
Nico Huber967730f2021-07-17 11:43:44 +0200815 if ( $inside_choice && $symbols{$symbol}{choice} ) {
Martin Rothaa206472017-03-24 08:51:51 -0600816 show_error( "$symbol entry at $filename:$line_no has already been created inside another choice block "
817 . "at $symbols{$symbol}{0}{file}:$symbols{$symbol}{0}{line_no}." );
818 }
Martin Rothbcaaad12015-10-18 11:16:25 -0600819 }
820
821 # add the location of this instance
822 my $symcount = $symbols{$symbol}{count};
823 $symbols{$symbol}{$symcount}{file} = $filename;
824 $symbols{$symbol}{$symcount}{line_no} = $line_no;
825
826 #Add the menu structure
827 if ( defined @$menu_array_ref[0] ) {
828 $symbols{$symbol}{$symcount}{menu} = $menu_array_ref;
829 }
830
831 #Add any 'if' statements that the symbol is inside as dependencies
832 if (@inside_if) {
833 my $dep_num = 0;
834 for my $dependency (@inside_if) {
835 $symbols{$symbol}{$symcount}{dependency}{$dep_num} = $dependency;
836 $symbols{$symbol}{$symcount}{max_dependency} = $dep_num;
837 $dep_num++;
838 }
839 }
840}
841
842#-------------------------------------------------------------------------------
843# handle range
844#-------------------------------------------------------------------------------
845sub handle_range {
846 my ( $range1, $range2, $inside_config, $filename, $line_no ) = @_;
847
848 my $expression;
849 ( $range2, $expression ) = handle_if_line( $range2, $inside_config, $filename, $line_no );
850
851 $range1 =~ /^\s*(?:0x)?([A-Fa-f0-9]+)\s*$/;
852 my $checkrange1 = $1;
853 $range2 =~ /^\s*(?:0x)?([A-Fa-f0-9]+)\s*$/;
854 my $checkrange2 = $1;
855
856 if ( $checkrange1 && $checkrange2 && ( hex($checkrange1) > hex($checkrange2) ) ) {
Martin Rothd8080172015-11-26 19:12:44 -0700857 show_error("Range entry in $filename line $line_no value 1 ($range1) is greater than value 2 ($range2).");
Martin Rothbcaaad12015-10-18 11:16:25 -0600858 }
859
860 if ($inside_config) {
861 if ( exists( $symbols{$inside_config}{range1} ) ) {
862 if ( ( $symbols{$inside_config}{range1} != $range1 ) || ( $symbols{$inside_config}{range2} != $range2 ) ) {
Martin Rothd8080172015-11-26 19:12:44 -0700863 if ($show_note_output) {
Martin Roth7aa3cea2015-11-27 18:45:45 -0700864 print "#!!!!! Note: Config '$inside_config' range entry $range1 $range2 at $filename:$line_no does";
Martin Roth1b44f7e2016-01-11 14:31:38 -0700865 print " not match the previously defined range $symbols{$inside_config}{range1}"
866 . " $symbols{$inside_config}{range2}";
Martin Roth7aa3cea2015-11-27 18:45:45 -0700867 print " defined at $symbols{$inside_config}{range_file}:$symbols{$inside_config}{range_line_no}.\n";
Martin Rothbcaaad12015-10-18 11:16:25 -0600868 }
869 }
870 }
871 else {
872 $symbols{$inside_config}{range1} = $range1;
873 $symbols{$inside_config}{range2} = $range2;
874 $symbols{$inside_config}{range_file} = $filename;
875 $symbols{$inside_config}{range_line_no} = $line_no;
876 }
877 }
878 else {
Martin Roth7aa3cea2015-11-27 18:45:45 -0700879 show_error("Range entry at $filename:$line_no is not inside a config block.");
Martin Rothbcaaad12015-10-18 11:16:25 -0600880 }
881}
882
883#-------------------------------------------------------------------------------
884# handle_default
885#-------------------------------------------------------------------------------
886sub handle_default {
887 my ( $default, $name, $inside_config, $inside_choice, $filename, $line_no ) = @_;
888 my $expression;
889 ( $default, $expression ) = handle_if_line( $default, $inside_config, $filename, $line_no );
890
891 if ($inside_config) {
892 handle_expressions( $default, $inside_config, $filename, $line_no );
893 my $sym_num = $symbols{$inside_config}{count};
894
895 unless ( exists $symbols{$inside_config}{$sym_num}{default_max} ) {
896 $symbols{$inside_config}{$sym_num}{default_max} = 0;
897 }
898 my $default_max = $symbols{$inside_config}{$sym_num}{default_max};
899 $symbols{$inside_config}{$sym_num}{default}{$default_max}{default} = $default;
900 $symbols{$inside_config}{$sym_num}{default}{$default_max}{default_line_no} = $line_no;
901 if ($expression) {
902 $symbols{$inside_config}{$sym_num}{default}{$default_max}{default_depends_on} = $expression;
903 }
904 }
905 elsif ($inside_choice) {
906 handle_expressions( $default, $inside_config, $filename, $line_no );
907 }
908 else {
Martin Roth7aa3cea2015-11-27 18:45:45 -0700909 show_error("$name entry at $filename:$line_no is not inside a config or choice block.");
Martin Rothbcaaad12015-10-18 11:16:25 -0600910 }
911}
912
913#-------------------------------------------------------------------------------
914# handle_if_line
915#-------------------------------------------------------------------------------
916sub handle_if_line {
917 my ( $exprline, $inside_config, $filename, $line_no ) = @_;
918
919 if ( $exprline !~ /if/ ) {
920 return ( $exprline, "" );
921 }
922
923 #remove any quotes that might have an 'if' in them
924 my $savequote;
925 if ( $exprline =~ /^\s*("[^"]+")/ ) {
926 $savequote = $1;
927 $exprline =~ s/^\s*("[^"]+")//;
928 }
929
930 my $expr = "";
931 if ( $exprline =~ /\s*if\s+(.*)$/ ) {
932 $expr = $1;
933 $exprline =~ s/\s*if\s+.*$//;
934
935 if ($expr) {
936 handle_expressions( $expr, $inside_config, $filename, $line_no );
937 }
938 }
939
940 if ($savequote) {
941 $exprline = $savequote;
942 }
943
944 return ( $exprline, $expr );
945}
946
947#-------------------------------------------------------------------------------
Nico Huberf6b2baa2021-04-02 21:23:32 +0200948# handle_symbol - log which symbols are being used
949#-------------------------------------------------------------------------------
950sub handle_symbol {
951 my ( $symbol, $filename, $line_no ) = @_;
952
953 #filter constant symbols first
954 if ( $symbol =~ /^[yn]$/ ) { # constant y/n
955 return;
956 }
957 if ( $symbol =~ /^-?(?:0x)?\p{XDigit}+$/ ) { # int/hex values
958 return;
959 }
960 if ( $symbol =~ /^"[^"]*"$/ ) { # string values
961 return;
962 }
963
964 if ( $symbol =~ /^([A-Za-z0-9_]+)$/ ) { # actual symbol
965 add_referenced_symbol( $1, $filename, $line_no, 'expression' );
966 }
967 else {
968 show_error("Unrecognized expression: expected symbol, "
969 . "found '$symbol' in $filename line $line_no.");
970 }
971}
972
973#-------------------------------------------------------------------------------
974# handle_expressions - find symbols in expressions
Martin Rothbcaaad12015-10-18 11:16:25 -0600975#-------------------------------------------------------------------------------
976sub handle_expressions {
977 my ( $exprline, $inside_config, $filename, $line_no ) = @_;
978
Nico Huberf6b2baa2021-04-02 21:23:32 +0200979 my $strip = qr/\s*(.*[^\s]+)\s*/;
Martin Rothbcaaad12015-10-18 11:16:25 -0600980
Nico Huberf6b2baa2021-04-02 21:23:32 +0200981 my $parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
982 my $quotes = qr/"[^"]*"/;
983 my $balanced = qr/((?:$parens|$quotes|[^\(\)"])+)/;
Martin Rothbcaaad12015-10-18 11:16:25 -0600984
Nico Huberf6b2baa2021-04-02 21:23:32 +0200985 if ( $exprline =~ /^\s*$balanced\s*(?:\|\||&&)\s*(.+)$/ ) {
Nico Huber2d821952021-04-02 21:56:45 +0200986 # <expr> '||' <expr>, <expr> '&&' <expr> (8)(7)
Nico Huberf6b2baa2021-04-02 21:23:32 +0200987 my ( $lhs, $rhs ) = ( $1, $3 );
988 handle_expressions( $lhs, $inside_config, $filename, $line_no );
989 handle_expressions( $rhs, $inside_config, $filename, $line_no );
990 }
991 elsif ( $exprline =~ /^\s*!(.+)$/ ) {
Nico Huber2d821952021-04-02 21:56:45 +0200992 # '!' <expr> (6)
Martin Rothbcaaad12015-10-18 11:16:25 -0600993 handle_expressions( $1, $inside_config, $filename, $line_no );
994 }
Nico Huberf6b2baa2021-04-02 21:23:32 +0200995 elsif ( $exprline =~ /^\s*$parens\s*$/ ) {
Nico Huber2d821952021-04-02 21:56:45 +0200996 # '(' <expr> ')' (5)
Nico Huberf6b2baa2021-04-02 21:23:32 +0200997 $exprline =~ /^\s*\((.*)\)\s*$/;
Martin Rothbcaaad12015-10-18 11:16:25 -0600998 handle_expressions( $1, $inside_config, $filename, $line_no );
999 }
Nico Huber2d821952021-04-02 21:56:45 +02001000 elsif ( $exprline =~ /^\s*($quotes|[^"\s]+)\s*(?:[<>]=?|!=)$strip$/ ) {
1001 # <symbol> '<' <symbol>, <symbol> '!=' <symbol>, etc. (4)(3)
Nico Huberf6b2baa2021-04-02 21:23:32 +02001002 my ( $lhs, $rhs ) = ( $1, $2 );
1003 handle_symbol( $lhs, $filename, $line_no );
1004 handle_symbol( $rhs, $filename, $line_no );
Martin Rothbcaaad12015-10-18 11:16:25 -06001005 }
Nico Huberf6b2baa2021-04-02 21:23:32 +02001006 elsif ( $exprline =~ /^\s*($quotes|[^"\s]+)\s*=$strip$/ ) {
1007 # <symbol> '=' <symbol> (2)
1008 my ( $lhs, $rhs ) = ( $1, $2 );
1009 handle_symbol( $lhs, $filename, $line_no );
1010 handle_symbol( $rhs, $filename, $line_no );
Martin Rothbcaaad12015-10-18 11:16:25 -06001011 }
Nico Huberf6b2baa2021-04-02 21:23:32 +02001012 elsif ( $exprline =~ /^$strip$/ ) {
1013 # <symbol> (1)
1014 handle_symbol( $1, $filename, $line_no );
Martin Rothbcaaad12015-10-18 11:16:25 -06001015 }
Martin Rothbcaaad12015-10-18 11:16:25 -06001016}
1017
1018#-------------------------------------------------------------------------------
1019# add_referenced_symbol
1020#-------------------------------------------------------------------------------
1021sub add_referenced_symbol {
Martin Rothb7c39b22016-01-14 09:04:53 -07001022 my ( $symbol, $filename, $line_no, $reftype ) = @_;
Martin Rothbcaaad12015-10-18 11:16:25 -06001023 if ( exists $referenced_symbols{$symbol} ) {
1024 $referenced_symbols{$symbol}{count}++;
1025 $referenced_symbols{$symbol}{ $referenced_symbols{$symbol}{count} }{filename} = $filename;
1026 $referenced_symbols{$symbol}{ $referenced_symbols{$symbol}{count} }{line_no} = $line_no;
1027 }
1028 else {
1029 $referenced_symbols{$symbol}{count} = 0;
1030 $referenced_symbols{$symbol}{0}{filename} = $filename;
1031 $referenced_symbols{$symbol}{0}{line_no} = $line_no;
1032 }
Martin Rothb7c39b22016-01-14 09:04:53 -07001033
1034 #mark the symbol as being selected, use referenced symbols for location
1035 if ( $reftype eq 'select' ) {
1036 $selected_symbols{$symbol}{ $referenced_symbols{$symbol}{count} } = 1;
1037 }
Martin Rothbcaaad12015-10-18 11:16:25 -06001038}
1039
1040#-------------------------------------------------------------------------------
1041# handle_help
1042#-------------------------------------------------------------------------------
1043{
1044 #create a non-global static variable by enclosing it and the subroutine
1045 my $help_whitespace = ""; #string to show length of the help whitespace
Martin Roth8849f3b2017-05-23 19:43:43 -06001046 my $help_keyword_whitespace = "";
Martin Rothbcaaad12015-10-18 11:16:25 -06001047
1048 sub handle_help {
1049 my ( $line, $inside_help, $inside_config, $inside_choice, $filename, $line_no ) = @_;
1050
1051 if ($inside_help) {
1052
1053 #get the indentation level if it's not already set.
1054 if ( ( !$help_whitespace ) && ( $line !~ /^[\r\n]+/ ) ) {
1055 $line =~ /^(\s+)/; #find the indentation level.
1056 $help_whitespace = $1;
1057 if ( !$help_whitespace ) {
Martin Roth8849f3b2017-05-23 19:43:43 -06001058 show_error("$filename:$line_no - help text starts with no whitespace.");
1059 return $inside_help;
1060 }
1061 elsif ($help_keyword_whitespace eq $help_whitespace) {
1062 show_error("$filename:$line_no - help text needs additional indentation.");
Martin Rothbcaaad12015-10-18 11:16:25 -06001063 return $inside_help;
Martin Rothbcaaad12015-10-18 11:16:25 -06001064 }
1065 }
1066
1067 #help ends at the first line which has a smaller indentation than the first line of the help text.
Martin Roth8849f3b2017-05-23 19:43:43 -06001068 if ( ( $line !~ /^$help_whitespace/ ) && ( $line !~ /^[\r\n]+/ ) ) {
Martin Rothbcaaad12015-10-18 11:16:25 -06001069 $inside_help = 0;
1070 $help_whitespace = "";
Martin Roth8849f3b2017-05-23 19:43:43 -06001071 $help_keyword_whitespace = "";
Martin Rothbcaaad12015-10-18 11:16:25 -06001072 }
1073 else { #if it's not ended, add the line to the helptext array for the symbol's instance
1074 if ($inside_config) {
1075 my $sym_num = $symbols{$inside_config}{count};
1076 if ($help_whitespace) { $line =~ s/^$help_whitespace//; }
1077 push( @{ $symbols{$inside_config}{$sym_num}{helptext} }, $line );
1078 }
Martin Roth8849f3b2017-05-23 19:43:43 -06001079 if ( ($help_keyword_whitespace eq $help_whitespace) && ( $line !~ /^[\r\n]+/ ) ) {
1080 show_error("$filename:$line_no - help text needs additional indentation.");
1081 }
Martin Rothbcaaad12015-10-18 11:16:25 -06001082 }
1083 }
1084 elsif ( ( $line =~ /^(\s*)help/ ) || ( $line =~ /^(\s*)---help---/ ) ) {
1085 $inside_help = $line_no;
Martin Roth8849f3b2017-05-23 19:43:43 -06001086 $line =~ /^(\s+)/;
1087 $help_keyword_whitespace = $1;
Martin Rothbcaaad12015-10-18 11:16:25 -06001088 if ( ( !$inside_config ) && ( !$inside_choice ) ) {
Martin Rothd8080172015-11-26 19:12:44 -07001089 if ($show_note_output) {
Martin Roth7aa3cea2015-11-27 18:45:45 -07001090 print "# Note: $filename:$line_no help is not inside a config or choice block.\n";
Martin Rothbcaaad12015-10-18 11:16:25 -06001091 }
Martin Rothbcaaad12015-10-18 11:16:25 -06001092 }
1093 elsif ($inside_config) {
1094 $help_whitespace = "";
1095 my $sym_num = $symbols{$inside_config}{count};
1096 $symbols{$inside_config}{$sym_num}{help_line_no} = $line_no;
1097 $symbols{$inside_config}{$sym_num}{helptext} = ();
1098 }
1099 }
1100 return $inside_help;
1101 }
1102}
1103
1104#-------------------------------------------------------------------------------
1105# handle_type
1106#-------------------------------------------------------------------------------
1107sub handle_type {
1108 my ( $type, $inside_config, $filename, $line_no ) = @_;
1109
1110 my $expression;
1111 ( $type, $expression ) = handle_if_line( $type, $inside_config, $filename, $line_no );
1112
Martin Roth08ee1cf2016-01-25 16:39:32 -07001113 if ( $type =~ /tristate/ ) {
Julius Wernere5eb2de2019-03-05 17:10:19 -08001114 show_error("$filename:$line_no - tristate types are not used.");
Martin Roth08ee1cf2016-01-25 16:39:32 -07001115 }
1116
Martin Rothbcaaad12015-10-18 11:16:25 -06001117 if ($inside_config) {
1118 if ( exists( $symbols{$inside_config}{type} ) ) {
1119 if ( $symbols{$inside_config}{type} !~ /$type/ ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -07001120 show_error( "Config '$inside_config' type entry $type"
1121 . " at $filename:$line_no does not match $symbols{$inside_config}{type}"
1122 . " defined at $symbols{$inside_config}{type_file}:$symbols{$inside_config}{type_line_no}." );
Martin Rothbcaaad12015-10-18 11:16:25 -06001123 }
1124 }
1125 else {
1126 $symbols{$inside_config}{type} = $type;
1127 $symbols{$inside_config}{type_file} = $filename;
1128 $symbols{$inside_config}{type_line_no} = $line_no;
1129 }
1130 }
1131 else {
Martin Roth7aa3cea2015-11-27 18:45:45 -07001132 show_error("Type entry at $filename:$line_no is not inside a config block.");
Martin Rothbcaaad12015-10-18 11:16:25 -06001133 }
1134}
1135
1136#-------------------------------------------------------------------------------
1137# handle_prompt
1138#-------------------------------------------------------------------------------
1139sub handle_prompt {
1140 my ( $prompt, $name, $menu_array_ref, $inside_config, $inside_choice, $filename, $line_no ) = @_;
1141
1142 my $expression;
1143 ( $prompt, $expression ) = handle_if_line( $prompt, $inside_config, $filename, $line_no );
1144
1145 if ($inside_config) {
1146 if ( $prompt !~ /^\s*$/ ) {
1147 if ( $prompt =~ /^\s*"([^"]*)"\s*$/ ) {
1148 $prompt = $1;
1149 }
1150
Martin Roth08cf90f2016-01-25 19:54:16 -07001151 #display an error if there's a prompt at the top menu level
Martin Rothbcaaad12015-10-18 11:16:25 -06001152 if ( !defined @$menu_array_ref[0] ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -07001153 show_error( "Symbol '$inside_config' with prompt '$prompt' appears outside of a menu"
1154 . " at $filename:$line_no." );
Martin Rothbcaaad12015-10-18 11:16:25 -06001155 }
1156
1157 my $sym_num = $symbols{$inside_config}{count};
Martin Rothb58d3492016-01-25 16:42:13 -07001158 if ( !exists $symbols{$inside_config}{$sym_num}{prompt_max} ) {
Martin Rothbcaaad12015-10-18 11:16:25 -06001159 $symbols{$inside_config}{$sym_num}{prompt_max} = 0;
1160 }
Martin Rothb58d3492016-01-25 16:42:13 -07001161 else {
1162 $symbols{$inside_config}{$sym_num}{prompt_max}++;
1163 }
Martin Rothbcaaad12015-10-18 11:16:25 -06001164 my $prompt_max = $symbols{$inside_config}{$sym_num}{prompt_max};
1165 $symbols{$inside_config}{$sym_num}{prompt}{$prompt_max}{prompt} = $prompt;
1166 $symbols{$inside_config}{$sym_num}{prompt}{$prompt_max}{prompt_line_no} = $line_no;
Martin Rothb58d3492016-01-25 16:42:13 -07001167
1168 $symbols{$inside_config}{$sym_num}{prompt}{$prompt_max}{prompt_menu} = @$menu_array_ref;
Martin Rothbcaaad12015-10-18 11:16:25 -06001169 if ($expression) {
1170 $symbols{$inside_config}{$sym_num}{prompt}{$prompt_max}{prompt_depends_on} = $expression;
1171 }
1172 }
1173 }
1174 elsif ($inside_choice) {
1175
1176 #do nothing
1177 }
1178 else {
Martin Roth7aa3cea2015-11-27 18:45:45 -07001179 show_error("$name entry at $filename:$line_no is not inside a config or choice block.");
Martin Rothbcaaad12015-10-18 11:16:25 -06001180 }
1181}
1182
1183#-------------------------------------------------------------------------------
1184# simple_line_checks - Does some basic checks on the current line, then cleans the line
1185# up for further processing.
1186#-------------------------------------------------------------------------------
1187sub simple_line_checks {
1188 my ( $line, $filename, $line_no ) = @_;
1189
1190 #check for spaces instead of tabs
1191 if ( $line =~ /^ +/ ) {
Martin Roth7aa3cea2015-11-27 18:45:45 -07001192 show_error("$filename:$line_no starts with a space.");
Martin Rothbcaaad12015-10-18 11:16:25 -06001193 }
1194
1195 #verify a linefeed at the end of the line
1196 if ( $line !~ /.*\n/ ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -07001197 show_error( "$filename:$line_no does not end with linefeed."
1198 . " This can cause the line to not be recognized by the Kconfig parser.\n#($line)" );
Martin Rothbcaaad12015-10-18 11:16:25 -06001199 $line =~ s/\s*$//;
1200 }
1201 else {
1202 chop($line);
1203 }
1204
1205 return $line;
1206}
1207
1208#-------------------------------------------------------------------------------
1209# load_kconfig_file - Loads a single Kconfig file or expands * wildcard
1210#-------------------------------------------------------------------------------
1211sub load_kconfig_file {
1212 my ( $input_file, $loadfile, $loadline, $expanded, $topfile, $topline ) = @_;
1213 my @file_data;
1214 my @dir_file_data;
1215
1216 #recursively handle coreboot's new source glob operator
Arthur Heymans55f01322019-11-05 12:06:59 +01001217 if ( $input_file =~ /^(.*?)\/(\w*)\*(\w*)\/(.*)$/ ) {
Martin Rothbcaaad12015-10-18 11:16:25 -06001218 my $dir_prefix = $1;
Arthur Heymans55f01322019-11-05 12:06:59 +01001219 my $dir_glob_prefix = $2;
1220 my $dir_glob_suffix = $3;
1221 my $dir_suffix = $4;
Martin Rothbcaaad12015-10-18 11:16:25 -06001222 if ( -d "$dir_prefix" ) {
1223
1224 opendir( D, "$dir_prefix" ) || die "Can't open directory '$dir_prefix'\n";
1225 my @dirlist = sort { $a cmp $b } readdir(D);
1226 closedir(D);
1227
1228 while ( my $directory = shift @dirlist ) {
1229
1230 #ignore non-directory files
Arthur Heymans55f01322019-11-05 12:06:59 +01001231 if ( ( -d "$dir_prefix/$directory" ) && !( $directory =~ /^\..*/ )
1232 && ( $directory =~ /\Q$dir_glob_prefix\E.*\Q$dir_glob_suffix\E/ ) ) {
Martin Roth1b44f7e2016-01-11 14:31:38 -07001233 push @dir_file_data,
1234 load_kconfig_file( "$dir_prefix/$directory/$dir_suffix",
1235 $input_file, $loadline, 1, $loadfile, $loadline );
Martin Rothbcaaad12015-10-18 11:16:25 -06001236 }
1237 }
1238 }
1239
1240 #the directory should exist when using a glob
1241 else {
Julius Wernere5eb2de2019-03-05 17:10:19 -08001242 show_error("Could not find dir '$dir_prefix'");
Martin Rothbcaaad12015-10-18 11:16:25 -06001243 }
1244 }
1245
1246 #if the file exists, try to load it.
1247 elsif ( -e "$input_file" ) {
1248
Martin Rotha7d00272016-10-03 23:00:04 +02001249 #throw a warning if the file has already been loaded.
Martin Rothbcaaad12015-10-18 11:16:25 -06001250 if ( exists $loaded_files{$input_file} ) {
Martin Rotha7d00272016-10-03 23:00:04 +02001251 show_warning("'$input_file' sourced at $loadfile:$loadline was already loaded by $loaded_files{$input_file}");
Martin Rothbcaaad12015-10-18 11:16:25 -06001252 }
1253
1254 #load the file's contents and mark the file as loaded for checking later
1255 open( my $HANDLE, "<", "$input_file" ) or die "Error: could not open file '$input_file'\n";
1256 @file_data = <$HANDLE>;
1257 close $HANDLE;
1258 $loaded_files{$input_file} = "'$loadfile' line $loadline";
1259 }
1260
1261 # if the file isn't being loaded from a glob, it should exist.
1262 elsif ( $expanded == 0 ) {
Martin Roth7aa3cea2015-11-27 18:45:45 -07001263 show_warning("Could not find file '$input_file' sourced at $loadfile:$loadline");
Martin Rothbcaaad12015-10-18 11:16:25 -06001264 }
1265
1266 my $line_in_file = 0;
1267 while ( my $line = shift @file_data ) {
1268
1269 #handle line continuation.
1270 my $continue_line = 0;
Martin Roth1b44f7e2016-01-11 14:31:38 -07001271 while ( $line =~ /(.*)\s+\\$/ ) {
Martin Rothbcaaad12015-10-18 11:16:25 -06001272 my $text = $1;
1273
1274 # get rid of leading whitespace on all but the first and last lines
1275 $text =~ s/^\s*/ / if ($continue_line);
1276
1277 $dir_file_data[$line_in_file]{text} .= $text;
1278 $line = shift @file_data;
1279 $continue_line++;
1280
1281 #put the data into the continued lines (other than the first)
1282 $line =~ /^\s*(.*)\s*$/;
1283
Martin Roth1b44f7e2016-01-11 14:31:38 -07001284 $dir_file_data[ $line_in_file + $continue_line ]{text} = "\t# continued line ( " . $1 . " )\n";
1285 $dir_file_data[ $line_in_file + $continue_line ]{filename} = $input_file;
1286 $dir_file_data[ $line_in_file + $continue_line ]{file_line_no} = $line_in_file + $continue_line + 1;
Martin Rothbcaaad12015-10-18 11:16:25 -06001287
1288 #get rid of multiple leading spaces for last line
1289 $line = " $1\n";
1290 }
1291
Martin Roth1b44f7e2016-01-11 14:31:38 -07001292 $dir_file_data[$line_in_file]{text} .= $line;
Martin Rothbcaaad12015-10-18 11:16:25 -06001293 $dir_file_data[$line_in_file]{filename} = $input_file;
1294 $dir_file_data[$line_in_file]{file_line_no} = $line_in_file + 1;
1295
1296 $line_in_file++;
1297 if ($continue_line) {
1298 $line_in_file += $continue_line;
1299 }
1300 }
1301
1302 if ($topfile) {
1303 my %file_data;
Martin Roth1b44f7e2016-01-11 14:31:38 -07001304 $file_data{text} = "\t### File '$input_file' loaded from '$topfile' line $topline\n";
Martin Rothbcaaad12015-10-18 11:16:25 -06001305 $file_data{filename} = $topfile;
1306 $file_data{file_line_no} = "($topline)";
Martin Roth1b44f7e2016-01-11 14:31:38 -07001307 unshift( @dir_file_data, \%file_data );
Martin Rothbcaaad12015-10-18 11:16:25 -06001308 }
1309
1310 return @dir_file_data;
1311}
1312
Martin Rothbcaaad12015-10-18 11:16:25 -06001313#-------------------------------------------------------------------------------
1314# print_wholeconfig - prints out the parsed Kconfig file
1315#-------------------------------------------------------------------------------
1316sub print_wholeconfig {
1317
1318 return unless $print_full_output;
1319
Martin Rotha7648f22021-11-05 17:24:29 -06001320 for ( my $i = 0 ; $i <= $#wholeconfig ; $i++ ) {
Martin Rothbcaaad12015-10-18 11:16:25 -06001321 my $line = $wholeconfig[$i];
1322 chop( $line->{text} );
1323
1324 #replace tabs with spaces for consistency
1325 $line->{text} =~ s/\t/ /g;
Martin Roth819e6722016-01-25 16:38:05 -07001326 printf "%-120s # $line->{filename} line $line->{file_line_no} ($line->{menus})\n", $line->{text};
Martin Rothbcaaad12015-10-18 11:16:25 -06001327 }
1328}
1329
1330#-------------------------------------------------------------------------------
1331# check_if_file_referenced - checks for kconfig files that are not being parsed
1332#-------------------------------------------------------------------------------
1333sub check_if_file_referenced {
1334 my $filename = $File::Find::name;
Martin Rothab2d7772016-01-25 16:45:14 -07001335 if ( ( $filename =~ /Kconfig/ )
1336 && ( !$filename =~ /\.orig$/ )
1337 && ( !$filename =~ /~$/ )
1338 && ( !exists $loaded_files{$filename} ) )
1339 {
Martin Rothd8080172015-11-26 19:12:44 -07001340 show_warning("'$filename' is never referenced");
Martin Rothbcaaad12015-10-18 11:16:25 -06001341 }
1342}
1343
1344#-------------------------------------------------------------------------------
1345# check_arguments parse the command line arguments
1346#-------------------------------------------------------------------------------
1347sub check_arguments {
1348 my $show_usage = 0;
1349 GetOptions(
1350 'help|?' => sub { usage() },
Martin Rothd8080172015-11-26 19:12:44 -07001351 'e|errors_off' => \$suppress_error_output,
1352 'n|notes' => \$show_note_output,
Martin Rothbcaaad12015-10-18 11:16:25 -06001353 'o|output=s' => \$output_file,
1354 'p|print' => \$print_full_output,
Martin Rothd8080172015-11-26 19:12:44 -07001355 'w|warnings_off' => \$suppress_warning_output,
Martin Rothbcaaad12015-10-18 11:16:25 -06001356 'path=s' => \$top_dir,
1357 'c|config=s' => \$config_file,
1358 'G|no_git_grep' => \$dont_use_git_grep,
1359 );
Martin Rothd8080172015-11-26 19:12:44 -07001360
1361 if ($suppress_error_output) {
1362 $suppress_warning_output = 1;
1363 }
1364 if ($suppress_warning_output) {
Martin Roth1b44f7e2016-01-11 14:31:38 -07001365 $show_note_output = 0;
Martin Rothd8080172015-11-26 19:12:44 -07001366 }
Martin Rothbcaaad12015-10-18 11:16:25 -06001367}
1368
1369#-------------------------------------------------------------------------------
1370# usage - Print the arguments for the user
1371#-------------------------------------------------------------------------------
1372sub usage {
1373 print "kconfig_lint <options>\n";
1374 print " -o|--output=file Set output filename\n";
1375 print " -p|--print Print full output\n";
Martin Rothd8080172015-11-26 19:12:44 -07001376 print " -e|--errors_off Don't print warnings or errors\n";
Martin Rothbcaaad12015-10-18 11:16:25 -06001377 print " -w|--warnings_off Don't print warnings\n";
Martin Rothd8080172015-11-26 19:12:44 -07001378 print " -n|--notes Show minor notes\n";
Martin Rothbcaaad12015-10-18 11:16:25 -06001379 print " --path=dir Path to top level kconfig\n";
1380 print " -c|--config=file Filename of config file to load\n";
1381 print " -G|--no_git_grep Use standard grep tools instead of git grep\n";
1382
1383 exit(0);
1384}
1385
13861;