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