| @@ -41,6 +41,8 @@ my $web = 0; · 40 unmodified lines |
| 41 | 41 | my $subsystem = 0; |
| 42 | 42 | my $status = 0; |
| 43 | 43 | my $keywords = 1; |
| 44 | +my $sections = 0; |
| 45 | +my $file_emails = 0; |
| 44 | 46 | my $from_filename = 0; |
| 45 | 47 | my $pattern_depth = 0; |
| 46 | 48 | my $version = 0; |
| @@ -120,9 +122,11 @@ if (!GetOptions( · 73 unmodified lines |
| 120 | 122 | 'web!' => \$web, |
| 121 | 123 | 'pattern-depth=i' => \$pattern_depth, |
| 122 | 124 | 'k|keywords!' => \$keywords, |
| 125 | + 'sections!' => \$sections, |
| 126 | + 'fe|file-emails!' => \$file_emails, |
| 123 | 127 | 'f|file' => \$from_filename, |
| 124 | 128 | 'v|version' => \$version, |
| 125 | | − 'h|help' => \$help, |
| 129 | + 'h|help|usage' => \$help, |
| 126 | 130 | )) { |
| 127 | 131 | die "$P: invalid argument - use --help if necessary\n"; |
| 128 | 132 | } |
| @@ -137,9 +141,9 @@ if ($version != 0) { · 8 unmodified lines |
| 137 | 141 | exit 0; |
| 138 | 142 | } |
| 139 | 143 | |
| 140 | | −if ($#ARGV < 0) { |
| 141 | | − usage(); |
| 142 | | − die "$P: argument missing: patchfile or -f file please\n"; |
| 144 | +if (-t STDIN && !@ARGV) { |
| 145 | + # We're talking to a terminal, but have no command line arguments. |
| 146 | + die "$P: missing patchfile or -f file - use --help if necessary\n"; |
| 143 | 147 | } |
| 144 | 148 | |
| 145 | 149 | if ($output_separator ne ", ") { |
| @@ -150,16 +154,24 @@ if ($output_rolestats) { · 4 unmodified lines |
| 150 | 154 | $output_roles = 1; |
| 151 | 155 | } |
| 152 | 156 | |
| 153 | | −my $selections = $email + $scm + $status + $subsystem + $web; |
| 154 | | −if ($selections == 0) { |
| 155 | | − usage(); |
| 156 | | − die "$P: Missing required option: email, scm, status, subsystem or web\n"; |
| 157 | +if ($sections) { |
| 158 | + $email = 0; |
| 159 | + $email_list = 0; |
| 160 | + $scm = 0; |
| 161 | + $status = 0; |
| 162 | + $subsystem = 0; |
| 163 | + $web = 0; |
| 164 | + $keywords = 0; |
| 165 | +} else { |
| 166 | + my $selections = $email + $scm + $status + $subsystem + $web; |
| 167 | + if ($selections == 0) { |
| 168 | + die "$P: Missing required option: email, scm, status, subsystem or web\n"; |
| 169 | + } |
| 157 | 170 | } |
| 158 | 171 | |
| 159 | 172 | if ($email && |
| 160 | 173 | ($email_maintainer + $email_list + $email_subscriber_list + |
| 161 | 174 | $email_git + $email_git_penguin_chiefs + $email_git_blame) == 0) { |
| 162 | | − usage(); |
| 163 | 175 | die "$P: Please select at least 1 email option\n"; |
| 164 | 176 | } |
| 165 | 177 | |
| @@ -173,8 +185,9 @@ if (!top_of_kernel_tree($lk_path)) { · 7 unmodified lines |
| 173 | 185 | my @typevalue = (); |
| 174 | 186 | my %keyword_hash; |
| 175 | 187 | |
| 176 | | −open(MAINT, "<${lk_path}MAINTAINERS") || die "$P: Can't open MAINTAINERS\n"; |
| 177 | | −while (<MAINT>) { |
| 188 | +open (my $maint, '<', "${lk_path}MAINTAINERS") |
| 189 | + or die "$P: Can't open MAINTAINERS: $!\n"; |
| 190 | +while (<$maint>) { |
| 178 | 191 | my $line = $_; |
| 179 | 192 | |
| 180 | 193 | if ($line =~ m/^(\C):\s*(.*)/) { |
| @@ -199,13 +212,14 @@ while (<MAINT>) { · 18 unmodified lines |
| 199 | 212 | push(@typevalue, $line); |
| 200 | 213 | } |
| 201 | 214 | } |
| 202 | | −close(MAINT); |
| 215 | +close($maint); |
| 203 | 216 | |
| 204 | 217 | my %mailmap; |
| 205 | 218 | |
| 206 | 219 | if ($email_remove_duplicates) { |
| 207 | | − open(MAILMAP, "<${lk_path}.mailmap") || warn "$P: Can't open .mailmap\n"; |
| 208 | | − while (<MAILMAP>) { |
| 220 | + open(my $mailmap, '<', "${lk_path}.mailmap") |
| 221 | + or warn "$P: Can't open .mailmap: $!\n"; |
| 222 | + while (<$mailmap>) { |
| 209 | 223 | my $line = $_; |
| 210 | 224 | |
| 211 | 225 | next if ($line =~ m/^\s*#/); |
| @@ -224,7 +238,7 @@ if ($email_remove_duplicates) { · 12 unmodified lines |
| 224 | 238 | $mailmap{$name} = \@arr; |
| 225 | 239 | } |
| 226 | 240 | } |
| 227 | | − close(MAILMAP); |
| 241 | + close($mailmap); |
| 228 | 242 | } |
| 229 | 243 | |
| 230 | 244 | ## use the filenames on the command line or find the filenames in the patchfiles |
| @@ -232,31 +246,47 @@ if ($email_remove_duplicates) { · 1 unmodified line |
| 232 | 246 | my @files = (); |
| 233 | 247 | my @range = (); |
| 234 | 248 | my @keyword_tvi = (); |
| 249 | +my @file_emails = (); |
| 250 | + |
| 251 | +if (!@ARGV) { |
| 252 | + push(@ARGV, "&STDIN"); |
| 253 | +} |
| 235 | 254 | |
| 236 | 255 | foreach my $file (@ARGV) { |
| 237 | | − ##if $file is a directory and it lacks a trailing slash, add one |
| 238 | | − if ((-d $file)) { |
| 239 | | − $file =~ s@([^/])$@$1/@; |
| 240 | | − } elsif (!(-f $file)) { |
| 241 | | − die "$P: file '${file}' not found\n"; |
| 256 | + if ($file ne "&STDIN") { |
| 257 | + ##if $file is a directory and it lacks a trailing slash, add one |
| 258 | + if ((-d $file)) { |
| 259 | + $file =~ s@([^/])$@$1/@; |
| 260 | + } elsif (!(-f $file)) { |
| 261 | + die "$P: file '${file}' not found\n"; |
| 262 | + } |
| 242 | 263 | } |
| 243 | 264 | if ($from_filename) { |
| 244 | 265 | push(@files, $file); |
| 245 | | − if (-f $file && $keywords) { |
| 246 | | − open(FILE, "<$file") or die "$P: Can't open ${file}\n"; |
| 247 | | − my $text = do { local($/) ; <FILE> }; |
| 248 | | − foreach my $line (keys %keyword_hash) { |
| 249 | | − if ($text =~ m/$keyword_hash{$line}/x) { |
| 250 | | − push(@keyword_tvi, $line); |
| 266 | + if (-f $file && ($keywords || $file_emails)) { |
| 267 | + open(my $f, '<', $file) |
| 268 | + or die "$P: Can't open $file: $!\n"; |
| 269 | + my $text = do { local($/) ; <$f> }; |
| 270 | + close($f); |
| 271 | + if ($keywords) { |
| 272 | + foreach my $line (keys %keyword_hash) { |
| 273 | + if ($text =~ m/$keyword_hash{$line}/x) { |
| 274 | + push(@keyword_tvi, $line); |
| 275 | + } |
| 251 | 276 | } |
| 252 | 277 | } |
| 253 | | − close(FILE); |
| 278 | + if ($file_emails) { |
| 279 | + 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; |
| 280 | + push(@file_emails, clean_file_emails(@poss_addr)); |
| 281 | + } |
| 254 | 282 | } |
| 255 | 283 | } else { |
| 256 | 284 | my $file_cnt = @files; |
| 257 | 285 | my $lastfile; |
| 258 | | − open(PATCH, "<$file") or die "$P: Can't open ${file}\n"; |
| 259 | | − while (<PATCH>) { |
| 286 | + |
| 287 | + open(my $patch, "< $file") |
| 288 | + or die "$P: Can't open $file: $!\n"; |
| 289 | + while (<$patch>) { |
| 260 | 290 | my $patch_line = $_; |
| 261 | 291 | if (m/^\+\+\+\s+(\S+)/) { |
| 262 | 292 | my $filename = $1; |
| @@ -276,7 +306,8 @@ foreach my $file (@ARGV) { · 13 unmodified lines |
| 276 | 306 | } |
| 277 | 307 | } |
| 278 | 308 | } |
| 279 | | − close(PATCH); |
| 309 | + close($patch); |
| 310 | + |
| 280 | 311 | if ($file_cnt == @files) { |
| 281 | 312 | warn "$P: file '${file}' doesn't appear to be a patch. " |
| 282 | 313 | . "Add -f to options?\n"; |
| @@ -285,6 +316,8 @@ foreach my $file (@ARGV) { · 2 unmodified lines |
| 285 | 316 | } |
| 286 | 317 | } |
| 287 | 318 | |
| 319 | +@file_emails = uniq(@file_emails); |
| 320 | + |
| 288 | 321 | my @email_to = (); |
| 289 | 322 | my @list_to = (); |
| 290 | 323 | my @scm = (); |
| @@ -314,6 +347,7 @@ foreach my $file (@files) { · 23 unmodified lines |
| 314 | 347 | if ($type eq 'X') { |
| 315 | 348 | if (file_match_pattern($file, $value)) { |
| 316 | 349 | $exclude = 1; |
| 350 | + last; |
| 317 | 351 | } |
| 318 | 352 | } |
| 319 | 353 | } |
| @@ -340,12 +374,28 @@ foreach my $file (@files) { · 20 unmodified lines |
| 340 | 374 | } |
| 341 | 375 | } |
| 342 | 376 | |
| 343 | | − $tvi += ($end - $start); |
| 344 | | − |
| 377 | + $tvi = $end + 1; |
| 345 | 378 | } |
| 346 | 379 | |
| 347 | 380 | foreach my $line (sort {$hash{$b} <=> $hash{$a}} keys %hash) { |
| 348 | 381 | add_categories($line); |
| 382 | + if ($sections) { |
| 383 | + my $i; |
| 384 | + my $start = find_starting_index($line); |
| 385 | + my $end = find_ending_index($line); |
| 386 | + for ($i = $start; $i < $end; $i++) { |
| 387 | + my $line = $typevalue[$i]; |
| 388 | + if ($line =~ /^[FX]:/) { ##Restore file patterns |
| 389 | + $line =~ s/([^\\])\.([^\*])/$1\?$2/g; |
| 390 | + $line =~ s/([^\\])\.$/$1\?/g; ##Convert . back to ? |
| 391 | + $line =~ s/\\\./\./g; ##Convert \. to . |
| 392 | + $line =~ s/\.\*/\*/g; ##Convert .* to * |
| 393 | + } |
| 394 | + $line =~ s/^([A-Z]):/$1:\t/g; |
| 395 | + print("$line\n"); |
| 396 | + } |
| 397 | + print("\n"); |
| 398 | + } |
| 349 | 399 | } |
| 350 | 400 | |
| 351 | 401 | if ($email && $email_git) { |
| @@ -377,6 +427,14 @@ if ($email) { · 25 unmodified lines |
| 377 | 427 | } |
| 378 | 428 | } |
| 379 | 429 | } |
| 430 | + |
| 431 | + foreach my $email (@file_emails) { |
| 432 | + my ($name, $address) = parse_email($email); |
| 433 | + |
| 434 | + my $tmp_email = format_email($name, $address, $email_usename); |
| 435 | + push_email_address($tmp_email, ''); |
| 436 | + add_role($tmp_email, 'in file'); |
| 437 | + } |
| 380 | 438 | } |
| 381 | 439 | |
| 382 | 440 | if ($email || $email_list) { |
| @@ -453,6 +511,7 @@ MAINTAINER field selection options: · 70 unmodified lines |
| 453 | 511 | --remove-duplicates => minimize duplicate email names/addresses |
| 454 | 512 | --roles => show roles (status:subsystem, git-signer, list, etc...) |
| 455 | 513 | --rolestats => show roles and statistics (commits/total_commits, %) |
| 514 | + --file-emails => add email addresses found in -f file (default: 0 (off)) |
| 456 | 515 | --scm => print SCM tree(s) if any |
| 457 | 516 | --status => print status if any |
| 458 | 517 | --subsystem => print subsystem name if any |
| @@ -466,6 +525,7 @@ Output type options: · 7 unmodified lines |
| 466 | 525 | Other options: |
| 467 | 526 | --pattern-depth => Number of pattern directory traversals (default: 0 (all)) |
| 468 | 527 | --keywords => scan patch for keywords (default: 1 (on)) |
| 528 | + --sections => print the entire subsystem sections with pattern matches |
| 469 | 529 | --version => show version |
| 470 | 530 | --help => show this help information |
| 471 | 531 | |
| @@ -545,7 +605,7 @@ sub parse_email { · 73 unmodified lines |
| 545 | 605 | $name =~ s/^\"|\"$//g; |
| 546 | 606 | $address =~ s/^\s+|\s+$//g; |
| 547 | 607 | |
| 548 | | − if ($name =~ /[^a-z0-9 \.\-]/i) { ##has "must quote" chars |
| 608 | + if ($name =~ /[^\w \-]/i) { ##has "must quote" chars |
| 549 | 609 | $name =~ s/(?<!\\)"/\\"/g; ##escape quotes |
| 550 | 610 | $name = "\"$name\""; |
| 551 | 611 | } |
| @@ -562,7 +622,7 @@ sub format_email { · 10 unmodified lines |
| 562 | 622 | $name =~ s/^\"|\"$//g; |
| 563 | 623 | $address =~ s/^\s+|\s+$//g; |
| 564 | 624 | |
| 565 | | − if ($name =~ /[^a-z0-9 \.\-]/i) { ##has "must quote" chars |
| 625 | + if ($name =~ /[^\w \-]/i) { ##has "must quote" chars |
| 566 | 626 | $name =~ s/(?<!\\)"/\\"/g; ##escape quotes |
| 567 | 627 | $name = "\"$name\""; |
| 568 | 628 | } |
| @@ -811,7 +871,9 @@ sub add_role { · 242 unmodified lines |
| 811 | 871 | foreach my $entry (@email_to) { |
| 812 | 872 | if ($email_remove_duplicates) { |
| 813 | 873 | my ($entry_name, $entry_address) = parse_email($entry->[0]); |
| 814 | | − if ($name eq $entry_name || $address eq $entry_address) { |
| 874 | + if (($name eq $entry_name || $address eq $entry_address) |
| 875 | + && ($role eq "" || !($entry->[1] =~ m/$role/)) |
| 876 | + ) { |
| 815 | 877 | if ($entry->[1] eq "") { |
| 816 | 878 | $entry->[1] = "$role"; |
| 817 | 879 | } else { |
| @@ -819,7 +881,9 @@ sub add_role { · 1 unmodified line |
| 819 | 881 | } |
| 820 | 882 | } |
| 821 | 883 | } else { |
| 822 | | − if ($email eq $entry->[0]) { |
| 884 | + if ($email eq $entry->[0] |
| 885 | + && ($role eq "" || !($entry->[1] =~ m/$role/)) |
| 886 | + ) { |
| 823 | 887 | if ($entry->[1] eq "") { |
| 824 | 888 | $entry->[1] = "$role"; |
| 825 | 889 | } else { |
| @@ -1099,6 +1163,51 @@ sub sort_and_uniq { · 273 unmodified lines |
| 1099 | 1163 | return @parms; |
| 1100 | 1164 | } |
| 1101 | 1165 | |
| 1166 | +sub clean_file_emails { |
| 1167 | + my (@file_emails) = @_; |
| 1168 | + my @fmt_emails = (); |
| 1169 | + |
| 1170 | + foreach my $email (@file_emails) { |
| 1171 | + $email =~ s/[\(\<\{]{0,1}([A-Za-z0-9_\.\+-]+\@[A-Za-z0-9\.-]+)[\)\>\}]{0,1}/\<$1\>/g; |
| 1172 | + my ($name, $address) = parse_email($email); |
| 1173 | + if ($name eq '"[,\.]"') { |
| 1174 | + $name = ""; |
| 1175 | + } |
| 1176 | + |
| 1177 | + my @nw = split(/[^A-Za-zÀ-ÿ\'\,\.\+-]/, $name); |
| 1178 | + if (@nw > 2) { |
| 1179 | + my $first = $nw[@nw - 3]; |
| 1180 | + my $middle = $nw[@nw - 2]; |
| 1181 | + my $last = $nw[@nw - 1]; |
| 1182 | + |
| 1183 | + if (((length($first) == 1 && $first =~ m/[A-Za-z]/) || |
| 1184 | + (length($first) == 2 && substr($first, -1) eq ".")) || |
| 1185 | + (length($middle) == 1 || |
| 1186 | + (length($middle) == 2 && substr($middle, -1) eq "."))) { |
| 1187 | + $name = "$first $middle $last"; |
| 1188 | + } else { |
| 1189 | + $name = "$middle $last"; |
| 1190 | + } |
| 1191 | + } |
| 1192 | + |
| 1193 | + if (substr($name, -1) =~ /[,\.]/) { |
| 1194 | + $name = substr($name, 0, length($name) - 1); |
| 1195 | + } elsif (substr($name, -2) =~ /[,\.]"/) { |
| 1196 | + $name = substr($name, 0, length($name) - 2) . '"'; |
| 1197 | + } |
| 1198 | + |
| 1199 | + if (substr($name, 0, 1) =~ /[,\.]/) { |
| 1200 | + $name = substr($name, 1, length($name) - 1); |
| 1201 | + } elsif (substr($name, 0, 2) =~ /"[,\.]/) { |
| 1202 | + $name = '"' . substr($name, 2, length($name) - 2); |
| 1203 | + } |
| 1204 | + |
| 1205 | + my $fmt_email = format_email($name, $address, $email_usename); |
| 1206 | + push(@fmt_emails, $fmt_email); |
| 1207 | + } |
| 1208 | + return @fmt_emails; |
| 1209 | +} |
| 1210 | + |
| 1102 | 1211 | sub merge_email { |
| 1103 | 1212 | my @lines; |
| 1104 | 1213 | my %saw; |
| @@ -1183,7 +1292,7 @@ sub rfc822_strip_comments { · 78 unmodified lines |
| 1183 | 1292 | |
| 1184 | 1293 | # valid: returns true if the parameter is an RFC822 valid address |
| 1185 | 1294 | # |
| 1186 | | −sub rfc822_valid ($) { |
| 1295 | +sub rfc822_valid { |
| 1187 | 1296 | my $s = rfc822_strip_comments(shift); |
| 1188 | 1297 | |
| 1189 | 1298 | if (!$rfc822re) { |
| @@ -1203,7 +1312,7 @@ sub rfc822_valid ($) { · 13 unmodified lines |
| 1203 | 1312 | # from success with no addresses found, because an empty string is |
| 1204 | 1313 | # a valid list. |
| 1205 | 1314 | |
| 1206 | | −sub rfc822_validlist ($) { |
| 1315 | +sub rfc822_validlist { |
| 1207 | 1316 | my $s = rfc822_strip_comments(shift); |
| 1208 | 1317 | |
| 1209 | 1318 | if (!$rfc822re) { |