#!/usr/bin/perl # # Script used to sort kernel-*.config files. # Usage: # ./kernel-config-sort.pl ../BUILD/linux-2.6.*/ kernel-multiarch.config # # ./kernel-config-sort.pl ../BUILD/linux-2.6.*/ -a x86 kernel-x86.config # use strict; use warnings; my $dir = ( shift @ARGV ) || "."; my $arch; if ( $ARGV[0] eq "-a" ) { shift @ARGV; $arch = shift @ARGV; } my $old_dir = $ENV{PWD}; chdir $dir; my @Kconfig_list; my @Kconfig_arch; sub look_in { my $parent = shift; my @files = glob $parent."*"; foreach ( @files ) { if ( -d ) { if ( $_ eq "Documentation" or $_ eq "build-done" ) { warn "Skipping $_\n"; next; } look_in( $_ . '/' ); next; } if ( m#^.*/Kconfig# ) { if ( m#^arch/# ) { push @Kconfig_arch, $_; } else { push @Kconfig_list, $_; } } } } if ( $arch ) { push @Kconfig_list, "arch/$arch/Kconfig"; } else { look_in(""); push @Kconfig_list, @Kconfig_arch; } my %byFile; my %byName; sub add_Kconfig { my $file = shift; my @maybe_add_source; my @config_list; unless ( -r $file ) { warn "FILE $file does not exist\n"; return; } open my $f_in, '<', $file; while ( <$f_in> ) { if ( /^\s?(?:menu)?config\s+(.*?)`?\s*$/ ) { if ( $byName{ $1 } ) { warn "Warning: $file: $1 already defined in $byName{ $1 }\n"; next; } push @config_list, [ 'o', $1 ]; next; } if ( /^\s?comment\s+"(.*?)"\s*$/ ) { push @config_list, [ 'c', $1 ]; next; } if ( /^\s*source\s+"(\S+?)"\s*$/ or /^\s*source\s+(\S+?)\s*$/) { push @maybe_add_source, $1; push @config_list, [ 's', $1 ]; next; } } close $f_in; $byFile{ $file } = \@config_list; { my %add; @add{ @maybe_add_source } = (); foreach ( @Kconfig_list ) { delete $add{ $_ } if exists $add{ $_ }; } if ( keys %add ) { #warn "Adding more source files: " . ( join ", ", sort keys %add ) ."\n"; push @Kconfig_list, sort keys %add; } } } { my $i; for ( $i = 0; $i < scalar @Kconfig_list; $i++ ) { my $file = $Kconfig_list[ $i ]; add_Kconfig( $file ); } } my $arch_specific; unless ( $arch ) { my @arch_specific; foreach my $f ( sort keys %byFile ) { next unless $f =~ /^arch/; foreach my $line ( @{ $byFile{ $f } } ) { push @arch_specific, $line->[1] if $line->[0] eq 'o'; } delete $byFile{ $f }; } my @as = map { [ 'o', $_ ] } sort @arch_specific; $arch_specific = \@as; } chdir $old_dir; my $out_file = $ARGV[ $#ARGV ]; my %setOptions; my $allowed_name = qr/[A-Za-z0-9_]+/; my $comment = ""; while ( <> ) { if ( /^#\*/ ) { $comment .= $_; next; } my $opt; if ( /^# CONFIG_($allowed_name) is not set$/ ) { $opt = $1; } if ( /^(?:CONFIG_)?($allowed_name)[=\s]/ ) { $opt = $1; } unless ( $opt ) { if ( /\S/ and !/^#-/ ) { warn "Ignored line: $_"; } next; } if ( exists $setOptions{ $opt } ) { die "OPTION $opt REDEFINED"; } chomp; $setOptions{ $opt } = $comment . $_; $comment = ""; } sub file_out { my $file = shift; my $any_out = 0; my @out; push @out, "#-", "#- *** FILE: $file ***", "#-"; my $file_lines = $byFile{ $file }; foreach my $line ( @{$file_lines} ) { my ($type, $data) = @$line; if ( $type eq 'o' ) { if ( exists $setOptions{ $data } ) { push @out, $setOptions{ $data }; delete $setOptions{ $data }; $any_out = 1; } } elsif ( $type eq 'c' ) { push @out, "#- $data"; } elsif ( $type eq 's' ) { push @out, "#- file $data goes here"; } } if ( $any_out ) { return "\n" . ( join "\n", @out ) . "\n"; } return ""; } *FILE_OUT = \*STDOUT; if ( $out_file ) { open FILE_OUT, '>', $out_file; } unless ( $arch ) { my @out; foreach my $f ( sort keys %byFile ) { push @out, file_out( $f ); } my $as_name = "arch/* - ARCH SPECIFIC OPTIONS"; $byFile{ $as_name } = $arch_specific; unshift @out, file_out( $as_name ); print FILE_OUT @out; } else { foreach my $f ( sort keys %byFile ) { print FILE_OUT file_out( $f ); } } if ( keys %setOptions ) { print FILE_OUT "\n#-\n#- *** PROBABLY REMOVED OPTIONS ***\n#-\n"; foreach my $k ( sort keys %setOptions ) { print FILE_OUT $setOptions{ $k } . "\n"; } }