All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] get_maintainer: add patch-only keyword matching
@ 2023-09-27  3:19 Justin Stitt
  2023-09-27  3:19 ` [PATCH 1/3] MAINTAINERS: add documentation for D: Justin Stitt
                   ` (3 more replies)
  0 siblings, 4 replies; 16+ messages in thread
From: Justin Stitt @ 2023-09-27  3:19 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello, Justin Stitt

This series aims to add "D:" which behaves exactly the same as "K:" but
works only on patch files.

The goal of this is to reduce noise when folks use get_maintainer on
tree files as opposed to patches. This use case should be steered away
from [1] but "D:" should help maintainers reduce noise in their inboxes
regardless, especially when matching omnipresent keywords like [2]. In
the event of [2] Kees would be to/cc'd from folks running get_maintainer
on _any_ file containing "__counted_by". The number of these files is
rising and I fear for his inbox as his goal, as I understand it, is to
simply monitor the introduction of new __counted_by annotations to
ensure accurate semantics.

See [3/3] for an illustrative example.

This series also includes a formatting pass over get_maintainer because
I personally found it difficult to parse with the human eye.

[1]: https://lore.kernel.org/all/20230726151515.1650519-1-kuba@kernel.org/
[2]: https://lore.kernel.org/all/20230925172037.work.853-kees@kernel.org/

Signed-off-by: Justin Stitt <justinstitt@google.com>
---
Justin Stitt (3):
      MAINTAINERS: add documentation for D:
      get_maintainer: run perltidy
      get_maintainer: add patch-only pattern matching type

 MAINTAINERS               |    3 +
 scripts/get_maintainer.pl | 3334 +++++++++++++++++++++++----------------------
 2 files changed, 1718 insertions(+), 1619 deletions(-)
---
base-commit: 6465e260f48790807eef06b583b38ca9789b6072
change-id: 20230926-get_maintainer_add_d-07424a814e72

Best regards,
--
Justin Stitt <justinstitt@google.com>


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/3] MAINTAINERS: add documentation for D:
  2023-09-27  3:19 [PATCH 0/3] get_maintainer: add patch-only keyword matching Justin Stitt
@ 2023-09-27  3:19 ` Justin Stitt
  2023-09-27  3:27   ` Joe Perches
  2023-09-27 16:06   ` Kees Cook
  2023-09-27  3:19 ` [PATCH 2/3] get_maintainer: run perltidy Justin Stitt
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 16+ messages in thread
From: Justin Stitt @ 2023-09-27  3:19 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello, Justin Stitt

Document what "D:" does.

This is more or less the same as what "K:" does but only works for patch
files.

See [3/3] for more info and an illustrative example.
---
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b19995690904..de68d2c0cf29 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -59,6 +59,9 @@ Descriptions of section entries and preferred order
 	      matches patches or files that contain one or more of the words
 	      printk, pr_info or pr_err
 	   One regex pattern per line.  Multiple K: lines acceptable.
+  D: *Content regex* (perl extended) pattern match patches only.
+     Usage same as K:.
+
 
 Maintainers List
 ----------------

