#!/usr/bin/perl # Copyright (C) 2015 Francois Gouget # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA use strict; use warnings; my $name0=$0; $name0 =~ s%^.*/%%; sub error(@) { print STDERR "$name0:error: ", @_; } my ($opt_regexp, $opt_lines, $opt_chars, $opt_traces, $opt_min, $opt_max, $opt_help); use Getopt::Long; Getopt::Long::Configure ("no_ignore_case"); my $rc = GetOptions("l" => \$opt_lines, "c" => \$opt_chars, "traces!" => \$opt_traces, "m=i" => \$opt_min, "M=i" => \$opt_max, "e=s" => \$opt_regexp, "help" => \$opt_help, ); if ($opt_help) { print "Usage: $name0 [-e REGEXP] [-m MIN] [-M MAX] [-c|-l] [--traces] [--help] FILE...\n"; print "\n"; print "Looks for lines matching the regular expression and for each match reports the number of corresponding lines or characters. By default looks for lines starting with '::'.\n"; print "\n"; print "Options:\n"; print " -l Sort matches by lines matched.\n"; print " -c Sort matches by characters in the lines matched. This is the default.\n"; print " --traces Traces only, not test results (for WineTest logs). The default is both.\n"; print " --no-traces Test results only, not traces (for WineTest logs).\n"; print " -m MIN Only reports on matches with MIN or more lines or characters.\n"; print " -M MAX Only reports on matches less than MAX lines or characters.\n"; print " -e REGEXP Specifies which part of the line to match.\n"; print " --help Prints this help message\n"; exit 0; } if ($rc) { if (defined $opt_regexp and defined $opt_traces) { error("-e, --traces and --no-traces are mutually exclusive\n"); $rc = 0; } else { $opt_regexp ||= $opt_traces ? "^[^:]*:[0-9]*:(?! Test [a-z ]*:)" : defined $opt_traces ? "^[^:]*:[0-9]*: Test [a-z ]*:" : "^[^:]*:[0-9]*:( Test [a-z ]*:)?"; } if ($opt_lines and $opt_chars) { error("-l and -c are mutually exclusive\n"); $rc = 0; } elsif (!$opt_lines) { $opt_chars = 1; } if (!@ARGV) { error("you must specify one or more files to analyze\n"); $rc = 0; } } if (!$rc) { error("try running $name0 --help\n"); exit 2; } my %lines; my %chars; foreach my $filename (@ARGV) { if (open(my $fh, "<", $filename)) { while (my $line=<$fh>) { if ($line =~ /($opt_regexp)/) { $lines{$1}++; $chars{$1} += length($line); } } close($fh); } else { error("could not open '$filename' for reading: $!\n"); exit 1; } } sub compare_matches() { return $opt_lines ? $lines{$b} <=> $lines{$a} : $chars{$b} <=> $chars{$a}; } print "Lines Chars Match\n"; my $matches = 0; my $total_lines = 0; my $total_chars = 0; foreach my $match (sort compare_matches keys %lines) { if (defined $opt_min) { next if ($opt_lines and $lines{$match} < $opt_min); next if ($opt_chars and $chars{$match} < $opt_min); } if (defined $opt_max) { next if ($opt_lines and $lines{$match} >= $opt_max); next if ($opt_chars and $chars{$match} >= $opt_max); } $matches++; $total_lines += $lines{$match}; $total_chars += $chars{$match}; printf "%5d %6d %s\n", $lines{$match}, $chars{$match}, $match; } print "$matches matches for a total of $total_lines lines and $total_chars characters\n"; exit 0;