summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '3rdParty/LCov/lcov')
-rwxr-xr-x3rdParty/LCov/lcov489
1 files changed, 380 insertions, 109 deletions
diff --git a/3rdParty/LCov/lcov b/3rdParty/LCov/lcov
index 4e392ff..7760ba2 100755
--- a/3rdParty/LCov/lcov
+++ b/3rdParty/LCov/lcov
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
#
-# Copyright (c) International Business Machines Corp., 2002,2010
+# Copyright (c) International Business Machines Corp., 2002,2012
#
# 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
@@ -71,7 +71,8 @@ use Cwd qw /abs_path getcwd/;
# Global constants
-our $lcov_version = 'LCOV version 1.9';
+our $tool_dir = abs_path(dirname($0));
+our $lcov_version = "LCOV version 1.12";
our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php";
our $tool_name = basename($0);
@@ -93,6 +94,7 @@ our $BR_BRANCH = 1;
our $BR_TAKEN = 2;
our $BR_VEC_ENTRIES = 3;
our $BR_VEC_WIDTH = 32;
+our $BR_VEC_MAX = vec(pack('b*', 1 x $BR_VEC_WIDTH), 0, $BR_VEC_WIDTH);
# Branch data combination types
our $BR_SUB = 0;
@@ -139,6 +141,8 @@ sub lcov_geninfo(@);
sub create_package($$$;$);
sub get_func_found_and_hit($);
sub br_ivec_get($$);
+sub summary();
+sub rate($$;$$$);
# Global variables & initialization
our @directory; # Specifies where to get coverage data from
@@ -168,7 +172,7 @@ our $no_checksum; # If set, don't calculate a checksum for each line
our $compat_libtool; # If set, indicates that libtool mode is to be enabled
our $no_compat_libtool; # If set, indicates that libtool mode is to be disabled
our $gcov_tool;
-our $ignore_errors;
+our @opt_ignore_errors;
our $initial;
our $no_recursion = 0;
our $to_package;
@@ -177,7 +181,6 @@ our $maxdepth;
our $no_markers;
our $config; # Configuration file contents
chomp($cwd);
-our $tool_dir = dirname($0); # Directory where genhtml tool is installed
our @temp_dirs;
our $gcov_gkv; # gcov kernel support version found on machine
our $opt_derive_func_data;
@@ -186,12 +189,20 @@ our $opt_list_full_path;
our $opt_no_list_full_path;
our $opt_list_width = 80;
our $opt_list_truncate_max = 20;
+our $opt_external;
+our $opt_no_external;
+our $opt_config_file;
+our %opt_rc;
+our @opt_summary;
+our $opt_compat;
our $ln_overall_found;
our $ln_overall_hit;
our $fn_overall_found;
our $fn_overall_hit;
our $br_overall_found;
our $br_overall_hit;
+our $func_coverage = 1;
+our $br_coverage = 0;
#
@@ -203,17 +214,29 @@ $SIG{__DIE__} = \&die_handler;
$SIG{'INT'} = \&abort_handler;
$SIG{'QUIT'} = \&abort_handler;
-# Prettify version string
-$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+# Check command line for a configuration file name
+Getopt::Long::Configure("pass_through", "no_auto_abbrev");
+GetOptions("config-file=s" => \$opt_config_file,
+ "rc=s%" => \%opt_rc);
+Getopt::Long::Configure("default");
-# Add current working directory if $tool_dir is not already an absolute path
-if (! ($tool_dir =~ /^\/(.*)$/))
{
- $tool_dir = "$cwd/$tool_dir";
+ # Remove spaces around rc options
+ my %new_opt_rc;
+
+ while (my ($key, $value) = each(%opt_rc)) {
+ $key =~ s/^\s+|\s+$//g;
+ $value =~ s/^\s+|\s+$//g;
+
+ $new_opt_rc{$key} = $value;
+ }
+ %opt_rc = %new_opt_rc;
}
# Read configuration file if available
-if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
+if (defined($opt_config_file)) {
+ $config = read_config($opt_config_file);
+} elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
{
$config = read_config($ENV{"HOME"}."/.lcovrc");
}
@@ -222,15 +245,17 @@ elsif (-r "/etc/lcovrc")
$config = read_config("/etc/lcovrc");
}
-if ($config)
+if ($config || %opt_rc)
{
- # Copy configuration file values to variables
+ # Copy configuration file and --rc values to variables
apply_config({
"lcov_gcov_dir" => \$gcov_dir,
"lcov_tmp_dir" => \$tmp_dir,
"lcov_list_full_path" => \$opt_list_full_path,
"lcov_list_width" => \$opt_list_width,
"lcov_list_truncate_max"=> \$opt_list_truncate_max,
+ "lcov_branch_coverage" => \$br_coverage,
+ "lcov_function_coverage"=> \$func_coverage,
});
}
@@ -259,7 +284,7 @@ if (!GetOptions("directory|d|di=s" => \@directory,
"compat-libtool" => \$compat_libtool,
"no-compat-libtool" => \$no_compat_libtool,
"gcov-tool=s" => \$gcov_tool,
- "ignore-errors=s" => \$ignore_errors,
+ "ignore-errors=s" => \@opt_ignore_errors,
"initial|i" => \$initial,
"no-recursion" => \$no_recursion,
"to-package=s" => \$to_package,
@@ -269,6 +294,12 @@ if (!GetOptions("directory|d|di=s" => \@directory,
"debug" => \$opt_debug,
"list-full-path" => \$opt_list_full_path,
"no-list-full-path" => \$opt_no_list_full_path,
+ "external" => \$opt_external,
+ "no-external" => \$opt_no_external,
+ "summary=s" => \@opt_summary,
+ "compat=s" => \$opt_compat,
+ "config-file=s" => \$opt_config_file,
+ "rc=s%" => \%opt_rc,
))
{
print(STDERR "Use $tool_name --help to get usage information\n");
@@ -294,6 +325,11 @@ else
$opt_list_full_path = ($opt_no_list_full_path ? 0 : 1);
$opt_no_list_full_path = undef;
}
+
+ if (defined($opt_no_external)) {
+ $opt_external = 0;
+ $opt_no_external = undef;
+ }
}
# Check for help option
@@ -341,7 +377,7 @@ else
check_options();
# Only --extract, --remove and --diff allow unnamed parameters
-if (@ARGV && !($extract || $remove || $diff))
+if (@ARGV && !($extract || $remove || $diff || @opt_summary))
{
die("Extra parameter found: '".join(" ", @ARGV)."'\n".
"Use $tool_name --help to get usage information\n");
@@ -429,6 +465,12 @@ elsif ($diff)
$fn_overall_found, $fn_overall_hit,
$br_overall_found, $br_overall_hit) = diff();
}
+elsif (@opt_summary)
+{
+ ($ln_overall_found, $ln_overall_hit,
+ $fn_overall_found, $fn_overall_hit,
+ $br_overall_found, $br_overall_hit) = summary();
+}
temp_cleanup();
@@ -471,6 +513,7 @@ Operation:
-r, --remove FILE PATTERN Remove files matching PATTERN from FILE
-l, --list FILE List contents of tracefile FILE
--diff FILE DIFF Transform tracefile FILE according to DIFF
+ --summary FILE Show summary coverage data for tracefiles
Options:
-i, --initial Capture initial zero coverage data
@@ -493,6 +536,10 @@ Options:
--no-markers Ignore exclusion markers in source code
--derive-func-data Generate function data from line data
--list-full-path Print full path during a list operation
+ --(no-)external Include (ignore) data for external files
+ --config-file FILENAME Specify configuration file location
+ --rc SETTING=VALUE Override configuration file setting
+ --compat MODE=on|off|auto Set compat MODE (libtool, hammer, split_crc)
For more information see: $lcov_url
END_OF_USAGE
@@ -518,17 +565,18 @@ sub check_options()
$remove && $i++;
$list && $i++;
$diff && $i++;
+ @opt_summary && $i++;
if ($i == 0)
{
- die("Need one of the options -z, -c, -a, -e, -r, -l or ".
- "--diff\n".
+ die("Need one of options -z, -c, -a, -e, -r, -l, ".
+ "--diff or --summary\n".
"Use $tool_name --help to get usage information\n");
}
elsif ($i > 1)
{
- die("ERROR: only one of -z, -c, -a, -e, -r, -l or ".
- "--diff allowed!\n".
+ die("ERROR: only one of -z, -c, -a, -e, -r, -l, ".
+ "--diff or --summary allowed!\n".
"Use $tool_name --help to get usage information\n");
}
}
@@ -551,7 +599,7 @@ sub userspace_reset()
{
info("Deleting all .da files in $current_dir".
($no_recursion?"\n":" and subdirectories\n"));
- @file_list = `find "$current_dir" $maxdepth $follow -name \\*\\.da -o -name \\*\\.gcda -type f 2>/dev/null`;
+ @file_list = `find "$current_dir" $maxdepth $follow -name \\*\\.da -type f -o -name \\*\\.gcda -type f 2>/dev/null`;
chomp(@file_list);
foreach (@file_list)
{
@@ -613,7 +661,7 @@ sub kernel_reset()
} else {
die("ERROR: no reset control found in $gcov_dir\n");
}
- open(HANDLE, ">$reset_file") or
+ open(HANDLE, ">", $reset_file) or
die("ERROR: cannot write to $reset_file!\n");
print(HANDLE "0");
close(HANDLE);
@@ -635,10 +683,10 @@ sub lcov_copy_single($$)
local $/;
local *HANDLE;
- open(HANDLE, "<$from") or die("ERROR: cannot read $from: $!\n");
+ open(HANDLE, "<", $from) or die("ERROR: cannot read $from: $!\n");
$content = <HANDLE>;
close(HANDLE);
- open(HANDLE, ">$to") or die("ERROR: cannot write $from: $!\n");
+ open(HANDLE, ">", $to) or die("ERROR: cannot write $from: $!\n");
if (defined($content)) {
print(HANDLE $content);
}
@@ -798,9 +846,11 @@ sub lcov_geninfo(@)
{
@param = (@param, "--gcov-tool", $gcov_tool);
}
- if ($ignore_errors)
- {
- @param = (@param, "--ignore-errors", $ignore_errors);
+ foreach (@opt_ignore_errors) {
+ @param = (@param, "--ignore-errors", $_);
+ }
+ if ($no_recursion) {
+ @param = (@param, "--no-recursion");
}
if ($initial)
{
@@ -818,6 +868,26 @@ sub lcov_geninfo(@)
{
@param = (@param, "--debug");
}
+ if (defined($opt_external) && $opt_external)
+ {
+ @param = (@param, "--external");
+ }
+ if (defined($opt_external) && !$opt_external)
+ {
+ @param = (@param, "--no-external");
+ }
+ if (defined($opt_compat)) {
+ @param = (@param, "--compat", $opt_compat);
+ }
+ if (%opt_rc) {
+ foreach my $key (keys(%opt_rc)) {
+ @param = (@param, "--rc", "$key=".$opt_rc{$key});
+ }
+ }
+ if (defined($opt_config_file)) {
+ @param = (@param, "--config-file", $opt_config_file);
+ }
+
system(@param) and exit($? >> 8);
}
@@ -834,7 +904,7 @@ sub read_file($)
local $\;
local *HANDLE;
- open(HANDLE, "<$filename") || return undef;
+ open(HANDLE, "<", $filename) || return undef;
$content = <HANDLE>;
close(HANDLE);
@@ -860,17 +930,21 @@ sub get_package($)
local *HANDLE;
info("Reading package $file:\n");
- info(" data directory .......: $dir\n");
$file = abs_path($file);
chdir($dir);
- open(HANDLE, "tar xvfz $file 2>/dev/null|")
+ open(HANDLE, "-|", "tar xvfz '$file' 2>/dev/null")
or die("ERROR: could not process package $file\n");
+ $count = 0;
while (<HANDLE>) {
if (/\.da$/ || /\.gcda$/) {
$count++;
}
}
close(HANDLE);
+ if ($count == 0) {
+ die("ERROR: no data file found in package $file\n");
+ }
+ info(" data directory .......: $dir\n");
$build = read_file("$dir/$pkg_build_file");
if (defined($build)) {
info(" build directory ......: $build\n");
@@ -904,7 +978,7 @@ sub write_file($$)
my ($filename, $content) = @_;
local *HANDLE;
- open(HANDLE, ">$filename") || return 0;
+ open(HANDLE, ">", $filename) || return 0;
print(HANDLE $content);
close(HANDLE) || return 0;
@@ -922,7 +996,7 @@ sub count_package_data($)
local *HANDLE;
my $count = 0;
- open(HANDLE, "tar tfz $filename|") or return undef;
+ open(HANDLE, "-|", "tar tfz '$filename'") or return undef;
while (<HANDLE>) {
if (/\.da$/ || /\.gcda$/) {
$count++;
@@ -944,6 +1018,10 @@ sub create_package($$$;$)
my ($file, $dir, $build, $gkv) = @_;
my $cwd = getcwd();
+ # Check for availability of tar tool first
+ system("tar --help > /dev/null")
+ and die("ERROR: tar command not available\n");
+
# Print information about the package
info("Creating package $file:\n");
info(" data directory .......: $dir\n");
@@ -972,6 +1050,7 @@ sub create_package($$$;$)
chdir($dir);
system("tar cfz $file .")
and die("ERROR: could not create package $file\n");
+ chdir($cwd);
# Remove temporary files
unlink("$dir/$pkg_build_file");
@@ -985,7 +1064,6 @@ sub create_package($$$;$)
info(" data files ...........: $count\n");
}
}
- chdir($cwd);
}
sub find_link_fn($$$)
@@ -1208,6 +1286,113 @@ sub kernel_capture()
}
#
+# link_data_cb(datadir, rel, graphdir)
+#
+# Create symbolic link in GRAPDIR/REL pointing to DATADIR/REL.
+#
+
+sub link_data_cb($$$)
+{
+ my ($datadir, $rel, $graphdir) = @_;
+ my $absfrom = catfile($datadir, $rel);
+ my $absto = catfile($graphdir, $rel);
+ my $base;
+ my $dir;
+
+ if (-e $absto) {
+ die("ERROR: could not create symlink at $absto: ".
+ "File already exists!\n");
+ }
+ if (-l $absto) {
+ # Broken link - possibly from an interrupted earlier run
+ unlink($absto);
+ }
+
+ # Check for graph file
+ $base = $absto;
+ $base =~ s/\.(gcda|da)$//;
+ if (! -e $base.".gcno" && ! -e $base.".bbg" && ! -e $base.".bb") {
+ die("ERROR: No graph file found for $absfrom in ".
+ dirname($base)."!\n");
+ }
+
+ symlink($absfrom, $absto) or
+ die("ERROR: could not create symlink at $absto: $!\n");
+}
+
+#
+# unlink_data_cb(datadir, rel, graphdir)
+#
+# Remove symbolic link from GRAPHDIR/REL to DATADIR/REL.
+#
+
+sub unlink_data_cb($$$)
+{
+ my ($datadir, $rel, $graphdir) = @_;
+ my $absfrom = catfile($datadir, $rel);
+ my $absto = catfile($graphdir, $rel);
+ my $target;
+
+ return if (!-l $absto);
+ $target = readlink($absto);
+ return if (!defined($target) || $target ne $absfrom);
+
+ unlink($absto) or
+ warn("WARNING: could not remove symlink $absto: $!\n");
+}
+
+#
+# link_data(datadir, graphdir, create)
+#
+# If CREATE is non-zero, create symbolic links in GRAPHDIR for data files
+# found in DATADIR. Otherwise remove link in GRAPHDIR.
+#
+
+sub link_data($$$)
+{
+ my ($datadir, $graphdir, $create) = @_;
+
+ $datadir = abs_path($datadir);
+ $graphdir = abs_path($graphdir);
+ if ($create) {
+ lcov_find($datadir, \&link_data_cb, $graphdir, '\.gcda$',
+ '\.da$');
+ } else {
+ lcov_find($datadir, \&unlink_data_cb, $graphdir, '\.gcda$',
+ '\.da$');
+ }
+}
+
+#
+# find_graph_cb(datadir, rel, count_ref)
+#
+# Count number of files found.
+#
+
+sub find_graph_cb($$$)
+{
+ my ($dir, $rel, $count_ref) = @_;
+
+ ($$count_ref)++;
+}
+
+#
+# find_graph(dir)
+#
+# Search DIR for a graph file. Return non-zero if one was found, zero otherwise.
+#
+
+sub find_graph($)
+{
+ my ($dir) = @_;
+ my $count = 0;
+
+ lcov_find($dir, \&find_graph_cb, \$count, '\.gcno$', '\.bb$', '\.bbg$');
+
+ return $count > 0 ? 1 : 0;
+}
+
+#
# package_capture()
#
# Capture coverage data from a package of unprocessed coverage data files
@@ -1242,7 +1427,16 @@ sub package_capture()
} else {
# Build directory needs to be passed to geninfo
$base_directory = $build;
- lcov_geninfo($dir);
+ if (find_graph($dir)) {
+ # Package contains graph files - collect from there
+ lcov_geninfo($dir);
+ } else {
+ # No graph files found, link data files next to
+ # graph files
+ link_data($dir, $base_directory, 1);
+ lcov_geninfo($base_directory);
+ link_data($dir, $base_directory, 0);
+ }
}
}
@@ -1397,10 +1591,12 @@ sub br_ivec_push($$$$)
my $i;
$vec = "" if (!defined($vec));
+ $block = $BR_VEC_MAX if $block < 0;
# Check if branch already exists in vector
for ($i = 0; $i < $num; $i++) {
my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
+ $v_block = $BR_VEC_MAX if $v_block < 0;
next if ($v_block != $block || $v_branch != $branch);
@@ -1437,6 +1633,7 @@ sub br_ivec_get($$)
# Retrieve data from vector
$block = vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+ $block = -1 if ($block == $BR_VEC_MAX);
$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
$taken = vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
@@ -1492,6 +1689,10 @@ sub get_br_found_and_hit($)
# "func" -> \%funcdata
# "found" -> $lines_found (number of instrumented lines found in file)
# "hit" -> $lines_hit (number of executed lines in file)
+# "f_found" -> $fn_found (number of instrumented functions found in file)
+# "f_hit" -> $fn_hit (number of executed functions in file)
+# "b_found" -> $br_found (number of instrumented branches found in file)
+# "b_hit" -> $br_hit (number of executed branches in file)
# "check" -> \%checkdata
# "testfnc" -> \%testfncdata
# "sumfnc" -> \%sumfnccount
@@ -1576,14 +1777,14 @@ sub read_info_file($)
"compressed file $_[0]!\n");
# Open compressed file
- open(INFO_HANDLE, "gunzip -c $_[0]|")
+ open(INFO_HANDLE, "-|", "gunzip -c '$_[0]'")
or die("ERROR: cannot start gunzip to decompress ".
"file $_[0]!\n");
}
else
{
# Open decompressed file
- open(INFO_HANDLE, $_[0])
+ open(INFO_HANDLE, "<", $_[0])
or die("ERROR: cannot read file $_[0]!\n");
}
@@ -1674,6 +1875,8 @@ sub read_info_file($)
/^FN:(\d+),([^,]+)/ && do
{
+ last if (!$func_coverage);
+
# Function data found, add to structure
$funcdata->{$2} = $1;
@@ -1692,6 +1895,8 @@ sub read_info_file($)
/^FNDA:(\d+),([^,]+)/ && do
{
+ last if (!$func_coverage);
+
# Function call count found, add to structure
# Add summary counts
$sumfnccount->{$2} += $1;
@@ -1709,6 +1914,7 @@ sub read_info_file($)
my ($line, $block, $branch, $taken) =
($1, $2, $3, $4);
+ last if (!$br_coverage);
$sumbrcount->{$line} =
br_ivec_push($sumbrcount->{$line},
$block, $branch, $taken);
@@ -1912,8 +2118,8 @@ sub set_info_entry($$$$$$$$$;$$$$$$)
sub add_counts($$)
{
- my %data1 = %{$_[0]}; # Hash 1
- my %data2 = %{$_[1]}; # Hash 2
+ my $data1_ref = $_[0]; # Hash 1
+ my $data2_ref = $_[1]; # Hash 2
my %result; # Resulting hash
my $line; # Current line iteration scalar
my $data1_count; # Count of line in hash1
@@ -1921,10 +2127,10 @@ sub add_counts($$)
my $found = 0; # Total number of lines found
my $hit = 0; # Number of lines with a count > 0
- foreach $line (keys(%data1))
+ foreach $line (keys(%$data1_ref))
{
- $data1_count = $data1{$line};
- $data2_count = $data2{$line};
+ $data1_count = $data1_ref->{$line};
+ $data2_count = $data2_ref->{$line};
# Add counts if present in both hashes
if (defined($data2_count)) { $data1_count += $data2_count; }
@@ -1936,14 +2142,14 @@ sub add_counts($$)
if ($data1_count > 0) { $hit++; }
}
- # Add lines unique to data2
- foreach $line (keys(%data2))
+ # Add lines unique to data2_ref
+ foreach $line (keys(%$data2_ref))
{
- # Skip lines already in data1
- if (defined($data1{$line})) { next; }
+ # Skip lines already in data1_ref
+ if (defined($data1_ref->{$line})) { next; }
- # Copy count from data2
- $result{$line} = $data2{$line};
+ # Copy count from data2_ref
+ $result{$line} = $data2_ref->{$line};
$found++;
if ($result{$line} > 0) { $hit++; }
@@ -2439,7 +2645,7 @@ sub add_traces()
if ($to_file)
{
info("Writing data to $output_filename\n");
- open(INFO_HANDLE, ">$output_filename")
+ open(INFO_HANDLE, ">", $output_filename)
or die("ERROR: cannot write to $output_filename!\n");
@result = write_info_file(*INFO_HANDLE, $total_trace);
close(*INFO_HANDLE);
@@ -2548,6 +2754,7 @@ sub write_info_file(*$)
my ($block, $branch, $taken) =
br_ivec_get($brdata, $i);
+ $block = $BR_VEC_MAX if ($block < 0);
print(INFO_HANDLE "BRDA:$line,$block,".
"$branch,$taken\n");
$br_found++;
@@ -2589,7 +2796,7 @@ sub write_info_file(*$)
#
# transform_pattern(pattern)
#
-# Transform shell wildcard expression to equivalent PERL regular expression.
+# Transform shell wildcard expression to equivalent Perl regular expression.
# Return transformed pattern.
#
@@ -2669,7 +2876,7 @@ sub extract()
{
info("Extracted $extracted files\n");
info("Writing data to $output_filename\n");
- open(INFO_HANDLE, ">$output_filename")
+ open(INFO_HANDLE, ">", $output_filename)
or die("ERROR: cannot write to $output_filename!\n");
@result = write_info_file(*INFO_HANDLE, $data);
close(*INFO_HANDLE);
@@ -2725,7 +2932,7 @@ sub remove()
{
info("Deleted $removed files\n");
info("Writing data to $output_filename\n");
- open(INFO_HANDLE, ">$output_filename")
+ open(INFO_HANDLE, ">", $output_filename)
or die("ERROR: cannot write to $output_filename!\n");
@result = write_info_file(*INFO_HANDLE, $data);
close(*INFO_HANDLE);
@@ -2836,13 +3043,13 @@ sub shorten_number($$)
return '#';
}
-sub shorten_rate($$)
+sub shorten_rate($$$)
{
- my ($rate, $width) = @_;
- my $result = sprintf("%*.1f%%", $width - 3, $rate);
+ my ($hit, $found, $width) = @_;
+ my $result = rate($hit, $found, "%", 1, $width);
return $result if (length($result) <= $width);
- $result = sprintf("%*d%%", $width - 1, $rate);
+ $result = rate($hit, $found, "%", 0, $width);
return $result if (length($result) <= $width);
return "#";
}
@@ -3060,26 +3267,11 @@ sub list()
$br_total_hit += $br_hit;
# Determine line coverage rate for this file
- if ($found == 0) {
- $rate = "-";
- } else {
- $rate = shorten_rate(100 * $hit / $found,
- $fwidth[$F_LN_RATE]);
- }
+ $rate = shorten_rate($hit, $found, $fwidth[$F_LN_RATE]);
# Determine function coverage rate for this file
- if (!defined($fn_found) || $fn_found == 0) {
- $fnrate = "-";
- } else {
- $fnrate = shorten_rate(100 * $fn_hit / $fn_found,
- $fwidth[$F_FN_RATE]);
- }
+ $fnrate = shorten_rate($fn_hit, $fn_found, $fwidth[$F_FN_RATE]);
# Determine branch coverage rate for this file
- if (!defined($br_found) || $br_found == 0) {
- $brrate = "-";
- } else {
- $brrate = shorten_rate(100 * $br_hit / $br_found,
- $fwidth[$F_BR_RATE]);
- }
+ $brrate = shorten_rate($br_hit, $br_found, $fwidth[$F_BR_RATE]);
# Assemble line parameters
push(@file_data, $print_filename);
@@ -3095,26 +3287,13 @@ sub list()
}
# Determine total line coverage rate
- if ($total_found == 0) {
- $rate = "-";
- } else {
- $rate = shorten_rate(100 * $total_hit / $total_found,
- $fwidth[$F_LN_RATE]);
- }
+ $rate = shorten_rate($total_hit, $total_found, $fwidth[$F_LN_RATE]);
# Determine total function coverage rate
- if ($fn_total_found == 0) {
- $fnrate = "-";
- } else {
- $fnrate = shorten_rate(100 * $fn_total_hit / $fn_total_found,
- $fwidth[$F_FN_RATE]);
- }
+ $fnrate = shorten_rate($fn_total_hit, $fn_total_found,
+ $fwidth[$F_FN_RATE]);
# Determine total branch coverage rate
- if ($br_total_found == 0) {
- $brrate = "-";
- } else {
- $brrate = shorten_rate(100 * $br_total_hit / $br_total_found,
- $fwidth[$F_BR_RATE]);
- }
+ $brrate = shorten_rate($br_total_hit, $br_total_found,
+ $fwidth[$F_BR_RATE]);
# Print separator
print(("="x$barlen)."\n");
@@ -3253,14 +3432,14 @@ sub read_diff($)
"compressed file $diff_file!\n");
# Open compressed file
- open(HANDLE, "gunzip -c $diff_file|")
+ open(HANDLE, "-|", "gunzip -c '$diff_file'")
or die("ERROR: cannot start gunzip to decompress ".
"file $_[0]!\n");
}
else
{
# Open decompressed file
- open(HANDLE, $diff_file)
+ open(HANDLE, "<", $diff_file)
or die("ERROR: cannot read file $_[0]!\n");
}
@@ -3668,10 +3847,10 @@ sub adjust_fncdata($$$)
# Remove count data in testfncdata for functions which are no longer
# in funcdata
- foreach $testname (%{$testfncdata}) {
+ foreach $testname (keys(%{$testfncdata})) {
my $fnccount = $testfncdata->{$testname};
- foreach $func (%{$fnccount}) {
+ foreach $func (keys(%{$fnccount})) {
if (!defined($funcdata->{$func})) {
delete($fnccount->{$func});
}
@@ -3679,7 +3858,7 @@ sub adjust_fncdata($$$)
}
# Remove count data in sumfnccount for functions which are no longer
# in funcdata
- foreach $func (%{$sumfnccount}) {
+ foreach $func (keys(%{$sumfnccount})) {
if (!defined($funcdata->{$func})) {
delete($sumfnccount->{$func});
}
@@ -3886,7 +4065,7 @@ sub diff()
if ($to_file)
{
info("Writing data to $output_filename\n");
- open(INFO_HANDLE, ">$output_filename")
+ open(INFO_HANDLE, ">", $output_filename)
or die("ERROR: cannot write to $output_filename!\n");
@result = write_info_file(*INFO_HANDLE, $trace_data);
close(*INFO_HANDLE);
@@ -3899,6 +4078,59 @@ sub diff()
return @result;
}
+#
+# summary()
+#
+
+sub summary()
+{
+ my $filename;
+ my $current;
+ my $total;
+ my $ln_total_found;
+ my $ln_total_hit;
+ my $fn_total_found;
+ my $fn_total_hit;
+ my $br_total_found;
+ my $br_total_hit;
+
+ # Read and combine trace files
+ foreach $filename (@opt_summary) {
+ $current = read_info_file($filename);
+ if (!defined($total)) {
+ $total = $current;
+ } else {
+ $total = combine_info_files($total, $current);
+ }
+ }
+ # Calculate coverage data
+ foreach $filename (keys(%{$total}))
+ {
+ my $entry = $total->{$filename};
+ my $ln_found;
+ my $ln_hit;
+ my $fn_found;
+ my $fn_hit;
+ my $br_found;
+ my $br_hit;
+
+ (undef, undef, undef, undef, undef, undef, undef, undef,
+ $ln_found, $ln_hit, $fn_found, $fn_hit, $br_found,
+ $br_hit) = get_info_entry($entry);
+
+ # Add to totals
+ $ln_total_found += $ln_found;
+ $ln_total_hit += $ln_hit;
+ $fn_total_found += $fn_found;
+ $fn_total_hit += $fn_hit;
+ $br_total_found += $br_found;
+ $br_total_hit += $br_hit;
+ }
+
+
+ return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit,
+ $br_total_found, $br_total_hit);
+}
#
# system_no_output(mode, parameters)
@@ -3920,12 +4152,12 @@ sub system_no_output($@)
local *OLD_STDOUT;
# Save old stdout and stderr handles
- ($mode & 1) && open(OLD_STDOUT, ">>&STDOUT");
- ($mode & 2) && open(OLD_STDERR, ">>&STDERR");
+ ($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
+ ($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
# Redirect to /dev/null
- ($mode & 1) && open(STDOUT, ">/dev/null");
- ($mode & 2) && open(STDERR, ">/dev/null");
+ ($mode & 1) && open(STDOUT, ">", "/dev/null");
+ ($mode & 2) && open(STDERR, ">", "/dev/null");
system(@_);
$result = $?;
@@ -3935,8 +4167,8 @@ sub system_no_output($@)
($mode & 2) && close(STDERR);
# Restore old handles
- ($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
- ($mode & 2) && open(STDERR, ">>&OLD_STDERR");
+ ($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
+ ($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
return $result;
}
@@ -3957,7 +4189,7 @@ sub read_config($)
my $value;
local *HANDLE;
- if (!open(HANDLE, "<$filename"))
+ if (!open(HANDLE, "<", $filename))
{
warn("WARNING: cannot read configuration file $filename\n");
return undef;
@@ -3996,8 +4228,8 @@ sub read_config($)
# key_string => var_ref
#
# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
-# variable. If the global configuration hash CONFIG contains a value for
-# keyword KEY_STRING, VAR_REF will be assigned the value for that keyword.
+# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
+# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword.
#
sub apply_config($)
@@ -4006,8 +4238,9 @@ sub apply_config($)
foreach (keys(%{$ref}))
{
- if (defined($config->{$_}))
- {
+ if (defined($opt_rc{$_})) {
+ ${$ref->{$_}} = $opt_rc{$_};
+ } elsif (defined($config->{$_})) {
${$ref->{$_}} = $config->{$_};
}
}
@@ -4037,6 +4270,9 @@ sub abort_handler($)
sub temp_cleanup()
{
+ # Ensure temp directory is not in use by current process
+ chdir("/");
+
if (@temp_dirs) {
info("Removing temporary directories.\n");
foreach (@temp_dirs) {
@@ -4145,8 +4381,8 @@ sub get_overall_line($$$$)
return "no data found" if (!defined($found) || $found == 0);
$name = ($found == 1) ? $name_sn : $name_pl;
- return sprintf("%.1f%% (%d of %d %s)", $hit * 100 / $found, $hit,
- $found, $name);
+
+ return rate($hit, $found, "% ($hit of $found $name)");
}
@@ -4162,7 +4398,7 @@ sub print_overall_rate($$$$$$$$$)
my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
$br_do, $br_found, $br_hit) = @_;
- info("Overall coverage rate:\n");
+ info("Summary coverage rate:\n");
info(" lines......: %s\n",
get_overall_line($ln_found, $ln_hit, "line", "lines"))
if ($ln_do);
@@ -4173,3 +4409,38 @@ sub print_overall_rate($$$$$$$$$)
get_overall_line($br_found, $br_hit, "branch", "branches"))
if ($br_do);
}
+
+
+#
+# rate(hit, found[, suffix, precision, width])
+#
+# Return the coverage rate [0..100] for HIT and FOUND values. 0 is only
+# returned when HIT is 0. 100 is only returned when HIT equals FOUND.
+# PRECISION specifies the precision of the result. SUFFIX defines a
+# string that is appended to the result if FOUND is non-zero. Spaces
+# are added to the start of the resulting string until it is at least WIDTH
+# characters wide.
+#
+
+sub rate($$;$$$)
+{
+ my ($hit, $found, $suffix, $precision, $width) = @_;
+ my $rate;
+
+ # Assign defaults if necessary
+ $precision = 1 if (!defined($precision));
+ $suffix = "" if (!defined($suffix));
+ $width = 0 if (!defined($width));
+
+ return sprintf("%*s", $width, "-") if (!defined($found) || $found == 0);
+ $rate = sprintf("%.*f", $precision, $hit * 100 / $found);
+
+ # Adjust rates if necessary
+ if ($rate == 0 && $hit > 0) {
+ $rate = sprintf("%.*f", $precision, 1 / 10 ** $precision);
+ } elsif ($rate == 100 && $hit != $found) {
+ $rate = sprintf("%.*f", $precision, 100 - 1 / 10 ** $precision);
+ }
+
+ return sprintf("%*s", $width, $rate.$suffix);
+}