|  | #!/usr/bin/perl -w | 
|  | # SPDX-License-Identifier: GPL-2.0 | 
|  |  | 
|  | use strict; | 
|  | use Getopt::Long qw(:config no_auto_abbrev); | 
|  |  | 
|  | my $input_file = "MAINTAINERS"; | 
|  | my $output_file = "MAINTAINERS.new"; | 
|  | my $output_section = "SECTION.new"; | 
|  | my $help = 0; | 
|  | my $order = 0; | 
|  | my $P = $0; | 
|  |  | 
|  | if (!GetOptions( | 
|  | 'input=s' => \$input_file, | 
|  | 'output=s' => \$output_file, | 
|  | 'section=s' => \$output_section, | 
|  | 'order!' => \$order, | 
|  | 'h|help|usage' => \$help, | 
|  | )) { | 
|  | die "$P: invalid argument - use --help if necessary\n"; | 
|  | } | 
|  |  | 
|  | if ($help != 0) { | 
|  | usage(); | 
|  | exit 0; | 
|  | } | 
|  |  | 
|  | sub usage { | 
|  | print <<EOT; | 
|  | usage: $P [options] <pattern matching regexes> | 
|  |  | 
|  | --input => MAINTAINERS file to read (default: MAINTAINERS) | 
|  | --output => sorted MAINTAINERS file to write (default: MAINTAINERS.new) | 
|  | --section => new sorted MAINTAINERS file to write to (default: SECTION.new) | 
|  | --order => Use the preferred section content output ordering (default: 0) | 
|  | Preferred ordering of section output is: | 
|  | M:  Person acting as a maintainer | 
|  | R:  Person acting as a patch reviewer | 
|  | L:  Mailing list where patches should be sent | 
|  | S:  Maintenance status | 
|  | W:  URI for general information | 
|  | Q:  URI for patchwork tracking | 
|  | B:  URI for bug tracking/submission | 
|  | C:  URI for chat | 
|  | P:  URI or file for subsystem specific coding styles | 
|  | T:  SCM tree type and location | 
|  | F:  File and directory pattern | 
|  | X:  File and directory exclusion pattern | 
|  | N:  File glob | 
|  | K:  Keyword - patch content regex | 
|  |  | 
|  | If <pattern match regexes> exist, then the sections that match the | 
|  | regexes are not written to the output file but are written to the | 
|  | section file. | 
|  |  | 
|  | EOT | 
|  | } | 
|  |  | 
|  | # sort comparison functions | 
|  | sub by_category($$) { | 
|  | my ($a, $b) = @_; | 
|  |  | 
|  | $a = uc $a; | 
|  | $b = uc $b; | 
|  |  | 
|  | # This always sorts last | 
|  | $a =~ s/THE REST/ZZZZZZ/g; | 
|  | $b =~ s/THE REST/ZZZZZZ/g; | 
|  |  | 
|  | return $a cmp $b; | 
|  | } | 
|  |  | 
|  | sub by_pattern($$) { | 
|  | my ($a, $b) = @_; | 
|  | my $preferred_order = 'MRLSWQBCPTFXNK'; | 
|  |  | 
|  | my $a1 = uc(substr($a, 0, 1)); | 
|  | my $b1 = uc(substr($b, 0, 1)); | 
|  |  | 
|  | my $a_index = index($preferred_order, $a1); | 
|  | my $b_index = index($preferred_order, $b1); | 
|  |  | 
|  | $a_index = 1000 if ($a_index == -1); | 
|  | $b_index = 1000 if ($b_index == -1); | 
|  |  | 
|  | if (($a1 =~ /^F$/ && $b1 =~ /^F$/) || | 
|  | ($a1 =~ /^X$/ && $b1 =~ /^X$/)) { | 
|  | return $a cmp $b; | 
|  | } | 
|  |  | 
|  | if ($a_index < $b_index) { | 
|  | return -1; | 
|  | } elsif ($a_index == $b_index) { | 
|  | return 0; | 
|  | } else { | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | sub trim { | 
|  | my $s = shift; | 
|  | $s =~ s/\s+$//; | 
|  | $s =~ s/^\s+//; | 
|  | return $s; | 
|  | } | 
|  |  | 
|  | sub alpha_output { | 
|  | my ($hashref, $filename) = (@_); | 
|  |  | 
|  | return if ! scalar(keys %$hashref); | 
|  |  | 
|  | open(my $file, '>', "$filename") or die "$P: $filename: open failed - $!\n"; | 
|  | my $separator; | 
|  | foreach my $key (sort by_category keys %$hashref) { | 
|  | if ($key eq " ") { | 
|  | print $file $$hashref{$key}; | 
|  | } else { | 
|  | if (! defined $separator) { | 
|  | $separator = "\n"; | 
|  | } else { | 
|  | print $file $separator; | 
|  | } | 
|  | print $file $key . "\n"; | 
|  | if ($order) { | 
|  | foreach my $pattern (sort by_pattern split('\n', %$hashref{$key})) { | 
|  | print $file ($pattern . "\n"); | 
|  | } | 
|  | } else { | 
|  | foreach my $pattern (split('\n', %$hashref{$key})) { | 
|  | print $file ($pattern . "\n"); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | close($file); | 
|  | } | 
|  |  | 
|  | sub file_input { | 
|  | my ($hashref, $filename) = (@_); | 
|  |  | 
|  | my $lastline = ""; | 
|  | my $case = " "; | 
|  | $$hashref{$case} = ""; | 
|  |  | 
|  | open(my $file, '<', "$filename") or die "$P: $filename: open failed - $!\n"; | 
|  |  | 
|  | while (<$file>) { | 
|  | my $line = $_; | 
|  |  | 
|  | # Pattern line? | 
|  | if ($line =~ m/^([A-Z]):\s*(.*)/) { | 
|  | $line = $1 . ":\t" . trim($2) . "\n"; | 
|  | if ($lastline eq "") { | 
|  | $$hashref{$case} = $$hashref{$case} . $line; | 
|  | next; | 
|  | } | 
|  | $case = trim($lastline); | 
|  | exists $$hashref{$case} and die "Header '$case' already exists"; | 
|  | $$hashref{$case} = $line; | 
|  | $lastline = ""; | 
|  | next; | 
|  | } | 
|  |  | 
|  | if ($case eq " ") { | 
|  | $$hashref{$case} = $$hashref{$case} . $lastline; | 
|  | $lastline = $line; | 
|  | next; | 
|  | } | 
|  | trim($lastline) eq "" or die ("Odd non-pattern line '$lastline' for '$case'"); | 
|  | $lastline = $line; | 
|  | } | 
|  | $$hashref{$case} = $$hashref{$case} . $lastline; | 
|  | close($file); | 
|  | } | 
|  |  | 
|  | my %hash; | 
|  | my %new_hash; | 
|  |  | 
|  | file_input(\%hash, $input_file); | 
|  |  | 
|  | foreach my $type (@ARGV) { | 
|  | foreach my $key (keys %hash) { | 
|  | if ($key =~ /$type/ || $hash{$key} =~ /$type/) { | 
|  | $new_hash{$key} = $hash{$key}; | 
|  | delete $hash{$key}; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | alpha_output(\%hash, $output_file); | 
|  | alpha_output(\%new_hash, $output_section); | 
|  |  | 
|  | exit(0); |