~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/get_maintainer.pl

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /scripts/get_maintainer.pl (Version linux-6.11.5) and /scripts/get_maintainer.pl (Version linux-3.10.108)


  1 #!/usr/bin/env perl                            !!   1 #!/usr/bin/perl -w
  2 # SPDX-License-Identifier: GPL-2.0             << 
  3 #                                              << 
  4 # (c) 2007, Joe Perches <joe@perches.com>            2 # (c) 2007, Joe Perches <joe@perches.com>
  5 #           created from checkpatch.pl              3 #           created from checkpatch.pl
  6 #                                                   4 #
  7 # Print selected MAINTAINERS information for        5 # Print selected MAINTAINERS information for
  8 # the files modified in a patch or for a file       6 # the files modified in a patch or for a file
  9 #                                                   7 #
 10 # usage: perl scripts/get_maintainer.pl [OPTIO      8 # usage: perl scripts/get_maintainer.pl [OPTIONS] <patch>
 11 #        perl scripts/get_maintainer.pl [OPTIO      9 #        perl scripts/get_maintainer.pl [OPTIONS] -f <file>
                                                   >>  10 #
                                                   >>  11 # Licensed under the terms of the GNU GPL License version 2
 12                                                    12 
 13 use warnings;                                  << 
 14 use strict;                                        13 use strict;
 15                                                    14 
 16 my $P = $0;                                        15 my $P = $0;
 17 my $V = '0.26';                                    16 my $V = '0.26';
 18                                                    17 
 19 use Getopt::Long qw(:config no_auto_abbrev);       18 use Getopt::Long qw(:config no_auto_abbrev);
 20 use Cwd;                                       << 
 21 use File::Find;                                << 
 22 use File::Spec::Functions;                     << 
 23 use open qw(:std :encoding(UTF-8));            << 
 24                                                    19 
 25 my $cur_path = fastgetcwd() . '/';             << 
 26 my $lk_path = "./";                                20 my $lk_path = "./";
 27 my $email = 1;                                     21 my $email = 1;
 28 my $email_usename = 1;                             22 my $email_usename = 1;
 29 my $email_maintainer = 1;                          23 my $email_maintainer = 1;
 30 my $email_reviewer = 1;                        << 
 31 my $email_fixes = 1;                           << 
 32 my $email_list = 1;                                24 my $email_list = 1;
 33 my $email_moderated_list = 1;                  << 
 34 my $email_subscriber_list = 0;                     25 my $email_subscriber_list = 0;
 35 my $email_git_penguin_chiefs = 0;                  26 my $email_git_penguin_chiefs = 0;
 36 my $email_git = 0;                                 27 my $email_git = 0;
 37 my $email_git_all_signature_types = 0;             28 my $email_git_all_signature_types = 0;
 38 my $email_git_blame = 0;                           29 my $email_git_blame = 0;
 39 my $email_git_blame_signatures = 1;                30 my $email_git_blame_signatures = 1;
 40 my $email_git_fallback = 1;                        31 my $email_git_fallback = 1;
 41 my $email_git_min_signatures = 1;                  32 my $email_git_min_signatures = 1;
 42 my $email_git_max_maintainers = 5;                 33 my $email_git_max_maintainers = 5;
 43 my $email_git_min_percent = 5;                     34 my $email_git_min_percent = 5;
 44 my $email_git_since = "1-year-ago";                35 my $email_git_since = "1-year-ago";
 45 my $email_hg_since = "-365";                       36 my $email_hg_since = "-365";
 46 my $interactive = 0;                               37 my $interactive = 0;
 47 my $email_remove_duplicates = 1;                   38 my $email_remove_duplicates = 1;
 48 my $email_use_mailmap = 1;                         39 my $email_use_mailmap = 1;
 49 my $output_multiline = 1;                          40 my $output_multiline = 1;
 50 my $output_separator = ", ";                       41 my $output_separator = ", ";
 51 my $output_roles = 0;                              42 my $output_roles = 0;
 52 my $output_rolestats = 1;                          43 my $output_rolestats = 1;
 53 my $output_section_maxlen = 50;                << 
 54 my $scm = 0;                                       44 my $scm = 0;
 55 my $tree = 1;                                  << 
 56 my $web = 0;                                       45 my $web = 0;
 57 my $subsystem = 0;                                 46 my $subsystem = 0;
 58 my $status = 0;                                    47 my $status = 0;
 59 my $letters = "";                              << 
 60 my $keywords = 1;                                  48 my $keywords = 1;
 61 my $keywords_in_file = 0;                      << 
 62 my $sections = 0;                                  49 my $sections = 0;
 63 my $email_file_emails = 0;                     !!  50 my $file_emails = 0;
 64 my $from_filename = 0;                             51 my $from_filename = 0;
 65 my $pattern_depth = 0;                             52 my $pattern_depth = 0;
 66 my $self_test = undef;                         << 
 67 my $version = 0;                                   53 my $version = 0;
 68 my $help = 0;                                      54 my $help = 0;
 69 my $find_maintainer_files = 0;                 !!  55 
 70 my $maintainer_path;                           << 
 71 my $vcs_used = 0;                                  56 my $vcs_used = 0;
 72                                                    57 
 73 my $exit = 0;                                      58 my $exit = 0;
 74                                                    59 
 75 my @files = ();                                << 
 76 my @fixes = ();                 # If a patch d << 
 77 my @range = ();                                << 
 78 my @keyword_tvi = ();                          << 
 79 my @file_emails = ();                          << 
 80                                                << 
 81 my %commit_author_hash;                            60 my %commit_author_hash;
 82 my %commit_signer_hash;                            61 my %commit_signer_hash;
 83                                                    62 
 84 my @penguin_chief = ();                            63 my @penguin_chief = ();
 85 push(@penguin_chief, "Linus Torvalds:torvalds\     64 push(@penguin_chief, "Linus Torvalds:torvalds\@linux-foundation.org");
 86 #Andrew wants in on most everything - 2009/01/     65 #Andrew wants in on most everything - 2009/01/14
 87 #push(@penguin_chief, "Andrew Morton:akpm\@lin     66 #push(@penguin_chief, "Andrew Morton:akpm\@linux-foundation.org");
 88                                                    67 
 89 my @penguin_chief_names = ();                      68 my @penguin_chief_names = ();
 90 foreach my $chief (@penguin_chief) {               69 foreach my $chief (@penguin_chief) {
 91     if ($chief =~ m/^(.*):(.*)/) {                 70     if ($chief =~ m/^(.*):(.*)/) {
 92         my $chief_name = $1;                       71         my $chief_name = $1;
 93         my $chief_addr = $2;                       72         my $chief_addr = $2;
 94         push(@penguin_chief_names, $chief_name     73         push(@penguin_chief_names, $chief_name);
 95     }                                              74     }
 96 }                                                  75 }
 97 my $penguin_chiefs = "\(" . join("|", @penguin     76 my $penguin_chiefs = "\(" . join("|", @penguin_chief_names) . "\)";
 98                                                    77 
 99 # Signature types of people who are either         78 # Signature types of people who are either
100 #       a) responsible for the code in questio     79 #       a) responsible for the code in question, or
101 #       b) familiar enough with it to give rel     80 #       b) familiar enough with it to give relevant feedback
102 my @signature_tags = ();                           81 my @signature_tags = ();
103 push(@signature_tags, "Signed-off-by:");           82 push(@signature_tags, "Signed-off-by:");
104 push(@signature_tags, "Reviewed-by:");             83 push(@signature_tags, "Reviewed-by:");
105 push(@signature_tags, "Acked-by:");                84 push(@signature_tags, "Acked-by:");
106                                                    85 
107 my $signature_pattern = "\(" . join("|", @sign     86 my $signature_pattern = "\(" . join("|", @signature_tags) . "\)";
108                                                    87 
109 # rfc822 email address - preloaded methods go      88 # rfc822 email address - preloaded methods go here.
110 my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";         89 my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
111 my $rfc822_char = '[\\000-\\377]';                 90 my $rfc822_char = '[\\000-\\377]';
112                                                    91 
113 # VCS command support: class-like functions an     92 # VCS command support: class-like functions and strings
114                                                    93 
115 my %VCS_cmds;                                      94 my %VCS_cmds;
116                                                    95 
117 my %VCS_cmds_git = (                               96 my %VCS_cmds_git = (
118     "execute_cmd" => \&git_execute_cmd,            97     "execute_cmd" => \&git_execute_cmd,
119     "available" => '(which("git") ne "") && (- !!  98     "available" => '(which("git") ne "") && (-d ".git")',
120     "find_signers_cmd" =>                          99     "find_signers_cmd" =>
121         "git log --no-color --follow --since=\    100         "git log --no-color --follow --since=\$email_git_since " .
122             '--numstat --no-merges ' .         << 
123             '--format="GitCommit: %H%n' .         101             '--format="GitCommit: %H%n' .
124                       'GitAuthor: %an <%ae>%n'    102                       'GitAuthor: %an <%ae>%n' .
125                       'GitDate: %aD%n' .          103                       'GitDate: %aD%n' .
126                       'GitSubject: %s%n' .        104                       'GitSubject: %s%n' .
127                       '%b%n"' .                   105                       '%b%n"' .
128             " -- \$file",                         106             " -- \$file",
129     "find_commit_signers_cmd" =>                  107     "find_commit_signers_cmd" =>
130         "git log --no-color " .                   108         "git log --no-color " .
131             '--numstat ' .                     << 
132             '--format="GitCommit: %H%n' .         109             '--format="GitCommit: %H%n' .
133                       'GitAuthor: %an <%ae>%n'    110                       'GitAuthor: %an <%ae>%n' .
134                       'GitDate: %aD%n' .          111                       'GitDate: %aD%n' .
135                       'GitSubject: %s%n' .        112                       'GitSubject: %s%n' .
136                       '%b%n"' .                   113                       '%b%n"' .
137             " -1 \$commit",                       114             " -1 \$commit",
138     "find_commit_author_cmd" =>                   115     "find_commit_author_cmd" =>
139         "git log --no-color " .                   116         "git log --no-color " .
140             '--numstat ' .                     << 
141             '--format="GitCommit: %H%n' .         117             '--format="GitCommit: %H%n' .
142                       'GitAuthor: %an <%ae>%n'    118                       'GitAuthor: %an <%ae>%n' .
143                       'GitDate: %aD%n' .          119                       'GitDate: %aD%n' .
144                       'GitSubject: %s%n"' .       120                       'GitSubject: %s%n"' .
145             " -1 \$commit",                       121             " -1 \$commit",
146     "blame_range_cmd" => "git blame -l -L \$di    122     "blame_range_cmd" => "git blame -l -L \$diff_start,+\$diff_length \$file",
147     "blame_file_cmd" => "git blame -l \$file",    123     "blame_file_cmd" => "git blame -l \$file",
148     "commit_pattern" => "^GitCommit: ([0-9a-f]    124     "commit_pattern" => "^GitCommit: ([0-9a-f]{40,40})",
149     "blame_commit_pattern" => "^([0-9a-f]+) ",    125     "blame_commit_pattern" => "^([0-9a-f]+) ",
150     "author_pattern" => "^GitAuthor: (.*)",       126     "author_pattern" => "^GitAuthor: (.*)",
151     "subject_pattern" => "^GitSubject: (.*)",     127     "subject_pattern" => "^GitSubject: (.*)",
152     "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$fi << 
153     "file_exists_cmd" => "git ls-files \$file" << 
154     "list_files_cmd" => "git ls-files \$file", << 
155 );                                                128 );
156                                                   129 
157 my %VCS_cmds_hg = (                               130 my %VCS_cmds_hg = (
158     "execute_cmd" => \&hg_execute_cmd,            131     "execute_cmd" => \&hg_execute_cmd,
159     "available" => '(which("hg") ne "") && (-d    132     "available" => '(which("hg") ne "") && (-d ".hg")',
160     "find_signers_cmd" =>                         133     "find_signers_cmd" =>
161         "hg log --date=\$email_hg_since " .       134         "hg log --date=\$email_hg_since " .
162             "--template='HgCommit: {node}\\n"     135             "--template='HgCommit: {node}\\n" .
163                         "HgAuthor: {author}\\n    136                         "HgAuthor: {author}\\n" .
164                         "HgSubject: {desc}\\n'    137                         "HgSubject: {desc}\\n'" .
165             " -- \$file",                         138             " -- \$file",
166     "find_commit_signers_cmd" =>                  139     "find_commit_signers_cmd" =>
167         "hg log " .                               140         "hg log " .
168             "--template='HgSubject: {desc}\\n'    141             "--template='HgSubject: {desc}\\n'" .
169             " -r \$commit",                       142             " -r \$commit",
170     "find_commit_author_cmd" =>                   143     "find_commit_author_cmd" =>
171         "hg log " .                               144         "hg log " .
172             "--template='HgCommit: {node}\\n"     145             "--template='HgCommit: {node}\\n" .
173                         "HgAuthor: {author}\\n    146                         "HgAuthor: {author}\\n" .
174                         "HgSubject: {desc|firs    147                         "HgSubject: {desc|firstline}\\n'" .
175             " -r \$commit",                       148             " -r \$commit",
176     "blame_range_cmd" => "",            # not     149     "blame_range_cmd" => "",            # not supported
177     "blame_file_cmd" => "hg blame -n \$file",     150     "blame_file_cmd" => "hg blame -n \$file",
178     "commit_pattern" => "^HgCommit: ([0-9a-f]{    151     "commit_pattern" => "^HgCommit: ([0-9a-f]{40,40})",
179     "blame_commit_pattern" => "^([ 0-9a-f]+):"    152     "blame_commit_pattern" => "^([ 0-9a-f]+):",
180     "author_pattern" => "^HgAuthor: (.*)",        153     "author_pattern" => "^HgAuthor: (.*)",
181     "subject_pattern" => "^HgSubject: (.*)",      154     "subject_pattern" => "^HgSubject: (.*)",
182     "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file << 
183     "file_exists_cmd" => "hg files \$file",    << 
184     "list_files_cmd" => "hg manifest -R \$file << 
185 );                                                155 );
186                                                   156 
187 my $conf = which_conf(".get_maintainer.conf");    157 my $conf = which_conf(".get_maintainer.conf");
188 if (-f $conf) {                                   158 if (-f $conf) {
189     my @conf_args;                                159     my @conf_args;
190     open(my $conffile, '<', "$conf")              160     open(my $conffile, '<', "$conf")
191         or warn "$P: Can't find a readable .ge    161         or warn "$P: Can't find a readable .get_maintainer.conf file $!\n";
192                                                   162 
193     while (<$conffile>) {                         163     while (<$conffile>) {
194         my $line = $_;                            164         my $line = $_;
195                                                   165 
196         $line =~ s/\s*\n?$//g;                    166         $line =~ s/\s*\n?$//g;
197         $line =~ s/^\s*//g;                       167         $line =~ s/^\s*//g;
198         $line =~ s/\s+/ /g;                       168         $line =~ s/\s+/ /g;
199                                                   169 
200         next if ($line =~ m/^\s*#/);              170         next if ($line =~ m/^\s*#/);
201         next if ($line =~ m/^\s*$/);              171         next if ($line =~ m/^\s*$/);
202                                                   172 
203         my @words = split(" ", $line);            173         my @words = split(" ", $line);
204         foreach my $word (@words) {               174         foreach my $word (@words) {
205             last if ($word =~ m/^#/);             175             last if ($word =~ m/^#/);
206             push (@conf_args, $word);             176             push (@conf_args, $word);
207         }                                         177         }
208     }                                             178     }
209     close($conffile);                             179     close($conffile);
210     unshift(@ARGV, @conf_args) if @conf_args;     180     unshift(@ARGV, @conf_args) if @conf_args;
211 }                                                 181 }
212                                                   182 
213 my @ignore_emails = ();                        << 
214 my $ignore_file = which_conf(".get_maintainer. << 
215 if (-f $ignore_file) {                         << 
216     open(my $ignore, '<', "$ignore_file")      << 
217         or warn "$P: Can't find a readable .ge << 
218     while (<$ignore>) {                        << 
219         my $line = $_;                         << 
220                                                << 
221         $line =~ s/\s*\n?$//;                  << 
222         $line =~ s/^\s*//;                     << 
223         $line =~ s/\s+$//;                     << 
224         $line =~ s/#.*$//;                     << 
225                                                << 
226         next if ($line =~ m/^\s*$/);           << 
227         if (rfc822_valid($line)) {             << 
228             push(@ignore_emails, $line);       << 
229         }                                      << 
230     }                                          << 
231     close($ignore);                            << 
232 }                                              << 
233                                                << 
234 if ($#ARGV > 0) {                              << 
235     foreach (@ARGV) {                          << 
236         if ($_ =~ /^-{1,2}self-test(?:=|$)/) { << 
237             die "$P: using --self-test does no << 
238         }                                      << 
239     }                                          << 
240 }                                              << 
241                                                << 
242 if (!GetOptions(                                  183 if (!GetOptions(
243                 'email!' => \$email,              184                 'email!' => \$email,
244                 'git!' => \$email_git,            185                 'git!' => \$email_git,
245                 'git-all-signature-types!' =>     186                 'git-all-signature-types!' => \$email_git_all_signature_types,
246                 'git-blame!' => \$email_git_bl    187                 'git-blame!' => \$email_git_blame,
247                 'git-blame-signatures!' => \$e    188                 'git-blame-signatures!' => \$email_git_blame_signatures,
248                 'git-fallback!' => \$email_git    189                 'git-fallback!' => \$email_git_fallback,
249                 'git-chief-penguins!' => \$ema    190                 'git-chief-penguins!' => \$email_git_penguin_chiefs,
250                 'git-min-signatures=i' => \$em    191                 'git-min-signatures=i' => \$email_git_min_signatures,
251                 'git-max-maintainers=i' => \$e    192                 'git-max-maintainers=i' => \$email_git_max_maintainers,
252                 'git-min-percent=i' => \$email    193                 'git-min-percent=i' => \$email_git_min_percent,
253                 'git-since=s' => \$email_git_s    194                 'git-since=s' => \$email_git_since,
254                 'hg-since=s' => \$email_hg_sin    195                 'hg-since=s' => \$email_hg_since,
255                 'i|interactive!' => \$interact    196                 'i|interactive!' => \$interactive,
256                 'remove-duplicates!' => \$emai    197                 'remove-duplicates!' => \$email_remove_duplicates,
257                 'mailmap!' => \$email_use_mail    198                 'mailmap!' => \$email_use_mailmap,
258                 'm!' => \$email_maintainer,       199                 'm!' => \$email_maintainer,
259                 'r!' => \$email_reviewer,      << 
260                 'n!' => \$email_usename,          200                 'n!' => \$email_usename,
261                 'l!' => \$email_list,             201                 'l!' => \$email_list,
262                 'fixes!' => \$email_fixes,     << 
263                 'moderated!' => \$email_modera << 
264                 's!' => \$email_subscriber_lis    202                 's!' => \$email_subscriber_list,
265                 'multiline!' => \$output_multi    203                 'multiline!' => \$output_multiline,
266                 'roles!' => \$output_roles,       204                 'roles!' => \$output_roles,
267                 'rolestats!' => \$output_roles    205                 'rolestats!' => \$output_rolestats,
268                 'separator=s' => \$output_sepa    206                 'separator=s' => \$output_separator,
269                 'subsystem!' => \$subsystem,      207                 'subsystem!' => \$subsystem,
270                 'status!' => \$status,            208                 'status!' => \$status,
271                 'scm!' => \$scm,                  209                 'scm!' => \$scm,
272                 'tree!' => \$tree,             << 
273                 'web!' => \$web,                  210                 'web!' => \$web,
274                 'letters=s' => \$letters,      << 
275                 'pattern-depth=i' => \$pattern    211                 'pattern-depth=i' => \$pattern_depth,
276                 'k|keywords!' => \$keywords,      212                 'k|keywords!' => \$keywords,
277                 'kf|keywords-in-file!' => \$ke << 
278                 'sections!' => \$sections,        213                 'sections!' => \$sections,
279                 'fe|file-emails!' => \$email_f !! 214                 'fe|file-emails!' => \$file_emails,
280                 'f|file' => \$from_filename,      215                 'f|file' => \$from_filename,
281                 'find-maintainer-files' => \$f << 
282                 'mpath|maintainer-path=s' => \ << 
283                 'self-test:s' => \$self_test,  << 
284                 'v|version' => \$version,         216                 'v|version' => \$version,
285                 'h|help|usage' => \$help,         217                 'h|help|usage' => \$help,
286                 )) {                              218                 )) {
287     die "$P: invalid argument - use --help if     219     die "$P: invalid argument - use --help if necessary\n";
288 }                                                 220 }
289                                                   221 
290 if ($help != 0) {                                 222 if ($help != 0) {
291     usage();                                      223     usage();
292     exit 0;                                       224     exit 0;
293 }                                                 225 }
294                                                   226 
295 if ($version != 0) {                              227 if ($version != 0) {
296     print("${P} ${V}\n");                         228     print("${P} ${V}\n");
297     exit 0;                                       229     exit 0;
298 }                                                 230 }
299                                                   231 
300 if (defined $self_test) {                      << 
301     read_all_maintainer_files();               << 
302     self_test();                               << 
303     exit 0;                                    << 
304 }                                              << 
305                                                << 
306 if (-t STDIN && !@ARGV) {                         232 if (-t STDIN && !@ARGV) {
307     # We're talking to a terminal, but have no    233     # We're talking to a terminal, but have no command line arguments.
308     die "$P: missing patchfile or -f file - us    234     die "$P: missing patchfile or -f file - use --help if necessary\n";
309 }                                                 235 }
310                                                   236 
311 $output_multiline = 0 if ($output_separator ne    237 $output_multiline = 0 if ($output_separator ne ", ");
312 $output_rolestats = 1 if ($interactive);          238 $output_rolestats = 1 if ($interactive);
313 $output_roles = 1 if ($output_rolestats);         239 $output_roles = 1 if ($output_rolestats);
314                                                   240 
315 if ($sections || $letters ne "") {             !! 241 if ($sections) {
316     $sections = 1;                             << 
317     $email = 0;                                   242     $email = 0;
318     $email_list = 0;                              243     $email_list = 0;
319     $scm = 0;                                     244     $scm = 0;
320     $status = 0;                                  245     $status = 0;
321     $subsystem = 0;                               246     $subsystem = 0;
322     $web = 0;                                     247     $web = 0;
323     $keywords = 0;                                248     $keywords = 0;
324     $keywords_in_file = 0;                     << 
325     $interactive = 0;                             249     $interactive = 0;
326 } else {                                          250 } else {
327     my $selections = $email + $scm + $status +    251     my $selections = $email + $scm + $status + $subsystem + $web;
328     if ($selections == 0) {                       252     if ($selections == 0) {
329         die "$P:  Missing required option: ema    253         die "$P:  Missing required option: email, scm, status, subsystem or web\n";
330     }                                             254     }
331 }                                                 255 }
332                                                   256 
333 if ($email &&                                     257 if ($email &&
334     ($email_maintainer + $email_reviewer +     !! 258     ($email_maintainer + $email_list + $email_subscriber_list +
335      $email_list + $email_subscriber_list +    << 
336      $email_git + $email_git_penguin_chiefs +     259      $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) {
337     die "$P: Please select at least 1 email op    260     die "$P: Please select at least 1 email option\n";
338 }                                                 261 }
339                                                   262 
340 if ($tree && !top_of_kernel_tree($lk_path)) {  !! 263 if (!top_of_kernel_tree($lk_path)) {
341     die "$P: The current directory does not ap    264     die "$P: The current directory does not appear to be "
342         . "a linux kernel source tree.\n";        265         . "a linux kernel source tree.\n";
343 }                                                 266 }
344                                                   267 
345 ## Read MAINTAINERS for type/value pairs          268 ## Read MAINTAINERS for type/value pairs
346                                                   269 
347 my @typevalue = ();                               270 my @typevalue = ();
348 my %keyword_hash;                                 271 my %keyword_hash;
349 my @mfiles = ();                               << 
350 my @self_test_info = ();                       << 
351                                                << 
352 sub read_maintainer_file {                     << 
353     my ($file) = @_;                           << 
354                                                << 
355     open (my $maint, '<', "$file")             << 
356         or die "$P: Can't open MAINTAINERS fil << 
357     my $i = 1;                                 << 
358     while (<$maint>) {                         << 
359         my $line = $_;                         << 
360         chomp $line;                           << 
361                                                << 
362         if ($line =~ m/^([A-Z]):\s*(.*)/) {    << 
363             my $type = $1;                     << 
364             my $value = $2;                    << 
365                                                << 
366             ##Filename pattern matching        << 
367             if ($type eq "F" || $type eq "X")  << 
368                 $value =~ s@\.@\\\.@g;       # << 
369                 $value =~ s/\*/\.\*/g;       # << 
370                 $value =~ s/\?/\./g;         # << 
371                 ##if pattern is a directory an << 
372                 if ((-d $value)) {             << 
373                     $value =~ s@([^/])$@$1/@;  << 
374                 }                              << 
375             } elsif ($type eq "K") {           << 
376                 $keyword_hash{@typevalue} = $v << 
377             }                                  << 
378             push(@typevalue, "$type:$value");  << 
379         } elsif (!(/^\s*$/ || /^\s*\#/)) {     << 
380             push(@typevalue, $line);           << 
381         }                                      << 
382         if (defined $self_test) {              << 
383             push(@self_test_info, {file=>$file << 
384         }                                      << 
385         $i++;                                  << 
386     }                                          << 
387     close($maint);                             << 
388 }                                              << 
389                                                << 
390 sub find_is_maintainer_file {                  << 
391     my ($file) = $_;                           << 
392     return if ($file !~ m@/MAINTAINERS$@);     << 
393     $file = $File::Find::name;                 << 
394     return if (! -f $file);                    << 
395     push(@mfiles, $file);                      << 
396 }                                              << 
397                                                   272 
398 sub find_ignore_git {                          !! 273 open (my $maint, '<', "${lk_path}MAINTAINERS")
399     return grep { $_ !~ /^\.git$/; } @_;       !! 274     or die "$P: Can't open MAINTAINERS: $!\n";
400 }                                              !! 275 while (<$maint>) {
                                                   >> 276     my $line = $_;
401                                                   277 
402 read_all_maintainer_files();                   !! 278     if ($line =~ m/^(\C):\s*(.*)/) {
403                                                !! 279         my $type = $1;
404 sub read_all_maintainer_files {                !! 280         my $value = $2;
405     my $path = "${lk_path}MAINTAINERS";        << 
406     if (defined $maintainer_path) {            << 
407         $path = $maintainer_path;              << 
408         # Perl Cookbook tilde expansion if nec << 
409         $path =~ s@^~([^/]*)@ $1 ? (getpwnam($ << 
410     }                                          << 
411                                                   281 
412     if (-d $path) {                            !! 282         ##Filename pattern matching
413         $path .= '/' if ($path !~ m@/$@);      !! 283         if ($type eq "F" || $type eq "X") {
414         if ($find_maintainer_files) {          !! 284             $value =~ s@\.@\\\.@g;       ##Convert . to \.
415             find( { wanted => \&find_is_mainta !! 285             $value =~ s/\*/\.\*/g;       ##Convert * to .*
416                     preprocess => \&find_ignor !! 286             $value =~ s/\?/\./g;         ##Convert ? to .
417                     no_chdir => 1,             !! 287             ##if pattern is a directory and it lacks a trailing slash, add one
418                 }, "$path");                   !! 288             if ((-d $value)) {
419         } else {                               !! 289                 $value =~ s@([^/])$@$1/@;
420             opendir(DIR, "$path") or die $!;   << 
421             my @files = readdir(DIR);          << 
422             closedir(DIR);                     << 
423             foreach my $file (@files) {        << 
424                 push(@mfiles, "$path$file") if << 
425             }                                     290             }
                                                   >> 291         } elsif ($type eq "K") {
                                                   >> 292             $keyword_hash{@typevalue} = $value;
426         }                                         293         }
427     } elsif (-f "$path") {                     !! 294         push(@typevalue, "$type:$value");
428         push(@mfiles, "$path");                !! 295     } elsif (!/^(\s)*$/) {
429     } else {                                   !! 296         $line =~ s/\n$//g;
430         die "$P: MAINTAINER file not found '$p !! 297         push(@typevalue, $line);
431     }                                          << 
432     die "$P: No MAINTAINER files found in '$pa << 
433     foreach my $file (@mfiles) {               << 
434         read_maintainer_file("$file");         << 
435     }                                             298     }
436 }                                                 299 }
                                                   >> 300 close($maint);
437                                                   301 
438 sub maintainers_in_file {                      << 
439     my ($file) = @_;                           << 
440                                                << 
441     return if ($file =~ m@\bMAINTAINERS$@);    << 
442                                                << 
443     if (-f $file && ($email_file_emails || $fi << 
444         open(my $f, '<', $file)                << 
445             or die "$P: Can't open $file: $!\n << 
446         my $text = do { local($/) ; <$f> };    << 
447         close($f);                             << 
448                                                << 
449         my @poss_addr = $text =~ m$[\p{L}\"\' < << 
450         push(@file_emails, clean_file_emails(@ << 
451     }                                          << 
452 }                                              << 
453                                                   302 
454 #                                                 303 #
455 # Read mail address map                           304 # Read mail address map
456 #                                                 305 #
457                                                   306 
458 my $mailmap;                                      307 my $mailmap;
459                                                   308 
460 read_mailmap();                                   309 read_mailmap();
461                                                   310 
462 sub read_mailmap {                                311 sub read_mailmap {
463     $mailmap = {                                  312     $mailmap = {
464         names => {},                              313         names => {},
465         addresses => {}                           314         addresses => {}
466     };                                            315     };
467                                                   316 
468     return if (!$email_use_mailmap || !(-f "${    317     return if (!$email_use_mailmap || !(-f "${lk_path}.mailmap"));
469                                                   318 
470     open(my $mailmap_file, '<', "${lk_path}.ma    319     open(my $mailmap_file, '<', "${lk_path}.mailmap")
471         or warn "$P: Can't open .mailmap: $!\n    320         or warn "$P: Can't open .mailmap: $!\n";
472                                                   321 
473     while (<$mailmap_file>) {                     322     while (<$mailmap_file>) {
474         s/#.*$//; #strip comments                 323         s/#.*$//; #strip comments
475         s/^\s+|\s+$//g; #trim                     324         s/^\s+|\s+$//g; #trim
476                                                   325 
477         next if (/^\s*$/); #skip empty lines      326         next if (/^\s*$/); #skip empty lines
478         #entries have one of the following for    327         #entries have one of the following formats:
479         # name1 <mail1>                           328         # name1 <mail1>
480         # <mail1> <mail2>                         329         # <mail1> <mail2>
481         # name1 <mail1> <mail2>                   330         # name1 <mail1> <mail2>
482         # name1 <mail1> name2 <mail2>             331         # name1 <mail1> name2 <mail2>
483         # (see man git-shortlog)                  332         # (see man git-shortlog)
484                                                   333 
485         if (/^([^<]+)<([^>]+)>$/) {               334         if (/^([^<]+)<([^>]+)>$/) {
486             my $real_name = $1;                   335             my $real_name = $1;
487             my $address = $2;                     336             my $address = $2;
488                                                   337 
489             $real_name =~ s/\s+$//;               338             $real_name =~ s/\s+$//;
490             ($real_name, $address) = parse_ema    339             ($real_name, $address) = parse_email("$real_name <$address>");
491             $mailmap->{names}->{$address} = $r    340             $mailmap->{names}->{$address} = $real_name;
492                                                   341 
493         } elsif (/^<([^>]+)>\s*<([^>]+)>$/) {     342         } elsif (/^<([^>]+)>\s*<([^>]+)>$/) {
494             my $real_address = $1;                343             my $real_address = $1;
495             my $wrong_address = $2;               344             my $wrong_address = $2;
496                                                   345 
497             $mailmap->{addresses}->{$wrong_add    346             $mailmap->{addresses}->{$wrong_address} = $real_address;
498                                                   347 
499         } elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/    348         } elsif (/^(.+)<([^>]+)>\s*<([^>]+)>$/) {
500             my $real_name = $1;                   349             my $real_name = $1;
501             my $real_address = $2;                350             my $real_address = $2;
502             my $wrong_address = $3;               351             my $wrong_address = $3;
503                                                   352 
504             $real_name =~ s/\s+$//;               353             $real_name =~ s/\s+$//;
505             ($real_name, $real_address) =         354             ($real_name, $real_address) =
506                 parse_email("$real_name <$real    355                 parse_email("$real_name <$real_address>");
507             $mailmap->{names}->{$wrong_address    356             $mailmap->{names}->{$wrong_address} = $real_name;
508             $mailmap->{addresses}->{$wrong_add    357             $mailmap->{addresses}->{$wrong_address} = $real_address;
509                                                   358 
510         } elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^    359         } elsif (/^(.+)<([^>]+)>\s*(.+)\s*<([^>]+)>$/) {
511             my $real_name = $1;                   360             my $real_name = $1;
512             my $real_address = $2;                361             my $real_address = $2;
513             my $wrong_name = $3;                  362             my $wrong_name = $3;
514             my $wrong_address = $4;               363             my $wrong_address = $4;
515                                                   364 
516             $real_name =~ s/\s+$//;               365             $real_name =~ s/\s+$//;
517             ($real_name, $real_address) =         366             ($real_name, $real_address) =
518                 parse_email("$real_name <$real    367                 parse_email("$real_name <$real_address>");
519                                                   368 
520             $wrong_name =~ s/\s+$//;              369             $wrong_name =~ s/\s+$//;
521             ($wrong_name, $wrong_address) =       370             ($wrong_name, $wrong_address) =
522                 parse_email("$wrong_name <$wro    371                 parse_email("$wrong_name <$wrong_address>");
523                                                   372 
524             my $wrong_email = format_email($wr    373             my $wrong_email = format_email($wrong_name, $wrong_address, 1);
525             $mailmap->{names}->{$wrong_email}     374             $mailmap->{names}->{$wrong_email} = $real_name;
526             $mailmap->{addresses}->{$wrong_ema    375             $mailmap->{addresses}->{$wrong_email} = $real_address;
527         }                                         376         }
528     }                                             377     }
529     close($mailmap_file);                         378     close($mailmap_file);
530 }                                                 379 }
531                                                   380 
532 ## use the filenames on the command line or fi    381 ## use the filenames on the command line or find the filenames in the patchfiles
533                                                   382 
                                                   >> 383 my @files = ();
                                                   >> 384 my @range = ();
                                                   >> 385 my @keyword_tvi = ();
                                                   >> 386 my @file_emails = ();
                                                   >> 387 
534 if (!@ARGV) {                                     388 if (!@ARGV) {
535     push(@ARGV, "&STDIN");                        389     push(@ARGV, "&STDIN");
536 }                                                 390 }
537                                                   391 
538 foreach my $file (@ARGV) {                        392 foreach my $file (@ARGV) {
539     if ($file ne "&STDIN") {                      393     if ($file ne "&STDIN") {
540         $file = canonpath($file);              << 
541         ##if $file is a directory and it lacks    394         ##if $file is a directory and it lacks a trailing slash, add one
542         if ((-d $file)) {                         395         if ((-d $file)) {
543             $file =~ s@([^/])$@$1/@;              396             $file =~ s@([^/])$@$1/@;
544         } elsif (!(-f $file)) {                   397         } elsif (!(-f $file)) {
545             die "$P: file '${file}' not found\    398             die "$P: file '${file}' not found\n";
546         }                                         399         }
547     }                                             400     }
548     if ($from_filename && (vcs_exists() && !vc !! 401     if ($from_filename) {
549         warn "$P: file '$file' not found in ve << 
550     }                                          << 
551     if ($from_filename || ($file ne "&STDIN" & << 
552         $file =~ s/^\Q${cur_path}\E//;  #strip << 
553         $file =~ s/^\Q${lk_path}\E//;   #or th << 
554         push(@files, $file);                      402         push(@files, $file);
555         if ($file ne "MAINTAINERS" && -f $file !! 403         if ($file ne "MAINTAINERS" && -f $file && ($keywords || $file_emails)) {
556             open(my $f, '<', $file)               404             open(my $f, '<', $file)
557                 or die "$P: Can't open $file:     405                 or die "$P: Can't open $file: $!\n";
558             my $text = do { local($/) ; <$f> }    406             my $text = do { local($/) ; <$f> };
559             close($f);                            407             close($f);
560             foreach my $line (keys %keyword_ha !! 408             if ($keywords) {
561                 if ($text =~ m/$keyword_hash{$ !! 409                 foreach my $line (keys %keyword_hash) {
562                     push(@keyword_tvi, $line); !! 410                     if ($text =~ m/$keyword_hash{$line}/x) {
                                                   >> 411                         push(@keyword_tvi, $line);
                                                   >> 412                     }
563                 }                                 413                 }
564             }                                     414             }
                                                   >> 415             if ($file_emails) {
                                                   >> 416                 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;
                                                   >> 417                 push(@file_emails, clean_file_emails(@poss_addr));
                                                   >> 418             }
565         }                                         419         }
566     } else {                                      420     } else {
567         my $file_cnt = @files;                    421         my $file_cnt = @files;
568         my $lastfile;                             422         my $lastfile;
569                                                   423 
570         open(my $patch, "< $file")                424         open(my $patch, "< $file")
571             or die "$P: Can't open $file: $!\n    425             or die "$P: Can't open $file: $!\n";
572                                                   426 
573         # We can check arbitrary information b    427         # We can check arbitrary information before the patch
574         # like the commit message, mail header    428         # like the commit message, mail headers, etc...
575         # This allows us to match arbitrary ke    429         # This allows us to match arbitrary keywords against any part
576         # of a git format-patch generated file    430         # of a git format-patch generated file (subject tags, etc...)
577                                                   431 
578         my $patch_prefix = "";                    432         my $patch_prefix = "";                  #Parsing the intro
579                                                   433 
580         while (<$patch>) {                        434         while (<$patch>) {
581             my $patch_line = $_;                  435             my $patch_line = $_;
582             if (m/^ mode change [0-7]+ => [0-7 !! 436             if (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) {
583                 my $filename = $1;             << 
584                 push(@files, $filename);       << 
585             } elsif (m/^rename (?:from|to) (\S << 
586                 my $filename = $1;             << 
587                 push(@files, $filename);       << 
588             } elsif (m/^diff --git a\/(\S+) b\ << 
589                 my $filename1 = $1;            << 
590                 my $filename2 = $2;            << 
591                 push(@files, $filename1);      << 
592                 push(@files, $filename2);      << 
593             } elsif (m/^Fixes:\s+([0-9a-fA-F]{ << 
594                 push(@fixes, $1) if ($email_fi << 
595             } elsif (m/^\+\+\+\s+(\S+)/ or m/^ << 
596                 my $filename = $1;                437                 my $filename = $1;
597                 $filename =~ s@^[^/]*/@@;         438                 $filename =~ s@^[^/]*/@@;
598                 $filename =~ s@\n@@;              439                 $filename =~ s@\n@@;
599                 $lastfile = $filename;            440                 $lastfile = $filename;
600                 push(@files, $filename);          441                 push(@files, $filename);
601                 $patch_prefix = "^[+-].*";        442                 $patch_prefix = "^[+-].*";      #Now parsing the actual patch
602             } elsif (m/^\@\@ -(\d+),(\d+)/) {     443             } elsif (m/^\@\@ -(\d+),(\d+)/) {
603                 if ($email_git_blame) {           444                 if ($email_git_blame) {
604                     push(@range, "$lastfile:$1    445                     push(@range, "$lastfile:$1:$2");
605                 }                                 446                 }
606             } elsif ($keywords) {                 447             } elsif ($keywords) {
607                 foreach my $line (keys %keywor    448                 foreach my $line (keys %keyword_hash) {
608                     if ($patch_line =~ m/${pat    449                     if ($patch_line =~ m/${patch_prefix}$keyword_hash{$line}/x) {
609                         push(@keyword_tvi, $li    450                         push(@keyword_tvi, $line);
610                     }                             451                     }
611                 }                                 452                 }
612             }                                     453             }
613         }                                         454         }
614         close($patch);                            455         close($patch);
615                                                   456 
616         if ($file_cnt == @files) {                457         if ($file_cnt == @files) {
617             warn "$P: file '${file}' doesn't a    458             warn "$P: file '${file}' doesn't appear to be a patch.  "
618                 . "Add -f to options?\n";         459                 . "Add -f to options?\n";
619         }                                         460         }
620         @files = sort_and_uniq(@files);           461         @files = sort_and_uniq(@files);
621     }                                             462     }
622 }                                                 463 }
623                                                   464 
624 @file_emails = uniq(@file_emails);                465 @file_emails = uniq(@file_emails);
625 @fixes = uniq(@fixes);                         << 
626                                                   466 
627 my %email_hash_name;                              467 my %email_hash_name;
628 my %email_hash_address;                           468 my %email_hash_address;
629 my @email_to = ();                                469 my @email_to = ();
630 my %hash_list_to;                                 470 my %hash_list_to;
631 my @list_to = ();                                 471 my @list_to = ();
632 my @scm = ();                                     472 my @scm = ();
633 my @web = ();                                     473 my @web = ();
634 my @subsystem = ();                               474 my @subsystem = ();
635 my @status = ();                                  475 my @status = ();
636 my %deduplicate_name_hash = ();                   476 my %deduplicate_name_hash = ();
637 my %deduplicate_address_hash = ();                477 my %deduplicate_address_hash = ();
638                                                   478 
639 my @maintainers = get_maintainers();              479 my @maintainers = get_maintainers();
                                                   >> 480 
640 if (@maintainers) {                               481 if (@maintainers) {
641     @maintainers = merge_email(@maintainers);     482     @maintainers = merge_email(@maintainers);
642     output(@maintainers);                         483     output(@maintainers);
643 }                                                 484 }
644                                                   485 
645 if ($scm) {                                       486 if ($scm) {
646     @scm = uniq(@scm);                            487     @scm = uniq(@scm);
647     output(@scm);                                 488     output(@scm);
648 }                                                 489 }
649                                                   490 
650 if ($status) {                                    491 if ($status) {
651     @status = uniq(@status);                      492     @status = uniq(@status);
652     output(@status);                              493     output(@status);
653 }                                                 494 }
654                                                   495 
655 if ($subsystem) {                                 496 if ($subsystem) {
656     @subsystem = uniq(@subsystem);                497     @subsystem = uniq(@subsystem);
657     output(@subsystem);                           498     output(@subsystem);
658 }                                                 499 }
659                                                   500 
660 if ($web) {                                       501 if ($web) {
661     @web = uniq(@web);                            502     @web = uniq(@web);
662     output(@web);                                 503     output(@web);
663 }                                                 504 }
664                                                   505 
665 exit($exit);                                      506 exit($exit);
666                                                   507 
667 sub self_test {                                << 
668     my @lsfiles = ();                          << 
669     my @good_links = ();                       << 
670     my @bad_links = ();                        << 
671     my @section_headers = ();                  << 
672     my $index = 0;                             << 
673                                                << 
674     @lsfiles = vcs_list_files($lk_path);       << 
675                                                << 
676     for my $x (@self_test_info) {              << 
677         $index++;                              << 
678                                                << 
679         ## Section header duplication and miss << 
680         if (($self_test eq "" || $self_test =~ << 
681             $x->{line} =~ /^\S[^:]/ &&         << 
682             defined $self_test_info[$index] && << 
683             $self_test_info[$index]->{line} =~ << 
684             my $has_S = 0;                     << 
685             my $has_F = 0;                     << 
686             my $has_ML = 0;                    << 
687             my $status = "";                   << 
688             if (grep(m@^\Q$x->{line}\E@, @sect << 
689                 print("$x->{file}:$x->{linenr} << 
690             } else {                           << 
691                 push(@section_headers, $x->{li << 
692             }                                  << 
693             my $nextline = $index;             << 
694             while (defined $self_test_info[$ne << 
695                    $self_test_info[$nextline]- << 
696                 my $type = $1;                 << 
697                 my $value = $2;                << 
698                 if ($type eq "S") {            << 
699                     $has_S = 1;                << 
700                     $status = $value;          << 
701                 } elsif ($type eq "F" || $type << 
702                     $has_F = 1;                << 
703                 } elsif ($type eq "M" || $type << 
704                     $has_ML = 1;               << 
705                 }                              << 
706                 $nextline++;                   << 
707             }                                  << 
708             if (!$has_ML && $status !~ /orphan << 
709                 print("$x->{file}:$x->{linenr} << 
710             }                                  << 
711             if (!$has_S) {                     << 
712                 print("$x->{file}:$x->{linenr} << 
713             }                                  << 
714             if (!$has_F) {                     << 
715                 print("$x->{file}:$x->{linenr} << 
716             }                                  << 
717         }                                      << 
718                                                << 
719         next if ($x->{line} !~ /^([A-Z]):\s*(. << 
720                                                << 
721         my $type = $1;                         << 
722         my $value = $2;                        << 
723                                                << 
724         ## Filename pattern matching           << 
725         if (($type eq "F" || $type eq "X") &&  << 
726             ($self_test eq "" || $self_test =~ << 
727             $value =~ s@\.@\\\.@g;       ##Con << 
728             $value =~ s/\*/\.\*/g;       ##Con << 
729             $value =~ s/\?/\./g;         ##Con << 
730             ##if pattern is a directory and it << 
731             if ((-d $value)) {                 << 
732                 $value =~ s@([^/])$@$1/@;      << 
733             }                                  << 
734             if (!grep(m@^$value@, @lsfiles)) { << 
735                 print("$x->{file}:$x->{linenr} << 
736             }                                  << 
737                                                << 
738         ## Link reachability                   << 
739         } elsif (($type eq "W" || $type eq "Q" << 
740                  $value =~ /^https?:/ &&       << 
741                  ($self_test eq "" || $self_te << 
742             next if (grep(m@^\Q$value\E$@, @go << 
743             my $isbad = 0;                     << 
744             if (grep(m@^\Q$value\E$@, @bad_lin << 
745                 $isbad = 1;                    << 
746             } else {                           << 
747                 my $output = `wget --spider -q << 
748                 if ($? == 0) {                 << 
749                     push(@good_links, $value); << 
750                 } else {                       << 
751                     push(@bad_links, $value);  << 
752                     $isbad = 1;                << 
753                 }                              << 
754             }                                  << 
755             if ($isbad) {                      << 
756                 print("$x->{file}:$x->{linenr} << 
757             }                                  << 
758                                                << 
759         ## SCM reachability                    << 
760         } elsif ($type eq "T" &&               << 
761                  ($self_test eq "" || $self_te << 
762             next if (grep(m@^\Q$value\E$@, @go << 
763             my $isbad = 0;                     << 
764             if (grep(m@^\Q$value\E$@, @bad_lin << 
765                 $isbad = 1;                    << 
766             } elsif ($value !~ /^(?:git|quilt| << 
767                 print("$x->{file}:$x->{linenr} << 
768             } elsif ($value =~ /^git\s+(\S+)(\ << 
769                 my $url = $1;                  << 
770                 my $branch = "";               << 
771                 $branch = $3 if $3;            << 
772                 my $output = `git ls-remote -- << 
773                 if ($? == 0) {                 << 
774                     push(@good_links, $value); << 
775                 } else {                       << 
776                     push(@bad_links, $value);  << 
777                     $isbad = 1;                << 
778                 }                              << 
779             } elsif ($value =~ /^(?:quilt|hg)\ << 
780                 my $url = $1;                  << 
781                 my $output = `wget --spider -q << 
782                 if ($? == 0) {                 << 
783                     push(@good_links, $value); << 
784                 } else {                       << 
785                     push(@bad_links, $value);  << 
786                     $isbad = 1;                << 
787                 }                              << 
788             }                                  << 
789             if ($isbad) {                      << 
790                 print("$x->{file}:$x->{linenr} << 
791             }                                  << 
792         }                                      << 
793     }                                          << 
794 }                                              << 
795                                                << 
796 sub ignore_email_address {                     << 
797     my ($address) = @_;                        << 
798                                                << 
799     foreach my $ignore (@ignore_emails) {      << 
800         return 1 if ($ignore eq $address);     << 
801     }                                          << 
802                                                << 
803     return 0;                                  << 
804 }                                              << 
805                                                << 
806 sub range_is_maintained {                         508 sub range_is_maintained {
807     my ($start, $end) = @_;                       509     my ($start, $end) = @_;
808                                                   510 
809     for (my $i = $start; $i < $end; $i++) {       511     for (my $i = $start; $i < $end; $i++) {
810         my $line = $typevalue[$i];                512         my $line = $typevalue[$i];
811         if ($line =~ m/^([A-Z]):\s*(.*)/) {    !! 513         if ($line =~ m/^(\C):\s*(.*)/) {
812             my $type = $1;                        514             my $type = $1;
813             my $value = $2;                       515             my $value = $2;
814             if ($type eq 'S') {                   516             if ($type eq 'S') {
815                 if ($value =~ /(maintain|suppo    517                 if ($value =~ /(maintain|support)/i) {
816                     return 1;                     518                     return 1;
817                 }                                 519                 }
818             }                                     520             }
819         }                                         521         }
820     }                                             522     }
821     return 0;                                     523     return 0;
822 }                                                 524 }
823                                                   525 
824 sub range_has_maintainer {                        526 sub range_has_maintainer {
825     my ($start, $end) = @_;                       527     my ($start, $end) = @_;
826                                                   528 
827     for (my $i = $start; $i < $end; $i++) {       529     for (my $i = $start; $i < $end; $i++) {
828         my $line = $typevalue[$i];                530         my $line = $typevalue[$i];
829         if ($line =~ m/^([A-Z]):\s*(.*)/) {    !! 531         if ($line =~ m/^(\C):\s*(.*)/) {
830             my $type = $1;                        532             my $type = $1;
831             my $value = $2;                       533             my $value = $2;
832             if ($type eq 'M') {                   534             if ($type eq 'M') {
833                 return 1;                         535                 return 1;
834             }                                     536             }
835         }                                         537         }
836     }                                             538     }
837     return 0;                                     539     return 0;
838 }                                                 540 }
839                                                   541 
840 sub get_maintainers {                             542 sub get_maintainers {
841     %email_hash_name = ();                        543     %email_hash_name = ();
842     %email_hash_address = ();                     544     %email_hash_address = ();
843     %commit_author_hash = ();                     545     %commit_author_hash = ();
844     %commit_signer_hash = ();                     546     %commit_signer_hash = ();
845     @email_to = ();                               547     @email_to = ();
846     %hash_list_to = ();                           548     %hash_list_to = ();
847     @list_to = ();                                549     @list_to = ();
848     @scm = ();                                    550     @scm = ();
849     @web = ();                                    551     @web = ();
850     @subsystem = ();                              552     @subsystem = ();
851     @status = ();                                 553     @status = ();
852     %deduplicate_name_hash = ();                  554     %deduplicate_name_hash = ();
853     %deduplicate_address_hash = ();               555     %deduplicate_address_hash = ();
854     if ($email_git_all_signature_types) {         556     if ($email_git_all_signature_types) {
855         $signature_pattern = "(.+?)[Bb][Yy]:";    557         $signature_pattern = "(.+?)[Bb][Yy]:";
856     } else {                                      558     } else {
857         $signature_pattern = "\(" . join("|",     559         $signature_pattern = "\(" . join("|", @signature_tags) . "\)";
858     }                                             560     }
859                                                   561 
860     # Find responsible parties                    562     # Find responsible parties
861                                                   563 
862     my %exact_pattern_match_hash = ();            564     my %exact_pattern_match_hash = ();
863                                                   565 
864     foreach my $file (@files) {                   566     foreach my $file (@files) {
865                                                   567 
866         my %hash;                                 568         my %hash;
867         my $tvi = find_first_section();           569         my $tvi = find_first_section();
868         while ($tvi < @typevalue) {               570         while ($tvi < @typevalue) {
869             my $start = find_starting_index($t    571             my $start = find_starting_index($tvi);
870             my $end = find_ending_index($tvi);    572             my $end = find_ending_index($tvi);
871             my $exclude = 0;                      573             my $exclude = 0;
872             my $i;                                574             my $i;
873                                                   575 
874             #Do not match excluded file patter    576             #Do not match excluded file patterns
875                                                   577 
876             for ($i = $start; $i < $end; $i++)    578             for ($i = $start; $i < $end; $i++) {
877                 my $line = $typevalue[$i];        579                 my $line = $typevalue[$i];
878                 if ($line =~ m/^([A-Z]):\s*(.* !! 580                 if ($line =~ m/^(\C):\s*(.*)/) {
879                     my $type = $1;                581                     my $type = $1;
880                     my $value = $2;               582                     my $value = $2;
881                     if ($type eq 'X') {           583                     if ($type eq 'X') {
882                         if (file_match_pattern    584                         if (file_match_pattern($file, $value)) {
883                             $exclude = 1;         585                             $exclude = 1;
884                             last;                 586                             last;
885                         }                         587                         }
886                     }                             588                     }
887                 }                                 589                 }
888             }                                     590             }
889                                                   591 
890             if (!$exclude) {                      592             if (!$exclude) {
891                 for ($i = $start; $i < $end; $    593                 for ($i = $start; $i < $end; $i++) {
892                     my $line = $typevalue[$i];    594                     my $line = $typevalue[$i];
893                     if ($line =~ m/^([A-Z]):\s !! 595                     if ($line =~ m/^(\C):\s*(.*)/) {
894                         my $type = $1;            596                         my $type = $1;
895                         my $value = $2;           597                         my $value = $2;
896                         if ($type eq 'F') {       598                         if ($type eq 'F') {
897                             if (file_match_pat    599                             if (file_match_pattern($file, $value)) {
898                                 my $value_pd =    600                                 my $value_pd = ($value =~ tr@/@@);
899                                 my $file_pd =     601                                 my $file_pd = ($file  =~ tr@/@@);
900                                 $value_pd++ if    602                                 $value_pd++ if (substr($value,-1,1) ne "/");
901                                 $value_pd = -1    603                                 $value_pd = -1 if ($value =~ /^\.\*/);
902                                 if ($value_pd     604                                 if ($value_pd >= $file_pd &&
903                                     range_is_m    605                                     range_is_maintained($start, $end) &&
904                                     range_has_    606                                     range_has_maintainer($start, $end)) {
905                                     $exact_pat    607                                     $exact_pattern_match_hash{$file} = 1;
906                                 }                 608                                 }
907                                 if ($pattern_d    609                                 if ($pattern_depth == 0 ||
908                                     (($file_pd    610                                     (($file_pd - $value_pd) < $pattern_depth)) {
909                                     $hash{$tvi    611                                     $hash{$tvi} = $value_pd;
910                                 }                 612                                 }
911                             }                     613                             }
912                         } elsif ($type eq 'N')    614                         } elsif ($type eq 'N') {
913                             if ($file =~ m/$va    615                             if ($file =~ m/$value/x) {
914                                 $hash{$tvi} =     616                                 $hash{$tvi} = 0;
915                             }                     617                             }
916                         }                         618                         }
917                     }                             619                     }
918                 }                                 620                 }
919             }                                     621             }
920             $tvi = $end + 1;                      622             $tvi = $end + 1;
921         }                                         623         }
922                                                   624 
923         foreach my $line (sort {$hash{$b} <=>     625         foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
924             add_categories($line, "");         !! 626             add_categories($line);
925             if ($sections) {                      627             if ($sections) {
926                 my $i;                            628                 my $i;
927                 my $start = find_starting_inde    629                 my $start = find_starting_index($line);
928                 my $end = find_ending_index($l    630                 my $end = find_ending_index($line);
929                 for ($i = $start; $i < $end; $    631                 for ($i = $start; $i < $end; $i++) {
930                     my $line = $typevalue[$i];    632                     my $line = $typevalue[$i];
931                     if ($line =~ /^[FX]:/) {      633                     if ($line =~ /^[FX]:/) {            ##Restore file patterns
932                         $line =~ s/([^\\])\.([    634                         $line =~ s/([^\\])\.([^\*])/$1\?$2/g;
933                         $line =~ s/([^\\])\.$/    635                         $line =~ s/([^\\])\.$/$1\?/g;   ##Convert . back to ?
934                         $line =~ s/\\\./\./g;     636                         $line =~ s/\\\./\./g;           ##Convert \. to .
935                         $line =~ s/\.\*/\*/g;     637                         $line =~ s/\.\*/\*/g;           ##Convert .* to *
936                     }                             638                     }
937                     my $count = $line =~ s/^([ !! 639                     $line =~ s/^([A-Z]):/$1:\t/g;
938                     if ($letters eq "" || (!$c !! 640                     print("$line\n");
939                         print("$line\n");      << 
940                     }                          << 
941                 }                                 641                 }
942                 print("\n");                      642                 print("\n");
943             }                                     643             }
944         }                                         644         }
945                                                << 
946         maintainers_in_file($file);            << 
947     }                                             645     }
948                                                   646 
949     if ($keywords) {                              647     if ($keywords) {
950         @keyword_tvi = sort_and_uniq(@keyword_    648         @keyword_tvi = sort_and_uniq(@keyword_tvi);
951         foreach my $line (@keyword_tvi) {         649         foreach my $line (@keyword_tvi) {
952             add_categories($line, ":Keyword:$k !! 650             add_categories($line);
953         }                                         651         }
954     }                                             652     }
955                                                   653 
956     foreach my $email (@email_to, @list_to) {     654     foreach my $email (@email_to, @list_to) {
957         $email->[0] = deduplicate_email($email    655         $email->[0] = deduplicate_email($email->[0]);
958     }                                             656     }
959                                                   657 
960     foreach my $file (@files) {                   658     foreach my $file (@files) {
961         if ($email &&                             659         if ($email &&
962             ($email_git ||                     !! 660             ($email_git || ($email_git_fallback &&
963              ($email_git_fallback &&           !! 661                             !$exact_pattern_match_hash{$file}))) {
964               $file !~ /MAINTAINERS$/ &&       << 
965               !$exact_pattern_match_hash{$file << 
966             vcs_file_signoffs($file);             662             vcs_file_signoffs($file);
967         }                                         663         }
968         if ($email && $email_git_blame) {         664         if ($email && $email_git_blame) {
969             vcs_file_blame($file);                665             vcs_file_blame($file);
970         }                                         666         }
971     }                                             667     }
972                                                   668 
973     if ($email) {                                 669     if ($email) {
974         foreach my $chief (@penguin_chief) {      670         foreach my $chief (@penguin_chief) {
975             if ($chief =~ m/^(.*):(.*)/) {        671             if ($chief =~ m/^(.*):(.*)/) {
976                 my $email_address;                672                 my $email_address;
977                                                   673 
978                 $email_address = format_email(    674                 $email_address = format_email($1, $2, $email_usename);
979                 if ($email_git_penguin_chiefs)    675                 if ($email_git_penguin_chiefs) {
980                     push(@email_to, [$email_ad    676                     push(@email_to, [$email_address, 'chief penguin']);
981                 } else {                          677                 } else {
982                     @email_to = grep($_->[0] !    678                     @email_to = grep($_->[0] !~ /${email_address}/, @email_to);
983                 }                                 679                 }
984             }                                     680             }
985         }                                         681         }
986                                                   682 
987         foreach my $email (@file_emails) {        683         foreach my $email (@file_emails) {
988             $email = mailmap_email($email);    << 
989             my ($name, $address) = parse_email    684             my ($name, $address) = parse_email($email);
990                                                   685 
991             my $tmp_email = format_email($name    686             my $tmp_email = format_email($name, $address, $email_usename);
992             push_email_address($tmp_email, '')    687             push_email_address($tmp_email, '');
993             add_role($tmp_email, 'in file');      688             add_role($tmp_email, 'in file');
994         }                                         689         }
995     }                                             690     }
996                                                   691 
997     foreach my $fix (@fixes) {                 << 
998         vcs_add_commit_signers($fix, "blamed_f << 
999     }                                          << 
1000                                               << 
1001     my @to = ();                                 692     my @to = ();
1002     if ($email || $email_list) {                 693     if ($email || $email_list) {
1003         if ($email) {                            694         if ($email) {
1004             @to = (@to, @email_to);              695             @to = (@to, @email_to);
1005         }                                        696         }
1006         if ($email_list) {                       697         if ($email_list) {
1007             @to = (@to, @list_to);               698             @to = (@to, @list_to);
1008         }                                        699         }
1009     }                                            700     }
1010                                                  701 
1011     if ($interactive) {                          702     if ($interactive) {
1012         @to = interactive_get_maintainers(\@t    703         @to = interactive_get_maintainers(\@to);
1013     }                                            704     }
1014                                                  705 
1015     return @to;                                  706     return @to;
1016 }                                                707 }
1017                                                  708 
1018 sub file_match_pattern {                         709 sub file_match_pattern {
1019     my ($file, $pattern) = @_;                   710     my ($file, $pattern) = @_;
1020     if (substr($pattern, -1) eq "/") {           711     if (substr($pattern, -1) eq "/") {
1021         if ($file =~ m@^$pattern@) {             712         if ($file =~ m@^$pattern@) {
1022             return 1;                            713             return 1;
1023         }                                        714         }
1024     } else {                                     715     } else {
1025         if ($file =~ m@^$pattern@) {             716         if ($file =~ m@^$pattern@) {
1026             my $s1 = ($file =~ tr@/@@);          717             my $s1 = ($file =~ tr@/@@);
1027             my $s2 = ($pattern =~ tr@/@@);       718             my $s2 = ($pattern =~ tr@/@@);
1028             if ($s1 == $s2) {                    719             if ($s1 == $s2) {
1029                 return 1;                        720                 return 1;
1030             }                                    721             }
1031         }                                        722         }
1032     }                                            723     }
1033     return 0;                                    724     return 0;
1034 }                                                725 }
1035                                                  726 
1036 sub usage {                                      727 sub usage {
1037     print <<EOT;                                 728     print <<EOT;
1038 usage: $P [options] patchfile                    729 usage: $P [options] patchfile
1039        $P [options] -f file|directory            730        $P [options] -f file|directory
1040 version: $V                                      731 version: $V
1041                                                  732 
1042 MAINTAINER field selection options:              733 MAINTAINER field selection options:
1043   --email => print email address(es) if any      734   --email => print email address(es) if any
1044     --git => include recent git \*-by: signer    735     --git => include recent git \*-by: signers
1045     --git-all-signature-types => include sign    736     --git-all-signature-types => include signers regardless of signature type
1046         or use only ${signature_pattern} sign    737         or use only ${signature_pattern} signers (default: $email_git_all_signature_types)
1047     --git-fallback => use git when no exact M    738     --git-fallback => use git when no exact MAINTAINERS pattern (default: $email_git_fallback)
1048     --git-chief-penguins => include ${penguin    739     --git-chief-penguins => include ${penguin_chiefs}
1049     --git-min-signatures => number of signatu    740     --git-min-signatures => number of signatures required (default: $email_git_min_signatures)
1050     --git-max-maintainers => maximum maintain    741     --git-max-maintainers => maximum maintainers to add (default: $email_git_max_maintainers)
1051     --git-min-percent => minimum percentage o    742     --git-min-percent => minimum percentage of commits required (default: $email_git_min_percent)
1052     --git-blame => use git blame to find modi    743     --git-blame => use git blame to find modified commits for patch or file
1053     --git-blame-signatures => when used with  << 
1054     --git-since => git history to use (defaul    744     --git-since => git history to use (default: $email_git_since)
1055     --hg-since => hg history to use (default:    745     --hg-since => hg history to use (default: $email_hg_since)
1056     --interactive => display a menu (mostly u    746     --interactive => display a menu (mostly useful if used with the --git option)
1057     --m => include maintainer(s) if any          747     --m => include maintainer(s) if any
1058     --r => include reviewer(s) if any         << 
1059     --n => include name 'Full Name <addr\@doma    748     --n => include name 'Full Name <addr\@domain.tld>'
1060     --l => include list(s) if any                749     --l => include list(s) if any
1061     --moderated => include moderated lists(s) !! 750     --s => include subscriber only list(s) if any
1062     --s => include subscriber only list(s) if << 
1063     --remove-duplicates => minimize duplicate    751     --remove-duplicates => minimize duplicate email names/addresses
1064     --roles => show roles (status:subsystem,     752     --roles => show roles (status:subsystem, git-signer, list, etc...)
1065     --rolestats => show roles and statistics     753     --rolestats => show roles and statistics (commits/total_commits, %)
1066     --file-emails => add email addresses foun    754     --file-emails => add email addresses found in -f file (default: 0 (off))
1067     --fixes => for patches, add signatures of << 
1068   --scm => print SCM tree(s) if any              755   --scm => print SCM tree(s) if any
1069   --status => print status if any                756   --status => print status if any
1070   --subsystem => print subsystem name if any     757   --subsystem => print subsystem name if any
1071   --web => print website(s) if any               758   --web => print website(s) if any
1072                                                  759 
1073 Output type options:                             760 Output type options:
1074   --separator [, ] => separator for multiple     761   --separator [, ] => separator for multiple entries on 1 line
1075     using --separator also sets --nomultiline    762     using --separator also sets --nomultiline if --separator is not [, ]
1076   --multiline => print 1 entry per line          763   --multiline => print 1 entry per line
1077                                                  764 
1078 Other options:                                   765 Other options:
1079   --pattern-depth => Number of pattern direct    766   --pattern-depth => Number of pattern directory traversals (default: 0 (all))
1080   --keywords => scan patch for keywords (defa    767   --keywords => scan patch for keywords (default: $keywords)
1081   --keywords-in-file => scan file for keyword << 
1082   --sections => print all of the subsystem se    768   --sections => print all of the subsystem sections with pattern matches
1083   --letters => print all matching 'letter' ty << 
1084   --mailmap => use .mailmap file (default: $e    769   --mailmap => use .mailmap file (default: $email_use_mailmap)
1085   --no-tree => run without a kernel tree      << 
1086   --self-test => show potential issues with M << 
1087   --version => show version                      770   --version => show version
1088   --help => show this help information           771   --help => show this help information
1089                                                  772 
1090 Default options:                                 773 Default options:
1091   [--email --tree --nogit --git-fallback --m  !! 774   [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0
1092    --pattern-depth=0 --remove-duplicates --ro !! 775    --remove-duplicates --rolestats]
1093                                                  776 
1094 Notes:                                           777 Notes:
1095   Using "-f directory" may give unexpected re    778   Using "-f directory" may give unexpected results:
1096       Used with "--git", git signators for _a    779       Used with "--git", git signators for _all_ files in and below
1097           directory are examined as git recur    780           directory are examined as git recurses directories.
1098           Any specified X: (exclude) pattern     781           Any specified X: (exclude) pattern matches are _not_ ignored.
1099       Used with "--nogit", directory is used     782       Used with "--nogit", directory is used as a pattern match,
1100           no individual file within the direc    783           no individual file within the directory or subdirectory
1101           is matched.                            784           is matched.
1102       Used with "--git-blame", does not itera    785       Used with "--git-blame", does not iterate all files in directory
1103   Using "--git-blame" is slow and may add old    786   Using "--git-blame" is slow and may add old committers and authors
1104       that are no longer active maintainers t    787       that are no longer active maintainers to the output.
1105   Using "--roles" or "--rolestats" with git s    788   Using "--roles" or "--rolestats" with git send-email --cc-cmd or any
1106       other automated tools that expect only     789       other automated tools that expect only ["name"] <email address>
1107       may not work because of additional outp    790       may not work because of additional output after <email address>.
1108   Using "--rolestats" and "--git-blame" shows    791   Using "--rolestats" and "--git-blame" shows the #/total=% commits,
1109       not the percentage of the entire file a    792       not the percentage of the entire file authored.  # of commits is
1110       not a good measure of amount of code au    793       not a good measure of amount of code authored.  1 major commit may
1111       contain a thousand lines, 5 trivial com    794       contain a thousand lines, 5 trivial commits may modify a single line.
1112   If git is not installed, but mercurial (hg)    795   If git is not installed, but mercurial (hg) is installed and an .hg
1113       repository exists, the following option    796       repository exists, the following options apply to mercurial:
1114           --git,                                 797           --git,
1115           --git-min-signatures, --git-max-mai    798           --git-min-signatures, --git-max-maintainers, --git-min-percent, and
1116           --git-blame                            799           --git-blame
1117       Use --hg-since not --git-since to contr    800       Use --hg-since not --git-since to control date selection
1118   File ".get_maintainer.conf", if it exists i    801   File ".get_maintainer.conf", if it exists in the linux kernel source root
1119       directory, can change whatever get_main    802       directory, can change whatever get_maintainer defaults are desired.
1120       Entries in this file can be any command    803       Entries in this file can be any command line argument.
1121       This file is prepended to any additiona    804       This file is prepended to any additional command line arguments.
1122       Multiple lines and # comments are allow    805       Multiple lines and # comments are allowed.
1123   Most options have both positive and negativ << 
1124       The negative forms for --<foo> are --no << 
1125                                               << 
1126 EOT                                              806 EOT
1127 }                                                807 }
1128                                                  808 
1129 sub top_of_kernel_tree {                         809 sub top_of_kernel_tree {
1130     my ($lk_path) = @_;                          810     my ($lk_path) = @_;
1131                                                  811 
1132     if ($lk_path ne "" && substr($lk_path,len    812     if ($lk_path ne "" && substr($lk_path,length($lk_path)-1,1) ne "/") {
1133         $lk_path .= "/";                         813         $lk_path .= "/";
1134     }                                            814     }
1135     if (   (-f "${lk_path}COPYING")              815     if (   (-f "${lk_path}COPYING")
1136         && (-f "${lk_path}CREDITS")              816         && (-f "${lk_path}CREDITS")
1137         && (-f "${lk_path}Kbuild")               817         && (-f "${lk_path}Kbuild")
1138         && (-e "${lk_path}MAINTAINERS")       !! 818         && (-f "${lk_path}MAINTAINERS")
1139         && (-f "${lk_path}Makefile")             819         && (-f "${lk_path}Makefile")
1140         && (-f "${lk_path}README")               820         && (-f "${lk_path}README")
1141         && (-d "${lk_path}Documentation")        821         && (-d "${lk_path}Documentation")
1142         && (-d "${lk_path}arch")                 822         && (-d "${lk_path}arch")
1143         && (-d "${lk_path}include")              823         && (-d "${lk_path}include")
1144         && (-d "${lk_path}drivers")              824         && (-d "${lk_path}drivers")
1145         && (-d "${lk_path}fs")                   825         && (-d "${lk_path}fs")
1146         && (-d "${lk_path}init")                 826         && (-d "${lk_path}init")
1147         && (-d "${lk_path}ipc")                  827         && (-d "${lk_path}ipc")
1148         && (-d "${lk_path}kernel")               828         && (-d "${lk_path}kernel")
1149         && (-d "${lk_path}lib")                  829         && (-d "${lk_path}lib")
1150         && (-d "${lk_path}scripts")) {           830         && (-d "${lk_path}scripts")) {
1151         return 1;                                831         return 1;
1152     }                                            832     }
1153     return 0;                                    833     return 0;
1154 }                                                834 }
1155                                                  835 
1156 sub escape_name {                             << 
1157     my ($name) = @_;                          << 
1158                                               << 
1159     if ($name =~ /[^\w \-]/ai) {         ##ha << 
1160         $name =~ s/(?<!\\)"/\\"/g;       ##es << 
1161         $name = "\"$name\"";                  << 
1162     }                                         << 
1163                                               << 
1164     return $name;                             << 
1165 }                                             << 
1166                                               << 
1167 sub parse_email {                                836 sub parse_email {
1168     my ($formatted_email) = @_;                  837     my ($formatted_email) = @_;
1169                                                  838 
1170     my $name = "";                               839     my $name = "";
1171     my $address = "";                            840     my $address = "";
1172                                                  841 
1173     if ($formatted_email =~ /^([^<]+)<(.+\@.*)    842     if ($formatted_email =~ /^([^<]+)<(.+\@.*)>.*$/) {
1174         $name = $1;                              843         $name = $1;
1175         $address = $2;                           844         $address = $2;
1176     } elsif ($formatted_email =~ /^\s*<(.+\@\S    845     } elsif ($formatted_email =~ /^\s*<(.+\@\S*)>.*$/) {
1177         $address = $1;                           846         $address = $1;
1178     } elsif ($formatted_email =~ /^(.+\@\S*).    847     } elsif ($formatted_email =~ /^(.+\@\S*).*$/) {
1179         $address = $1;                           848         $address = $1;
1180     }                                            849     }
1181                                                  850 
1182     $name =~ s/^\s+|\s+$//g;                     851     $name =~ s/^\s+|\s+$//g;
1183     $name =~ s/^\"|\"$//g;                       852     $name =~ s/^\"|\"$//g;
1184     $name = escape_name($name);               << 
1185     $address =~ s/^\s+|\s+$//g;                  853     $address =~ s/^\s+|\s+$//g;
1186                                                  854 
                                                   >> 855     if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
                                                   >> 856         $name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
                                                   >> 857         $name = "\"$name\"";
                                                   >> 858     }
                                                   >> 859 
1187     return ($name, $address);                    860     return ($name, $address);
1188 }                                                861 }
1189                                                  862 
1190 sub format_email {                               863 sub format_email {
1191     my ($name, $address, $usename) = @_;         864     my ($name, $address, $usename) = @_;
1192                                                  865 
1193     my $formatted_email;                         866     my $formatted_email;
1194                                                  867 
1195     $name =~ s/^\s+|\s+$//g;                     868     $name =~ s/^\s+|\s+$//g;
1196     $name =~ s/^\"|\"$//g;                       869     $name =~ s/^\"|\"$//g;
1197     $name = escape_name($name);               << 
1198     $address =~ s/^\s+|\s+$//g;                  870     $address =~ s/^\s+|\s+$//g;
1199                                                  871 
                                                   >> 872     if ($name =~ /[^\w \-]/i) {          ##has "must quote" chars
                                                   >> 873         $name =~ s/(?<!\\)"/\\"/g;       ##escape quotes
                                                   >> 874         $name = "\"$name\"";
                                                   >> 875     }
                                                   >> 876 
1200     if ($usename) {                              877     if ($usename) {
1201         if ("$name" eq "") {                     878         if ("$name" eq "") {
1202             $formatted_email = "$address";       879             $formatted_email = "$address";
1203         } else {                                 880         } else {
1204             $formatted_email = "$name <$addre    881             $formatted_email = "$name <$address>";
1205         }                                        882         }
1206     } else {                                     883     } else {
1207         $formatted_email = $address;             884         $formatted_email = $address;
1208     }                                            885     }
1209                                                  886 
1210     return $formatted_email;                     887     return $formatted_email;
1211 }                                                888 }
1212                                                  889 
1213 sub find_first_section {                         890 sub find_first_section {
1214     my $index = 0;                               891     my $index = 0;
1215                                                  892 
1216     while ($index < @typevalue) {                893     while ($index < @typevalue) {
1217         my $tv = $typevalue[$index];             894         my $tv = $typevalue[$index];
1218         if (($tv =~ m/^([A-Z]):\s*(.*)/)) {   !! 895         if (($tv =~ m/^(\C):\s*(.*)/)) {
1219             last;                                896             last;
1220         }                                        897         }
1221         $index++;                                898         $index++;
1222     }                                            899     }
1223                                                  900 
1224     return $index;                               901     return $index;
1225 }                                                902 }
1226                                                  903 
1227 sub find_starting_index {                        904 sub find_starting_index {
1228     my ($index) = @_;                            905     my ($index) = @_;
1229                                                  906 
1230     while ($index > 0) {                         907     while ($index > 0) {
1231         my $tv = $typevalue[$index];             908         my $tv = $typevalue[$index];
1232         if (!($tv =~ m/^([A-Z]):\s*(.*)/)) {  !! 909         if (!($tv =~ m/^(\C):\s*(.*)/)) {
1233             last;                                910             last;
1234         }                                        911         }
1235         $index--;                                912         $index--;
1236     }                                            913     }
1237                                                  914 
1238     return $index;                               915     return $index;
1239 }                                                916 }
1240                                                  917 
1241 sub find_ending_index {                          918 sub find_ending_index {
1242     my ($index) = @_;                            919     my ($index) = @_;
1243                                                  920 
1244     while ($index < @typevalue) {                921     while ($index < @typevalue) {
1245         my $tv = $typevalue[$index];             922         my $tv = $typevalue[$index];
1246         if (!($tv =~ m/^([A-Z]):\s*(.*)/)) {  !! 923         if (!($tv =~ m/^(\C):\s*(.*)/)) {
1247             last;                                924             last;
1248         }                                        925         }
1249         $index++;                                926         $index++;
1250     }                                            927     }
1251                                                  928 
1252     return $index;                               929     return $index;
1253 }                                                930 }
1254                                                  931 
1255 sub get_subsystem_name {                      << 
1256     my ($index) = @_;                         << 
1257                                               << 
1258     my $start = find_starting_index($index);  << 
1259                                               << 
1260     my $subsystem = $typevalue[$start];       << 
1261     if ($output_section_maxlen && length($sub << 
1262         $subsystem = substr($subsystem, 0, $o << 
1263         $subsystem =~ s/\s*$//;               << 
1264         $subsystem = $subsystem . "...";      << 
1265     }                                         << 
1266     return $subsystem;                        << 
1267 }                                             << 
1268                                               << 
1269 sub get_maintainer_role {                        932 sub get_maintainer_role {
1270     my ($index) = @_;                            933     my ($index) = @_;
1271                                                  934 
1272     my $i;                                       935     my $i;
1273     my $start = find_starting_index($index);     936     my $start = find_starting_index($index);
1274     my $end = find_ending_index($index);         937     my $end = find_ending_index($index);
1275                                                  938 
1276     my $role = "unknown";                        939     my $role = "unknown";
1277     my $subsystem = get_subsystem_name($index !! 940     my $subsystem = $typevalue[$start];
                                                   >> 941     if (length($subsystem) > 20) {
                                                   >> 942         $subsystem = substr($subsystem, 0, 17);
                                                   >> 943         $subsystem =~ s/\s*$//;
                                                   >> 944         $subsystem = $subsystem . "...";
                                                   >> 945     }
1278                                                  946 
1279     for ($i = $start + 1; $i < $end; $i++) {     947     for ($i = $start + 1; $i < $end; $i++) {
1280         my $tv = $typevalue[$i];                 948         my $tv = $typevalue[$i];
1281         if ($tv =~ m/^([A-Z]):\s*(.*)/) {     !! 949         if ($tv =~ m/^(\C):\s*(.*)/) {
1282             my $ptype = $1;                      950             my $ptype = $1;
1283             my $pvalue = $2;                     951             my $pvalue = $2;
1284             if ($ptype eq "S") {                 952             if ($ptype eq "S") {
1285                 $role = $pvalue;                 953                 $role = $pvalue;
1286             }                                    954             }
1287         }                                        955         }
1288     }                                            956     }
1289                                                  957 
1290     $role = lc($role);                           958     $role = lc($role);
1291     if      ($role eq "supported") {             959     if      ($role eq "supported") {
1292         $role = "supporter";                     960         $role = "supporter";
1293     } elsif ($role eq "maintained") {            961     } elsif ($role eq "maintained") {
1294         $role = "maintainer";                    962         $role = "maintainer";
1295     } elsif ($role eq "odd fixes") {             963     } elsif ($role eq "odd fixes") {
1296         $role = "odd fixer";                     964         $role = "odd fixer";
1297     } elsif ($role eq "orphan") {                965     } elsif ($role eq "orphan") {
1298         $role = "orphan minder";                 966         $role = "orphan minder";
1299     } elsif ($role eq "obsolete") {              967     } elsif ($role eq "obsolete") {
1300         $role = "obsolete minder";               968         $role = "obsolete minder";
1301     } elsif ($role eq "buried alive in report    969     } elsif ($role eq "buried alive in reporters") {
1302         $role = "chief penguin";                 970         $role = "chief penguin";
1303     }                                            971     }
1304                                                  972 
1305     return $role . ":" . $subsystem;             973     return $role . ":" . $subsystem;
1306 }                                                974 }
1307                                                  975 
1308 sub get_list_role {                              976 sub get_list_role {
1309     my ($index) = @_;                            977     my ($index) = @_;
1310                                                  978 
1311     my $subsystem = get_subsystem_name($index !! 979     my $i;
                                                   >> 980     my $start = find_starting_index($index);
                                                   >> 981     my $end = find_ending_index($index);
                                                   >> 982 
                                                   >> 983     my $subsystem = $typevalue[$start];
                                                   >> 984     if (length($subsystem) > 20) {
                                                   >> 985         $subsystem = substr($subsystem, 0, 17);
                                                   >> 986         $subsystem =~ s/\s*$//;
                                                   >> 987         $subsystem = $subsystem . "...";
                                                   >> 988     }
1312                                                  989 
1313     if ($subsystem eq "THE REST") {              990     if ($subsystem eq "THE REST") {
1314         $subsystem = "";                         991         $subsystem = "";
1315     }                                            992     }
1316                                                  993 
1317     return $subsystem;                           994     return $subsystem;
1318 }                                                995 }
1319                                                  996 
1320 sub add_categories {                             997 sub add_categories {
1321     my ($index, $suffix) = @_;                !! 998     my ($index) = @_;
1322                                                  999 
1323     my $i;                                       1000     my $i;
1324     my $start = find_starting_index($index);     1001     my $start = find_starting_index($index);
1325     my $end = find_ending_index($index);         1002     my $end = find_ending_index($index);
1326                                                  1003 
1327     push(@subsystem, $typevalue[$start]);        1004     push(@subsystem, $typevalue[$start]);
1328                                                  1005 
1329     for ($i = $start + 1; $i < $end; $i++) {     1006     for ($i = $start + 1; $i < $end; $i++) {
1330         my $tv = $typevalue[$i];                 1007         my $tv = $typevalue[$i];
1331         if ($tv =~ m/^([A-Z]):\s*(.*)/) {     !! 1008         if ($tv =~ m/^(\C):\s*(.*)/) {
1332             my $ptype = $1;                      1009             my $ptype = $1;
1333             my $pvalue = $2;                     1010             my $pvalue = $2;
1334             if ($ptype eq "L") {                 1011             if ($ptype eq "L") {
1335                 my $list_address = $pvalue;      1012                 my $list_address = $pvalue;
1336                 my $list_additional = "";        1013                 my $list_additional = "";
1337                 my $list_role = get_list_role    1014                 my $list_role = get_list_role($i);
1338                                                  1015 
1339                 if ($list_role ne "") {          1016                 if ($list_role ne "") {
1340                     $list_role = ":" . $list_    1017                     $list_role = ":" . $list_role;
1341                 }                                1018                 }
1342                 if ($list_address =~ m/([^\s]    1019                 if ($list_address =~ m/([^\s]+)\s+(.*)$/) {
1343                     $list_address = $1;          1020                     $list_address = $1;
1344                     $list_additional = $2;       1021                     $list_additional = $2;
1345                 }                                1022                 }
1346                 if ($list_additional =~ m/sub    1023                 if ($list_additional =~ m/subscribers-only/) {
1347                     if ($email_subscriber_lis    1024                     if ($email_subscriber_list) {
1348                         if (!$hash_list_to{lc    1025                         if (!$hash_list_to{lc($list_address)}) {
1349                             $hash_list_to{lc(    1026                             $hash_list_to{lc($list_address)} = 1;
1350                             push(@list_to, [$    1027                             push(@list_to, [$list_address,
1351                                             " !! 1028                                             "subscriber list${list_role}"]);
1352                         }                        1029                         }
1353                     }                            1030                     }
1354                 } else {                         1031                 } else {
1355                     if ($email_list) {           1032                     if ($email_list) {
1356                         if (!$hash_list_to{lc    1033                         if (!$hash_list_to{lc($list_address)}) {
                                                   >> 1034                             $hash_list_to{lc($list_address)} = 1;
1357                             if ($list_additio    1035                             if ($list_additional =~ m/moderated/) {
1358                                 if ($email_mo !! 1036                                 push(@list_to, [$list_address,
1359                                     $hash_lis !! 1037                                                 "moderated list${list_role}"]);
1360                                     push(@lis << 
1361                                               << 
1362                                 }             << 
1363                             } else {             1038                             } else {
1364                                 $hash_list_to << 
1365                                 push(@list_to    1039                                 push(@list_to, [$list_address,
1366                                               !! 1040                                                 "open list${list_role}"]);
1367                             }                    1041                             }
1368                         }                        1042                         }
1369                     }                            1043                     }
1370                 }                                1044                 }
1371             } elsif ($ptype eq "M") {            1045             } elsif ($ptype eq "M") {
                                                   >> 1046                 my ($name, $address) = parse_email($pvalue);
                                                   >> 1047                 if ($name eq "") {
                                                   >> 1048                     if ($i > 0) {
                                                   >> 1049                         my $tv = $typevalue[$i - 1];
                                                   >> 1050                         if ($tv =~ m/^(\C):\s*(.*)/) {
                                                   >> 1051                             if ($1 eq "P") {
                                                   >> 1052                                 $name = $2;
                                                   >> 1053                                 $pvalue = format_email($name, $address, $email_usename);
                                                   >> 1054                             }
                                                   >> 1055                         }
                                                   >> 1056                     }
                                                   >> 1057                 }
1372                 if ($email_maintainer) {         1058                 if ($email_maintainer) {
1373                     my $role = get_maintainer    1059                     my $role = get_maintainer_role($i);
1374                     push_email_addresses($pva !! 1060                     push_email_addresses($pvalue, $role);
1375                 }                             << 
1376             } elsif ($ptype eq "R") {         << 
1377                 if ($email_reviewer) {        << 
1378                     my $subsystem = get_subsy << 
1379                     push_email_addresses($pva << 
1380                 }                                1061                 }
1381             } elsif ($ptype eq "T") {            1062             } elsif ($ptype eq "T") {
1382                 push(@scm, $pvalue . $suffix) !! 1063                 push(@scm, $pvalue);
1383             } elsif ($ptype eq "W") {            1064             } elsif ($ptype eq "W") {
1384                 push(@web, $pvalue . $suffix) !! 1065                 push(@web, $pvalue);
1385             } elsif ($ptype eq "S") {            1066             } elsif ($ptype eq "S") {
1386                 push(@status, $pvalue . $suff !! 1067                 push(@status, $pvalue);
1387             }                                    1068             }
1388         }                                        1069         }
1389     }                                            1070     }
1390 }                                                1071 }
1391                                                  1072 
1392 sub email_inuse {                                1073 sub email_inuse {
1393     my ($name, $address) = @_;                   1074     my ($name, $address) = @_;
1394                                                  1075 
1395     return 1 if (($name eq "") && ($address e    1076     return 1 if (($name eq "") && ($address eq ""));
1396     return 1 if (($name ne "") && exists($ema    1077     return 1 if (($name ne "") && exists($email_hash_name{lc($name)}));
1397     return 1 if (($address ne "") && exists($    1078     return 1 if (($address ne "") && exists($email_hash_address{lc($address)}));
1398                                                  1079 
1399     return 0;                                    1080     return 0;
1400 }                                                1081 }
1401                                                  1082 
1402 sub push_email_address {                         1083 sub push_email_address {
1403     my ($line, $role) = @_;                      1084     my ($line, $role) = @_;
1404                                                  1085 
1405     my ($name, $address) = parse_email($line)    1086     my ($name, $address) = parse_email($line);
1406                                                  1087 
1407     if ($address eq "") {                        1088     if ($address eq "") {
1408         return 0;                                1089         return 0;
1409     }                                            1090     }
1410                                                  1091 
1411     if (!$email_remove_duplicates) {             1092     if (!$email_remove_duplicates) {
1412         push(@email_to, [format_email($name,     1093         push(@email_to, [format_email($name, $address, $email_usename), $role]);
1413     } elsif (!email_inuse($name, $address)) {    1094     } elsif (!email_inuse($name, $address)) {
1414         push(@email_to, [format_email($name,     1095         push(@email_to, [format_email($name, $address, $email_usename), $role]);
1415         $email_hash_name{lc($name)}++ if ($na    1096         $email_hash_name{lc($name)}++ if ($name ne "");
1416         $email_hash_address{lc($address)}++;     1097         $email_hash_address{lc($address)}++;
1417     }                                            1098     }
1418                                                  1099 
1419     return 1;                                    1100     return 1;
1420 }                                                1101 }
1421                                                  1102 
1422 sub push_email_addresses {                       1103 sub push_email_addresses {
1423     my ($address, $role) = @_;                   1104     my ($address, $role) = @_;
1424                                                  1105 
1425     my @address_list = ();                       1106     my @address_list = ();
1426                                                  1107 
1427     if (rfc822_valid($address)) {                1108     if (rfc822_valid($address)) {
1428         push_email_address($address, $role);     1109         push_email_address($address, $role);
1429     } elsif (@address_list = rfc822_validlist    1110     } elsif (@address_list = rfc822_validlist($address)) {
1430         my $array_count = shift(@address_list    1111         my $array_count = shift(@address_list);
1431         while (my $entry = shift(@address_lis    1112         while (my $entry = shift(@address_list)) {
1432             push_email_address($entry, $role)    1113             push_email_address($entry, $role);
1433         }                                        1114         }
1434     } else {                                     1115     } else {
1435         if (!push_email_address($address, $ro    1116         if (!push_email_address($address, $role)) {
1436             warn("Invalid MAINTAINERS address    1117             warn("Invalid MAINTAINERS address: '" . $address . "'\n");
1437         }                                        1118         }
1438     }                                            1119     }
1439 }                                                1120 }
1440                                                  1121 
1441 sub add_role {                                   1122 sub add_role {
1442     my ($line, $role) = @_;                      1123     my ($line, $role) = @_;
1443                                                  1124 
1444     my ($name, $address) = parse_email($line)    1125     my ($name, $address) = parse_email($line);
1445     my $email = format_email($name, $address,    1126     my $email = format_email($name, $address, $email_usename);
1446                                                  1127 
1447     foreach my $entry (@email_to) {              1128     foreach my $entry (@email_to) {
1448         if ($email_remove_duplicates) {          1129         if ($email_remove_duplicates) {
1449             my ($entry_name, $entry_address)     1130             my ($entry_name, $entry_address) = parse_email($entry->[0]);
1450             if (($name eq $entry_name || $add    1131             if (($name eq $entry_name || $address eq $entry_address)
1451                 && ($role eq "" || !($entry->    1132                 && ($role eq "" || !($entry->[1] =~ m/$role/))
1452             ) {                                  1133             ) {
1453                 if ($entry->[1] eq "") {         1134                 if ($entry->[1] eq "") {
1454                     $entry->[1] = "$role";       1135                     $entry->[1] = "$role";
1455                 } else {                         1136                 } else {
1456                     $entry->[1] = "$entry->[1    1137                     $entry->[1] = "$entry->[1],$role";
1457                 }                                1138                 }
1458             }                                    1139             }
1459         } else {                                 1140         } else {
1460             if ($email eq $entry->[0]            1141             if ($email eq $entry->[0]
1461                 && ($role eq "" || !($entry->    1142                 && ($role eq "" || !($entry->[1] =~ m/$role/))
1462             ) {                                  1143             ) {
1463                 if ($entry->[1] eq "") {         1144                 if ($entry->[1] eq "") {
1464                     $entry->[1] = "$role";       1145                     $entry->[1] = "$role";
1465                 } else {                         1146                 } else {
1466                     $entry->[1] = "$entry->[1    1147                     $entry->[1] = "$entry->[1],$role";
1467                 }                                1148                 }
1468             }                                    1149             }
1469         }                                        1150         }
1470     }                                            1151     }
1471 }                                                1152 }
1472                                                  1153 
1473 sub which {                                      1154 sub which {
1474     my ($bin) = @_;                              1155     my ($bin) = @_;
1475                                                  1156 
1476     foreach my $path (split(/:/, $ENV{PATH}))    1157     foreach my $path (split(/:/, $ENV{PATH})) {
1477         if (-e "$path/$bin") {                   1158         if (-e "$path/$bin") {
1478             return "$path/$bin";                 1159             return "$path/$bin";
1479         }                                        1160         }
1480     }                                            1161     }
1481                                                  1162 
1482     return "";                                   1163     return "";
1483 }                                                1164 }
1484                                                  1165 
1485 sub which_conf {                                 1166 sub which_conf {
1486     my ($conf) = @_;                             1167     my ($conf) = @_;
1487                                                  1168 
1488     foreach my $path (split(/:/, ".:$ENV{HOME    1169     foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
1489         if (-e "$path/$conf") {                  1170         if (-e "$path/$conf") {
1490             return "$path/$conf";                1171             return "$path/$conf";
1491         }                                        1172         }
1492     }                                            1173     }
1493                                                  1174 
1494     return "";                                   1175     return "";
1495 }                                                1176 }
1496                                                  1177 
1497 sub mailmap_email {                              1178 sub mailmap_email {
1498     my ($line) = @_;                             1179     my ($line) = @_;
1499                                                  1180 
1500     my ($name, $address) = parse_email($line)    1181     my ($name, $address) = parse_email($line);
1501     my $email = format_email($name, $address,    1182     my $email = format_email($name, $address, 1);
1502     my $real_name = $name;                       1183     my $real_name = $name;
1503     my $real_address = $address;                 1184     my $real_address = $address;
1504                                                  1185 
1505     if (exists $mailmap->{names}->{$email} ||    1186     if (exists $mailmap->{names}->{$email} ||
1506         exists $mailmap->{addresses}->{$email    1187         exists $mailmap->{addresses}->{$email}) {
1507         if (exists $mailmap->{names}->{$email    1188         if (exists $mailmap->{names}->{$email}) {
1508             $real_name = $mailmap->{names}->{    1189             $real_name = $mailmap->{names}->{$email};
1509         }                                        1190         }
1510         if (exists $mailmap->{addresses}->{$e    1191         if (exists $mailmap->{addresses}->{$email}) {
1511             $real_address = $mailmap->{addres    1192             $real_address = $mailmap->{addresses}->{$email};
1512         }                                        1193         }
1513     } else {                                     1194     } else {
1514         if (exists $mailmap->{names}->{$addre    1195         if (exists $mailmap->{names}->{$address}) {
1515             $real_name = $mailmap->{names}->{    1196             $real_name = $mailmap->{names}->{$address};
1516         }                                        1197         }
1517         if (exists $mailmap->{addresses}->{$a    1198         if (exists $mailmap->{addresses}->{$address}) {
1518             $real_address = $mailmap->{addres    1199             $real_address = $mailmap->{addresses}->{$address};
1519         }                                        1200         }
1520     }                                            1201     }
1521     return format_email($real_name, $real_add    1202     return format_email($real_name, $real_address, 1);
1522 }                                                1203 }
1523                                                  1204 
1524 sub mailmap {                                    1205 sub mailmap {
1525     my (@addresses) = @_;                        1206     my (@addresses) = @_;
1526                                                  1207 
1527     my @mapped_emails = ();                      1208     my @mapped_emails = ();
1528     foreach my $line (@addresses) {              1209     foreach my $line (@addresses) {
1529         push(@mapped_emails, mailmap_email($l    1210         push(@mapped_emails, mailmap_email($line));
1530     }                                            1211     }
1531     merge_by_realname(@mapped_emails) if ($em    1212     merge_by_realname(@mapped_emails) if ($email_use_mailmap);
1532     return @mapped_emails;                       1213     return @mapped_emails;
1533 }                                                1214 }
1534                                                  1215 
1535 sub merge_by_realname {                          1216 sub merge_by_realname {
1536     my %address_map;                             1217     my %address_map;
1537     my (@emails) = @_;                           1218     my (@emails) = @_;
1538                                                  1219 
1539     foreach my $email (@emails) {                1220     foreach my $email (@emails) {
1540         my ($name, $address) = parse_email($e    1221         my ($name, $address) = parse_email($email);
1541         if (exists $address_map{$name}) {        1222         if (exists $address_map{$name}) {
1542             $address = $address_map{$name};      1223             $address = $address_map{$name};
1543             $email = format_email($name, $add    1224             $email = format_email($name, $address, 1);
1544         } else {                                 1225         } else {
1545             $address_map{$name} = $address;      1226             $address_map{$name} = $address;
1546         }                                        1227         }
1547     }                                            1228     }
1548 }                                                1229 }
1549                                                  1230 
1550 sub git_execute_cmd {                            1231 sub git_execute_cmd {
1551     my ($cmd) = @_;                              1232     my ($cmd) = @_;
1552     my @lines = ();                              1233     my @lines = ();
1553                                                  1234 
1554     my $output = `$cmd`;                         1235     my $output = `$cmd`;
1555     $output =~ s/^\s*//gm;                       1236     $output =~ s/^\s*//gm;
1556     @lines = split("\n", $output);               1237     @lines = split("\n", $output);
1557                                                  1238 
1558     return @lines;                               1239     return @lines;
1559 }                                                1240 }
1560                                                  1241 
1561 sub hg_execute_cmd {                             1242 sub hg_execute_cmd {
1562     my ($cmd) = @_;                              1243     my ($cmd) = @_;
1563     my @lines = ();                              1244     my @lines = ();
1564                                                  1245 
1565     my $output = `$cmd`;                         1246     my $output = `$cmd`;
1566     @lines = split("\n", $output);               1247     @lines = split("\n", $output);
1567                                                  1248 
1568     return @lines;                               1249     return @lines;
1569 }                                                1250 }
1570                                                  1251 
1571 sub extract_formatted_signatures {               1252 sub extract_formatted_signatures {
1572     my (@signature_lines) = @_;                  1253     my (@signature_lines) = @_;
1573                                                  1254 
1574     my @type = @signature_lines;                 1255     my @type = @signature_lines;
1575                                                  1256 
1576     s/\s*(.*):.*/$1/ for (@type);                1257     s/\s*(.*):.*/$1/ for (@type);
1577                                                  1258 
1578     # cut -f2- -d":"                             1259     # cut -f2- -d":"
1579     s/\s*.*:\s*(.+)\s*/$1/ for (@signature_li    1260     s/\s*.*:\s*(.+)\s*/$1/ for (@signature_lines);
1580                                                  1261 
1581 ## Reformat email addresses (with names) to a    1262 ## Reformat email addresses (with names) to avoid badly written signatures
1582                                                  1263 
1583     foreach my $signer (@signature_lines) {      1264     foreach my $signer (@signature_lines) {
1584         $signer = deduplicate_email($signer);    1265         $signer = deduplicate_email($signer);
1585     }                                            1266     }
1586                                                  1267 
1587     return (\@type, \@signature_lines);          1268     return (\@type, \@signature_lines);
1588 }                                                1269 }
1589                                                  1270 
1590 sub vcs_find_signers {                           1271 sub vcs_find_signers {
1591     my ($cmd, $file) = @_;                    !! 1272     my ($cmd) = @_;
1592     my $commits;                                 1273     my $commits;
1593     my @lines = ();                              1274     my @lines = ();
1594     my @signatures = ();                         1275     my @signatures = ();
1595     my @authors = ();                         << 
1596     my @stats = ();                           << 
1597                                                  1276 
1598     @lines = &{$VCS_cmds{"execute_cmd"}}($cmd    1277     @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
1599                                                  1278 
1600     my $pattern = $VCS_cmds{"commit_pattern"}    1279     my $pattern = $VCS_cmds{"commit_pattern"};
1601     my $author_pattern = $VCS_cmds{"author_pa << 
1602     my $stat_pattern = $VCS_cmds{"stat_patter << 
1603                                               << 
1604     $stat_pattern =~ s/(\$\w+)/$1/eeg;        << 
1605                                                  1280 
1606     $commits = grep(/$pattern/, @lines);         1281     $commits = grep(/$pattern/, @lines);        # of commits
1607                                                  1282 
1608     @authors = grep(/$author_pattern/, @lines << 
1609     @signatures = grep(/^[ \t]*${signature_pa    1283     @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines);
1610     @stats = grep(/$stat_pattern/, @lines);   << 
1611                                               << 
1612 #    print("stats: <@stats>\n");               << 
1613                                                  1284 
1614     return (0, \@signatures, \@authors, \@sta !! 1285     return (0, @signatures) if !@signatures;
1615                                                  1286 
1616     save_commits_by_author(@lines) if ($inter    1287     save_commits_by_author(@lines) if ($interactive);
1617     save_commits_by_signer(@lines) if ($inter    1288     save_commits_by_signer(@lines) if ($interactive);
1618                                                  1289 
1619     if (!$email_git_penguin_chiefs) {            1290     if (!$email_git_penguin_chiefs) {
1620         @signatures = grep(!/${penguin_chiefs    1291         @signatures = grep(!/${penguin_chiefs}/i, @signatures);
1621     }                                            1292     }
1622                                                  1293 
1623     my ($author_ref, $authors_ref) = extract_ << 
1624     my ($types_ref, $signers_ref) = extract_f    1294     my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
1625                                                  1295 
1626     return ($commits, $signers_ref, $authors_ !! 1296     return ($commits, @$signers_ref);
1627 }                                                1297 }
1628                                                  1298 
1629 sub vcs_find_author {                            1299 sub vcs_find_author {
1630     my ($cmd) = @_;                              1300     my ($cmd) = @_;
1631     my @lines = ();                              1301     my @lines = ();
1632                                                  1302 
1633     @lines = &{$VCS_cmds{"execute_cmd"}}($cmd    1303     @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
1634                                                  1304 
1635     if (!$email_git_penguin_chiefs) {            1305     if (!$email_git_penguin_chiefs) {
1636         @lines = grep(!/${penguin_chiefs}/i,     1306         @lines = grep(!/${penguin_chiefs}/i, @lines);
1637     }                                            1307     }
1638                                                  1308 
1639     return @lines if !@lines;                    1309     return @lines if !@lines;
1640                                                  1310 
1641     my @authors = ();                            1311     my @authors = ();
1642     foreach my $line (@lines) {                  1312     foreach my $line (@lines) {
1643         if ($line =~ m/$VCS_cmds{"author_patt    1313         if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
1644             my $author = $1;                     1314             my $author = $1;
1645             my ($name, $address) = parse_emai    1315             my ($name, $address) = parse_email($author);
1646             $author = format_email($name, $ad    1316             $author = format_email($name, $address, 1);
1647             push(@authors, $author);             1317             push(@authors, $author);
1648         }                                        1318         }
1649     }                                            1319     }
1650                                                  1320 
1651     save_commits_by_author(@lines) if ($inter    1321     save_commits_by_author(@lines) if ($interactive);
1652     save_commits_by_signer(@lines) if ($inter    1322     save_commits_by_signer(@lines) if ($interactive);
1653                                                  1323 
1654     return @authors;                             1324     return @authors;
1655 }                                                1325 }
1656                                                  1326 
1657 sub vcs_save_commits {                           1327 sub vcs_save_commits {
1658     my ($cmd) = @_;                              1328     my ($cmd) = @_;
1659     my @lines = ();                              1329     my @lines = ();
1660     my @commits = ();                            1330     my @commits = ();
1661                                                  1331 
1662     @lines = &{$VCS_cmds{"execute_cmd"}}($cmd    1332     @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
1663                                                  1333 
1664     foreach my $line (@lines) {                  1334     foreach my $line (@lines) {
1665         if ($line =~ m/$VCS_cmds{"blame_commi    1335         if ($line =~ m/$VCS_cmds{"blame_commit_pattern"}/) {
1666             push(@commits, $1);                  1336             push(@commits, $1);
1667         }                                        1337         }
1668     }                                            1338     }
1669                                                  1339 
1670     return @commits;                             1340     return @commits;
1671 }                                                1341 }
1672                                                  1342 
1673 sub vcs_blame {                                  1343 sub vcs_blame {
1674     my ($file) = @_;                             1344     my ($file) = @_;
1675     my $cmd;                                     1345     my $cmd;
1676     my @commits = ();                            1346     my @commits = ();
1677                                                  1347 
1678     return @commits if (!(-f $file));            1348     return @commits if (!(-f $file));
1679                                                  1349 
1680     if (@range && $VCS_cmds{"blame_range_cmd"    1350     if (@range && $VCS_cmds{"blame_range_cmd"} eq "") {
1681         my @all_commits = ();                    1351         my @all_commits = ();
1682                                                  1352 
1683         $cmd = $VCS_cmds{"blame_file_cmd"};      1353         $cmd = $VCS_cmds{"blame_file_cmd"};
1684         $cmd =~ s/(\$\w+)/$1/eeg;                1354         $cmd =~ s/(\$\w+)/$1/eeg;               #interpolate $cmd
1685         @all_commits = vcs_save_commits($cmd)    1355         @all_commits = vcs_save_commits($cmd);
1686                                                  1356 
1687         foreach my $file_range_diff (@range)     1357         foreach my $file_range_diff (@range) {
1688             next if (!($file_range_diff =~ m/    1358             next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
1689             my $diff_file = $1;                  1359             my $diff_file = $1;
1690             my $diff_start = $2;                 1360             my $diff_start = $2;
1691             my $diff_length = $3;                1361             my $diff_length = $3;
1692             next if ("$file" ne "$diff_file")    1362             next if ("$file" ne "$diff_file");
1693             for (my $i = $diff_start; $i < $d    1363             for (my $i = $diff_start; $i < $diff_start + $diff_length; $i++) {
1694                 push(@commits, $all_commits[$    1364                 push(@commits, $all_commits[$i]);
1695             }                                    1365             }
1696         }                                        1366         }
1697     } elsif (@range) {                           1367     } elsif (@range) {
1698         foreach my $file_range_diff (@range)     1368         foreach my $file_range_diff (@range) {
1699             next if (!($file_range_diff =~ m/    1369             next if (!($file_range_diff =~ m/(.+):(.+):(.+)/));
1700             my $diff_file = $1;                  1370             my $diff_file = $1;
1701             my $diff_start = $2;                 1371             my $diff_start = $2;
1702             my $diff_length = $3;                1372             my $diff_length = $3;
1703             next if ("$file" ne "$diff_file")    1373             next if ("$file" ne "$diff_file");
1704             $cmd = $VCS_cmds{"blame_range_cmd    1374             $cmd = $VCS_cmds{"blame_range_cmd"};
1705             $cmd =~ s/(\$\w+)/$1/eeg;            1375             $cmd =~ s/(\$\w+)/$1/eeg;           #interpolate $cmd
1706             push(@commits, vcs_save_commits($    1376             push(@commits, vcs_save_commits($cmd));
1707         }                                        1377         }
1708     } else {                                     1378     } else {
1709         $cmd = $VCS_cmds{"blame_file_cmd"};      1379         $cmd = $VCS_cmds{"blame_file_cmd"};
1710         $cmd =~ s/(\$\w+)/$1/eeg;                1380         $cmd =~ s/(\$\w+)/$1/eeg;               #interpolate $cmd
1711         @commits = vcs_save_commits($cmd);       1381         @commits = vcs_save_commits($cmd);
1712     }                                            1382     }
1713                                                  1383 
1714     foreach my $commit (@commits) {              1384     foreach my $commit (@commits) {
1715         $commit =~ s/^\^//g;                     1385         $commit =~ s/^\^//g;
1716     }                                            1386     }
1717                                                  1387 
1718     return @commits;                             1388     return @commits;
1719 }                                                1389 }
1720                                                  1390 
1721 my $printed_novcs = 0;                           1391 my $printed_novcs = 0;
1722 sub vcs_exists {                                 1392 sub vcs_exists {
1723     %VCS_cmds = %VCS_cmds_git;                   1393     %VCS_cmds = %VCS_cmds_git;
1724     return 1 if eval $VCS_cmds{"available"};     1394     return 1 if eval $VCS_cmds{"available"};
1725     %VCS_cmds = %VCS_cmds_hg;                    1395     %VCS_cmds = %VCS_cmds_hg;
1726     return 2 if eval $VCS_cmds{"available"};     1396     return 2 if eval $VCS_cmds{"available"};
1727     %VCS_cmds = ();                              1397     %VCS_cmds = ();
1728     if (!$printed_novcs && $email_git) {      !! 1398     if (!$printed_novcs) {
1729         warn("$P: No supported VCS found.  Ad    1399         warn("$P: No supported VCS found.  Add --nogit to options?\n");
1730         warn("Using a git repository produces    1400         warn("Using a git repository produces better results.\n");
1731         warn("Try Linus Torvalds' latest git     1401         warn("Try Linus Torvalds' latest git repository using:\n");
1732         warn("git clone git://git.kernel.org/    1402         warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n");
1733         $printed_novcs = 1;                      1403         $printed_novcs = 1;
1734     }                                            1404     }
1735     return 0;                                    1405     return 0;
1736 }                                                1406 }
1737                                                  1407 
1738 sub vcs_is_git {                                 1408 sub vcs_is_git {
1739     vcs_exists();                                1409     vcs_exists();
1740     return $vcs_used == 1;                       1410     return $vcs_used == 1;
1741 }                                                1411 }
1742                                                  1412 
1743 sub vcs_is_hg {                                  1413 sub vcs_is_hg {
1744     return $vcs_used == 2;                       1414     return $vcs_used == 2;
1745 }                                                1415 }
1746                                                  1416 
1747 sub vcs_add_commit_signers {                  << 
1748     return if (!vcs_exists());                << 
1749                                               << 
1750     my ($commit, $desc) = @_;                 << 
1751     my $commit_count = 0;                     << 
1752     my $commit_authors_ref;                   << 
1753     my $commit_signers_ref;                   << 
1754     my $stats_ref;                            << 
1755     my @commit_authors = ();                  << 
1756     my @commit_signers = ();                  << 
1757     my $cmd;                                  << 
1758                                               << 
1759     $cmd = $VCS_cmds{"find_commit_signers_cmd << 
1760     $cmd =~ s/(\$\w+)/$1/eeg;   #substitute v << 
1761                                               << 
1762     ($commit_count, $commit_signers_ref, $com << 
1763     @commit_authors = @{$commit_authors_ref}  << 
1764     @commit_signers = @{$commit_signers_ref}  << 
1765                                               << 
1766     foreach my $signer (@commit_signers) {    << 
1767         $signer = deduplicate_email($signer); << 
1768     }                                         << 
1769                                               << 
1770     vcs_assign($desc, 1, @commit_signers);    << 
1771 }                                             << 
1772                                               << 
1773 sub interactive_get_maintainers {                1417 sub interactive_get_maintainers {
1774     my ($list_ref) = @_;                         1418     my ($list_ref) = @_;
1775     my @list = @$list_ref;                       1419     my @list = @$list_ref;
1776                                                  1420 
1777     vcs_exists();                                1421     vcs_exists();
1778                                                  1422 
1779     my %selected;                                1423     my %selected;
1780     my %authored;                                1424     my %authored;
1781     my %signed;                                  1425     my %signed;
1782     my $count = 0;                               1426     my $count = 0;
1783     my $maintained = 0;                          1427     my $maintained = 0;
1784     foreach my $entry (@list) {                  1428     foreach my $entry (@list) {
1785         $maintained = 1 if ($entry->[1] =~ /^    1429         $maintained = 1 if ($entry->[1] =~ /^(maintainer|supporter)/i);
1786         $selected{$count} = 1;                   1430         $selected{$count} = 1;
1787         $authored{$count} = 0;                   1431         $authored{$count} = 0;
1788         $signed{$count} = 0;                     1432         $signed{$count} = 0;
1789         $count++;                                1433         $count++;
1790     }                                            1434     }
1791                                                  1435 
1792     #menu loop                                   1436     #menu loop
1793     my $done = 0;                                1437     my $done = 0;
1794     my $print_options = 0;                       1438     my $print_options = 0;
1795     my $redraw = 1;                              1439     my $redraw = 1;
1796     while (!$done) {                             1440     while (!$done) {
1797         $count = 0;                              1441         $count = 0;
1798         if ($redraw) {                           1442         if ($redraw) {
1799             printf STDERR "\n%1s %2s %-65s",     1443             printf STDERR "\n%1s %2s %-65s",
1800                           "*", "#", "email/li    1444                           "*", "#", "email/list and role:stats";
1801             if ($email_git ||                    1445             if ($email_git ||
1802                 ($email_git_fallback && !$mai    1446                 ($email_git_fallback && !$maintained) ||
1803                 $email_git_blame) {              1447                 $email_git_blame) {
1804                 print STDERR "auth sign";        1448                 print STDERR "auth sign";
1805             }                                    1449             }
1806             print STDERR "\n";                   1450             print STDERR "\n";
1807             foreach my $entry (@list) {          1451             foreach my $entry (@list) {
1808                 my $email = $entry->[0];         1452                 my $email = $entry->[0];
1809                 my $role = $entry->[1];          1453                 my $role = $entry->[1];
1810                 my $sel = "";                    1454                 my $sel = "";
1811                 $sel = "*" if ($selected{$cou    1455                 $sel = "*" if ($selected{$count});
1812                 my $commit_author = $commit_a    1456                 my $commit_author = $commit_author_hash{$email};
1813                 my $commit_signer = $commit_s    1457                 my $commit_signer = $commit_signer_hash{$email};
1814                 my $authored = 0;                1458                 my $authored = 0;
1815                 my $signed = 0;                  1459                 my $signed = 0;
1816                 $authored++ for (@{$commit_au    1460                 $authored++ for (@{$commit_author});
1817                 $signed++ for (@{$commit_sign    1461                 $signed++ for (@{$commit_signer});
1818                 printf STDERR "%1s %2d %-65s"    1462                 printf STDERR "%1s %2d %-65s", $sel, $count + 1, $email;
1819                 printf STDERR "%4d %4d", $aut    1463                 printf STDERR "%4d %4d", $authored, $signed
1820                     if ($authored > 0 || $sig    1464                     if ($authored > 0 || $signed > 0);
1821                 printf STDERR "\n     %s\n",     1465                 printf STDERR "\n     %s\n", $role;
1822                 if ($authored{$count}) {         1466                 if ($authored{$count}) {
1823                     my $commit_author = $comm    1467                     my $commit_author = $commit_author_hash{$email};
1824                     foreach my $ref (@{$commi    1468                     foreach my $ref (@{$commit_author}) {
1825                         print STDERR "     Au    1469                         print STDERR "     Author: @{$ref}[1]\n";
1826                     }                            1470                     }
1827                 }                                1471                 }
1828                 if ($signed{$count}) {           1472                 if ($signed{$count}) {
1829                     my $commit_signer = $comm    1473                     my $commit_signer = $commit_signer_hash{$email};
1830                     foreach my $ref (@{$commi    1474                     foreach my $ref (@{$commit_signer}) {
1831                         print STDERR "     @{    1475                         print STDERR "     @{$ref}[2]: @{$ref}[1]\n";
1832                     }                            1476                     }
1833                 }                                1477                 }
1834                                                  1478 
1835                 $count++;                        1479                 $count++;
1836             }                                    1480             }
1837         }                                        1481         }
1838         my $date_ref = \$email_git_since;        1482         my $date_ref = \$email_git_since;
1839         $date_ref = \$email_hg_since if (vcs_    1483         $date_ref = \$email_hg_since if (vcs_is_hg());
1840         if ($print_options) {                    1484         if ($print_options) {
1841             $print_options = 0;                  1485             $print_options = 0;
1842             if (vcs_exists()) {                  1486             if (vcs_exists()) {
1843                 print STDERR <<EOT               1487                 print STDERR <<EOT
1844                                                  1488 
1845 Version Control options:                         1489 Version Control options:
1846 g  use git history      [$email_git]             1490 g  use git history      [$email_git]
1847 gf use git-fallback     [$email_git_fallback]    1491 gf use git-fallback     [$email_git_fallback]
1848 b  use git blame        [$email_git_blame]       1492 b  use git blame        [$email_git_blame]
1849 bs use blame signatures [$email_git_blame_sig    1493 bs use blame signatures [$email_git_blame_signatures]
1850 c# minimum commits      [$email_git_min_signa    1494 c# minimum commits      [$email_git_min_signatures]
1851 %# min percent          [$email_git_min_perce    1495 %# min percent          [$email_git_min_percent]
1852 d# history to use       [$$date_ref]             1496 d# history to use       [$$date_ref]
1853 x# max maintainers      [$email_git_max_maint    1497 x# max maintainers      [$email_git_max_maintainers]
1854 t  all signature types  [$email_git_all_signa    1498 t  all signature types  [$email_git_all_signature_types]
1855 m  use .mailmap         [$email_use_mailmap]     1499 m  use .mailmap         [$email_use_mailmap]
1856 EOT                                              1500 EOT
1857             }                                    1501             }
1858             print STDERR <<EOT                   1502             print STDERR <<EOT
1859                                                  1503 
1860 Additional options:                              1504 Additional options:
1861 0  toggle all                                    1505 0  toggle all
1862 tm toggle maintainers                            1506 tm toggle maintainers
1863 tg toggle git entries                            1507 tg toggle git entries
1864 tl toggle open list entries                      1508 tl toggle open list entries
1865 ts toggle subscriber list entries                1509 ts toggle subscriber list entries
1866 f  emails in file       [$email_file_emails]  !! 1510 f  emails in file       [$file_emails]
1867 k  keywords in file     [$keywords]              1511 k  keywords in file     [$keywords]
1868 r  remove duplicates    [$email_remove_duplic    1512 r  remove duplicates    [$email_remove_duplicates]
1869 p# pattern match depth  [$pattern_depth]         1513 p# pattern match depth  [$pattern_depth]
1870 EOT                                              1514 EOT
1871         }                                        1515         }
1872         print STDERR                             1516         print STDERR
1873 "\n#(toggle), A#(author), S#(signed) *(all),     1517 "\n#(toggle), A#(author), S#(signed) *(all), ^(none), O(options), Y(approve): ";
1874                                                  1518 
1875         my $input = <STDIN>;                     1519         my $input = <STDIN>;
1876         chomp($input);                           1520         chomp($input);
1877                                                  1521 
1878         $redraw = 1;                             1522         $redraw = 1;
1879         my $rerun = 0;                           1523         my $rerun = 0;
1880         my @wish = split(/[, ]+/, $input);       1524         my @wish = split(/[, ]+/, $input);
1881         foreach my $nr (@wish) {                 1525         foreach my $nr (@wish) {
1882             $nr = lc($nr);                       1526             $nr = lc($nr);
1883             my $sel = substr($nr, 0, 1);         1527             my $sel = substr($nr, 0, 1);
1884             my $str = substr($nr, 1);            1528             my $str = substr($nr, 1);
1885             my $val = 0;                         1529             my $val = 0;
1886             $val = $1 if $str =~ /^(\d+)$/;      1530             $val = $1 if $str =~ /^(\d+)$/;
1887                                                  1531 
1888             if ($sel eq "y") {                   1532             if ($sel eq "y") {
1889                 $interactive = 0;                1533                 $interactive = 0;
1890                 $done = 1;                       1534                 $done = 1;
1891                 $output_rolestats = 0;           1535                 $output_rolestats = 0;
1892                 $output_roles = 0;               1536                 $output_roles = 0;
1893                 last;                            1537                 last;
1894             } elsif ($nr =~ /^\d+$/ && $nr >     1538             } elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
1895                 $selected{$nr - 1} = !$select    1539                 $selected{$nr - 1} = !$selected{$nr - 1};
1896             } elsif ($sel eq "*" || $sel eq '    1540             } elsif ($sel eq "*" || $sel eq '^') {
1897                 my $toggle = 0;                  1541                 my $toggle = 0;
1898                 $toggle = 1 if ($sel eq '*');    1542                 $toggle = 1 if ($sel eq '*');
1899                 for (my $i = 0; $i < $count;     1543                 for (my $i = 0; $i < $count; $i++) {
1900                     $selected{$i} = $toggle;     1544                     $selected{$i} = $toggle;
1901                 }                                1545                 }
1902             } elsif ($sel eq "0") {              1546             } elsif ($sel eq "0") {
1903                 for (my $i = 0; $i < $count;     1547                 for (my $i = 0; $i < $count; $i++) {
1904                     $selected{$i} = !$selecte    1548                     $selected{$i} = !$selected{$i};
1905                 }                                1549                 }
1906             } elsif ($sel eq "t") {              1550             } elsif ($sel eq "t") {
1907                 if (lc($str) eq "m") {           1551                 if (lc($str) eq "m") {
1908                     for (my $i = 0; $i < $cou    1552                     for (my $i = 0; $i < $count; $i++) {
1909                         $selected{$i} = !$sel    1553                         $selected{$i} = !$selected{$i}
1910                             if ($list[$i]->[1    1554                             if ($list[$i]->[1] =~ /^(maintainer|supporter)/i);
1911                     }                            1555                     }
1912                 } elsif (lc($str) eq "g") {      1556                 } elsif (lc($str) eq "g") {
1913                     for (my $i = 0; $i < $cou    1557                     for (my $i = 0; $i < $count; $i++) {
1914                         $selected{$i} = !$sel    1558                         $selected{$i} = !$selected{$i}
1915                             if ($list[$i]->[1    1559                             if ($list[$i]->[1] =~ /^(author|commit|signer)/i);
1916                     }                            1560                     }
1917                 } elsif (lc($str) eq "l") {      1561                 } elsif (lc($str) eq "l") {
1918                     for (my $i = 0; $i < $cou    1562                     for (my $i = 0; $i < $count; $i++) {
1919                         $selected{$i} = !$sel    1563                         $selected{$i} = !$selected{$i}
1920                             if ($list[$i]->[1    1564                             if ($list[$i]->[1] =~ /^(open list)/i);
1921                     }                            1565                     }
1922                 } elsif (lc($str) eq "s") {      1566                 } elsif (lc($str) eq "s") {
1923                     for (my $i = 0; $i < $cou    1567                     for (my $i = 0; $i < $count; $i++) {
1924                         $selected{$i} = !$sel    1568                         $selected{$i} = !$selected{$i}
1925                             if ($list[$i]->[1    1569                             if ($list[$i]->[1] =~ /^(subscriber list)/i);
1926                     }                            1570                     }
1927                 }                                1571                 }
1928             } elsif ($sel eq "a") {              1572             } elsif ($sel eq "a") {
1929                 if ($val > 0 && $val <= $coun    1573                 if ($val > 0 && $val <= $count) {
1930                     $authored{$val - 1} = !$a    1574                     $authored{$val - 1} = !$authored{$val - 1};
1931                 } elsif ($str eq '*' || $str     1575                 } elsif ($str eq '*' || $str eq '^') {
1932                     my $toggle = 0;              1576                     my $toggle = 0;
1933                     $toggle = 1 if ($str eq '    1577                     $toggle = 1 if ($str eq '*');
1934                     for (my $i = 0; $i < $cou    1578                     for (my $i = 0; $i < $count; $i++) {
1935                         $authored{$i} = $togg    1579                         $authored{$i} = $toggle;
1936                     }                            1580                     }
1937                 }                                1581                 }
1938             } elsif ($sel eq "s") {              1582             } elsif ($sel eq "s") {
1939                 if ($val > 0 && $val <= $coun    1583                 if ($val > 0 && $val <= $count) {
1940                     $signed{$val - 1} = !$sig    1584                     $signed{$val - 1} = !$signed{$val - 1};
1941                 } elsif ($str eq '*' || $str     1585                 } elsif ($str eq '*' || $str eq '^') {
1942                     my $toggle = 0;              1586                     my $toggle = 0;
1943                     $toggle = 1 if ($str eq '    1587                     $toggle = 1 if ($str eq '*');
1944                     for (my $i = 0; $i < $cou    1588                     for (my $i = 0; $i < $count; $i++) {
1945                         $signed{$i} = $toggle    1589                         $signed{$i} = $toggle;
1946                     }                            1590                     }
1947                 }                                1591                 }
1948             } elsif ($sel eq "o") {              1592             } elsif ($sel eq "o") {
1949                 $print_options = 1;              1593                 $print_options = 1;
1950                 $redraw = 1;                     1594                 $redraw = 1;
1951             } elsif ($sel eq "g") {              1595             } elsif ($sel eq "g") {
1952                 if ($str eq "f") {               1596                 if ($str eq "f") {
1953                     bool_invert(\$email_git_f    1597                     bool_invert(\$email_git_fallback);
1954                 } else {                         1598                 } else {
1955                     bool_invert(\$email_git);    1599                     bool_invert(\$email_git);
1956                 }                                1600                 }
1957                 $rerun = 1;                      1601                 $rerun = 1;
1958             } elsif ($sel eq "b") {              1602             } elsif ($sel eq "b") {
1959                 if ($str eq "s") {               1603                 if ($str eq "s") {
1960                     bool_invert(\$email_git_b    1604                     bool_invert(\$email_git_blame_signatures);
1961                 } else {                         1605                 } else {
1962                     bool_invert(\$email_git_b    1606                     bool_invert(\$email_git_blame);
1963                 }                                1607                 }
1964                 $rerun = 1;                      1608                 $rerun = 1;
1965             } elsif ($sel eq "c") {              1609             } elsif ($sel eq "c") {
1966                 if ($val > 0) {                  1610                 if ($val > 0) {
1967                     $email_git_min_signatures    1611                     $email_git_min_signatures = $val;
1968                     $rerun = 1;                  1612                     $rerun = 1;
1969                 }                                1613                 }
1970             } elsif ($sel eq "x") {              1614             } elsif ($sel eq "x") {
1971                 if ($val > 0) {                  1615                 if ($val > 0) {
1972                     $email_git_max_maintainer    1616                     $email_git_max_maintainers = $val;
1973                     $rerun = 1;                  1617                     $rerun = 1;
1974                 }                                1618                 }
1975             } elsif ($sel eq "%") {              1619             } elsif ($sel eq "%") {
1976                 if ($str ne "" && $val >= 0)     1620                 if ($str ne "" && $val >= 0) {
1977                     $email_git_min_percent =     1621                     $email_git_min_percent = $val;
1978                     $rerun = 1;                  1622                     $rerun = 1;
1979                 }                                1623                 }
1980             } elsif ($sel eq "d") {              1624             } elsif ($sel eq "d") {
1981                 if (vcs_is_git()) {              1625                 if (vcs_is_git()) {
1982                     $email_git_since = $str;     1626                     $email_git_since = $str;
1983                 } elsif (vcs_is_hg()) {          1627                 } elsif (vcs_is_hg()) {
1984                     $email_hg_since = $str;      1628                     $email_hg_since = $str;
1985                 }                                1629                 }
1986                 $rerun = 1;                      1630                 $rerun = 1;
1987             } elsif ($sel eq "t") {              1631             } elsif ($sel eq "t") {
1988                 bool_invert(\$email_git_all_s    1632                 bool_invert(\$email_git_all_signature_types);
1989                 $rerun = 1;                      1633                 $rerun = 1;
1990             } elsif ($sel eq "f") {              1634             } elsif ($sel eq "f") {
1991                 bool_invert(\$email_file_emai !! 1635                 bool_invert(\$file_emails);
1992                 $rerun = 1;                      1636                 $rerun = 1;
1993             } elsif ($sel eq "r") {              1637             } elsif ($sel eq "r") {
1994                 bool_invert(\$email_remove_du    1638                 bool_invert(\$email_remove_duplicates);
1995                 $rerun = 1;                      1639                 $rerun = 1;
1996             } elsif ($sel eq "m") {              1640             } elsif ($sel eq "m") {
1997                 bool_invert(\$email_use_mailm    1641                 bool_invert(\$email_use_mailmap);
1998                 read_mailmap();                  1642                 read_mailmap();
1999                 $rerun = 1;                      1643                 $rerun = 1;
2000             } elsif ($sel eq "k") {              1644             } elsif ($sel eq "k") {
2001                 bool_invert(\$keywords);         1645                 bool_invert(\$keywords);
2002                 $rerun = 1;                      1646                 $rerun = 1;
2003             } elsif ($sel eq "p") {              1647             } elsif ($sel eq "p") {
2004                 if ($str ne "" && $val >= 0)     1648                 if ($str ne "" && $val >= 0) {
2005                     $pattern_depth = $val;       1649                     $pattern_depth = $val;
2006                     $rerun = 1;                  1650                     $rerun = 1;
2007                 }                                1651                 }
2008             } elsif ($sel eq "h" || $sel eq "    1652             } elsif ($sel eq "h" || $sel eq "?") {
2009                 print STDERR <<EOT               1653                 print STDERR <<EOT
2010                                                  1654 
2011 Interactive mode allows you to select the var    1655 Interactive mode allows you to select the various maintainers, submitters,
2012 commit signers and mailing lists that could b    1656 commit signers and mailing lists that could be CC'd on a patch.
2013                                                  1657 
2014 Any *'d entry is selected.                       1658 Any *'d entry is selected.
2015                                                  1659 
2016 If you have git or hg installed, you can choo    1660 If you have git or hg installed, you can choose to summarize the commit
2017 history of files in the patch.  Also, each li    1661 history of files in the patch.  Also, each line of the current file can
2018 be matched to its commit author and that comm    1662 be matched to its commit author and that commits signers with blame.
2019                                                  1663 
2020 Various knobs exist to control the length of     1664 Various knobs exist to control the length of time for active commit
2021 tracking, the maximum number of commit author    1665 tracking, the maximum number of commit authors and signers to add,
2022 and such.                                        1666 and such.
2023                                                  1667 
2024 Enter selections at the prompt until you are     1668 Enter selections at the prompt until you are satisfied that the selected
2025 maintainers are appropriate.  You may enter m    1669 maintainers are appropriate.  You may enter multiple selections separated
2026 by either commas or spaces.                      1670 by either commas or spaces.
2027                                                  1671 
2028 EOT                                              1672 EOT
2029             } else {                             1673             } else {
2030                 print STDERR "invalid option:    1674                 print STDERR "invalid option: '$nr'\n";
2031                 $redraw = 0;                     1675                 $redraw = 0;
2032             }                                    1676             }
2033         }                                        1677         }
2034         if ($rerun) {                            1678         if ($rerun) {
2035             print STDERR "git-blame can be ve    1679             print STDERR "git-blame can be very slow, please have patience..."
2036                 if ($email_git_blame);           1680                 if ($email_git_blame);
2037             goto &get_maintainers;               1681             goto &get_maintainers;
2038         }                                        1682         }
2039     }                                            1683     }
2040                                                  1684 
2041     #drop not selected entries                   1685     #drop not selected entries
2042     $count = 0;                                  1686     $count = 0;
2043     my @new_emailto = ();                        1687     my @new_emailto = ();
2044     foreach my $entry (@list) {                  1688     foreach my $entry (@list) {
2045         if ($selected{$count}) {                 1689         if ($selected{$count}) {
2046             push(@new_emailto, $list[$count])    1690             push(@new_emailto, $list[$count]);
2047         }                                        1691         }
2048         $count++;                                1692         $count++;
2049     }                                            1693     }
2050     return @new_emailto;                         1694     return @new_emailto;
2051 }                                                1695 }
2052                                                  1696 
2053 sub bool_invert {                                1697 sub bool_invert {
2054     my ($bool_ref) = @_;                         1698     my ($bool_ref) = @_;
2055                                                  1699 
2056     if ($$bool_ref) {                            1700     if ($$bool_ref) {
2057         $$bool_ref = 0;                          1701         $$bool_ref = 0;
2058     } else {                                     1702     } else {
2059         $$bool_ref = 1;                          1703         $$bool_ref = 1;
2060     }                                            1704     }
2061 }                                                1705 }
2062                                                  1706 
2063 sub deduplicate_email {                          1707 sub deduplicate_email {
2064     my ($email) = @_;                            1708     my ($email) = @_;
2065                                                  1709 
2066     my $matched = 0;                             1710     my $matched = 0;
2067     my ($name, $address) = parse_email($email    1711     my ($name, $address) = parse_email($email);
2068     $email = format_email($name, $address, 1)    1712     $email = format_email($name, $address, 1);
2069     $email = mailmap_email($email);              1713     $email = mailmap_email($email);
2070                                                  1714 
2071     return $email if (!$email_remove_duplicat    1715     return $email if (!$email_remove_duplicates);
2072                                                  1716 
2073     ($name, $address) = parse_email($email);     1717     ($name, $address) = parse_email($email);
2074                                                  1718 
2075     if ($name ne "" && $deduplicate_name_hash    1719     if ($name ne "" && $deduplicate_name_hash{lc($name)}) {
2076         $name = $deduplicate_name_hash{lc($na    1720         $name = $deduplicate_name_hash{lc($name)}->[0];
2077         $address = $deduplicate_name_hash{lc(    1721         $address = $deduplicate_name_hash{lc($name)}->[1];
2078         $matched = 1;                            1722         $matched = 1;
2079     } elsif ($deduplicate_address_hash{lc($ad    1723     } elsif ($deduplicate_address_hash{lc($address)}) {
2080         $name = $deduplicate_address_hash{lc(    1724         $name = $deduplicate_address_hash{lc($address)}->[0];
2081         $address = $deduplicate_address_hash{    1725         $address = $deduplicate_address_hash{lc($address)}->[1];
2082         $matched = 1;                            1726         $matched = 1;
2083     }                                            1727     }
2084     if (!$matched) {                             1728     if (!$matched) {
2085         $deduplicate_name_hash{lc($name)} = [    1729         $deduplicate_name_hash{lc($name)} = [ $name, $address ];
2086         $deduplicate_address_hash{lc($address    1730         $deduplicate_address_hash{lc($address)} = [ $name, $address ];
2087     }                                            1731     }
2088     $email = format_email($name, $address, 1)    1732     $email = format_email($name, $address, 1);
2089     $email = mailmap_email($email);              1733     $email = mailmap_email($email);
2090     return $email;                               1734     return $email;
2091 }                                                1735 }
2092                                                  1736 
2093 sub save_commits_by_author {                     1737 sub save_commits_by_author {
2094     my (@lines) = @_;                            1738     my (@lines) = @_;
2095                                                  1739 
2096     my @authors = ();                            1740     my @authors = ();
2097     my @commits = ();                            1741     my @commits = ();
2098     my @subjects = ();                           1742     my @subjects = ();
2099                                                  1743 
2100     foreach my $line (@lines) {                  1744     foreach my $line (@lines) {
2101         if ($line =~ m/$VCS_cmds{"author_patt    1745         if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
2102             my $author = $1;                     1746             my $author = $1;
2103             $author = deduplicate_email($auth    1747             $author = deduplicate_email($author);
2104             push(@authors, $author);             1748             push(@authors, $author);
2105         }                                        1749         }
2106         push(@commits, $1) if ($line =~ m/$VC    1750         push(@commits, $1) if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
2107         push(@subjects, $1) if ($line =~ m/$V    1751         push(@subjects, $1) if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
2108     }                                            1752     }
2109                                                  1753 
2110     for (my $i = 0; $i < @authors; $i++) {       1754     for (my $i = 0; $i < @authors; $i++) {
2111         my $exists = 0;                          1755         my $exists = 0;
2112         foreach my $ref(@{$commit_author_hash    1756         foreach my $ref(@{$commit_author_hash{$authors[$i]}}) {
2113             if (@{$ref}[0] eq $commits[$i] &&    1757             if (@{$ref}[0] eq $commits[$i] &&
2114                 @{$ref}[1] eq $subjects[$i])     1758                 @{$ref}[1] eq $subjects[$i]) {
2115                 $exists = 1;                     1759                 $exists = 1;
2116                 last;                            1760                 last;
2117             }                                    1761             }
2118         }                                        1762         }
2119         if (!$exists) {                          1763         if (!$exists) {
2120             push(@{$commit_author_hash{$autho    1764             push(@{$commit_author_hash{$authors[$i]}},
2121                  [ ($commits[$i], $subjects[$    1765                  [ ($commits[$i], $subjects[$i]) ]);
2122         }                                        1766         }
2123     }                                            1767     }
2124 }                                                1768 }
2125                                                  1769 
2126 sub save_commits_by_signer {                     1770 sub save_commits_by_signer {
2127     my (@lines) = @_;                            1771     my (@lines) = @_;
2128                                                  1772 
2129     my $commit = "";                             1773     my $commit = "";
2130     my $subject = "";                            1774     my $subject = "";
2131                                                  1775 
2132     foreach my $line (@lines) {                  1776     foreach my $line (@lines) {
2133         $commit = $1 if ($line =~ m/$VCS_cmds    1777         $commit = $1 if ($line =~ m/$VCS_cmds{"commit_pattern"}/);
2134         $subject = $1 if ($line =~ m/$VCS_cmd    1778         $subject = $1 if ($line =~ m/$VCS_cmds{"subject_pattern"}/);
2135         if ($line =~ /^[ \t]*${signature_patt    1779         if ($line =~ /^[ \t]*${signature_pattern}.*\@.*$/) {
2136             my @signatures = ($line);            1780             my @signatures = ($line);
2137             my ($types_ref, $signers_ref) = e    1781             my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures);
2138             my @types = @$types_ref;             1782             my @types = @$types_ref;
2139             my @signers = @$signers_ref;         1783             my @signers = @$signers_ref;
2140                                                  1784 
2141             my $type = $types[0];                1785             my $type = $types[0];
2142             my $signer = $signers[0];            1786             my $signer = $signers[0];
2143                                                  1787 
2144             $signer = deduplicate_email($sign    1788             $signer = deduplicate_email($signer);
2145                                                  1789 
2146             my $exists = 0;                      1790             my $exists = 0;
2147             foreach my $ref(@{$commit_signer_    1791             foreach my $ref(@{$commit_signer_hash{$signer}}) {
2148                 if (@{$ref}[0] eq $commit &&     1792                 if (@{$ref}[0] eq $commit &&
2149                     @{$ref}[1] eq $subject &&    1793                     @{$ref}[1] eq $subject &&
2150                     @{$ref}[2] eq $type) {       1794                     @{$ref}[2] eq $type) {
2151                     $exists = 1;                 1795                     $exists = 1;
2152                     last;                        1796                     last;
2153                 }                                1797                 }
2154             }                                    1798             }
2155             if (!$exists) {                      1799             if (!$exists) {
2156                 push(@{$commit_signer_hash{$s    1800                 push(@{$commit_signer_hash{$signer}},
2157                      [ ($commit, $subject, $t    1801                      [ ($commit, $subject, $type) ]);
2158             }                                    1802             }
2159         }                                        1803         }
2160     }                                            1804     }
2161 }                                                1805 }
2162                                                  1806 
2163 sub vcs_assign {                                 1807 sub vcs_assign {
2164     my ($role, $divisor, @lines) = @_;           1808     my ($role, $divisor, @lines) = @_;
2165                                                  1809 
2166     my %hash;                                    1810     my %hash;
2167     my $count = 0;                               1811     my $count = 0;
2168                                                  1812 
2169     return if (@lines <= 0);                     1813     return if (@lines <= 0);
2170                                                  1814 
2171     if ($divisor <= 0) {                         1815     if ($divisor <= 0) {
2172         warn("Bad divisor in " . (caller(0))[    1816         warn("Bad divisor in " . (caller(0))[3] . ": $divisor\n");
2173         $divisor = 1;                            1817         $divisor = 1;
2174     }                                            1818     }
2175                                                  1819 
2176     @lines = mailmap(@lines);                    1820     @lines = mailmap(@lines);
2177                                                  1821 
2178     return if (@lines <= 0);                     1822     return if (@lines <= 0);
2179                                                  1823 
2180     @lines = sort(@lines);                       1824     @lines = sort(@lines);
2181                                                  1825 
2182     # uniq -c                                    1826     # uniq -c
2183     $hash{$_}++ for @lines;                      1827     $hash{$_}++ for @lines;
2184                                                  1828 
2185     # sort -rn                                   1829     # sort -rn
2186     foreach my $line (sort {$hash{$b} <=> $ha    1830     foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) {
2187         my $sign_offs = $hash{$line};            1831         my $sign_offs = $hash{$line};
2188         my $percent = $sign_offs * 100 / $div    1832         my $percent = $sign_offs * 100 / $divisor;
2189                                                  1833 
2190         $percent = 100 if ($percent > 100);      1834         $percent = 100 if ($percent > 100);
2191         next if (ignore_email_address($line)) << 
2192         $count++;                                1835         $count++;
2193         last if ($sign_offs < $email_git_min_    1836         last if ($sign_offs < $email_git_min_signatures ||
2194                  $count > $email_git_max_main    1837                  $count > $email_git_max_maintainers ||
2195                  $percent < $email_git_min_pe    1838                  $percent < $email_git_min_percent);
2196         push_email_address($line, '');           1839         push_email_address($line, '');
2197         if ($output_rolestats) {                 1840         if ($output_rolestats) {
2198             my $fmt_percent = sprintf("%.0f",    1841             my $fmt_percent = sprintf("%.0f", $percent);
2199             add_role($line, "$role:$sign_offs    1842             add_role($line, "$role:$sign_offs/$divisor=$fmt_percent%");
2200         } else {                                 1843         } else {
2201             add_role($line, $role);              1844             add_role($line, $role);
2202         }                                        1845         }
2203     }                                            1846     }
2204 }                                                1847 }
2205                                                  1848 
2206 sub vcs_file_signoffs {                          1849 sub vcs_file_signoffs {
2207     my ($file) = @_;                             1850     my ($file) = @_;
2208                                                  1851 
2209     my $authors_ref;                          << 
2210     my $signers_ref;                          << 
2211     my $stats_ref;                            << 
2212     my @authors = ();                         << 
2213     my @signers = ();                            1852     my @signers = ();
2214     my @stats = ();                           << 
2215     my $commits;                                 1853     my $commits;
2216                                                  1854 
2217     $vcs_used = vcs_exists();                    1855     $vcs_used = vcs_exists();
2218     return if (!$vcs_used);                      1856     return if (!$vcs_used);
2219                                                  1857 
2220     my $cmd = $VCS_cmds{"find_signers_cmd"};     1858     my $cmd = $VCS_cmds{"find_signers_cmd"};
2221     $cmd =~ s/(\$\w+)/$1/eeg;           # int    1859     $cmd =~ s/(\$\w+)/$1/eeg;           # interpolate $cmd
2222                                                  1860 
2223     ($commits, $signers_ref, $authors_ref, $s !! 1861     ($commits, @signers) = vcs_find_signers($cmd);
2224                                               << 
2225     @signers = @{$signers_ref} if defined $si << 
2226     @authors = @{$authors_ref} if defined $au << 
2227     @stats = @{$stats_ref} if defined $stats_ << 
2228                                               << 
2229 #    print("commits: <$commits>\nsigners:<@sig << 
2230                                                  1862 
2231     foreach my $signer (@signers) {              1863     foreach my $signer (@signers) {
2232         $signer = deduplicate_email($signer);    1864         $signer = deduplicate_email($signer);
2233     }                                            1865     }
2234                                                  1866 
2235     vcs_assign("commit_signer", $commits, @si    1867     vcs_assign("commit_signer", $commits, @signers);
2236     vcs_assign("authored", $commits, @authors << 
2237     if ($#authors == $#stats) {               << 
2238         my $stat_pattern = $VCS_cmds{"stat_pa << 
2239         $stat_pattern =~ s/(\$\w+)/$1/eeg;    << 
2240                                               << 
2241         my $added = 0;                        << 
2242         my $deleted = 0;                      << 
2243         for (my $i = 0; $i <= $#stats; $i++)  << 
2244             if ($stats[$i] =~ /$stat_pattern/ << 
2245                 $added += $1;                 << 
2246                 $deleted += $2;               << 
2247             }                                 << 
2248         }                                     << 
2249         my @tmp_authors = uniq(@authors);     << 
2250         foreach my $author (@tmp_authors) {   << 
2251             $author = deduplicate_email($auth << 
2252         }                                     << 
2253         @tmp_authors = uniq(@tmp_authors);    << 
2254         my @list_added = ();                  << 
2255         my @list_deleted = ();                << 
2256         foreach my $author (@tmp_authors) {   << 
2257             my $auth_added = 0;               << 
2258             my $auth_deleted = 0;             << 
2259             for (my $i = 0; $i <= $#stats; $i << 
2260                 if ($author eq deduplicate_em << 
2261                     $stats[$i] =~ /$stat_patt << 
2262                     $auth_added += $1;        << 
2263                     $auth_deleted += $2;      << 
2264                 }                             << 
2265             }                                 << 
2266             for (my $i = 0; $i < $auth_added; << 
2267                 push(@list_added, $author);   << 
2268             }                                 << 
2269             for (my $i = 0; $i < $auth_delete << 
2270                 push(@list_deleted, $author); << 
2271             }                                 << 
2272         }                                     << 
2273         vcs_assign("added_lines", $added, @li << 
2274         vcs_assign("removed_lines", $deleted, << 
2275     }                                         << 
2276 }                                                1868 }
2277                                                  1869 
2278 sub vcs_file_blame {                             1870 sub vcs_file_blame {
2279     my ($file) = @_;                             1871     my ($file) = @_;
2280                                                  1872 
2281     my @signers = ();                            1873     my @signers = ();
2282     my @all_commits = ();                        1874     my @all_commits = ();
2283     my @commits = ();                            1875     my @commits = ();
2284     my $total_commits;                           1876     my $total_commits;
2285     my $total_lines;                             1877     my $total_lines;
2286                                                  1878 
2287     $vcs_used = vcs_exists();                    1879     $vcs_used = vcs_exists();
2288     return if (!$vcs_used);                      1880     return if (!$vcs_used);
2289                                                  1881 
2290     @all_commits = vcs_blame($file);             1882     @all_commits = vcs_blame($file);
2291     @commits = uniq(@all_commits);               1883     @commits = uniq(@all_commits);
2292     $total_commits = @commits;                   1884     $total_commits = @commits;
2293     $total_lines = @all_commits;                 1885     $total_lines = @all_commits;
2294                                                  1886 
2295     if ($email_git_blame_signatures) {           1887     if ($email_git_blame_signatures) {
2296         if (vcs_is_hg()) {                       1888         if (vcs_is_hg()) {
2297             my $commit_count;                    1889             my $commit_count;
2298             my $commit_authors_ref;           << 
2299             my $commit_signers_ref;           << 
2300             my $stats_ref;                    << 
2301             my @commit_authors = ();          << 
2302             my @commit_signers = ();             1890             my @commit_signers = ();
2303             my $commit = join(" -r ", @commit    1891             my $commit = join(" -r ", @commits);
2304             my $cmd;                             1892             my $cmd;
2305                                                  1893 
2306             $cmd = $VCS_cmds{"find_commit_sig    1894             $cmd = $VCS_cmds{"find_commit_signers_cmd"};
2307             $cmd =~ s/(\$\w+)/$1/eeg;   #subs    1895             $cmd =~ s/(\$\w+)/$1/eeg;   #substitute variables in $cmd
2308                                                  1896 
2309             ($commit_count, $commit_signers_r !! 1897             ($commit_count, @commit_signers) = vcs_find_signers($cmd);
2310             @commit_authors = @{$commit_autho << 
2311             @commit_signers = @{$commit_signe << 
2312                                                  1898 
2313             push(@signers, @commit_signers);     1899             push(@signers, @commit_signers);
2314         } else {                                 1900         } else {
2315             foreach my $commit (@commits) {      1901             foreach my $commit (@commits) {
2316                 my $commit_count;                1902                 my $commit_count;
2317                 my $commit_authors_ref;       << 
2318                 my $commit_signers_ref;       << 
2319                 my $stats_ref;                << 
2320                 my @commit_authors = ();      << 
2321                 my @commit_signers = ();         1903                 my @commit_signers = ();
2322                 my $cmd;                         1904                 my $cmd;
2323                                                  1905 
2324                 $cmd = $VCS_cmds{"find_commit    1906                 $cmd = $VCS_cmds{"find_commit_signers_cmd"};
2325                 $cmd =~ s/(\$\w+)/$1/eeg;        1907                 $cmd =~ s/(\$\w+)/$1/eeg;       #substitute variables in $cmd
2326                                                  1908 
2327                 ($commit_count, $commit_signe !! 1909                 ($commit_count, @commit_signers) = vcs_find_signers($cmd);
2328                 @commit_authors = @{$commit_a << 
2329                 @commit_signers = @{$commit_s << 
2330                                                  1910 
2331                 push(@signers, @commit_signer    1911                 push(@signers, @commit_signers);
2332             }                                    1912             }
2333         }                                        1913         }
2334     }                                            1914     }
2335                                                  1915 
2336     if ($from_filename) {                        1916     if ($from_filename) {
2337         if ($output_rolestats) {                 1917         if ($output_rolestats) {
2338             my @blame_signers;                   1918             my @blame_signers;
2339             if (vcs_is_hg()) {{         # Dou    1919             if (vcs_is_hg()) {{         # Double brace for last exit
2340                 my $commit_count;                1920                 my $commit_count;
2341                 my @commit_signers = ();         1921                 my @commit_signers = ();
2342                 @commits = uniq(@commits);       1922                 @commits = uniq(@commits);
2343                 @commits = sort(@commits);       1923                 @commits = sort(@commits);
2344                 my $commit = join(" -r ", @co    1924                 my $commit = join(" -r ", @commits);
2345                 my $cmd;                         1925                 my $cmd;
2346                                                  1926 
2347                 $cmd = $VCS_cmds{"find_commit    1927                 $cmd = $VCS_cmds{"find_commit_author_cmd"};
2348                 $cmd =~ s/(\$\w+)/$1/eeg;        1928                 $cmd =~ s/(\$\w+)/$1/eeg;       #substitute variables in $cmd
2349                                                  1929 
2350                 my @lines = ();                  1930                 my @lines = ();
2351                                                  1931 
2352                 @lines = &{$VCS_cmds{"execute    1932                 @lines = &{$VCS_cmds{"execute_cmd"}}($cmd);
2353                                                  1933 
2354                 if (!$email_git_penguin_chief    1934                 if (!$email_git_penguin_chiefs) {
2355                     @lines = grep(!/${penguin    1935                     @lines = grep(!/${penguin_chiefs}/i, @lines);
2356                 }                                1936                 }
2357                                                  1937 
2358                 last if !@lines;                 1938                 last if !@lines;
2359                                                  1939 
2360                 my @authors = ();                1940                 my @authors = ();
2361                 foreach my $line (@lines) {      1941                 foreach my $line (@lines) {
2362                     if ($line =~ m/$VCS_cmds{    1942                     if ($line =~ m/$VCS_cmds{"author_pattern"}/) {
2363                         my $author = $1;         1943                         my $author = $1;
2364                         $author = deduplicate    1944                         $author = deduplicate_email($author);
2365                         push(@authors, $autho    1945                         push(@authors, $author);
2366                     }                            1946                     }
2367                 }                                1947                 }
2368                                                  1948 
2369                 save_commits_by_author(@lines    1949                 save_commits_by_author(@lines) if ($interactive);
2370                 save_commits_by_signer(@lines    1950                 save_commits_by_signer(@lines) if ($interactive);
2371                                                  1951 
2372                 push(@signers, @authors);        1952                 push(@signers, @authors);
2373             }}                                   1953             }}
2374             else {                               1954             else {
2375                 foreach my $commit (@commits)    1955                 foreach my $commit (@commits) {
2376                     my $i;                       1956                     my $i;
2377                     my $cmd = $VCS_cmds{"find    1957                     my $cmd = $VCS_cmds{"find_commit_author_cmd"};
2378                     $cmd =~ s/(\$\w+)/$1/eeg;    1958                     $cmd =~ s/(\$\w+)/$1/eeg;   #interpolate $cmd
2379                     my @author = vcs_find_aut    1959                     my @author = vcs_find_author($cmd);
2380                     next if !@author;            1960                     next if !@author;
2381                                                  1961 
2382                     my $formatted_author = de    1962                     my $formatted_author = deduplicate_email($author[0]);
2383                                                  1963 
2384                     my $count = grep(/$commit    1964                     my $count = grep(/$commit/, @all_commits);
2385                     for ($i = 0; $i < $count     1965                     for ($i = 0; $i < $count ; $i++) {
2386                         push(@blame_signers,     1966                         push(@blame_signers, $formatted_author);
2387                     }                            1967                     }
2388                 }                                1968                 }
2389             }                                    1969             }
2390             if (@blame_signers) {                1970             if (@blame_signers) {
2391                 vcs_assign("authored lines",     1971                 vcs_assign("authored lines", $total_lines, @blame_signers);
2392             }                                    1972             }
2393         }                                        1973         }
2394         foreach my $signer (@signers) {          1974         foreach my $signer (@signers) {
2395             $signer = deduplicate_email($sign    1975             $signer = deduplicate_email($signer);
2396         }                                        1976         }
2397         vcs_assign("commits", $total_commits,    1977         vcs_assign("commits", $total_commits, @signers);
2398     } else {                                     1978     } else {
2399         foreach my $signer (@signers) {          1979         foreach my $signer (@signers) {
2400             $signer = deduplicate_email($sign    1980             $signer = deduplicate_email($signer);
2401         }                                        1981         }
2402         vcs_assign("modified commits", $total    1982         vcs_assign("modified commits", $total_commits, @signers);
2403     }                                            1983     }
2404 }                                                1984 }
2405                                                  1985 
2406 sub vcs_file_exists {                         << 
2407     my ($file) = @_;                          << 
2408                                               << 
2409     my $exists;                               << 
2410                                               << 
2411     my $vcs_used = vcs_exists();              << 
2412     return 0 if (!$vcs_used);                 << 
2413                                               << 
2414     my $cmd = $VCS_cmds{"file_exists_cmd"};   << 
2415     $cmd =~ s/(\$\w+)/$1/eeg;           # int << 
2416     $cmd .= " 2>&1";                          << 
2417     $exists = &{$VCS_cmds{"execute_cmd"}}($cm << 
2418                                               << 
2419     return 0 if ($? != 0);                    << 
2420                                               << 
2421     return $exists;                           << 
2422 }                                             << 
2423                                               << 
2424 sub vcs_list_files {                          << 
2425     my ($file) = @_;                          << 
2426                                               << 
2427     my @lsfiles = ();                         << 
2428                                               << 
2429     my $vcs_used = vcs_exists();              << 
2430     return 0 if (!$vcs_used);                 << 
2431                                               << 
2432     my $cmd = $VCS_cmds{"list_files_cmd"};    << 
2433     $cmd =~ s/(\$\w+)/$1/eeg;   # interpolate << 
2434     @lsfiles = &{$VCS_cmds{"execute_cmd"}}($c << 
2435                                               << 
2436     return () if ($? != 0);                   << 
2437                                               << 
2438     return @lsfiles;                          << 
2439 }                                             << 
2440                                               << 
2441 sub uniq {                                       1986 sub uniq {
2442     my (@parms) = @_;                            1987     my (@parms) = @_;
2443                                                  1988 
2444     my %saw;                                     1989     my %saw;
2445     @parms = grep(!$saw{$_}++, @parms);          1990     @parms = grep(!$saw{$_}++, @parms);
2446     return @parms;                               1991     return @parms;
2447 }                                                1992 }
2448                                                  1993 
2449 sub sort_and_uniq {                              1994 sub sort_and_uniq {
2450     my (@parms) = @_;                            1995     my (@parms) = @_;
2451                                                  1996 
2452     my %saw;                                     1997     my %saw;
2453     @parms = sort @parms;                        1998     @parms = sort @parms;
2454     @parms = grep(!$saw{$_}++, @parms);          1999     @parms = grep(!$saw{$_}++, @parms);
2455     return @parms;                               2000     return @parms;
2456 }                                                2001 }
2457                                                  2002 
2458 sub clean_file_emails {                          2003 sub clean_file_emails {
2459     my (@file_emails) = @_;                      2004     my (@file_emails) = @_;
2460     my @fmt_emails = ();                         2005     my @fmt_emails = ();
2461                                                  2006 
2462     foreach my $email (@file_emails) {           2007     foreach my $email (@file_emails) {
2463         $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\    2008         $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g;
2464         my ($name, $address) = parse_email($e    2009         my ($name, $address) = parse_email($email);
                                                   >> 2010         if ($name eq '"[,\.]"') {
                                                   >> 2011             $name = "";
                                                   >> 2012         }
2465                                                  2013 
2466         # Strip quotes for easier processing, !! 2014         my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name);
2467         $name =~ s/^"(.*)"$/$1/;              << 
2468                                               << 
2469         # Split into name-like parts and remo << 
2470         my @nw = split(/[^\p{L}\'\,\.\+-]/, $ << 
2471         @nw = grep(!/^[\'\,\.\+-]$/, @nw);    << 
2472                                               << 
2473         # Make a best effort to extract the n << 
2474         # only the last two names, or in the  << 
2475         # three names.                        << 
2476         if (@nw > 2) {                           2015         if (@nw > 2) {
2477             my $first = $nw[@nw - 3];            2016             my $first = $nw[@nw - 3];
2478             my $middle = $nw[@nw - 2];           2017             my $middle = $nw[@nw - 2];
2479             my $last = $nw[@nw - 1];             2018             my $last = $nw[@nw - 1];
2480                                                  2019 
2481             if (((length($first) == 1 && $fir !! 2020             if (((length($first) == 1 && $first =~ m/[A-Za-z]/) ||
2482                  (length($first) == 2 && subs    2021                  (length($first) == 2 && substr($first, -1) eq ".")) ||
2483                 (length($middle) == 1 ||         2022                 (length($middle) == 1 ||
2484                  (length($middle) == 2 && sub    2023                  (length($middle) == 2 && substr($middle, -1) eq "."))) {
2485                 $name = "$first $middle $last    2024                 $name = "$first $middle $last";
2486             } else {                             2025             } else {
2487                 $name = "$middle $last";         2026                 $name = "$middle $last";
2488             }                                    2027             }
2489         } else {                              << 
2490             $name = "@nw";                    << 
2491         }                                        2028         }
2492                                                  2029 
2493         if (substr($name, -1) =~ /[,\.]/) {      2030         if (substr($name, -1) =~ /[,\.]/) {
2494             $name = substr($name, 0, length($    2031             $name = substr($name, 0, length($name) - 1);
                                                   >> 2032         } elsif (substr($name, -2) =~ /[,\.]"/) {
                                                   >> 2033             $name = substr($name, 0, length($name) - 2) . '"';
2495         }                                        2034         }
2496                                                  2035 
2497         if (substr($name, 0, 1) =~ /[,\.]/) {    2036         if (substr($name, 0, 1) =~ /[,\.]/) {
2498             $name = substr($name, 1, length($    2037             $name = substr($name, 1, length($name) - 1);
                                                   >> 2038         } elsif (substr($name, 0, 2) =~ /"[,\.]/) {
                                                   >> 2039             $name = '"' . substr($name, 2, length($name) - 2);
2499         }                                        2040         }
2500                                                  2041 
2501         my $fmt_email = format_email($name, $    2042         my $fmt_email = format_email($name, $address, $email_usename);
2502         push(@fmt_emails, $fmt_email);           2043         push(@fmt_emails, $fmt_email);
2503     }                                            2044     }
2504     return @fmt_emails;                          2045     return @fmt_emails;
2505 }                                                2046 }
2506                                                  2047 
2507 sub merge_email {                                2048 sub merge_email {
2508     my @lines;                                   2049     my @lines;
2509     my %saw;                                     2050     my %saw;
2510                                                  2051 
2511     for (@_) {                                   2052     for (@_) {
2512         my ($address, $role) = @$_;              2053         my ($address, $role) = @$_;
2513         if (!$saw{$address}) {                   2054         if (!$saw{$address}) {
2514             if ($output_roles) {                 2055             if ($output_roles) {
2515                 push(@lines, "$address ($role    2056                 push(@lines, "$address ($role)");
2516             } else {                             2057             } else {
2517                 push(@lines, $address);          2058                 push(@lines, $address);
2518             }                                    2059             }
2519             $saw{$address} = 1;                  2060             $saw{$address} = 1;
2520         }                                        2061         }
2521     }                                            2062     }
2522                                                  2063 
2523     return @lines;                               2064     return @lines;
2524 }                                                2065 }
2525                                                  2066 
2526 sub output {                                     2067 sub output {
2527     my (@parms) = @_;                            2068     my (@parms) = @_;
2528                                                  2069 
2529     if ($output_multiline) {                     2070     if ($output_multiline) {
2530         foreach my $line (@parms) {              2071         foreach my $line (@parms) {
2531             print("${line}\n");                  2072             print("${line}\n");
2532         }                                        2073         }
2533     } else {                                     2074     } else {
2534         print(join($output_separator, @parms)    2075         print(join($output_separator, @parms));
2535         print("\n");                             2076         print("\n");
2536     }                                            2077     }
2537 }                                                2078 }
2538                                                  2079 
2539 my $rfc822re;                                    2080 my $rfc822re;
2540                                                  2081 
2541 sub make_rfc822re {                              2082 sub make_rfc822re {
2542 #   Basic lexical tokens are specials, domain    2083 #   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
2543 #   comment.  We must allow for rfc822_lwsp (    2084 #   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
2544 #   This regexp will only work on addresses w    2085 #   This regexp will only work on addresses which have had comments stripped
2545 #   and replaced with rfc822_lwsp.               2086 #   and replaced with rfc822_lwsp.
2546                                                  2087 
2547     my $specials = '()<>@,;:\\\\".\\[\\]';       2088     my $specials = '()<>@,;:\\\\".\\[\\]';
2548     my $controls = '\\000-\\037\\177';           2089     my $controls = '\\000-\\037\\177';
2549                                                  2090 
2550     my $dtext = "[^\\[\\]\\r\\\\]";              2091     my $dtext = "[^\\[\\]\\r\\\\]";
2551     my $domain_literal = "\\[(?:$dtext|\\\\.)    2092     my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*";
2552                                                  2093 
2553     my $quoted_string = "\"(?:[^\\\"\\r\\\\]|    2094     my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*";
2554                                                  2095 
2555 #   Use zero-width assertion to spot the limi    2096 #   Use zero-width assertion to spot the limit of an atom.  A simple
2556 #   $rfc822_lwsp* causes the regexp engine to    2097 #   $rfc822_lwsp* causes the regexp engine to hang occasionally.
2557     my $atom = "[^$specials $controls]+(?:$rf    2098     my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
2558     my $word = "(?:$atom|$quoted_string)";       2099     my $word = "(?:$atom|$quoted_string)";
2559     my $localpart = "$word(?:\\.$rfc822_lwsp*    2100     my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*";
2560                                                  2101 
2561     my $sub_domain = "(?:$atom|$domain_litera    2102     my $sub_domain = "(?:$atom|$domain_literal)";
2562     my $domain = "$sub_domain(?:\\.$rfc822_lw    2103     my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
2563                                                  2104 
2564     my $addr_spec = "$localpart\@$rfc822_lwsp    2105     my $addr_spec = "$localpart\@$rfc822_lwsp*$domain";
2565                                                  2106 
2566     my $phrase = "$word*";                       2107     my $phrase = "$word*";
2567     my $route = "(?:\@$domain(?:,\@$rfc822_lw    2108     my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
2568     my $route_addr = "\\<$rfc822_lwsp*$route?    2109     my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*";
2569     my $mailbox = "(?:$addr_spec|$phrase$rout    2110     my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
2570                                                  2111 
2571     my $group = "$phrase:$rfc822_lwsp*(?:$mai    2112     my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
2572     my $address = "(?:$mailbox|$group)";         2113     my $address = "(?:$mailbox|$group)";
2573                                                  2114 
2574     return "$rfc822_lwsp*$address";              2115     return "$rfc822_lwsp*$address";
2575 }                                                2116 }
2576                                                  2117 
2577 sub rfc822_strip_comments {                      2118 sub rfc822_strip_comments {
2578     my $s = shift;                               2119     my $s = shift;
2579 #   Recursively remove comments, and replace     2120 #   Recursively remove comments, and replace with a single space.  The simpler
2580 #   regexps in the Email Addressing FAQ are i    2121 #   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
2581 #   chars in atoms, for example.                 2122 #   chars in atoms, for example.
2582                                                  2123 
2583     while ($s =~ s/^((?:[^"\\]|\\.)*             2124     while ($s =~ s/^((?:[^"\\]|\\.)*
2584                     (?:"(?:[^"\\]|\\.)*"(?:[^    2125                     (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
2585                     \((?:[^()\\]|\\.)*\)/$1 /    2126                     \((?:[^()\\]|\\.)*\)/$1 /osx) {}
2586     return $s;                                   2127     return $s;
2587 }                                                2128 }
2588                                                  2129 
2589 #   valid: returns true if the parameter is a    2130 #   valid: returns true if the parameter is an RFC822 valid address
2590 #                                                2131 #
2591 sub rfc822_valid {                               2132 sub rfc822_valid {
2592     my $s = rfc822_strip_comments(shift);        2133     my $s = rfc822_strip_comments(shift);
2593                                                  2134 
2594     if (!$rfc822re) {                            2135     if (!$rfc822re) {
2595         $rfc822re = make_rfc822re();             2136         $rfc822re = make_rfc822re();
2596     }                                            2137     }
2597                                                  2138 
2598     return $s =~ m/^$rfc822re$/so && $s =~ m/    2139     return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/;
2599 }                                                2140 }
2600                                                  2141 
2601 #   validlist: In scalar context, returns tru    2142 #   validlist: In scalar context, returns true if the parameter is an RFC822
2602 #              valid list of addresses.          2143 #              valid list of addresses.
2603 #                                                2144 #
2604 #              In list context, returns an em    2145 #              In list context, returns an empty list on failure (an invalid
2605 #              address was found); otherwise     2146 #              address was found); otherwise a list whose first element is the
2606 #              number of addresses found and     2147 #              number of addresses found and whose remaining elements are the
2607 #              addresses.  This is needed to     2148 #              addresses.  This is needed to disambiguate failure (invalid)
2608 #              from success with no addresses    2149 #              from success with no addresses found, because an empty string is
2609 #              a valid list.                     2150 #              a valid list.
2610                                                  2151 
2611 sub rfc822_validlist {                           2152 sub rfc822_validlist {
2612     my $s = rfc822_strip_comments(shift);        2153     my $s = rfc822_strip_comments(shift);
2613                                                  2154 
2614     if (!$rfc822re) {                            2155     if (!$rfc822re) {
2615         $rfc822re = make_rfc822re();             2156         $rfc822re = make_rfc822re();
2616     }                                            2157     }
2617     # * null list items are valid according t    2158     # * null list items are valid according to the RFC
2618     # * the '1' business is to aid in disting    2159     # * the '1' business is to aid in distinguishing failure from no results
2619                                                  2160 
2620     my @r;                                       2161     my @r;
2621     if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822    2162     if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so &&
2622         $s =~ m/^$rfc822_char*$/) {              2163         $s =~ m/^$rfc822_char*$/) {
2623         while ($s =~ m/(?:^|,$rfc822_lwsp*)($    2164         while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) {
2624             push(@r, $1);                        2165             push(@r, $1);
2625         }                                        2166         }
2626         return wantarray ? (scalar(@r), @r) :    2167         return wantarray ? (scalar(@r), @r) : 1;
2627     }                                            2168     }
2628     return wantarray ? () : 0;                   2169     return wantarray ? () : 0;
2629 }                                                2170 }
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php