1#!/usr/bin/perl -w 2# SPDX-License-Identifier: GPL-2.0 3 4use strict; 5use Getopt::Long qw(:config no_auto_abbrev); 6 7my $input_file = "MAINTAINERS"; 8my $output_file = "MAINTAINERS.new"; 9my $output_section = "SECTION.new"; 10my $help = 0; 11my $order = 0; 12my $P = $0; 13 14if (!GetOptions( 15 'input=s' => \$input_file, 16 'output=s' => \$output_file, 17 'section=s' => \$output_section, 18 'order!' => \$order, 19 'h|help|usage' => \$help, 20 )) { 21 die "$P: invalid argument - use --help if necessary\n"; 22} 23 24if ($help != 0) { 25 usage(); 26 exit 0; 27} 28 29sub usage { 30 print <<EOT; 31usage: $P [options] <pattern matching regexes> 32 33 --input => MAINTAINERS file to read (default: MAINTAINERS) 34 --output => sorted MAINTAINERS file to write (default: MAINTAINERS.new) 35 --section => new sorted MAINTAINERS file to write to (default: SECTION.new) 36 --order => Use the preferred section content output ordering (default: 0) 37 Preferred ordering of section output is: 38 M: Person acting as a maintainer 39 R: Person acting as a patch reviewer 40 L: Mailing list where patches should be sent 41 S: Maintenance status 42 W: URI for general information 43 Q: URI for patchwork tracking 44 B: URI for bug tracking/submission 45 C: URI for chat 46 P: URI or file for subsystem specific coding styles 47 T: SCM tree type and location 48 F: File and directory pattern 49 X: File and directory exclusion pattern 50 N: File glob 51 K: Keyword - patch content regex 52 53If <pattern match regexes> exist, then the sections that match the 54regexes are not written to the output file but are written to the 55section file. 56 57EOT 58} 59 60# sort comparison functions 61sub by_category($$) { 62 my ($a, $b) = @_; 63 64 $a = uc $a; 65 $b = uc $b; 66 67 # This always sorts last 68 $a =~ s/THE REST/ZZZZZZ/g; 69 $b =~ s/THE REST/ZZZZZZ/g; 70 71 return $a cmp $b; 72} 73 74sub by_pattern($$) { 75 my ($a, $b) = @_; 76 my $preferred_order = 'MRLSWQBCPTFXNK'; 77 78 my $a1 = uc(substr($a, 0, 1)); 79 my $b1 = uc(substr($b, 0, 1)); 80 81 my $a_index = index($preferred_order, $a1); 82 my $b_index = index($preferred_order, $b1); 83 84 $a_index = 1000 if ($a_index == -1); 85 $b_index = 1000 if ($b_index == -1); 86 87 if (($a1 =~ /^F$/ && $b1 =~ /^F$/) || 88 ($a1 =~ /^X$/ && $b1 =~ /^X$/)) { 89 return $a cmp $b; 90 } 91 92 if ($a_index < $b_index) { 93 return -1; 94 } elsif ($a_index == $b_index) { 95 return 0; 96 } else { 97 return 1; 98 } 99} 100 101sub trim { 102 my $s = shift; 103 $s =~ s/\s+$//; 104 $s =~ s/^\s+//; 105 return $s; 106} 107 108sub alpha_output { 109 my ($hashref, $filename) = (@_); 110 111 return if ! scalar(keys %$hashref); 112 113 open(my $file, '>', "$filename") or die "$P: $filename: open failed - $!\n"; 114 my $separator; 115 foreach my $key (sort by_category keys %$hashref) { 116 if ($key eq " ") { 117 print $file $$hashref{$key}; 118 } else { 119 if (! defined $separator) { 120 $separator = "\n"; 121 } else { 122 print $file $separator; 123 } 124 print $file $key . "\n"; 125 if ($order) { 126 foreach my $pattern (sort by_pattern split('\n', %$hashref{$key})) { 127 print $file ($pattern . "\n"); 128 } 129 } else { 130 foreach my $pattern (split('\n', %$hashref{$key})) { 131 print $file ($pattern . "\n"); 132 } 133 } 134 } 135 } 136 close($file); 137} 138 139sub file_input { 140 my ($hashref, $filename) = (@_); 141 142 my $lastline = ""; 143 my $case = " "; 144 $$hashref{$case} = ""; 145 146 open(my $file, '<', "$filename") or die "$P: $filename: open failed - $!\n"; 147 148 while (<$file>) { 149 my $line = $_; 150 151 # Pattern line? 152 if ($line =~ m/^([A-Z]):\s*(.*)/) { 153 $line = $1 . ":\t" . trim($2) . "\n"; 154 if ($lastline eq "") { 155 $$hashref{$case} = $$hashref{$case} . $line; 156 next; 157 } 158 $case = trim($lastline); 159 exists $$hashref{$case} and die "Header '$case' already exists"; 160 $$hashref{$case} = $line; 161 $lastline = ""; 162 next; 163 } 164 165 if ($case eq " ") { 166 $$hashref{$case} = $$hashref{$case} . $lastline; 167 $lastline = $line; 168 next; 169 } 170 trim($lastline) eq "" or die ("Odd non-pattern line '$lastline' for '$case'"); 171 $lastline = $line; 172 } 173 $$hashref{$case} = $$hashref{$case} . $lastline; 174 close($file); 175} 176 177my %hash; 178my %new_hash; 179 180file_input(\%hash, $input_file); 181 182foreach my $type (@ARGV) { 183 foreach my $key (keys %hash) { 184 if ($key =~ /$type/ || $hash{$key} =~ /$type/) { 185 $new_hash{$key} = $hash{$key}; 186 delete $hash{$key}; 187 } 188 } 189} 190 191alpha_output(\%hash, $output_file); 192alpha_output(\%new_hash, $output_section); 193 194exit(0); 195