-- 
2.42.0.582.g8ccd20d70d-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/3] get_maintainer: run perltidy
  2023-09-27  3:19 [PATCH 0/3] get_maintainer: add patch-only keyword matching Justin Stitt
  2023-09-27  3:19 ` [PATCH 1/3] MAINTAINERS: add documentation for D: Justin Stitt
@ 2023-09-27  3:19 ` Justin Stitt
  2023-09-27  3:26   ` Joe Perches
  2023-09-27  3:19 ` [PATCH 3/3] get_maintainer: add patch-only pattern matching type Justin Stitt
  2023-09-27 15:24 ` [PATCH 0/3] get_maintainer: add patch-only keyword matching Nick Desaulniers
  3 siblings, 1 reply; 16+ messages in thread
From: Justin Stitt @ 2023-09-27  3:19 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello, Justin Stitt

I'm a first time contributor to get_maintainer.pl and the formatting is
suspicious. I am not sure if there is a particular reason it is the way
it is but I let my editor format it and submitted the diff here in this
patch.

Note that my next patch [3/3] probably won't apply without this one. If
for some reason we don't want this file formatted I'll send a new patch
series with my changes diff'd against the non-formatted
get_maintainer.pl.

Note that I don't write perl very often and might not be aware of
particular styling decisions that were made. I just let perltidy do its
thing.

There's an online version of perltidy available here [1]

[1]: https://perltidy.com/
---
Note: I used these options (pretty sure these are default)
options="-l=478 -i=4 -ci=4 -vt=2 -cti=0 -pt=1 -bt=1 -sbt=1 -bbt=1 -nsfs -nolq -it=2 -wbb="% + - * / x != == >= <= =~ !~ < > | & = **= += *= &= <<= &&= -= /= |= >>= ||= //= .= %= ^= x="

Note: I did not notice any regressions in my usage of get_maintainer
post-formatting. I'd be surprised if my formatter broke functionality
but you never know.
---
 scripts/get_maintainer.pl | 3325 +++++++++++++++++++++++----------------------
 1 file changed, 1706 insertions(+), 1619 deletions(-)

diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index ab123b498fd9..e679eac96793 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -21,58 +21,58 @@ use Cwd;
 use File::Find;
 use File::Spec::Functions;
 
-my $cur_path = fastgetcwd() . '/';
-my $lk_path = "./";
-my $email = 1;
-my $email_usename = 1;
-my $email_maintainer = 1;
-my $email_reviewer = 1;
-my $email_fixes = 1;
-my $email_list = 1;
-my $email_moderated_list = 1;
-my $email_subscriber_list = 0;
-my $email_git_penguin_chiefs = 0;
-my $email_git = 0;
+my $cur_path                      = fastgetcwd() . '/';
+my $lk_path                       = "./";
+my $email                         = 1;
+my $email_usename                 = 1;
+my $email_maintainer              = 1;
+my $email_reviewer                = 1;
+my $email_fixes                   = 1;
+my $email_list                    = 1;
+my $email_moderated_list          = 1;
+my $email_subscriber_list         = 0;
+my $email_git_penguin_chiefs      = 0;
+my $email_git                     = 0;
 my $email_git_all_signature_types = 0;
-my $email_git_blame = 0;
-my $email_git_blame_signatures = 1;
-my $email_git_fallback = 1;
-my $email_git_min_signatures = 1;
-my $email_git_max_maintainers = 5;
-my $email_git_min_percent = 5;
-my $email_git_since = "1-year-ago";
-my $email_hg_since = "-365";
-my $interactive = 0;
-my $email_remove_duplicates = 1;
-my $email_use_mailmap = 1;
-my $output_multiline = 1;
-my $output_separator = ", ";
-my $output_roles = 0;
-my $output_rolestats = 1;
-my $output_section_maxlen = 50;
-my $scm = 0;
-my $tree = 1;
-my $web = 0;
-my $subsystem = 0;
-my $status = 0;
-my $letters = "";
-my $keywords = 1;
-my $sections = 0;
-my $email_file_emails = 0;
-my $from_filename = 0;
-my $pattern_depth = 0;
-my $self_test = undef;
-my $version = 0;
-my $help = 0;
-my $find_maintainer_files = 0;
+my $email_git_blame               = 0;
+my $email_git_blame_signatures    = 1;
+my $email_git_fallback            = 1;
+my $email_git_min_signatures      = 1;
+my $email_git_max_maintainers     = 5;
+my $email_git_min_percent         = 5;
+my $email_git_since               = "1-year-ago";
+my $email_hg_since                = "-365";
+my $interactive                   = 0;
+my $email_remove_duplicates       = 1;
+my $email_use_mailmap             = 1;
+my $output_multiline              = 1;
+my $output_separator              = ", ";
+my $output_roles                  = 0;
+my $output_rolestats              = 1;
+my $output_section_maxlen         = 50;
+my $scm                           = 0;
+my $tree                          = 1;
+my $web                           = 0;
+my $subsystem                     = 0;
+my $status                        = 0;
+my $letters                       = "";
+my $keywords                      = 1;
+my $sections                      = 0;
+my $email_file_emails             = 0;
+my $from_filename                 = 0;
+my $pattern_depth                 = 0;
+my $self_test                     = undef;
+my $version                       = 0;
+my $help                          = 0;
+my $find_maintainer_files         = 0;
 my $maintainer_path;
 my $vcs_used = 0;
 
 my $exit = 0;
 
-my @files = ();
-my @fixes = ();			# If a patch description includes Fixes: lines
-my @range = ();
+my @files       = ();
+my @fixes       = ();    # If a patch description includes Fixes: lines
+my @range       = ();
 my @keyword_tvi = ();
 my @file_emails = ();
 
@@ -80,29 +80,30 @@ my %commit_author_hash;
 my %commit_signer_hash;
 
 my @penguin_chief = ();
-push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
+push( @penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org" );
+
 #Andrew wants in on most everything - 2009/01/14
 #push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
 
 my @penguin_chief_names = ();
 foreach my $chief (@penguin_chief) {
-    if ($chief =~ m/^(.*):(.*)/) {
-	my $chief_name = $1;
-	my $chief_addr = $2;
-	push(@penguin_chief_names, $chief_name);
+    if ( $chief =~ m/^(.*):(.*)/ ) {
+        my $chief_name = $1;
+        my $chief_addr = $2;
+        push( @penguin_chief_names, $chief_name );
     }
 }
-my $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
+my $penguin_chiefs = "\(" . join( "|", @penguin_chief_names ) . "\)";
 
 # Signature types of people who are either
 # 	a) responsible for the code in question, or
 # 	b) familiar enough with it to give relevant feedback
 my @signature_tags = ();
-push(@signature_tags, "Signed-off-by:");
-push(@signature_tags, "Reviewed-by:");
-push(@signature_tags, "Acked-by:");
+push( @signature_tags, "Signed-off-by:" );
+push( @signature_tags, "Reviewed-by:" );
+push( @signature_tags, "Acked-by:" );
 
-my $signature_pattern = "\(" . join("|", @signature_tags) . "\)";
+my $signature_pattern = "\(" . join( "|", @signature_tags ) . "\)";
 
 # rfc822 email address - preloaded methods go here.
 my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
@@ -113,282 +114,250 @@ my $rfc822_char = '[\\000-\\377]';
 my %VCS_cmds;
 
 my %VCS_cmds_git = (
-    "execute_cmd" => \&git_execute_cmd,
-    "available" => '(which("git") ne "") && (-e ".git")',
-    "find_signers_cmd" =>
-	"git log --no-color --follow --since=\$email_git_since " .
-	    '--numstat --no-merges ' .
-	    '--format="GitCommit: %H%n' .
-		      'GitAuthor: %an <%ae>%n' .
-		      'GitDate: %aD%n' .
-		      'GitSubject: %s%n' .
-		      '%b%n"' .
-	    " -- \$file",
-    "find_commit_signers_cmd" =>
-	"git log --no-color " .
-	    '--numstat ' .
-	    '--format="GitCommit: %H%n' .
-		      'GitAuthor: %an <%ae>%n' .
-		      'GitDate: %aD%n' .
-		      'GitSubject: %s%n' .
-		      '%b%n"' .
-	    " -1 \$commit",
-    "find_commit_author_cmd" =>
-	"git log --no-color " .
-	    '--numstat ' .
-	    '--format="GitCommit: %H%n' .
-		      'GitAuthor: %an <%ae>%n' .
-		      'GitDate: %aD%n' .
-		      'GitSubject: %s%n"' .
-	    " -1 \$commit",
-    "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
-    "blame_file_cmd" => "git blame -l \$file",
-    "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
-    "blame_commit_pattern" => "^([0-9a-f]+) ",
-    "author_pattern" => "^GitAuthor: (.*)",
-    "subject_pattern" => "^GitSubject: (.*)",
-    "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$",
-    "file_exists_cmd" => "git ls-files \$file",
-    "list_files_cmd" => "git ls-files \$file",
+    "execute_cmd"             => \&git_execute_cmd,
+    "available"               => '(which("git") ne "") && (-e ".git")',
+    "find_signers_cmd"        => "git log --no-color --follow --since=\$email_git_since " . '--numstat --no-merges ' . '--format="GitCommit: %H%n' . 'GitAuthor: %an <%ae>%n' . 'GitDate: %aD%n' . 'GitSubject: %s%n' . '%b%n"' . " -- \$file",
+    "find_commit_signers_cmd" => "git log --no-color " . '--numstat ' . '--format="GitCommit: %H%n' . 'GitAuthor: %an <%ae>%n' . 'GitDate: %aD%n' . 'GitSubject: %s%n' . '%b%n"' . " -1 \$commit",
+    "find_commit_author_cmd"  => "git log --no-color " . '--numstat ' . '--format="GitCommit: %H%n' . 'GitAuthor: %an <%ae>%n' . 'GitDate: %aD%n' . 'GitSubject: %s%n"' . " -1 \$commit",
+    "blame_range_cmd"         => "git blame -l -L \$diff_start,+\$diff_length \$file",
+    "blame_file_cmd"          => "git blame -l \$file",
+    "commit_pattern"          => "^GitCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern"    => "^([0-9a-f]+) ",
+    "author_pattern"          => "^GitAuthor: (.*)",
+    "subject_pattern"         => "^GitSubject: (.*)",
+    "stat_pattern"            => "^(\\d+)\\t(\\d+)\\t\$file\$",
+    "file_exists_cmd"         => "git ls-files \$file",
+    "list_files_cmd"          => "git ls-files \$file",
 );
 
 my %VCS_cmds_hg = (
-    "execute_cmd" => \&hg_execute_cmd,
-    "available" => '(which("hg") ne "") && (-d ".hg")',
-    "find_signers_cmd" =>
-	"hg log --date=\$email_hg_since " .
-	    "--template='HgCommit: {node}\\n" .
-	                "HgAuthor: {author}\\n" .
-			"HgSubject: {desc}\\n'" .
-	    " -- \$file",
-    "find_commit_signers_cmd" =>
-	"hg log " .
-	    "--template='HgSubject: {desc}\\n'" .
-	    " -r \$commit",
-    "find_commit_author_cmd" =>
-	"hg log " .
-	    "--template='HgCommit: {node}\\n" .
-		        "HgAuthor: {author}\\n" .
-			"HgSubject: {desc|firstline}\\n'" .
-	    " -r \$commit",
-    "blame_range_cmd" => "",		# not supported
-    "blame_file_cmd" => "hg blame -n \$file",
-    "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
-    "blame_commit_pattern" => "^([ 0-9a-f]+):",
-    "author_pattern" => "^HgAuthor: (.*)",
-    "subject_pattern" => "^HgSubject: (.*)",
-    "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$",
-    "file_exists_cmd" => "hg files \$file",
-    "list_files_cmd" => "hg manifest -R \$file",
+    "execute_cmd"             => \&hg_execute_cmd,
+    "available"               => '(which("hg") ne "") && (-d ".hg")',
+    "find_signers_cmd"        => "hg log --date=\$email_hg_since " . "--template='HgCommit: {node}\\n" . "HgAuthor: {author}\\n" . "HgSubject: {desc}\\n'" . " -- \$file",
+    "find_commit_signers_cmd" => "hg log " . "--template='HgSubject: {desc}\\n'" . " -r \$commit",
+    "find_commit_author_cmd"  => "hg log " . "--template='HgCommit: {node}\\n" . "HgAuthor: {author}\\n" . "HgSubject: {desc|firstline}\\n'" . " -r \$commit",
+    "blame_range_cmd"         => "",                                                                                                                                         # not supported
+    "blame_file_cmd"          => "hg blame -n \$file",
+    "commit_pattern"          => "^HgCommit: ([0-9a-f]{40,40})",
+    "blame_commit_pattern"    => "^([ 0-9a-f]+):",
+    "author_pattern"          => "^HgAuthor: (.*)",
+    "subject_pattern"         => "^HgSubject: (.*)",
+    "stat_pattern"            => "^(\\d+)\t(\\d+)\t\$file\$",
+    "file_exists_cmd"         => "hg files \$file",
+    "list_files_cmd"          => "hg manifest -R \$file",
 );
 
 my $conf = which_conf(".get_maintainer.conf");
-if (-f $conf) {
+if ( -f $conf ) {
     my @conf_args;
-    open(my $conffile, '<', "$conf")
-	or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
+    open( my $conffile, '<', "$conf" )
+        or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
 
     while (<$conffile>) {
-	my $line = $_;
+        my $line = $_;
 
-	$line =~ s/\s*\n?$//g;
-	$line =~ s/^\s*//g;
-	$line =~ s/\s+/ /g;
+        $line =~ s/\s*\n?$//g;
+        $line =~ s/^\s*//g;
+        $line =~ s/\s+/ /g;
 
-	next if ($line =~ m/^\s*#/);
-	next if ($line =~ m/^\s*$/);
+        next if ( $line =~ m/^\s*#/ );
+        next if ( $line =~ m/^\s*$/ );
 
-	my @words = split(" ", $line);
-	foreach my $word (@words) {
-	    last if ($word =~ m/^#/);
-	    push (@conf_args, $word);
-	}
+        my @words = split( " ", $line );
+        foreach my $word (@words) {
+            last if ( $word =~ m/^#/ );
+            push( @conf_args, $word );
+        }
     }
     close($conffile);
-    unshift(@ARGV, @conf_args) if @conf_args;
+    unshift( @ARGV, @conf_args ) if @conf_args;
 }
 
 my @ignore_emails = ();
-my $ignore_file = which_conf(".get_maintainer.ignore");
-if (-f $ignore_file) {
-    open(my $ignore, '<', "$ignore_file")
-	or warn "$P: Can't find a readable .get_maintainer.ignore file $!\n";
+my $ignore_file   = which_conf(".get_maintainer.ignore");
+if ( -f $ignore_file ) {
+    open( my $ignore, '<', "$ignore_file" )
+        or warn "$P: Can't find a readable .get_maintainer.ignore file $!\n";
     while (<$ignore>) {
-	my $line = $_;
+        my $line = $_;
 
-	$line =~ s/\s*\n?$//;
-	$line =~ s/^\s*//;
-	$line =~ s/\s+$//;
-	$line =~ s/#.*$//;
+        $line =~ s/\s*\n?$//;
+        $line =~ s/^\s*//;
+        $line =~ s/\s+$//;
+        $line =~ s/#.*$//;
 
-	next if ($line =~ m/^\s*$/);
-	if (rfc822_valid($line)) {
-	    push(@ignore_emails, $line);
-	}
+        next if ( $line =~ m/^\s*$/ );
+        if ( rfc822_valid($line) ) {
+            push( @ignore_emails, $line );
+        }
     }
     close($ignore);
 }
 
-if ($#ARGV > 0) {
+if ( $#ARGV > 0 ) {
     foreach (@ARGV) {
-        if ($_ =~ /^-{1,2}self-test(?:=|$)/) {
+        if ( $_ =~ /^-{1,2}self-test(?:=|$)/ ) {
             die "$P: using --self-test does not allow any other option or argument\n";
         }
     }
 }
 
 if (!GetOptions(
-		'email!' => \$email,
-		'git!' => \$email_git,
-		'git-all-signature-types!' => \$email_git_all_signature_types,
-		'git-blame!' => \$email_git_blame,
-		'git-blame-signatures!' => \$email_git_blame_signatures,
-		'git-fallback!' => \$email_git_fallback,
-		'git-chief-penguins!' => \$email_git_penguin_chiefs,
-		'git-min-signatures=i' => \$email_git_min_signatures,
-		'git-max-maintainers=i' => \$email_git_max_maintainers,
-		'git-min-percent=i' => \$email_git_min_percent,
-		'git-since=s' => \$email_git_since,
-		'hg-since=s' => \$email_hg_since,
-		'i|interactive!' => \$interactive,
-		'remove-duplicates!' => \$email_remove_duplicates,
-		'mailmap!' => \$email_use_mailmap,
-		'm!' => \$email_maintainer,
-		'r!' => \$email_reviewer,
-		'n!' => \$email_usename,
-		'l!' => \$email_list,
-		'fixes!' => \$email_fixes,
-		'moderated!' => \$email_moderated_list,
-		's!' => \$email_subscriber_list,
-		'multiline!' => \$output_multiline,
-		'roles!' => \$output_roles,
-		'rolestats!' => \$output_rolestats,
-		'separator=s' => \$output_separator,
-		'subsystem!' => \$subsystem,
-		'status!' => \$status,
-		'scm!' => \$scm,
-		'tree!' => \$tree,
-		'web!' => \$web,
-		'letters=s' => \$letters,
-		'pattern-depth=i' => \$pattern_depth,
-		'k|keywords!' => \$keywords,
-		'sections!' => \$sections,
-		'fe|file-emails!' => \$email_file_emails,
-		'f|file' => \$from_filename,
-		'find-maintainer-files' => \$find_maintainer_files,
-		'mpath|maintainer-path=s' => \$maintainer_path,
-		'self-test:s' => \$self_test,
-		'v|version' => \$version,
-		'h|help|usage' => \$help,
-		)) {
+        'email!'                   => \$email,
+        'git!'                     => \$email_git,
+        'git-all-signature-types!' => \$email_git_all_signature_types,
+        'git-blame!'               => \$email_git_blame,
+        'git-blame-signatures!'    => \$email_git_blame_signatures,
+        'git-fallback!'            => \$email_git_fallback,
+        'git-chief-penguins!'      => \$email_git_penguin_chiefs,
+        'git-min-signatures=i'     => \$email_git_min_signatures,
+        'git-max-maintainers=i'    => \$email_git_max_maintainers,
+        'git-min-percent=i'        => \$email_git_min_percent,
+        'git-since=s'              => \$email_git_since,
+        'hg-since=s'               => \$email_hg_since,
+        'i|interactive!'           => \$interactive,
+        'remove-duplicates!'       => \$email_remove_duplicates,
+        'mailmap!'                 => \$email_use_mailmap,
+        'm!'                       => \$email_maintainer,
+        'r!'                       => \$email_reviewer,
+        'n!'                       => \$email_usename,
+        'l!'                       => \$email_list,
+        'fixes!'                   => \$email_fixes,
+        'moderated!'               => \$email_moderated_list,
+        's!'                       => \$email_subscriber_list,
+        'multiline!'               => \$output_multiline,
+        'roles!'                   => \$output_roles,
+        'rolestats!'               => \$output_rolestats,
+        'separator=s'              => \$output_separator,
+        'subsystem!'               => \$subsystem,
+        'status!'                  => \$status,
+        'scm!'                     => \$scm,
+        'tree!'                    => \$tree,
+        'web!'                     => \$web,
+        'letters=s'                => \$letters,
+        'pattern-depth=i'          => \$pattern_depth,
+        'k|keywords!'              => \$keywords,
+        'sections!'                => \$sections,
+        'fe|file-emails!'          => \$email_file_emails,
+        'f|file'                   => \$from_filename,
+        'find-maintainer-files'    => \$find_maintainer_files,
+        'mpath|maintainer-path=s'  => \$maintainer_path,
+        'self-test:s'              => \$self_test,
+        'v|version'                => \$version,
+        'h|help|usage'             => \$help,
+    )
+    )
+{
     die "$P: invalid argument - use --help if necessary\n";
 }
 
-if ($help != 0) {
+if ( $help != 0 ) {
     usage();
     exit 0;
 }
 
-if ($version != 0) {
+if ( $version != 0 ) {
     print("${P} ${V}\n");
     exit 0;
 }
 
-if (defined $self_test) {
+if ( defined $self_test ) {
     read_all_maintainer_files();
     self_test();
     exit 0;
 }
 
-if (-t STDIN && !@ARGV) {
+if ( -t STDIN && !@ARGV ) {
+
     # We're talking to a terminal, but have no command line arguments.
     die "$P: missing patchfile or -f file - use --help if necessary\n";
 }
 
-$output_multiline = 0 if ($output_separator ne ", ");
+$output_multiline = 0 if ( $output_separator ne ", " );
 $output_rolestats = 1 if ($interactive);
-$output_roles = 1 if ($output_rolestats);
-
-if ($sections || $letters ne "") {
-    $sections = 1;
-    $email = 0;
-    $email_list = 0;
-    $scm = 0;
-    $status = 0;
-    $subsystem = 0;
-    $web = 0;
-    $keywords = 0;
+$output_roles     = 1 if ($output_rolestats);
+
+if ( $sections || $letters ne "" ) {
+    $sections    = 1;
+    $email       = 0;
+    $email_list  = 0;
+    $scm         = 0;
+    $status      = 0;
+    $subsystem   = 0;
+    $web         = 0;
+    $keywords    = 0;
     $interactive = 0;
-} else {
+}
+else {
     my $selections = $email + $scm + $status + $subsystem + $web;
-    if ($selections == 0) {
-	die "$P:  Missing required option: email, scm, status, subsystem or web\n";
+    if ( $selections == 0 ) {
+        die "$P:  Missing required option: email, scm, status, subsystem or web\n";
     }
 }
 
-if ($email &&
-    ($email_maintainer + $email_reviewer +
-     $email_list + $email_subscriber_list +
-     $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
+if ( $email
+    && ( $email_maintainer + $email_reviewer + $email_list + $email_subscriber_list + $email_git + $email_git_penguin_chiefs + $email_git_blame ) == 0 )
+{
     die "$P: Please select at least 1 email option\n";
 }
 
-if ($tree && !top_of_kernel_tree($lk_path)) {
-    die "$P: The current directory does not appear to be "
-	. "a linux kernel source tree.\n";
+if ( $tree && !top_of_kernel_tree($lk_path) ) {
+    die "$P: The current directory does not appear to be " . "a linux kernel source tree.\n";
 }
 
 ## Read MAINTAINERS for type/value pairs
 
 my @typevalue = ();
 my %keyword_hash;
-my @mfiles = ();
+my @mfiles         = ();
 my @self_test_info = ();
 
 sub read_maintainer_file {
     my ($file) = @_;
 
-    open (my $maint, '<', "$file")
-	or die "$P: Can't open MAINTAINERS file '$file': $!\n";
+    open( my $maint, '<', "$file" )
+        or die "$P: Can't open MAINTAINERS file '$file': $!\n";
     my $i = 1;
     while (<$maint>) {
-	my $line = $_;
-	chomp $line;
-
-	if ($line =~ m/^([A-Z]):\s*(.*)/) {
-	    my $type = $1;
-	    my $value = $2;
-
-	    ##Filename pattern matching
-	    if ($type eq "F" || $type eq "X") {
-		$value =~ s@\.@\\\.@g;       ##Convert . to \.
-		$value =~ s/\*/\.\*/g;       ##Convert * to .*
-		$value =~ s/\?/\./g;         ##Convert ? to .
-		##if pattern is a directory and it lacks a trailing slash, add one
-		if ((-d $value)) {
-		    $value =~ s@([^/])$@$1/@;
-		}
-	    } elsif ($type eq "K") {
-		$keyword_hash{@typevalue} = $value;
-	    }
-	    push(@typevalue, "$type:$value");
-	} elsif (!(/^\s*$/ || /^\s*\#/)) {
-	    push(@typevalue, $line);
-	}
-	if (defined $self_test) {
-	    push(@self_test_info, {file=>$file, linenr=>$i, line=>$line});
-	}
-	$i++;
+        my $line = $_;
+        chomp $line;
+
+        if ( $line =~ m/^([A-Z]):\s*(.*)/ ) {
+            my $type  = $1;
+            my $value = $2;
+
+            ##Filename pattern matching
+            if ( $type eq "F" || $type eq "X" ) {
+                $value =~ s@\.@\\\.@g;    ##Convert . to \.
+                $value =~ s/\*/\.\*/g;    ##Convert * to .*
+                $value =~ s/\?/\./g;      ##Convert ? to .
+                ##if pattern is a directory and it lacks a trailing slash, add one
+                if ( ( -d $value ) ) {
+                    $value =~ s@([^/])$@$1/@;
+                }
+            }
+            elsif ( $type eq "K" ) {
+                $keyword_hash{@typevalue} = $value;
+            }
+            push( @typevalue, "$type:$value" );
+        }
+        elsif ( !( /^\s*$/ || /^\s*\#/ ) ) {
+            push( @typevalue, $line );
+        }
+        if ( defined $self_test ) {
+            push( @self_test_info, { file => $file, linenr => $i, line => $line } );
+        }
+        $i++;
     }
     close($maint);
 }
 
 sub find_is_maintainer_file {
     my ($file) = $_;
-    return if ($file !~ m@/MAINTAINERS$@);
+    return if ( $file !~ m@/MAINTAINERS$@ );
     $file = $File::Find::name;
-    return if (! -f $file);
-    push(@mfiles, $file);
+    return if ( !-f $file );
+    push( @mfiles, $file );
 }
 
 sub find_ignore_git {
@@ -399,51 +368,58 @@ read_all_maintainer_files();
 
 sub read_all_maintainer_files {
     my $path = "${lk_path}MAINTAINERS";
-    if (defined $maintainer_path) {
-	$path = $maintainer_path;
-	# Perl Cookbook tilde expansion if necessary
-	$path =~ s@^~([^/]*)@ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7])@ex;
-    }
-
-    if (-d $path) {
-	$path .= '/' if ($path !~ m@/$@);
-	if ($find_maintainer_files) {
-	    find( { wanted => \&find_is_maintainer_file,
-		    preprocess => \&find_ignore_git,
-		    no_chdir => 1,
-		}, "$path");
-	} else {
-	    opendir(DIR, "$path") or die $!;
-	    my @files = readdir(DIR);
-	    closedir(DIR);
-	    foreach my $file (@files) {
-		push(@mfiles, "$path$file") if ($file !~ /^\./);
-	    }
-	}
-    } elsif (-f "$path") {
-	push(@mfiles, "$path");
-    } else {
-	die "$P: MAINTAINER file not found '$path'\n";
-    }
-    die "$P: No MAINTAINER files found in '$path'\n" if (scalar(@mfiles) == 0);
+    if ( defined $maintainer_path ) {
+        $path = $maintainer_path;
+
+        # Perl Cookbook tilde expansion if necessary
+        $path =~ s@^~([^/]*)@ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7])@ex;
+    }
+
+    if ( -d $path ) {
+        $path .= '/' if ( $path !~ m@/$@ );
+        if ($find_maintainer_files) {
+            find(
+                {   wanted     => \&find_is_maintainer_file,
+                    preprocess => \&find_ignore_git,
+                    no_chdir   => 1,
+                },
+                "$path"
+            );
+        }
+        else {
+            opendir( DIR, "$path" ) or die $!;
+            my @files = readdir(DIR);
+            closedir(DIR);
+            foreach my $file (@files) {
+                push( @mfiles, "$path$file" ) if ( $file !~ /^\./ );
+            }
+        }
+    }
+    elsif ( -f "$path" ) {
+        push( @mfiles, "$path" );
+    }
+    else {
+        die "$P: MAINTAINER file not found '$path'\n";
+    }
+    die "$P: No MAINTAINER files found in '$path'\n" if ( scalar(@mfiles) == 0 );
     foreach my $file (@mfiles) {
-	read_maintainer_file("$file");
+        read_maintainer_file("$file");
     }
 }
 
 sub maintainers_in_file {
     my ($file) = @_;
 
-    return if ($file =~ m@\bMAINTAINERS$@);
+    return if ( $file =~ m@\bMAINTAINERS$@ );
 
-    if (-f $file && ($email_file_emails || $file =~ /\.yaml$/)) {
-	open(my $f, '<', $file)
-	    or die "$P: Can't open $file: $!\n";
-	my $text = do { local($/) ; <$f> };
-	close($f);
+    if ( -f $file && ( $email_file_emails || $file =~ /\.yaml$/ ) ) {
+        open( my $f, '<', $file )
+            or die "$P: Can't open $file: $!\n";
+        my $text = do { local ($/); <$f> };
+        close($f);
 
-	my @poss_addr = $text =~ m$[A-Za-zÀ-ÿ\"\' \,\.\+-]*\s*[\,]*\s*[\(\<\{]{0,1}[A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+\.[A-Za-z0-9]+[\)\>\}]{0,1}$g;
-	push(@file_emails, clean_file_emails(@poss_addr));
+        my @poss_addr = $text =~ m$[A-Za-zÀ-ÿ\"\' \,\.\+-]*\s*[\,]*\s*[\(\<\{]{0,1}[A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+\.[A-Za-z0-9]+[\)\>\}]{0,1}$g;
+        push( @file_emails, clean_file_emails(@poss_addr) );
     }
 }
 
@@ -457,181 +433,188 @@ read_mailmap();
 
 sub read_mailmap {
     $mailmap = {
-	names => {},
-	addresses => {}
+        names     => {},
+        addresses => {}
     };
 
-    return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
+    return if ( !$email_use_mailmap || !( -f "${lk_path}.mailmap" ) );
 
-    open(my $mailmap_file, '<', "${lk_path}.mailmap")
-	or warn "$P: Can't open .mailmap: $!\n";
+    open( my $mailmap_file, '<', "${lk_path}.mailmap" )
+        or warn "$P: Can't open .mailmap: $!\n";
 
     while (<$mailmap_file>) {
-	s/#.*$//; #strip comments
-	s/^\s+|\s+$//g; #trim
-
-	next if (/^\s*$/); #skip empty lines
-	#entries have one of the following formats:
-	# name1 <mail1>
-	# <mail1> <mail2>
-	# name1 <mail1> <mail2>
-	# name1 <mail1> name2 <mail2>
-	# (see man git-shortlog)
-
-	if (/^([^<]+)<([^>]+)>$/) {
-	    my $real_name = $1;
-	    my $address = $2;
-
-	    $real_name =~ s/\s+$//;
-	    ($real_name, $address) = parse_email("$real_name <$address>");
-	    $mailmap->{names}->{$address} = $real_name;
-
-	} elsif (/^<([^>]+)>\s*<([^>]+)>$/) {
-	    my $real_address = $1;
-	    my $wrong_address = $2;
-
-	    $mailmap->{addresses}->{$wrong_address} = $real_address;
-
-	} elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/) {
-	    my $real_name = $1;
-	    my $real_address = $2;
-	    my $wrong_address = $3;
-
-	    $real_name =~ s/\s+$//;
-	    ($real_name, $real_address) =
-		parse_email("$real_name <$real_address>");
-	    $mailmap->{names}->{$wrong_address} = $real_name;
-	    $mailmap->{addresses}->{$wrong_address} = $real_address;
-
-	} elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^>]+)>$/) {
-	    my $real_name = $1;
-	    my $real_address = $2;
-	    my $wrong_name = $3;
-	    my $wrong_address = $4;
-
-	    $real_name =~ s/\s+$//;
-	    ($real_name, $real_address) =
-		parse_email("$real_name <$real_address>");
-
-	    $wrong_name =~ s/\s+$//;
-	    ($wrong_name, $wrong_address) =
-		parse_email("$wrong_name <$wrong_address>");
-
-	    my $wrong_email = format_email($wrong_name, $wrong_address, 1);
-	    $mailmap->{names}->{$wrong_email} = $real_name;
-	    $mailmap->{addresses}->{$wrong_email} = $real_address;
-	}
+        s/#.*$//;          #strip comments
+        s/^\s+|\s+$//g;    #trim
+
+        next if (/^\s*$/); #skip empty lines
+                           #entries have one of the following formats:
+                           # name1 <mail1>
+                           # <mail1> <mail2>
+                           # name1 <mail1> <mail2>
+                           # name1 <mail1> name2 <mail2>
+                           # (see man git-shortlog)
+
+        if (/^([^<]+)<([^>]+)>$/) {
+            my $real_name = $1;
+            my $address   = $2;
+
+            $real_name =~ s/\s+$//;
+            ( $real_name, $address ) = parse_email("$real_name <$address>");
+            $mailmap->{names}->{$address} = $real_name;
+
+        }
+        elsif (/^<([^>]+)>\s*<([^>]+)>$/) {
+            my $real_address  = $1;
+            my $wrong_address = $2;
+
+            $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+        }
+        elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/) {
+            my $real_name     = $1;
+            my $real_address  = $2;
+            my $wrong_address = $3;
+
+            $real_name =~ s/\s+$//;
+            ( $real_name, $real_address ) = parse_email("$real_name <$real_address>");
+            $mailmap->{names}->{$wrong_address}     = $real_name;
+            $mailmap->{addresses}->{$wrong_address} = $real_address;
+
+        }
+        elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^>]+)>$/) {
+            my $real_name     = $1;
+            my $real_address  = $2;
+            my $wrong_name    = $3;
+            my $wrong_address = $4;
+
+            $real_name =~ s/\s+$//;
+            ( $real_name, $real_address ) = parse_email("$real_name <$real_address>");
+
+            $wrong_name =~ s/\s+$//;
+            ( $wrong_name, $wrong_address ) = parse_email("$wrong_name <$wrong_address>");
+
+            my $wrong_email = format_email( $wrong_name, $wrong_address, 1 );
+            $mailmap->{names}->{$wrong_email}     = $real_name;
+            $mailmap->{addresses}->{$wrong_email} = $real_address;
+        }
     }
     close($mailmap_file);
 }
 
 ## use the filenames on the command line or find the filenames in the patchfiles
 
-if (!@ARGV) {
-    push(@ARGV, "&STDIN");
+if ( !@ARGV ) {
+    push( @ARGV, "&STDIN" );
 }
 
 foreach my $file (@ARGV) {
-    if ($file ne "&STDIN") {
-	$file = canonpath($file);
-	##if $file is a directory and it lacks a trailing slash, add one
-	if ((-d $file)) {
-	    $file =~ s@([^/])$@$1/@;
-	} elsif (!(-f $file)) {
-	    die "$P: file '${file}' not found\n";
-	}
-    }
-    if ($from_filename && (vcs_exists() && !vcs_file_exists($file))) {
-	warn "$P: file '$file' not found in version control $!\n";
-    }
-    if ($from_filename || ($file ne "&STDIN" && vcs_file_exists($file))) {
-	$file =~ s/^\Q${cur_path}\E//;	#strip any absolute path
-	$file =~ s/^\Q${lk_path}\E//;	#or the path to the lk tree
-	push(@files, $file);
-	if ($file ne "MAINTAINERS" && -f $file && $keywords) {
-	    open(my $f, '<', $file)
-		or die "$P: Can't open $file: $!\n";
-	    my $text = do { local($/) ; <$f> };
-	    close($f);
-	    if ($keywords) {
-		foreach my $line (keys %keyword_hash) {
-		    if ($text =~ m/$keyword_hash{$line}/x) {
-			push(@keyword_tvi, $line);
-		    }
-		}
-	    }
-	}
-    } else {
-	my $file_cnt = @files;
-	my $lastfile;
-
-	open(my $patch, "< $file")
-	    or die "$P: Can't open $file: $!\n";
-
-	# We can check arbitrary information before the patch
-	# like the commit message, mail headers, etc...
-	# This allows us to match arbitrary keywords against any part
-	# of a git format-patch generated file (subject tags, etc...)
-
-	my $patch_prefix = "";			#Parsing the intro
-
-	while (<$patch>) {
-	    my $patch_line = $_;
-	    if (m/^ mode change [0-7]+ => [0-7]+ (\S+)\s*$/) {
-		my $filename = $1;
-		push(@files, $filename);
-	    } elsif (m/^rename (?:from|to) (\S+)\s*$/) {
-		my $filename = $1;
-		push(@files, $filename);
-	    } elsif (m/^diff --git a\/(\S+) b\/(\S+)\s*$/) {
-		my $filename1 = $1;
-		my $filename2 = $2;
-		push(@files, $filename1);
-		push(@files, $filename2);
-	    } elsif (m/^Fixes:\s+([0-9a-fA-F]{6,40})/) {
-		push(@fixes, $1) if ($email_fixes);
-	    } elsif (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) {
-		my $filename = $1;
-		$filename =~ s@^[^/]*/@@;
-		$filename =~ s@\n@@;
-		$lastfile = $filename;
-		push(@files, $filename);
-		$patch_prefix = "^[+-].*";	#Now parsing the actual patch
-	    } elsif (m/^\@\@ -(\d+),(\d+)/) {
-		if ($email_git_blame) {
-		    push(@range, "$lastfile:$1:$2");
-		}
-	    } elsif ($keywords) {
-		foreach my $line (keys %keyword_hash) {
-		    if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) {
-			push(@keyword_tvi, $line);
-		    }
-		}
-	    }
-	}
-	close($patch);
-
-	if ($file_cnt == @files) {
-	    warn "$P: file '${file}' doesn't appear to be a patch.  "
-		. "Add -f to options?\n";
-	}
-	@files = sort_and_uniq(@files);
+    if ( $file ne "&STDIN" ) {
+        $file = canonpath($file);
+        ##if $file is a directory and it lacks a trailing slash, add one
+        if ( ( -d $file ) ) {
+            $file =~ s@([^/])$@$1/@;
+        }
+        elsif ( !( -f $file ) ) {
+            die "$P: file '${file}' not found\n";
+        }
+    }
+    if ( $from_filename && ( vcs_exists() && !vcs_file_exists($file) ) ) {
+        warn "$P: file '$file' not found in version control $!\n";
+    }
+    if ( $from_filename || ( $file ne "&STDIN" && vcs_file_exists($file) ) ) {
+        $file =~ s/^\Q${cur_path}\E//;    #strip any absolute path
+        $file =~ s/^\Q${lk_path}\E//;     #or the path to the lk tree
+        push( @files, $file );
+        if ( $file ne "MAINTAINERS" && -f $file && $keywords ) {
+            open( my $f, '<', $file )
+                or die "$P: Can't open $file: $!\n";
+            my $text = do { local ($/); <$f> };
+            close($f);
+            if ($keywords) {
+                foreach my $line ( keys %keyword_hash ) {
+                    if ( $text =~ m/$keyword_hash{$line}/x ) {
+                        push( @keyword_tvi, $line );
+                    }
+                }
+            }
+        }
+    }
+    else {
+        my $file_cnt = @files;
+        my $lastfile;
+
+        open( my $patch, "< $file" )
+            or die "$P: Can't open $file: $!\n";
+
+        # We can check arbitrary information before the patch
+        # like the commit message, mail headers, etc...
+        # This allows us to match arbitrary keywords against any part
+        # of a git format-patch generated file (subject tags, etc...)
+
+        my $patch_prefix = "";    #Parsing the intro
+
+        while (<$patch>) {
+            my $patch_line = $_;
+            if (m/^ mode change [0-7]+ => [0-7]+ (\S+)\s*$/) {
+                my $filename = $1;
+                push( @files, $filename );
+            }
+            elsif (m/^rename (?:from|to) (\S+)\s*$/) {
+                my $filename = $1;
+                push( @files, $filename );
+            }
+            elsif (m/^diff --git a\/(\S+) b\/(\S+)\s*$/) {
+                my $filename1 = $1;
+                my $filename2 = $2;
+                push( @files, $filename1 );
+                push( @files, $filename2 );
+            }
+            elsif (m/^Fixes:\s+([0-9a-fA-F]{6,40})/) {
+                push( @fixes, $1 ) if ($email_fixes);
+            }
+            elsif ( m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/ ) {
+                my $filename = $1;
+                $filename =~ s@^[^/]*/@@;
+                $filename =~ s@\n@@;
+                $lastfile = $filename;
+                push( @files, $filename );
+                $patch_prefix = "^[+-].*";    #Now parsing the actual patch
+            }
+            elsif (m/^\@\@ -(\d+),(\d+)/) {
+                if ($email_git_blame) {
+                    push( @range, "$lastfile:$1:$2" );
+                }
+            }
+            elsif ($keywords) {
+                foreach my $line ( keys %keyword_hash ) {
+                    if ( $patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x ) {
+                        push( @keyword_tvi, $line );
+                    }
+                }
+            }
+        }
+        close($patch);
+
+        if ( $file_cnt == @files ) {
+            warn "$P: file '${file}' doesn't appear to be a patch.  " . "Add -f to options?\n";
+        }
+        @files = sort_and_uniq(@files);
     }
 }
 
 @file_emails = uniq(@file_emails);
-@fixes = uniq(@fixes);
+@fixes       = uniq(@fixes);
 
 my %email_hash_name;
 my %email_hash_address;
 my @email_to = ();
 my %hash_list_to;
-my @list_to = ();
-my @scm = ();
-my @web = ();
-my @subsystem = ();
-my @status = ();
-my %deduplicate_name_hash = ();
+my @list_to                  = ();
+my @scm                      = ();
+my @web                      = ();
+my @subsystem                = ();
+my @status                   = ();
+my %deduplicate_name_hash    = ();
 my %deduplicate_address_hash = ();
 
 my @maintainers = get_maintainers();
@@ -663,131 +646,148 @@ if ($web) {
 exit($exit);
 
 sub self_test {
-    my @lsfiles = ();
-    my @good_links = ();
-    my @bad_links = ();
+    my @lsfiles         = ();
+    my @good_links      = ();
+    my @bad_links       = ();
     my @section_headers = ();
-    my $index = 0;
+    my $index           = 0;
 
     @lsfiles = vcs_list_files($lk_path);
 
     for my $x (@self_test_info) {
-	$index++;
-
-	## Section header duplication and missing section content
-	if (($self_test eq "" || $self_test =~ /\bsections\b/) &&
-	    $x->{line} =~ /^\S[^:]/ &&
-	    defined $self_test_info[$index] &&
-	    $self_test_info[$index]->{line} =~ /^([A-Z]):\s*\S/) {
-	    my $has_S = 0;
-	    my $has_F = 0;
-	    my $has_ML = 0;
-	    my $status = "";
-	    if (grep(m@^\Q$x->{line}\E@, @section_headers)) {
-		print("$x->{file}:$x->{linenr}: warning: duplicate section header\t$x->{line}\n");
-	    } else {
-		push(@section_headers, $x->{line});
-	    }
-	    my $nextline = $index;
-	    while (defined $self_test_info[$nextline] &&
-		   $self_test_info[$nextline]->{line} =~ /^([A-Z]):\s*(\S.*)/) {
-		my $type = $1;
-		my $value = $2;
-		if ($type eq "S") {
-		    $has_S = 1;
-		    $status = $value;
-		} elsif ($type eq "F" || $type eq "N") {
-		    $has_F = 1;
-		} elsif ($type eq "M" || $type eq "R" || $type eq "L") {
-		    $has_ML = 1;
-		}
-		$nextline++;
-	    }
-	    if (!$has_ML && $status !~ /orphan|obsolete/i) {
-		print("$x->{file}:$x->{linenr}: warning: section without email address\t$x->{line}\n");
-	    }
-	    if (!$has_S) {
-		print("$x->{file}:$x->{linenr}: warning: section without status \t$x->{line}\n");
-	    }
-	    if (!$has_F) {
-		print("$x->{file}:$x->{linenr}: warning: section without file pattern\t$x->{line}\n");
-	    }
-	}
-
-	next if ($x->{line} !~ /^([A-Z]):\s*(.*)/);
-
-	my $type = $1;
-	my $value = $2;
-
-	## Filename pattern matching
-	if (($type eq "F" || $type eq "X") &&
-	    ($self_test eq "" || $self_test =~ /\bpatterns\b/)) {
-	    $value =~ s@\.@\\\.@g;       ##Convert . to \.
-	    $value =~ s/\*/\.\*/g;       ##Convert * to .*
-	    $value =~ s/\?/\./g;         ##Convert ? to .
-	    ##if pattern is a directory and it lacks a trailing slash, add one
-	    if ((-d $value)) {
-		$value =~ s@([^/])$@$1/@;
-	    }
-	    if (!grep(m@^$value@, @lsfiles)) {
-		print("$x->{file}:$x->{linenr}: warning: no file matches\t$x->{line}\n");
-	    }
-
-	## Link reachability
-	} elsif (($type eq "W" || $type eq "Q" || $type eq "B") &&
-		 $value =~ /^https?:/ &&
-		 ($self_test eq "" || $self_test =~ /\blinks\b/)) {
-	    next if (grep(m@^\Q$value\E$@, @good_links));
-	    my $isbad = 0;
-	    if (grep(m@^\Q$value\E$@, @bad_links)) {
-	        $isbad = 1;
-	    } else {
-		my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $value`;
-		if ($? == 0) {
-		    push(@good_links, $value);
-		} else {
-		    push(@bad_links, $value);
-		    $isbad = 1;
-		}
-	    }
-	    if ($isbad) {
-	        print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
-	    }
-
-	## SCM reachability
-	} elsif ($type eq "T" &&
-		 ($self_test eq "" || $self_test =~ /\bscm\b/)) {
-	    next if (grep(m@^\Q$value\E$@, @good_links));
-	    my $isbad = 0;
-	    if (grep(m@^\Q$value\E$@, @bad_links)) {
-	        $isbad = 1;
-            } elsif ($value !~ /^(?:git|quilt|hg)\s+\S/) {
-		print("$x->{file}:$x->{linenr}: warning: malformed entry\t$x->{line}\n");
-	    } elsif ($value =~ /^git\s+(\S+)(\s+([^\(]+\S+))?/) {
-		my $url = $1;
-		my $branch = "";
-		$branch = $3 if $3;
-		my $output = `git ls-remote --exit-code -h "$url" $branch > /dev/null 2>&1`;
-		if ($? == 0) {
-		    push(@good_links, $value);
-		} else {
-		    push(@bad_links, $value);
-		    $isbad = 1;
-		}
-	    } elsif ($value =~ /^(?:quilt|hg)\s+(https?:\S+)/) {
-		my $url = $1;
-		my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $url`;
-		if ($? == 0) {
-		    push(@good_links, $value);
-		} else {
-		    push(@bad_links, $value);
-		    $isbad = 1;
-		}
-	    }
-	    if ($isbad) {
-		print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
-	    }
-	}
+        $index++;
+
+        ## Section header duplication and missing section content
+        if (   ( $self_test eq "" || $self_test =~ /\bsections\b/ )
+            && $x->{line} =~ /^\S[^:]/
+            && defined $self_test_info[$index]
+            && $self_test_info[$index]->{line} =~ /^([A-Z]):\s*\S/ )
+        {
+            my $has_S  = 0;
+            my $has_F  = 0;
+            my $has_ML = 0;
+            my $status = "";
+            if ( grep( m@^\Q$x->{line}\E@, @section_headers ) ) {
+                print("$x->{file}:$x->{linenr}: warning: duplicate section header\t$x->{line}\n");
+            }
+            else {
+                push( @section_headers, $x->{line} );
+            }
+            my $nextline = $index;
+            while ( defined $self_test_info[$nextline]
+                && $self_test_info[$nextline]->{line} =~ /^([A-Z]):\s*(\S.*)/ )
+            {
+                my $type  = $1;
+                my $value = $2;
+                if ( $type eq "S" ) {
+                    $has_S  = 1;
+                    $status = $value;
+                }
+                elsif ( $type eq "F" || $type eq "N" ) {
+                    $has_F = 1;
+                }
+                elsif ( $type eq "M" || $type eq "R" || $type eq "L" ) {
+                    $has_ML = 1;
+                }
+                $nextline++;
+            }
+            if ( !$has_ML && $status !~ /orphan|obsolete/i ) {
+                print("$x->{file}:$x->{linenr}: warning: section without email address\t$x->{line}\n");
+            }
+            if ( !$has_S ) {
+                print("$x->{file}:$x->{linenr}: warning: section without status \t$x->{line}\n");
+            }
+            if ( !$has_F ) {
+                print("$x->{file}:$x->{linenr}: warning: section without file pattern\t$x->{line}\n");
+            }
+        }
+
+        next if ( $x->{line} !~ /^([A-Z]):\s*(.*)/ );
+
+        my $type  = $1;
+        my $value = $2;
+
+        ## Filename pattern matching
+        if (   ( $type eq "F" || $type eq "X" )
+            && ( $self_test eq "" || $self_test =~ /\bpatterns\b/ ) )
+        {
+            $value =~ s@\.@\\\.@g;    ##Convert . to \.
+            $value =~ s/\*/\.\*/g;    ##Convert * to .*
+            $value =~ s/\?/\./g;      ##Convert ? to .
+            ##if pattern is a directory and it lacks a trailing slash, add one
+            if ( ( -d $value ) ) {
+                $value =~ s@([^/])$@$1/@;
+            }
+            if ( !grep( m@^$value@, @lsfiles ) ) {
+                print("$x->{file}:$x->{linenr}: warning: no file matches\t$x->{line}\n");
+            }
+
+            ## Link reachability
+        }
+        elsif (( $type eq "W" || $type eq "Q" || $type eq "B" )
+            && $value =~ /^https?:/
+            && ( $self_test eq "" || $self_test =~ /\blinks\b/ ) )
+        {
+            next if ( grep( m@^\Q$value\E$@, @good_links ) );
+            my $isbad = 0;
+            if ( grep( m@^\Q$value\E$@, @bad_links ) ) {
+                $isbad = 1;
+            }
+            else {
+                my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $value`;
+                if ( $? == 0 ) {
+                    push( @good_links, $value );
+                }
+                else {
+                    push( @bad_links, $value );
+                    $isbad = 1;
+                }
+            }
+            if ($isbad) {
+                print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
+            }
+
+            ## SCM reachability
+        }
+        elsif ( $type eq "T"
+            && ( $self_test eq "" || $self_test =~ /\bscm\b/ ) )
+        {
+            next if ( grep( m@^\Q$value\E$@, @good_links ) );
+            my $isbad = 0;
+            if ( grep( m@^\Q$value\E$@, @bad_links ) ) {
+                $isbad = 1;
+            }
+            elsif ( $value !~ /^(?:git|quilt|hg)\s+\S/ ) {
+                print("$x->{file}:$x->{linenr}: warning: malformed entry\t$x->{line}\n");
+            }
+            elsif ( $value =~ /^git\s+(\S+)(\s+([^\(]+\S+))?/ ) {
+                my $url    = $1;
+                my $branch = "";
+                $branch = $3 if $3;
+                my $output = `git ls-remote --exit-code -h "$url" $branch > /dev/null 2>&1`;
+                if ( $? == 0 ) {
+                    push( @good_links, $value );
+                }
+                else {
+                    push( @bad_links, $value );
+                    $isbad = 1;
+                }
+            }
+            elsif ( $value =~ /^(?:quilt|hg)\s+(https?:\S+)/ ) {
+                my $url    = $1;
+                my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $url`;
+                if ( $? == 0 ) {
+                    push( @good_links, $value );
+                }
+                else {
+                    push( @bad_links, $value );
+                    $isbad = 1;
+                }
+            }
+            if ($isbad) {
+                print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
+            }
+        }
     }
 }
 
@@ -795,64 +795,66 @@ sub ignore_email_address {
     my ($address) = @_;
 
     foreach my $ignore (@ignore_emails) {
-	return 1 if ($ignore eq $address);
+        return 1 if ( $ignore eq $address );
     }
 
     return 0;
 }
 
 sub range_is_maintained {
-    my ($start, $end) = @_;
-
-    for (my $i = $start; $i < $end; $i++) {
-	my $line = $typevalue[$i];
-	if ($line =~ m/^([A-Z]):\s*(.*)/) {
-	    my $type = $1;
-	    my $value = $2;
-	    if ($type eq 'S') {
-		if ($value =~ /(maintain|support)/i) {
-		    return 1;
-		}
-	    }
-	}
+    my ( $start, $end ) = @_;
+
+    for ( my $i = $start; $i < $end; $i++ ) {
+        my $line = $typevalue[$i];
+        if ( $line =~ m/^([A-Z]):\s*(.*)/ ) {
+            my $type  = $1;
+            my $value = $2;
+            if ( $type eq 'S' ) {
+                if ( $value =~ /(maintain|support)/i ) {
+                    return 1;
+                }
+            }
+        }
     }
     return 0;
 }
 
 sub range_has_maintainer {
-    my ($start, $end) = @_;
-
-    for (my $i = $start; $i < $end; $i++) {
-	my $line = $typevalue[$i];
-	if ($line =~ m/^([A-Z]):\s*(.*)/) {
-	    my $type = $1;
-	    my $value = $2;
-	    if ($type eq 'M') {
-		return 1;
-	    }
-	}
+    my ( $start, $end ) = @_;
+
+    for ( my $i = $start; $i < $end; $i++ ) {
+        my $line = $typevalue[$i];
+        if ( $line =~ m/^([A-Z]):\s*(.*)/ ) {
+            my $type  = $1;
+            my $value = $2;
+            if ( $type eq 'M' ) {
+                return 1;
+            }
+        }
     }
     return 0;
 }
 
 sub get_maintainers {
-    %email_hash_name = ();
-    %email_hash_address = ();
-    %commit_author_hash = ();
-    %commit_signer_hash = ();
-    @email_to = ();
-    %hash_list_to = ();
-    @list_to = ();
-    @scm = ();
-    @web = ();
-    @subsystem = ();
-    @status = ();
-    %deduplicate_name_hash = ();
+    %email_hash_name          = ();
+    %email_hash_address       = ();
+    %commit_author_hash       = ();
+    %commit_signer_hash       = ();
+    @email_to                 = ();
+    %hash_list_to             = ();
+    @list_to                  = ();
+    @scm                      = ();
+    @web                      = ();
+    @subsystem                = ();
+    @status                   = ();
+    %deduplicate_name_hash    = ();
     %deduplicate_address_hash = ();
+
     if ($email_git_all_signature_types) {
-	$signature_pattern = "(.+?)[Bb][Yy]:";
-    } else {
-	$signature_pattern = "\(" . join("|", @signature_tags) . "\)";
+        $signature_pattern = "(.+?)[Bb][Yy]:";
+    }
+    else {
+        $signature_pattern = "\(" . join( "|", @signature_tags ) . "\)";
     }
 
     # Find responsible parties
@@ -861,172 +863,180 @@ sub get_maintainers {
 
     foreach my $file (@files) {
 
-	my %hash;
-	my $tvi = find_first_section();
-	while ($tvi < @typevalue) {
-	    my $start = find_starting_index($tvi);
-	    my $end = find_ending_index($tvi);
-	    my $exclude = 0;
-	    my $i;
-
-	    #Do not match excluded file patterns
-
-	    for ($i = $start; $i < $end; $i++) {
-		my $line = $typevalue[$i];
-		if ($line =~ m/^([A-Z]):\s*(.*)/) {
-		    my $type = $1;
-		    my $value = $2;
-		    if ($type eq 'X') {
-			if (file_match_pattern($file, $value)) {
-			    $exclude = 1;
-			    last;
-			}
-		    }
-		}
-	    }
-
-	    if (!$exclude) {
-		for ($i = $start; $i < $end; $i++) {
-		    my $line = $typevalue[$i];
-		    if ($line =~ m/^([A-Z]):\s*(.*)/) {
-			my $type = $1;
-			my $value = $2;
-			if ($type eq 'F') {
-			    if (file_match_pattern($file, $value)) {
-				my $value_pd = ($value =~ tr@/@@);
-				my $file_pd = ($file  =~ tr@/@@);
-				$value_pd++ if (substr($value,-1,1) ne "/");
-				$value_pd = -1 if ($value =~ /^\.\*/);
-				if ($value_pd >= $file_pd &&
-				    range_is_maintained($start, $end) &&
-				    range_has_maintainer($start, $end)) {
-				    $exact_pattern_match_hash{$file} = 1;
-				}
-				if ($pattern_depth == 0 ||
-				    (($file_pd - $value_pd) < $pattern_depth)) {
-				    $hash{$tvi} = $value_pd;
-				}
-			    }
-			} elsif ($type eq 'N') {
-			    if ($file =~ m/$value/x) {
-				$hash{$tvi} = 0;
-			    }
-			}
-		    }
-		}
-	    }
-	    $tvi = $end + 1;
-	}
-
-	foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
-	    add_categories($line);
-	    if ($sections) {
-		my $i;
-		my $start = find_starting_index($line);
-		my $end = find_ending_index($line);
-		for ($i = $start; $i < $end; $i++) {
-		    my $line = $typevalue[$i];
-		    if ($line =~ /^[FX]:/) {		##Restore file patterns
-			$line =~ s/([^\\])\.([^\*])/$1\?$2/g;
-			$line =~ s/([^\\])\.$/$1\?/g;	##Convert . back to ?
-			$line =~ s/\\\./\./g;       	##Convert \. to .
-			$line =~ s/\.\*/\*/g;       	##Convert .* to *
-		    }
-		    my $count = $line =~ s/^([A-Z]):/$1:\t/g;
-		    if ($letters eq "" || (!$count || $letters =~ /$1/i)) {
-			print("$line\n");
-		    }
-		}
-		print("\n");
-	    }
-	}
-
-	maintainers_in_file($file);
+        my %hash;
+        my $tvi = find_first_section();
+        while ( $tvi < @typevalue ) {
+            my $start   = find_starting_index($tvi);
+            my $end     = find_ending_index($tvi);
+            my $exclude = 0;
+            my $i;
+
+            #Do not match excluded file patterns
+
+            for ( $i = $start; $i < $end; $i++ ) {
+                my $line = $typevalue[$i];
+                if ( $line =~ m/^([A-Z]):\s*(.*)/ ) {
+                    my $type  = $1;
+                    my $value = $2;
+                    if ( $type eq 'X' ) {
+                        if ( file_match_pattern( $file, $value ) ) {
+                            $exclude = 1;
+                            last;
+                        }
+                    }
+                }
+            }
+
+            if ( !$exclude ) {
+                for ( $i = $start; $i < $end; $i++ ) {
+                    my $line = $typevalue[$i];
+                    if ( $line =~ m/^([A-Z]):\s*(.*)/ ) {
+                        my $type  = $1;
+                        my $value = $2;
+                        if ( $type eq 'F' ) {
+                            if ( file_match_pattern( $file, $value ) ) {
+                                my $value_pd = ( $value =~ tr@/@@ );
+                                my $file_pd  = ( $file  =~ tr@/@@ );
+                                $value_pd++    if ( substr( $value, -1, 1 ) ne "/" );
+                                $value_pd = -1 if ( $value =~ /^\.\*/ );
+                                if (   $value_pd >= $file_pd
+                                    && range_is_maintained( $start, $end )
+                                    && range_has_maintainer( $start, $end ) )
+                                {
+                                    $exact_pattern_match_hash{$file} = 1;
+                                }
+                                if ( $pattern_depth == 0
+                                    || ( ( $file_pd - $value_pd ) < $pattern_depth ) )
+                                {
+                                    $hash{$tvi} = $value_pd;
+                                }
+                            }
+                        }
+                        elsif ( $type eq 'N' ) {
+                            if ( $file =~ m/$value/x ) {
+                                $hash{$tvi} = 0;
+                            }
+                        }
+                    }
+                }
+            }
+            $tvi = $end + 1;
+        }
+
+        foreach my $line ( sort { $hash{$b} <=> $hash{$a} } keys %hash ) {
+            add_categories($line);
+            if ($sections) {
+                my $i;
+                my $start = find_starting_index($line);
+                my $end   = find_ending_index($line);
+                for ( $i = $start; $i < $end; $i++ ) {
+                    my $line = $typevalue[$i];
+                    if ( $line =~ /^[FX]:/ ) {    ##Restore file patterns
+                        $line =~ s/([^\\])\.([^\*])/$1\?$2/g;
+                        $line =~ s/([^\\])\.$/$1\?/g;           ##Convert . back to ?
+                        $line =~ s/\\\./\./g;                   ##Convert \. to .
+                        $line =~ s/\.\*/\*/g;                   ##Convert .* to *
+                    }
+                    my $count = $line =~ s/^([A-Z]):/$1:\t/g;
+                    if ( $letters eq "" || ( !$count || $letters =~ /$1/i ) ) {
+                        print("$line\n");
+                    }
+                }
+                print("\n");
+            }
+        }
+
+        maintainers_in_file($file);
     }
 
     if ($keywords) {
-	@keyword_tvi = sort_and_uniq(@keyword_tvi);
-	foreach my $line (@keyword_tvi) {
-	    add_categories($line);
-	}
+        @keyword_tvi = sort_and_uniq(@keyword_tvi);
+        foreach my $line (@keyword_tvi) {
+            add_categories($line);
+        }
     }
 
-    foreach my $email (@email_to, @list_to) {
-	$email->[0] = deduplicate_email($email->[0]);
+    foreach my $email ( @email_to, @list_to ) {
+        $email->[0] = deduplicate_email( $email->[0] );
     }
 
     foreach my $file (@files) {
-	if ($email &&
-	    ($email_git ||
-	     ($email_git_fallback &&
-	      $file !~ /MAINTAINERS$/ &&
-	      !$exact_pattern_match_hash{$file}))) {
-	    vcs_file_signoffs($file);
-	}
-	if ($email && $email_git_blame) {
-	    vcs_file_blame($file);
-	}
+        if ($email
+            && ($email_git
+                || (   $email_git_fallback
+                    && $file !~ /MAINTAINERS$/
+                    && !$exact_pattern_match_hash{$file} )
+            )
+            )
+        {
+            vcs_file_signoffs($file);
+        }
+        if ( $email && $email_git_blame ) {
+            vcs_file_blame($file);
+        }
     }
 
     if ($email) {
-	foreach my $chief (@penguin_chief) {
-	    if ($chief =~ m/^(.*):(.*)/) {
-		my $email_address;
-
-		$email_address = format_email($1, $2, $email_usename);
-		if ($email_git_penguin_chiefs) {
-		    push(@email_to, [$email_address, 'chief penguin']);
-		} else {
-		    @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
-		}
-	    }
-	}
+        foreach my $chief (@penguin_chief) {
+            if ( $chief =~ m/^(.*):(.*)/ ) {
+                my $email_address;
+
+                $email_address = format_email( $1, $2, $email_usename );
+                if ($email_git_penguin_chiefs) {
+                    push( @email_to, [ $email_address, 'chief penguin' ] );
+                }
+                else {
+                    @email_to = grep( $_->[0] !~ /${email_address}/, @email_to );
+                }
+            }
+        }
 
-	foreach my $email (@file_emails) {
-	    $email = mailmap_email($email);
-	    my ($name, $address) = parse_email($email);
+        foreach my $email (@file_emails) {
+            $email = mailmap_email($email);
+            my ( $name, $address ) = parse_email($email);
 
-	    my $tmp_email = format_email($name, $address, $email_usename);
-	    push_email_address($tmp_email, '');
-	    add_role($tmp_email, 'in file');
-	}
+            my $tmp_email = format_email( $name, $address, $email_usename );
+            push_email_address( $tmp_email, '' );
+            add_role( $tmp_email, 'in file' );
+        }
     }
 
     foreach my $fix (@fixes) {
-	vcs_add_commit_signers($fix, "blamed_fixes");
+        vcs_add_commit_signers( $fix, "blamed_fixes" );
     }
 
     my @to = ();
-    if ($email || $email_list) {
-	if ($email) {
-	    @to = (@to, @email_to);
-	}
-	if ($email_list) {
-	    @to = (@to, @list_to);
-	}
+    if ( $email || $email_list ) {
+        if ($email) {
+            @to = ( @to, @email_to );
+        }
+        if ($email_list) {
+            @to = ( @to, @list_to );
+        }
     }
 
     if ($interactive) {
-	@to = interactive_get_maintainers(\@to);
+        @to = interactive_get_maintainers( \@to );
     }
 
     return @to;
 }
 
 sub file_match_pattern {
-    my ($file, $pattern) = @_;
-    if (substr($pattern, -1) eq "/") {
-	if ($file =~ m@^$pattern@) {
-	    return 1;
-	}
-    } else {
-	if ($file =~ m@^$pattern@) {
-	    my $s1 = ($file =~ tr@/@@);
-	    my $s2 = ($pattern =~ tr@/@@);
-	    if ($s1 == $s2) {
-		return 1;
-	    }
-	}
+    my ( $file, $pattern ) = @_;
+    if ( substr( $pattern, -1 ) eq "/" ) {
+        if ( $file =~ m@^$pattern@ ) {
+            return 1;
+        }
+    }
+    else {
+        if ( $file =~ m@^$pattern@ ) {
+            my $s1 = ( $file    =~ tr@/@@ );
+            my $s2 = ( $pattern =~ tr@/@@ );
+            if ( $s1 == $s2 ) {
+                return 1;
+            }
+        }
     }
     return 0;
 }
@@ -1126,26 +1136,27 @@ EOT
 sub top_of_kernel_tree {
     my ($lk_path) = @_;
 
-    if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
-	$lk_path .= "/";
-    }
-    if (   (-f "${lk_path}COPYING")
-	&& (-f "${lk_path}CREDITS")
-	&& (-f "${lk_path}Kbuild")
-	&& (-e "${lk_path}MAINTAINERS")
-	&& (-f "${lk_path}Makefile")
-	&& (-f "${lk_path}README")
-	&& (-d "${lk_path}Documentation")
-	&& (-d "${lk_path}arch")
-	&& (-d "${lk_path}include")
-	&& (-d "${lk_path}drivers")
-	&& (-d "${lk_path}fs")
-	&& (-d "${lk_path}init")
-	&& (-d "${lk_path}ipc")
-	&& (-d "${lk_path}kernel")
-	&& (-d "${lk_path}lib")
-	&& (-d "${lk_path}scripts")) {
-	return 1;
+    if ( $lk_path ne "" && substr( $lk_path, length($lk_path) - 1, 1 ) ne "/" ) {
+        $lk_path .= "/";
+    }
+    if (   ( -f "${lk_path}COPYING" )
+        && ( -f "${lk_path}CREDITS" )
+        && ( -f "${lk_path}Kbuild" )
+        && ( -e "${lk_path}MAINTAINERS" )
+        && ( -f "${lk_path}Makefile" )
+        && ( -f "${lk_path}README" )
+        && ( -d "${lk_path}Documentation" )
+        && ( -d "${lk_path}arch" )
+        && ( -d "${lk_path}include" )
+        && ( -d "${lk_path}drivers" )
+        && ( -d "${lk_path}fs" )
+        && ( -d "${lk_path}init" )
+        && ( -d "${lk_path}ipc" )
+        && ( -d "${lk_path}kernel" )
+        && ( -d "${lk_path}lib" )
+        && ( -d "${lk_path}scripts" ) )
+    {
+        return 1;
     }
     return 0;
 }
@@ -1153,52 +1164,56 @@ sub top_of_kernel_tree {
 sub parse_email {
     my ($formatted_email) = @_;
 
-    my $name = "";
+    my $name    = "";
     my $address = "";
 
-    if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) {
-	$name = $1;
-	$address = $2;
-    } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) {
-	$address = $1;
-    } elsif ($formatted_email =~ /^(.+\@\S*).*$/) {
-	$address = $1;
+    if ( $formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/ ) {
+        $name    = $1;
+        $address = $2;
+    }
+    elsif ( $formatted_email =~ /^\s*<(.+\@\S*)>.*$/ ) {
+        $address = $1;
+    }
+    elsif ( $formatted_email =~ /^(.+\@\S*).*$/ ) {
+        $address = $1;
     }
 
-    $name =~ s/^\s+|\s+$//g;
-    $name =~ s/^\"|\"$//g;
+    $name    =~ s/^\s+|\s+$//g;
+    $name    =~ s/^\"|\"$//g;
     $address =~ s/^\s+|\s+$//g;
 
-    if ($name =~ /[^\w \-]/i) {  	 ##has "must quote" chars
-	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
-	$name = "\"$name\"";
+    if ( $name =~ /[^\w \-]/i ) {    ##has "must quote" chars
+        $name =~ s/(?<!\\)"/\\"/g;    ##escape quotes
+        $name = "\"$name\"";
     }
 
-    return ($name, $address);
+    return ( $name, $address );
 }
 
 sub format_email {
-    my ($name, $address, $usename) = @_;
+    my ( $name, $address, $usename ) = @_;
 
     my $formatted_email;
 
-    $name =~ s/^\s+|\s+$//g;
-    $name =~ s/^\"|\"$//g;
+    $name    =~ s/^\s+|\s+$//g;
+    $name    =~ s/^\"|\"$//g;
     $address =~ s/^\s+|\s+$//g;
 
-    if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
-	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
-	$name = "\"$name\"";
+    if ( $name =~ /[^\w \-]/i ) {    ##has "must quote" chars
+        $name =~ s/(?<!\\)"/\\"/g;    ##escape quotes
+        $name = "\"$name\"";
     }
 
     if ($usename) {
-	if ("$name" eq "") {
-	    $formatted_email = "$address";
-	} else {
-	    $formatted_email = "$name <$address>";
-	}
-    } else {
-	$formatted_email = $address;
+        if ( "$name" eq "" ) {
+            $formatted_email = "$address";
+        }
+        else {
+            $formatted_email = "$name <$address>";
+        }
+    }
+    else {
+        $formatted_email = $address;
     }
 
     return $formatted_email;
@@ -1207,12 +1222,12 @@ sub format_email {
 sub find_first_section {
     my $index = 0;
 
-    while ($index < @typevalue) {
-	my $tv = $typevalue[$index];
-	if (($tv =~ m/^([A-Z]):\s*(.*)/)) {
-	    last;
-	}
-	$index++;
+    while ( $index < @typevalue ) {
+        my $tv = $typevalue[$index];
+        if ( ( $tv =~ m/^([A-Z]):\s*(.*)/ ) ) {
+            last;
+        }
+        $index++;
     }
 
     return $index;
@@ -1221,12 +1236,12 @@ sub find_first_section {
 sub find_starting_index {
     my ($index) = @_;
 
-    while ($index > 0) {
-	my $tv = $typevalue[$index];
-	if (!($tv =~ m/^([A-Z]):\s*(.*)/)) {
-	    last;
-	}
-	$index--;
+    while ( $index > 0 ) {
+        my $tv = $typevalue[$index];
+        if ( !( $tv =~ m/^([A-Z]):\s*(.*)/ ) ) {
+            last;
+        }
+        $index--;
     }
 
     return $index;
@@ -1235,12 +1250,12 @@ sub find_starting_index {
 sub find_ending_index {
     my ($index) = @_;
 
-    while ($index < @typevalue) {
-	my $tv = $typevalue[$index];
-	if (!($tv =~ m/^([A-Z]):\s*(.*)/)) {
-	    last;
-	}
-	$index++;
+    while ( $index < @typevalue ) {
+        my $tv = $typevalue[$index];
+        if ( !( $tv =~ m/^([A-Z]):\s*(.*)/ ) ) {
+            last;
+        }
+        $index++;
     }
 
     return $index;
@@ -1252,10 +1267,10 @@ sub get_subsystem_name {
     my $start = find_starting_index($index);
 
     my $subsystem = $typevalue[$start];
-    if ($output_section_maxlen && length($subsystem) > $output_section_maxlen) {
-	$subsystem = substr($subsystem, 0, $output_section_maxlen - 3);
-	$subsystem =~ s/\s*$//;
-	$subsystem = $subsystem . "...";
+    if ( $output_section_maxlen && length($subsystem) > $output_section_maxlen ) {
+        $subsystem = substr( $subsystem, 0, $output_section_maxlen - 3 );
+        $subsystem =~ s/\s*$//;
+        $subsystem = $subsystem . "...";
     }
     return $subsystem;
 }
@@ -1265,35 +1280,40 @@ sub get_maintainer_role {
 
     my $i;
     my $start = find_starting_index($index);
-    my $end = find_ending_index($index);
+    my $end   = find_ending_index($index);
 
-    my $role = "unknown";
+    my $role      = "unknown";
     my $subsystem = get_subsystem_name($index);
 
-    for ($i = $start + 1; $i < $end; $i++) {
-	my $tv = $typevalue[$i];
-	if ($tv =~ m/^([A-Z]):\s*(.*)/) {
-	    my $ptype = $1;
-	    my $pvalue = $2;
-	    if ($ptype eq "S") {
-		$role = $pvalue;
-	    }
-	}
+    for ( $i = $start + 1; $i < $end; $i++ ) {
+        my $tv = $typevalue[$i];
+        if ( $tv =~ m/^([A-Z]):\s*(.*)/ ) {
+            my $ptype  = $1;
+            my $pvalue = $2;
+            if ( $ptype eq "S" ) {
+                $role = $pvalue;
+            }
+        }
     }
 
     $role = lc($role);
-    if      ($role eq "supported") {
-	$role = "supporter";
-    } elsif ($role eq "maintained") {
-	$role = "maintainer";
-    } elsif ($role eq "odd fixes") {
-	$role = "odd fixer";
-    } elsif ($role eq "orphan") {
-	$role = "orphan minder";
-    } elsif ($role eq "obsolete") {
-	$role = "obsolete minder";
-    } elsif ($role eq "buried alive in reporters") {
-	$role = "chief penguin";
+    if ( $role eq "supported" ) {
+        $role = "supporter";
+    }
+    elsif ( $role eq "maintained" ) {
+        $role = "maintainer";
+    }
+    elsif ( $role eq "odd fixes" ) {
+        $role = "odd fixer";
+    }
+    elsif ( $role eq "orphan" ) {
+        $role = "orphan minder";
+    }
+    elsif ( $role eq "obsolete" ) {
+        $role = "obsolete minder";
+    }
+    elsif ( $role eq "buried alive in reporters" ) {
+        $role = "chief penguin";
     }
 
     return $role . ":" . $subsystem;
@@ -1304,8 +1324,8 @@ sub get_list_role {
 
     my $subsystem = get_subsystem_name($index);
 
-    if ($subsystem eq "THE REST") {
-	$subsystem = "";
+    if ( $subsystem eq "THE REST" ) {
+        $subsystem = "";
     }
 
     return $subsystem;
@@ -1316,161 +1336,171 @@ sub add_categories {
 
     my $i;
     my $start = find_starting_index($index);
-    my $end = find_ending_index($index);
-
-    push(@subsystem, $typevalue[$start]);
-
-    for ($i = $start + 1; $i < $end; $i++) {
-	my $tv = $typevalue[$i];
-	if ($tv =~ m/^([A-Z]):\s*(.*)/) {
-	    my $ptype = $1;
-	    my $pvalue = $2;
-	    if ($ptype eq "L") {
-		my $list_address = $pvalue;
-		my $list_additional = "";
-		my $list_role = get_list_role($i);
-
-		if ($list_role ne "") {
-		    $list_role = ":" . $list_role;
-		}
-		if ($list_address =~ m/([^\s]+)\s+(.*)$/) {
-		    $list_address = $1;
-		    $list_additional = $2;
-		}
-		if ($list_additional =~ m/subscribers-only/) {
-		    if ($email_subscriber_list) {
-			if (!$hash_list_to{lc($list_address)}) {
-			    $hash_list_to{lc($list_address)} = 1;
-			    push(@list_to, [$list_address,
-					    "subscriber list${list_role}"]);
-			}
-		    }
-		} else {
-		    if ($email_list) {
-			if (!$hash_list_to{lc($list_address)}) {
-			    if ($list_additional =~ m/moderated/) {
-				if ($email_moderated_list) {
-				    $hash_list_to{lc($list_address)} = 1;
-				    push(@list_to, [$list_address,
-						    "moderated list${list_role}"]);
-				}
-			    } else {
-				$hash_list_to{lc($list_address)} = 1;
-				push(@list_to, [$list_address,
-						"open list${list_role}"]);
-			    }
-			}
-		    }
-		}
-	    } elsif ($ptype eq "M") {
-		if ($email_maintainer) {
-		    my $role = get_maintainer_role($i);
-		    push_email_addresses($pvalue, $role);
-		}
-	    } elsif ($ptype eq "R") {
-		if ($email_reviewer) {
-		    my $subsystem = get_subsystem_name($i);
-		    push_email_addresses($pvalue, "reviewer:$subsystem");
-		}
-	    } elsif ($ptype eq "T") {
-		push(@scm, $pvalue);
-	    } elsif ($ptype eq "W") {
-		push(@web, $pvalue);
-	    } elsif ($ptype eq "S") {
-		push(@status, $pvalue);
-	    }
-	}
+    my $end   = find_ending_index($index);
+
+    push( @subsystem, $typevalue[$start] );
+
+    for ( $i = $start + 1; $i < $end; $i++ ) {
+        my $tv = $typevalue[$i];
+        if ( $tv =~ m/^([A-Z]):\s*(.*)/ ) {
+            my $ptype  = $1;
+            my $pvalue = $2;
+            if ( $ptype eq "L" ) {
+                my $list_address    = $pvalue;
+                my $list_additional = "";
+                my $list_role       = get_list_role($i);
+
+                if ( $list_role ne "" ) {
+                    $list_role = ":" . $list_role;
+                }
+                if ( $list_address =~ m/([^\s]+)\s+(.*)$/ ) {
+                    $list_address    = $1;
+                    $list_additional = $2;
+                }
+                if ( $list_additional =~ m/subscribers-only/ ) {
+                    if ($email_subscriber_list) {
+                        if ( !$hash_list_to{ lc($list_address) } ) {
+                            $hash_list_to{ lc($list_address) } = 1;
+                            push( @list_to, [ $list_address, "subscriber list${list_role}" ] );
+                        }
+                    }
+                }
+                else {
+                    if ($email_list) {
+                        if ( !$hash_list_to{ lc($list_address) } ) {
+                            if ( $list_additional =~ m/moderated/ ) {
+                                if ($email_moderated_list) {
+                                    $hash_list_to{ lc($list_address) } = 1;
+                                    push( @list_to, [ $list_address, "moderated list${list_role}" ] );
+                                }
+                            }
+                            else {
+                                $hash_list_to{ lc($list_address) } = 1;
+                                push( @list_to, [ $list_address, "open list${list_role}" ] );
+                            }
+                        }
+                    }
+                }
+            }
+            elsif ( $ptype eq "M" ) {
+                if ($email_maintainer) {
+                    my $role = get_maintainer_role($i);
+                    push_email_addresses( $pvalue, $role );
+                }
+            }
+            elsif ( $ptype eq "R" ) {
+                if ($email_reviewer) {
+                    my $subsystem = get_subsystem_name($i);
+                    push_email_addresses( $pvalue, "reviewer:$subsystem" );
+                }
+            }
+            elsif ( $ptype eq "T" ) {
+                push( @scm, $pvalue );
+            }
+            elsif ( $ptype eq "W" ) {
+                push( @web, $pvalue );
+            }
+            elsif ( $ptype eq "S" ) {
+                push( @status, $pvalue );
+            }
+        }
     }
 }
 
 sub email_inuse {
-    my ($name, $address) = @_;
+    my ( $name, $address ) = @_;
 
-    return 1 if (($name eq "") && ($address eq ""));
-    return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
-    return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
+    return 1 if ( ( $name eq "" )    && ( $address eq "" ) );
+    return 1 if ( ( $name ne "" )    && exists( $email_hash_name{ lc($name) } ) );
+    return 1 if ( ( $address ne "" ) && exists( $email_hash_address{ lc($address) } ) );
 
     return 0;
 }
 
 sub push_email_address {
-    my ($line, $role) = @_;
+    my ( $line, $role ) = @_;
 
-    my ($name, $address) = parse_email($line);
+    my ( $name, $address ) = parse_email($line);
 
-    if ($address eq "") {
-	return 0;
+    if ( $address eq "" ) {
+        return 0;
     }
 
-    if (!$email_remove_duplicates) {
-	push(@email_to, [format_email($name, $address, $email_usename), $role]);
-    } elsif (!email_inuse($name, $address)) {
-	push(@email_to, [format_email($name, $address, $email_usename), $role]);
-	$email_hash_name{lc($name)}++ if ($name ne "");
-	$email_hash_address{lc($address)}++;
+    if ( !$email_remove_duplicates ) {
+        push( @email_to, [ format_email( $name, $address, $email_usename ), $role ] );
+    }
+    elsif ( !email_inuse( $name, $address ) ) {
+        push( @email_to, [ format_email( $name, $address, $email_usename ), $role ] );
+        $email_hash_name{ lc($name) }++ if ( $name ne "" );
+        $email_hash_address{ lc($address) }++;
     }
 
     return 1;
 }
 
 sub push_email_addresses {
-    my ($address, $role) = @_;
+    my ( $address, $role ) = @_;
 
     my @address_list = ();
 
-    if (rfc822_valid($address)) {
-	push_email_address($address, $role);
-    } elsif (@address_list = rfc822_validlist($address)) {
-	my $array_count = shift(@address_list);
-	while (my $entry = shift(@address_list)) {
-	    push_email_address($entry, $role);
-	}
-    } else {
-	if (!push_email_address($address, $role)) {
-	    warn("Invalid MAINTAINERS address: '" . $address . "'\n");
-	}
+    if ( rfc822_valid($address) ) {
+        push_email_address( $address, $role );
+    }
+    elsif ( @address_list = rfc822_validlist($address) ) {
+        my $array_count = shift(@address_list);
+        while ( my $entry = shift(@address_list) ) {
+            push_email_address( $entry, $role );
+        }
+    }
+    else {
+        if ( !push_email_address( $address, $role ) ) {
+            warn( "Invalid MAINTAINERS address: '" . $address . "'\n" );
+        }
     }
 }
 
 sub add_role {
-    my ($line, $role) = @_;
+    my ( $line, $role ) = @_;
 
-    my ($name, $address) = parse_email($line);
-    my $email = format_email($name, $address, $email_usename);
+    my ( $name, $address ) = parse_email($line);
+    my $email = format_email( $name, $address, $email_usename );
 
     foreach my $entry (@email_to) {
-	if ($email_remove_duplicates) {
-	    my ($entry_name, $entry_address) = parse_email($entry->[0]);
-	    if (($name eq $entry_name || $address eq $entry_address)
-		&& ($role eq "" || !($entry->[1] =~ m/$role/))
-	    ) {
-		if ($entry->[1] eq "") {
-		    $entry->[1] = "$role";
-		} else {
-		    $entry->[1] = "$entry->[1],$role";
-		}
-	    }
-	} else {
-	    if ($email eq $entry->[0]
-		&& ($role eq "" || !($entry->[1] =~ m/$role/))
-	    ) {
-		if ($entry->[1] eq "") {
-		    $entry->[1] = "$role";
-		} else {
-		    $entry->[1] = "$entry->[1],$role";
-		}
-	    }
-	}
+        if ($email_remove_duplicates) {
+            my ( $entry_name, $entry_address ) = parse_email( $entry->[0] );
+            if (   ( $name eq $entry_name || $address eq $entry_address )
+                && ( $role eq "" || !( $entry->[1] =~ m/$role/ ) ) )
+            {
+                if ( $entry->[1] eq "" ) {
+                    $entry->[1] = "$role";
+                }
+                else {
+                    $entry->[1] = "$entry->[1],$role";
+                }
+            }
+        }
+        else {
+            if ( $email eq $entry->[0]
+                && ( $role eq "" || !( $entry->[1] =~ m/$role/ ) ) )
+            {
+                if ( $entry->[1] eq "" ) {
+                    $entry->[1] = "$role";
+                }
+                else {
+                    $entry->[1] = "$entry->[1],$role";
+                }
+            }
+        }
     }
 }
 
 sub which {
     my ($bin) = @_;
 
-    foreach my $path (split(/:/, $ENV{PATH})) {
-	if (-e "$path/$bin") {
-	    return "$path/$bin";
-	}
+    foreach my $path ( split( /:/, $ENV{PATH} ) ) {
+        if ( -e "$path/$bin" ) {
+            return "$path/$bin";
+        }
     }
 
     return "";
@@ -1479,10 +1509,10 @@ sub which {
 sub which_conf {
     my ($conf) = @_;
 
-    foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
-	if (-e "$path/$conf") {
-	    return "$path/$conf";
-	}
+    foreach my $path ( split( /:/, ".:$ENV{HOME}:.scripts" ) ) {
+        if ( -e "$path/$conf" ) {
+            return "$path/$conf";
+        }
     }
 
     return "";
@@ -1491,28 +1521,30 @@ sub which_conf {
 sub mailmap_email {
     my ($line) = @_;
 
-    my ($name, $address) = parse_email($line);
-    my $email = format_email($name, $address, 1);
-    my $real_name = $name;
+    my ( $name, $address ) = parse_email($line);
+    my $email        = format_email( $name, $address, 1 );
+    my $real_name    = $name;
     my $real_address = $address;
 
-    if (exists $mailmap->{names}->{$email} ||
-	exists $mailmap->{addresses}->{$email}) {
-	if (exists $mailmap->{names}->{$email}) {
-	    $real_name = $mailmap->{names}->{$email};
-	}
-	if (exists $mailmap->{addresses}->{$email}) {
-	    $real_address = $mailmap->{addresses}->{$email};
-	}
-    } else {
-	if (exists $mailmap->{names}->{$address}) {
-	    $real_name = $mailmap->{names}->{$address};
-	}
-	if (exists $mailmap->{addresses}->{$address}) {
-	    $real_address = $mailmap->{addresses}->{$address};
-	}
-    }
-    return format_email($real_name, $real_address, 1);
+    if (   exists $mailmap->{names}->{$email}
+        || exists $mailmap->{addresses}->{$email} )
+    {
+        if ( exists $mailmap->{names}->{$email} ) {
+            $real_name = $mailmap->{names}->{$email};
+        }
+        if ( exists $mailmap->{addresses}->{$email} ) {
+            $real_address = $mailmap->{addresses}->{$email};
+        }
+    }
+    else {
+        if ( exists $mailmap->{names}->{$address} ) {
+            $real_name = $mailmap->{names}->{$address};
+        }
+        if ( exists $mailmap->{addresses}->{$address} ) {
+            $real_address = $mailmap->{addresses}->{$address};
+        }
+    }
+    return format_email( $real_name, $real_address, 1 );
 }
 
 sub mailmap {
@@ -1520,7 +1552,7 @@ sub mailmap {
 
     my @mapped_emails = ();
     foreach my $line (@addresses) {
-	push(@mapped_emails, mailmap_email($line));
+        push( @mapped_emails, mailmap_email($line) );
     }
     merge_by_realname(@mapped_emails) if ($email_use_mailmap);
     return @mapped_emails;
@@ -1531,13 +1563,14 @@ sub merge_by_realname {
     my (@emails) = @_;
 
     foreach my $email (@emails) {
-	my ($name, $address) = parse_email($email);
-	if (exists $address_map{$name}) {
-	    $address = $address_map{$name};
-	    $email = format_email($name, $address, 1);
-	} else {
-	    $address_map{$name} = $address;
-	}
+        my ( $name, $address ) = parse_email($email);
+        if ( exists $address_map{$name} ) {
+            $address = $address_map{$name};
+            $email   = format_email( $name, $address, 1 );
+        }
+        else {
+            $address_map{$name} = $address;
+        }
     }
 }
 
@@ -1547,7 +1580,7 @@ sub git_execute_cmd {
 
     my $output = `$cmd`;
     $output =~ s/^\s*//gm;
-    @lines = split("\n", $output);
+    @lines = split( "\n", $output );
 
     return @lines;
 }
@@ -1557,7 +1590,7 @@ sub hg_execute_cmd {
     my @lines = ();
 
     my $output = `$cmd`;
-    @lines = split("\n", $output);
+    @lines = split( "\n", $output );
 
     return @lines;
 }
@@ -1575,71 +1608,71 @@ sub extract_formatted_signatures {
 ## Reformat email addresses (with names) to avoid badly written signatures
 
     foreach my $signer (@signature_lines) {
-	$signer = deduplicate_email($signer);
+        $signer = deduplicate_email($signer);
     }
 
-    return (\@type, \@signature_lines);
+    return ( \@type, \@signature_lines );
 }
 
 sub vcs_find_signers {
-    my ($cmd, $file) = @_;
+    my ( $cmd, $file ) = @_;
     my $commits;
-    my @lines = ();
+    my @lines      = ();
     my @signatures = ();
-    my @authors = ();
-    my @stats = ();
+    my @authors    = ();
+    my @stats      = ();
 
-    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+    @lines = &{ $VCS_cmds{"execute_cmd"} }($cmd);
 
-    my $pattern = $VCS_cmds{"commit_pattern"};
+    my $pattern        = $VCS_cmds{"commit_pattern"};
     my $author_pattern = $VCS_cmds{"author_pattern"};
-    my $stat_pattern = $VCS_cmds{"stat_pattern"};
+    my $stat_pattern   = $VCS_cmds{"stat_pattern"};
 
-    $stat_pattern =~ s/(\$\w+)/$1/eeg;		#interpolate $stat_pattern
+    $stat_pattern =~ s/(\$\w+)/$1/eeg;    #interpolate $stat_pattern
 
-    $commits = grep(/$pattern/, @lines);	# of commits
+    $commits = grep( /$pattern/, @lines );    # of commits
 
-    @authors = grep(/$author_pattern/, @lines);
-    @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
-    @stats = grep(/$stat_pattern/, @lines);
+    @authors    = grep( /$author_pattern/,                    @lines );
+    @signatures = grep( /^[ \t]*${signature_pattern}.*\@.*$/, @lines );
+    @stats      = grep( /$stat_pattern/,                      @lines );
 
-#    print("stats: <@stats>\n");
+    #    print("stats: <@stats>\n");
 
-    return (0, \@signatures, \@authors, \@stats) if !@signatures;
+    return ( 0, \@signatures, \@authors, \@stats ) if !@signatures;
 
     save_commits_by_author(@lines) if ($interactive);
     save_commits_by_signer(@lines) if ($interactive);
 
-    if (!$email_git_penguin_chiefs) {
-	@signatures = grep(!/${penguin_chiefs}/i, @signatures);
+    if ( !$email_git_penguin_chiefs ) {
+        @signatures = grep( !/${penguin_chiefs}/i, @signatures );
     }
 
-    my ($author_ref, $authors_ref) = extract_formatted_signatures(@authors);
-    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
+    my ( $author_ref, $authors_ref ) = extract_formatted_signatures(@authors);
+    my ( $types_ref,  $signers_ref ) = extract_formatted_signatures(@signatures);
 
-    return ($commits, $signers_ref, $authors_ref, \@stats);
+    return ( $commits, $signers_ref, $authors_ref, \@stats );
 }
 
 sub vcs_find_author {
     my ($cmd) = @_;
     my @lines = ();
 
-    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+    @lines = &{ $VCS_cmds{"execute_cmd"} }($cmd);
 
-    if (!$email_git_penguin_chiefs) {
-	@lines = grep(!/${penguin_chiefs}/i, @lines);
+    if ( !$email_git_penguin_chiefs ) {
+        @lines = grep( !/${penguin_chiefs}/i, @lines );
     }
 
     return @lines if !@lines;
 
     my @authors = ();
     foreach my $line (@lines) {
-	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
-	    my $author = $1;
-	    my ($name, $address) = parse_email($author);
-	    $author = format_email($name, $address, 1);
-	    push(@authors, $author);
-	}
+        if ( $line =~ m/$VCS_cmds{"author_pattern"}/ ) {
+            my $author = $1;
+            my ( $name, $address ) = parse_email($author);
+            $author = format_email( $name, $address, 1 );
+            push( @authors, $author );
+        }
     }
 
     save_commits_by_author(@lines) if ($interactive);
@@ -1649,16 +1682,16 @@ sub vcs_find_author {
 }
 
 sub vcs_save_commits {
-    my ($cmd) = @_;
-    my @lines = ();
+    my ($cmd)   = @_;
+    my @lines   = ();
     my @commits = ();
 
-    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
+    @lines = &{ $VCS_cmds{"execute_cmd"} }($cmd);
 
     foreach my $line (@lines) {
-	if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) {
-	    push(@commits, $1);
-	}
+        if ( $line =~ m/$VCS_cmds{"blame_commit_pattern"}/ ) {
+            push( @commits, $1 );
+        }
     }
 
     return @commits;
@@ -1669,62 +1702,65 @@ sub vcs_blame {
     my $cmd;
     my @commits = ();
 
-    return @commits if (!(-f $file));
-
-    if (@range && $VCS_cmds{"blame_range_cmd"} eq "") {
-	my @all_commits = ();
-
-	$cmd = $VCS_cmds{"blame_file_cmd"};
-	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
-	@all_commits = vcs_save_commits($cmd);
-
-	foreach my $file_range_diff (@range) {
-	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
-	    my $diff_file = $1;
-	    my $diff_start = $2;
-	    my $diff_length = $3;
-	    next if ("$file" ne "$diff_file");
-	    for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) {
-		push(@commits, $all_commits[$i]);
-	    }
-	}
-    } elsif (@range) {
-	foreach my $file_range_diff (@range) {
-	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
-	    my $diff_file = $1;
-	    my $diff_start = $2;
-	    my $diff_length = $3;
-	    next if ("$file" ne "$diff_file");
-	    $cmd = $VCS_cmds{"blame_range_cmd"};
-	    $cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
-	    push(@commits, vcs_save_commits($cmd));
-	}
-    } else {
-	$cmd = $VCS_cmds{"blame_file_cmd"};
-	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
-	@commits = vcs_save_commits($cmd);
+    return @commits if ( !( -f $file ) );
+
+    if ( @range && $VCS_cmds{"blame_range_cmd"} eq "" ) {
+        my @all_commits = ();
+
+        $cmd = $VCS_cmds{"blame_file_cmd"};
+        $cmd =~ s/(\$\w+)/$1/eeg;    #interpolate $cmd
+        @all_commits = vcs_save_commits($cmd);
+
+        foreach my $file_range_diff (@range) {
+            next if ( !( $file_range_diff =~ m/(.+):(.+):(.+)/ ) );
+            my $diff_file   = $1;
+            my $diff_start  = $2;
+            my $diff_length = $3;
+            next if ( "$file" ne "$diff_file" );
+            for ( my $i = $diff_start; $i < $diff_start + $diff_length; $i++ ) {
+                push( @commits, $all_commits[$i] );
+            }
+        }
+    }
+    elsif (@range) {
+        foreach my $file_range_diff (@range) {
+            next if ( !( $file_range_diff =~ m/(.+):(.+):(.+)/ ) );
+            my $diff_file   = $1;
+            my $diff_start  = $2;
+            my $diff_length = $3;
+            next if ( "$file" ne "$diff_file" );
+            $cmd = $VCS_cmds{"blame_range_cmd"};
+            $cmd =~ s/(\$\w+)/$1/eeg;    #interpolate $cmd
+            push( @commits, vcs_save_commits($cmd) );
+        }
+    }
+    else {
+        $cmd = $VCS_cmds{"blame_file_cmd"};
+        $cmd =~ s/(\$\w+)/$1/eeg;        #interpolate $cmd
+        @commits = vcs_save_commits($cmd);
     }
 
     foreach my $commit (@commits) {
-	$commit =~ s/^\^//g;
+        $commit =~ s/^\^//g;
     }
 
     return @commits;
 }
 
 my $printed_novcs = 0;
+
 sub vcs_exists {
     %VCS_cmds = %VCS_cmds_git;
     return 1 if eval $VCS_cmds{"available"};
     %VCS_cmds = %VCS_cmds_hg;
     return 2 if eval $VCS_cmds{"available"};
     %VCS_cmds = ();
-    if (!$printed_novcs && $email_git) {
-	warn("$P: No supported VCS found.  Add --nogit to options?\n");
-	warn("Using a git repository produces better results.\n");
-	warn("Try Linus Torvalds' latest git repository using:\n");
-	warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n");
-	$printed_novcs = 1;
+    if ( !$printed_novcs && $email_git ) {
+        warn("$P: No supported VCS found.  Add --nogit to options?\n");
+        warn("Using a git repository produces better results.\n");
+        warn("Try Linus Torvalds' latest git repository using:\n");
+        warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n");
+        $printed_novcs = 1;
     }
     return 0;
 }
@@ -1739,9 +1775,9 @@ sub vcs_is_hg {
 }
 
 sub vcs_add_commit_signers {
-    return if (!vcs_exists());
+    return if ( !vcs_exists() );
 
-    my ($commit, $desc) = @_;
+    my ( $commit, $desc ) = @_;
     my $commit_count = 0;
     my $commit_authors_ref;
     my $commit_signers_ref;
@@ -1751,17 +1787,17 @@ sub vcs_add_commit_signers {
     my $cmd;
 
     $cmd = $VCS_cmds{"find_commit_signers_cmd"};
-    $cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
+    $cmd =~ s/(\$\w+)/$1/eeg;    #substitute variables in $cmd
 
-    ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, "");
+    ( $commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref ) = vcs_find_signers( $cmd, "" );
     @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
     @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
 
     foreach my $signer (@commit_signers) {
-	$signer = deduplicate_email($signer);
+        $signer = deduplicate_email($signer);
     }
 
-    vcs_assign($desc, 1, @commit_signers);
+    vcs_assign( $desc, 1, @commit_signers );
 }
 
 sub interactive_get_maintainers {
@@ -1773,68 +1809,69 @@ sub interactive_get_maintainers {
     my %selected;
     my %authored;
     my %signed;
-    my $count = 0;
+    my $count      = 0;
     my $maintained = 0;
     foreach my $entry (@list) {
-	$maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
-	$selected{$count} = 1;
-	$authored{$count} = 0;
-	$signed{$count} = 0;
-	$count++;
+        $maintained       = 1 if ( $entry->[1] =~ /^(maintainer|supporter)/i );
+        $selected{$count} = 1;
+        $authored{$count} = 0;
+        $signed{$count}   = 0;
+        $count++;
     }
 
     #menu loop
-    my $done = 0;
+    my $done          = 0;
     my $print_options = 0;
-    my $redraw = 1;
-    while (!$done) {
-	$count = 0;
-	if ($redraw) {
-	    printf STDERR "\n%1s %2s %-65s",
-			  "*", "#", "email/list and role:stats";
-	    if ($email_git ||
-		($email_git_fallback && !$maintained) ||
-		$email_git_blame) {
-		print STDERR "auth sign";
-	    }
-	    print STDERR "\n";
-	    foreach my $entry (@list) {
-		my $email = $entry->[0];
-		my $role = $entry->[1];
-		my $sel = "";
-		$sel = "*" if ($selected{$count});
-		my $commit_author = $commit_author_hash{$email};
-		my $commit_signer = $commit_signer_hash{$email};
-		my $authored = 0;
-		my $signed = 0;
-		$authored++ for (@{$commit_author});
-		$signed++ for (@{$commit_signer});
-		printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
-		printf STDERR "%4d %4d", $authored, $signed
-		    if ($authored > 0 || $signed > 0);
-		printf STDERR "\n     %s\n", $role;
-		if ($authored{$count}) {
-		    my $commit_author = $commit_author_hash{$email};
-		    foreach my $ref (@{$commit_author}) {
-			print STDERR "     Author: @{$ref}[1]\n";
-		    }
-		}
-		if ($signed{$count}) {
-		    my $commit_signer = $commit_signer_hash{$email};
-		    foreach my $ref (@{$commit_signer}) {
-			print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
-		    }
-		}
-
-		$count++;
-	    }
-	}
-	my $date_ref = \$email_git_since;
-	$date_ref = \$email_hg_since if (vcs_is_hg());
-	if ($print_options) {
-	    $print_options = 0;
-	    if (vcs_exists()) {
-		print STDERR <<EOT
+    my $redraw        = 1;
+    while ( !$done ) {
+        $count = 0;
+        if ($redraw) {
+            printf STDERR "\n%1s %2s %-65s", "*", "#", "email/list and role:stats";
+            if (   $email_git
+                || ( $email_git_fallback && !$maintained )
+                || $email_git_blame )
+            {
+                print STDERR "auth sign";
+            }
+            print STDERR "\n";
+            foreach my $entry (@list) {
+                my $email = $entry->[0];
+                my $role  = $entry->[1];
+                my $sel   = "";
+                $sel = "*" if ( $selected{$count} );
+                my $commit_author = $commit_author_hash{$email};
+                my $commit_signer = $commit_signer_hash{$email};
+                my $authored      = 0;
+                my $signed        = 0;
+                $authored++ for ( @{$commit_author} );
+                $signed++   for ( @{$commit_signer} );
+                printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
+                printf STDERR "%4d %4d", $authored, $signed
+                    if ( $authored > 0 || $signed > 0 );
+                printf STDERR "\n     %s\n", $role;
+
+                if ( $authored{$count} ) {
+                    my $commit_author = $commit_author_hash{$email};
+                    foreach my $ref ( @{$commit_author} ) {
+                        print STDERR "     Author: @{$ref}[1]\n";
+                    }
+                }
+                if ( $signed{$count} ) {
+                    my $commit_signer = $commit_signer_hash{$email};
+                    foreach my $ref ( @{$commit_signer} ) {
+                        print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
+                    }
+                }
+
+                $count++;
+            }
+        }
+        my $date_ref = \$email_git_since;
+        $date_ref = \$email_hg_since if ( vcs_is_hg() );
+        if ($print_options) {
+            $print_options = 0;
+            if ( vcs_exists() ) {
+                print STDERR <<EOT;
 
 Version Control options:
 g  use git history      [$email_git]
@@ -1848,8 +1885,8 @@ x# max maintainers      [$email_git_max_maintainers]
 t  all signature types  [$email_git_all_signature_types]
 m  use .mailmap         [$email_use_mailmap]
 EOT
-	    }
-	    print STDERR <<EOT
+            }
+            print STDERR <<EOT;
 
 Additional options:
 0  toggle all
@@ -1862,145 +1899,172 @@ k  keywords in file     [$keywords]
 r  remove duplicates    [$email_remove_duplicates]
 p# pattern match depth  [$pattern_depth]
 EOT
-	}
-	print STDERR
-"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
-
-	my $input = <STDIN>;
-	chomp($input);
-
-	$redraw = 1;
-	my $rerun = 0;
-	my @wish = split(/[, ]+/, $input);
-	foreach my $nr (@wish) {
-	    $nr = lc($nr);
-	    my $sel = substr($nr, 0, 1);
-	    my $str = substr($nr, 1);
-	    my $val = 0;
-	    $val = $1 if $str =~ /^(\d+)$/;
-
-	    if ($sel eq "y") {
-		$interactive = 0;
-		$done = 1;
-		$output_rolestats = 0;
-		$output_roles = 0;
-		last;
-	    } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
-		$selected{$nr - 1} = !$selected{$nr - 1};
-	    } elsif ($sel eq "*" || $sel eq '^') {
-		my $toggle = 0;
-		$toggle = 1 if ($sel eq '*');
-		for (my $i = 0; $i < $count; $i++) {
-		    $selected{$i} = $toggle;
-		}
-	    } elsif ($sel eq "0") {
-		for (my $i = 0; $i < $count; $i++) {
-		    $selected{$i} = !$selected{$i};
-		}
-	    } elsif ($sel eq "t") {
-		if (lc($str) eq "m") {
-		    for (my $i = 0; $i < $count; $i++) {
-			$selected{$i} = !$selected{$i}
-			    if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
-		    }
-		} elsif (lc($str) eq "g") {
-		    for (my $i = 0; $i < $count; $i++) {
-			$selected{$i} = !$selected{$i}
-			    if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
-		    }
-		} elsif (lc($str) eq "l") {
-		    for (my $i = 0; $i < $count; $i++) {
-			$selected{$i} = !$selected{$i}
-			    if ($list[$i]->[1] =~ /^(open list)/i);
-		    }
-		} elsif (lc($str) eq "s") {
-		    for (my $i = 0; $i < $count; $i++) {
-			$selected{$i} = !$selected{$i}
-			    if ($list[$i]->[1] =~ /^(subscriber list)/i);
-		    }
-		}
-	    } elsif ($sel eq "a") {
-		if ($val > 0 && $val <= $count) {
-		    $authored{$val - 1} = !$authored{$val - 1};
-		} elsif ($str eq '*' || $str eq '^') {
-		    my $toggle = 0;
-		    $toggle = 1 if ($str eq '*');
-		    for (my $i = 0; $i < $count; $i++) {
-			$authored{$i} = $toggle;
-		    }
-		}
-	    } elsif ($sel eq "s") {
-		if ($val > 0 && $val <= $count) {
-		    $signed{$val - 1} = !$signed{$val - 1};
-		} elsif ($str eq '*' || $str eq '^') {
-		    my $toggle = 0;
-		    $toggle = 1 if ($str eq '*');
-		    for (my $i = 0; $i < $count; $i++) {
-			$signed{$i} = $toggle;
-		    }
-		}
-	    } elsif ($sel eq "o") {
-		$print_options = 1;
-		$redraw = 1;
-	    } elsif ($sel eq "g") {
-		if ($str eq "f") {
-		    bool_invert(\$email_git_fallback);
-		} else {
-		    bool_invert(\$email_git);
-		}
-		$rerun = 1;
-	    } elsif ($sel eq "b") {
-		if ($str eq "s") {
-		    bool_invert(\$email_git_blame_signatures);
-		} else {
-		    bool_invert(\$email_git_blame);
-		}
-		$rerun = 1;
-	    } elsif ($sel eq "c") {
-		if ($val > 0) {
-		    $email_git_min_signatures = $val;
-		    $rerun = 1;
-		}
-	    } elsif ($sel eq "x") {
-		if ($val > 0) {
-		    $email_git_max_maintainers = $val;
-		    $rerun = 1;
-		}
-	    } elsif ($sel eq "%") {
-		if ($str ne "" && $val >= 0) {
-		    $email_git_min_percent = $val;
-		    $rerun = 1;
-		}
-	    } elsif ($sel eq "d") {
-		if (vcs_is_git()) {
-		    $email_git_since = $str;
-		} elsif (vcs_is_hg()) {
-		    $email_hg_since = $str;
-		}
-		$rerun = 1;
-	    } elsif ($sel eq "t") {
-		bool_invert(\$email_git_all_signature_types);
-		$rerun = 1;
-	    } elsif ($sel eq "f") {
-		bool_invert(\$email_file_emails);
-		$rerun = 1;
-	    } elsif ($sel eq "r") {
-		bool_invert(\$email_remove_duplicates);
-		$rerun = 1;
-	    } elsif ($sel eq "m") {
-		bool_invert(\$email_use_mailmap);
-		read_mailmap();
-		$rerun = 1;
-	    } elsif ($sel eq "k") {
-		bool_invert(\$keywords);
-		$rerun = 1;
-	    } elsif ($sel eq "p") {
-		if ($str ne "" && $val >= 0) {
-		    $pattern_depth = $val;
-		    $rerun = 1;
-		}
-	    } elsif ($sel eq "h" || $sel eq "?") {
-		print STDERR <<EOT
+        }
+        print STDERR "\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
+
+        my $input = <STDIN>;
+        chomp($input);
+
+        $redraw = 1;
+        my $rerun = 0;
+        my @wish  = split( /[, ]+/, $input );
+        foreach my $nr (@wish) {
+            $nr = lc($nr);
+            my $sel = substr( $nr, 0, 1 );
+            my $str = substr( $nr, 1 );
+            my $val = 0;
+            $val = $1 if $str =~ /^(\d+)$/;
+
+            if ( $sel eq "y" ) {
+                $interactive      = 0;
+                $done             = 1;
+                $output_rolestats = 0;
+                $output_roles     = 0;
+                last;
+            }
+            elsif ( $nr =~ /^\d+$/ && $nr > 0 && $nr <= $count ) {
+                $selected{ $nr - 1 } = !$selected{ $nr - 1 };
+            }
+            elsif ( $sel eq "*" || $sel eq '^' ) {
+                my $toggle = 0;
+                $toggle = 1 if ( $sel eq '*' );
+                for ( my $i = 0; $i < $count; $i++ ) {
+                    $selected{$i} = $toggle;
+                }
+            }
+            elsif ( $sel eq "0" ) {
+                for ( my $i = 0; $i < $count; $i++ ) {
+                    $selected{$i} = !$selected{$i};
+                }
+            }
+            elsif ( $sel eq "t" ) {
+                if ( lc($str) eq "m" ) {
+                    for ( my $i = 0; $i < $count; $i++ ) {
+                        $selected{$i} = !$selected{$i}
+                            if ( $list[$i]->[1] =~ /^(maintainer|supporter)/i );
+                    }
+                }
+                elsif ( lc($str) eq "g" ) {
+                    for ( my $i = 0; $i < $count; $i++ ) {
+                        $selected{$i} = !$selected{$i}
+                            if ( $list[$i]->[1] =~ /^(author|commit|signer)/i );
+                    }
+                }
+                elsif ( lc($str) eq "l" ) {
+                    for ( my $i = 0; $i < $count; $i++ ) {
+                        $selected{$i} = !$selected{$i}
+                            if ( $list[$i]->[1] =~ /^(open list)/i );
+                    }
+                }
+                elsif ( lc($str) eq "s" ) {
+                    for ( my $i = 0; $i < $count; $i++ ) {
+                        $selected{$i} = !$selected{$i}
+                            if ( $list[$i]->[1] =~ /^(subscriber list)/i );
+                    }
+                }
+            }
+            elsif ( $sel eq "a" ) {
+                if ( $val > 0 && $val <= $count ) {
+                    $authored{ $val - 1 } = !$authored{ $val - 1 };
+                }
+                elsif ( $str eq '*' || $str eq '^' ) {
+                    my $toggle = 0;
+                    $toggle = 1 if ( $str eq '*' );
+                    for ( my $i = 0; $i < $count; $i++ ) {
+                        $authored{$i} = $toggle;
+                    }
+                }
+            }
+            elsif ( $sel eq "s" ) {
+                if ( $val > 0 && $val <= $count ) {
+                    $signed{ $val - 1 } = !$signed{ $val - 1 };
+                }
+                elsif ( $str eq '*' || $str eq '^' ) {
+                    my $toggle = 0;
+                    $toggle = 1 if ( $str eq '*' );
+                    for ( my $i = 0; $i < $count; $i++ ) {
+                        $signed{$i} = $toggle;
+                    }
+                }
+            }
+            elsif ( $sel eq "o" ) {
+                $print_options = 1;
+                $redraw        = 1;
+            }
+            elsif ( $sel eq "g" ) {
+                if ( $str eq "f" ) {
+                    bool_invert( \$email_git_fallback );
+                }
+                else {
+                    bool_invert( \$email_git );
+                }
+                $rerun = 1;
+            }
+            elsif ( $sel eq "b" ) {
+                if ( $str eq "s" ) {
+                    bool_invert( \$email_git_blame_signatures );
+                }
+                else {
+                    bool_invert( \$email_git_blame );
+                }
+                $rerun = 1;
+            }
+            elsif ( $sel eq "c" ) {
+                if ( $val > 0 ) {
+                    $email_git_min_signatures = $val;
+                    $rerun                    = 1;
+                }
+            }
+            elsif ( $sel eq "x" ) {
+                if ( $val > 0 ) {
+                    $email_git_max_maintainers = $val;
+                    $rerun                     = 1;
+                }
+            }
+            elsif ( $sel eq "%" ) {
+                if ( $str ne "" && $val >= 0 ) {
+                    $email_git_min_percent = $val;
+                    $rerun                 = 1;
+                }
+            }
+            elsif ( $sel eq "d" ) {
+                if ( vcs_is_git() ) {
+                    $email_git_since = $str;
+                }
+                elsif ( vcs_is_hg() ) {
+                    $email_hg_since = $str;
+                }
+                $rerun = 1;
+            }
+            elsif ( $sel eq "t" ) {
+                bool_invert( \$email_git_all_signature_types );
+                $rerun = 1;
+            }
+            elsif ( $sel eq "f" ) {
+                bool_invert( \$email_file_emails );
+                $rerun = 1;
+            }
+            elsif ( $sel eq "r" ) {
+                bool_invert( \$email_remove_duplicates );
+                $rerun = 1;
+            }
+            elsif ( $sel eq "m" ) {
+                bool_invert( \$email_use_mailmap );
+                read_mailmap();
+                $rerun = 1;
+            }
+            elsif ( $sel eq "k" ) {
+                bool_invert( \$keywords );
+                $rerun = 1;
+            }
+            elsif ( $sel eq "p" ) {
+                if ( $str ne "" && $val >= 0 ) {
+                    $pattern_depth = $val;
+                    $rerun         = 1;
+                }
+            }
+            elsif ( $sel eq "h" || $sel eq "?" ) {
+                print STDERR <<EOT;
 
 Interactive mode allows you to select the various maintainers, submitters,
 commit signers and mailing lists that could be CC'd on a patch.
@@ -2020,26 +2084,27 @@ maintainers are appropriate.  You may enter multiple selections separated
 by either commas or spaces.
 
 EOT
-	    } else {
-		print STDERR "invalid option: '$nr'\n";
-		$redraw = 0;
-	    }
-	}
-	if ($rerun) {
-	    print STDERR "git-blame can be very slow, please have patience..."
-		if ($email_git_blame);
-	    goto &get_maintainers;
-	}
+            }
+            else {
+                print STDERR "invalid option: '$nr'\n";
+                $redraw = 0;
+            }
+        }
+        if ($rerun) {
+            print STDERR "git-blame can be very slow, please have patience..."
+                if ($email_git_blame);
+            goto &get_maintainers;
+        }
     }
 
     #drop not selected entries
     $count = 0;
     my @new_emailto = ();
     foreach my $entry (@list) {
-	if ($selected{$count}) {
-	    push(@new_emailto, $list[$count]);
-	}
-	$count++;
+        if ( $selected{$count} ) {
+            push( @new_emailto, $list[$count] );
+        }
+        $count++;
     }
     return @new_emailto;
 }
@@ -2048,9 +2113,10 @@ sub bool_invert {
     my ($bool_ref) = @_;
 
     if ($$bool_ref) {
-	$$bool_ref = 0;
-    } else {
-	$$bool_ref = 1;
+        $$bool_ref = 0;
+    }
+    else {
+        $$bool_ref = 1;
     }
 }
 
@@ -2058,28 +2124,29 @@ sub deduplicate_email {
     my ($email) = @_;
 
     my $matched = 0;
-    my ($name, $address) = parse_email($email);
-    $email = format_email($name, $address, 1);
+    my ( $name, $address ) = parse_email($email);
+    $email = format_email( $name, $address, 1 );
     $email = mailmap_email($email);
 
-    return $email if (!$email_remove_duplicates);
+    return $email if ( !$email_remove_duplicates );
 
-    ($name, $address) = parse_email($email);
+    ( $name, $address ) = parse_email($email);
 
-    if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
-	$name = $deduplicate_name_hash{lc($name)}->[0];
-	$address = $deduplicate_name_hash{lc($name)}->[1];
-	$matched = 1;
-    } elsif ($deduplicate_address_hash{lc($address)}) {
-	$name = $deduplicate_address_hash{lc($address)}->[0];
-	$address = $deduplicate_address_hash{lc($address)}->[1];
-	$matched = 1;
+    if ( $name ne "" && $deduplicate_name_hash{ lc($name) } ) {
+        $name    = $deduplicate_name_hash{ lc($name) }->[0];
+        $address = $deduplicate_name_hash{ lc($name) }->[1];
+        $matched = 1;
+    }
+    elsif ( $deduplicate_address_hash{ lc($address) } ) {
+        $name    = $deduplicate_address_hash{ lc($address) }->[0];
+        $address = $deduplicate_address_hash{ lc($address) }->[1];
+        $matched = 1;
     }
-    if (!$matched) {
-	$deduplicate_name_hash{lc($name)} = [ $name, $address ];
-	$deduplicate_address_hash{lc($address)} = [ $name, $address ];
+    if ( !$matched ) {
+        $deduplicate_name_hash{ lc($name) }       = [ $name, $address ];
+        $deduplicate_address_hash{ lc($address) } = [ $name, $address ];
     }
-    $email = format_email($name, $address, 1);
+    $email = format_email( $name, $address, 1 );
     $email = mailmap_email($email);
     return $email;
 }
@@ -2087,89 +2154,89 @@ sub deduplicate_email {
 sub save_commits_by_author {
     my (@lines) = @_;
 
-    my @authors = ();
-    my @commits = ();
+    my @authors  = ();
+    my @commits  = ();
     my @subjects = ();
 
     foreach my $line (@lines) {
-	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
-	    my $author = $1;
-	    $author = deduplicate_email($author);
-	    push(@authors, $author);
-	}
-	push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
-	push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
-    }
-
-    for (my $i = 0; $i < @authors; $i++) {
-	my $exists = 0;
-	foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
-	    if (@{$ref}[0] eq $commits[$i] &&
-		@{$ref}[1] eq $subjects[$i]) {
-		$exists = 1;
-		last;
-	    }
-	}
-	if (!$exists) {
-	    push(@{$commit_author_hash{$authors[$i]}},
-		 [ ($commits[$i], $subjects[$i]) ]);
-	}
+        if ( $line =~ m/$VCS_cmds{"author_pattern"}/ ) {
+            my $author = $1;
+            $author = deduplicate_email($author);
+            push( @authors, $author );
+        }
+        push( @commits,  $1 ) if ( $line =~ m/$VCS_cmds{"commit_pattern"}/ );
+        push( @subjects, $1 ) if ( $line =~ m/$VCS_cmds{"subject_pattern"}/ );
+    }
+
+    for ( my $i = 0; $i < @authors; $i++ ) {
+        my $exists = 0;
+        foreach my $ref ( @{ $commit_author_hash{ $authors[$i] } } ) {
+            if (   @{$ref}[0] eq $commits[$i]
+                && @{$ref}[1] eq $subjects[$i] )
+            {
+                $exists = 1;
+                last;
+            }
+        }
+        if ( !$exists ) {
+            push( @{ $commit_author_hash{ $authors[$i] } }, [ ( $commits[$i], $subjects[$i] ) ] );
+        }
     }
 }
 
 sub save_commits_by_signer {
     my (@lines) = @_;
 
-    my $commit = "";
+    my $commit  = "";
     my $subject = "";
 
     foreach my $line (@lines) {
-	$commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
-	$subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
-	if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
-	    my @signatures = ($line);
-	    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
-	    my @types = @$types_ref;
-	    my @signers = @$signers_ref;
-
-	    my $type = $types[0];
-	    my $signer = $signers[0];
-
-	    $signer = deduplicate_email($signer);
-
-	    my $exists = 0;
-	    foreach my $ref(@{$commit_signer_hash{$signer}}) {
-		if (@{$ref}[0] eq $commit &&
-		    @{$ref}[1] eq $subject &&
-		    @{$ref}[2] eq $type) {
-		    $exists = 1;
-		    last;
-		}
-	    }
-	    if (!$exists) {
-		push(@{$commit_signer_hash{$signer}},
-		     [ ($commit, $subject, $type) ]);
-	    }
-	}
+        $commit  = $1 if ( $line =~ m/$VCS_cmds{"commit_pattern"}/ );
+        $subject = $1 if ( $line =~ m/$VCS_cmds{"subject_pattern"}/ );
+        if ( $line =~ /^[ \t]*${signature_pattern}.*\@.*$/ ) {
+            my @signatures = ($line);
+            my ( $types_ref, $signers_ref ) = extract_formatted_signatures(@signatures);
+            my @types   = @$types_ref;
+            my @signers = @$signers_ref;
+
+            my $type   = $types[0];
+            my $signer = $signers[0];
+
+            $signer = deduplicate_email($signer);
+
+            my $exists = 0;
+            foreach my $ref ( @{ $commit_signer_hash{$signer} } ) {
+                if (   @{$ref}[0] eq $commit
+                    && @{$ref}[1] eq $subject
+                    && @{$ref}[2] eq $type )
+                {
+                    $exists = 1;
+                    last;
+                }
+            }
+            if ( !$exists ) {
+                push( @{ $commit_signer_hash{$signer} }, [ ( $commit, $subject, $type ) ] );
+            }
+        }
     }
 }
 
 sub vcs_assign {
-    my ($role, $divisor, @lines) = @_;
+    my ( $role, $divisor, @lines ) = @_;
 
     my %hash;
     my $count = 0;
 
-    return if (@lines <= 0);
+    return if ( @lines <= 0 );
 
-    if ($divisor <= 0) {
-	warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n");
-	$divisor = 1;
+    if ( $divisor <= 0 ) {
+        warn( "Bad divisor in " . ( caller(0) )[3] . ": $divisor\n" );
+        $divisor = 1;
     }
 
     @lines = mailmap(@lines);
 
-    return if (@lines <= 0);
+    return if ( @lines <= 0 );
 
     @lines = sort(@lines);
 
@@ -2177,23 +2244,24 @@ sub vcs_assign {
     $hash{$_}++ for @lines;
 
     # sort -rn
-    foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
-	my $sign_offs = $hash{$line};
-	my $percent = $sign_offs * 100 / $divisor;
-
-	$percent = 100 if ($percent > 100);
-	next if (ignore_email_address($line));
-	$count++;
-	last if ($sign_offs < $email_git_min_signatures ||
-		 $count > $email_git_max_maintainers ||
-		 $percent < $email_git_min_percent);
-	push_email_address($line, '');
-	if ($output_rolestats) {
-	    my $fmt_percent = sprintf("%.0f", $percent);
-	    add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%");
-	} else {
-	    add_role($line, $role);
-	}
+    foreach my $line ( sort { $hash{$b} <=> $hash{$a} } keys %hash ) {
+        my $sign_offs = $hash{$line};
+        my $percent   = $sign_offs * 100 / $divisor;
+
+        $percent = 100 if ( $percent > 100 );
+        next           if ( ignore_email_address($line) );
+        $count++;
+        last if ( $sign_offs < $email_git_min_signatures
+            || $count > $email_git_max_maintainers
+            || $percent < $email_git_min_percent );
+        push_email_address( $line, '' );
+        if ($output_rolestats) {
+            my $fmt_percent = sprintf( "%.0f", $percent );
+            add_role( $line, "$role:$sign_offs/$divisor=$fmt_percent%" );
+        }
+        else {
+            add_role( $line, $role );
+        }
     }
 }
 
@@ -2205,195 +2273,200 @@ sub vcs_file_signoffs {
     my $stats_ref;
     my @authors = ();
     my @signers = ();
-    my @stats = ();
+    my @stats   = ();
     my $commits;
 
     $vcs_used = vcs_exists();
-    return if (!$vcs_used);
+    return if ( !$vcs_used );
 
     my $cmd = $VCS_cmds{"find_signers_cmd"};
-    $cmd =~ s/(\$\w+)/$1/eeg;		# interpolate $cmd
+    $cmd =~ s/(\$\w+)/$1/eeg;    # interpolate $cmd
 
-    ($commits, $signers_ref, $authors_ref, $stats_ref) = vcs_find_signers($cmd, $file);
+    ( $commits, $signers_ref, $authors_ref, $stats_ref ) = vcs_find_signers( $cmd, $file );
 
     @signers = @{$signers_ref} if defined $signers_ref;
     @authors = @{$authors_ref} if defined $authors_ref;
-    @stats = @{$stats_ref} if defined $stats_ref;
+    @stats   = @{$stats_ref}   if defined $stats_ref;
 
-#    print("commits: <$commits>\nsigners:<@signers>\nauthors: <@authors>\nstats: <@stats>\n");
+    #    print("commits: <$commits>\nsigners:<@signers>\nauthors: <@authors>\nstats: <@stats>\n");
 
     foreach my $signer (@signers) {
-	$signer = deduplicate_email($signer);
-    }
-
-    vcs_assign("commit_signer", $commits, @signers);
-    vcs_assign("authored", $commits, @authors);
-    if ($#authors == $#stats) {
-	my $stat_pattern = $VCS_cmds{"stat_pattern"};
-	$stat_pattern =~ s/(\$\w+)/$1/eeg;	#interpolate $stat_pattern
-
-	my $added = 0;
-	my $deleted = 0;
-	for (my $i = 0; $i <= $#stats; $i++) {
-	    if ($stats[$i] =~ /$stat_pattern/) {
-		$added += $1;
-		$deleted += $2;
-	    }
-	}
-	my @tmp_authors = uniq(@authors);
-	foreach my $author (@tmp_authors) {
-	    $author = deduplicate_email($author);
-	}
-	@tmp_authors = uniq(@tmp_authors);
-	my @list_added = ();
-	my @list_deleted = ();
-	foreach my $author (@tmp_authors) {
-	    my $auth_added = 0;
-	    my $auth_deleted = 0;
-	    for (my $i = 0; $i <= $#stats; $i++) {
-		if ($author eq deduplicate_email($authors[$i]) &&
-		    $stats[$i] =~ /$stat_pattern/) {
-		    $auth_added += $1;
-		    $auth_deleted += $2;
-		}
-	    }
-	    for (my $i = 0; $i < $auth_added; $i++) {
-		push(@list_added, $author);
-	    }
-	    for (my $i = 0; $i < $auth_deleted; $i++) {
-		push(@list_deleted, $author);
-	    }
-	}
-	vcs_assign("added_lines", $added, @list_added);
-	vcs_assign("removed_lines", $deleted, @list_deleted);
+        $signer = deduplicate_email($signer);
+    }
+
+    vcs_assign( "commit_signer", $commits, @signers );
+    vcs_assign( "authored",      $commits, @authors );
+    if ( $#authors == $#stats ) {
+        my $stat_pattern = $VCS_cmds{"stat_pattern"};
+        $stat_pattern =~ s/(\$\w+)/$1/eeg;    #interpolate $stat_pattern
+
+        my $added   = 0;
+        my $deleted = 0;
+        for ( my $i = 0; $i <= $#stats; $i++ ) {
+            if ( $stats[$i] =~ /$stat_pattern/ ) {
+                $added   += $1;
+                $deleted += $2;
+            }
+        }
+        my @tmp_authors = uniq(@authors);
+        foreach my $author (@tmp_authors) {
+            $author = deduplicate_email($author);
+        }
+        @tmp_authors = uniq(@tmp_authors);
+        my @list_added   = ();
+        my @list_deleted = ();
+        foreach my $author (@tmp_authors) {
+            my $auth_added   = 0;
+            my $auth_deleted = 0;
+            for ( my $i = 0; $i <= $#stats; $i++ ) {
+                if (   $author eq deduplicate_email( $authors[$i] )
+                    && $stats[$i] =~ /$stat_pattern/ )
+                {
+                    $auth_added   += $1;
+                    $auth_deleted += $2;
+                }
+            }
+            for ( my $i = 0; $i < $auth_added; $i++ ) {
+                push( @list_added, $author );
+            }
+            for ( my $i = 0; $i < $auth_deleted; $i++ ) {
+                push( @list_deleted, $author );
+            }
+        }
+        vcs_assign( "added_lines",   $added,   @list_added );
+        vcs_assign( "removed_lines", $deleted, @list_deleted );
     }
 }
 
 sub vcs_file_blame {
     my ($file) = @_;
 
-    my @signers = ();
+    my @signers     = ();
     my @all_commits = ();
-    my @commits = ();
+    my @commits     = ();
     my $total_commits;
     my $total_lines;
 
     $vcs_used = vcs_exists();
-    return if (!$vcs_used);
+    return if ( !$vcs_used );
 
-    @all_commits = vcs_blame($file);
-    @commits = uniq(@all_commits);
+    @all_commits   = vcs_blame($file);
+    @commits       = uniq(@all_commits);
     $total_commits = @commits;
-    $total_lines = @all_commits;
+    $total_lines   = @all_commits;
 
     if ($email_git_blame_signatures) {
-	if (vcs_is_hg()) {
-	    my $commit_count;
-	    my $commit_authors_ref;
-	    my $commit_signers_ref;
-	    my $stats_ref;
-	    my @commit_authors = ();
-	    my @commit_signers = ();
-	    my $commit = join(" -r ", @commits);
-	    my $cmd;
-
-	    $cmd = $VCS_cmds{"find_commit_signers_cmd"};
-	    $cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
-
-	    ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file);
-	    @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
-	    @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
-
-	    push(@signers, @commit_signers);
-	} else {
-	    foreach my $commit (@commits) {
-		my $commit_count;
-		my $commit_authors_ref;
-		my $commit_signers_ref;
-		my $stats_ref;
-		my @commit_authors = ();
-		my @commit_signers = ();
-		my $cmd;
-
-		$cmd = $VCS_cmds{"find_commit_signers_cmd"};
-		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
-
-		($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file);
-		@commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
-		@commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
-
-		push(@signers, @commit_signers);
-	    }
-	}
+        if ( vcs_is_hg() ) {
+            my $commit_count;
+            my $commit_authors_ref;
+            my $commit_signers_ref;
+            my $stats_ref;
+            my @commit_authors = ();
+            my @commit_signers = ();
+            my $commit         = join( " -r ", @commits );
+            my $cmd;
+
+            $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+            $cmd =~ s/(\$\w+)/$1/eeg;    #substitute variables in $cmd
+
+            ( $commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref ) = vcs_find_signers( $cmd, $file );
+            @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
+            @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
+
+            push( @signers, @commit_signers );
+        }
+        else {
+            foreach my $commit (@commits) {
+                my $commit_count;
+                my $commit_authors_ref;
+                my $commit_signers_ref;
+                my $stats_ref;
+                my @commit_authors = ();
+                my @commit_signers = ();
+                my $cmd;
+
+                $cmd = $VCS_cmds{"find_commit_signers_cmd"};
+                $cmd =~ s/(\$\w+)/$1/eeg;    #substitute variables in $cmd
+
+                ( $commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref ) = vcs_find_signers( $cmd, $file );
+                @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
+                @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
+
+                push( @signers, @commit_signers );
+            }
+        }
     }
 
     if ($from_filename) {
-	if ($output_rolestats) {
-	    my @blame_signers;
-	    if (vcs_is_hg()) {{		# Double brace for last exit
-		my $commit_count;
-		my @commit_signers = ();
-		@commits = uniq(@commits);
-		@commits = sort(@commits);
-		my $commit = join(" -r ", @commits);
-		my $cmd;
-
-		$cmd = $VCS_cmds{"find_commit_author_cmd"};
-		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
-
-		my @lines = ();
-
-		@lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
-
-		if (!$email_git_penguin_chiefs) {
-		    @lines = grep(!/${penguin_chiefs}/i, @lines);
-		}
-
-		last if !@lines;
-
-		my @authors = ();
-		foreach my $line (@lines) {
-		    if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
-			my $author = $1;
-			$author = deduplicate_email($author);
-			push(@authors, $author);
-		    }
-		}
-
-		save_commits_by_author(@lines) if ($interactive);
-		save_commits_by_signer(@lines) if ($interactive);
-
-		push(@signers, @authors);
-	    }}
-	    else {
-		foreach my $commit (@commits) {
-		    my $i;
-		    my $cmd = $VCS_cmds{"find_commit_author_cmd"};
-		    $cmd =~ s/(\$\w+)/$1/eeg;	#interpolate $cmd
-		    my @author = vcs_find_author($cmd);
-		    next if !@author;
-
-		    my $formatted_author = deduplicate_email($author[0]);
-
-		    my $count = grep(/$commit/, @all_commits);
-		    for ($i = 0; $i < $count ; $i++) {
-			push(@blame_signers, $formatted_author);
-		    }
-		}
-	    }
-	    if (@blame_signers) {
-		vcs_assign("authored lines", $total_lines, @blame_signers);
-	    }
-	}
-	foreach my $signer (@signers) {
-	    $signer = deduplicate_email($signer);
-	}
-	vcs_assign("commits", $total_commits, @signers);
-    } else {
-	foreach my $signer (@signers) {
-	    $signer = deduplicate_email($signer);
-	}
-	vcs_assign("modified commits", $total_commits, @signers);
+        if ($output_rolestats) {
+            my @blame_signers;
+            if ( vcs_is_hg() ) {
+                {    # Double brace for last exit
+                    my $commit_count;
+                    my @commit_signers = ();
+                    @commits = uniq(@commits);
+                    @commits = sort(@commits);
+                    my $commit = join( " -r ", @commits );
+                    my $cmd;
+
+                    $cmd = $VCS_cmds{"find_commit_author_cmd"};
+                    $cmd =~ s/(\$\w+)/$1/eeg;    #substitute variables in $cmd
+
+                    my @lines = ();
+
+                    @lines = &{ $VCS_cmds{"execute_cmd"} }($cmd);
+
+                    if ( !$email_git_penguin_chiefs ) {
+                        @lines = grep( !/${penguin_chiefs}/i, @lines );
+                    }
+
+                    last if !@lines;
+
+                    my @authors = ();
+                    foreach my $line (@lines) {
+                        if ( $line =~ m/$VCS_cmds{"author_pattern"}/ ) {
+                            my $author = $1;
+                            $author = deduplicate_email($author);
+                            push( @authors, $author );
+                        }
+                    }
+
+                    save_commits_by_author(@lines) if ($interactive);
+                    save_commits_by_signer(@lines) if ($interactive);
+
+                    push( @signers, @authors );
+                }
+            }
+            else {
+                foreach my $commit (@commits) {
+                    my $i;
+                    my $cmd = $VCS_cmds{"find_commit_author_cmd"};
+                    $cmd =~ s/(\$\w+)/$1/eeg;    #interpolate $cmd
+                    my @author = vcs_find_author($cmd);
+                    next if !@author;
+
+                    my $formatted_author = deduplicate_email( $author[0] );
+
+                    my $count = grep( /$commit/, @all_commits );
+                    for ( $i = 0; $i < $count; $i++ ) {
+                        push( @blame_signers, $formatted_author );
+                    }
+                }
+            }
+            if (@blame_signers) {
+                vcs_assign( "authored lines", $total_lines, @blame_signers );
+            }
+        }
+        foreach my $signer (@signers) {
+            $signer = deduplicate_email($signer);
+        }
+        vcs_assign( "commits", $total_commits, @signers );
+    }
+    else {
+        foreach my $signer (@signers) {
+            $signer = deduplicate_email($signer);
+        }
+        vcs_assign( "modified commits", $total_commits, @signers );
     }
 }
 
@@ -2403,14 +2476,14 @@ sub vcs_file_exists {
     my $exists;
 
     my $vcs_used = vcs_exists();
-    return 0 if (!$vcs_used);
+    return 0 if ( !$vcs_used );
 
     my $cmd = $VCS_cmds{"file_exists_cmd"};
-    $cmd =~ s/(\$\w+)/$1/eeg;		# interpolate $cmd
+    $cmd =~ s/(\$\w+)/$1/eeg;    # interpolate $cmd
     $cmd .= " 2>&1";
-    $exists = &{$VCS_cmds{"execute_cmd"}}($cmd);
+    $exists = &{ $VCS_cmds{"execute_cmd"} }($cmd);
 
-    return 0 if ($? != 0);
+    return 0 if ( $? != 0 );
 
     return $exists;
 }
@@ -2421,13 +2494,13 @@ sub vcs_list_files {
     my @lsfiles = ();
 
     my $vcs_used = vcs_exists();
-    return 0 if (!$vcs_used);
+    return 0 if ( !$vcs_used );
 
     my $cmd = $VCS_cmds{"list_files_cmd"};
-    $cmd =~ s/(\$\w+)/$1/eeg;   # interpolate $cmd
-    @lsfiles = &{$VCS_cmds{"execute_cmd"}}($cmd);
+    $cmd =~ s/(\$\w+)/$1/eeg;    # interpolate $cmd
+    @lsfiles = &{ $VCS_cmds{"execute_cmd"} }($cmd);
 
-    return () if ($? != 0);
+    return () if ( $? != 0 );
 
     return @lsfiles;
 }
@@ -2436,7 +2509,7 @@ sub uniq {
     my (@parms) = @_;
 
     my %saw;
-    @parms = grep(!$saw{$_}++, @parms);
+    @parms = grep( !$saw{$_}++, @parms );
     return @parms;
 }
 
@@ -2445,7 +2518,7 @@ sub sort_and_uniq {
 
     my %saw;
     @parms = sort @parms;
-    @parms = grep(!$saw{$_}++, @parms);
+    @parms = grep( !$saw{$_}++, @parms );
     return @parms;
 }
 
@@ -2454,42 +2527,46 @@ sub clean_file_emails {
     my @fmt_emails = ();
 
     foreach my $email (@file_emails) {
-	$email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g;
-	my ($name, $address) = parse_email($email);
-	if ($name eq '"[,\.]"') {
-	    $name = "";
-	}
-
-	my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name);
-	if (@nw > 2) {
-	    my $first = $nw[@nw - 3];
-	    my $middle = $nw[@nw - 2];
-	    my $last = $nw[@nw - 1];
-
-	    if (((length($first) == 1 && $first =~ m/[A-Za-z]/) ||
-		 (length($first) == 2 && substr($first, -1) eq ".")) ||
-		(length($middle) == 1 ||
-		 (length($middle) == 2 && substr($middle, -1) eq "."))) {
-		$name = "$first $middle $last";
-	    } else {
-		$name = "$middle $last";
-	    }
-	}
-
-	if (substr($name, -1) =~ /[,\.]/) {
-	    $name = substr($name, 0, length($name) - 1);
-	} elsif (substr($name, -2) =~ /[,\.]"/) {
-	    $name = substr($name, 0, length($name) - 2) . '"';
-	}
-
-	if (substr($name, 0, 1) =~ /[,\.]/) {
-	    $name = substr($name, 1, length($name) - 1);
-	} elsif (substr($name, 0, 2) =~ /"[,\.]/) {
-	    $name = '"' . substr($name, 2, length($name) - 2);
-	}
-
-	my $fmt_email = format_email($name, $address, $email_usename);
-	push(@fmt_emails, $fmt_email);
+        $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g;
+        my ( $name, $address ) = parse_email($email);
+        if ( $name eq '"[,\.]"' ) {
+            $name = "";
+        }
+
+        my @nw = split( /[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name );
+        if ( @nw > 2 ) {
+            my $first  = $nw[ @nw - 3 ];
+            my $middle = $nw[ @nw - 2 ];
+            my $last   = $nw[ @nw - 1 ];
+
+            if (( ( length($first) == 1 && $first =~ m/[A-Za-z]/ ) || ( length($first) == 2 && substr( $first, -1 ) eq "." ) )
+                || ( length($middle) == 1
+                    || ( length($middle) == 2 && substr( $middle, -1 ) eq "." ) )
+                )
+            {
+                $name = "$first $middle $last";
+            }
+            else {
+                $name = "$middle $last";
+            }
+        }
+
+        if ( substr( $name, -1 ) =~ /[,\.]/ ) {
+            $name = substr( $name, 0, length($name) - 1 );
+        }
+        elsif ( substr( $name, -2 ) =~ /[,\.]"/ ) {
+            $name = substr( $name, 0, length($name) - 2 ) . '"';
+        }
+
+        if ( substr( $name, 0, 1 ) =~ /[,\.]/ ) {
+            $name = substr( $name, 1, length($name) - 1 );
+        }
+        elsif ( substr( $name, 0, 2 ) =~ /"[,\.]/ ) {
+            $name = '"' . substr( $name, 2, length($name) - 2 );
+        }
+
+        my $fmt_email = format_email( $name, $address, $email_usename );
+        push( @fmt_emails, $fmt_email );
     }
     return @fmt_emails;
 }
@@ -2499,15 +2576,16 @@ sub merge_email {
     my %saw;
 
     for (@_) {
-	my ($address, $role) = @$_;
-	if (!$saw{$address}) {
-	    if ($output_roles) {
-		push(@lines, "$address ($role)");
-	    } else {
-		push(@lines, $address);
-	    }
-	    $saw{$address} = 1;
-	}
+        my ( $address, $role ) = @$_;
+        if ( !$saw{$address} ) {
+            if ($output_roles) {
+                push( @lines, "$address ($role)" );
+            }
+            else {
+                push( @lines, $address );
+            }
+            $saw{$address} = 1;
+        }
     }
 
     return @lines;
@@ -2517,48 +2595,50 @@ sub output {
     my (@parms) = @_;
 
     if ($output_multiline) {
-	foreach my $line (@parms) {
-	    print("${line}\n");
-	}
-    } else {
-	print(join($output_separator, @parms));
-	print("\n");
+        foreach my $line (@parms) {
+            print("${line}\n");
+        }
+    }
+    else {
+        print( join( $output_separator, @parms ) );
+        print("\n");
     }
 }
 
 my $rfc822re;
 
 sub make_rfc822re {
-#   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
-#   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
-#   This regexp will only work on addresses which have had comments stripped
-#   and replaced with rfc822_lwsp.
+
+    #   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
+    #   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
+    #   This regexp will only work on addresses which have had comments stripped
+    #   and replaced with rfc822_lwsp.
 
     my $specials = '()<>@,;:\\\\".\\[\\]';
     my $controls = '\\000-\\037\\177';
 
-    my $dtext = "[^\\[\\]\\r\\\\]";
+    my $dtext          = "[^\\[\\]\\r\\\\]";
     my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*";
 
     my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*";
 
-#   Use zero-width assertion to spot the limit of an atom.  A simple
-#   $rfc822_lwsp* causes the regexp engine to hang occasionally.
-    my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
-    my $word = "(?:$atom|$quoted_string)";
+    #   Use zero-width assertion to spot the limit of an atom.  A simple
+    #   $rfc822_lwsp* causes the regexp engine to hang occasionally.
+    my $atom      = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
+    my $word      = "(?:$atom|$quoted_string)";
     my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*";
 
     my $sub_domain = "(?:$atom|$domain_literal)";
-    my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
+    my $domain     = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
 
     my $addr_spec = "$localpart\@$rfc822_lwsp*$domain";
 
-    my $phrase = "$word*";
-    my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
+    my $phrase     = "$word*";
+    my $route      = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
     my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*";
-    my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
+    my $mailbox    = "(?:$addr_spec|$phrase$route_addr)";
 
-    my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
+    my $group   = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
     my $address = "(?:$mailbox|$group)";
 
     return "$rfc822_lwsp*$address";
@@ -2566,13 +2646,18 @@ sub make_rfc822re {
 
 sub rfc822_strip_comments {
     my $s = shift;
-#   Recursively remove comments, and replace with a single space.  The simpler
-#   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
-#   chars in atoms, for example.
 
-    while ($s =~ s/^((?:[^"\\]|\\.)*
+    #   Recursively remove comments, and replace with a single space.  The simpler
+    #   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
+    #   chars in atoms, for example.
+
+    while (
+        $s =~ s/^((?:[^"\\]|\\.)*
                     (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
-                    \((?:[^()\\]|\\.)*\)/$1 /osx) {}
+                    \((?:[^()\\]|\\.)*\)/$1 /osx
+        )
+    {
+    }
     return $s;
 }
 
@@ -2581,7 +2666,7 @@ sub rfc822_strip_comments {
 sub rfc822_valid {
     my $s = rfc822_strip_comments(shift);
 
-    if (!$rfc822re) {
+    if ( !$rfc822re ) {
         $rfc822re = make_rfc822re();
     }
 
@@ -2601,19 +2686,21 @@ sub rfc822_valid {
 sub rfc822_validlist {
     my $s = rfc822_strip_comments(shift);
 
-    if (!$rfc822re) {
+    if ( !$rfc822re ) {
         $rfc822re = make_rfc822re();
     }
+
     # * null list items are valid according to the RFC
     # * the '1' business is to aid in distinguishing failure from no results
 
     my @r;
-    if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so &&
-	$s =~ m/^$rfc822_char*$/) {
-        while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) {
-            push(@r, $1);
+    if (   $s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so
+        && $s =~ m/^$rfc822_char*$/ )
+    {
+        while ( $s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos ) {
+            push( @r, $1 );
         }
-        return wantarray ? (scalar(@r), @r) : 1;
+        return wantarray ? ( scalar(@r), @r ) : 1;
     }
     return wantarray ? () : 0;
 }

-- 
2.42.0.582.g8ccd20d70d-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/3] get_maintainer: add patch-only pattern matching type
  2023-09-27  3:19 [PATCH 0/3] get_maintainer: add patch-only keyword matching Justin Stitt
  2023-09-27  3:19 ` [PATCH 1/3] MAINTAINERS: add documentation for D: Justin Stitt
  2023-09-27  3:19 ` [PATCH 2/3] get_maintainer: run perltidy Justin Stitt
@ 2023-09-27  3:19 ` Justin Stitt
  2023-09-27  6:14   ` Greg KH
                     ` (2 more replies)
  2023-09-27 15:24 ` [PATCH 0/3] get_maintainer: add patch-only keyword matching Nick Desaulniers
  3 siblings, 3 replies; 16+ messages in thread
From: Justin Stitt @ 2023-09-27  3:19 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello, Justin Stitt

Add the "D:" type which behaves the same as "K:" but will only match
content present in a patch file.

To illustrate:

Imagine this entry in MAINTAINERS:

NEW REPUBLIC
M: Han Solo <hansolo@rebelalliance.co>
W: https://www.jointheresistance.org
D: \bstrncpy\b

Our maintainer, Han, will only be added to the recipients if a patch
file is passed to get_maintainer (like what b4 does):
$ ./scripts/get_maintainer.pl 0004-some-change.patch

If the above patch has a `strncpy` present in the subject, commit log or
diff then Han will be to/cc'd.

However, in the event of a file from the tree given like:
$ ./scripts/get_maintainer.pl ./lib/string.c

Han will not be noisily to/cc'd (like a K: type would in this
circumstance)

Note that folks really shouldn't be using get_maintainer on tree files
anyways [1].

[1]: https://lore.kernel.org/all/20230726151515.1650519-1-kuba@kernel.org/
---
 scripts/get_maintainer.pl | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index e679eac96793..f290bf0948f1 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -309,6 +309,7 @@ if ( $tree && !top_of_kernel_tree($lk_path) ) {
 
 my @typevalue = ();
 my %keyword_hash;
+my %patch_keyword_hash;
 my @mfiles         = ();
 my @self_test_info = ();
 
@@ -339,6 +340,9 @@ sub read_maintainer_file {
             elsif ( $type eq "K" ) {
                 $keyword_hash{@typevalue} = $value;
             }
+            elsif ( $type eq "D" ) {
+                $patch_keyword_hash{@typevalue} = $value;
+            }
             push( @typevalue, "$type:$value" );
         }
         elsif ( !( /^\s*$/ || /^\s*\#/ ) ) {
@@ -591,6 +595,11 @@ foreach my $file (@ARGV) {
                         push( @keyword_tvi, $line );
                     }
                 }
+                foreach my $line ( keys %patch_keyword_hash ) {
+                    if ($patch_line =~ m/${patch_prefix}$patch_keyword_hash{$line}/x ) {
+                        push( @keyword_tvi, $line );
+                    }
+                }
             }
         }
         close($patch);

-- 
2.42.0.582.g8ccd20d70d-goog


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 2/3] get_maintainer: run perltidy
  2023-09-27  3:19 ` [PATCH 2/3] get_maintainer: run perltidy Justin Stitt
@ 2023-09-27  3:26   ` Joe Perches
  0 siblings, 0 replies; 16+ messages in thread
From: Joe Perches @ 2023-09-27  3:26 UTC (permalink / raw)
  To: Justin Stitt
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, 2023-09-27 at 03:19 +0000, Justin Stitt wrote:
> I'm a first time contributor to get_maintainer.pl and the formatting is
> suspicious. I am not sure if there is a particular reason it is the way
> it is but I let my editor format it and submitted the diff here in this
> patch.

Capital NACK.  Completely unnecessary and adds no value.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] MAINTAINERS: add documentation for D:
  2023-09-27  3:19 ` [PATCH 1/3] MAINTAINERS: add documentation for D: Justin Stitt
@ 2023-09-27  3:27   ` Joe Perches
  2023-09-27  3:30     ` Justin Stitt
  2023-09-27 16:06   ` Kees Cook
  1 sibling, 1 reply; 16+ messages in thread
From: Joe Perches @ 2023-09-27  3:27 UTC (permalink / raw)
  To: Justin Stitt
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, 2023-09-27 at 03:19 +0000, Justin Stitt wrote:
> Document what "D:" does.
> 
> This is more or less the same as what "K:" does but only works for patch
> files.

Nack.  I'd rather just add a !$file test to K: patterns.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] MAINTAINERS: add documentation for D:
  2023-09-27  3:27   ` Joe Perches
@ 2023-09-27  3:30     ` Justin Stitt
  0 siblings, 0 replies; 16+ messages in thread
From: Justin Stitt @ 2023-09-27  3:30 UTC (permalink / raw)
  To: Joe Perches
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, Sep 27, 2023 at 12:27 PM Joe Perches <joe@perches.com> wrote:
>
> On Wed, 2023-09-27 at 03:19 +0000, Justin Stitt wrote:
> > Document what "D:" does.
> >
> > This is more or less the same as what "K:" does but only works for patch
> > files.
>
> Nack.  I'd rather just add a !$file test to K: patterns.

Are there no legitimate use cases for K:'s current behavior to warrant
keeping it around?

>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/3] get_maintainer: add patch-only pattern matching type
  2023-09-27  3:19 ` [PATCH 3/3] get_maintainer: add patch-only pattern matching type Justin Stitt
@ 2023-09-27  6:14   ` Greg KH
  2023-09-27  6:46     ` Justin Stitt
  2023-09-27 16:15   ` Kees Cook
  2023-09-27 19:00   ` Joe Perches
  2 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2023-09-27  6:14 UTC (permalink / raw)
  To: Justin Stitt
  Cc: Joe Perches, linux-kernel, Kees Cook, Nick Desaulniers,
	Nathan Chancellor, Jakub Kicinski, Krzysztof Kozlowski, geert,
	workflows, mario.limonciello

On Wed, Sep 27, 2023 at 03:19:16AM +0000, Justin Stitt wrote:
> Note that folks really shouldn't be using get_maintainer on tree files
> anyways [1].

That's not true, Linus and I use it on a daily basis this way, it's part
of our normal workflow, AND the workflow of the kernel security team.

So please don't take that valid use-case away from us.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/3] get_maintainer: add patch-only pattern matching type
  2023-09-27  6:14   ` Greg KH
@ 2023-09-27  6:46     ` Justin Stitt
  2023-09-27  8:21       ` Greg KH
  0 siblings, 1 reply; 16+ messages in thread
From: Justin Stitt @ 2023-09-27  6:46 UTC (permalink / raw)
  To: Greg KH
  Cc: Joe Perches, linux-kernel, Kees Cook, Nick Desaulniers,
	Nathan Chancellor, Jakub Kicinski, Krzysztof Kozlowski, geert,
	workflows, mario.limonciello

On Wed, Sep 27, 2023 at 3:14 PM Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Wed, Sep 27, 2023 at 03:19:16AM +0000, Justin Stitt wrote:
> > Note that folks really shouldn't be using get_maintainer on tree files
> > anyways [1].
>
> That's not true, Linus and I use it on a daily basis this way, it's part
> of our normal workflow, AND the workflow of the kernel security team.
>
> So please don't take that valid use-case away from us.

Fair. I'm on the side of keeping the "K:'' behavior the way it is and
that's why I'm proposing adding "D:" to provide a more granular
content matching type operating strictly on patches. It's purely
opt-in.

The patch I linked mentioned steering folks away from using
tree files but not necessarily removing the behavior.

>
> thanks,
>
> greg k-h

Thanks
Justin

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/3] get_maintainer: add patch-only pattern matching type
  2023-09-27  6:46     ` Justin Stitt
@ 2023-09-27  8:21       ` Greg KH
  0 siblings, 0 replies; 16+ messages in thread
From: Greg KH @ 2023-09-27  8:21 UTC (permalink / raw)
  To: Justin Stitt
  Cc: Joe Perches, linux-kernel, Kees Cook, Nick Desaulniers,
	Nathan Chancellor, Jakub Kicinski, Krzysztof Kozlowski, geert,
	workflows, mario.limonciello

On Wed, Sep 27, 2023 at 03:46:30PM +0900, Justin Stitt wrote:
> On Wed, Sep 27, 2023 at 3:14 PM Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > On Wed, Sep 27, 2023 at 03:19:16AM +0000, Justin Stitt wrote:
> > > Note that folks really shouldn't be using get_maintainer on tree files
> > > anyways [1].
> >
> > That's not true, Linus and I use it on a daily basis this way, it's part
> > of our normal workflow, AND the workflow of the kernel security team.
> >
> > So please don't take that valid use-case away from us.
> 
> Fair. I'm on the side of keeping the "K:'' behavior the way it is and
> that's why I'm proposing adding "D:" to provide a more granular
> content matching type operating strictly on patches. It's purely
> opt-in.
> 
> The patch I linked mentioned steering folks away from using
> tree files but not necessarily removing the behavior.

Please don't steer folks away from it, it is a valid use case of the
tool, and I would argue, one of the most important ones given how often
I use it that way.

Hence my objection to this verbage in the changelog, it's not correct.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/3] get_maintainer: add patch-only keyword matching
  2023-09-27  3:19 [PATCH 0/3] get_maintainer: add patch-only keyword matching Justin Stitt
                   ` (2 preceding siblings ...)
  2023-09-27  3:19 ` [PATCH 3/3] get_maintainer: add patch-only pattern matching type Justin Stitt
@ 2023-09-27 15:24 ` Nick Desaulniers
  2023-09-27 16:01   ` Kees Cook
  3 siblings, 1 reply; 16+ messages in thread
From: Nick Desaulniers @ 2023-09-27 15:24 UTC (permalink / raw)
  To: Justin Stitt
  Cc: Joe Perches, linux-kernel, Kees Cook, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Tue, Sep 26, 2023 at 8:19 PM Justin Stitt <justinstitt@google.com> wrote:
>
> This series aims to add "D:" which behaves exactly the same as "K:" but
> works only on patch files.
>
> The goal of this is to reduce noise when folks use get_maintainer on
> tree files as opposed to patches. This use case should be steered away
> from [1] but "D:" should help maintainers reduce noise in their inboxes
> regardless, especially when matching omnipresent keywords like [2]. In
> the event of [2] Kees would be to/cc'd from folks running get_maintainer
> on _any_ file containing "__counted_by". The number of these files is
> rising and I fear for his inbox as his goal, as I understand it, is to
> simply monitor the introduction of new __counted_by annotations to
> ensure accurate semantics.

Something like this (whether this series or a different approach)
would be helpful to me as well; we use K: to get cc'ed on patches
mentioning clang or llvm, but our ML also then ends up getting cc'ed
on every follow up patch to most files.

This is causing excessive posts on our ML. As a result, it's a
struggle to get folks to cc themselves to the ML, which puts the code
review burden on fewer people.

Whether it's a new D: or refinement to the behavior of K:, I applaud
the effort.  Hopefully we can find an approach that works for
everyone.

And may God have mercy on your soul for having to touch that much perl. :-P

>
> See [3/3] for an illustrative example.
>
> This series also includes a formatting pass over get_maintainer because
> I personally found it difficult to parse with the human eye.
>
> [1]: https://lore.kernel.org/all/20230726151515.1650519-1-kuba@kernel.org/
> [2]: https://lore.kernel.org/all/20230925172037.work.853-kees@kernel.org/
>
> Signed-off-by: Justin Stitt <justinstitt@google.com>
> ---
> Justin Stitt (3):
>       MAINTAINERS: add documentation for D:
>       get_maintainer: run perltidy
>       get_maintainer: add patch-only pattern matching type
>
>  MAINTAINERS               |    3 +
>  scripts/get_maintainer.pl | 3334 +++++++++++++++++++++++----------------------
>  2 files changed, 1718 insertions(+), 1619 deletions(-)
> ---
> base-commit: 6465e260f48790807eef06b583b38ca9789b6072
> change-id: 20230926-get_maintainer_add_d-07424a814e72
>
> Best regards,
> --
> Justin Stitt <justinstitt@google.com>
>


-- 
Thanks,
~Nick Desaulniers

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/3] get_maintainer: add patch-only keyword matching
  2023-09-27 15:24 ` [PATCH 0/3] get_maintainer: add patch-only keyword matching Nick Desaulniers
@ 2023-09-27 16:01   ` Kees Cook
  0 siblings, 0 replies; 16+ messages in thread
From: Kees Cook @ 2023-09-27 16:01 UTC (permalink / raw)
  To: Nick Desaulniers
  Cc: Justin Stitt, Joe Perches, linux-kernel, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, Sep 27, 2023 at 08:24:58AM -0700, Nick Desaulniers wrote:
> On Tue, Sep 26, 2023 at 8:19 PM Justin Stitt <justinstitt@google.com> wrote:
> >
> > This series aims to add "D:" which behaves exactly the same as "K:" but
> > works only on patch files.
> >
> > The goal of this is to reduce noise when folks use get_maintainer on
> > tree files as opposed to patches. This use case should be steered away
> > from [1] but "D:" should help maintainers reduce noise in their inboxes
> > regardless, especially when matching omnipresent keywords like [2]. In
> > the event of [2] Kees would be to/cc'd from folks running get_maintainer
> > on _any_ file containing "__counted_by". The number of these files is
> > rising and I fear for his inbox as his goal, as I understand it, is to
> > simply monitor the introduction of new __counted_by annotations to
> > ensure accurate semantics.
> 
> Something like this (whether this series or a different approach)
> would be helpful to me as well; we use K: to get cc'ed on patches
> mentioning clang or llvm, but our ML also then ends up getting cc'ed
> on every follow up patch to most files.
> 
> This is causing excessive posts on our ML. As a result, it's a
> struggle to get folks to cc themselves to the ML, which puts the code
> review burden on fewer people.
> 
> Whether it's a new D: or refinement to the behavior of K:, I applaud
> the effort.  Hopefully we can find an approach that works for
> everyone.

Yes, please! I would use this immediately -- there are a bunch of places
where pstore, strings, hardening, etc all want review if certain
functions or structures are changed in a patch, but we're not
maintainers of the files they appear in.

> > Justin Stitt (3):
> >       MAINTAINERS: add documentation for D:
> >       get_maintainer: add patch-only pattern matching type

Can we squash these two changes together, and then likely add some
patches for moving things out of K: ?

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 1/3] MAINTAINERS: add documentation for D:
  2023-09-27  3:19 ` [PATCH 1/3] MAINTAINERS: add documentation for D: Justin Stitt
  2023-09-27  3:27   ` Joe Perches
@ 2023-09-27 16:06   ` Kees Cook
  1 sibling, 0 replies; 16+ messages in thread
From: Kees Cook @ 2023-09-27 16:06 UTC (permalink / raw)
  To: Justin Stitt
  Cc: Joe Perches, linux-kernel, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, Sep 27, 2023 at 03:19:14AM +0000, Justin Stitt wrote:
> Document what "D:" does.
> 
> This is more or less the same as what "K:" does but only works for patch
> files.
> 
> See [3/3] for more info and an illustrative example.
> ---
>  MAINTAINERS | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b19995690904..de68d2c0cf29 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -59,6 +59,9 @@ Descriptions of section entries and preferred order
>  	      matches patches or files that contain one or more of the words
>  	      printk, pr_info or pr_err
>  	   One regex pattern per line.  Multiple K: lines acceptable.
> +  D: *Content regex* (perl extended) pattern match patches only.
> +     Usage same as K:.
> +

The "emphasis" tags here are used when rendering:
https://docs.kernel.org/process/maintainers.html

In this case, I assume "D" is inspired by "Diff", so perhaps reword this
to get a proper emphasis hint, and add additional context:

  D: *Diff content regex* (perl extended) pattern match that applies
     only to patches and not entire files (e.g. when using the
     get_maintainers.pl script).


-- 
Kees Cook

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/3] get_maintainer: add patch-only pattern matching type
  2023-09-27  3:19 ` [PATCH 3/3] get_maintainer: add patch-only pattern matching type Justin Stitt
  2023-09-27  6:14   ` Greg KH
@ 2023-09-27 16:15   ` Kees Cook
  2023-09-27 19:33     ` Joe Perches
  2023-09-27 19:00   ` Joe Perches
  2 siblings, 1 reply; 16+ messages in thread
From: Kees Cook @ 2023-09-27 16:15 UTC (permalink / raw)
  To: Justin Stitt
  Cc: Joe Perches, linux-kernel, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, Sep 27, 2023 at 03:19:16AM +0000, Justin Stitt wrote:
> Add the "D:" type which behaves the same as "K:" but will only match
> content present in a patch file.
> 
> To illustrate:
> 
> Imagine this entry in MAINTAINERS:
> 
> NEW REPUBLIC
> M: Han Solo <hansolo@rebelalliance.co>
> W: https://www.jointheresistance.org
> D: \bstrncpy\b
> 
> Our maintainer, Han, will only be added to the recipients if a patch
> file is passed to get_maintainer (like what b4 does):
> $ ./scripts/get_maintainer.pl 0004-some-change.patch
> 
> If the above patch has a `strncpy` present in the subject, commit log or
> diff then Han will be to/cc'd.
> 
> However, in the event of a file from the tree given like:
> $ ./scripts/get_maintainer.pl ./lib/string.c
> 
> Han will not be noisily to/cc'd (like a K: type would in this
> circumstance)
> 
> Note that folks really shouldn't be using get_maintainer on tree files
> anyways [1].
> 
> [1]: https://lore.kernel.org/all/20230726151515.1650519-1-kuba@kernel.org/

As Greg suggested, please drop the above paragraph and link. Then this
looks good to me.

I would immediately want to send this patch too, so please feel free to
add this to your series (and I bet many other hints on "git grep 'K:.\\b'"
would want to switch from K: to D: too):

diff --git a/MAINTAINERS b/MAINTAINERS
index 5f18c6ba3c3c..830e10866acf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5057,7 +5057,7 @@ F:	Documentation/kbuild/llvm.rst
 F:	include/linux/compiler-clang.h
 F:	scripts/Makefile.clang
 F:	scripts/clang-tools/
-K:	\b(?i:clang|llvm)\b
+D:	\b(?i:clang|llvm)\b
 
 CLK API
 M:	Russell King <linux@armlinux.org.uk>
@@ -8199,7 +8199,7 @@ F:	lib/strcat_kunit.c
 F:	lib/strscpy_kunit.c
 F:	lib/test_fortify/*
 F:	scripts/test_fortify.sh
-K:	\b__NO_FORTIFY\b
+D:	\b__NO_FORTIFY\b
 
 FPGA DFL DRIVERS
 M:	Wu Hao <hao.wu@intel.com>
@@ -11457,9 +11457,9 @@ F:	include/linux/overflow.h
 F:	include/linux/randomize_kstack.h
 F:	kernel/configs/hardening.config
 F:	mm/usercopy.c
-K:	\b(add|choose)_random_kstack_offset\b
-K:	\b__check_(object_size|heap_object)\b
-K:	\b__counted_by\b
+D:	\b(add|choose)_random_kstack_offset\b
+D:	\b__check_(object_size|heap_object)\b
+D:	\b__counted_by\b
 
 KERNEL JANITORS
 L:	kernel-janitors@vger.kernel.org
@@ -17354,7 +17354,7 @@ F:	drivers/acpi/apei/erst.c
 F:	drivers/firmware/efi/efi-pstore.c
 F:	fs/pstore/
 F:	include/linux/pstore*
-K:	\b(pstore|ramoops)
+D:	\b(pstore|ramoops)
 
 PTP HARDWARE CLOCK SUPPORT
 M:	Richard Cochran <richardcochran@gmail.com>
@@ -19302,8 +19302,8 @@ F:	include/uapi/linux/seccomp.h
 F:	kernel/seccomp.c
 F:	tools/testing/selftests/kselftest_harness.h
 F:	tools/testing/selftests/seccomp/*
-K:	\bsecure_computing
-K:	\bTIF_SECCOMP\b
+D:	\bsecure_computing
+D:	\bTIF_SECCOMP\b
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) Broadcom BRCMSTB DRIVER
 M:	Kamal Dasu <kamal.dasu@broadcom.com>

-- 
Kees Cook

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/3] get_maintainer: add patch-only pattern matching type
  2023-09-27  3:19 ` [PATCH 3/3] get_maintainer: add patch-only pattern matching type Justin Stitt
  2023-09-27  6:14   ` Greg KH
  2023-09-27 16:15   ` Kees Cook
@ 2023-09-27 19:00   ` Joe Perches
  2 siblings, 0 replies; 16+ messages in thread
From: Joe Perches @ 2023-09-27 19:00 UTC (permalink / raw)
  To: Justin Stitt
  Cc: linux-kernel, Kees Cook, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, 2023-09-27 at 03:19 +0000, Justin Stitt wrote:
> Add the "D:" type which behaves the same as "K:" but will only match
> content present in a patch file.

Likely it'd be less aggravating just to document
that K: is only for patches and add a !$file test.




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 3/3] get_maintainer: add patch-only pattern matching type
  2023-09-27 16:15   ` Kees Cook
@ 2023-09-27 19:33     ` Joe Perches
  0 siblings, 0 replies; 16+ messages in thread
From: Joe Perches @ 2023-09-27 19:33 UTC (permalink / raw)
  To: Kees Cook, Justin Stitt
  Cc: linux-kernel, Nick Desaulniers, Nathan Chancellor,
	Jakub Kicinski, Krzysztof Kozlowski, geert, gregkh, workflows,
	mario.limonciello

On Wed, 2023-09-27 at 09:15 -0700, Kees Cook wrote:
> On Wed, Sep 27, 2023 at 03:19:16AM +0000, Justin Stitt wrote:
> > Add the "D:" type which behaves the same as "K:" but will only match
> > content present in a patch file.
> > 
> > To illustrate:
> > 
> > Imagine this entry in MAINTAINERS:
> > 
> > NEW REPUBLIC
> > M: Han Solo <hansolo@rebelalliance.co>
> > W: https://www.jointheresistance.org
> > D: \bstrncpy\b
> > 
> > Our maintainer, Han, will only be added to the recipients if a patch
> > file is passed to get_maintainer (like what b4 does):
> > $ ./scripts/get_maintainer.pl 0004-some-change.patch
> > 
> > If the above patch has a `strncpy` present in the subject, commit log or
> > diff then Han will be to/cc'd.
> > 
> > However, in the event of a file from the tree given like:
> > $ ./scripts/get_maintainer.pl ./lib/string.c
> > 
> > Han will not be noisily to/cc'd (like a K: type would in this
> > circumstance)
> > 
> > Note that folks really shouldn't be using get_maintainer on tree files
> > anyways [1].
> > 
> > [1]: https://lore.kernel.org/all/20230726151515.1650519-1-kuba@kernel.org/
> 
> As Greg suggested, please drop the above paragraph and link. Then this
> looks good to me.
> 
> I would immediately want to send this patch too, so please feel free to
> add this to your series (and I bet many other hints on "git grep 'K:.\\b'"
> would want to switch from K: to D: too):
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
[]
> @@ -5057,7 +5057,7 @@ F:	Documentation/kbuild/llvm.rst
>  F:	include/linux/compiler-clang.h
>  F:	scripts/Makefile.clang
>  F:	scripts/clang-tools/
> -K:	\b(?i:clang|llvm)\b
> +D:	\b(?i:clang|llvm)\b

etc...

My assumption is that the K: --file use is just unnecessary
and it'd be better to only use the K: lookup on patches.

(and I've somehow stuffed up the receiving side of my
 email configuration so please ignore any emails to me
 that bounce for a while)


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2023-09-27 19:34 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-27  3:19 [PATCH 0/3] get_maintainer: add patch-only keyword matching Justin Stitt
2023-09-27  3:19 ` [PATCH 1/3] MAINTAINERS: add documentation for D: Justin Stitt
2023-09-27  3:27   ` Joe Perches
2023-09-27  3:30     ` Justin Stitt
2023-09-27 16:06   ` Kees Cook
2023-09-27  3:19 ` [PATCH 2/3] get_maintainer: run perltidy Justin Stitt
2023-09-27  3:26   ` Joe Perches
2023-09-27  3:19 ` [PATCH 3/3] get_maintainer: add patch-only pattern matching type Justin Stitt
2023-09-27  6:14   ` Greg KH
2023-09-27  6:46     ` Justin Stitt
2023-09-27  8:21       ` Greg KH
2023-09-27 16:15   ` Kees Cook
2023-09-27 19:33     ` Joe Perches
2023-09-27 19:00   ` Joe Perches
2023-09-27 15:24 ` [PATCH 0/3] get_maintainer: add patch-only keyword matching Nick Desaulniers
2023-09-27 16:01   ` Kees Cook

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.