18c2ecf20Sopenharmony_ci#!/usr/bin/env perl
28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
38c2ecf20Sopenharmony_ci#
48c2ecf20Sopenharmony_ci# (c) 2007, Joe Perches <joe@perches.com>
58c2ecf20Sopenharmony_ci#           created from checkpatch.pl
68c2ecf20Sopenharmony_ci#
78c2ecf20Sopenharmony_ci# Print selected MAINTAINERS information for
88c2ecf20Sopenharmony_ci# the files modified in a patch or for a file
98c2ecf20Sopenharmony_ci#
108c2ecf20Sopenharmony_ci# usage: perl scripts/get_maintainer.pl [OPTIONS] <patch>
118c2ecf20Sopenharmony_ci#        perl scripts/get_maintainer.pl [OPTIONS] -f <file>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ciuse warnings;
148c2ecf20Sopenharmony_ciuse strict;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cimy $P = $0;
178c2ecf20Sopenharmony_cimy $V = '0.26';
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciuse Getopt::Long qw(:config no_auto_abbrev);
208c2ecf20Sopenharmony_ciuse Cwd;
218c2ecf20Sopenharmony_ciuse File::Find;
228c2ecf20Sopenharmony_ciuse File::Spec::Functions;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cimy $cur_path = fastgetcwd() . '/';
258c2ecf20Sopenharmony_cimy $lk_path = "./";
268c2ecf20Sopenharmony_cimy $email = 1;
278c2ecf20Sopenharmony_cimy $email_usename = 1;
288c2ecf20Sopenharmony_cimy $email_maintainer = 1;
298c2ecf20Sopenharmony_cimy $email_reviewer = 1;
308c2ecf20Sopenharmony_cimy $email_fixes = 1;
318c2ecf20Sopenharmony_cimy $email_list = 1;
328c2ecf20Sopenharmony_cimy $email_moderated_list = 1;
338c2ecf20Sopenharmony_cimy $email_subscriber_list = 0;
348c2ecf20Sopenharmony_cimy $email_git_penguin_chiefs = 0;
358c2ecf20Sopenharmony_cimy $email_git = 0;
368c2ecf20Sopenharmony_cimy $email_git_all_signature_types = 0;
378c2ecf20Sopenharmony_cimy $email_git_blame = 0;
388c2ecf20Sopenharmony_cimy $email_git_blame_signatures = 1;
398c2ecf20Sopenharmony_cimy $email_git_fallback = 1;
408c2ecf20Sopenharmony_cimy $email_git_min_signatures = 1;
418c2ecf20Sopenharmony_cimy $email_git_max_maintainers = 5;
428c2ecf20Sopenharmony_cimy $email_git_min_percent = 5;
438c2ecf20Sopenharmony_cimy $email_git_since = "1-year-ago";
448c2ecf20Sopenharmony_cimy $email_hg_since = "-365";
458c2ecf20Sopenharmony_cimy $interactive = 0;
468c2ecf20Sopenharmony_cimy $email_remove_duplicates = 1;
478c2ecf20Sopenharmony_cimy $email_use_mailmap = 1;
488c2ecf20Sopenharmony_cimy $output_multiline = 1;
498c2ecf20Sopenharmony_cimy $output_separator = ", ";
508c2ecf20Sopenharmony_cimy $output_roles = 0;
518c2ecf20Sopenharmony_cimy $output_rolestats = 1;
528c2ecf20Sopenharmony_cimy $output_section_maxlen = 50;
538c2ecf20Sopenharmony_cimy $scm = 0;
548c2ecf20Sopenharmony_cimy $tree = 1;
558c2ecf20Sopenharmony_cimy $web = 0;
568c2ecf20Sopenharmony_cimy $subsystem = 0;
578c2ecf20Sopenharmony_cimy $status = 0;
588c2ecf20Sopenharmony_cimy $letters = "";
598c2ecf20Sopenharmony_cimy $keywords = 1;
608c2ecf20Sopenharmony_cimy $sections = 0;
618c2ecf20Sopenharmony_cimy $email_file_emails = 0;
628c2ecf20Sopenharmony_cimy $from_filename = 0;
638c2ecf20Sopenharmony_cimy $pattern_depth = 0;
648c2ecf20Sopenharmony_cimy $self_test = undef;
658c2ecf20Sopenharmony_cimy $version = 0;
668c2ecf20Sopenharmony_cimy $help = 0;
678c2ecf20Sopenharmony_cimy $find_maintainer_files = 0;
688c2ecf20Sopenharmony_cimy $maintainer_path;
698c2ecf20Sopenharmony_cimy $vcs_used = 0;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cimy $exit = 0;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cimy @files = ();
748c2ecf20Sopenharmony_cimy @fixes = ();			# If a patch description includes Fixes: lines
758c2ecf20Sopenharmony_cimy @range = ();
768c2ecf20Sopenharmony_cimy @keyword_tvi = ();
778c2ecf20Sopenharmony_cimy @file_emails = ();
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cimy %commit_author_hash;
808c2ecf20Sopenharmony_cimy %commit_signer_hash;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cimy @penguin_chief = ();
838c2ecf20Sopenharmony_cipush(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
848c2ecf20Sopenharmony_ci#Andrew wants in on most everything - 2009/01/14
858c2ecf20Sopenharmony_ci#push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cimy @penguin_chief_names = ();
888c2ecf20Sopenharmony_ciforeach my $chief (@penguin_chief) {
898c2ecf20Sopenharmony_ci    if ($chief =~ m/^(.*):(.*)/) {
908c2ecf20Sopenharmony_ci	my $chief_name = $1;
918c2ecf20Sopenharmony_ci	my $chief_addr = $2;
928c2ecf20Sopenharmony_ci	push(@penguin_chief_names, $chief_name);
938c2ecf20Sopenharmony_ci    }
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_cimy $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci# Signature types of people who are either
988c2ecf20Sopenharmony_ci# 	a) responsible for the code in question, or
998c2ecf20Sopenharmony_ci# 	b) familiar enough with it to give relevant feedback
1008c2ecf20Sopenharmony_cimy @signature_tags = ();
1018c2ecf20Sopenharmony_cipush(@signature_tags, "Signed-off-by:");
1028c2ecf20Sopenharmony_cipush(@signature_tags, "Reviewed-by:");
1038c2ecf20Sopenharmony_cipush(@signature_tags, "Acked-by:");
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cimy $signature_pattern = "\(" . join("|", @signature_tags) . "\)";
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci# rfc822 email address - preloaded methods go here.
1088c2ecf20Sopenharmony_cimy $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
1098c2ecf20Sopenharmony_cimy $rfc822_char = '[\\000-\\377]';
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci# VCS command support: class-like functions and strings
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cimy %VCS_cmds;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cimy %VCS_cmds_git = (
1168c2ecf20Sopenharmony_ci    "execute_cmd" => \&git_execute_cmd,
1178c2ecf20Sopenharmony_ci    "available" => '(which("git") ne "") && (-e ".git")',
1188c2ecf20Sopenharmony_ci    "find_signers_cmd" =>
1198c2ecf20Sopenharmony_ci	"git log --no-color --follow --since=\$email_git_since " .
1208c2ecf20Sopenharmony_ci	    '--numstat --no-merges ' .
1218c2ecf20Sopenharmony_ci	    '--format="GitCommit: %H%n' .
1228c2ecf20Sopenharmony_ci		      'GitAuthor: %an <%ae>%n' .
1238c2ecf20Sopenharmony_ci		      'GitDate: %aD%n' .
1248c2ecf20Sopenharmony_ci		      'GitSubject: %s%n' .
1258c2ecf20Sopenharmony_ci		      '%b%n"' .
1268c2ecf20Sopenharmony_ci	    " -- \$file",
1278c2ecf20Sopenharmony_ci    "find_commit_signers_cmd" =>
1288c2ecf20Sopenharmony_ci	"git log --no-color " .
1298c2ecf20Sopenharmony_ci	    '--numstat ' .
1308c2ecf20Sopenharmony_ci	    '--format="GitCommit: %H%n' .
1318c2ecf20Sopenharmony_ci		      'GitAuthor: %an <%ae>%n' .
1328c2ecf20Sopenharmony_ci		      'GitDate: %aD%n' .
1338c2ecf20Sopenharmony_ci		      'GitSubject: %s%n' .
1348c2ecf20Sopenharmony_ci		      '%b%n"' .
1358c2ecf20Sopenharmony_ci	    " -1 \$commit",
1368c2ecf20Sopenharmony_ci    "find_commit_author_cmd" =>
1378c2ecf20Sopenharmony_ci	"git log --no-color " .
1388c2ecf20Sopenharmony_ci	    '--numstat ' .
1398c2ecf20Sopenharmony_ci	    '--format="GitCommit: %H%n' .
1408c2ecf20Sopenharmony_ci		      'GitAuthor: %an <%ae>%n' .
1418c2ecf20Sopenharmony_ci		      'GitDate: %aD%n' .
1428c2ecf20Sopenharmony_ci		      'GitSubject: %s%n"' .
1438c2ecf20Sopenharmony_ci	    " -1 \$commit",
1448c2ecf20Sopenharmony_ci    "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
1458c2ecf20Sopenharmony_ci    "blame_file_cmd" => "git blame -l \$file",
1468c2ecf20Sopenharmony_ci    "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
1478c2ecf20Sopenharmony_ci    "blame_commit_pattern" => "^([0-9a-f]+) ",
1488c2ecf20Sopenharmony_ci    "author_pattern" => "^GitAuthor: (.*)",
1498c2ecf20Sopenharmony_ci    "subject_pattern" => "^GitSubject: (.*)",
1508c2ecf20Sopenharmony_ci    "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$",
1518c2ecf20Sopenharmony_ci    "file_exists_cmd" => "git ls-files \$file",
1528c2ecf20Sopenharmony_ci    "list_files_cmd" => "git ls-files \$file",
1538c2ecf20Sopenharmony_ci);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cimy %VCS_cmds_hg = (
1568c2ecf20Sopenharmony_ci    "execute_cmd" => \&hg_execute_cmd,
1578c2ecf20Sopenharmony_ci    "available" => '(which("hg") ne "") && (-d ".hg")',
1588c2ecf20Sopenharmony_ci    "find_signers_cmd" =>
1598c2ecf20Sopenharmony_ci	"hg log --date=\$email_hg_since " .
1608c2ecf20Sopenharmony_ci	    "--template='HgCommit: {node}\\n" .
1618c2ecf20Sopenharmony_ci	                "HgAuthor: {author}\\n" .
1628c2ecf20Sopenharmony_ci			"HgSubject: {desc}\\n'" .
1638c2ecf20Sopenharmony_ci	    " -- \$file",
1648c2ecf20Sopenharmony_ci    "find_commit_signers_cmd" =>
1658c2ecf20Sopenharmony_ci	"hg log " .
1668c2ecf20Sopenharmony_ci	    "--template='HgSubject: {desc}\\n'" .
1678c2ecf20Sopenharmony_ci	    " -r \$commit",
1688c2ecf20Sopenharmony_ci    "find_commit_author_cmd" =>
1698c2ecf20Sopenharmony_ci	"hg log " .
1708c2ecf20Sopenharmony_ci	    "--template='HgCommit: {node}\\n" .
1718c2ecf20Sopenharmony_ci		        "HgAuthor: {author}\\n" .
1728c2ecf20Sopenharmony_ci			"HgSubject: {desc|firstline}\\n'" .
1738c2ecf20Sopenharmony_ci	    " -r \$commit",
1748c2ecf20Sopenharmony_ci    "blame_range_cmd" => "",		# not supported
1758c2ecf20Sopenharmony_ci    "blame_file_cmd" => "hg blame -n \$file",
1768c2ecf20Sopenharmony_ci    "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
1778c2ecf20Sopenharmony_ci    "blame_commit_pattern" => "^([ 0-9a-f]+):",
1788c2ecf20Sopenharmony_ci    "author_pattern" => "^HgAuthor: (.*)",
1798c2ecf20Sopenharmony_ci    "subject_pattern" => "^HgSubject: (.*)",
1808c2ecf20Sopenharmony_ci    "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$",
1818c2ecf20Sopenharmony_ci    "file_exists_cmd" => "hg files \$file",
1828c2ecf20Sopenharmony_ci    "list_files_cmd" => "hg manifest -R \$file",
1838c2ecf20Sopenharmony_ci);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cimy $conf = which_conf(".get_maintainer.conf");
1868c2ecf20Sopenharmony_ciif (-f $conf) {
1878c2ecf20Sopenharmony_ci    my @conf_args;
1888c2ecf20Sopenharmony_ci    open(my $conffile, '<', "$conf")
1898c2ecf20Sopenharmony_ci	or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci    while (<$conffile>) {
1928c2ecf20Sopenharmony_ci	my $line = $_;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	$line =~ s/\s*\n?$//g;
1958c2ecf20Sopenharmony_ci	$line =~ s/^\s*//g;
1968c2ecf20Sopenharmony_ci	$line =~ s/\s+/ /g;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	next if ($line =~ m/^\s*#/);
1998c2ecf20Sopenharmony_ci	next if ($line =~ m/^\s*$/);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	my @words = split(" ", $line);
2028c2ecf20Sopenharmony_ci	foreach my $word (@words) {
2038c2ecf20Sopenharmony_ci	    last if ($word =~ m/^#/);
2048c2ecf20Sopenharmony_ci	    push (@conf_args, $word);
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci    }
2078c2ecf20Sopenharmony_ci    close($conffile);
2088c2ecf20Sopenharmony_ci    unshift(@ARGV, @conf_args) if @conf_args;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cimy @ignore_emails = ();
2128c2ecf20Sopenharmony_cimy $ignore_file = which_conf(".get_maintainer.ignore");
2138c2ecf20Sopenharmony_ciif (-f $ignore_file) {
2148c2ecf20Sopenharmony_ci    open(my $ignore, '<', "$ignore_file")
2158c2ecf20Sopenharmony_ci	or warn "$P: Can't find a readable .get_maintainer.ignore file $!\n";
2168c2ecf20Sopenharmony_ci    while (<$ignore>) {
2178c2ecf20Sopenharmony_ci	my $line = $_;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	$line =~ s/\s*\n?$//;
2208c2ecf20Sopenharmony_ci	$line =~ s/^\s*//;
2218c2ecf20Sopenharmony_ci	$line =~ s/\s+$//;
2228c2ecf20Sopenharmony_ci	$line =~ s/#.*$//;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	next if ($line =~ m/^\s*$/);
2258c2ecf20Sopenharmony_ci	if (rfc822_valid($line)) {
2268c2ecf20Sopenharmony_ci	    push(@ignore_emails, $line);
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci    }
2298c2ecf20Sopenharmony_ci    close($ignore);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ciif ($#ARGV > 0) {
2338c2ecf20Sopenharmony_ci    foreach (@ARGV) {
2348c2ecf20Sopenharmony_ci        if ($_ =~ /^-{1,2}self-test(?:=|$)/) {
2358c2ecf20Sopenharmony_ci            die "$P: using --self-test does not allow any other option or argument\n";
2368c2ecf20Sopenharmony_ci        }
2378c2ecf20Sopenharmony_ci    }
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ciif (!GetOptions(
2418c2ecf20Sopenharmony_ci		'email!' => \$email,
2428c2ecf20Sopenharmony_ci		'git!' => \$email_git,
2438c2ecf20Sopenharmony_ci		'git-all-signature-types!' => \$email_git_all_signature_types,
2448c2ecf20Sopenharmony_ci		'git-blame!' => \$email_git_blame,
2458c2ecf20Sopenharmony_ci		'git-blame-signatures!' => \$email_git_blame_signatures,
2468c2ecf20Sopenharmony_ci		'git-fallback!' => \$email_git_fallback,
2478c2ecf20Sopenharmony_ci		'git-chief-penguins!' => \$email_git_penguin_chiefs,
2488c2ecf20Sopenharmony_ci		'git-min-signatures=i' => \$email_git_min_signatures,
2498c2ecf20Sopenharmony_ci		'git-max-maintainers=i' => \$email_git_max_maintainers,
2508c2ecf20Sopenharmony_ci		'git-min-percent=i' => \$email_git_min_percent,
2518c2ecf20Sopenharmony_ci		'git-since=s' => \$email_git_since,
2528c2ecf20Sopenharmony_ci		'hg-since=s' => \$email_hg_since,
2538c2ecf20Sopenharmony_ci		'i|interactive!' => \$interactive,
2548c2ecf20Sopenharmony_ci		'remove-duplicates!' => \$email_remove_duplicates,
2558c2ecf20Sopenharmony_ci		'mailmap!' => \$email_use_mailmap,
2568c2ecf20Sopenharmony_ci		'm!' => \$email_maintainer,
2578c2ecf20Sopenharmony_ci		'r!' => \$email_reviewer,
2588c2ecf20Sopenharmony_ci		'n!' => \$email_usename,
2598c2ecf20Sopenharmony_ci		'l!' => \$email_list,
2608c2ecf20Sopenharmony_ci		'fixes!' => \$email_fixes,
2618c2ecf20Sopenharmony_ci		'moderated!' => \$email_moderated_list,
2628c2ecf20Sopenharmony_ci		's!' => \$email_subscriber_list,
2638c2ecf20Sopenharmony_ci		'multiline!' => \$output_multiline,
2648c2ecf20Sopenharmony_ci		'roles!' => \$output_roles,
2658c2ecf20Sopenharmony_ci		'rolestats!' => \$output_rolestats,
2668c2ecf20Sopenharmony_ci		'separator=s' => \$output_separator,
2678c2ecf20Sopenharmony_ci		'subsystem!' => \$subsystem,
2688c2ecf20Sopenharmony_ci		'status!' => \$status,
2698c2ecf20Sopenharmony_ci		'scm!' => \$scm,
2708c2ecf20Sopenharmony_ci		'tree!' => \$tree,
2718c2ecf20Sopenharmony_ci		'web!' => \$web,
2728c2ecf20Sopenharmony_ci		'letters=s' => \$letters,
2738c2ecf20Sopenharmony_ci		'pattern-depth=i' => \$pattern_depth,
2748c2ecf20Sopenharmony_ci		'k|keywords!' => \$keywords,
2758c2ecf20Sopenharmony_ci		'sections!' => \$sections,
2768c2ecf20Sopenharmony_ci		'fe|file-emails!' => \$email_file_emails,
2778c2ecf20Sopenharmony_ci		'f|file' => \$from_filename,
2788c2ecf20Sopenharmony_ci		'find-maintainer-files' => \$find_maintainer_files,
2798c2ecf20Sopenharmony_ci		'mpath|maintainer-path=s' => \$maintainer_path,
2808c2ecf20Sopenharmony_ci		'self-test:s' => \$self_test,
2818c2ecf20Sopenharmony_ci		'v|version' => \$version,
2828c2ecf20Sopenharmony_ci		'h|help|usage' => \$help,
2838c2ecf20Sopenharmony_ci		)) {
2848c2ecf20Sopenharmony_ci    die "$P: invalid argument - use --help if necessary\n";
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ciif ($help != 0) {
2888c2ecf20Sopenharmony_ci    usage();
2898c2ecf20Sopenharmony_ci    exit 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ciif ($version != 0) {
2938c2ecf20Sopenharmony_ci    print("${P} ${V}\n");
2948c2ecf20Sopenharmony_ci    exit 0;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ciif (defined $self_test) {
2988c2ecf20Sopenharmony_ci    read_all_maintainer_files();
2998c2ecf20Sopenharmony_ci    self_test();
3008c2ecf20Sopenharmony_ci    exit 0;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ciif (-t STDIN && !@ARGV) {
3048c2ecf20Sopenharmony_ci    # We're talking to a terminal, but have no command line arguments.
3058c2ecf20Sopenharmony_ci    die "$P: missing patchfile or -f file - use --help if necessary\n";
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci$output_multiline = 0 if ($output_separator ne ", ");
3098c2ecf20Sopenharmony_ci$output_rolestats = 1 if ($interactive);
3108c2ecf20Sopenharmony_ci$output_roles = 1 if ($output_rolestats);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ciif ($sections || $letters ne "") {
3138c2ecf20Sopenharmony_ci    $sections = 1;
3148c2ecf20Sopenharmony_ci    $email = 0;
3158c2ecf20Sopenharmony_ci    $email_list = 0;
3168c2ecf20Sopenharmony_ci    $scm = 0;
3178c2ecf20Sopenharmony_ci    $status = 0;
3188c2ecf20Sopenharmony_ci    $subsystem = 0;
3198c2ecf20Sopenharmony_ci    $web = 0;
3208c2ecf20Sopenharmony_ci    $keywords = 0;
3218c2ecf20Sopenharmony_ci    $interactive = 0;
3228c2ecf20Sopenharmony_ci} else {
3238c2ecf20Sopenharmony_ci    my $selections = $email + $scm + $status + $subsystem + $web;
3248c2ecf20Sopenharmony_ci    if ($selections == 0) {
3258c2ecf20Sopenharmony_ci	die "$P:  Missing required option: email, scm, status, subsystem or web\n";
3268c2ecf20Sopenharmony_ci    }
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ciif ($email &&
3308c2ecf20Sopenharmony_ci    ($email_maintainer + $email_reviewer +
3318c2ecf20Sopenharmony_ci     $email_list + $email_subscriber_list +
3328c2ecf20Sopenharmony_ci     $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
3338c2ecf20Sopenharmony_ci    die "$P: Please select at least 1 email option\n";
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ciif ($tree && !top_of_kernel_tree($lk_path)) {
3378c2ecf20Sopenharmony_ci    die "$P: The current directory does not appear to be "
3388c2ecf20Sopenharmony_ci	. "a linux kernel source tree.\n";
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci## Read MAINTAINERS for type/value pairs
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cimy @typevalue = ();
3448c2ecf20Sopenharmony_cimy %keyword_hash;
3458c2ecf20Sopenharmony_cimy @mfiles = ();
3468c2ecf20Sopenharmony_cimy @self_test_info = ();
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cisub read_maintainer_file {
3498c2ecf20Sopenharmony_ci    my ($file) = @_;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci    open (my $maint, '<', "$file")
3528c2ecf20Sopenharmony_ci	or die "$P: Can't open MAINTAINERS file '$file': $!\n";
3538c2ecf20Sopenharmony_ci    my $i = 1;
3548c2ecf20Sopenharmony_ci    while (<$maint>) {
3558c2ecf20Sopenharmony_ci	my $line = $_;
3568c2ecf20Sopenharmony_ci	chomp $line;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if ($line =~ m/^([A-Z]):\s*(.*)/) {
3598c2ecf20Sopenharmony_ci	    my $type = $1;
3608c2ecf20Sopenharmony_ci	    my $value = $2;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	    ##Filename pattern matching
3638c2ecf20Sopenharmony_ci	    if ($type eq "F" || $type eq "X") {
3648c2ecf20Sopenharmony_ci		$value =~ s@\.@\\\.@g;       ##Convert . to \.
3658c2ecf20Sopenharmony_ci		$value =~ s/\*/\.\*/g;       ##Convert * to .*
3668c2ecf20Sopenharmony_ci		$value =~ s/\?/\./g;         ##Convert ? to .
3678c2ecf20Sopenharmony_ci		##if pattern is a directory and it lacks a trailing slash, add one
3688c2ecf20Sopenharmony_ci		if ((-d $value)) {
3698c2ecf20Sopenharmony_ci		    $value =~ s@([^/])$@$1/@;
3708c2ecf20Sopenharmony_ci		}
3718c2ecf20Sopenharmony_ci	    } elsif ($type eq "K") {
3728c2ecf20Sopenharmony_ci		$keyword_hash{@typevalue} = $value;
3738c2ecf20Sopenharmony_ci	    }
3748c2ecf20Sopenharmony_ci	    push(@typevalue, "$type:$value");
3758c2ecf20Sopenharmony_ci	} elsif (!(/^\s*$/ || /^\s*\#/)) {
3768c2ecf20Sopenharmony_ci	    push(@typevalue, $line);
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci	if (defined $self_test) {
3798c2ecf20Sopenharmony_ci	    push(@self_test_info, {file=>$file, linenr=>$i, line=>$line});
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci	$i++;
3828c2ecf20Sopenharmony_ci    }
3838c2ecf20Sopenharmony_ci    close($maint);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cisub find_is_maintainer_file {
3878c2ecf20Sopenharmony_ci    my ($file) = $_;
3888c2ecf20Sopenharmony_ci    return if ($file !~ m@/MAINTAINERS$@);
3898c2ecf20Sopenharmony_ci    $file = $File::Find::name;
3908c2ecf20Sopenharmony_ci    return if (! -f $file);
3918c2ecf20Sopenharmony_ci    push(@mfiles, $file);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cisub find_ignore_git {
3958c2ecf20Sopenharmony_ci    return grep { $_ !~ /^\.git$/; } @_;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ciread_all_maintainer_files();
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cisub read_all_maintainer_files {
4018c2ecf20Sopenharmony_ci    my $path = "${lk_path}MAINTAINERS";
4028c2ecf20Sopenharmony_ci    if (defined $maintainer_path) {
4038c2ecf20Sopenharmony_ci	$path = $maintainer_path;
4048c2ecf20Sopenharmony_ci	# Perl Cookbook tilde expansion if necessary
4058c2ecf20Sopenharmony_ci	$path =~ s@^~([^/]*)@ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7])@ex;
4068c2ecf20Sopenharmony_ci    }
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci    if (-d $path) {
4098c2ecf20Sopenharmony_ci	$path .= '/' if ($path !~ m@/$@);
4108c2ecf20Sopenharmony_ci	if ($find_maintainer_files) {
4118c2ecf20Sopenharmony_ci	    find( { wanted => \&find_is_maintainer_file,
4128c2ecf20Sopenharmony_ci		    preprocess => \&find_ignore_git,
4138c2ecf20Sopenharmony_ci		    no_chdir => 1,
4148c2ecf20Sopenharmony_ci		}, "$path");
4158c2ecf20Sopenharmony_ci	} else {
4168c2ecf20Sopenharmony_ci	    opendir(DIR, "$path") or die $!;
4178c2ecf20Sopenharmony_ci	    my @files = readdir(DIR);
4188c2ecf20Sopenharmony_ci	    closedir(DIR);
4198c2ecf20Sopenharmony_ci	    foreach my $file (@files) {
4208c2ecf20Sopenharmony_ci		push(@mfiles, "$path$file") if ($file !~ /^\./);
4218c2ecf20Sopenharmony_ci	    }
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci    } elsif (-f "$path") {
4248c2ecf20Sopenharmony_ci	push(@mfiles, "$path");
4258c2ecf20Sopenharmony_ci    } else {
4268c2ecf20Sopenharmony_ci	die "$P: MAINTAINER file not found '$path'\n";
4278c2ecf20Sopenharmony_ci    }
4288c2ecf20Sopenharmony_ci    die "$P: No MAINTAINER files found in '$path'\n" if (scalar(@mfiles) == 0);
4298c2ecf20Sopenharmony_ci    foreach my $file (@mfiles) {
4308c2ecf20Sopenharmony_ci	read_maintainer_file("$file");
4318c2ecf20Sopenharmony_ci    }
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cisub maintainers_in_file {
4358c2ecf20Sopenharmony_ci    my ($file) = @_;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci    return if ($file =~ m@\bMAINTAINERS$@);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci    if (-f $file && ($email_file_emails || $file =~ /\.yaml$/)) {
4408c2ecf20Sopenharmony_ci	open(my $f, '<', $file)
4418c2ecf20Sopenharmony_ci	    or die "$P: Can't open $file: $!\n";
4428c2ecf20Sopenharmony_ci	my $text = do { local($/) ; <$f> };
4438c2ecf20Sopenharmony_ci	close($f);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	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;
4468c2ecf20Sopenharmony_ci	push(@file_emails, clean_file_emails(@poss_addr));
4478c2ecf20Sopenharmony_ci    }
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci#
4518c2ecf20Sopenharmony_ci# Read mail address map
4528c2ecf20Sopenharmony_ci#
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cimy $mailmap;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ciread_mailmap();
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cisub read_mailmap {
4598c2ecf20Sopenharmony_ci    $mailmap = {
4608c2ecf20Sopenharmony_ci	names => {},
4618c2ecf20Sopenharmony_ci	addresses => {}
4628c2ecf20Sopenharmony_ci    };
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci    return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci    open(my $mailmap_file, '<', "${lk_path}.mailmap")
4678c2ecf20Sopenharmony_ci	or warn "$P: Can't open .mailmap: $!\n";
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci    while (<$mailmap_file>) {
4708c2ecf20Sopenharmony_ci	s/#.*$//; #strip comments
4718c2ecf20Sopenharmony_ci	s/^\s+|\s+$//g; #trim
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	next if (/^\s*$/); #skip empty lines
4748c2ecf20Sopenharmony_ci	#entries have one of the following formats:
4758c2ecf20Sopenharmony_ci	# name1 <mail1>
4768c2ecf20Sopenharmony_ci	# <mail1> <mail2>
4778c2ecf20Sopenharmony_ci	# name1 <mail1> <mail2>
4788c2ecf20Sopenharmony_ci	# name1 <mail1> name2 <mail2>
4798c2ecf20Sopenharmony_ci	# (see man git-shortlog)
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (/^([^<]+)<([^>]+)>$/) {
4828c2ecf20Sopenharmony_ci	    my $real_name = $1;
4838c2ecf20Sopenharmony_ci	    my $address = $2;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	    $real_name =~ s/\s+$//;
4868c2ecf20Sopenharmony_ci	    ($real_name, $address) = parse_email("$real_name <$address>");
4878c2ecf20Sopenharmony_ci	    $mailmap->{names}->{$address} = $real_name;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	} elsif (/^<([^>]+)>\s*<([^>]+)>$/) {
4908c2ecf20Sopenharmony_ci	    my $real_address = $1;
4918c2ecf20Sopenharmony_ci	    my $wrong_address = $2;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	    $mailmap->{addresses}->{$wrong_address} = $real_address;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	} elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/) {
4968c2ecf20Sopenharmony_ci	    my $real_name = $1;
4978c2ecf20Sopenharmony_ci	    my $real_address = $2;
4988c2ecf20Sopenharmony_ci	    my $wrong_address = $3;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	    $real_name =~ s/\s+$//;
5018c2ecf20Sopenharmony_ci	    ($real_name, $real_address) =
5028c2ecf20Sopenharmony_ci		parse_email("$real_name <$real_address>");
5038c2ecf20Sopenharmony_ci	    $mailmap->{names}->{$wrong_address} = $real_name;
5048c2ecf20Sopenharmony_ci	    $mailmap->{addresses}->{$wrong_address} = $real_address;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	} elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^>]+)>$/) {
5078c2ecf20Sopenharmony_ci	    my $real_name = $1;
5088c2ecf20Sopenharmony_ci	    my $real_address = $2;
5098c2ecf20Sopenharmony_ci	    my $wrong_name = $3;
5108c2ecf20Sopenharmony_ci	    my $wrong_address = $4;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	    $real_name =~ s/\s+$//;
5138c2ecf20Sopenharmony_ci	    ($real_name, $real_address) =
5148c2ecf20Sopenharmony_ci		parse_email("$real_name <$real_address>");
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	    $wrong_name =~ s/\s+$//;
5178c2ecf20Sopenharmony_ci	    ($wrong_name, $wrong_address) =
5188c2ecf20Sopenharmony_ci		parse_email("$wrong_name <$wrong_address>");
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	    my $wrong_email = format_email($wrong_name, $wrong_address, 1);
5218c2ecf20Sopenharmony_ci	    $mailmap->{names}->{$wrong_email} = $real_name;
5228c2ecf20Sopenharmony_ci	    $mailmap->{addresses}->{$wrong_email} = $real_address;
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci    }
5258c2ecf20Sopenharmony_ci    close($mailmap_file);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci## use the filenames on the command line or find the filenames in the patchfiles
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ciif (!@ARGV) {
5318c2ecf20Sopenharmony_ci    push(@ARGV, "&STDIN");
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ciforeach my $file (@ARGV) {
5358c2ecf20Sopenharmony_ci    if ($file ne "&STDIN") {
5368c2ecf20Sopenharmony_ci	$file = canonpath($file);
5378c2ecf20Sopenharmony_ci	##if $file is a directory and it lacks a trailing slash, add one
5388c2ecf20Sopenharmony_ci	if ((-d $file)) {
5398c2ecf20Sopenharmony_ci	    $file =~ s@([^/])$@$1/@;
5408c2ecf20Sopenharmony_ci	} elsif (!(-f $file)) {
5418c2ecf20Sopenharmony_ci	    die "$P: file '${file}' not found\n";
5428c2ecf20Sopenharmony_ci	}
5438c2ecf20Sopenharmony_ci    }
5448c2ecf20Sopenharmony_ci    if ($from_filename && (vcs_exists() && !vcs_file_exists($file))) {
5458c2ecf20Sopenharmony_ci	warn "$P: file '$file' not found in version control $!\n";
5468c2ecf20Sopenharmony_ci    }
5478c2ecf20Sopenharmony_ci    if ($from_filename || ($file ne "&STDIN" && vcs_file_exists($file))) {
5488c2ecf20Sopenharmony_ci	$file =~ s/^\Q${cur_path}\E//;	#strip any absolute path
5498c2ecf20Sopenharmony_ci	$file =~ s/^\Q${lk_path}\E//;	#or the path to the lk tree
5508c2ecf20Sopenharmony_ci	push(@files, $file);
5518c2ecf20Sopenharmony_ci	if ($file ne "MAINTAINERS" && -f $file && $keywords) {
5528c2ecf20Sopenharmony_ci	    open(my $f, '<', $file)
5538c2ecf20Sopenharmony_ci		or die "$P: Can't open $file: $!\n";
5548c2ecf20Sopenharmony_ci	    my $text = do { local($/) ; <$f> };
5558c2ecf20Sopenharmony_ci	    close($f);
5568c2ecf20Sopenharmony_ci	    if ($keywords) {
5578c2ecf20Sopenharmony_ci		foreach my $line (keys %keyword_hash) {
5588c2ecf20Sopenharmony_ci		    if ($text =~ m/$keyword_hash{$line}/x) {
5598c2ecf20Sopenharmony_ci			push(@keyword_tvi, $line);
5608c2ecf20Sopenharmony_ci		    }
5618c2ecf20Sopenharmony_ci		}
5628c2ecf20Sopenharmony_ci	    }
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci    } else {
5658c2ecf20Sopenharmony_ci	my $file_cnt = @files;
5668c2ecf20Sopenharmony_ci	my $lastfile;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	open(my $patch, "< $file")
5698c2ecf20Sopenharmony_ci	    or die "$P: Can't open $file: $!\n";
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	# We can check arbitrary information before the patch
5728c2ecf20Sopenharmony_ci	# like the commit message, mail headers, etc...
5738c2ecf20Sopenharmony_ci	# This allows us to match arbitrary keywords against any part
5748c2ecf20Sopenharmony_ci	# of a git format-patch generated file (subject tags, etc...)
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	my $patch_prefix = "";			#Parsing the intro
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	while (<$patch>) {
5798c2ecf20Sopenharmony_ci	    my $patch_line = $_;
5808c2ecf20Sopenharmony_ci	    if (m/^ mode change [0-7]+ => [0-7]+ (\S+)\s*$/) {
5818c2ecf20Sopenharmony_ci		my $filename = $1;
5828c2ecf20Sopenharmony_ci		push(@files, $filename);
5838c2ecf20Sopenharmony_ci	    } elsif (m/^rename (?:from|to) (\S+)\s*$/) {
5848c2ecf20Sopenharmony_ci		my $filename = $1;
5858c2ecf20Sopenharmony_ci		push(@files, $filename);
5868c2ecf20Sopenharmony_ci	    } elsif (m/^diff --git a\/(\S+) b\/(\S+)\s*$/) {
5878c2ecf20Sopenharmony_ci		my $filename1 = $1;
5888c2ecf20Sopenharmony_ci		my $filename2 = $2;
5898c2ecf20Sopenharmony_ci		push(@files, $filename1);
5908c2ecf20Sopenharmony_ci		push(@files, $filename2);
5918c2ecf20Sopenharmony_ci	    } elsif (m/^Fixes:\s+([0-9a-fA-F]{6,40})/) {
5928c2ecf20Sopenharmony_ci		push(@fixes, $1) if ($email_fixes);
5938c2ecf20Sopenharmony_ci	    } elsif (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) {
5948c2ecf20Sopenharmony_ci		my $filename = $1;
5958c2ecf20Sopenharmony_ci		$filename =~ s@^[^/]*/@@;
5968c2ecf20Sopenharmony_ci		$filename =~ s@\n@@;
5978c2ecf20Sopenharmony_ci		$lastfile = $filename;
5988c2ecf20Sopenharmony_ci		push(@files, $filename);
5998c2ecf20Sopenharmony_ci		$patch_prefix = "^[+-].*";	#Now parsing the actual patch
6008c2ecf20Sopenharmony_ci	    } elsif (m/^\@\@ -(\d+),(\d+)/) {
6018c2ecf20Sopenharmony_ci		if ($email_git_blame) {
6028c2ecf20Sopenharmony_ci		    push(@range, "$lastfile:$1:$2");
6038c2ecf20Sopenharmony_ci		}
6048c2ecf20Sopenharmony_ci	    } elsif ($keywords) {
6058c2ecf20Sopenharmony_ci		foreach my $line (keys %keyword_hash) {
6068c2ecf20Sopenharmony_ci		    if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) {
6078c2ecf20Sopenharmony_ci			push(@keyword_tvi, $line);
6088c2ecf20Sopenharmony_ci		    }
6098c2ecf20Sopenharmony_ci		}
6108c2ecf20Sopenharmony_ci	    }
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci	close($patch);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if ($file_cnt == @files) {
6158c2ecf20Sopenharmony_ci	    warn "$P: file '${file}' doesn't appear to be a patch.  "
6168c2ecf20Sopenharmony_ci		. "Add -f to options?\n";
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci	@files = sort_and_uniq(@files);
6198c2ecf20Sopenharmony_ci    }
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci@file_emails = uniq(@file_emails);
6238c2ecf20Sopenharmony_ci@fixes = uniq(@fixes);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cimy %email_hash_name;
6268c2ecf20Sopenharmony_cimy %email_hash_address;
6278c2ecf20Sopenharmony_cimy @email_to = ();
6288c2ecf20Sopenharmony_cimy %hash_list_to;
6298c2ecf20Sopenharmony_cimy @list_to = ();
6308c2ecf20Sopenharmony_cimy @scm = ();
6318c2ecf20Sopenharmony_cimy @web = ();
6328c2ecf20Sopenharmony_cimy @subsystem = ();
6338c2ecf20Sopenharmony_cimy @status = ();
6348c2ecf20Sopenharmony_cimy %deduplicate_name_hash = ();
6358c2ecf20Sopenharmony_cimy %deduplicate_address_hash = ();
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cimy @maintainers = get_maintainers();
6388c2ecf20Sopenharmony_ciif (@maintainers) {
6398c2ecf20Sopenharmony_ci    @maintainers = merge_email(@maintainers);
6408c2ecf20Sopenharmony_ci    output(@maintainers);
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ciif ($scm) {
6448c2ecf20Sopenharmony_ci    @scm = uniq(@scm);
6458c2ecf20Sopenharmony_ci    output(@scm);
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ciif ($status) {
6498c2ecf20Sopenharmony_ci    @status = uniq(@status);
6508c2ecf20Sopenharmony_ci    output(@status);
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ciif ($subsystem) {
6548c2ecf20Sopenharmony_ci    @subsystem = uniq(@subsystem);
6558c2ecf20Sopenharmony_ci    output(@subsystem);
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ciif ($web) {
6598c2ecf20Sopenharmony_ci    @web = uniq(@web);
6608c2ecf20Sopenharmony_ci    output(@web);
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ciexit($exit);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cisub self_test {
6668c2ecf20Sopenharmony_ci    my @lsfiles = ();
6678c2ecf20Sopenharmony_ci    my @good_links = ();
6688c2ecf20Sopenharmony_ci    my @bad_links = ();
6698c2ecf20Sopenharmony_ci    my @section_headers = ();
6708c2ecf20Sopenharmony_ci    my $index = 0;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci    @lsfiles = vcs_list_files($lk_path);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci    for my $x (@self_test_info) {
6758c2ecf20Sopenharmony_ci	$index++;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	## Section header duplication and missing section content
6788c2ecf20Sopenharmony_ci	if (($self_test eq "" || $self_test =~ /\bsections\b/) &&
6798c2ecf20Sopenharmony_ci	    $x->{line} =~ /^\S[^:]/ &&
6808c2ecf20Sopenharmony_ci	    defined $self_test_info[$index] &&
6818c2ecf20Sopenharmony_ci	    $self_test_info[$index]->{line} =~ /^([A-Z]):\s*\S/) {
6828c2ecf20Sopenharmony_ci	    my $has_S = 0;
6838c2ecf20Sopenharmony_ci	    my $has_F = 0;
6848c2ecf20Sopenharmony_ci	    my $has_ML = 0;
6858c2ecf20Sopenharmony_ci	    my $status = "";
6868c2ecf20Sopenharmony_ci	    if (grep(m@^\Q$x->{line}\E@, @section_headers)) {
6878c2ecf20Sopenharmony_ci		print("$x->{file}:$x->{linenr}: warning: duplicate section header\t$x->{line}\n");
6888c2ecf20Sopenharmony_ci	    } else {
6898c2ecf20Sopenharmony_ci		push(@section_headers, $x->{line});
6908c2ecf20Sopenharmony_ci	    }
6918c2ecf20Sopenharmony_ci	    my $nextline = $index;
6928c2ecf20Sopenharmony_ci	    while (defined $self_test_info[$nextline] &&
6938c2ecf20Sopenharmony_ci		   $self_test_info[$nextline]->{line} =~ /^([A-Z]):\s*(\S.*)/) {
6948c2ecf20Sopenharmony_ci		my $type = $1;
6958c2ecf20Sopenharmony_ci		my $value = $2;
6968c2ecf20Sopenharmony_ci		if ($type eq "S") {
6978c2ecf20Sopenharmony_ci		    $has_S = 1;
6988c2ecf20Sopenharmony_ci		    $status = $value;
6998c2ecf20Sopenharmony_ci		} elsif ($type eq "F" || $type eq "N") {
7008c2ecf20Sopenharmony_ci		    $has_F = 1;
7018c2ecf20Sopenharmony_ci		} elsif ($type eq "M" || $type eq "R" || $type eq "L") {
7028c2ecf20Sopenharmony_ci		    $has_ML = 1;
7038c2ecf20Sopenharmony_ci		}
7048c2ecf20Sopenharmony_ci		$nextline++;
7058c2ecf20Sopenharmony_ci	    }
7068c2ecf20Sopenharmony_ci	    if (!$has_ML && $status !~ /orphan|obsolete/i) {
7078c2ecf20Sopenharmony_ci		print("$x->{file}:$x->{linenr}: warning: section without email address\t$x->{line}\n");
7088c2ecf20Sopenharmony_ci	    }
7098c2ecf20Sopenharmony_ci	    if (!$has_S) {
7108c2ecf20Sopenharmony_ci		print("$x->{file}:$x->{linenr}: warning: section without status \t$x->{line}\n");
7118c2ecf20Sopenharmony_ci	    }
7128c2ecf20Sopenharmony_ci	    if (!$has_F) {
7138c2ecf20Sopenharmony_ci		print("$x->{file}:$x->{linenr}: warning: section without file pattern\t$x->{line}\n");
7148c2ecf20Sopenharmony_ci	    }
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	next if ($x->{line} !~ /^([A-Z]):\s*(.*)/);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	my $type = $1;
7208c2ecf20Sopenharmony_ci	my $value = $2;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	## Filename pattern matching
7238c2ecf20Sopenharmony_ci	if (($type eq "F" || $type eq "X") &&
7248c2ecf20Sopenharmony_ci	    ($self_test eq "" || $self_test =~ /\bpatterns\b/)) {
7258c2ecf20Sopenharmony_ci	    $value =~ s@\.@\\\.@g;       ##Convert . to \.
7268c2ecf20Sopenharmony_ci	    $value =~ s/\*/\.\*/g;       ##Convert * to .*
7278c2ecf20Sopenharmony_ci	    $value =~ s/\?/\./g;         ##Convert ? to .
7288c2ecf20Sopenharmony_ci	    ##if pattern is a directory and it lacks a trailing slash, add one
7298c2ecf20Sopenharmony_ci	    if ((-d $value)) {
7308c2ecf20Sopenharmony_ci		$value =~ s@([^/])$@$1/@;
7318c2ecf20Sopenharmony_ci	    }
7328c2ecf20Sopenharmony_ci	    if (!grep(m@^$value@, @lsfiles)) {
7338c2ecf20Sopenharmony_ci		print("$x->{file}:$x->{linenr}: warning: no file matches\t$x->{line}\n");
7348c2ecf20Sopenharmony_ci	    }
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	## Link reachability
7378c2ecf20Sopenharmony_ci	} elsif (($type eq "W" || $type eq "Q" || $type eq "B") &&
7388c2ecf20Sopenharmony_ci		 $value =~ /^https?:/ &&
7398c2ecf20Sopenharmony_ci		 ($self_test eq "" || $self_test =~ /\blinks\b/)) {
7408c2ecf20Sopenharmony_ci	    next if (grep(m@^\Q$value\E$@, @good_links));
7418c2ecf20Sopenharmony_ci	    my $isbad = 0;
7428c2ecf20Sopenharmony_ci	    if (grep(m@^\Q$value\E$@, @bad_links)) {
7438c2ecf20Sopenharmony_ci	        $isbad = 1;
7448c2ecf20Sopenharmony_ci	    } else {
7458c2ecf20Sopenharmony_ci		my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $value`;
7468c2ecf20Sopenharmony_ci		if ($? == 0) {
7478c2ecf20Sopenharmony_ci		    push(@good_links, $value);
7488c2ecf20Sopenharmony_ci		} else {
7498c2ecf20Sopenharmony_ci		    push(@bad_links, $value);
7508c2ecf20Sopenharmony_ci		    $isbad = 1;
7518c2ecf20Sopenharmony_ci		}
7528c2ecf20Sopenharmony_ci	    }
7538c2ecf20Sopenharmony_ci	    if ($isbad) {
7548c2ecf20Sopenharmony_ci	        print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
7558c2ecf20Sopenharmony_ci	    }
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	## SCM reachability
7588c2ecf20Sopenharmony_ci	} elsif ($type eq "T" &&
7598c2ecf20Sopenharmony_ci		 ($self_test eq "" || $self_test =~ /\bscm\b/)) {
7608c2ecf20Sopenharmony_ci	    next if (grep(m@^\Q$value\E$@, @good_links));
7618c2ecf20Sopenharmony_ci	    my $isbad = 0;
7628c2ecf20Sopenharmony_ci	    if (grep(m@^\Q$value\E$@, @bad_links)) {
7638c2ecf20Sopenharmony_ci	        $isbad = 1;
7648c2ecf20Sopenharmony_ci            } elsif ($value !~ /^(?:git|quilt|hg)\s+\S/) {
7658c2ecf20Sopenharmony_ci		print("$x->{file}:$x->{linenr}: warning: malformed entry\t$x->{line}\n");
7668c2ecf20Sopenharmony_ci	    } elsif ($value =~ /^git\s+(\S+)(\s+([^\(]+\S+))?/) {
7678c2ecf20Sopenharmony_ci		my $url = $1;
7688c2ecf20Sopenharmony_ci		my $branch = "";
7698c2ecf20Sopenharmony_ci		$branch = $3 if $3;
7708c2ecf20Sopenharmony_ci		my $output = `git ls-remote --exit-code -h "$url" $branch > /dev/null 2>&1`;
7718c2ecf20Sopenharmony_ci		if ($? == 0) {
7728c2ecf20Sopenharmony_ci		    push(@good_links, $value);
7738c2ecf20Sopenharmony_ci		} else {
7748c2ecf20Sopenharmony_ci		    push(@bad_links, $value);
7758c2ecf20Sopenharmony_ci		    $isbad = 1;
7768c2ecf20Sopenharmony_ci		}
7778c2ecf20Sopenharmony_ci	    } elsif ($value =~ /^(?:quilt|hg)\s+(https?:\S+)/) {
7788c2ecf20Sopenharmony_ci		my $url = $1;
7798c2ecf20Sopenharmony_ci		my $output = `wget --spider -q --no-check-certificate --timeout 10 --tries 1 $url`;
7808c2ecf20Sopenharmony_ci		if ($? == 0) {
7818c2ecf20Sopenharmony_ci		    push(@good_links, $value);
7828c2ecf20Sopenharmony_ci		} else {
7838c2ecf20Sopenharmony_ci		    push(@bad_links, $value);
7848c2ecf20Sopenharmony_ci		    $isbad = 1;
7858c2ecf20Sopenharmony_ci		}
7868c2ecf20Sopenharmony_ci	    }
7878c2ecf20Sopenharmony_ci	    if ($isbad) {
7888c2ecf20Sopenharmony_ci		print("$x->{file}:$x->{linenr}: warning: possible bad link\t$x->{line}\n");
7898c2ecf20Sopenharmony_ci	    }
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci    }
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_cisub ignore_email_address {
7958c2ecf20Sopenharmony_ci    my ($address) = @_;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci    foreach my $ignore (@ignore_emails) {
7988c2ecf20Sopenharmony_ci	return 1 if ($ignore eq $address);
7998c2ecf20Sopenharmony_ci    }
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci    return 0;
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cisub range_is_maintained {
8058c2ecf20Sopenharmony_ci    my ($start, $end) = @_;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci    for (my $i = $start; $i < $end; $i++) {
8088c2ecf20Sopenharmony_ci	my $line = $typevalue[$i];
8098c2ecf20Sopenharmony_ci	if ($line =~ m/^([A-Z]):\s*(.*)/) {
8108c2ecf20Sopenharmony_ci	    my $type = $1;
8118c2ecf20Sopenharmony_ci	    my $value = $2;
8128c2ecf20Sopenharmony_ci	    if ($type eq 'S') {
8138c2ecf20Sopenharmony_ci		if ($value =~ /(maintain|support)/i) {
8148c2ecf20Sopenharmony_ci		    return 1;
8158c2ecf20Sopenharmony_ci		}
8168c2ecf20Sopenharmony_ci	    }
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci    }
8198c2ecf20Sopenharmony_ci    return 0;
8208c2ecf20Sopenharmony_ci}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_cisub range_has_maintainer {
8238c2ecf20Sopenharmony_ci    my ($start, $end) = @_;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci    for (my $i = $start; $i < $end; $i++) {
8268c2ecf20Sopenharmony_ci	my $line = $typevalue[$i];
8278c2ecf20Sopenharmony_ci	if ($line =~ m/^([A-Z]):\s*(.*)/) {
8288c2ecf20Sopenharmony_ci	    my $type = $1;
8298c2ecf20Sopenharmony_ci	    my $value = $2;
8308c2ecf20Sopenharmony_ci	    if ($type eq 'M') {
8318c2ecf20Sopenharmony_ci		return 1;
8328c2ecf20Sopenharmony_ci	    }
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci    }
8358c2ecf20Sopenharmony_ci    return 0;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cisub get_maintainers {
8398c2ecf20Sopenharmony_ci    %email_hash_name = ();
8408c2ecf20Sopenharmony_ci    %email_hash_address = ();
8418c2ecf20Sopenharmony_ci    %commit_author_hash = ();
8428c2ecf20Sopenharmony_ci    %commit_signer_hash = ();
8438c2ecf20Sopenharmony_ci    @email_to = ();
8448c2ecf20Sopenharmony_ci    %hash_list_to = ();
8458c2ecf20Sopenharmony_ci    @list_to = ();
8468c2ecf20Sopenharmony_ci    @scm = ();
8478c2ecf20Sopenharmony_ci    @web = ();
8488c2ecf20Sopenharmony_ci    @subsystem = ();
8498c2ecf20Sopenharmony_ci    @status = ();
8508c2ecf20Sopenharmony_ci    %deduplicate_name_hash = ();
8518c2ecf20Sopenharmony_ci    %deduplicate_address_hash = ();
8528c2ecf20Sopenharmony_ci    if ($email_git_all_signature_types) {
8538c2ecf20Sopenharmony_ci	$signature_pattern = "(.+?)[Bb][Yy]:";
8548c2ecf20Sopenharmony_ci    } else {
8558c2ecf20Sopenharmony_ci	$signature_pattern = "\(" . join("|", @signature_tags) . "\)";
8568c2ecf20Sopenharmony_ci    }
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci    # Find responsible parties
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci    my %exact_pattern_match_hash = ();
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci    foreach my $file (@files) {
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	my %hash;
8658c2ecf20Sopenharmony_ci	my $tvi = find_first_section();
8668c2ecf20Sopenharmony_ci	while ($tvi < @typevalue) {
8678c2ecf20Sopenharmony_ci	    my $start = find_starting_index($tvi);
8688c2ecf20Sopenharmony_ci	    my $end = find_ending_index($tvi);
8698c2ecf20Sopenharmony_ci	    my $exclude = 0;
8708c2ecf20Sopenharmony_ci	    my $i;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	    #Do not match excluded file patterns
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	    for ($i = $start; $i < $end; $i++) {
8758c2ecf20Sopenharmony_ci		my $line = $typevalue[$i];
8768c2ecf20Sopenharmony_ci		if ($line =~ m/^([A-Z]):\s*(.*)/) {
8778c2ecf20Sopenharmony_ci		    my $type = $1;
8788c2ecf20Sopenharmony_ci		    my $value = $2;
8798c2ecf20Sopenharmony_ci		    if ($type eq 'X') {
8808c2ecf20Sopenharmony_ci			if (file_match_pattern($file, $value)) {
8818c2ecf20Sopenharmony_ci			    $exclude = 1;
8828c2ecf20Sopenharmony_ci			    last;
8838c2ecf20Sopenharmony_ci			}
8848c2ecf20Sopenharmony_ci		    }
8858c2ecf20Sopenharmony_ci		}
8868c2ecf20Sopenharmony_ci	    }
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	    if (!$exclude) {
8898c2ecf20Sopenharmony_ci		for ($i = $start; $i < $end; $i++) {
8908c2ecf20Sopenharmony_ci		    my $line = $typevalue[$i];
8918c2ecf20Sopenharmony_ci		    if ($line =~ m/^([A-Z]):\s*(.*)/) {
8928c2ecf20Sopenharmony_ci			my $type = $1;
8938c2ecf20Sopenharmony_ci			my $value = $2;
8948c2ecf20Sopenharmony_ci			if ($type eq 'F') {
8958c2ecf20Sopenharmony_ci			    if (file_match_pattern($file, $value)) {
8968c2ecf20Sopenharmony_ci				my $value_pd = ($value =~ tr@/@@);
8978c2ecf20Sopenharmony_ci				my $file_pd = ($file  =~ tr@/@@);
8988c2ecf20Sopenharmony_ci				$value_pd++ if (substr($value,-1,1) ne "/");
8998c2ecf20Sopenharmony_ci				$value_pd = -1 if ($value =~ /^\.\*/);
9008c2ecf20Sopenharmony_ci				if ($value_pd >= $file_pd &&
9018c2ecf20Sopenharmony_ci				    range_is_maintained($start, $end) &&
9028c2ecf20Sopenharmony_ci				    range_has_maintainer($start, $end)) {
9038c2ecf20Sopenharmony_ci				    $exact_pattern_match_hash{$file} = 1;
9048c2ecf20Sopenharmony_ci				}
9058c2ecf20Sopenharmony_ci				if ($pattern_depth == 0 ||
9068c2ecf20Sopenharmony_ci				    (($file_pd - $value_pd) < $pattern_depth)) {
9078c2ecf20Sopenharmony_ci				    $hash{$tvi} = $value_pd;
9088c2ecf20Sopenharmony_ci				}
9098c2ecf20Sopenharmony_ci			    }
9108c2ecf20Sopenharmony_ci			} elsif ($type eq 'N') {
9118c2ecf20Sopenharmony_ci			    if ($file =~ m/$value/x) {
9128c2ecf20Sopenharmony_ci				$hash{$tvi} = 0;
9138c2ecf20Sopenharmony_ci			    }
9148c2ecf20Sopenharmony_ci			}
9158c2ecf20Sopenharmony_ci		    }
9168c2ecf20Sopenharmony_ci		}
9178c2ecf20Sopenharmony_ci	    }
9188c2ecf20Sopenharmony_ci	    $tvi = $end + 1;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
9228c2ecf20Sopenharmony_ci	    add_categories($line);
9238c2ecf20Sopenharmony_ci	    if ($sections) {
9248c2ecf20Sopenharmony_ci		my $i;
9258c2ecf20Sopenharmony_ci		my $start = find_starting_index($line);
9268c2ecf20Sopenharmony_ci		my $end = find_ending_index($line);
9278c2ecf20Sopenharmony_ci		for ($i = $start; $i < $end; $i++) {
9288c2ecf20Sopenharmony_ci		    my $line = $typevalue[$i];
9298c2ecf20Sopenharmony_ci		    if ($line =~ /^[FX]:/) {		##Restore file patterns
9308c2ecf20Sopenharmony_ci			$line =~ s/([^\\])\.([^\*])/$1\?$2/g;
9318c2ecf20Sopenharmony_ci			$line =~ s/([^\\])\.$/$1\?/g;	##Convert . back to ?
9328c2ecf20Sopenharmony_ci			$line =~ s/\\\./\./g;       	##Convert \. to .
9338c2ecf20Sopenharmony_ci			$line =~ s/\.\*/\*/g;       	##Convert .* to *
9348c2ecf20Sopenharmony_ci		    }
9358c2ecf20Sopenharmony_ci		    my $count = $line =~ s/^([A-Z]):/$1:\t/g;
9368c2ecf20Sopenharmony_ci		    if ($letters eq "" || (!$count || $letters =~ /$1/i)) {
9378c2ecf20Sopenharmony_ci			print("$line\n");
9388c2ecf20Sopenharmony_ci		    }
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci		print("\n");
9418c2ecf20Sopenharmony_ci	    }
9428c2ecf20Sopenharmony_ci	}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	maintainers_in_file($file);
9458c2ecf20Sopenharmony_ci    }
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci    if ($keywords) {
9488c2ecf20Sopenharmony_ci	@keyword_tvi = sort_and_uniq(@keyword_tvi);
9498c2ecf20Sopenharmony_ci	foreach my $line (@keyword_tvi) {
9508c2ecf20Sopenharmony_ci	    add_categories($line);
9518c2ecf20Sopenharmony_ci	}
9528c2ecf20Sopenharmony_ci    }
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci    foreach my $email (@email_to, @list_to) {
9558c2ecf20Sopenharmony_ci	$email->[0] = deduplicate_email($email->[0]);
9568c2ecf20Sopenharmony_ci    }
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci    foreach my $file (@files) {
9598c2ecf20Sopenharmony_ci	if ($email &&
9608c2ecf20Sopenharmony_ci	    ($email_git ||
9618c2ecf20Sopenharmony_ci	     ($email_git_fallback &&
9628c2ecf20Sopenharmony_ci	      $file !~ /MAINTAINERS$/ &&
9638c2ecf20Sopenharmony_ci	      !$exact_pattern_match_hash{$file}))) {
9648c2ecf20Sopenharmony_ci	    vcs_file_signoffs($file);
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci	if ($email && $email_git_blame) {
9678c2ecf20Sopenharmony_ci	    vcs_file_blame($file);
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci    }
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci    if ($email) {
9728c2ecf20Sopenharmony_ci	foreach my $chief (@penguin_chief) {
9738c2ecf20Sopenharmony_ci	    if ($chief =~ m/^(.*):(.*)/) {
9748c2ecf20Sopenharmony_ci		my $email_address;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci		$email_address = format_email($1, $2, $email_usename);
9778c2ecf20Sopenharmony_ci		if ($email_git_penguin_chiefs) {
9788c2ecf20Sopenharmony_ci		    push(@email_to, [$email_address, 'chief penguin']);
9798c2ecf20Sopenharmony_ci		} else {
9808c2ecf20Sopenharmony_ci		    @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
9818c2ecf20Sopenharmony_ci		}
9828c2ecf20Sopenharmony_ci	    }
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	foreach my $email (@file_emails) {
9868c2ecf20Sopenharmony_ci	    my ($name, $address) = parse_email($email);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	    my $tmp_email = format_email($name, $address, $email_usename);
9898c2ecf20Sopenharmony_ci	    push_email_address($tmp_email, '');
9908c2ecf20Sopenharmony_ci	    add_role($tmp_email, 'in file');
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci    }
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci    foreach my $fix (@fixes) {
9958c2ecf20Sopenharmony_ci	vcs_add_commit_signers($fix, "blamed_fixes");
9968c2ecf20Sopenharmony_ci    }
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci    my @to = ();
9998c2ecf20Sopenharmony_ci    if ($email || $email_list) {
10008c2ecf20Sopenharmony_ci	if ($email) {
10018c2ecf20Sopenharmony_ci	    @to = (@to, @email_to);
10028c2ecf20Sopenharmony_ci	}
10038c2ecf20Sopenharmony_ci	if ($email_list) {
10048c2ecf20Sopenharmony_ci	    @to = (@to, @list_to);
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci    }
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci    if ($interactive) {
10098c2ecf20Sopenharmony_ci	@to = interactive_get_maintainers(\@to);
10108c2ecf20Sopenharmony_ci    }
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci    return @to;
10138c2ecf20Sopenharmony_ci}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_cisub file_match_pattern {
10168c2ecf20Sopenharmony_ci    my ($file, $pattern) = @_;
10178c2ecf20Sopenharmony_ci    if (substr($pattern, -1) eq "/") {
10188c2ecf20Sopenharmony_ci	if ($file =~ m@^$pattern@) {
10198c2ecf20Sopenharmony_ci	    return 1;
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci    } else {
10228c2ecf20Sopenharmony_ci	if ($file =~ m@^$pattern@) {
10238c2ecf20Sopenharmony_ci	    my $s1 = ($file =~ tr@/@@);
10248c2ecf20Sopenharmony_ci	    my $s2 = ($pattern =~ tr@/@@);
10258c2ecf20Sopenharmony_ci	    if ($s1 == $s2) {
10268c2ecf20Sopenharmony_ci		return 1;
10278c2ecf20Sopenharmony_ci	    }
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci    }
10308c2ecf20Sopenharmony_ci    return 0;
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_cisub usage {
10348c2ecf20Sopenharmony_ci    print <<EOT;
10358c2ecf20Sopenharmony_ciusage: $P [options] patchfile
10368c2ecf20Sopenharmony_ci       $P [options] -f file|directory
10378c2ecf20Sopenharmony_civersion: $V
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ciMAINTAINER field selection options:
10408c2ecf20Sopenharmony_ci  --email => print email address(es) if any
10418c2ecf20Sopenharmony_ci    --git => include recent git \*-by: signers
10428c2ecf20Sopenharmony_ci    --git-all-signature-types => include signers regardless of signature type
10438c2ecf20Sopenharmony_ci        or use only ${signature_pattern} signers (default: $email_git_all_signature_types)
10448c2ecf20Sopenharmony_ci    --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback)
10458c2ecf20Sopenharmony_ci    --git-chief-penguins => include ${penguin_chiefs}
10468c2ecf20Sopenharmony_ci    --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
10478c2ecf20Sopenharmony_ci    --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
10488c2ecf20Sopenharmony_ci    --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent)
10498c2ecf20Sopenharmony_ci    --git-blame => use git blame to find modified commits for patch or file
10508c2ecf20Sopenharmony_ci    --git-blame-signatures => when used with --git-blame, also include all commit signers
10518c2ecf20Sopenharmony_ci    --git-since => git history to use (default: $email_git_since)
10528c2ecf20Sopenharmony_ci    --hg-since => hg history to use (default: $email_hg_since)
10538c2ecf20Sopenharmony_ci    --interactive => display a menu (mostly useful if used with the --git option)
10548c2ecf20Sopenharmony_ci    --m => include maintainer(s) if any
10558c2ecf20Sopenharmony_ci    --r => include reviewer(s) if any
10568c2ecf20Sopenharmony_ci    --n => include name 'Full Name <addr\@domain.tld>'
10578c2ecf20Sopenharmony_ci    --l => include list(s) if any
10588c2ecf20Sopenharmony_ci    --moderated => include moderated lists(s) if any (default: true)
10598c2ecf20Sopenharmony_ci    --s => include subscriber only list(s) if any (default: false)
10608c2ecf20Sopenharmony_ci    --remove-duplicates => minimize duplicate email names/addresses
10618c2ecf20Sopenharmony_ci    --roles => show roles (status:subsystem, git-signer, list, etc...)
10628c2ecf20Sopenharmony_ci    --rolestats => show roles and statistics (commits/total_commits, %)
10638c2ecf20Sopenharmony_ci    --file-emails => add email addresses found in -f file (default: 0 (off))
10648c2ecf20Sopenharmony_ci    --fixes => for patches, add signatures of commits with 'Fixes: <commit>' (default: 1 (on))
10658c2ecf20Sopenharmony_ci  --scm => print SCM tree(s) if any
10668c2ecf20Sopenharmony_ci  --status => print status if any
10678c2ecf20Sopenharmony_ci  --subsystem => print subsystem name if any
10688c2ecf20Sopenharmony_ci  --web => print website(s) if any
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ciOutput type options:
10718c2ecf20Sopenharmony_ci  --separator [, ] => separator for multiple entries on 1 line
10728c2ecf20Sopenharmony_ci    using --separator also sets --nomultiline if --separator is not [, ]
10738c2ecf20Sopenharmony_ci  --multiline => print 1 entry per line
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ciOther options:
10768c2ecf20Sopenharmony_ci  --pattern-depth => Number of pattern directory traversals (default: 0 (all))
10778c2ecf20Sopenharmony_ci  --keywords => scan patch for keywords (default: $keywords)
10788c2ecf20Sopenharmony_ci  --sections => print all of the subsystem sections with pattern matches
10798c2ecf20Sopenharmony_ci  --letters => print all matching 'letter' types from all matching sections
10808c2ecf20Sopenharmony_ci  --mailmap => use .mailmap file (default: $email_use_mailmap)
10818c2ecf20Sopenharmony_ci  --no-tree => run without a kernel tree
10828c2ecf20Sopenharmony_ci  --self-test => show potential issues with MAINTAINERS file content
10838c2ecf20Sopenharmony_ci  --version => show version
10848c2ecf20Sopenharmony_ci  --help => show this help information
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ciDefault options:
10878c2ecf20Sopenharmony_ci  [--email --tree --nogit --git-fallback --m --r --n --l --multiline
10888c2ecf20Sopenharmony_ci   --pattern-depth=0 --remove-duplicates --rolestats]
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ciNotes:
10918c2ecf20Sopenharmony_ci  Using "-f directory" may give unexpected results:
10928c2ecf20Sopenharmony_ci      Used with "--git", git signators for _all_ files in and below
10938c2ecf20Sopenharmony_ci          directory are examined as git recurses directories.
10948c2ecf20Sopenharmony_ci          Any specified X: (exclude) pattern matches are _not_ ignored.
10958c2ecf20Sopenharmony_ci      Used with "--nogit", directory is used as a pattern match,
10968c2ecf20Sopenharmony_ci          no individual file within the directory or subdirectory
10978c2ecf20Sopenharmony_ci          is matched.
10988c2ecf20Sopenharmony_ci      Used with "--git-blame", does not iterate all files in directory
10998c2ecf20Sopenharmony_ci  Using "--git-blame" is slow and may add old committers and authors
11008c2ecf20Sopenharmony_ci      that are no longer active maintainers to the output.
11018c2ecf20Sopenharmony_ci  Using "--roles" or "--rolestats" with git send-email --cc-cmd or any
11028c2ecf20Sopenharmony_ci      other automated tools that expect only ["name"] <email address>
11038c2ecf20Sopenharmony_ci      may not work because of additional output after <email address>.
11048c2ecf20Sopenharmony_ci  Using "--rolestats" and "--git-blame" shows the #/total=% commits,
11058c2ecf20Sopenharmony_ci      not the percentage of the entire file authored.  # of commits is
11068c2ecf20Sopenharmony_ci      not a good measure of amount of code authored.  1 major commit may
11078c2ecf20Sopenharmony_ci      contain a thousand lines, 5 trivial commits may modify a single line.
11088c2ecf20Sopenharmony_ci  If git is not installed, but mercurial (hg) is installed and an .hg
11098c2ecf20Sopenharmony_ci      repository exists, the following options apply to mercurial:
11108c2ecf20Sopenharmony_ci          --git,
11118c2ecf20Sopenharmony_ci          --git-min-signatures, --git-max-maintainers, --git-min-percent, and
11128c2ecf20Sopenharmony_ci          --git-blame
11138c2ecf20Sopenharmony_ci      Use --hg-since not --git-since to control date selection
11148c2ecf20Sopenharmony_ci  File ".get_maintainer.conf", if it exists in the linux kernel source root
11158c2ecf20Sopenharmony_ci      directory, can change whatever get_maintainer defaults are desired.
11168c2ecf20Sopenharmony_ci      Entries in this file can be any command line argument.
11178c2ecf20Sopenharmony_ci      This file is prepended to any additional command line arguments.
11188c2ecf20Sopenharmony_ci      Multiple lines and # comments are allowed.
11198c2ecf20Sopenharmony_ci  Most options have both positive and negative forms.
11208c2ecf20Sopenharmony_ci      The negative forms for --<foo> are --no<foo> and --no-<foo>.
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ciEOT
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cisub top_of_kernel_tree {
11268c2ecf20Sopenharmony_ci    my ($lk_path) = @_;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci    if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
11298c2ecf20Sopenharmony_ci	$lk_path .= "/";
11308c2ecf20Sopenharmony_ci    }
11318c2ecf20Sopenharmony_ci    if (   (-f "${lk_path}COPYING")
11328c2ecf20Sopenharmony_ci	&& (-f "${lk_path}CREDITS")
11338c2ecf20Sopenharmony_ci	&& (-f "${lk_path}Kbuild")
11348c2ecf20Sopenharmony_ci	&& (-e "${lk_path}MAINTAINERS")
11358c2ecf20Sopenharmony_ci	&& (-f "${lk_path}Makefile")
11368c2ecf20Sopenharmony_ci	&& (-f "${lk_path}README")
11378c2ecf20Sopenharmony_ci	&& (-d "${lk_path}Documentation")
11388c2ecf20Sopenharmony_ci	&& (-d "${lk_path}arch")
11398c2ecf20Sopenharmony_ci	&& (-d "${lk_path}include")
11408c2ecf20Sopenharmony_ci	&& (-d "${lk_path}drivers")
11418c2ecf20Sopenharmony_ci	&& (-d "${lk_path}fs")
11428c2ecf20Sopenharmony_ci	&& (-d "${lk_path}init")
11438c2ecf20Sopenharmony_ci	&& (-d "${lk_path}ipc")
11448c2ecf20Sopenharmony_ci	&& (-d "${lk_path}kernel")
11458c2ecf20Sopenharmony_ci	&& (-d "${lk_path}lib")
11468c2ecf20Sopenharmony_ci	&& (-d "${lk_path}scripts")) {
11478c2ecf20Sopenharmony_ci	return 1;
11488c2ecf20Sopenharmony_ci    }
11498c2ecf20Sopenharmony_ci    return 0;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cisub parse_email {
11538c2ecf20Sopenharmony_ci    my ($formatted_email) = @_;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci    my $name = "";
11568c2ecf20Sopenharmony_ci    my $address = "";
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci    if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) {
11598c2ecf20Sopenharmony_ci	$name = $1;
11608c2ecf20Sopenharmony_ci	$address = $2;
11618c2ecf20Sopenharmony_ci    } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) {
11628c2ecf20Sopenharmony_ci	$address = $1;
11638c2ecf20Sopenharmony_ci    } elsif ($formatted_email =~ /^(.+\@\S*).*$/) {
11648c2ecf20Sopenharmony_ci	$address = $1;
11658c2ecf20Sopenharmony_ci    }
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci    $name =~ s/^\s+|\s+$//g;
11688c2ecf20Sopenharmony_ci    $name =~ s/^\"|\"$//g;
11698c2ecf20Sopenharmony_ci    $address =~ s/^\s+|\s+$//g;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci    if ($name =~ /[^\w \-]/i) {  	 ##has "must quote" chars
11728c2ecf20Sopenharmony_ci	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
11738c2ecf20Sopenharmony_ci	$name = "\"$name\"";
11748c2ecf20Sopenharmony_ci    }
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci    return ($name, $address);
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cisub format_email {
11808c2ecf20Sopenharmony_ci    my ($name, $address, $usename) = @_;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci    my $formatted_email;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci    $name =~ s/^\s+|\s+$//g;
11858c2ecf20Sopenharmony_ci    $name =~ s/^\"|\"$//g;
11868c2ecf20Sopenharmony_ci    $address =~ s/^\s+|\s+$//g;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci    if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
11898c2ecf20Sopenharmony_ci	$name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
11908c2ecf20Sopenharmony_ci	$name = "\"$name\"";
11918c2ecf20Sopenharmony_ci    }
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci    if ($usename) {
11948c2ecf20Sopenharmony_ci	if ("$name" eq "") {
11958c2ecf20Sopenharmony_ci	    $formatted_email = "$address";
11968c2ecf20Sopenharmony_ci	} else {
11978c2ecf20Sopenharmony_ci	    $formatted_email = "$name <$address>";
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci    } else {
12008c2ecf20Sopenharmony_ci	$formatted_email = $address;
12018c2ecf20Sopenharmony_ci    }
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci    return $formatted_email;
12048c2ecf20Sopenharmony_ci}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_cisub find_first_section {
12078c2ecf20Sopenharmony_ci    my $index = 0;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci    while ($index < @typevalue) {
12108c2ecf20Sopenharmony_ci	my $tv = $typevalue[$index];
12118c2ecf20Sopenharmony_ci	if (($tv =~ m/^([A-Z]):\s*(.*)/)) {
12128c2ecf20Sopenharmony_ci	    last;
12138c2ecf20Sopenharmony_ci	}
12148c2ecf20Sopenharmony_ci	$index++;
12158c2ecf20Sopenharmony_ci    }
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci    return $index;
12188c2ecf20Sopenharmony_ci}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_cisub find_starting_index {
12218c2ecf20Sopenharmony_ci    my ($index) = @_;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci    while ($index > 0) {
12248c2ecf20Sopenharmony_ci	my $tv = $typevalue[$index];
12258c2ecf20Sopenharmony_ci	if (!($tv =~ m/^([A-Z]):\s*(.*)/)) {
12268c2ecf20Sopenharmony_ci	    last;
12278c2ecf20Sopenharmony_ci	}
12288c2ecf20Sopenharmony_ci	$index--;
12298c2ecf20Sopenharmony_ci    }
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci    return $index;
12328c2ecf20Sopenharmony_ci}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_cisub find_ending_index {
12358c2ecf20Sopenharmony_ci    my ($index) = @_;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci    while ($index < @typevalue) {
12388c2ecf20Sopenharmony_ci	my $tv = $typevalue[$index];
12398c2ecf20Sopenharmony_ci	if (!($tv =~ m/^([A-Z]):\s*(.*)/)) {
12408c2ecf20Sopenharmony_ci	    last;
12418c2ecf20Sopenharmony_ci	}
12428c2ecf20Sopenharmony_ci	$index++;
12438c2ecf20Sopenharmony_ci    }
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci    return $index;
12468c2ecf20Sopenharmony_ci}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_cisub get_subsystem_name {
12498c2ecf20Sopenharmony_ci    my ($index) = @_;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci    my $start = find_starting_index($index);
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci    my $subsystem = $typevalue[$start];
12548c2ecf20Sopenharmony_ci    if ($output_section_maxlen && length($subsystem) > $output_section_maxlen) {
12558c2ecf20Sopenharmony_ci	$subsystem = substr($subsystem, 0, $output_section_maxlen - 3);
12568c2ecf20Sopenharmony_ci	$subsystem =~ s/\s*$//;
12578c2ecf20Sopenharmony_ci	$subsystem = $subsystem . "...";
12588c2ecf20Sopenharmony_ci    }
12598c2ecf20Sopenharmony_ci    return $subsystem;
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_cisub get_maintainer_role {
12638c2ecf20Sopenharmony_ci    my ($index) = @_;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci    my $i;
12668c2ecf20Sopenharmony_ci    my $start = find_starting_index($index);
12678c2ecf20Sopenharmony_ci    my $end = find_ending_index($index);
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci    my $role = "unknown";
12708c2ecf20Sopenharmony_ci    my $subsystem = get_subsystem_name($index);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci    for ($i = $start + 1; $i < $end; $i++) {
12738c2ecf20Sopenharmony_ci	my $tv = $typevalue[$i];
12748c2ecf20Sopenharmony_ci	if ($tv =~ m/^([A-Z]):\s*(.*)/) {
12758c2ecf20Sopenharmony_ci	    my $ptype = $1;
12768c2ecf20Sopenharmony_ci	    my $pvalue = $2;
12778c2ecf20Sopenharmony_ci	    if ($ptype eq "S") {
12788c2ecf20Sopenharmony_ci		$role = $pvalue;
12798c2ecf20Sopenharmony_ci	    }
12808c2ecf20Sopenharmony_ci	}
12818c2ecf20Sopenharmony_ci    }
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci    $role = lc($role);
12848c2ecf20Sopenharmony_ci    if      ($role eq "supported") {
12858c2ecf20Sopenharmony_ci	$role = "supporter";
12868c2ecf20Sopenharmony_ci    } elsif ($role eq "maintained") {
12878c2ecf20Sopenharmony_ci	$role = "maintainer";
12888c2ecf20Sopenharmony_ci    } elsif ($role eq "odd fixes") {
12898c2ecf20Sopenharmony_ci	$role = "odd fixer";
12908c2ecf20Sopenharmony_ci    } elsif ($role eq "orphan") {
12918c2ecf20Sopenharmony_ci	$role = "orphan minder";
12928c2ecf20Sopenharmony_ci    } elsif ($role eq "obsolete") {
12938c2ecf20Sopenharmony_ci	$role = "obsolete minder";
12948c2ecf20Sopenharmony_ci    } elsif ($role eq "buried alive in reporters") {
12958c2ecf20Sopenharmony_ci	$role = "chief penguin";
12968c2ecf20Sopenharmony_ci    }
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci    return $role . ":" . $subsystem;
12998c2ecf20Sopenharmony_ci}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_cisub get_list_role {
13028c2ecf20Sopenharmony_ci    my ($index) = @_;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci    my $subsystem = get_subsystem_name($index);
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci    if ($subsystem eq "THE REST") {
13078c2ecf20Sopenharmony_ci	$subsystem = "";
13088c2ecf20Sopenharmony_ci    }
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci    return $subsystem;
13118c2ecf20Sopenharmony_ci}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_cisub add_categories {
13148c2ecf20Sopenharmony_ci    my ($index) = @_;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci    my $i;
13178c2ecf20Sopenharmony_ci    my $start = find_starting_index($index);
13188c2ecf20Sopenharmony_ci    my $end = find_ending_index($index);
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci    push(@subsystem, $typevalue[$start]);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci    for ($i = $start + 1; $i < $end; $i++) {
13238c2ecf20Sopenharmony_ci	my $tv = $typevalue[$i];
13248c2ecf20Sopenharmony_ci	if ($tv =~ m/^([A-Z]):\s*(.*)/) {
13258c2ecf20Sopenharmony_ci	    my $ptype = $1;
13268c2ecf20Sopenharmony_ci	    my $pvalue = $2;
13278c2ecf20Sopenharmony_ci	    if ($ptype eq "L") {
13288c2ecf20Sopenharmony_ci		my $list_address = $pvalue;
13298c2ecf20Sopenharmony_ci		my $list_additional = "";
13308c2ecf20Sopenharmony_ci		my $list_role = get_list_role($i);
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci		if ($list_role ne "") {
13338c2ecf20Sopenharmony_ci		    $list_role = ":" . $list_role;
13348c2ecf20Sopenharmony_ci		}
13358c2ecf20Sopenharmony_ci		if ($list_address =~ m/([^\s]+)\s+(.*)$/) {
13368c2ecf20Sopenharmony_ci		    $list_address = $1;
13378c2ecf20Sopenharmony_ci		    $list_additional = $2;
13388c2ecf20Sopenharmony_ci		}
13398c2ecf20Sopenharmony_ci		if ($list_additional =~ m/subscribers-only/) {
13408c2ecf20Sopenharmony_ci		    if ($email_subscriber_list) {
13418c2ecf20Sopenharmony_ci			if (!$hash_list_to{lc($list_address)}) {
13428c2ecf20Sopenharmony_ci			    $hash_list_to{lc($list_address)} = 1;
13438c2ecf20Sopenharmony_ci			    push(@list_to, [$list_address,
13448c2ecf20Sopenharmony_ci					    "subscriber list${list_role}"]);
13458c2ecf20Sopenharmony_ci			}
13468c2ecf20Sopenharmony_ci		    }
13478c2ecf20Sopenharmony_ci		} else {
13488c2ecf20Sopenharmony_ci		    if ($email_list) {
13498c2ecf20Sopenharmony_ci			if (!$hash_list_to{lc($list_address)}) {
13508c2ecf20Sopenharmony_ci			    if ($list_additional =~ m/moderated/) {
13518c2ecf20Sopenharmony_ci				if ($email_moderated_list) {
13528c2ecf20Sopenharmony_ci				    $hash_list_to{lc($list_address)} = 1;
13538c2ecf20Sopenharmony_ci				    push(@list_to, [$list_address,
13548c2ecf20Sopenharmony_ci						    "moderated list${list_role}"]);
13558c2ecf20Sopenharmony_ci				}
13568c2ecf20Sopenharmony_ci			    } else {
13578c2ecf20Sopenharmony_ci				$hash_list_to{lc($list_address)} = 1;
13588c2ecf20Sopenharmony_ci				push(@list_to, [$list_address,
13598c2ecf20Sopenharmony_ci						"open list${list_role}"]);
13608c2ecf20Sopenharmony_ci			    }
13618c2ecf20Sopenharmony_ci			}
13628c2ecf20Sopenharmony_ci		    }
13638c2ecf20Sopenharmony_ci		}
13648c2ecf20Sopenharmony_ci	    } elsif ($ptype eq "M") {
13658c2ecf20Sopenharmony_ci		if ($email_maintainer) {
13668c2ecf20Sopenharmony_ci		    my $role = get_maintainer_role($i);
13678c2ecf20Sopenharmony_ci		    push_email_addresses($pvalue, $role);
13688c2ecf20Sopenharmony_ci		}
13698c2ecf20Sopenharmony_ci	    } elsif ($ptype eq "R") {
13708c2ecf20Sopenharmony_ci		if ($email_reviewer) {
13718c2ecf20Sopenharmony_ci		    my $subsystem = get_subsystem_name($i);
13728c2ecf20Sopenharmony_ci		    push_email_addresses($pvalue, "reviewer:$subsystem");
13738c2ecf20Sopenharmony_ci		}
13748c2ecf20Sopenharmony_ci	    } elsif ($ptype eq "T") {
13758c2ecf20Sopenharmony_ci		push(@scm, $pvalue);
13768c2ecf20Sopenharmony_ci	    } elsif ($ptype eq "W") {
13778c2ecf20Sopenharmony_ci		push(@web, $pvalue);
13788c2ecf20Sopenharmony_ci	    } elsif ($ptype eq "S") {
13798c2ecf20Sopenharmony_ci		push(@status, $pvalue);
13808c2ecf20Sopenharmony_ci	    }
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci    }
13838c2ecf20Sopenharmony_ci}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_cisub email_inuse {
13868c2ecf20Sopenharmony_ci    my ($name, $address) = @_;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci    return 1 if (($name eq "") && ($address eq ""));
13898c2ecf20Sopenharmony_ci    return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
13908c2ecf20Sopenharmony_ci    return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci    return 0;
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_cisub push_email_address {
13968c2ecf20Sopenharmony_ci    my ($line, $role) = @_;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci    my ($name, $address) = parse_email($line);
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci    if ($address eq "") {
14018c2ecf20Sopenharmony_ci	return 0;
14028c2ecf20Sopenharmony_ci    }
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci    if (!$email_remove_duplicates) {
14058c2ecf20Sopenharmony_ci	push(@email_to, [format_email($name, $address, $email_usename), $role]);
14068c2ecf20Sopenharmony_ci    } elsif (!email_inuse($name, $address)) {
14078c2ecf20Sopenharmony_ci	push(@email_to, [format_email($name, $address, $email_usename), $role]);
14088c2ecf20Sopenharmony_ci	$email_hash_name{lc($name)}++ if ($name ne "");
14098c2ecf20Sopenharmony_ci	$email_hash_address{lc($address)}++;
14108c2ecf20Sopenharmony_ci    }
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci    return 1;
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_cisub push_email_addresses {
14168c2ecf20Sopenharmony_ci    my ($address, $role) = @_;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci    my @address_list = ();
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci    if (rfc822_valid($address)) {
14218c2ecf20Sopenharmony_ci	push_email_address($address, $role);
14228c2ecf20Sopenharmony_ci    } elsif (@address_list = rfc822_validlist($address)) {
14238c2ecf20Sopenharmony_ci	my $array_count = shift(@address_list);
14248c2ecf20Sopenharmony_ci	while (my $entry = shift(@address_list)) {
14258c2ecf20Sopenharmony_ci	    push_email_address($entry, $role);
14268c2ecf20Sopenharmony_ci	}
14278c2ecf20Sopenharmony_ci    } else {
14288c2ecf20Sopenharmony_ci	if (!push_email_address($address, $role)) {
14298c2ecf20Sopenharmony_ci	    warn("Invalid MAINTAINERS address: '" . $address . "'\n");
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci    }
14328c2ecf20Sopenharmony_ci}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_cisub add_role {
14358c2ecf20Sopenharmony_ci    my ($line, $role) = @_;
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci    my ($name, $address) = parse_email($line);
14388c2ecf20Sopenharmony_ci    my $email = format_email($name, $address, $email_usename);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci    foreach my $entry (@email_to) {
14418c2ecf20Sopenharmony_ci	if ($email_remove_duplicates) {
14428c2ecf20Sopenharmony_ci	    my ($entry_name, $entry_address) = parse_email($entry->[0]);
14438c2ecf20Sopenharmony_ci	    if (($name eq $entry_name || $address eq $entry_address)
14448c2ecf20Sopenharmony_ci		&& ($role eq "" || !($entry->[1] =~ m/$role/))
14458c2ecf20Sopenharmony_ci	    ) {
14468c2ecf20Sopenharmony_ci		if ($entry->[1] eq "") {
14478c2ecf20Sopenharmony_ci		    $entry->[1] = "$role";
14488c2ecf20Sopenharmony_ci		} else {
14498c2ecf20Sopenharmony_ci		    $entry->[1] = "$entry->[1],$role";
14508c2ecf20Sopenharmony_ci		}
14518c2ecf20Sopenharmony_ci	    }
14528c2ecf20Sopenharmony_ci	} else {
14538c2ecf20Sopenharmony_ci	    if ($email eq $entry->[0]
14548c2ecf20Sopenharmony_ci		&& ($role eq "" || !($entry->[1] =~ m/$role/))
14558c2ecf20Sopenharmony_ci	    ) {
14568c2ecf20Sopenharmony_ci		if ($entry->[1] eq "") {
14578c2ecf20Sopenharmony_ci		    $entry->[1] = "$role";
14588c2ecf20Sopenharmony_ci		} else {
14598c2ecf20Sopenharmony_ci		    $entry->[1] = "$entry->[1],$role";
14608c2ecf20Sopenharmony_ci		}
14618c2ecf20Sopenharmony_ci	    }
14628c2ecf20Sopenharmony_ci	}
14638c2ecf20Sopenharmony_ci    }
14648c2ecf20Sopenharmony_ci}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_cisub which {
14678c2ecf20Sopenharmony_ci    my ($bin) = @_;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci    foreach my $path (split(/:/, $ENV{PATH})) {
14708c2ecf20Sopenharmony_ci	if (-e "$path/$bin") {
14718c2ecf20Sopenharmony_ci	    return "$path/$bin";
14728c2ecf20Sopenharmony_ci	}
14738c2ecf20Sopenharmony_ci    }
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci    return "";
14768c2ecf20Sopenharmony_ci}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_cisub which_conf {
14798c2ecf20Sopenharmony_ci    my ($conf) = @_;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci    foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
14828c2ecf20Sopenharmony_ci	if (-e "$path/$conf") {
14838c2ecf20Sopenharmony_ci	    return "$path/$conf";
14848c2ecf20Sopenharmony_ci	}
14858c2ecf20Sopenharmony_ci    }
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci    return "";
14888c2ecf20Sopenharmony_ci}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_cisub mailmap_email {
14918c2ecf20Sopenharmony_ci    my ($line) = @_;
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci    my ($name, $address) = parse_email($line);
14948c2ecf20Sopenharmony_ci    my $email = format_email($name, $address, 1);
14958c2ecf20Sopenharmony_ci    my $real_name = $name;
14968c2ecf20Sopenharmony_ci    my $real_address = $address;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci    if (exists $mailmap->{names}->{$email} ||
14998c2ecf20Sopenharmony_ci	exists $mailmap->{addresses}->{$email}) {
15008c2ecf20Sopenharmony_ci	if (exists $mailmap->{names}->{$email}) {
15018c2ecf20Sopenharmony_ci	    $real_name = $mailmap->{names}->{$email};
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci	if (exists $mailmap->{addresses}->{$email}) {
15048c2ecf20Sopenharmony_ci	    $real_address = $mailmap->{addresses}->{$email};
15058c2ecf20Sopenharmony_ci	}
15068c2ecf20Sopenharmony_ci    } else {
15078c2ecf20Sopenharmony_ci	if (exists $mailmap->{names}->{$address}) {
15088c2ecf20Sopenharmony_ci	    $real_name = $mailmap->{names}->{$address};
15098c2ecf20Sopenharmony_ci	}
15108c2ecf20Sopenharmony_ci	if (exists $mailmap->{addresses}->{$address}) {
15118c2ecf20Sopenharmony_ci	    $real_address = $mailmap->{addresses}->{$address};
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci    }
15148c2ecf20Sopenharmony_ci    return format_email($real_name, $real_address, 1);
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_cisub mailmap {
15188c2ecf20Sopenharmony_ci    my (@addresses) = @_;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci    my @mapped_emails = ();
15218c2ecf20Sopenharmony_ci    foreach my $line (@addresses) {
15228c2ecf20Sopenharmony_ci	push(@mapped_emails, mailmap_email($line));
15238c2ecf20Sopenharmony_ci    }
15248c2ecf20Sopenharmony_ci    merge_by_realname(@mapped_emails) if ($email_use_mailmap);
15258c2ecf20Sopenharmony_ci    return @mapped_emails;
15268c2ecf20Sopenharmony_ci}
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_cisub merge_by_realname {
15298c2ecf20Sopenharmony_ci    my %address_map;
15308c2ecf20Sopenharmony_ci    my (@emails) = @_;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci    foreach my $email (@emails) {
15338c2ecf20Sopenharmony_ci	my ($name, $address) = parse_email($email);
15348c2ecf20Sopenharmony_ci	if (exists $address_map{$name}) {
15358c2ecf20Sopenharmony_ci	    $address = $address_map{$name};
15368c2ecf20Sopenharmony_ci	    $email = format_email($name, $address, 1);
15378c2ecf20Sopenharmony_ci	} else {
15388c2ecf20Sopenharmony_ci	    $address_map{$name} = $address;
15398c2ecf20Sopenharmony_ci	}
15408c2ecf20Sopenharmony_ci    }
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_cisub git_execute_cmd {
15448c2ecf20Sopenharmony_ci    my ($cmd) = @_;
15458c2ecf20Sopenharmony_ci    my @lines = ();
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci    my $output = `$cmd`;
15488c2ecf20Sopenharmony_ci    $output =~ s/^\s*//gm;
15498c2ecf20Sopenharmony_ci    @lines = split("\n", $output);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci    return @lines;
15528c2ecf20Sopenharmony_ci}
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_cisub hg_execute_cmd {
15558c2ecf20Sopenharmony_ci    my ($cmd) = @_;
15568c2ecf20Sopenharmony_ci    my @lines = ();
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci    my $output = `$cmd`;
15598c2ecf20Sopenharmony_ci    @lines = split("\n", $output);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci    return @lines;
15628c2ecf20Sopenharmony_ci}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_cisub extract_formatted_signatures {
15658c2ecf20Sopenharmony_ci    my (@signature_lines) = @_;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci    my @type = @signature_lines;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci    s/\s*(.*):.*/$1/ for (@type);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci    # cut -f2- -d":"
15728c2ecf20Sopenharmony_ci    s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci## Reformat email addresses (with names) to avoid badly written signatures
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci    foreach my $signer (@signature_lines) {
15778c2ecf20Sopenharmony_ci	$signer = deduplicate_email($signer);
15788c2ecf20Sopenharmony_ci    }
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci    return (\@type, \@signature_lines);
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_cisub vcs_find_signers {
15848c2ecf20Sopenharmony_ci    my ($cmd, $file) = @_;
15858c2ecf20Sopenharmony_ci    my $commits;
15868c2ecf20Sopenharmony_ci    my @lines = ();
15878c2ecf20Sopenharmony_ci    my @signatures = ();
15888c2ecf20Sopenharmony_ci    my @authors = ();
15898c2ecf20Sopenharmony_ci    my @stats = ();
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci    my $pattern = $VCS_cmds{"commit_pattern"};
15948c2ecf20Sopenharmony_ci    my $author_pattern = $VCS_cmds{"author_pattern"};
15958c2ecf20Sopenharmony_ci    my $stat_pattern = $VCS_cmds{"stat_pattern"};
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci    $stat_pattern =~ s/(\$\w+)/$1/eeg;		#interpolate $stat_pattern
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci    $commits = grep(/$pattern/, @lines);	# of commits
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci    @authors = grep(/$author_pattern/, @lines);
16028c2ecf20Sopenharmony_ci    @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
16038c2ecf20Sopenharmony_ci    @stats = grep(/$stat_pattern/, @lines);
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci#    print("stats: <@stats>\n");
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci    return (0, \@signatures, \@authors, \@stats) if !@signatures;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci    save_commits_by_author(@lines) if ($interactive);
16108c2ecf20Sopenharmony_ci    save_commits_by_signer(@lines) if ($interactive);
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci    if (!$email_git_penguin_chiefs) {
16138c2ecf20Sopenharmony_ci	@signatures = grep(!/${penguin_chiefs}/i, @signatures);
16148c2ecf20Sopenharmony_ci    }
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci    my ($author_ref, $authors_ref) = extract_formatted_signatures(@authors);
16178c2ecf20Sopenharmony_ci    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci    return ($commits, $signers_ref, $authors_ref, \@stats);
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_cisub vcs_find_author {
16238c2ecf20Sopenharmony_ci    my ($cmd) = @_;
16248c2ecf20Sopenharmony_ci    my @lines = ();
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci    if (!$email_git_penguin_chiefs) {
16298c2ecf20Sopenharmony_ci	@lines = grep(!/${penguin_chiefs}/i, @lines);
16308c2ecf20Sopenharmony_ci    }
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci    return @lines if !@lines;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci    my @authors = ();
16358c2ecf20Sopenharmony_ci    foreach my $line (@lines) {
16368c2ecf20Sopenharmony_ci	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
16378c2ecf20Sopenharmony_ci	    my $author = $1;
16388c2ecf20Sopenharmony_ci	    my ($name, $address) = parse_email($author);
16398c2ecf20Sopenharmony_ci	    $author = format_email($name, $address, 1);
16408c2ecf20Sopenharmony_ci	    push(@authors, $author);
16418c2ecf20Sopenharmony_ci	}
16428c2ecf20Sopenharmony_ci    }
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci    save_commits_by_author(@lines) if ($interactive);
16458c2ecf20Sopenharmony_ci    save_commits_by_signer(@lines) if ($interactive);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci    return @authors;
16488c2ecf20Sopenharmony_ci}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_cisub vcs_save_commits {
16518c2ecf20Sopenharmony_ci    my ($cmd) = @_;
16528c2ecf20Sopenharmony_ci    my @lines = ();
16538c2ecf20Sopenharmony_ci    my @commits = ();
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci    @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci    foreach my $line (@lines) {
16588c2ecf20Sopenharmony_ci	if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) {
16598c2ecf20Sopenharmony_ci	    push(@commits, $1);
16608c2ecf20Sopenharmony_ci	}
16618c2ecf20Sopenharmony_ci    }
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci    return @commits;
16648c2ecf20Sopenharmony_ci}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_cisub vcs_blame {
16678c2ecf20Sopenharmony_ci    my ($file) = @_;
16688c2ecf20Sopenharmony_ci    my $cmd;
16698c2ecf20Sopenharmony_ci    my @commits = ();
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci    return @commits if (!(-f $file));
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci    if (@range && $VCS_cmds{"blame_range_cmd"} eq "") {
16748c2ecf20Sopenharmony_ci	my @all_commits = ();
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	$cmd = $VCS_cmds{"blame_file_cmd"};
16778c2ecf20Sopenharmony_ci	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
16788c2ecf20Sopenharmony_ci	@all_commits = vcs_save_commits($cmd);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	foreach my $file_range_diff (@range) {
16818c2ecf20Sopenharmony_ci	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
16828c2ecf20Sopenharmony_ci	    my $diff_file = $1;
16838c2ecf20Sopenharmony_ci	    my $diff_start = $2;
16848c2ecf20Sopenharmony_ci	    my $diff_length = $3;
16858c2ecf20Sopenharmony_ci	    next if ("$file" ne "$diff_file");
16868c2ecf20Sopenharmony_ci	    for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) {
16878c2ecf20Sopenharmony_ci		push(@commits, $all_commits[$i]);
16888c2ecf20Sopenharmony_ci	    }
16898c2ecf20Sopenharmony_ci	}
16908c2ecf20Sopenharmony_ci    } elsif (@range) {
16918c2ecf20Sopenharmony_ci	foreach my $file_range_diff (@range) {
16928c2ecf20Sopenharmony_ci	    next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
16938c2ecf20Sopenharmony_ci	    my $diff_file = $1;
16948c2ecf20Sopenharmony_ci	    my $diff_start = $2;
16958c2ecf20Sopenharmony_ci	    my $diff_length = $3;
16968c2ecf20Sopenharmony_ci	    next if ("$file" ne "$diff_file");
16978c2ecf20Sopenharmony_ci	    $cmd = $VCS_cmds{"blame_range_cmd"};
16988c2ecf20Sopenharmony_ci	    $cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
16998c2ecf20Sopenharmony_ci	    push(@commits, vcs_save_commits($cmd));
17008c2ecf20Sopenharmony_ci	}
17018c2ecf20Sopenharmony_ci    } else {
17028c2ecf20Sopenharmony_ci	$cmd = $VCS_cmds{"blame_file_cmd"};
17038c2ecf20Sopenharmony_ci	$cmd =~ s/(\$\w+)/$1/eeg;		#interpolate $cmd
17048c2ecf20Sopenharmony_ci	@commits = vcs_save_commits($cmd);
17058c2ecf20Sopenharmony_ci    }
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci    foreach my $commit (@commits) {
17088c2ecf20Sopenharmony_ci	$commit =~ s/^\^//g;
17098c2ecf20Sopenharmony_ci    }
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci    return @commits;
17128c2ecf20Sopenharmony_ci}
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_cimy $printed_novcs = 0;
17158c2ecf20Sopenharmony_cisub vcs_exists {
17168c2ecf20Sopenharmony_ci    %VCS_cmds = %VCS_cmds_git;
17178c2ecf20Sopenharmony_ci    return 1 if eval $VCS_cmds{"available"};
17188c2ecf20Sopenharmony_ci    %VCS_cmds = %VCS_cmds_hg;
17198c2ecf20Sopenharmony_ci    return 2 if eval $VCS_cmds{"available"};
17208c2ecf20Sopenharmony_ci    %VCS_cmds = ();
17218c2ecf20Sopenharmony_ci    if (!$printed_novcs) {
17228c2ecf20Sopenharmony_ci	warn("$P: No supported VCS found.  Add --nogit to options?\n");
17238c2ecf20Sopenharmony_ci	warn("Using a git repository produces better results.\n");
17248c2ecf20Sopenharmony_ci	warn("Try Linus Torvalds' latest git repository using:\n");
17258c2ecf20Sopenharmony_ci	warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n");
17268c2ecf20Sopenharmony_ci	$printed_novcs = 1;
17278c2ecf20Sopenharmony_ci    }
17288c2ecf20Sopenharmony_ci    return 0;
17298c2ecf20Sopenharmony_ci}
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_cisub vcs_is_git {
17328c2ecf20Sopenharmony_ci    vcs_exists();
17338c2ecf20Sopenharmony_ci    return $vcs_used == 1;
17348c2ecf20Sopenharmony_ci}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_cisub vcs_is_hg {
17378c2ecf20Sopenharmony_ci    return $vcs_used == 2;
17388c2ecf20Sopenharmony_ci}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_cisub vcs_add_commit_signers {
17418c2ecf20Sopenharmony_ci    return if (!vcs_exists());
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci    my ($commit, $desc) = @_;
17448c2ecf20Sopenharmony_ci    my $commit_count = 0;
17458c2ecf20Sopenharmony_ci    my $commit_authors_ref;
17468c2ecf20Sopenharmony_ci    my $commit_signers_ref;
17478c2ecf20Sopenharmony_ci    my $stats_ref;
17488c2ecf20Sopenharmony_ci    my @commit_authors = ();
17498c2ecf20Sopenharmony_ci    my @commit_signers = ();
17508c2ecf20Sopenharmony_ci    my $cmd;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci    $cmd = $VCS_cmds{"find_commit_signers_cmd"};
17538c2ecf20Sopenharmony_ci    $cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci    ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, "");
17568c2ecf20Sopenharmony_ci    @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
17578c2ecf20Sopenharmony_ci    @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci    foreach my $signer (@commit_signers) {
17608c2ecf20Sopenharmony_ci	$signer = deduplicate_email($signer);
17618c2ecf20Sopenharmony_ci    }
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci    vcs_assign($desc, 1, @commit_signers);
17648c2ecf20Sopenharmony_ci}
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_cisub interactive_get_maintainers {
17678c2ecf20Sopenharmony_ci    my ($list_ref) = @_;
17688c2ecf20Sopenharmony_ci    my @list = @$list_ref;
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci    vcs_exists();
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci    my %selected;
17738c2ecf20Sopenharmony_ci    my %authored;
17748c2ecf20Sopenharmony_ci    my %signed;
17758c2ecf20Sopenharmony_ci    my $count = 0;
17768c2ecf20Sopenharmony_ci    my $maintained = 0;
17778c2ecf20Sopenharmony_ci    foreach my $entry (@list) {
17788c2ecf20Sopenharmony_ci	$maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
17798c2ecf20Sopenharmony_ci	$selected{$count} = 1;
17808c2ecf20Sopenharmony_ci	$authored{$count} = 0;
17818c2ecf20Sopenharmony_ci	$signed{$count} = 0;
17828c2ecf20Sopenharmony_ci	$count++;
17838c2ecf20Sopenharmony_ci    }
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci    #menu loop
17868c2ecf20Sopenharmony_ci    my $done = 0;
17878c2ecf20Sopenharmony_ci    my $print_options = 0;
17888c2ecf20Sopenharmony_ci    my $redraw = 1;
17898c2ecf20Sopenharmony_ci    while (!$done) {
17908c2ecf20Sopenharmony_ci	$count = 0;
17918c2ecf20Sopenharmony_ci	if ($redraw) {
17928c2ecf20Sopenharmony_ci	    printf STDERR "\n%1s %2s %-65s",
17938c2ecf20Sopenharmony_ci			  "*", "#", "email/list and role:stats";
17948c2ecf20Sopenharmony_ci	    if ($email_git ||
17958c2ecf20Sopenharmony_ci		($email_git_fallback && !$maintained) ||
17968c2ecf20Sopenharmony_ci		$email_git_blame) {
17978c2ecf20Sopenharmony_ci		print STDERR "auth sign";
17988c2ecf20Sopenharmony_ci	    }
17998c2ecf20Sopenharmony_ci	    print STDERR "\n";
18008c2ecf20Sopenharmony_ci	    foreach my $entry (@list) {
18018c2ecf20Sopenharmony_ci		my $email = $entry->[0];
18028c2ecf20Sopenharmony_ci		my $role = $entry->[1];
18038c2ecf20Sopenharmony_ci		my $sel = "";
18048c2ecf20Sopenharmony_ci		$sel = "*" if ($selected{$count});
18058c2ecf20Sopenharmony_ci		my $commit_author = $commit_author_hash{$email};
18068c2ecf20Sopenharmony_ci		my $commit_signer = $commit_signer_hash{$email};
18078c2ecf20Sopenharmony_ci		my $authored = 0;
18088c2ecf20Sopenharmony_ci		my $signed = 0;
18098c2ecf20Sopenharmony_ci		$authored++ for (@{$commit_author});
18108c2ecf20Sopenharmony_ci		$signed++ for (@{$commit_signer});
18118c2ecf20Sopenharmony_ci		printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
18128c2ecf20Sopenharmony_ci		printf STDERR "%4d %4d", $authored, $signed
18138c2ecf20Sopenharmony_ci		    if ($authored > 0 || $signed > 0);
18148c2ecf20Sopenharmony_ci		printf STDERR "\n     %s\n", $role;
18158c2ecf20Sopenharmony_ci		if ($authored{$count}) {
18168c2ecf20Sopenharmony_ci		    my $commit_author = $commit_author_hash{$email};
18178c2ecf20Sopenharmony_ci		    foreach my $ref (@{$commit_author}) {
18188c2ecf20Sopenharmony_ci			print STDERR "     Author: @{$ref}[1]\n";
18198c2ecf20Sopenharmony_ci		    }
18208c2ecf20Sopenharmony_ci		}
18218c2ecf20Sopenharmony_ci		if ($signed{$count}) {
18228c2ecf20Sopenharmony_ci		    my $commit_signer = $commit_signer_hash{$email};
18238c2ecf20Sopenharmony_ci		    foreach my $ref (@{$commit_signer}) {
18248c2ecf20Sopenharmony_ci			print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
18258c2ecf20Sopenharmony_ci		    }
18268c2ecf20Sopenharmony_ci		}
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci		$count++;
18298c2ecf20Sopenharmony_ci	    }
18308c2ecf20Sopenharmony_ci	}
18318c2ecf20Sopenharmony_ci	my $date_ref = \$email_git_since;
18328c2ecf20Sopenharmony_ci	$date_ref = \$email_hg_since if (vcs_is_hg());
18338c2ecf20Sopenharmony_ci	if ($print_options) {
18348c2ecf20Sopenharmony_ci	    $print_options = 0;
18358c2ecf20Sopenharmony_ci	    if (vcs_exists()) {
18368c2ecf20Sopenharmony_ci		print STDERR <<EOT
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ciVersion Control options:
18398c2ecf20Sopenharmony_cig  use git history      [$email_git]
18408c2ecf20Sopenharmony_cigf use git-fallback     [$email_git_fallback]
18418c2ecf20Sopenharmony_cib  use git blame        [$email_git_blame]
18428c2ecf20Sopenharmony_cibs use blame signatures [$email_git_blame_signatures]
18438c2ecf20Sopenharmony_cic# minimum commits      [$email_git_min_signatures]
18448c2ecf20Sopenharmony_ci%# min percent          [$email_git_min_percent]
18458c2ecf20Sopenharmony_cid# history to use       [$$date_ref]
18468c2ecf20Sopenharmony_cix# max maintainers      [$email_git_max_maintainers]
18478c2ecf20Sopenharmony_cit  all signature types  [$email_git_all_signature_types]
18488c2ecf20Sopenharmony_cim  use .mailmap         [$email_use_mailmap]
18498c2ecf20Sopenharmony_ciEOT
18508c2ecf20Sopenharmony_ci	    }
18518c2ecf20Sopenharmony_ci	    print STDERR <<EOT
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ciAdditional options:
18548c2ecf20Sopenharmony_ci0  toggle all
18558c2ecf20Sopenharmony_citm toggle maintainers
18568c2ecf20Sopenharmony_citg toggle git entries
18578c2ecf20Sopenharmony_citl toggle open list entries
18588c2ecf20Sopenharmony_cits toggle subscriber list entries
18598c2ecf20Sopenharmony_cif  emails in file       [$email_file_emails]
18608c2ecf20Sopenharmony_cik  keywords in file     [$keywords]
18618c2ecf20Sopenharmony_cir  remove duplicates    [$email_remove_duplicates]
18628c2ecf20Sopenharmony_cip# pattern match depth  [$pattern_depth]
18638c2ecf20Sopenharmony_ciEOT
18648c2ecf20Sopenharmony_ci	}
18658c2ecf20Sopenharmony_ci	print STDERR
18668c2ecf20Sopenharmony_ci"\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	my $input = <STDIN>;
18698c2ecf20Sopenharmony_ci	chomp($input);
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	$redraw = 1;
18728c2ecf20Sopenharmony_ci	my $rerun = 0;
18738c2ecf20Sopenharmony_ci	my @wish = split(/[, ]+/, $input);
18748c2ecf20Sopenharmony_ci	foreach my $nr (@wish) {
18758c2ecf20Sopenharmony_ci	    $nr = lc($nr);
18768c2ecf20Sopenharmony_ci	    my $sel = substr($nr, 0, 1);
18778c2ecf20Sopenharmony_ci	    my $str = substr($nr, 1);
18788c2ecf20Sopenharmony_ci	    my $val = 0;
18798c2ecf20Sopenharmony_ci	    $val = $1 if $str =~ /^(\d+)$/;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	    if ($sel eq "y") {
18828c2ecf20Sopenharmony_ci		$interactive = 0;
18838c2ecf20Sopenharmony_ci		$done = 1;
18848c2ecf20Sopenharmony_ci		$output_rolestats = 0;
18858c2ecf20Sopenharmony_ci		$output_roles = 0;
18868c2ecf20Sopenharmony_ci		last;
18878c2ecf20Sopenharmony_ci	    } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
18888c2ecf20Sopenharmony_ci		$selected{$nr - 1} = !$selected{$nr - 1};
18898c2ecf20Sopenharmony_ci	    } elsif ($sel eq "*" || $sel eq '^') {
18908c2ecf20Sopenharmony_ci		my $toggle = 0;
18918c2ecf20Sopenharmony_ci		$toggle = 1 if ($sel eq '*');
18928c2ecf20Sopenharmony_ci		for (my $i = 0; $i < $count; $i++) {
18938c2ecf20Sopenharmony_ci		    $selected{$i} = $toggle;
18948c2ecf20Sopenharmony_ci		}
18958c2ecf20Sopenharmony_ci	    } elsif ($sel eq "0") {
18968c2ecf20Sopenharmony_ci		for (my $i = 0; $i < $count; $i++) {
18978c2ecf20Sopenharmony_ci		    $selected{$i} = !$selected{$i};
18988c2ecf20Sopenharmony_ci		}
18998c2ecf20Sopenharmony_ci	    } elsif ($sel eq "t") {
19008c2ecf20Sopenharmony_ci		if (lc($str) eq "m") {
19018c2ecf20Sopenharmony_ci		    for (my $i = 0; $i < $count; $i++) {
19028c2ecf20Sopenharmony_ci			$selected{$i} = !$selected{$i}
19038c2ecf20Sopenharmony_ci			    if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
19048c2ecf20Sopenharmony_ci		    }
19058c2ecf20Sopenharmony_ci		} elsif (lc($str) eq "g") {
19068c2ecf20Sopenharmony_ci		    for (my $i = 0; $i < $count; $i++) {
19078c2ecf20Sopenharmony_ci			$selected{$i} = !$selected{$i}
19088c2ecf20Sopenharmony_ci			    if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
19098c2ecf20Sopenharmony_ci		    }
19108c2ecf20Sopenharmony_ci		} elsif (lc($str) eq "l") {
19118c2ecf20Sopenharmony_ci		    for (my $i = 0; $i < $count; $i++) {
19128c2ecf20Sopenharmony_ci			$selected{$i} = !$selected{$i}
19138c2ecf20Sopenharmony_ci			    if ($list[$i]->[1] =~ /^(open list)/i);
19148c2ecf20Sopenharmony_ci		    }
19158c2ecf20Sopenharmony_ci		} elsif (lc($str) eq "s") {
19168c2ecf20Sopenharmony_ci		    for (my $i = 0; $i < $count; $i++) {
19178c2ecf20Sopenharmony_ci			$selected{$i} = !$selected{$i}
19188c2ecf20Sopenharmony_ci			    if ($list[$i]->[1] =~ /^(subscriber list)/i);
19198c2ecf20Sopenharmony_ci		    }
19208c2ecf20Sopenharmony_ci		}
19218c2ecf20Sopenharmony_ci	    } elsif ($sel eq "a") {
19228c2ecf20Sopenharmony_ci		if ($val > 0 && $val <= $count) {
19238c2ecf20Sopenharmony_ci		    $authored{$val - 1} = !$authored{$val - 1};
19248c2ecf20Sopenharmony_ci		} elsif ($str eq '*' || $str eq '^') {
19258c2ecf20Sopenharmony_ci		    my $toggle = 0;
19268c2ecf20Sopenharmony_ci		    $toggle = 1 if ($str eq '*');
19278c2ecf20Sopenharmony_ci		    for (my $i = 0; $i < $count; $i++) {
19288c2ecf20Sopenharmony_ci			$authored{$i} = $toggle;
19298c2ecf20Sopenharmony_ci		    }
19308c2ecf20Sopenharmony_ci		}
19318c2ecf20Sopenharmony_ci	    } elsif ($sel eq "s") {
19328c2ecf20Sopenharmony_ci		if ($val > 0 && $val <= $count) {
19338c2ecf20Sopenharmony_ci		    $signed{$val - 1} = !$signed{$val - 1};
19348c2ecf20Sopenharmony_ci		} elsif ($str eq '*' || $str eq '^') {
19358c2ecf20Sopenharmony_ci		    my $toggle = 0;
19368c2ecf20Sopenharmony_ci		    $toggle = 1 if ($str eq '*');
19378c2ecf20Sopenharmony_ci		    for (my $i = 0; $i < $count; $i++) {
19388c2ecf20Sopenharmony_ci			$signed{$i} = $toggle;
19398c2ecf20Sopenharmony_ci		    }
19408c2ecf20Sopenharmony_ci		}
19418c2ecf20Sopenharmony_ci	    } elsif ($sel eq "o") {
19428c2ecf20Sopenharmony_ci		$print_options = 1;
19438c2ecf20Sopenharmony_ci		$redraw = 1;
19448c2ecf20Sopenharmony_ci	    } elsif ($sel eq "g") {
19458c2ecf20Sopenharmony_ci		if ($str eq "f") {
19468c2ecf20Sopenharmony_ci		    bool_invert(\$email_git_fallback);
19478c2ecf20Sopenharmony_ci		} else {
19488c2ecf20Sopenharmony_ci		    bool_invert(\$email_git);
19498c2ecf20Sopenharmony_ci		}
19508c2ecf20Sopenharmony_ci		$rerun = 1;
19518c2ecf20Sopenharmony_ci	    } elsif ($sel eq "b") {
19528c2ecf20Sopenharmony_ci		if ($str eq "s") {
19538c2ecf20Sopenharmony_ci		    bool_invert(\$email_git_blame_signatures);
19548c2ecf20Sopenharmony_ci		} else {
19558c2ecf20Sopenharmony_ci		    bool_invert(\$email_git_blame);
19568c2ecf20Sopenharmony_ci		}
19578c2ecf20Sopenharmony_ci		$rerun = 1;
19588c2ecf20Sopenharmony_ci	    } elsif ($sel eq "c") {
19598c2ecf20Sopenharmony_ci		if ($val > 0) {
19608c2ecf20Sopenharmony_ci		    $email_git_min_signatures = $val;
19618c2ecf20Sopenharmony_ci		    $rerun = 1;
19628c2ecf20Sopenharmony_ci		}
19638c2ecf20Sopenharmony_ci	    } elsif ($sel eq "x") {
19648c2ecf20Sopenharmony_ci		if ($val > 0) {
19658c2ecf20Sopenharmony_ci		    $email_git_max_maintainers = $val;
19668c2ecf20Sopenharmony_ci		    $rerun = 1;
19678c2ecf20Sopenharmony_ci		}
19688c2ecf20Sopenharmony_ci	    } elsif ($sel eq "%") {
19698c2ecf20Sopenharmony_ci		if ($str ne "" && $val >= 0) {
19708c2ecf20Sopenharmony_ci		    $email_git_min_percent = $val;
19718c2ecf20Sopenharmony_ci		    $rerun = 1;
19728c2ecf20Sopenharmony_ci		}
19738c2ecf20Sopenharmony_ci	    } elsif ($sel eq "d") {
19748c2ecf20Sopenharmony_ci		if (vcs_is_git()) {
19758c2ecf20Sopenharmony_ci		    $email_git_since = $str;
19768c2ecf20Sopenharmony_ci		} elsif (vcs_is_hg()) {
19778c2ecf20Sopenharmony_ci		    $email_hg_since = $str;
19788c2ecf20Sopenharmony_ci		}
19798c2ecf20Sopenharmony_ci		$rerun = 1;
19808c2ecf20Sopenharmony_ci	    } elsif ($sel eq "t") {
19818c2ecf20Sopenharmony_ci		bool_invert(\$email_git_all_signature_types);
19828c2ecf20Sopenharmony_ci		$rerun = 1;
19838c2ecf20Sopenharmony_ci	    } elsif ($sel eq "f") {
19848c2ecf20Sopenharmony_ci		bool_invert(\$email_file_emails);
19858c2ecf20Sopenharmony_ci		$rerun = 1;
19868c2ecf20Sopenharmony_ci	    } elsif ($sel eq "r") {
19878c2ecf20Sopenharmony_ci		bool_invert(\$email_remove_duplicates);
19888c2ecf20Sopenharmony_ci		$rerun = 1;
19898c2ecf20Sopenharmony_ci	    } elsif ($sel eq "m") {
19908c2ecf20Sopenharmony_ci		bool_invert(\$email_use_mailmap);
19918c2ecf20Sopenharmony_ci		read_mailmap();
19928c2ecf20Sopenharmony_ci		$rerun = 1;
19938c2ecf20Sopenharmony_ci	    } elsif ($sel eq "k") {
19948c2ecf20Sopenharmony_ci		bool_invert(\$keywords);
19958c2ecf20Sopenharmony_ci		$rerun = 1;
19968c2ecf20Sopenharmony_ci	    } elsif ($sel eq "p") {
19978c2ecf20Sopenharmony_ci		if ($str ne "" && $val >= 0) {
19988c2ecf20Sopenharmony_ci		    $pattern_depth = $val;
19998c2ecf20Sopenharmony_ci		    $rerun = 1;
20008c2ecf20Sopenharmony_ci		}
20018c2ecf20Sopenharmony_ci	    } elsif ($sel eq "h" || $sel eq "?") {
20028c2ecf20Sopenharmony_ci		print STDERR <<EOT
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ciInteractive mode allows you to select the various maintainers, submitters,
20058c2ecf20Sopenharmony_cicommit signers and mailing lists that could be CC'd on a patch.
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ciAny *'d entry is selected.
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ciIf you have git or hg installed, you can choose to summarize the commit
20108c2ecf20Sopenharmony_cihistory of files in the patch.  Also, each line of the current file can
20118c2ecf20Sopenharmony_cibe matched to its commit author and that commits signers with blame.
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ciVarious knobs exist to control the length of time for active commit
20148c2ecf20Sopenharmony_citracking, the maximum number of commit authors and signers to add,
20158c2ecf20Sopenharmony_ciand such.
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ciEnter selections at the prompt until you are satisfied that the selected
20188c2ecf20Sopenharmony_cimaintainers are appropriate.  You may enter multiple selections separated
20198c2ecf20Sopenharmony_ciby either commas or spaces.
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ciEOT
20228c2ecf20Sopenharmony_ci	    } else {
20238c2ecf20Sopenharmony_ci		print STDERR "invalid option: '$nr'\n";
20248c2ecf20Sopenharmony_ci		$redraw = 0;
20258c2ecf20Sopenharmony_ci	    }
20268c2ecf20Sopenharmony_ci	}
20278c2ecf20Sopenharmony_ci	if ($rerun) {
20288c2ecf20Sopenharmony_ci	    print STDERR "git-blame can be very slow, please have patience..."
20298c2ecf20Sopenharmony_ci		if ($email_git_blame);
20308c2ecf20Sopenharmony_ci	    goto &get_maintainers;
20318c2ecf20Sopenharmony_ci	}
20328c2ecf20Sopenharmony_ci    }
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci    #drop not selected entries
20358c2ecf20Sopenharmony_ci    $count = 0;
20368c2ecf20Sopenharmony_ci    my @new_emailto = ();
20378c2ecf20Sopenharmony_ci    foreach my $entry (@list) {
20388c2ecf20Sopenharmony_ci	if ($selected{$count}) {
20398c2ecf20Sopenharmony_ci	    push(@new_emailto, $list[$count]);
20408c2ecf20Sopenharmony_ci	}
20418c2ecf20Sopenharmony_ci	$count++;
20428c2ecf20Sopenharmony_ci    }
20438c2ecf20Sopenharmony_ci    return @new_emailto;
20448c2ecf20Sopenharmony_ci}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_cisub bool_invert {
20478c2ecf20Sopenharmony_ci    my ($bool_ref) = @_;
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci    if ($$bool_ref) {
20508c2ecf20Sopenharmony_ci	$$bool_ref = 0;
20518c2ecf20Sopenharmony_ci    } else {
20528c2ecf20Sopenharmony_ci	$$bool_ref = 1;
20538c2ecf20Sopenharmony_ci    }
20548c2ecf20Sopenharmony_ci}
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_cisub deduplicate_email {
20578c2ecf20Sopenharmony_ci    my ($email) = @_;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci    my $matched = 0;
20608c2ecf20Sopenharmony_ci    my ($name, $address) = parse_email($email);
20618c2ecf20Sopenharmony_ci    $email = format_email($name, $address, 1);
20628c2ecf20Sopenharmony_ci    $email = mailmap_email($email);
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci    return $email if (!$email_remove_duplicates);
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci    ($name, $address) = parse_email($email);
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci    if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
20698c2ecf20Sopenharmony_ci	$name = $deduplicate_name_hash{lc($name)}->[0];
20708c2ecf20Sopenharmony_ci	$address = $deduplicate_name_hash{lc($name)}->[1];
20718c2ecf20Sopenharmony_ci	$matched = 1;
20728c2ecf20Sopenharmony_ci    } elsif ($deduplicate_address_hash{lc($address)}) {
20738c2ecf20Sopenharmony_ci	$name = $deduplicate_address_hash{lc($address)}->[0];
20748c2ecf20Sopenharmony_ci	$address = $deduplicate_address_hash{lc($address)}->[1];
20758c2ecf20Sopenharmony_ci	$matched = 1;
20768c2ecf20Sopenharmony_ci    }
20778c2ecf20Sopenharmony_ci    if (!$matched) {
20788c2ecf20Sopenharmony_ci	$deduplicate_name_hash{lc($name)} = [ $name, $address ];
20798c2ecf20Sopenharmony_ci	$deduplicate_address_hash{lc($address)} = [ $name, $address ];
20808c2ecf20Sopenharmony_ci    }
20818c2ecf20Sopenharmony_ci    $email = format_email($name, $address, 1);
20828c2ecf20Sopenharmony_ci    $email = mailmap_email($email);
20838c2ecf20Sopenharmony_ci    return $email;
20848c2ecf20Sopenharmony_ci}
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_cisub save_commits_by_author {
20878c2ecf20Sopenharmony_ci    my (@lines) = @_;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci    my @authors = ();
20908c2ecf20Sopenharmony_ci    my @commits = ();
20918c2ecf20Sopenharmony_ci    my @subjects = ();
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci    foreach my $line (@lines) {
20948c2ecf20Sopenharmony_ci	if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
20958c2ecf20Sopenharmony_ci	    my $author = $1;
20968c2ecf20Sopenharmony_ci	    $author = deduplicate_email($author);
20978c2ecf20Sopenharmony_ci	    push(@authors, $author);
20988c2ecf20Sopenharmony_ci	}
20998c2ecf20Sopenharmony_ci	push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
21008c2ecf20Sopenharmony_ci	push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
21018c2ecf20Sopenharmony_ci    }
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci    for (my $i = 0; $i < @authors; $i++) {
21048c2ecf20Sopenharmony_ci	my $exists = 0;
21058c2ecf20Sopenharmony_ci	foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
21068c2ecf20Sopenharmony_ci	    if (@{$ref}[0] eq $commits[$i] &&
21078c2ecf20Sopenharmony_ci		@{$ref}[1] eq $subjects[$i]) {
21088c2ecf20Sopenharmony_ci		$exists = 1;
21098c2ecf20Sopenharmony_ci		last;
21108c2ecf20Sopenharmony_ci	    }
21118c2ecf20Sopenharmony_ci	}
21128c2ecf20Sopenharmony_ci	if (!$exists) {
21138c2ecf20Sopenharmony_ci	    push(@{$commit_author_hash{$authors[$i]}},
21148c2ecf20Sopenharmony_ci		 [ ($commits[$i], $subjects[$i]) ]);
21158c2ecf20Sopenharmony_ci	}
21168c2ecf20Sopenharmony_ci    }
21178c2ecf20Sopenharmony_ci}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_cisub save_commits_by_signer {
21208c2ecf20Sopenharmony_ci    my (@lines) = @_;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci    my $commit = "";
21238c2ecf20Sopenharmony_ci    my $subject = "";
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci    foreach my $line (@lines) {
21268c2ecf20Sopenharmony_ci	$commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
21278c2ecf20Sopenharmony_ci	$subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
21288c2ecf20Sopenharmony_ci	if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
21298c2ecf20Sopenharmony_ci	    my @signatures = ($line);
21308c2ecf20Sopenharmony_ci	    my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
21318c2ecf20Sopenharmony_ci	    my @types = @$types_ref;
21328c2ecf20Sopenharmony_ci	    my @signers = @$signers_ref;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	    my $type = $types[0];
21358c2ecf20Sopenharmony_ci	    my $signer = $signers[0];
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	    $signer = deduplicate_email($signer);
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	    my $exists = 0;
21408c2ecf20Sopenharmony_ci	    foreach my $ref(@{$commit_signer_hash{$signer}}) {
21418c2ecf20Sopenharmony_ci		if (@{$ref}[0] eq $commit &&
21428c2ecf20Sopenharmony_ci		    @{$ref}[1] eq $subject &&
21438c2ecf20Sopenharmony_ci		    @{$ref}[2] eq $type) {
21448c2ecf20Sopenharmony_ci		    $exists = 1;
21458c2ecf20Sopenharmony_ci		    last;
21468c2ecf20Sopenharmony_ci		}
21478c2ecf20Sopenharmony_ci	    }
21488c2ecf20Sopenharmony_ci	    if (!$exists) {
21498c2ecf20Sopenharmony_ci		push(@{$commit_signer_hash{$signer}},
21508c2ecf20Sopenharmony_ci		     [ ($commit, $subject, $type) ]);
21518c2ecf20Sopenharmony_ci	    }
21528c2ecf20Sopenharmony_ci	}
21538c2ecf20Sopenharmony_ci    }
21548c2ecf20Sopenharmony_ci}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_cisub vcs_assign {
21578c2ecf20Sopenharmony_ci    my ($role, $divisor, @lines) = @_;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci    my %hash;
21608c2ecf20Sopenharmony_ci    my $count = 0;
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci    return if (@lines <= 0);
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci    if ($divisor <= 0) {
21658c2ecf20Sopenharmony_ci	warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n");
21668c2ecf20Sopenharmony_ci	$divisor = 1;
21678c2ecf20Sopenharmony_ci    }
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci    @lines = mailmap(@lines);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci    return if (@lines <= 0);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci    @lines = sort(@lines);
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci    # uniq -c
21768c2ecf20Sopenharmony_ci    $hash{$_}++ for @lines;
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci    # sort -rn
21798c2ecf20Sopenharmony_ci    foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
21808c2ecf20Sopenharmony_ci	my $sign_offs = $hash{$line};
21818c2ecf20Sopenharmony_ci	my $percent = $sign_offs * 100 / $divisor;
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	$percent = 100 if ($percent > 100);
21848c2ecf20Sopenharmony_ci	next if (ignore_email_address($line));
21858c2ecf20Sopenharmony_ci	$count++;
21868c2ecf20Sopenharmony_ci	last if ($sign_offs < $email_git_min_signatures ||
21878c2ecf20Sopenharmony_ci		 $count > $email_git_max_maintainers ||
21888c2ecf20Sopenharmony_ci		 $percent < $email_git_min_percent);
21898c2ecf20Sopenharmony_ci	push_email_address($line, '');
21908c2ecf20Sopenharmony_ci	if ($output_rolestats) {
21918c2ecf20Sopenharmony_ci	    my $fmt_percent = sprintf("%.0f", $percent);
21928c2ecf20Sopenharmony_ci	    add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%");
21938c2ecf20Sopenharmony_ci	} else {
21948c2ecf20Sopenharmony_ci	    add_role($line, $role);
21958c2ecf20Sopenharmony_ci	}
21968c2ecf20Sopenharmony_ci    }
21978c2ecf20Sopenharmony_ci}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_cisub vcs_file_signoffs {
22008c2ecf20Sopenharmony_ci    my ($file) = @_;
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci    my $authors_ref;
22038c2ecf20Sopenharmony_ci    my $signers_ref;
22048c2ecf20Sopenharmony_ci    my $stats_ref;
22058c2ecf20Sopenharmony_ci    my @authors = ();
22068c2ecf20Sopenharmony_ci    my @signers = ();
22078c2ecf20Sopenharmony_ci    my @stats = ();
22088c2ecf20Sopenharmony_ci    my $commits;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci    $vcs_used = vcs_exists();
22118c2ecf20Sopenharmony_ci    return if (!$vcs_used);
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci    my $cmd = $VCS_cmds{"find_signers_cmd"};
22148c2ecf20Sopenharmony_ci    $cmd =~ s/(\$\w+)/$1/eeg;		# interpolate $cmd
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci    ($commits, $signers_ref, $authors_ref, $stats_ref) = vcs_find_signers($cmd, $file);
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci    @signers = @{$signers_ref} if defined $signers_ref;
22198c2ecf20Sopenharmony_ci    @authors = @{$authors_ref} if defined $authors_ref;
22208c2ecf20Sopenharmony_ci    @stats = @{$stats_ref} if defined $stats_ref;
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci#    print("commits: <$commits>\nsigners:<@signers>\nauthors: <@authors>\nstats: <@stats>\n");
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci    foreach my $signer (@signers) {
22258c2ecf20Sopenharmony_ci	$signer = deduplicate_email($signer);
22268c2ecf20Sopenharmony_ci    }
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci    vcs_assign("commit_signer", $commits, @signers);
22298c2ecf20Sopenharmony_ci    vcs_assign("authored", $commits, @authors);
22308c2ecf20Sopenharmony_ci    if ($#authors == $#stats) {
22318c2ecf20Sopenharmony_ci	my $stat_pattern = $VCS_cmds{"stat_pattern"};
22328c2ecf20Sopenharmony_ci	$stat_pattern =~ s/(\$\w+)/$1/eeg;	#interpolate $stat_pattern
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	my $added = 0;
22358c2ecf20Sopenharmony_ci	my $deleted = 0;
22368c2ecf20Sopenharmony_ci	for (my $i = 0; $i <= $#stats; $i++) {
22378c2ecf20Sopenharmony_ci	    if ($stats[$i] =~ /$stat_pattern/) {
22388c2ecf20Sopenharmony_ci		$added += $1;
22398c2ecf20Sopenharmony_ci		$deleted += $2;
22408c2ecf20Sopenharmony_ci	    }
22418c2ecf20Sopenharmony_ci	}
22428c2ecf20Sopenharmony_ci	my @tmp_authors = uniq(@authors);
22438c2ecf20Sopenharmony_ci	foreach my $author (@tmp_authors) {
22448c2ecf20Sopenharmony_ci	    $author = deduplicate_email($author);
22458c2ecf20Sopenharmony_ci	}
22468c2ecf20Sopenharmony_ci	@tmp_authors = uniq(@tmp_authors);
22478c2ecf20Sopenharmony_ci	my @list_added = ();
22488c2ecf20Sopenharmony_ci	my @list_deleted = ();
22498c2ecf20Sopenharmony_ci	foreach my $author (@tmp_authors) {
22508c2ecf20Sopenharmony_ci	    my $auth_added = 0;
22518c2ecf20Sopenharmony_ci	    my $auth_deleted = 0;
22528c2ecf20Sopenharmony_ci	    for (my $i = 0; $i <= $#stats; $i++) {
22538c2ecf20Sopenharmony_ci		if ($author eq deduplicate_email($authors[$i]) &&
22548c2ecf20Sopenharmony_ci		    $stats[$i] =~ /$stat_pattern/) {
22558c2ecf20Sopenharmony_ci		    $auth_added += $1;
22568c2ecf20Sopenharmony_ci		    $auth_deleted += $2;
22578c2ecf20Sopenharmony_ci		}
22588c2ecf20Sopenharmony_ci	    }
22598c2ecf20Sopenharmony_ci	    for (my $i = 0; $i < $auth_added; $i++) {
22608c2ecf20Sopenharmony_ci		push(@list_added, $author);
22618c2ecf20Sopenharmony_ci	    }
22628c2ecf20Sopenharmony_ci	    for (my $i = 0; $i < $auth_deleted; $i++) {
22638c2ecf20Sopenharmony_ci		push(@list_deleted, $author);
22648c2ecf20Sopenharmony_ci	    }
22658c2ecf20Sopenharmony_ci	}
22668c2ecf20Sopenharmony_ci	vcs_assign("added_lines", $added, @list_added);
22678c2ecf20Sopenharmony_ci	vcs_assign("removed_lines", $deleted, @list_deleted);
22688c2ecf20Sopenharmony_ci    }
22698c2ecf20Sopenharmony_ci}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_cisub vcs_file_blame {
22728c2ecf20Sopenharmony_ci    my ($file) = @_;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci    my @signers = ();
22758c2ecf20Sopenharmony_ci    my @all_commits = ();
22768c2ecf20Sopenharmony_ci    my @commits = ();
22778c2ecf20Sopenharmony_ci    my $total_commits;
22788c2ecf20Sopenharmony_ci    my $total_lines;
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci    $vcs_used = vcs_exists();
22818c2ecf20Sopenharmony_ci    return if (!$vcs_used);
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci    @all_commits = vcs_blame($file);
22848c2ecf20Sopenharmony_ci    @commits = uniq(@all_commits);
22858c2ecf20Sopenharmony_ci    $total_commits = @commits;
22868c2ecf20Sopenharmony_ci    $total_lines = @all_commits;
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci    if ($email_git_blame_signatures) {
22898c2ecf20Sopenharmony_ci	if (vcs_is_hg()) {
22908c2ecf20Sopenharmony_ci	    my $commit_count;
22918c2ecf20Sopenharmony_ci	    my $commit_authors_ref;
22928c2ecf20Sopenharmony_ci	    my $commit_signers_ref;
22938c2ecf20Sopenharmony_ci	    my $stats_ref;
22948c2ecf20Sopenharmony_ci	    my @commit_authors = ();
22958c2ecf20Sopenharmony_ci	    my @commit_signers = ();
22968c2ecf20Sopenharmony_ci	    my $commit = join(" -r ", @commits);
22978c2ecf20Sopenharmony_ci	    my $cmd;
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	    $cmd = $VCS_cmds{"find_commit_signers_cmd"};
23008c2ecf20Sopenharmony_ci	    $cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	    ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file);
23038c2ecf20Sopenharmony_ci	    @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
23048c2ecf20Sopenharmony_ci	    @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci	    push(@signers, @commit_signers);
23078c2ecf20Sopenharmony_ci	} else {
23088c2ecf20Sopenharmony_ci	    foreach my $commit (@commits) {
23098c2ecf20Sopenharmony_ci		my $commit_count;
23108c2ecf20Sopenharmony_ci		my $commit_authors_ref;
23118c2ecf20Sopenharmony_ci		my $commit_signers_ref;
23128c2ecf20Sopenharmony_ci		my $stats_ref;
23138c2ecf20Sopenharmony_ci		my @commit_authors = ();
23148c2ecf20Sopenharmony_ci		my @commit_signers = ();
23158c2ecf20Sopenharmony_ci		my $cmd;
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci		$cmd = $VCS_cmds{"find_commit_signers_cmd"};
23188c2ecf20Sopenharmony_ci		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci		($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file);
23218c2ecf20Sopenharmony_ci		@commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref;
23228c2ecf20Sopenharmony_ci		@commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci		push(@signers, @commit_signers);
23258c2ecf20Sopenharmony_ci	    }
23268c2ecf20Sopenharmony_ci	}
23278c2ecf20Sopenharmony_ci    }
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci    if ($from_filename) {
23308c2ecf20Sopenharmony_ci	if ($output_rolestats) {
23318c2ecf20Sopenharmony_ci	    my @blame_signers;
23328c2ecf20Sopenharmony_ci	    if (vcs_is_hg()) {{		# Double brace for last exit
23338c2ecf20Sopenharmony_ci		my $commit_count;
23348c2ecf20Sopenharmony_ci		my @commit_signers = ();
23358c2ecf20Sopenharmony_ci		@commits = uniq(@commits);
23368c2ecf20Sopenharmony_ci		@commits = sort(@commits);
23378c2ecf20Sopenharmony_ci		my $commit = join(" -r ", @commits);
23388c2ecf20Sopenharmony_ci		my $cmd;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci		$cmd = $VCS_cmds{"find_commit_author_cmd"};
23418c2ecf20Sopenharmony_ci		$cmd =~ s/(\$\w+)/$1/eeg;	#substitute variables in $cmd
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci		my @lines = ();
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci		@lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci		if (!$email_git_penguin_chiefs) {
23488c2ecf20Sopenharmony_ci		    @lines = grep(!/${penguin_chiefs}/i, @lines);
23498c2ecf20Sopenharmony_ci		}
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci		last if !@lines;
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci		my @authors = ();
23548c2ecf20Sopenharmony_ci		foreach my $line (@lines) {
23558c2ecf20Sopenharmony_ci		    if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
23568c2ecf20Sopenharmony_ci			my $author = $1;
23578c2ecf20Sopenharmony_ci			$author = deduplicate_email($author);
23588c2ecf20Sopenharmony_ci			push(@authors, $author);
23598c2ecf20Sopenharmony_ci		    }
23608c2ecf20Sopenharmony_ci		}
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ci		save_commits_by_author(@lines) if ($interactive);
23638c2ecf20Sopenharmony_ci		save_commits_by_signer(@lines) if ($interactive);
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci		push(@signers, @authors);
23668c2ecf20Sopenharmony_ci	    }}
23678c2ecf20Sopenharmony_ci	    else {
23688c2ecf20Sopenharmony_ci		foreach my $commit (@commits) {
23698c2ecf20Sopenharmony_ci		    my $i;
23708c2ecf20Sopenharmony_ci		    my $cmd = $VCS_cmds{"find_commit_author_cmd"};
23718c2ecf20Sopenharmony_ci		    $cmd =~ s/(\$\w+)/$1/eeg;	#interpolate $cmd
23728c2ecf20Sopenharmony_ci		    my @author = vcs_find_author($cmd);
23738c2ecf20Sopenharmony_ci		    next if !@author;
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci		    my $formatted_author = deduplicate_email($author[0]);
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci		    my $count = grep(/$commit/, @all_commits);
23788c2ecf20Sopenharmony_ci		    for ($i = 0; $i < $count ; $i++) {
23798c2ecf20Sopenharmony_ci			push(@blame_signers, $formatted_author);
23808c2ecf20Sopenharmony_ci		    }
23818c2ecf20Sopenharmony_ci		}
23828c2ecf20Sopenharmony_ci	    }
23838c2ecf20Sopenharmony_ci	    if (@blame_signers) {
23848c2ecf20Sopenharmony_ci		vcs_assign("authored lines", $total_lines, @blame_signers);
23858c2ecf20Sopenharmony_ci	    }
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci	foreach my $signer (@signers) {
23888c2ecf20Sopenharmony_ci	    $signer = deduplicate_email($signer);
23898c2ecf20Sopenharmony_ci	}
23908c2ecf20Sopenharmony_ci	vcs_assign("commits", $total_commits, @signers);
23918c2ecf20Sopenharmony_ci    } else {
23928c2ecf20Sopenharmony_ci	foreach my $signer (@signers) {
23938c2ecf20Sopenharmony_ci	    $signer = deduplicate_email($signer);
23948c2ecf20Sopenharmony_ci	}
23958c2ecf20Sopenharmony_ci	vcs_assign("modified commits", $total_commits, @signers);
23968c2ecf20Sopenharmony_ci    }
23978c2ecf20Sopenharmony_ci}
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_cisub vcs_file_exists {
24008c2ecf20Sopenharmony_ci    my ($file) = @_;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci    my $exists;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci    my $vcs_used = vcs_exists();
24058c2ecf20Sopenharmony_ci    return 0 if (!$vcs_used);
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci    my $cmd = $VCS_cmds{"file_exists_cmd"};
24088c2ecf20Sopenharmony_ci    $cmd =~ s/(\$\w+)/$1/eeg;		# interpolate $cmd
24098c2ecf20Sopenharmony_ci    $cmd .= " 2>&1";
24108c2ecf20Sopenharmony_ci    $exists = &{$VCS_cmds{"execute_cmd"}}($cmd);
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci    return 0 if ($? != 0);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci    return $exists;
24158c2ecf20Sopenharmony_ci}
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_cisub vcs_list_files {
24188c2ecf20Sopenharmony_ci    my ($file) = @_;
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_ci    my @lsfiles = ();
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci    my $vcs_used = vcs_exists();
24238c2ecf20Sopenharmony_ci    return 0 if (!$vcs_used);
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci    my $cmd = $VCS_cmds{"list_files_cmd"};
24268c2ecf20Sopenharmony_ci    $cmd =~ s/(\$\w+)/$1/eeg;   # interpolate $cmd
24278c2ecf20Sopenharmony_ci    @lsfiles = &{$VCS_cmds{"execute_cmd"}}($cmd);
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci    return () if ($? != 0);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci    return @lsfiles;
24328c2ecf20Sopenharmony_ci}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_cisub uniq {
24358c2ecf20Sopenharmony_ci    my (@parms) = @_;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci    my %saw;
24388c2ecf20Sopenharmony_ci    @parms = grep(!$saw{$_}++, @parms);
24398c2ecf20Sopenharmony_ci    return @parms;
24408c2ecf20Sopenharmony_ci}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_cisub sort_and_uniq {
24438c2ecf20Sopenharmony_ci    my (@parms) = @_;
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci    my %saw;
24468c2ecf20Sopenharmony_ci    @parms = sort @parms;
24478c2ecf20Sopenharmony_ci    @parms = grep(!$saw{$_}++, @parms);
24488c2ecf20Sopenharmony_ci    return @parms;
24498c2ecf20Sopenharmony_ci}
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_cisub clean_file_emails {
24528c2ecf20Sopenharmony_ci    my (@file_emails) = @_;
24538c2ecf20Sopenharmony_ci    my @fmt_emails = ();
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci    foreach my $email (@file_emails) {
24568c2ecf20Sopenharmony_ci	$email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g;
24578c2ecf20Sopenharmony_ci	my ($name, $address) = parse_email($email);
24588c2ecf20Sopenharmony_ci	if ($name eq '"[,\.]"') {
24598c2ecf20Sopenharmony_ci	    $name = "";
24608c2ecf20Sopenharmony_ci	}
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name);
24638c2ecf20Sopenharmony_ci	if (@nw > 2) {
24648c2ecf20Sopenharmony_ci	    my $first = $nw[@nw - 3];
24658c2ecf20Sopenharmony_ci	    my $middle = $nw[@nw - 2];
24668c2ecf20Sopenharmony_ci	    my $last = $nw[@nw - 1];
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci	    if (((length($first) == 1 && $first =~ m/[A-Za-z]/) ||
24698c2ecf20Sopenharmony_ci		 (length($first) == 2 && substr($first, -1) eq ".")) ||
24708c2ecf20Sopenharmony_ci		(length($middle) == 1 ||
24718c2ecf20Sopenharmony_ci		 (length($middle) == 2 && substr($middle, -1) eq "."))) {
24728c2ecf20Sopenharmony_ci		$name = "$first $middle $last";
24738c2ecf20Sopenharmony_ci	    } else {
24748c2ecf20Sopenharmony_ci		$name = "$middle $last";
24758c2ecf20Sopenharmony_ci	    }
24768c2ecf20Sopenharmony_ci	}
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	if (substr($name, -1) =~ /[,\.]/) {
24798c2ecf20Sopenharmony_ci	    $name = substr($name, 0, length($name) - 1);
24808c2ecf20Sopenharmony_ci	} elsif (substr($name, -2) =~ /[,\.]"/) {
24818c2ecf20Sopenharmony_ci	    $name = substr($name, 0, length($name) - 2) . '"';
24828c2ecf20Sopenharmony_ci	}
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	if (substr($name, 0, 1) =~ /[,\.]/) {
24858c2ecf20Sopenharmony_ci	    $name = substr($name, 1, length($name) - 1);
24868c2ecf20Sopenharmony_ci	} elsif (substr($name, 0, 2) =~ /"[,\.]/) {
24878c2ecf20Sopenharmony_ci	    $name = '"' . substr($name, 2, length($name) - 2);
24888c2ecf20Sopenharmony_ci	}
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	my $fmt_email = format_email($name, $address, $email_usename);
24918c2ecf20Sopenharmony_ci	push(@fmt_emails, $fmt_email);
24928c2ecf20Sopenharmony_ci    }
24938c2ecf20Sopenharmony_ci    return @fmt_emails;
24948c2ecf20Sopenharmony_ci}
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_cisub merge_email {
24978c2ecf20Sopenharmony_ci    my @lines;
24988c2ecf20Sopenharmony_ci    my %saw;
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci    for (@_) {
25018c2ecf20Sopenharmony_ci	my ($address, $role) = @$_;
25028c2ecf20Sopenharmony_ci	if (!$saw{$address}) {
25038c2ecf20Sopenharmony_ci	    if ($output_roles) {
25048c2ecf20Sopenharmony_ci		push(@lines, "$address ($role)");
25058c2ecf20Sopenharmony_ci	    } else {
25068c2ecf20Sopenharmony_ci		push(@lines, $address);
25078c2ecf20Sopenharmony_ci	    }
25088c2ecf20Sopenharmony_ci	    $saw{$address} = 1;
25098c2ecf20Sopenharmony_ci	}
25108c2ecf20Sopenharmony_ci    }
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci    return @lines;
25138c2ecf20Sopenharmony_ci}
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_cisub output {
25168c2ecf20Sopenharmony_ci    my (@parms) = @_;
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci    if ($output_multiline) {
25198c2ecf20Sopenharmony_ci	foreach my $line (@parms) {
25208c2ecf20Sopenharmony_ci	    print("${line}\n");
25218c2ecf20Sopenharmony_ci	}
25228c2ecf20Sopenharmony_ci    } else {
25238c2ecf20Sopenharmony_ci	print(join($output_separator, @parms));
25248c2ecf20Sopenharmony_ci	print("\n");
25258c2ecf20Sopenharmony_ci    }
25268c2ecf20Sopenharmony_ci}
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_cimy $rfc822re;
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_cisub make_rfc822re {
25318c2ecf20Sopenharmony_ci#   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
25328c2ecf20Sopenharmony_ci#   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
25338c2ecf20Sopenharmony_ci#   This regexp will only work on addresses which have had comments stripped
25348c2ecf20Sopenharmony_ci#   and replaced with rfc822_lwsp.
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci    my $specials = '()<>@,;:\\\\".\\[\\]';
25378c2ecf20Sopenharmony_ci    my $controls = '\\000-\\037\\177';
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci    my $dtext = "[^\\[\\]\\r\\\\]";
25408c2ecf20Sopenharmony_ci    my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*";
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci    my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*";
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_ci#   Use zero-width assertion to spot the limit of an atom.  A simple
25458c2ecf20Sopenharmony_ci#   $rfc822_lwsp* causes the regexp engine to hang occasionally.
25468c2ecf20Sopenharmony_ci    my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
25478c2ecf20Sopenharmony_ci    my $word = "(?:$atom|$quoted_string)";
25488c2ecf20Sopenharmony_ci    my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*";
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci    my $sub_domain = "(?:$atom|$domain_literal)";
25518c2ecf20Sopenharmony_ci    my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci    my $addr_spec = "$localpart\@$rfc822_lwsp*$domain";
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci    my $phrase = "$word*";
25568c2ecf20Sopenharmony_ci    my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
25578c2ecf20Sopenharmony_ci    my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*";
25588c2ecf20Sopenharmony_ci    my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci    my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
25618c2ecf20Sopenharmony_ci    my $address = "(?:$mailbox|$group)";
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci    return "$rfc822_lwsp*$address";
25648c2ecf20Sopenharmony_ci}
25658c2ecf20Sopenharmony_ci
25668c2ecf20Sopenharmony_cisub rfc822_strip_comments {
25678c2ecf20Sopenharmony_ci    my $s = shift;
25688c2ecf20Sopenharmony_ci#   Recursively remove comments, and replace with a single space.  The simpler
25698c2ecf20Sopenharmony_ci#   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
25708c2ecf20Sopenharmony_ci#   chars in atoms, for example.
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci    while ($s =~ s/^((?:[^"\\]|\\.)*
25738c2ecf20Sopenharmony_ci                    (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
25748c2ecf20Sopenharmony_ci                    \((?:[^()\\]|\\.)*\)/$1 /osx) {}
25758c2ecf20Sopenharmony_ci    return $s;
25768c2ecf20Sopenharmony_ci}
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci#   valid: returns true if the parameter is an RFC822 valid address
25798c2ecf20Sopenharmony_ci#
25808c2ecf20Sopenharmony_cisub rfc822_valid {
25818c2ecf20Sopenharmony_ci    my $s = rfc822_strip_comments(shift);
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci    if (!$rfc822re) {
25848c2ecf20Sopenharmony_ci        $rfc822re = make_rfc822re();
25858c2ecf20Sopenharmony_ci    }
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci    return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/;
25888c2ecf20Sopenharmony_ci}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci#   validlist: In scalar context, returns true if the parameter is an RFC822
25918c2ecf20Sopenharmony_ci#              valid list of addresses.
25928c2ecf20Sopenharmony_ci#
25938c2ecf20Sopenharmony_ci#              In list context, returns an empty list on failure (an invalid
25948c2ecf20Sopenharmony_ci#              address was found); otherwise a list whose first element is the
25958c2ecf20Sopenharmony_ci#              number of addresses found and whose remaining elements are the
25968c2ecf20Sopenharmony_ci#              addresses.  This is needed to disambiguate failure (invalid)
25978c2ecf20Sopenharmony_ci#              from success with no addresses found, because an empty string is
25988c2ecf20Sopenharmony_ci#              a valid list.
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_cisub rfc822_validlist {
26018c2ecf20Sopenharmony_ci    my $s = rfc822_strip_comments(shift);
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci    if (!$rfc822re) {
26048c2ecf20Sopenharmony_ci        $rfc822re = make_rfc822re();
26058c2ecf20Sopenharmony_ci    }
26068c2ecf20Sopenharmony_ci    # * null list items are valid according to the RFC
26078c2ecf20Sopenharmony_ci    # * the '1' business is to aid in distinguishing failure from no results
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci    my @r;
26108c2ecf20Sopenharmony_ci    if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so &&
26118c2ecf20Sopenharmony_ci	$s =~ m/^$rfc822_char*$/) {
26128c2ecf20Sopenharmony_ci        while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) {
26138c2ecf20Sopenharmony_ci            push(@r, $1);
26148c2ecf20Sopenharmony_ci        }
26158c2ecf20Sopenharmony_ci        return wantarray ? (scalar(@r), @r) : 1;
26168c2ecf20Sopenharmony_ci    }
26178c2ecf20Sopenharmony_ci    return wantarray ? () : 0;
26188c2ecf20Sopenharmony_ci}
2619