| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 #!/usr/bin/perl -w |  | 
| 2 # |  | 
| 3 #   Copyright (c) International Business Machines  Corp., 2002,2010 |  | 
| 4 # |  | 
| 5 #   This program is free software;  you can redistribute it and/or modify |  | 
| 6 #   it under the terms of the GNU General Public License as published by |  | 
| 7 #   the Free Software Foundation; either version 2 of the License, or (at |  | 
| 8 #   your option) any later version. |  | 
| 9 # |  | 
| 10 #   This program is distributed in the hope that it will be useful, but |  | 
| 11 #   WITHOUT ANY WARRANTY;  without even the implied warranty of |  | 
| 12 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU |  | 
| 13 #   General Public License for more details. |  | 
| 14 # |  | 
| 15 #   You should have received a copy of the GNU General Public License |  | 
| 16 #   along with this program;  if not, write to the Free Software |  | 
| 17 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |  | 
| 18 # |  | 
| 19 # |  | 
| 20 # genhtml |  | 
| 21 # |  | 
| 22 #   This script generates HTML output from .info files as created by the |  | 
| 23 #   geninfo script. Call it with --help and refer to the genhtml man page |  | 
| 24 #   to get information on usage and available options. |  | 
| 25 # |  | 
| 26 # |  | 
| 27 # History: |  | 
| 28 #   2002-08-23 created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com> |  | 
| 29 #                         IBM Lab Boeblingen |  | 
| 30 #        based on code by Manoj Iyer <manjo@mail.utexas.edu> and |  | 
| 31 #                         Megan Bock <mbock@us.ibm.com> |  | 
| 32 #                         IBM Austin |  | 
| 33 #   2002-08-27 / Peter Oberparleiter: implemented frame view |  | 
| 34 #   2002-08-29 / Peter Oberparleiter: implemented test description filtering |  | 
| 35 #                so that by default only descriptions for test cases which |  | 
| 36 #                actually hit some source lines are kept |  | 
| 37 #   2002-09-05 / Peter Oberparleiter: implemented --no-sourceview |  | 
| 38 #   2002-09-05 / Mike Kobler: One of my source file paths includes a "+" in |  | 
| 39 #                the directory name.  I found that genhtml.pl died when it |  | 
| 40 #                encountered it. I was able to fix the problem by modifying |  | 
| 41 #                the string with the escape character before parsing it. |  | 
| 42 #   2002-10-26 / Peter Oberparleiter: implemented --num-spaces |  | 
| 43 #   2003-04-07 / Peter Oberparleiter: fixed bug which resulted in an error |  | 
| 44 #                when trying to combine .info files containing data without |  | 
| 45 #                a test name |  | 
| 46 #   2003-04-10 / Peter Oberparleiter: extended fix by Mike to also cover |  | 
| 47 #                other special characters |  | 
| 48 #   2003-04-30 / Peter Oberparleiter: made info write to STDERR, not STDOUT |  | 
| 49 #   2003-07-10 / Peter Oberparleiter: added line checksum support |  | 
| 50 #   2004-08-09 / Peter Oberparleiter: added configuration file support |  | 
| 51 #   2005-03-04 / Cal Pierog: added legend to HTML output, fixed coloring of |  | 
| 52 #                "good coverage" background |  | 
| 53 #   2006-03-18 / Marcus Boerger: added --custom-intro, --custom-outro and |  | 
| 54 #                overwrite --no-prefix if --prefix is present |  | 
| 55 #   2006-03-20 / Peter Oberparleiter: changes to custom_* function (rename |  | 
| 56 #                to html_prolog/_epilog, minor modifications to implementation), |  | 
| 57 #                changed prefix/noprefix handling to be consistent with current |  | 
| 58 #                logic |  | 
| 59 #   2006-03-20 / Peter Oberparleiter: added --html-extension option |  | 
| 60 #   2008-07-14 / Tom Zoerner: added --function-coverage command line option; |  | 
| 61 #                added function table to source file page |  | 
| 62 #   2008-08-13 / Peter Oberparleiter: modified function coverage |  | 
| 63 #                implementation (now enabled per default), |  | 
| 64 #                introduced sorting option (enabled per default) |  | 
| 65 # |  | 
| 66 |  | 
| 67 use strict; |  | 
| 68 use File::Basename; |  | 
| 69 use Getopt::Long; |  | 
| 70 use Digest::MD5 qw(md5_base64); |  | 
| 71 |  | 
| 72 |  | 
| 73 # Global constants |  | 
| 74 our $title              = "LCOV - code coverage report"; |  | 
| 75 our $lcov_version       = 'LCOV version 1.9'; |  | 
| 76 our $lcov_url           = "http://ltp.sourceforge.net/coverage/lcov.php"; |  | 
| 77 our $tool_name          = basename($0); |  | 
| 78 |  | 
| 79 # Specify coverage rate limits (in %) for classifying file entries |  | 
| 80 # HI:   $hi_limit <= rate <= 100          graph color: green |  | 
| 81 # MED: $med_limit <= rate <  $hi_limit    graph color: orange |  | 
| 82 # LO:          0  <= rate <  $med_limit   graph color: red |  | 
| 83 |  | 
| 84 # For line coverage/all coverage types if not specified |  | 
| 85 our $hi_limit = 90; |  | 
| 86 our $med_limit = 75; |  | 
| 87 |  | 
| 88 # For function coverage |  | 
| 89 our $fn_hi_limit; |  | 
| 90 our $fn_med_limit; |  | 
| 91 |  | 
| 92 # For branch coverage |  | 
| 93 our $br_hi_limit; |  | 
| 94 our $br_med_limit; |  | 
| 95 |  | 
| 96 # Width of overview image |  | 
| 97 our $overview_width = 80; |  | 
| 98 |  | 
| 99 # Resolution of overview navigation: this number specifies the maximum |  | 
| 100 # difference in lines between the position a user selected from the overview |  | 
| 101 # and the position the source code window is scrolled to. |  | 
| 102 our $nav_resolution = 4; |  | 
| 103 |  | 
| 104 # Clicking a line in the overview image should show the source code view at |  | 
| 105 # a position a bit further up so that the requested line is not the first |  | 
| 106 # line in the window. This number specifies that offset in lines. |  | 
| 107 our $nav_offset = 10; |  | 
| 108 |  | 
| 109 # Clicking on a function name should show the source code at a position a |  | 
| 110 # few lines before the first line of code of that function. This number |  | 
| 111 # specifies that offset in lines. |  | 
| 112 our $func_offset = 2; |  | 
| 113 |  | 
| 114 our $overview_title = "top level"; |  | 
| 115 |  | 
| 116 # Width for line coverage information in the source code view |  | 
| 117 our $line_field_width = 12; |  | 
| 118 |  | 
| 119 # Width for branch coverage information in the source code view |  | 
| 120 our $br_field_width = 16; |  | 
| 121 |  | 
| 122 # Internal Constants |  | 
| 123 |  | 
| 124 # Header types |  | 
| 125 our $HDR_DIR            = 0; |  | 
| 126 our $HDR_FILE           = 1; |  | 
| 127 our $HDR_SOURCE         = 2; |  | 
| 128 our $HDR_TESTDESC       = 3; |  | 
| 129 our $HDR_FUNC           = 4; |  | 
| 130 |  | 
| 131 # Sort types |  | 
| 132 our $SORT_FILE          = 0; |  | 
| 133 our $SORT_LINE          = 1; |  | 
| 134 our $SORT_FUNC          = 2; |  | 
| 135 our $SORT_BRANCH        = 3; |  | 
| 136 |  | 
| 137 # Fileview heading types |  | 
| 138 our $HEAD_NO_DETAIL     = 1; |  | 
| 139 our $HEAD_DETAIL_HIDDEN = 2; |  | 
| 140 our $HEAD_DETAIL_SHOWN  = 3; |  | 
| 141 |  | 
| 142 # Offsets for storing branch coverage data in vectors |  | 
| 143 our $BR_BLOCK           = 0; |  | 
| 144 our $BR_BRANCH          = 1; |  | 
| 145 our $BR_TAKEN           = 2; |  | 
| 146 our $BR_VEC_ENTRIES     = 3; |  | 
| 147 our $BR_VEC_WIDTH       = 32; |  | 
| 148 |  | 
| 149 # Additional offsets used when converting branch coverage data to HTML |  | 
| 150 our $BR_LEN     = 3; |  | 
| 151 our $BR_OPEN    = 4; |  | 
| 152 our $BR_CLOSE   = 5; |  | 
| 153 |  | 
| 154 # Branch data combination types |  | 
| 155 our $BR_SUB = 0; |  | 
| 156 our $BR_ADD = 1; |  | 
| 157 |  | 
| 158 # Data related prototypes |  | 
| 159 sub print_usage(*); |  | 
| 160 sub gen_html(); |  | 
| 161 sub html_create($$); |  | 
| 162 sub process_dir($); |  | 
| 163 sub process_file($$$); |  | 
| 164 sub info(@); |  | 
| 165 sub read_info_file($); |  | 
| 166 sub get_info_entry($); |  | 
| 167 sub set_info_entry($$$$$$$$$;$$$$$$); |  | 
| 168 sub get_prefix(@); |  | 
| 169 sub shorten_prefix($); |  | 
| 170 sub get_dir_list(@); |  | 
| 171 sub get_relative_base_path($); |  | 
| 172 sub read_testfile($); |  | 
| 173 sub get_date_string(); |  | 
| 174 sub create_sub_dir($); |  | 
| 175 sub subtract_counts($$); |  | 
| 176 sub add_counts($$); |  | 
| 177 sub apply_baseline($$); |  | 
| 178 sub remove_unused_descriptions(); |  | 
| 179 sub get_found_and_hit($); |  | 
| 180 sub get_affecting_tests($$$); |  | 
| 181 sub combine_info_files($$); |  | 
| 182 sub merge_checksums($$$); |  | 
| 183 sub combine_info_entries($$$); |  | 
| 184 sub apply_prefix($$); |  | 
| 185 sub system_no_output($@); |  | 
| 186 sub read_config($); |  | 
| 187 sub apply_config($); |  | 
| 188 sub get_html_prolog($); |  | 
| 189 sub get_html_epilog($); |  | 
| 190 sub write_dir_page($$$$$$$$$$$$$$$$$); |  | 
| 191 sub classify_rate($$$$); |  | 
| 192 sub br_taken_add($$); |  | 
| 193 sub br_taken_sub($$); |  | 
| 194 sub br_ivec_len($); |  | 
| 195 sub br_ivec_get($$); |  | 
| 196 sub br_ivec_push($$$$); |  | 
| 197 sub combine_brcount($$$); |  | 
| 198 sub get_br_found_and_hit($); |  | 
| 199 sub warn_handler($); |  | 
| 200 sub die_handler($); |  | 
| 201 |  | 
| 202 |  | 
| 203 # HTML related prototypes |  | 
| 204 sub escape_html($); |  | 
| 205 sub get_bar_graph_code($$$); |  | 
| 206 |  | 
| 207 sub write_png_files(); |  | 
| 208 sub write_htaccess_file(); |  | 
| 209 sub write_css_file(); |  | 
| 210 sub write_description_file($$$$$$$); |  | 
| 211 sub write_function_table(*$$$$$$$$$$); |  | 
| 212 |  | 
| 213 sub write_html(*$); |  | 
| 214 sub write_html_prolog(*$$); |  | 
| 215 sub write_html_epilog(*$;$); |  | 
| 216 |  | 
| 217 sub write_header(*$$$$$$$$$$); |  | 
| 218 sub write_header_prolog(*$); |  | 
| 219 sub write_header_line(*@); |  | 
| 220 sub write_header_epilog(*$); |  | 
| 221 |  | 
| 222 sub write_file_table(*$$$$$$$); |  | 
| 223 sub write_file_table_prolog(*$@); |  | 
| 224 sub write_file_table_entry(*$$$@); |  | 
| 225 sub write_file_table_detail_entry(*$@); |  | 
| 226 sub write_file_table_epilog(*); |  | 
| 227 |  | 
| 228 sub write_test_table_prolog(*$); |  | 
| 229 sub write_test_table_entry(*$$); |  | 
| 230 sub write_test_table_epilog(*); |  | 
| 231 |  | 
| 232 sub write_source($$$$$$$); |  | 
| 233 sub write_source_prolog(*); |  | 
| 234 sub write_source_line(*$$$$$$); |  | 
| 235 sub write_source_epilog(*); |  | 
| 236 |  | 
| 237 sub write_frameset(*$$$); |  | 
| 238 sub write_overview_line(*$$$); |  | 
| 239 sub write_overview(*$$$$); |  | 
| 240 |  | 
| 241 # External prototype (defined in genpng) |  | 
| 242 sub gen_png($$$@); |  | 
| 243 |  | 
| 244 |  | 
| 245 # Global variables & initialization |  | 
| 246 our %info_data;         # Hash containing all data from .info file |  | 
| 247 our $dir_prefix;        # Prefix to remove from all sub directories |  | 
| 248 our %test_description;  # Hash containing test descriptions if available |  | 
| 249 our $date = get_date_string(); |  | 
| 250 |  | 
| 251 our @info_filenames;    # List of .info files to use as data source |  | 
| 252 our $test_title;        # Title for output as written to each page header |  | 
| 253 our $output_directory;  # Name of directory in which to store output |  | 
| 254 our $base_filename;     # Optional name of file containing baseline data |  | 
| 255 our $desc_filename;     # Name of file containing test descriptions |  | 
| 256 our $css_filename;      # Optional name of external stylesheet file to use |  | 
| 257 our $quiet;             # If set, suppress information messages |  | 
| 258 our $help;              # Help option flag |  | 
| 259 our $version;           # Version option flag |  | 
| 260 our $show_details;      # If set, generate detailed directory view |  | 
| 261 our $no_prefix;         # If set, do not remove filename prefix |  | 
| 262 our $func_coverage = 1; # If set, generate function coverage statistics |  | 
| 263 our $no_func_coverage;  # Disable func_coverage |  | 
| 264 our $br_coverage = 1;   # If set, generate branch coverage statistics |  | 
| 265 our $no_br_coverage;    # Disable br_coverage |  | 
| 266 our $sort = 1;          # If set, provide directory listings with sorted entries |  | 
| 267 our $no_sort;           # Disable sort |  | 
| 268 our $frames;            # If set, use frames for source code view |  | 
| 269 our $keep_descriptions; # If set, do not remove unused test case descriptions |  | 
| 270 our $no_sourceview;     # If set, do not create a source code view for each file |  | 
| 271 our $highlight;         # If set, highlight lines covered by converted data only |  | 
| 272 our $legend;            # If set, include legend in output |  | 
| 273 our $tab_size = 8;      # Number of spaces to use in place of tab |  | 
| 274 our $config;            # Configuration file contents |  | 
| 275 our $html_prolog_file;  # Custom HTML prolog file (up to and including <body>) |  | 
| 276 our $html_epilog_file;  # Custom HTML epilog file (from </body> onwards) |  | 
| 277 our $html_prolog;       # Actual HTML prolog |  | 
| 278 our $html_epilog;       # Actual HTML epilog |  | 
| 279 our $html_ext = "html"; # Extension for generated HTML files |  | 
| 280 our $html_gzip = 0;     # Compress with gzip |  | 
| 281 our $demangle_cpp = 0;  # Demangle C++ function names |  | 
| 282 our @fileview_sortlist; |  | 
| 283 our @fileview_sortname = ("", "-sort-l", "-sort-f", "-sort-b"); |  | 
| 284 our @funcview_sortlist; |  | 
| 285 our @rate_name = ("Lo", "Med", "Hi"); |  | 
| 286 our @rate_png = ("ruby.png", "amber.png", "emerald.png"); |  | 
| 287 |  | 
| 288 our $cwd = `pwd`;       # Current working directory |  | 
| 289 chomp($cwd); |  | 
| 290 our $tool_dir = dirname($0);    # Directory where genhtml tool is installed |  | 
| 291 |  | 
| 292 |  | 
| 293 # |  | 
| 294 # Code entry point |  | 
| 295 # |  | 
| 296 |  | 
| 297 $SIG{__WARN__} = \&warn_handler; |  | 
| 298 $SIG{__DIE__} = \&die_handler; |  | 
| 299 |  | 
| 300 # Prettify version string |  | 
| 301 $lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/; |  | 
| 302 |  | 
| 303 # Add current working directory if $tool_dir is not already an absolute path |  | 
| 304 if (! ($tool_dir =~ /^\/(.*)$/)) |  | 
| 305 { |  | 
| 306         $tool_dir = "$cwd/$tool_dir"; |  | 
| 307 } |  | 
| 308 |  | 
| 309 # Read configuration file if available |  | 
| 310 if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc")) |  | 
| 311 { |  | 
| 312         $config = read_config($ENV{"HOME"}."/.lcovrc"); |  | 
| 313 } |  | 
| 314 elsif (-r "/etc/lcovrc") |  | 
| 315 { |  | 
| 316         $config = read_config("/etc/lcovrc"); |  | 
| 317 } |  | 
| 318 |  | 
| 319 if ($config) |  | 
| 320 { |  | 
| 321         # Copy configuration file values to variables |  | 
| 322         apply_config({ |  | 
| 323                 "genhtml_css_file"              => \$css_filename, |  | 
| 324                 "genhtml_hi_limit"              => \$hi_limit, |  | 
| 325                 "genhtml_med_limit"             => \$med_limit, |  | 
| 326                 "genhtml_line_field_width"      => \$line_field_width, |  | 
| 327                 "genhtml_overview_width"        => \$overview_width, |  | 
| 328                 "genhtml_nav_resolution"        => \$nav_resolution, |  | 
| 329                 "genhtml_nav_offset"            => \$nav_offset, |  | 
| 330                 "genhtml_keep_descriptions"     => \$keep_descriptions, |  | 
| 331                 "genhtml_no_prefix"             => \$no_prefix, |  | 
| 332                 "genhtml_no_source"             => \$no_sourceview, |  | 
| 333                 "genhtml_num_spaces"            => \$tab_size, |  | 
| 334                 "genhtml_highlight"             => \$highlight, |  | 
| 335                 "genhtml_legend"                => \$legend, |  | 
| 336                 "genhtml_html_prolog"           => \$html_prolog_file, |  | 
| 337                 "genhtml_html_epilog"           => \$html_epilog_file, |  | 
| 338                 "genhtml_html_extension"        => \$html_ext, |  | 
| 339                 "genhtml_html_gzip"             => \$html_gzip, |  | 
| 340                 "genhtml_function_hi_limit"     => \$fn_hi_limit, |  | 
| 341                 "genhtml_function_med_limit"    => \$fn_med_limit, |  | 
| 342                 "genhtml_function_coverage"     => \$func_coverage, |  | 
| 343                 "genhtml_branch_hi_limit"       => \$br_hi_limit, |  | 
| 344                 "genhtml_branch_med_limit"      => \$br_med_limit, |  | 
| 345                 "genhtml_branch_coverage"       => \$br_coverage, |  | 
| 346                 "genhtml_branch_field_width"    => \$br_field_width, |  | 
| 347                 "genhtml_sort"                  => \$sort, |  | 
| 348                 }); |  | 
| 349 } |  | 
| 350 |  | 
| 351 # Copy limit values if not specified |  | 
| 352 $fn_hi_limit    = $hi_limit if (!defined($fn_hi_limit)); |  | 
| 353 $fn_med_limit   = $med_limit if (!defined($fn_med_limit)); |  | 
| 354 $br_hi_limit    = $hi_limit if (!defined($br_hi_limit)); |  | 
| 355 $br_med_limit   = $med_limit if (!defined($br_med_limit)); |  | 
| 356 |  | 
| 357 # Parse command line options |  | 
| 358 if (!GetOptions("output-directory|o=s"  => \$output_directory, |  | 
| 359                 "title|t=s"             => \$test_title, |  | 
| 360                 "description-file|d=s"  => \$desc_filename, |  | 
| 361                 "keep-descriptions|k"   => \$keep_descriptions, |  | 
| 362                 "css-file|c=s"          => \$css_filename, |  | 
| 363                 "baseline-file|b=s"     => \$base_filename, |  | 
| 364                 "prefix|p=s"            => \$dir_prefix, |  | 
| 365                 "num-spaces=i"          => \$tab_size, |  | 
| 366                 "no-prefix"             => \$no_prefix, |  | 
| 367                 "no-sourceview"         => \$no_sourceview, |  | 
| 368                 "show-details|s"        => \$show_details, |  | 
| 369                 "frames|f"              => \$frames, |  | 
| 370                 "highlight"             => \$highlight, |  | 
| 371                 "legend"                => \$legend, |  | 
| 372                 "quiet|q"               => \$quiet, |  | 
| 373                 "help|h|?"              => \$help, |  | 
| 374                 "version|v"             => \$version, |  | 
| 375                 "html-prolog=s"         => \$html_prolog_file, |  | 
| 376                 "html-epilog=s"         => \$html_epilog_file, |  | 
| 377                 "html-extension=s"      => \$html_ext, |  | 
| 378                 "html-gzip"             => \$html_gzip, |  | 
| 379                 "function-coverage"     => \$func_coverage, |  | 
| 380                 "no-function-coverage"  => \$no_func_coverage, |  | 
| 381                 "branch-coverage"       => \$br_coverage, |  | 
| 382                 "no-branch-coverage"    => \$no_br_coverage, |  | 
| 383                 "sort"                  => \$sort, |  | 
| 384                 "no-sort"               => \$no_sort, |  | 
| 385                 "demangle-cpp"          => \$demangle_cpp, |  | 
| 386                 )) |  | 
| 387 { |  | 
| 388         print(STDERR "Use $tool_name --help to get usage information\n"); |  | 
| 389         exit(1); |  | 
| 390 } else { |  | 
| 391         # Merge options |  | 
| 392         if ($no_func_coverage) { |  | 
| 393                 $func_coverage = 0; |  | 
| 394         } |  | 
| 395         if ($no_br_coverage) { |  | 
| 396                 $br_coverage = 0; |  | 
| 397         } |  | 
| 398 |  | 
| 399         # Merge sort options |  | 
| 400         if ($no_sort) { |  | 
| 401                 $sort = 0; |  | 
| 402         } |  | 
| 403 } |  | 
| 404 |  | 
| 405 @info_filenames = @ARGV; |  | 
| 406 |  | 
| 407 # Check for help option |  | 
| 408 if ($help) |  | 
| 409 { |  | 
| 410         print_usage(*STDOUT); |  | 
| 411         exit(0); |  | 
| 412 } |  | 
| 413 |  | 
| 414 # Check for version option |  | 
| 415 if ($version) |  | 
| 416 { |  | 
| 417         print("$tool_name: $lcov_version\n"); |  | 
| 418         exit(0); |  | 
| 419 } |  | 
| 420 |  | 
| 421 # Check for info filename |  | 
| 422 if (!@info_filenames) |  | 
| 423 { |  | 
| 424         die("No filename specified\n". |  | 
| 425             "Use $tool_name --help to get usage information\n"); |  | 
| 426 } |  | 
| 427 |  | 
| 428 # Generate a title if none is specified |  | 
| 429 if (!$test_title) |  | 
| 430 { |  | 
| 431         if (scalar(@info_filenames) == 1) |  | 
| 432         { |  | 
| 433                 # Only one filename specified, use it as title |  | 
| 434                 $test_title = basename($info_filenames[0]); |  | 
| 435         } |  | 
| 436         else |  | 
| 437         { |  | 
| 438                 # More than one filename specified, used default title |  | 
| 439                 $test_title = "unnamed"; |  | 
| 440         } |  | 
| 441 } |  | 
| 442 |  | 
| 443 # Make sure css_filename is an absolute path (in case we're changing |  | 
| 444 # directories) |  | 
| 445 if ($css_filename) |  | 
| 446 { |  | 
| 447         if (!($css_filename =~ /^\/(.*)$/)) |  | 
| 448         { |  | 
| 449                 $css_filename = $cwd."/".$css_filename; |  | 
| 450         } |  | 
| 451 } |  | 
| 452 |  | 
| 453 # Make sure tab_size is within valid range |  | 
| 454 if ($tab_size < 1) |  | 
| 455 { |  | 
| 456         print(STDERR "ERROR: invalid number of spaces specified: ". |  | 
| 457                      "$tab_size!\n"); |  | 
| 458         exit(1); |  | 
| 459 } |  | 
| 460 |  | 
| 461 # Get HTML prolog and epilog |  | 
| 462 $html_prolog = get_html_prolog($html_prolog_file); |  | 
| 463 $html_epilog = get_html_epilog($html_epilog_file); |  | 
| 464 |  | 
| 465 # Issue a warning if --no-sourceview is enabled together with --frames |  | 
| 466 if ($no_sourceview && defined($frames)) |  | 
| 467 { |  | 
| 468         warn("WARNING: option --frames disabled because --no-sourceview ". |  | 
| 469              "was specified!\n"); |  | 
| 470         $frames = undef; |  | 
| 471 } |  | 
| 472 |  | 
| 473 # Issue a warning if --no-prefix is enabled together with --prefix |  | 
| 474 if ($no_prefix && defined($dir_prefix)) |  | 
| 475 { |  | 
| 476         warn("WARNING: option --prefix disabled because --no-prefix was ". |  | 
| 477              "specified!\n"); |  | 
| 478         $dir_prefix = undef; |  | 
| 479 } |  | 
| 480 |  | 
| 481 @fileview_sortlist = ($SORT_FILE); |  | 
| 482 @funcview_sortlist = ($SORT_FILE); |  | 
| 483 |  | 
| 484 if ($sort) { |  | 
| 485         push(@fileview_sortlist, $SORT_LINE); |  | 
| 486         push(@fileview_sortlist, $SORT_FUNC) if ($func_coverage); |  | 
| 487         push(@fileview_sortlist, $SORT_BRANCH) if ($br_coverage); |  | 
| 488         push(@funcview_sortlist, $SORT_LINE); |  | 
| 489 } |  | 
| 490 |  | 
| 491 if ($frames) |  | 
| 492 { |  | 
| 493         # Include genpng code needed for overview image generation |  | 
| 494         do("$tool_dir/genpng"); |  | 
| 495 } |  | 
| 496 |  | 
| 497 # Ensure that the c++filt tool is available when using --demangle-cpp |  | 
| 498 if ($demangle_cpp) |  | 
| 499 { |  | 
| 500         if (system_no_output(3, "c++filt", "--version")) { |  | 
| 501                 die("ERROR: could not find c++filt tool needed for ". |  | 
| 502                     "--demangle-cpp\n"); |  | 
| 503         } |  | 
| 504 } |  | 
| 505 |  | 
| 506 # Make sure output_directory exists, create it if necessary |  | 
| 507 if ($output_directory) |  | 
| 508 { |  | 
| 509         stat($output_directory); |  | 
| 510 |  | 
| 511         if (! -e _) |  | 
| 512         { |  | 
| 513                 create_sub_dir($output_directory); |  | 
| 514         } |  | 
| 515 } |  | 
| 516 |  | 
| 517 # Do something |  | 
| 518 gen_html(); |  | 
| 519 |  | 
| 520 exit(0); |  | 
| 521 |  | 
| 522 |  | 
| 523 |  | 
| 524 # |  | 
| 525 # print_usage(handle) |  | 
| 526 # |  | 
| 527 # Print usage information. |  | 
| 528 # |  | 
| 529 |  | 
| 530 sub print_usage(*) |  | 
| 531 { |  | 
| 532         local *HANDLE = $_[0]; |  | 
| 533 |  | 
| 534         print(HANDLE <<END_OF_USAGE); |  | 
| 535 Usage: $tool_name [OPTIONS] INFOFILE(S) |  | 
| 536 |  | 
| 537 Create HTML output for coverage data found in INFOFILE. Note that INFOFILE |  | 
| 538 may also be a list of filenames. |  | 
| 539 |  | 
| 540 Misc: |  | 
| 541   -h, --help                        Print this help, then exit |  | 
| 542   -v, --version                     Print version number, then exit |  | 
| 543   -q, --quiet                       Do not print progress messages |  | 
| 544 |  | 
| 545 Operation: |  | 
| 546   -o, --output-directory OUTDIR     Write HTML output to OUTDIR |  | 
| 547   -s, --show-details                Generate detailed directory view |  | 
| 548   -d, --description-file DESCFILE   Read test case descriptions from DESCFILE |  | 
| 549   -k, --keep-descriptions           Do not remove unused test descriptions |  | 
| 550   -b, --baseline-file BASEFILE      Use BASEFILE as baseline file |  | 
| 551   -p, --prefix PREFIX               Remove PREFIX from all directory names |  | 
| 552       --no-prefix                   Do not remove prefix from directory names |  | 
| 553       --(no-)function-coverage      Enable (disable) function coverage display |  | 
| 554       --(no-)branch-coverage        Enable (disable) branch coverage display |  | 
| 555 |  | 
| 556 HTML output: |  | 
| 557   -f, --frames                      Use HTML frames for source code view |  | 
| 558   -t, --title TITLE                 Display TITLE in header of all pages |  | 
| 559   -c, --css-file CSSFILE            Use external style sheet file CSSFILE |  | 
| 560       --no-source                   Do not create source code view |  | 
| 561       --num-spaces NUM              Replace tabs with NUM spaces in source view |  | 
| 562       --highlight                   Highlight lines with converted-only data |  | 
| 563       --legend                      Include color legend in HTML output |  | 
| 564       --html-prolog FILE            Use FILE as HTML prolog for generated pages |  | 
| 565       --html-epilog FILE            Use FILE as HTML epilog for generated pages |  | 
| 566       --html-extension EXT          Use EXT as filename extension for pages |  | 
| 567       --html-gzip                   Use gzip to compress HTML |  | 
| 568       --(no-)sort                   Enable (disable) sorted coverage views |  | 
| 569       --demangle-cpp                Demangle C++ function names |  | 
| 570 |  | 
| 571 For more information see: $lcov_url |  | 
| 572 END_OF_USAGE |  | 
| 573         ; |  | 
| 574 } |  | 
| 575 |  | 
| 576 |  | 
| 577 # |  | 
| 578 # get_rate(found, hit) |  | 
| 579 # |  | 
| 580 # Return a relative value for the specified found&hit values |  | 
| 581 # which is used for sorting the corresponding entries in a |  | 
| 582 # file list. |  | 
| 583 # |  | 
| 584 |  | 
| 585 sub get_rate($$) |  | 
| 586 { |  | 
| 587         my ($found, $hit) = @_; |  | 
| 588 |  | 
| 589         if ($found == 0) { |  | 
| 590                 return 10000; |  | 
| 591         } |  | 
| 592         return int($hit * 1000 / $found) * 10 + 2 - (1 / $found); |  | 
| 593 } |  | 
| 594 |  | 
| 595 |  | 
| 596 # |  | 
| 597 # get_overall_line(found, hit, name_singular, name_plural) |  | 
| 598 # |  | 
| 599 # Return a string containing overall information for the specified |  | 
| 600 # found/hit data. |  | 
| 601 # |  | 
| 602 |  | 
| 603 sub get_overall_line($$$$) |  | 
| 604 { |  | 
| 605         my ($found, $hit, $name_sn, $name_pl) = @_; |  | 
| 606         my $name; |  | 
| 607 |  | 
| 608         return "no data found" if (!defined($found) || $found == 0); |  | 
| 609         $name = ($found == 1) ? $name_sn : $name_pl; |  | 
| 610         return sprintf("%.1f%% (%d of %d %s)", $hit * 100 / $found, $hit, |  | 
| 611                        $found, $name); |  | 
| 612 } |  | 
| 613 |  | 
| 614 |  | 
| 615 # |  | 
| 616 # print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do |  | 
| 617 #                    br_found, br_hit) |  | 
| 618 # |  | 
| 619 # Print overall coverage rates for the specified coverage types. |  | 
| 620 # |  | 
| 621 |  | 
| 622 sub print_overall_rate($$$$$$$$$) |  | 
| 623 { |  | 
| 624         my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit, |  | 
| 625             $br_do, $br_found, $br_hit) = @_; |  | 
| 626 |  | 
| 627         info("Overall coverage rate:\n"); |  | 
| 628         info("  lines......: %s\n", |  | 
| 629              get_overall_line($ln_found, $ln_hit, "line", "lines")) |  | 
| 630                 if ($ln_do); |  | 
| 631         info("  functions..: %s\n", |  | 
| 632              get_overall_line($fn_found, $fn_hit, "function", "functions")) |  | 
| 633                 if ($fn_do); |  | 
| 634         info("  branches...: %s\n", |  | 
| 635              get_overall_line($br_found, $br_hit, "branch", "branches")) |  | 
| 636                 if ($br_do); |  | 
| 637 } |  | 
| 638 |  | 
| 639 |  | 
| 640 # |  | 
| 641 # gen_html() |  | 
| 642 # |  | 
| 643 # Generate a set of HTML pages from contents of .info file INFO_FILENAME. |  | 
| 644 # Files will be written to the current directory. If provided, test case |  | 
| 645 # descriptions will be read from .tests file TEST_FILENAME and included |  | 
| 646 # in ouput. |  | 
| 647 # |  | 
| 648 # Die on error. |  | 
| 649 # |  | 
| 650 |  | 
| 651 sub gen_html() |  | 
| 652 { |  | 
| 653         local *HTML_HANDLE; |  | 
| 654         my %overview; |  | 
| 655         my %base_data; |  | 
| 656         my $lines_found; |  | 
| 657         my $lines_hit; |  | 
| 658         my $fn_found; |  | 
| 659         my $fn_hit; |  | 
| 660         my $br_found; |  | 
| 661         my $br_hit; |  | 
| 662         my $overall_found = 0; |  | 
| 663         my $overall_hit = 0; |  | 
| 664         my $total_fn_found = 0; |  | 
| 665         my $total_fn_hit = 0; |  | 
| 666         my $total_br_found = 0; |  | 
| 667         my $total_br_hit = 0; |  | 
| 668         my $dir_name; |  | 
| 669         my $link_name; |  | 
| 670         my @dir_list; |  | 
| 671         my %new_info; |  | 
| 672 |  | 
| 673         # Read in all specified .info files |  | 
| 674         foreach (@info_filenames) |  | 
| 675         { |  | 
| 676                 %new_info = %{read_info_file($_)}; |  | 
| 677 |  | 
| 678                 # Combine %new_info with %info_data |  | 
| 679                 %info_data = %{combine_info_files(\%info_data, \%new_info)}; |  | 
| 680         } |  | 
| 681 |  | 
| 682         info("Found %d entries.\n", scalar(keys(%info_data))); |  | 
| 683 |  | 
| 684         # Read and apply baseline data if specified |  | 
| 685         if ($base_filename) |  | 
| 686         { |  | 
| 687                 # Read baseline file |  | 
| 688                 info("Reading baseline file $base_filename\n"); |  | 
| 689                 %base_data = %{read_info_file($base_filename)}; |  | 
| 690                 info("Found %d entries.\n", scalar(keys(%base_data))); |  | 
| 691 |  | 
| 692                 # Apply baseline |  | 
| 693                 info("Subtracting baseline data.\n"); |  | 
| 694                 %info_data = %{apply_baseline(\%info_data, \%base_data)}; |  | 
| 695         } |  | 
| 696 |  | 
| 697         @dir_list = get_dir_list(keys(%info_data)); |  | 
| 698 |  | 
| 699         if ($no_prefix) |  | 
| 700         { |  | 
| 701                 # User requested that we leave filenames alone |  | 
| 702                 info("User asked not to remove filename prefix\n"); |  | 
| 703         } |  | 
| 704         elsif (!defined($dir_prefix)) |  | 
| 705         { |  | 
| 706                 # Get prefix common to most directories in list |  | 
| 707                 $dir_prefix = get_prefix(@dir_list); |  | 
| 708 |  | 
| 709                 if ($dir_prefix) |  | 
| 710                 { |  | 
| 711                         info("Found common filename prefix \"$dir_prefix\"\n"); |  | 
| 712                 } |  | 
| 713                 else |  | 
| 714                 { |  | 
| 715                         info("No common filename prefix found!\n"); |  | 
| 716                         $no_prefix=1; |  | 
| 717                 } |  | 
| 718         } |  | 
| 719         else |  | 
| 720         { |  | 
| 721                 info("Using user-specified filename prefix \"". |  | 
| 722                      "$dir_prefix\"\n"); |  | 
| 723         } |  | 
| 724 |  | 
| 725         # Read in test description file if specified |  | 
| 726         if ($desc_filename) |  | 
| 727         { |  | 
| 728                 info("Reading test description file $desc_filename\n"); |  | 
| 729                 %test_description = %{read_testfile($desc_filename)}; |  | 
| 730 |  | 
| 731                 # Remove test descriptions which are not referenced |  | 
| 732                 # from %info_data if user didn't tell us otherwise |  | 
| 733                 if (!$keep_descriptions) |  | 
| 734                 { |  | 
| 735                         remove_unused_descriptions(); |  | 
| 736                 } |  | 
| 737         } |  | 
| 738 |  | 
| 739         # Change to output directory if specified |  | 
| 740         if ($output_directory) |  | 
| 741         { |  | 
| 742                 chdir($output_directory) |  | 
| 743                         or die("ERROR: cannot change to directory ". |  | 
| 744                         "$output_directory!\n"); |  | 
| 745         } |  | 
| 746 |  | 
| 747         info("Writing .css and .png files.\n"); |  | 
| 748         write_css_file(); |  | 
| 749         write_png_files(); |  | 
| 750 |  | 
| 751         if ($html_gzip) |  | 
| 752         { |  | 
| 753                 info("Writing .htaccess file.\n"); |  | 
| 754                 write_htaccess_file(); |  | 
| 755         } |  | 
| 756 |  | 
| 757         info("Generating output.\n"); |  | 
| 758 |  | 
| 759         # Process each subdirectory and collect overview information |  | 
| 760         foreach $dir_name (@dir_list) |  | 
| 761         { |  | 
| 762                 ($lines_found, $lines_hit, $fn_found, $fn_hit, |  | 
| 763                  $br_found, $br_hit) |  | 
| 764                         = process_dir($dir_name); |  | 
| 765 |  | 
| 766                 # Remove prefix if applicable |  | 
| 767                 if (!$no_prefix && $dir_prefix) |  | 
| 768                 { |  | 
| 769                         # Match directory names beginning with $dir_prefix |  | 
| 770                         $dir_name = apply_prefix($dir_name, $dir_prefix); |  | 
| 771                 } |  | 
| 772 |  | 
| 773                 # Generate name for directory overview HTML page |  | 
| 774                 if ($dir_name =~ /^\/(.*)$/) |  | 
| 775                 { |  | 
| 776                         $link_name = substr($dir_name, 1)."/index.$html_ext"; |  | 
| 777                 } |  | 
| 778                 else |  | 
| 779                 { |  | 
| 780                         $link_name = $dir_name."/index.$html_ext"; |  | 
| 781                 } |  | 
| 782 |  | 
| 783                 $overview{$dir_name} = [$lines_found, $lines_hit, $fn_found, |  | 
| 784                                         $fn_hit, $br_found, $br_hit, $link_name, |  | 
| 785                                         get_rate($lines_found, $lines_hit), |  | 
| 786                                         get_rate($fn_found, $fn_hit), |  | 
| 787                                         get_rate($br_found, $br_hit)]; |  | 
| 788                 $overall_found  += $lines_found; |  | 
| 789                 $overall_hit    += $lines_hit; |  | 
| 790                 $total_fn_found += $fn_found; |  | 
| 791                 $total_fn_hit   += $fn_hit; |  | 
| 792                 $total_br_found += $br_found; |  | 
| 793                 $total_br_hit   += $br_hit; |  | 
| 794         } |  | 
| 795 |  | 
| 796         # Generate overview page |  | 
| 797         info("Writing directory view page.\n"); |  | 
| 798 |  | 
| 799         # Create sorted pages |  | 
| 800         foreach (@fileview_sortlist) { |  | 
| 801                 write_dir_page($fileview_sortname[$_], ".", "", $test_title, |  | 
| 802                                undef, $overall_found, $overall_hit, |  | 
| 803                                $total_fn_found, $total_fn_hit, $total_br_found, |  | 
| 804                                $total_br_hit, \%overview, {}, {}, {}, 0, $_); |  | 
| 805         } |  | 
| 806 |  | 
| 807         # Check if there are any test case descriptions to write out |  | 
| 808         if (%test_description) |  | 
| 809         { |  | 
| 810                 info("Writing test case description file.\n"); |  | 
| 811                 write_description_file( \%test_description, |  | 
| 812                                         $overall_found, $overall_hit, |  | 
| 813                                         $total_fn_found, $total_fn_hit, |  | 
| 814                                         $total_br_found, $total_br_hit); |  | 
| 815         } |  | 
| 816 |  | 
| 817         print_overall_rate(1, $overall_found, $overall_hit, |  | 
| 818                            $func_coverage, $total_fn_found, $total_fn_hit, |  | 
| 819                            $br_coverage, $total_br_found, $total_br_hit); |  | 
| 820 |  | 
| 821         chdir($cwd); |  | 
| 822 } |  | 
| 823 |  | 
| 824 # |  | 
| 825 # html_create(handle, filename) |  | 
| 826 # |  | 
| 827 |  | 
| 828 sub html_create($$) |  | 
| 829 { |  | 
| 830         my $handle = $_[0]; |  | 
| 831         my $filename = $_[1]; |  | 
| 832 |  | 
| 833         if ($html_gzip) |  | 
| 834         { |  | 
| 835                 open($handle, "|gzip -c >$filename") |  | 
| 836                         or die("ERROR: cannot open $filename for writing ". |  | 
| 837                                "(gzip)!\n"); |  | 
| 838         } |  | 
| 839         else |  | 
| 840         { |  | 
| 841                 open($handle, ">$filename") |  | 
| 842                         or die("ERROR: cannot open $filename for writing!\n"); |  | 
| 843         } |  | 
| 844 } |  | 
| 845 |  | 
| 846 sub write_dir_page($$$$$$$$$$$$$$$$$) |  | 
| 847 { |  | 
| 848         my ($name, $rel_dir, $base_dir, $title, $trunc_dir, $overall_found, |  | 
| 849             $overall_hit, $total_fn_found, $total_fn_hit, $total_br_found, |  | 
| 850             $total_br_hit, $overview, $testhash, $testfnchash, $testbrhash, |  | 
| 851             $view_type, $sort_type) = @_; |  | 
| 852 |  | 
| 853         # Generate directory overview page including details |  | 
| 854         html_create(*HTML_HANDLE, "$rel_dir/index$name.$html_ext"); |  | 
| 855         if (!defined($trunc_dir)) { |  | 
| 856                 $trunc_dir = ""; |  | 
| 857         } |  | 
| 858         write_html_prolog(*HTML_HANDLE, $base_dir, "LCOV - $title$trunc_dir"); |  | 
| 859         write_header(*HTML_HANDLE, $view_type, $trunc_dir, $rel_dir, |  | 
| 860                      $overall_found, $overall_hit, $total_fn_found, |  | 
| 861                      $total_fn_hit, $total_br_found, $total_br_hit, $sort_type); |  | 
| 862         write_file_table(*HTML_HANDLE, $base_dir, $overview, $testhash, |  | 
| 863                          $testfnchash, $testbrhash, $view_type, $sort_type); |  | 
| 864         write_html_epilog(*HTML_HANDLE, $base_dir); |  | 
| 865         close(*HTML_HANDLE); |  | 
| 866 } |  | 
| 867 |  | 
| 868 |  | 
| 869 # |  | 
| 870 # process_dir(dir_name) |  | 
| 871 # |  | 
| 872 |  | 
| 873 sub process_dir($) |  | 
| 874 { |  | 
| 875         my $abs_dir = $_[0]; |  | 
| 876         my $trunc_dir; |  | 
| 877         my $rel_dir = $abs_dir; |  | 
| 878         my $base_dir; |  | 
| 879         my $filename; |  | 
| 880         my %overview; |  | 
| 881         my $lines_found; |  | 
| 882         my $lines_hit; |  | 
| 883         my $fn_found; |  | 
| 884         my $fn_hit; |  | 
| 885         my $br_found; |  | 
| 886         my $br_hit; |  | 
| 887         my $overall_found=0; |  | 
| 888         my $overall_hit=0; |  | 
| 889         my $total_fn_found=0; |  | 
| 890         my $total_fn_hit=0; |  | 
| 891         my $total_br_found = 0; |  | 
| 892         my $total_br_hit = 0; |  | 
| 893         my $base_name; |  | 
| 894         my $extension; |  | 
| 895         my $testdata; |  | 
| 896         my %testhash; |  | 
| 897         my $testfncdata; |  | 
| 898         my %testfnchash; |  | 
| 899         my $testbrdata; |  | 
| 900         my %testbrhash; |  | 
| 901         my @sort_list; |  | 
| 902         local *HTML_HANDLE; |  | 
| 903 |  | 
| 904         # Remove prefix if applicable |  | 
| 905         if (!$no_prefix) |  | 
| 906         { |  | 
| 907                 # Match directory name beginning with $dir_prefix |  | 
| 908                 $rel_dir = apply_prefix($rel_dir, $dir_prefix); |  | 
| 909         } |  | 
| 910 |  | 
| 911         $trunc_dir = $rel_dir; |  | 
| 912 |  | 
| 913         # Remove leading / |  | 
| 914         if ($rel_dir =~ /^\/(.*)$/) |  | 
| 915         { |  | 
| 916                 $rel_dir = substr($rel_dir, 1); |  | 
| 917         } |  | 
| 918 |  | 
| 919         $base_dir = get_relative_base_path($rel_dir); |  | 
| 920 |  | 
| 921         create_sub_dir($rel_dir); |  | 
| 922 |  | 
| 923         # Match filenames which specify files in this directory, not including |  | 
| 924         # sub-directories |  | 
| 925         foreach $filename (grep(/^\Q$abs_dir\E\/[^\/]*$/,keys(%info_data))) |  | 
| 926         { |  | 
| 927                 my $page_link; |  | 
| 928                 my $func_link; |  | 
| 929 |  | 
| 930                 ($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found, |  | 
| 931                  $br_hit, $testdata, $testfncdata, $testbrdata) = |  | 
| 932                         process_file($trunc_dir, $rel_dir, $filename); |  | 
| 933 |  | 
| 934                 $base_name = basename($filename); |  | 
| 935 |  | 
| 936                 if ($no_sourceview) { |  | 
| 937                         $page_link = ""; |  | 
| 938                 } elsif ($frames) { |  | 
| 939                         # Link to frameset page |  | 
| 940                         $page_link = "$base_name.gcov.frameset.$html_ext"; |  | 
| 941                 } else { |  | 
| 942                         # Link directory to source code view page |  | 
| 943                         $page_link = "$base_name.gcov.$html_ext"; |  | 
| 944                 } |  | 
| 945                 $overview{$base_name} = [$lines_found, $lines_hit, $fn_found, |  | 
| 946                                          $fn_hit, $br_found, $br_hit, |  | 
| 947                                          $page_link, |  | 
| 948                                          get_rate($lines_found, $lines_hit), |  | 
| 949                                          get_rate($fn_found, $fn_hit), |  | 
| 950                                          get_rate($br_found, $br_hit)]; |  | 
| 951 |  | 
| 952                 $testhash{$base_name} = $testdata; |  | 
| 953                 $testfnchash{$base_name} = $testfncdata; |  | 
| 954                 $testbrhash{$base_name} = $testbrdata; |  | 
| 955 |  | 
| 956                 $overall_found  += $lines_found; |  | 
| 957                 $overall_hit    += $lines_hit; |  | 
| 958 |  | 
| 959                 $total_fn_found += $fn_found; |  | 
| 960                 $total_fn_hit   += $fn_hit; |  | 
| 961 |  | 
| 962                 $total_br_found += $br_found; |  | 
| 963                 $total_br_hit   += $br_hit; |  | 
| 964         } |  | 
| 965 |  | 
| 966         # Create sorted pages |  | 
| 967         foreach (@fileview_sortlist) { |  | 
| 968                 # Generate directory overview page (without details) |  | 
| 969                 write_dir_page($fileview_sortname[$_], $rel_dir, $base_dir, |  | 
| 970                                $test_title, $trunc_dir, $overall_found, |  | 
| 971                                $overall_hit, $total_fn_found, $total_fn_hit, |  | 
| 972                                $total_br_found, $total_br_hit, \%overview, {}, |  | 
| 973                                {}, {}, 1, $_); |  | 
| 974                 if (!$show_details) { |  | 
| 975                         next; |  | 
| 976                 } |  | 
| 977                 # Generate directory overview page including details |  | 
| 978                 write_dir_page("-detail".$fileview_sortname[$_], $rel_dir, |  | 
| 979                                $base_dir, $test_title, $trunc_dir, |  | 
| 980                                $overall_found, $overall_hit, $total_fn_found, |  | 
| 981                                $total_fn_hit, $total_br_found, $total_br_hit, |  | 
| 982                                \%overview, \%testhash, \%testfnchash, |  | 
| 983                                \%testbrhash, 1, $_); |  | 
| 984         } |  | 
| 985 |  | 
| 986         # Calculate resulting line counts |  | 
| 987         return ($overall_found, $overall_hit, $total_fn_found, $total_fn_hit, |  | 
| 988                 $total_br_found, $total_br_hit); |  | 
| 989 } |  | 
| 990 |  | 
| 991 |  | 
| 992 # |  | 
| 993 # get_converted_lines(testdata) |  | 
| 994 # |  | 
| 995 # Return hash of line numbers of those lines which were only covered in |  | 
| 996 # converted data sets. |  | 
| 997 # |  | 
| 998 |  | 
| 999 sub get_converted_lines($) |  | 
| 1000 { |  | 
| 1001         my $testdata = $_[0]; |  | 
| 1002         my $testcount; |  | 
| 1003         my %converted; |  | 
| 1004         my %nonconverted; |  | 
| 1005         my $hash; |  | 
| 1006         my $testcase; |  | 
| 1007         my $line; |  | 
| 1008         my %result; |  | 
| 1009 |  | 
| 1010 |  | 
| 1011         # Get a hash containing line numbers with positive counts both for |  | 
| 1012         # converted and original data sets |  | 
| 1013         foreach $testcase (keys(%{$testdata})) |  | 
| 1014         { |  | 
| 1015                 # Check to see if this is a converted data set |  | 
| 1016                 if ($testcase =~ /,diff$/) |  | 
| 1017                 { |  | 
| 1018                         $hash = \%converted; |  | 
| 1019                 } |  | 
| 1020                 else |  | 
| 1021                 { |  | 
| 1022                         $hash = \%nonconverted; |  | 
| 1023                 } |  | 
| 1024 |  | 
| 1025                 $testcount = $testdata->{$testcase}; |  | 
| 1026                 # Add lines with a positive count to hash |  | 
| 1027                 foreach $line (keys%{$testcount}) |  | 
| 1028                 { |  | 
| 1029                         if ($testcount->{$line} > 0) |  | 
| 1030                         { |  | 
| 1031                                 $hash->{$line} = 1; |  | 
| 1032                         } |  | 
| 1033                 } |  | 
| 1034         } |  | 
| 1035 |  | 
| 1036         # Combine both hashes to resulting list |  | 
| 1037         foreach $line (keys(%converted)) |  | 
| 1038         { |  | 
| 1039                 if (!defined($nonconverted{$line})) |  | 
| 1040                 { |  | 
| 1041                         $result{$line} = 1; |  | 
| 1042                 } |  | 
| 1043         } |  | 
| 1044 |  | 
| 1045         return \%result; |  | 
| 1046 } |  | 
| 1047 |  | 
| 1048 |  | 
| 1049 sub write_function_page($$$$$$$$$$$$$$$$$$) |  | 
| 1050 { |  | 
| 1051         my ($base_dir, $rel_dir, $trunc_dir, $base_name, $title, |  | 
| 1052             $lines_found, $lines_hit, $fn_found, $fn_hit, $br_found, $br_hit, |  | 
| 1053             $sumcount, $funcdata, $sumfnccount, $testfncdata, $sumbrcount, |  | 
| 1054             $testbrdata, $sort_type) = @_; |  | 
| 1055         my $pagetitle; |  | 
| 1056         my $filename; |  | 
| 1057 |  | 
| 1058         # Generate function table for this file |  | 
| 1059         if ($sort_type == 0) { |  | 
| 1060                 $filename = "$rel_dir/$base_name.func.$html_ext"; |  | 
| 1061         } else { |  | 
| 1062                 $filename = "$rel_dir/$base_name.func-sort-c.$html_ext"; |  | 
| 1063         } |  | 
| 1064         html_create(*HTML_HANDLE, $filename); |  | 
| 1065         $pagetitle = "LCOV - $title - $trunc_dir/$base_name - functions"; |  | 
| 1066         write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle); |  | 
| 1067         write_header(*HTML_HANDLE, 4, "$trunc_dir/$base_name", |  | 
| 1068                      "$rel_dir/$base_name", $lines_found, $lines_hit, |  | 
| 1069                      $fn_found, $fn_hit, $br_found, $br_hit, $sort_type); |  | 
| 1070         write_function_table(*HTML_HANDLE, "$base_name.gcov.$html_ext", |  | 
| 1071                              $sumcount, $funcdata, |  | 
| 1072                              $sumfnccount, $testfncdata, $sumbrcount, |  | 
| 1073                              $testbrdata, $base_name, |  | 
| 1074                              $base_dir, $sort_type); |  | 
| 1075         write_html_epilog(*HTML_HANDLE, $base_dir, 1); |  | 
| 1076         close(*HTML_HANDLE); |  | 
| 1077 } |  | 
| 1078 |  | 
| 1079 |  | 
| 1080 # |  | 
| 1081 # process_file(trunc_dir, rel_dir, filename) |  | 
| 1082 # |  | 
| 1083 |  | 
| 1084 sub process_file($$$) |  | 
| 1085 { |  | 
| 1086         info("Processing file ".apply_prefix($_[2], $dir_prefix)."\n"); |  | 
| 1087 |  | 
| 1088         my $trunc_dir = $_[0]; |  | 
| 1089         my $rel_dir = $_[1]; |  | 
| 1090         my $filename = $_[2]; |  | 
| 1091         my $base_name = basename($filename); |  | 
| 1092         my $base_dir = get_relative_base_path($rel_dir); |  | 
| 1093         my $testdata; |  | 
| 1094         my $testcount; |  | 
| 1095         my $sumcount; |  | 
| 1096         my $funcdata; |  | 
| 1097         my $checkdata; |  | 
| 1098         my $testfncdata; |  | 
| 1099         my $sumfnccount; |  | 
| 1100         my $testbrdata; |  | 
| 1101         my $sumbrcount; |  | 
| 1102         my $lines_found; |  | 
| 1103         my $lines_hit; |  | 
| 1104         my $fn_found; |  | 
| 1105         my $fn_hit; |  | 
| 1106         my $br_found; |  | 
| 1107         my $br_hit; |  | 
| 1108         my $converted; |  | 
| 1109         my @source; |  | 
| 1110         my $pagetitle; |  | 
| 1111         local *HTML_HANDLE; |  | 
| 1112 |  | 
| 1113         ($testdata, $sumcount, $funcdata, $checkdata, $testfncdata, |  | 
| 1114          $sumfnccount, $testbrdata, $sumbrcount, $lines_found, $lines_hit, |  | 
| 1115          $fn_found, $fn_hit, $br_found, $br_hit) |  | 
| 1116                 = get_info_entry($info_data{$filename}); |  | 
| 1117 |  | 
| 1118         # Return after this point in case user asked us not to generate |  | 
| 1119         # source code view |  | 
| 1120         if ($no_sourceview) |  | 
| 1121         { |  | 
| 1122                 return ($lines_found, $lines_hit, $fn_found, $fn_hit, |  | 
| 1123                         $br_found, $br_hit, $testdata, $testfncdata, |  | 
| 1124                         $testbrdata); |  | 
| 1125         } |  | 
| 1126 |  | 
| 1127         $converted = get_converted_lines($testdata); |  | 
| 1128         # Generate source code view for this file |  | 
| 1129         html_create(*HTML_HANDLE, "$rel_dir/$base_name.gcov.$html_ext"); |  | 
| 1130         $pagetitle = "LCOV - $test_title - $trunc_dir/$base_name"; |  | 
| 1131         write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle); |  | 
| 1132         write_header(*HTML_HANDLE, 2, "$trunc_dir/$base_name", |  | 
| 1133                      "$rel_dir/$base_name", $lines_found, $lines_hit, |  | 
| 1134                      $fn_found, $fn_hit, $br_found, $br_hit, 0); |  | 
| 1135         @source = write_source(*HTML_HANDLE, $filename, $sumcount, $checkdata, |  | 
| 1136                                $converted, $funcdata, $sumbrcount); |  | 
| 1137 |  | 
| 1138         write_html_epilog(*HTML_HANDLE, $base_dir, 1); |  | 
| 1139         close(*HTML_HANDLE); |  | 
| 1140 |  | 
| 1141         if ($func_coverage) { |  | 
| 1142                 # Create function tables |  | 
| 1143                 foreach (@funcview_sortlist) { |  | 
| 1144                         write_function_page($base_dir, $rel_dir, $trunc_dir, |  | 
| 1145                                             $base_name, $test_title, |  | 
| 1146                                             $lines_found, $lines_hit, |  | 
| 1147                                             $fn_found, $fn_hit, $br_found, |  | 
| 1148                                             $br_hit, $sumcount, |  | 
| 1149                                             $funcdata, $sumfnccount, |  | 
| 1150                                             $testfncdata, $sumbrcount, |  | 
| 1151                                             $testbrdata, $_); |  | 
| 1152                 } |  | 
| 1153         } |  | 
| 1154 |  | 
| 1155         # Additional files are needed in case of frame output |  | 
| 1156         if (!$frames) |  | 
| 1157         { |  | 
| 1158                 return ($lines_found, $lines_hit, $fn_found, $fn_hit, |  | 
| 1159                         $br_found, $br_hit, $testdata, $testfncdata, |  | 
| 1160                         $testbrdata); |  | 
| 1161         } |  | 
| 1162 |  | 
| 1163         # Create overview png file |  | 
| 1164         gen_png("$rel_dir/$base_name.gcov.png", $overview_width, $tab_size, |  | 
| 1165                 @source); |  | 
| 1166 |  | 
| 1167         # Create frameset page |  | 
| 1168         html_create(*HTML_HANDLE, |  | 
| 1169                     "$rel_dir/$base_name.gcov.frameset.$html_ext"); |  | 
| 1170         write_frameset(*HTML_HANDLE, $base_dir, $base_name, $pagetitle); |  | 
| 1171         close(*HTML_HANDLE); |  | 
| 1172 |  | 
| 1173         # Write overview frame |  | 
| 1174         html_create(*HTML_HANDLE, |  | 
| 1175                     "$rel_dir/$base_name.gcov.overview.$html_ext"); |  | 
| 1176         write_overview(*HTML_HANDLE, $base_dir, $base_name, $pagetitle, |  | 
| 1177                        scalar(@source)); |  | 
| 1178         close(*HTML_HANDLE); |  | 
| 1179 |  | 
| 1180         return ($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found, |  | 
| 1181                 $br_hit, $testdata, $testfncdata, $testbrdata); |  | 
| 1182 } |  | 
| 1183 |  | 
| 1184 |  | 
| 1185 # |  | 
| 1186 # read_info_file(info_filename) |  | 
| 1187 # |  | 
| 1188 # Read in the contents of the .info file specified by INFO_FILENAME. Data will |  | 
| 1189 # be returned as a reference to a hash containing the following mappings: |  | 
| 1190 # |  | 
| 1191 # %result: for each filename found in file -> \%data |  | 
| 1192 # |  | 
| 1193 # %data: "test"  -> \%testdata |  | 
| 1194 #        "sum"   -> \%sumcount |  | 
| 1195 #        "func"  -> \%funcdata |  | 
| 1196 #        "found" -> $lines_found (number of instrumented lines found in file) |  | 
| 1197 #        "hit"   -> $lines_hit (number of executed lines in file) |  | 
| 1198 #        "check" -> \%checkdata |  | 
| 1199 #        "testfnc" -> \%testfncdata |  | 
| 1200 #        "sumfnc"  -> \%sumfnccount |  | 
| 1201 #        "testbr"  -> \%testbrdata |  | 
| 1202 #        "sumbr"   -> \%sumbrcount |  | 
| 1203 # |  | 
| 1204 # %testdata   : name of test affecting this file -> \%testcount |  | 
| 1205 # %testfncdata: name of test affecting this file -> \%testfnccount |  | 
| 1206 # %testbrdata:  name of test affecting this file -> \%testbrcount |  | 
| 1207 # |  | 
| 1208 # %testcount   : line number   -> execution count for a single test |  | 
| 1209 # %testfnccount: function name -> execution count for a single test |  | 
| 1210 # %testbrcount : line number   -> branch coverage data for a single test |  | 
| 1211 # %sumcount    : line number   -> execution count for all tests |  | 
| 1212 # %sumfnccount : function name -> execution count for all tests |  | 
| 1213 # %sumbrcount  : line number   -> branch coverage data for all tests |  | 
| 1214 # %funcdata    : function name -> line number |  | 
| 1215 # %checkdata   : line number   -> checksum of source code line |  | 
| 1216 # $brdata      : vector of items: block, branch, taken |  | 
| 1217 # |  | 
| 1218 # Note that .info file sections referring to the same file and test name |  | 
| 1219 # will automatically be combined by adding all execution counts. |  | 
| 1220 # |  | 
| 1221 # Note that if INFO_FILENAME ends with ".gz", it is assumed that the file |  | 
| 1222 # is compressed using GZIP. If available, GUNZIP will be used to decompress |  | 
| 1223 # this file. |  | 
| 1224 # |  | 
| 1225 # Die on error. |  | 
| 1226 # |  | 
| 1227 |  | 
| 1228 sub read_info_file($) |  | 
| 1229 { |  | 
| 1230         my $tracefile = $_[0];          # Name of tracefile |  | 
| 1231         my %result;                     # Resulting hash: file -> data |  | 
| 1232         my $data;                       # Data handle for current entry |  | 
| 1233         my $testdata;                   #       "             " |  | 
| 1234         my $testcount;                  #       "             " |  | 
| 1235         my $sumcount;                   #       "             " |  | 
| 1236         my $funcdata;                   #       "             " |  | 
| 1237         my $checkdata;                  #       "             " |  | 
| 1238         my $testfncdata; |  | 
| 1239         my $testfnccount; |  | 
| 1240         my $sumfnccount; |  | 
| 1241         my $testbrdata; |  | 
| 1242         my $testbrcount; |  | 
| 1243         my $sumbrcount; |  | 
| 1244         my $line;                       # Current line read from .info file |  | 
| 1245         my $testname;                   # Current test name |  | 
| 1246         my $filename;                   # Current filename |  | 
| 1247         my $hitcount;                   # Count for lines hit |  | 
| 1248         my $count;                      # Execution count of current line |  | 
| 1249         my $negative;                   # If set, warn about negative counts |  | 
| 1250         my $changed_testname;           # If set, warn about changed testname |  | 
| 1251         my $line_checksum;              # Checksum of current line |  | 
| 1252         my $br_found; |  | 
| 1253         my $br_hit; |  | 
| 1254         local *INFO_HANDLE;             # Filehandle for .info file |  | 
| 1255 |  | 
| 1256         info("Reading data file $tracefile\n"); |  | 
| 1257 |  | 
| 1258         # Check if file exists and is readable |  | 
| 1259         stat($_[0]); |  | 
| 1260         if (!(-r _)) |  | 
| 1261         { |  | 
| 1262                 die("ERROR: cannot read file $_[0]!\n"); |  | 
| 1263         } |  | 
| 1264 |  | 
| 1265         # Check if this is really a plain file |  | 
| 1266         if (!(-f _)) |  | 
| 1267         { |  | 
| 1268                 die("ERROR: not a plain file: $_[0]!\n"); |  | 
| 1269         } |  | 
| 1270 |  | 
| 1271         # Check for .gz extension |  | 
| 1272         if ($_[0] =~ /\.gz$/) |  | 
| 1273         { |  | 
| 1274                 # Check for availability of GZIP tool |  | 
| 1275                 system_no_output(1, "gunzip" ,"-h") |  | 
| 1276                         and die("ERROR: gunzip command not available!\n"); |  | 
| 1277 |  | 
| 1278                 # Check integrity of compressed file |  | 
| 1279                 system_no_output(1, "gunzip", "-t", $_[0]) |  | 
| 1280                         and die("ERROR: integrity check failed for ". |  | 
| 1281                                 "compressed file $_[0]!\n"); |  | 
| 1282 |  | 
| 1283                 # Open compressed file |  | 
| 1284                 open(INFO_HANDLE, "gunzip -c $_[0]|") |  | 
| 1285                         or die("ERROR: cannot start gunzip to decompress ". |  | 
| 1286                                "file $_[0]!\n"); |  | 
| 1287         } |  | 
| 1288         else |  | 
| 1289         { |  | 
| 1290                 # Open decompressed file |  | 
| 1291                 open(INFO_HANDLE, $_[0]) |  | 
| 1292                         or die("ERROR: cannot read file $_[0]!\n"); |  | 
| 1293         } |  | 
| 1294 |  | 
| 1295         $testname = ""; |  | 
| 1296         while (<INFO_HANDLE>) |  | 
| 1297         { |  | 
| 1298                 chomp($_); |  | 
| 1299                 $line = $_; |  | 
| 1300 |  | 
| 1301                 # Switch statement |  | 
| 1302                 foreach ($line) |  | 
| 1303                 { |  | 
| 1304                         /^TN:([^,]*)(,diff)?/ && do |  | 
| 1305                         { |  | 
| 1306                                 # Test name information found |  | 
| 1307                                 $testname = defined($1) ? $1 : ""; |  | 
| 1308                                 if ($testname =~ s/\W/_/g) |  | 
| 1309                                 { |  | 
| 1310                                         $changed_testname = 1; |  | 
| 1311                                 } |  | 
| 1312                                 $testname .= $2 if (defined($2)); |  | 
| 1313                                 last; |  | 
| 1314                         }; |  | 
| 1315 |  | 
| 1316                         /^[SK]F:(.*)/ && do |  | 
| 1317                         { |  | 
| 1318                                 # Filename information found |  | 
| 1319                                 # Retrieve data for new entry |  | 
| 1320                                 $filename = $1; |  | 
| 1321 |  | 
| 1322                                 $data = $result{$filename}; |  | 
| 1323                                 ($testdata, $sumcount, $funcdata, $checkdata, |  | 
| 1324                                  $testfncdata, $sumfnccount, $testbrdata, |  | 
| 1325                                  $sumbrcount) = |  | 
| 1326                                         get_info_entry($data); |  | 
| 1327 |  | 
| 1328                                 if (defined($testname)) |  | 
| 1329                                 { |  | 
| 1330                                         $testcount = $testdata->{$testname}; |  | 
| 1331                                         $testfnccount = $testfncdata->{$testname
      }; |  | 
| 1332                                         $testbrcount = $testbrdata->{$testname}; |  | 
| 1333                                 } |  | 
| 1334                                 else |  | 
| 1335                                 { |  | 
| 1336                                         $testcount = {}; |  | 
| 1337                                         $testfnccount = {}; |  | 
| 1338                                         $testbrcount = {}; |  | 
| 1339                                 } |  | 
| 1340                                 last; |  | 
| 1341                         }; |  | 
| 1342 |  | 
| 1343                         /^DA:(\d+),(-?\d+)(,[^,\s]+)?/ && do |  | 
| 1344                         { |  | 
| 1345                                 # Fix negative counts |  | 
| 1346                                 $count = $2 < 0 ? 0 : $2; |  | 
| 1347                                 if ($2 < 0) |  | 
| 1348                                 { |  | 
| 1349                                         $negative = 1; |  | 
| 1350                                 } |  | 
| 1351                                 # Execution count found, add to structure |  | 
| 1352                                 # Add summary counts |  | 
| 1353                                 $sumcount->{$1} += $count; |  | 
| 1354 |  | 
| 1355                                 # Add test-specific counts |  | 
| 1356                                 if (defined($testname)) |  | 
| 1357                                 { |  | 
| 1358                                         $testcount->{$1} += $count; |  | 
| 1359                                 } |  | 
| 1360 |  | 
| 1361                                 # Store line checksum if available |  | 
| 1362                                 if (defined($3)) |  | 
| 1363                                 { |  | 
| 1364                                         $line_checksum = substr($3, 1); |  | 
| 1365 |  | 
| 1366                                         # Does it match a previous definition |  | 
| 1367                                         if (defined($checkdata->{$1}) && |  | 
| 1368                                             ($checkdata->{$1} ne |  | 
| 1369                                              $line_checksum)) |  | 
| 1370                                         { |  | 
| 1371                                                 die("ERROR: checksum mismatch ". |  | 
| 1372                                                     "at $filename:$1\n"); |  | 
| 1373                                         } |  | 
| 1374 |  | 
| 1375                                         $checkdata->{$1} = $line_checksum; |  | 
| 1376                                 } |  | 
| 1377                                 last; |  | 
| 1378                         }; |  | 
| 1379 |  | 
| 1380                         /^FN:(\d+),([^,]+)/ && do |  | 
| 1381                         { |  | 
| 1382                                 # Function data found, add to structure |  | 
| 1383                                 $funcdata->{$2} = $1; |  | 
| 1384 |  | 
| 1385                                 # Also initialize function call data |  | 
| 1386                                 if (!defined($sumfnccount->{$2})) { |  | 
| 1387                                         $sumfnccount->{$2} = 0; |  | 
| 1388                                 } |  | 
| 1389                                 if (defined($testname)) |  | 
| 1390                                 { |  | 
| 1391                                         if (!defined($testfnccount->{$2})) { |  | 
| 1392                                                 $testfnccount->{$2} = 0; |  | 
| 1393                                         } |  | 
| 1394                                 } |  | 
| 1395                                 last; |  | 
| 1396                         }; |  | 
| 1397 |  | 
| 1398                         /^FNDA:(\d+),([^,]+)/ && do |  | 
| 1399                         { |  | 
| 1400                                 # Function call count found, add to structure |  | 
| 1401                                 # Add summary counts |  | 
| 1402                                 $sumfnccount->{$2} += $1; |  | 
| 1403 |  | 
| 1404                                 # Add test-specific counts |  | 
| 1405                                 if (defined($testname)) |  | 
| 1406                                 { |  | 
| 1407                                         $testfnccount->{$2} += $1; |  | 
| 1408                                 } |  | 
| 1409                                 last; |  | 
| 1410                         }; |  | 
| 1411 |  | 
| 1412                         /^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do { |  | 
| 1413                                 # Branch coverage data found |  | 
| 1414                                 my ($line, $block, $branch, $taken) = |  | 
| 1415                                    ($1, $2, $3, $4); |  | 
| 1416 |  | 
| 1417                                 $sumbrcount->{$line} = |  | 
| 1418                                         br_ivec_push($sumbrcount->{$line}, |  | 
| 1419                                                      $block, $branch, $taken); |  | 
| 1420 |  | 
| 1421                                 # Add test-specific counts |  | 
| 1422                                 if (defined($testname)) { |  | 
| 1423                                         $testbrcount->{$line} = |  | 
| 1424                                                 br_ivec_push( |  | 
| 1425                                                         $testbrcount->{$line}, |  | 
| 1426                                                         $block, $branch, |  | 
| 1427                                                         $taken); |  | 
| 1428                                 } |  | 
| 1429                                 last; |  | 
| 1430                         }; |  | 
| 1431 |  | 
| 1432                         /^end_of_record/ && do |  | 
| 1433                         { |  | 
| 1434                                 # Found end of section marker |  | 
| 1435                                 if ($filename) |  | 
| 1436                                 { |  | 
| 1437                                         # Store current section data |  | 
| 1438                                         if (defined($testname)) |  | 
| 1439                                         { |  | 
| 1440                                                 $testdata->{$testname} = |  | 
| 1441                                                         $testcount; |  | 
| 1442                                                 $testfncdata->{$testname} = |  | 
| 1443                                                         $testfnccount; |  | 
| 1444                                                 $testbrdata->{$testname} = |  | 
| 1445                                                         $testbrcount; |  | 
| 1446                                         } |  | 
| 1447 |  | 
| 1448                                         set_info_entry($data, $testdata, |  | 
| 1449                                                        $sumcount, $funcdata, |  | 
| 1450                                                        $checkdata, $testfncdata, |  | 
| 1451                                                        $sumfnccount, |  | 
| 1452                                                        $testbrdata, |  | 
| 1453                                                        $sumbrcount); |  | 
| 1454                                         $result{$filename} = $data; |  | 
| 1455                                         last; |  | 
| 1456                                 } |  | 
| 1457                         }; |  | 
| 1458 |  | 
| 1459                         # default |  | 
| 1460                         last; |  | 
| 1461                 } |  | 
| 1462         } |  | 
| 1463         close(INFO_HANDLE); |  | 
| 1464 |  | 
| 1465         # Calculate lines_found and lines_hit for each file |  | 
| 1466         foreach $filename (keys(%result)) |  | 
| 1467         { |  | 
| 1468                 $data = $result{$filename}; |  | 
| 1469 |  | 
| 1470                 ($testdata, $sumcount, undef, undef, $testfncdata, |  | 
| 1471                  $sumfnccount, $testbrdata, $sumbrcount) = |  | 
| 1472                         get_info_entry($data); |  | 
| 1473 |  | 
| 1474                 # Filter out empty files |  | 
| 1475                 if (scalar(keys(%{$sumcount})) == 0) |  | 
| 1476                 { |  | 
| 1477                         delete($result{$filename}); |  | 
| 1478                         next; |  | 
| 1479                 } |  | 
| 1480                 # Filter out empty test cases |  | 
| 1481                 foreach $testname (keys(%{$testdata})) |  | 
| 1482                 { |  | 
| 1483                         if (!defined($testdata->{$testname}) || |  | 
| 1484                             scalar(keys(%{$testdata->{$testname}})) == 0) |  | 
| 1485                         { |  | 
| 1486                                 delete($testdata->{$testname}); |  | 
| 1487                                 delete($testfncdata->{$testname}); |  | 
| 1488                         } |  | 
| 1489                 } |  | 
| 1490 |  | 
| 1491                 $data->{"found"} = scalar(keys(%{$sumcount})); |  | 
| 1492                 $hitcount = 0; |  | 
| 1493 |  | 
| 1494                 foreach (keys(%{$sumcount})) |  | 
| 1495                 { |  | 
| 1496                         if ($sumcount->{$_} > 0) { $hitcount++; } |  | 
| 1497                 } |  | 
| 1498 |  | 
| 1499                 $data->{"hit"} = $hitcount; |  | 
| 1500 |  | 
| 1501                 # Get found/hit values for function call data |  | 
| 1502                 $data->{"f_found"} = scalar(keys(%{$sumfnccount})); |  | 
| 1503                 $hitcount = 0; |  | 
| 1504 |  | 
| 1505                 foreach (keys(%{$sumfnccount})) { |  | 
| 1506                         if ($sumfnccount->{$_} > 0) { |  | 
| 1507                                 $hitcount++; |  | 
| 1508                         } |  | 
| 1509                 } |  | 
| 1510                 $data->{"f_hit"} = $hitcount; |  | 
| 1511 |  | 
| 1512                 # Get found/hit values for branch data |  | 
| 1513                 ($br_found, $br_hit) = get_br_found_and_hit($sumbrcount); |  | 
| 1514 |  | 
| 1515                 $data->{"b_found"} = $br_found; |  | 
| 1516                 $data->{"b_hit"} = $br_hit; |  | 
| 1517         } |  | 
| 1518 |  | 
| 1519         if (scalar(keys(%result)) == 0) |  | 
| 1520         { |  | 
| 1521                 die("ERROR: no valid records found in tracefile $tracefile\n"); |  | 
| 1522         } |  | 
| 1523         if ($negative) |  | 
| 1524         { |  | 
| 1525                 warn("WARNING: negative counts found in tracefile ". |  | 
| 1526                      "$tracefile\n"); |  | 
| 1527         } |  | 
| 1528         if ($changed_testname) |  | 
| 1529         { |  | 
| 1530                 warn("WARNING: invalid characters removed from testname in ". |  | 
| 1531                      "tracefile $tracefile\n"); |  | 
| 1532         } |  | 
| 1533 |  | 
| 1534         return(\%result); |  | 
| 1535 } |  | 
| 1536 |  | 
| 1537 |  | 
| 1538 # |  | 
| 1539 # get_info_entry(hash_ref) |  | 
| 1540 # |  | 
| 1541 # Retrieve data from an entry of the structure generated by read_info_file(). |  | 
| 1542 # Return a list of references to hashes: |  | 
| 1543 # (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash |  | 
| 1544 #  ref, testfncdata hash ref, sumfnccount hash ref, lines found, lines hit, |  | 
| 1545 #  functions found, functions hit) |  | 
| 1546 # |  | 
| 1547 |  | 
| 1548 sub get_info_entry($) |  | 
| 1549 { |  | 
| 1550         my $testdata_ref = $_[0]->{"test"}; |  | 
| 1551         my $sumcount_ref = $_[0]->{"sum"}; |  | 
| 1552         my $funcdata_ref = $_[0]->{"func"}; |  | 
| 1553         my $checkdata_ref = $_[0]->{"check"}; |  | 
| 1554         my $testfncdata = $_[0]->{"testfnc"}; |  | 
| 1555         my $sumfnccount = $_[0]->{"sumfnc"}; |  | 
| 1556         my $testbrdata = $_[0]->{"testbr"}; |  | 
| 1557         my $sumbrcount = $_[0]->{"sumbr"}; |  | 
| 1558         my $lines_found = $_[0]->{"found"}; |  | 
| 1559         my $lines_hit = $_[0]->{"hit"}; |  | 
| 1560         my $fn_found = $_[0]->{"f_found"}; |  | 
| 1561         my $fn_hit = $_[0]->{"f_hit"}; |  | 
| 1562         my $br_found = $_[0]->{"b_found"}; |  | 
| 1563         my $br_hit = $_[0]->{"b_hit"}; |  | 
| 1564 |  | 
| 1565         return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref, |  | 
| 1566                 $testfncdata, $sumfnccount, $testbrdata, $sumbrcount, |  | 
| 1567                 $lines_found, $lines_hit, $fn_found, $fn_hit, |  | 
| 1568                 $br_found, $br_hit); |  | 
| 1569 } |  | 
| 1570 |  | 
| 1571 |  | 
| 1572 # |  | 
| 1573 # set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref, |  | 
| 1574 #                checkdata_ref, testfncdata_ref, sumfcncount_ref, |  | 
| 1575 #                testbrdata_ref, sumbrcount_ref[,lines_found, |  | 
| 1576 #                lines_hit, f_found, f_hit, $b_found, $b_hit]) |  | 
| 1577 # |  | 
| 1578 # Update the hash referenced by HASH_REF with the provided data references. |  | 
| 1579 # |  | 
| 1580 |  | 
| 1581 sub set_info_entry($$$$$$$$$;$$$$$$) |  | 
| 1582 { |  | 
| 1583         my $data_ref = $_[0]; |  | 
| 1584 |  | 
| 1585         $data_ref->{"test"} = $_[1]; |  | 
| 1586         $data_ref->{"sum"} = $_[2]; |  | 
| 1587         $data_ref->{"func"} = $_[3]; |  | 
| 1588         $data_ref->{"check"} = $_[4]; |  | 
| 1589         $data_ref->{"testfnc"} = $_[5]; |  | 
| 1590         $data_ref->{"sumfnc"} = $_[6]; |  | 
| 1591         $data_ref->{"testbr"} = $_[7]; |  | 
| 1592         $data_ref->{"sumbr"} = $_[8]; |  | 
| 1593 |  | 
| 1594         if (defined($_[9])) { $data_ref->{"found"} = $_[9]; } |  | 
| 1595         if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; } |  | 
| 1596         if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; } |  | 
| 1597         if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; } |  | 
| 1598         if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; } |  | 
| 1599         if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; } |  | 
| 1600 } |  | 
| 1601 |  | 
| 1602 |  | 
| 1603 # |  | 
| 1604 # add_counts(data1_ref, data2_ref) |  | 
| 1605 # |  | 
| 1606 # DATA1_REF and DATA2_REF are references to hashes containing a mapping |  | 
| 1607 # |  | 
| 1608 #   line number -> execution count |  | 
| 1609 # |  | 
| 1610 # Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF |  | 
| 1611 # is a reference to a hash containing the combined mapping in which |  | 
| 1612 # execution counts are added. |  | 
| 1613 # |  | 
| 1614 |  | 
| 1615 sub add_counts($$) |  | 
| 1616 { |  | 
| 1617         my %data1 = %{$_[0]};   # Hash 1 |  | 
| 1618         my %data2 = %{$_[1]};   # Hash 2 |  | 
| 1619         my %result;             # Resulting hash |  | 
| 1620         my $line;               # Current line iteration scalar |  | 
| 1621         my $data1_count;        # Count of line in hash1 |  | 
| 1622         my $data2_count;        # Count of line in hash2 |  | 
| 1623         my $found = 0;          # Total number of lines found |  | 
| 1624         my $hit = 0;            # Number of lines with a count > 0 |  | 
| 1625 |  | 
| 1626         foreach $line (keys(%data1)) |  | 
| 1627         { |  | 
| 1628                 $data1_count = $data1{$line}; |  | 
| 1629                 $data2_count = $data2{$line}; |  | 
| 1630 |  | 
| 1631                 # Add counts if present in both hashes |  | 
| 1632                 if (defined($data2_count)) { $data1_count += $data2_count; } |  | 
| 1633 |  | 
| 1634                 # Store sum in %result |  | 
| 1635                 $result{$line} = $data1_count; |  | 
| 1636 |  | 
| 1637                 $found++; |  | 
| 1638                 if ($data1_count > 0) { $hit++; } |  | 
| 1639         } |  | 
| 1640 |  | 
| 1641         # Add lines unique to data2 |  | 
| 1642         foreach $line (keys(%data2)) |  | 
| 1643         { |  | 
| 1644                 # Skip lines already in data1 |  | 
| 1645                 if (defined($data1{$line})) { next; } |  | 
| 1646 |  | 
| 1647                 # Copy count from data2 |  | 
| 1648                 $result{$line} = $data2{$line}; |  | 
| 1649 |  | 
| 1650                 $found++; |  | 
| 1651                 if ($result{$line} > 0) { $hit++; } |  | 
| 1652         } |  | 
| 1653 |  | 
| 1654         return (\%result, $found, $hit); |  | 
| 1655 } |  | 
| 1656 |  | 
| 1657 |  | 
| 1658 # |  | 
| 1659 # merge_checksums(ref1, ref2, filename) |  | 
| 1660 # |  | 
| 1661 # REF1 and REF2 are references to hashes containing a mapping |  | 
| 1662 # |  | 
| 1663 #   line number -> checksum |  | 
| 1664 # |  | 
| 1665 # Merge checksum lists defined in REF1 and REF2 and return reference to |  | 
| 1666 # resulting hash. Die if a checksum for a line is defined in both hashes |  | 
| 1667 # but does not match. |  | 
| 1668 # |  | 
| 1669 |  | 
| 1670 sub merge_checksums($$$) |  | 
| 1671 { |  | 
| 1672         my $ref1 = $_[0]; |  | 
| 1673         my $ref2 = $_[1]; |  | 
| 1674         my $filename = $_[2]; |  | 
| 1675         my %result; |  | 
| 1676         my $line; |  | 
| 1677 |  | 
| 1678         foreach $line (keys(%{$ref1})) |  | 
| 1679         { |  | 
| 1680                 if (defined($ref2->{$line}) && |  | 
| 1681                     ($ref1->{$line} ne $ref2->{$line})) |  | 
| 1682                 { |  | 
| 1683                         die("ERROR: checksum mismatch at $filename:$line\n"); |  | 
| 1684                 } |  | 
| 1685                 $result{$line} = $ref1->{$line}; |  | 
| 1686         } |  | 
| 1687 |  | 
| 1688         foreach $line (keys(%{$ref2})) |  | 
| 1689         { |  | 
| 1690                 $result{$line} = $ref2->{$line}; |  | 
| 1691         } |  | 
| 1692 |  | 
| 1693         return \%result; |  | 
| 1694 } |  | 
| 1695 |  | 
| 1696 |  | 
| 1697 # |  | 
| 1698 # merge_func_data(funcdata1, funcdata2, filename) |  | 
| 1699 # |  | 
| 1700 |  | 
| 1701 sub merge_func_data($$$) |  | 
| 1702 { |  | 
| 1703         my ($funcdata1, $funcdata2, $filename) = @_; |  | 
| 1704         my %result; |  | 
| 1705         my $func; |  | 
| 1706 |  | 
| 1707         if (defined($funcdata1)) { |  | 
| 1708                 %result = %{$funcdata1}; |  | 
| 1709         } |  | 
| 1710 |  | 
| 1711         foreach $func (keys(%{$funcdata2})) { |  | 
| 1712                 my $line1 = $result{$func}; |  | 
| 1713                 my $line2 = $funcdata2->{$func}; |  | 
| 1714 |  | 
| 1715                 if (defined($line1) && ($line1 != $line2)) { |  | 
| 1716                         warn("WARNING: function data mismatch at ". |  | 
| 1717                              "$filename:$line2\n"); |  | 
| 1718                         next; |  | 
| 1719                 } |  | 
| 1720                 $result{$func} = $line2; |  | 
| 1721         } |  | 
| 1722 |  | 
| 1723         return \%result; |  | 
| 1724 } |  | 
| 1725 |  | 
| 1726 |  | 
| 1727 # |  | 
| 1728 # add_fnccount(fnccount1, fnccount2) |  | 
| 1729 # |  | 
| 1730 # Add function call count data. Return list (fnccount_added, f_found, f_hit) |  | 
| 1731 # |  | 
| 1732 |  | 
| 1733 sub add_fnccount($$) |  | 
| 1734 { |  | 
| 1735         my ($fnccount1, $fnccount2) = @_; |  | 
| 1736         my %result; |  | 
| 1737         my $fn_found; |  | 
| 1738         my $fn_hit; |  | 
| 1739         my $function; |  | 
| 1740 |  | 
| 1741         if (defined($fnccount1)) { |  | 
| 1742                 %result = %{$fnccount1}; |  | 
| 1743         } |  | 
| 1744         foreach $function (keys(%{$fnccount2})) { |  | 
| 1745                 $result{$function} += $fnccount2->{$function}; |  | 
| 1746         } |  | 
| 1747         $fn_found = scalar(keys(%result)); |  | 
| 1748         $fn_hit = 0; |  | 
| 1749         foreach $function (keys(%result)) { |  | 
| 1750                 if ($result{$function} > 0) { |  | 
| 1751                         $fn_hit++; |  | 
| 1752                 } |  | 
| 1753         } |  | 
| 1754 |  | 
| 1755         return (\%result, $fn_found, $fn_hit); |  | 
| 1756 } |  | 
| 1757 |  | 
| 1758 # |  | 
| 1759 # add_testfncdata(testfncdata1, testfncdata2) |  | 
| 1760 # |  | 
| 1761 # Add function call count data for several tests. Return reference to |  | 
| 1762 # added_testfncdata. |  | 
| 1763 # |  | 
| 1764 |  | 
| 1765 sub add_testfncdata($$) |  | 
| 1766 { |  | 
| 1767         my ($testfncdata1, $testfncdata2) = @_; |  | 
| 1768         my %result; |  | 
| 1769         my $testname; |  | 
| 1770 |  | 
| 1771         foreach $testname (keys(%{$testfncdata1})) { |  | 
| 1772                 if (defined($testfncdata2->{$testname})) { |  | 
| 1773                         my $fnccount; |  | 
| 1774 |  | 
| 1775                         # Function call count data for this testname exists |  | 
| 1776                         # in both data sets: add |  | 
| 1777                         ($fnccount) = add_fnccount( |  | 
| 1778                                 $testfncdata1->{$testname}, |  | 
| 1779                                 $testfncdata2->{$testname}); |  | 
| 1780                         $result{$testname} = $fnccount; |  | 
| 1781                         next; |  | 
| 1782                 } |  | 
| 1783                 # Function call count data for this testname is unique to |  | 
| 1784                 # data set 1: copy |  | 
| 1785                 $result{$testname} = $testfncdata1->{$testname}; |  | 
| 1786         } |  | 
| 1787 |  | 
| 1788         # Add count data for testnames unique to data set 2 |  | 
| 1789         foreach $testname (keys(%{$testfncdata2})) { |  | 
| 1790                 if (!defined($result{$testname})) { |  | 
| 1791                         $result{$testname} = $testfncdata2->{$testname}; |  | 
| 1792                 } |  | 
| 1793         } |  | 
| 1794         return \%result; |  | 
| 1795 } |  | 
| 1796 |  | 
| 1797 |  | 
| 1798 # |  | 
| 1799 # brcount_to_db(brcount) |  | 
| 1800 # |  | 
| 1801 # Convert brcount data to the following format: |  | 
| 1802 # |  | 
| 1803 # db:          line number    -> block hash |  | 
| 1804 # block hash:  block number   -> branch hash |  | 
| 1805 # branch hash: branch number  -> taken value |  | 
| 1806 # |  | 
| 1807 |  | 
| 1808 sub brcount_to_db($) |  | 
| 1809 { |  | 
| 1810         my ($brcount) = @_; |  | 
| 1811         my $line; |  | 
| 1812         my $db; |  | 
| 1813 |  | 
| 1814         # Add branches from first count to database |  | 
| 1815         foreach $line (keys(%{$brcount})) { |  | 
| 1816                 my $brdata = $brcount->{$line}; |  | 
| 1817                 my $i; |  | 
| 1818                 my $num = br_ivec_len($brdata); |  | 
| 1819 |  | 
| 1820                 for ($i = 0; $i < $num; $i++) { |  | 
| 1821                         my ($block, $branch, $taken) = br_ivec_get($brdata, $i); |  | 
| 1822 |  | 
| 1823                         $db->{$line}->{$block}->{$branch} = $taken; |  | 
| 1824                 } |  | 
| 1825         } |  | 
| 1826 |  | 
| 1827         return $db; |  | 
| 1828 } |  | 
| 1829 |  | 
| 1830 |  | 
| 1831 # |  | 
| 1832 # db_to_brcount(db) |  | 
| 1833 # |  | 
| 1834 # Convert branch coverage data back to brcount format. |  | 
| 1835 # |  | 
| 1836 |  | 
| 1837 sub db_to_brcount($) |  | 
| 1838 { |  | 
| 1839         my ($db) = @_; |  | 
| 1840         my $line; |  | 
| 1841         my $brcount = {}; |  | 
| 1842         my $br_found = 0; |  | 
| 1843         my $br_hit = 0; |  | 
| 1844 |  | 
| 1845         # Convert database back to brcount format |  | 
| 1846         foreach $line (sort({$a <=> $b} keys(%{$db}))) { |  | 
| 1847                 my $ldata = $db->{$line}; |  | 
| 1848                 my $brdata; |  | 
| 1849                 my $block; |  | 
| 1850 |  | 
| 1851                 foreach $block (sort({$a <=> $b} keys(%{$ldata}))) { |  | 
| 1852                         my $bdata = $ldata->{$block}; |  | 
| 1853                         my $branch; |  | 
| 1854 |  | 
| 1855                         foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) { |  | 
| 1856                                 my $taken = $bdata->{$branch}; |  | 
| 1857 |  | 
| 1858                                 $br_found++; |  | 
| 1859                                 $br_hit++ if ($taken ne "-" && $taken > 0); |  | 
| 1860                                 $brdata = br_ivec_push($brdata, $block, |  | 
| 1861                                                        $branch, $taken); |  | 
| 1862                         } |  | 
| 1863                 } |  | 
| 1864                 $brcount->{$line} = $brdata; |  | 
| 1865         } |  | 
| 1866 |  | 
| 1867         return ($brcount, $br_found, $br_hit); |  | 
| 1868 } |  | 
| 1869 |  | 
| 1870 |  | 
| 1871 # |  | 
| 1872 # combine_brcount(brcount1, brcount2, type) |  | 
| 1873 # |  | 
| 1874 # If add is BR_ADD, add branch coverage data and return list (brcount_added, |  | 
| 1875 # br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2 |  | 
| 1876 # from brcount1 and return (brcount_sub, br_found, br_hit). |  | 
| 1877 # |  | 
| 1878 |  | 
| 1879 sub combine_brcount($$$) |  | 
| 1880 { |  | 
| 1881         my ($brcount1, $brcount2, $type) = @_; |  | 
| 1882         my $line; |  | 
| 1883         my $block; |  | 
| 1884         my $branch; |  | 
| 1885         my $taken; |  | 
| 1886         my $db; |  | 
| 1887         my $br_found = 0; |  | 
| 1888         my $br_hit = 0; |  | 
| 1889         my $result; |  | 
| 1890 |  | 
| 1891         # Convert branches from first count to database |  | 
| 1892         $db = brcount_to_db($brcount1); |  | 
| 1893         # Combine values from database and second count |  | 
| 1894         foreach $line (keys(%{$brcount2})) { |  | 
| 1895                 my $brdata = $brcount2->{$line}; |  | 
| 1896                 my $num = br_ivec_len($brdata); |  | 
| 1897                 my $i; |  | 
| 1898 |  | 
| 1899                 for ($i = 0; $i < $num; $i++) { |  | 
| 1900                         ($block, $branch, $taken) = br_ivec_get($brdata, $i); |  | 
| 1901                         my $new_taken = $db->{$line}->{$block}->{$branch}; |  | 
| 1902 |  | 
| 1903                         if ($type == $BR_ADD) { |  | 
| 1904                                 $new_taken = br_taken_add($new_taken, $taken); |  | 
| 1905                         } elsif ($type == $BR_SUB) { |  | 
| 1906                                 $new_taken = br_taken_sub($new_taken, $taken); |  | 
| 1907                         } |  | 
| 1908                         $db->{$line}->{$block}->{$branch} = $new_taken |  | 
| 1909                                 if (defined($new_taken)); |  | 
| 1910                 } |  | 
| 1911         } |  | 
| 1912         # Convert database back to brcount format |  | 
| 1913         ($result, $br_found, $br_hit) = db_to_brcount($db); |  | 
| 1914 |  | 
| 1915         return ($result, $br_found, $br_hit); |  | 
| 1916 } |  | 
| 1917 |  | 
| 1918 |  | 
| 1919 # |  | 
| 1920 # add_testbrdata(testbrdata1, testbrdata2) |  | 
| 1921 # |  | 
| 1922 # Add branch coverage data for several tests. Return reference to |  | 
| 1923 # added_testbrdata. |  | 
| 1924 # |  | 
| 1925 |  | 
| 1926 sub add_testbrdata($$) |  | 
| 1927 { |  | 
| 1928         my ($testbrdata1, $testbrdata2) = @_; |  | 
| 1929         my %result; |  | 
| 1930         my $testname; |  | 
| 1931 |  | 
| 1932         foreach $testname (keys(%{$testbrdata1})) { |  | 
| 1933                 if (defined($testbrdata2->{$testname})) { |  | 
| 1934                         my $brcount; |  | 
| 1935 |  | 
| 1936                         # Branch coverage data for this testname exists |  | 
| 1937                         # in both data sets: add |  | 
| 1938                         ($brcount) = combine_brcount($testbrdata1->{$testname}, |  | 
| 1939                                          $testbrdata2->{$testname}, $BR_ADD); |  | 
| 1940                         $result{$testname} = $brcount; |  | 
| 1941                         next; |  | 
| 1942                 } |  | 
| 1943                 # Branch coverage data for this testname is unique to |  | 
| 1944                 # data set 1: copy |  | 
| 1945                 $result{$testname} = $testbrdata1->{$testname}; |  | 
| 1946         } |  | 
| 1947 |  | 
| 1948         # Add count data for testnames unique to data set 2 |  | 
| 1949         foreach $testname (keys(%{$testbrdata2})) { |  | 
| 1950                 if (!defined($result{$testname})) { |  | 
| 1951                         $result{$testname} = $testbrdata2->{$testname}; |  | 
| 1952                 } |  | 
| 1953         } |  | 
| 1954         return \%result; |  | 
| 1955 } |  | 
| 1956 |  | 
| 1957 |  | 
| 1958 # |  | 
| 1959 # combine_info_entries(entry_ref1, entry_ref2, filename) |  | 
| 1960 # |  | 
| 1961 # Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2. |  | 
| 1962 # Return reference to resulting hash. |  | 
| 1963 # |  | 
| 1964 |  | 
| 1965 sub combine_info_entries($$$) |  | 
| 1966 { |  | 
| 1967         my $entry1 = $_[0];     # Reference to hash containing first entry |  | 
| 1968         my $testdata1; |  | 
| 1969         my $sumcount1; |  | 
| 1970         my $funcdata1; |  | 
| 1971         my $checkdata1; |  | 
| 1972         my $testfncdata1; |  | 
| 1973         my $sumfnccount1; |  | 
| 1974         my $testbrdata1; |  | 
| 1975         my $sumbrcount1; |  | 
| 1976 |  | 
| 1977         my $entry2 = $_[1];     # Reference to hash containing second entry |  | 
| 1978         my $testdata2; |  | 
| 1979         my $sumcount2; |  | 
| 1980         my $funcdata2; |  | 
| 1981         my $checkdata2; |  | 
| 1982         my $testfncdata2; |  | 
| 1983         my $sumfnccount2; |  | 
| 1984         my $testbrdata2; |  | 
| 1985         my $sumbrcount2; |  | 
| 1986 |  | 
| 1987         my %result;             # Hash containing combined entry |  | 
| 1988         my %result_testdata; |  | 
| 1989         my $result_sumcount = {}; |  | 
| 1990         my $result_funcdata; |  | 
| 1991         my $result_testfncdata; |  | 
| 1992         my $result_sumfnccount; |  | 
| 1993         my $result_testbrdata; |  | 
| 1994         my $result_sumbrcount; |  | 
| 1995         my $lines_found; |  | 
| 1996         my $lines_hit; |  | 
| 1997         my $fn_found; |  | 
| 1998         my $fn_hit; |  | 
| 1999         my $br_found; |  | 
| 2000         my $br_hit; |  | 
| 2001 |  | 
| 2002         my $testname; |  | 
| 2003         my $filename = $_[2]; |  | 
| 2004 |  | 
| 2005         # Retrieve data |  | 
| 2006         ($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1, |  | 
| 2007          $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1); |  | 
| 2008         ($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2, |  | 
| 2009          $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2); |  | 
| 2010 |  | 
| 2011         # Merge checksums |  | 
| 2012         $checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename); |  | 
| 2013 |  | 
| 2014         # Combine funcdata |  | 
| 2015         $result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename); |  | 
| 2016 |  | 
| 2017         # Combine function call count data |  | 
| 2018         $result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2); |  | 
| 2019         ($result_sumfnccount, $fn_found, $fn_hit) = |  | 
| 2020                 add_fnccount($sumfnccount1, $sumfnccount2); |  | 
| 2021 |  | 
| 2022         # Combine branch coverage data |  | 
| 2023         $result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2); |  | 
| 2024         ($result_sumbrcount, $br_found, $br_hit) = |  | 
| 2025                 combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD); |  | 
| 2026 |  | 
| 2027         # Combine testdata |  | 
| 2028         foreach $testname (keys(%{$testdata1})) |  | 
| 2029         { |  | 
| 2030                 if (defined($testdata2->{$testname})) |  | 
| 2031                 { |  | 
| 2032                         # testname is present in both entries, requires |  | 
| 2033                         # combination |  | 
| 2034                         ($result_testdata{$testname}) = |  | 
| 2035                                 add_counts($testdata1->{$testname}, |  | 
| 2036                                            $testdata2->{$testname}); |  | 
| 2037                 } |  | 
| 2038                 else |  | 
| 2039                 { |  | 
| 2040                         # testname only present in entry1, add to result |  | 
| 2041                         $result_testdata{$testname} = $testdata1->{$testname}; |  | 
| 2042                 } |  | 
| 2043 |  | 
| 2044                 # update sum count hash |  | 
| 2045                 ($result_sumcount, $lines_found, $lines_hit) = |  | 
| 2046                         add_counts($result_sumcount, |  | 
| 2047                                    $result_testdata{$testname}); |  | 
| 2048         } |  | 
| 2049 |  | 
| 2050         foreach $testname (keys(%{$testdata2})) |  | 
| 2051         { |  | 
| 2052                 # Skip testnames already covered by previous iteration |  | 
| 2053                 if (defined($testdata1->{$testname})) { next; } |  | 
| 2054 |  | 
| 2055                 # testname only present in entry2, add to result hash |  | 
| 2056                 $result_testdata{$testname} = $testdata2->{$testname}; |  | 
| 2057 |  | 
| 2058                 # update sum count hash |  | 
| 2059                 ($result_sumcount, $lines_found, $lines_hit) = |  | 
| 2060                         add_counts($result_sumcount, |  | 
| 2061                                    $result_testdata{$testname}); |  | 
| 2062         } |  | 
| 2063 |  | 
| 2064         # Calculate resulting sumcount |  | 
| 2065 |  | 
| 2066         # Store result |  | 
| 2067         set_info_entry(\%result, \%result_testdata, $result_sumcount, |  | 
| 2068                        $result_funcdata, $checkdata1, $result_testfncdata, |  | 
| 2069                        $result_sumfnccount, $result_testbrdata, |  | 
| 2070                        $result_sumbrcount, $lines_found, $lines_hit, |  | 
| 2071                        $fn_found, $fn_hit, $br_found, $br_hit); |  | 
| 2072 |  | 
| 2073         return(\%result); |  | 
| 2074 } |  | 
| 2075 |  | 
| 2076 |  | 
| 2077 # |  | 
| 2078 # combine_info_files(info_ref1, info_ref2) |  | 
| 2079 # |  | 
| 2080 # Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return |  | 
| 2081 # reference to resulting hash. |  | 
| 2082 # |  | 
| 2083 |  | 
| 2084 sub combine_info_files($$) |  | 
| 2085 { |  | 
| 2086         my %hash1 = %{$_[0]}; |  | 
| 2087         my %hash2 = %{$_[1]}; |  | 
| 2088         my $filename; |  | 
| 2089 |  | 
| 2090         foreach $filename (keys(%hash2)) |  | 
| 2091         { |  | 
| 2092                 if ($hash1{$filename}) |  | 
| 2093                 { |  | 
| 2094                         # Entry already exists in hash1, combine them |  | 
| 2095                         $hash1{$filename} = |  | 
| 2096                                 combine_info_entries($hash1{$filename}, |  | 
| 2097                                                      $hash2{$filename}, |  | 
| 2098                                                      $filename); |  | 
| 2099                 } |  | 
| 2100                 else |  | 
| 2101                 { |  | 
| 2102                         # Entry is unique in both hashes, simply add to |  | 
| 2103                         # resulting hash |  | 
| 2104                         $hash1{$filename} = $hash2{$filename}; |  | 
| 2105                 } |  | 
| 2106         } |  | 
| 2107 |  | 
| 2108         return(\%hash1); |  | 
| 2109 } |  | 
| 2110 |  | 
| 2111 |  | 
| 2112 # |  | 
| 2113 # get_prefix(filename_list) |  | 
| 2114 # |  | 
| 2115 # Search FILENAME_LIST for a directory prefix which is common to as many |  | 
| 2116 # list entries as possible, so that removing this prefix will minimize the |  | 
| 2117 # sum of the lengths of all resulting shortened filenames. |  | 
| 2118 # |  | 
| 2119 |  | 
| 2120 sub get_prefix(@) |  | 
| 2121 { |  | 
| 2122         my @filename_list = @_;         # provided list of filenames |  | 
| 2123         my %prefix;                     # mapping: prefix -> sum of lengths |  | 
| 2124         my $current;                    # Temporary iteration variable |  | 
| 2125 |  | 
| 2126         # Find list of prefixes |  | 
| 2127         foreach (@filename_list) |  | 
| 2128         { |  | 
| 2129                 # Need explicit assignment to get a copy of $_ so that |  | 
| 2130                 # shortening the contained prefix does not affect the list |  | 
| 2131                 $current = shorten_prefix($_); |  | 
| 2132                 while ($current = shorten_prefix($current)) |  | 
| 2133                 { |  | 
| 2134                         # Skip rest if the remaining prefix has already been |  | 
| 2135                         # added to hash |  | 
| 2136                         if ($prefix{$current}) { last; } |  | 
| 2137 |  | 
| 2138                         # Initialize with 0 |  | 
| 2139                         $prefix{$current}="0"; |  | 
| 2140                 } |  | 
| 2141 |  | 
| 2142         } |  | 
| 2143 |  | 
| 2144         # Calculate sum of lengths for all prefixes |  | 
| 2145         foreach $current (keys(%prefix)) |  | 
| 2146         { |  | 
| 2147                 foreach (@filename_list) |  | 
| 2148                 { |  | 
| 2149                         # Add original length |  | 
| 2150                         $prefix{$current} += length($_); |  | 
| 2151 |  | 
| 2152                         # Check whether prefix matches |  | 
| 2153                         if (substr($_, 0, length($current)) eq $current) |  | 
| 2154                         { |  | 
| 2155                                 # Subtract prefix length for this filename |  | 
| 2156                                 $prefix{$current} -= length($current); |  | 
| 2157                         } |  | 
| 2158                 } |  | 
| 2159         } |  | 
| 2160 |  | 
| 2161         # Find and return prefix with minimal sum |  | 
| 2162         $current = (keys(%prefix))[0]; |  | 
| 2163 |  | 
| 2164         foreach (keys(%prefix)) |  | 
| 2165         { |  | 
| 2166                 if ($prefix{$_} < $prefix{$current}) |  | 
| 2167                 { |  | 
| 2168                         $current = $_; |  | 
| 2169                 } |  | 
| 2170         } |  | 
| 2171 |  | 
| 2172         return($current); |  | 
| 2173 } |  | 
| 2174 |  | 
| 2175 |  | 
| 2176 # |  | 
| 2177 # shorten_prefix(prefix) |  | 
| 2178 # |  | 
| 2179 # Return PREFIX shortened by last directory component. |  | 
| 2180 # |  | 
| 2181 |  | 
| 2182 sub shorten_prefix($) |  | 
| 2183 { |  | 
| 2184         my @list = split("/", $_[0]); |  | 
| 2185 |  | 
| 2186         pop(@list); |  | 
| 2187         return join("/", @list); |  | 
| 2188 } |  | 
| 2189 |  | 
| 2190 |  | 
| 2191 |  | 
| 2192 # |  | 
| 2193 # get_dir_list(filename_list) |  | 
| 2194 # |  | 
| 2195 # Return sorted list of directories for each entry in given FILENAME_LIST. |  | 
| 2196 # |  | 
| 2197 |  | 
| 2198 sub get_dir_list(@) |  | 
| 2199 { |  | 
| 2200         my %result; |  | 
| 2201 |  | 
| 2202         foreach (@_) |  | 
| 2203         { |  | 
| 2204                 $result{shorten_prefix($_)} = ""; |  | 
| 2205         } |  | 
| 2206 |  | 
| 2207         return(sort(keys(%result))); |  | 
| 2208 } |  | 
| 2209 |  | 
| 2210 |  | 
| 2211 # |  | 
| 2212 # get_relative_base_path(subdirectory) |  | 
| 2213 # |  | 
| 2214 # Return a relative path string which references the base path when applied |  | 
| 2215 # in SUBDIRECTORY. |  | 
| 2216 # |  | 
| 2217 # Example: get_relative_base_path("fs/mm") -> "../../" |  | 
| 2218 # |  | 
| 2219 |  | 
| 2220 sub get_relative_base_path($) |  | 
| 2221 { |  | 
| 2222         my $result = ""; |  | 
| 2223         my $index; |  | 
| 2224 |  | 
| 2225         # Make an empty directory path a special case |  | 
| 2226         if (!$_[0]) { return(""); } |  | 
| 2227 |  | 
| 2228         # Count number of /s in path |  | 
| 2229         $index = ($_[0] =~ s/\//\//g); |  | 
| 2230 |  | 
| 2231         # Add a ../ to $result for each / in the directory path + 1 |  | 
| 2232         for (; $index>=0; $index--) |  | 
| 2233         { |  | 
| 2234                 $result .= "../"; |  | 
| 2235         } |  | 
| 2236 |  | 
| 2237         return $result; |  | 
| 2238 } |  | 
| 2239 |  | 
| 2240 |  | 
| 2241 # |  | 
| 2242 # read_testfile(test_filename) |  | 
| 2243 # |  | 
| 2244 # Read in file TEST_FILENAME which contains test descriptions in the format: |  | 
| 2245 # |  | 
| 2246 #   TN:<whitespace><test name> |  | 
| 2247 #   TD:<whitespace><test description> |  | 
| 2248 # |  | 
| 2249 # for each test case. Return a reference to a hash containing a mapping |  | 
| 2250 # |  | 
| 2251 #   test name -> test description. |  | 
| 2252 # |  | 
| 2253 # Die on error. |  | 
| 2254 # |  | 
| 2255 |  | 
| 2256 sub read_testfile($) |  | 
| 2257 { |  | 
| 2258         my %result; |  | 
| 2259         my $test_name; |  | 
| 2260         my $changed_testname; |  | 
| 2261         local *TEST_HANDLE; |  | 
| 2262 |  | 
| 2263         open(TEST_HANDLE, "<".$_[0]) |  | 
| 2264                 or die("ERROR: cannot open $_[0]!\n"); |  | 
| 2265 |  | 
| 2266         while (<TEST_HANDLE>) |  | 
| 2267         { |  | 
| 2268                 chomp($_); |  | 
| 2269 |  | 
| 2270                 # Match lines beginning with TN:<whitespace(s)> |  | 
| 2271                 if (/^TN:\s+(.*?)\s*$/) |  | 
| 2272                 { |  | 
| 2273                         # Store name for later use |  | 
| 2274                         $test_name = $1; |  | 
| 2275                         if ($test_name =~ s/\W/_/g) |  | 
| 2276                         { |  | 
| 2277                                 $changed_testname = 1; |  | 
| 2278                         } |  | 
| 2279                 } |  | 
| 2280 |  | 
| 2281                 # Match lines beginning with TD:<whitespace(s)> |  | 
| 2282                 if (/^TD:\s+(.*?)\s*$/) |  | 
| 2283                 { |  | 
| 2284                         # Check for empty line |  | 
| 2285                         if ($1) |  | 
| 2286                         { |  | 
| 2287                                 # Add description to hash |  | 
| 2288                                 $result{$test_name} .= " $1"; |  | 
| 2289                         } |  | 
| 2290                         else |  | 
| 2291                         { |  | 
| 2292                                 # Add empty line |  | 
| 2293                                 $result{$test_name} .= "\n\n"; |  | 
| 2294                         } |  | 
| 2295                 } |  | 
| 2296         } |  | 
| 2297 |  | 
| 2298         close(TEST_HANDLE); |  | 
| 2299 |  | 
| 2300         if ($changed_testname) |  | 
| 2301         { |  | 
| 2302                 warn("WARNING: invalid characters removed from testname in ". |  | 
| 2303                      "descriptions file $_[0]\n"); |  | 
| 2304         } |  | 
| 2305 |  | 
| 2306         return \%result; |  | 
| 2307 } |  | 
| 2308 |  | 
| 2309 |  | 
| 2310 # |  | 
| 2311 # escape_html(STRING) |  | 
| 2312 # |  | 
| 2313 # Return a copy of STRING in which all occurrences of HTML special characters |  | 
| 2314 # are escaped. |  | 
| 2315 # |  | 
| 2316 |  | 
| 2317 sub escape_html($) |  | 
| 2318 { |  | 
| 2319         my $string = $_[0]; |  | 
| 2320 |  | 
| 2321         if (!$string) { return ""; } |  | 
| 2322 |  | 
| 2323         $string =~ s/&/&/g;         # & -> & |  | 
| 2324         $string =~ s/</</g;          # < -> < |  | 
| 2325         $string =~ s/>/>/g;          # > -> > |  | 
| 2326         $string =~ s/\"/"/g;       # " -> " |  | 
| 2327 |  | 
| 2328         while ($string =~ /^([^\t]*)(\t)/) |  | 
| 2329         { |  | 
| 2330                 my $replacement = " "x($tab_size - (length($1) % $tab_size)); |  | 
| 2331                 $string =~ s/^([^\t]*)(\t)/$1$replacement/; |  | 
| 2332         } |  | 
| 2333 |  | 
| 2334         $string =~ s/\n/<br>/g;         # \n -> <br> |  | 
| 2335 |  | 
| 2336         return $string; |  | 
| 2337 } |  | 
| 2338 |  | 
| 2339 |  | 
| 2340 # |  | 
| 2341 # get_date_string() |  | 
| 2342 # |  | 
| 2343 # Return the current date in the form: yyyy-mm-dd |  | 
| 2344 # |  | 
| 2345 |  | 
| 2346 sub get_date_string() |  | 
| 2347 { |  | 
| 2348         my $year; |  | 
| 2349         my $month; |  | 
| 2350         my $day; |  | 
| 2351 |  | 
| 2352         ($year, $month, $day) = (localtime())[5, 4, 3]; |  | 
| 2353 |  | 
| 2354         return sprintf("%d-%02d-%02d", $year+1900, $month+1, $day); |  | 
| 2355 } |  | 
| 2356 |  | 
| 2357 |  | 
| 2358 # |  | 
| 2359 # create_sub_dir(dir_name) |  | 
| 2360 # |  | 
| 2361 # Create subdirectory DIR_NAME if it does not already exist, including all its |  | 
| 2362 # parent directories. |  | 
| 2363 # |  | 
| 2364 # Die on error. |  | 
| 2365 # |  | 
| 2366 |  | 
| 2367 sub create_sub_dir($) |  | 
| 2368 { |  | 
| 2369         my ($dir) = @_; |  | 
| 2370 |  | 
| 2371         system("mkdir", "-p" ,$dir) |  | 
| 2372                 and die("ERROR: cannot create directory $dir!\n"); |  | 
| 2373 } |  | 
| 2374 |  | 
| 2375 |  | 
| 2376 # |  | 
| 2377 # write_description_file(descriptions, overall_found, overall_hit, |  | 
| 2378 #                        total_fn_found, total_fn_hit, total_br_found, |  | 
| 2379 #                        total_br_hit) |  | 
| 2380 # |  | 
| 2381 # Write HTML file containing all test case descriptions. DESCRIPTIONS is a |  | 
| 2382 # reference to a hash containing a mapping |  | 
| 2383 # |  | 
| 2384 #   test case name -> test case description |  | 
| 2385 # |  | 
| 2386 # Die on error. |  | 
| 2387 # |  | 
| 2388 |  | 
| 2389 sub write_description_file($$$$$$$) |  | 
| 2390 { |  | 
| 2391         my %description = %{$_[0]}; |  | 
| 2392         my $found = $_[1]; |  | 
| 2393         my $hit = $_[2]; |  | 
| 2394         my $fn_found = $_[3]; |  | 
| 2395         my $fn_hit = $_[4]; |  | 
| 2396         my $br_found = $_[5]; |  | 
| 2397         my $br_hit = $_[6]; |  | 
| 2398         my $test_name; |  | 
| 2399         local *HTML_HANDLE; |  | 
| 2400 |  | 
| 2401         html_create(*HTML_HANDLE,"descriptions.$html_ext"); |  | 
| 2402         write_html_prolog(*HTML_HANDLE, "", "LCOV - test case descriptions"); |  | 
| 2403         write_header(*HTML_HANDLE, 3, "", "", $found, $hit, $fn_found, |  | 
| 2404                      $fn_hit, $br_found, $br_hit, 0); |  | 
| 2405 |  | 
| 2406         write_test_table_prolog(*HTML_HANDLE, |  | 
| 2407                          "Test case descriptions - alphabetical list"); |  | 
| 2408 |  | 
| 2409         foreach $test_name (sort(keys(%description))) |  | 
| 2410         { |  | 
| 2411                 write_test_table_entry(*HTML_HANDLE, $test_name, |  | 
| 2412                                        escape_html($description{$test_name})); |  | 
| 2413         } |  | 
| 2414 |  | 
| 2415         write_test_table_epilog(*HTML_HANDLE); |  | 
| 2416         write_html_epilog(*HTML_HANDLE, ""); |  | 
| 2417 |  | 
| 2418         close(*HTML_HANDLE); |  | 
| 2419 } |  | 
| 2420 |  | 
| 2421 |  | 
| 2422 |  | 
| 2423 # |  | 
| 2424 # write_png_files() |  | 
| 2425 # |  | 
| 2426 # Create all necessary .png files for the HTML-output in the current |  | 
| 2427 # directory. .png-files are used as bar graphs. |  | 
| 2428 # |  | 
| 2429 # Die on error. |  | 
| 2430 # |  | 
| 2431 |  | 
| 2432 sub write_png_files() |  | 
| 2433 { |  | 
| 2434         my %data; |  | 
| 2435         local *PNG_HANDLE; |  | 
| 2436 |  | 
| 2437         $data{"ruby.png"} = |  | 
| 2438                 [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, |  | 
| 2439                  0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, |  | 
| 2440                  0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, |  | 
| 2441                  0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, |  | 
| 2442                  0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x18, 0x10, 0x5d, 0x57, |  | 
| 2443                  0x34, 0x6e, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, |  | 
| 2444                  0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, |  | 
| 2445                  0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, |  | 
| 2446                  0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, |  | 
| 2447                  0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x35, 0x2f, |  | 
| 2448                  0x00, 0x00, 0x00, 0xd0, 0x33, 0x9a, 0x9d, 0x00, 0x00, 0x00, |  | 
| 2449                  0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, |  | 
| 2450                  0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, |  | 
| 2451                  0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, |  | 
| 2452                  0x82]; |  | 
| 2453         $data{"amber.png"} = |  | 
| 2454                 [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, |  | 
| 2455                  0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, |  | 
| 2456                  0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, |  | 
| 2457                  0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, |  | 
| 2458                  0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x28, 0x04, 0x98, 0xcb, |  | 
| 2459                  0xd6, 0xe0, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, |  | 
| 2460                  0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, |  | 
| 2461                  0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, |  | 
| 2462                  0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, |  | 
| 2463                  0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xe0, 0x50, |  | 
| 2464                  0x00, 0x00, 0x00, 0xa2, 0x7a, 0xda, 0x7e, 0x00, 0x00, 0x00, |  | 
| 2465                  0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, |  | 
| 2466                  0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, |  | 
| 2467                  0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, |  | 
| 2468                  0x82]; |  | 
| 2469         $data{"emerald.png"} = |  | 
| 2470                 [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, |  | 
| 2471                  0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, |  | 
| 2472                  0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, |  | 
| 2473                  0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, |  | 
| 2474                  0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x22, 0x2b, 0xc9, 0xf5, |  | 
| 2475                  0x03, 0x33, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, |  | 
| 2476                  0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, |  | 
| 2477                  0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, |  | 
| 2478                  0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, |  | 
| 2479                  0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0xea, 0x59, |  | 
| 2480                  0x0a, 0x0a, 0x0a, 0x0f, 0xba, 0x50, 0x83, 0x00, 0x00, 0x00, |  | 
| 2481                  0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, |  | 
| 2482                  0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, |  | 
| 2483                  0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, |  | 
| 2484                  0x82]; |  | 
| 2485         $data{"snow.png"} = |  | 
| 2486                 [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, |  | 
| 2487                  0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, |  | 
| 2488                  0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, |  | 
| 2489                  0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, |  | 
| 2490                  0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x1e, 0x1d, 0x75, 0xbc, |  | 
| 2491                  0xef, 0x55, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, |  | 
| 2492                  0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, |  | 
| 2493                  0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, |  | 
| 2494                  0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, |  | 
| 2495                  0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, |  | 
| 2496                  0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, |  | 
| 2497                  0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, |  | 
| 2498                  0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, |  | 
| 2499                  0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, |  | 
| 2500                  0x82]; |  | 
| 2501         $data{"glass.png"} = |  | 
| 2502                 [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, |  | 
| 2503                  0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, |  | 
| 2504                  0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, |  | 
| 2505                  0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, |  | 
| 2506                  0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, |  | 
| 2507                  0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, |  | 
| 2508                  0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, |  | 
| 2509                  0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, |  | 
| 2510                  0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x88, |  | 
| 2511                  0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, |  | 
| 2512                  0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, |  | 
| 2513                  0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, |  | 
| 2514                  0x4d, 0x45, 0x07, 0xd2, 0x07, 0x13, 0x0f, 0x08, 0x19, 0xc4, |  | 
| 2515                  0x40, 0x56, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, |  | 
| 2516                  0x54, 0x78, 0x9c, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, |  | 
| 2517                  0x01, 0x48, 0xaf, 0xa4, 0x71, 0x00, 0x00, 0x00, 0x00, 0x49, |  | 
| 2518                  0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82]; |  | 
| 2519         $data{"updown.png"} = |  | 
| 2520                 [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, |  | 
| 2521                  0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0a, |  | 
| 2522                  0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x00, 0x16, |  | 
| 2523                  0xa3, 0x8d, 0xab, 0x00, 0x00, 0x00, 0x3c, 0x49, 0x44, 0x41, |  | 
| 2524                  0x54, 0x28, 0xcf, 0x63, 0x60, 0x40, 0x03, 0xff, 0xa1, 0x00, |  | 
| 2525                  0x5d, 0x9c, 0x11, 0x5d, 0x11, 0x8a, 0x24, 0x23, 0x23, 0x23, |  | 
| 2526                  0x86, 0x42, 0x6c, 0xa6, 0x20, 0x2b, 0x66, 0xc4, 0xa7, 0x08, |  | 
| 2527                  0x59, 0x31, 0x23, 0x21, 0x45, 0x30, 0xc0, 0xc4, 0x30, 0x60, |  | 
| 2528                  0x80, 0xfa, 0x6e, 0x24, 0x3e, 0x78, 0x48, 0x0a, 0x70, 0x62, |  | 
| 2529                  0xa2, 0x90, 0x81, 0xd8, 0x44, 0x01, 0x00, 0xe9, 0x5c, 0x2f, |  | 
| 2530                  0xf5, 0xe2, 0x9d, 0x0f, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x49, |  | 
| 2531                  0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] if ($sort); |  | 
| 2532         foreach (keys(%data)) |  | 
| 2533         { |  | 
| 2534                 open(PNG_HANDLE, ">".$_) |  | 
| 2535                         or die("ERROR: cannot create $_!\n"); |  | 
| 2536                 binmode(PNG_HANDLE); |  | 
| 2537                 print(PNG_HANDLE map(chr,@{$data{$_}})); |  | 
| 2538                 close(PNG_HANDLE); |  | 
| 2539         } |  | 
| 2540 } |  | 
| 2541 |  | 
| 2542 |  | 
| 2543 # |  | 
| 2544 # write_htaccess_file() |  | 
| 2545 # |  | 
| 2546 |  | 
| 2547 sub write_htaccess_file() |  | 
| 2548 { |  | 
| 2549         local *HTACCESS_HANDLE; |  | 
| 2550         my $htaccess_data; |  | 
| 2551 |  | 
| 2552         open(*HTACCESS_HANDLE, ">.htaccess") |  | 
| 2553                 or die("ERROR: cannot open .htaccess for writing!\n"); |  | 
| 2554 |  | 
| 2555         $htaccess_data = (<<"END_OF_HTACCESS") |  | 
| 2556 AddEncoding x-gzip .html |  | 
| 2557 END_OF_HTACCESS |  | 
| 2558         ; |  | 
| 2559 |  | 
| 2560         print(HTACCESS_HANDLE $htaccess_data); |  | 
| 2561         close(*HTACCESS_HANDLE); |  | 
| 2562 } |  | 
| 2563 |  | 
| 2564 |  | 
| 2565 # |  | 
| 2566 # write_css_file() |  | 
| 2567 # |  | 
| 2568 # Write the cascading style sheet file gcov.css to the current directory. |  | 
| 2569 # This file defines basic layout attributes of all generated HTML pages. |  | 
| 2570 # |  | 
| 2571 |  | 
| 2572 sub write_css_file() |  | 
| 2573 { |  | 
| 2574         local *CSS_HANDLE; |  | 
| 2575 |  | 
| 2576         # Check for a specified external style sheet file |  | 
| 2577         if ($css_filename) |  | 
| 2578         { |  | 
| 2579                 # Simply copy that file |  | 
| 2580                 system("cp", $css_filename, "gcov.css") |  | 
| 2581                         and die("ERROR: cannot copy file $css_filename!\n"); |  | 
| 2582                 return; |  | 
| 2583         } |  | 
| 2584 |  | 
| 2585         open(CSS_HANDLE, ">gcov.css") |  | 
| 2586                 or die ("ERROR: cannot open gcov.css for writing!\n"); |  | 
| 2587 |  | 
| 2588 |  | 
| 2589         # ************************************************************* |  | 
| 2590 |  | 
| 2591         my $css_data = ($_=<<"END_OF_CSS") |  | 
| 2592         /* All views: initial background and text color */ |  | 
| 2593         body |  | 
| 2594         { |  | 
| 2595           color: #000000; |  | 
| 2596           background-color: #FFFFFF; |  | 
| 2597         } |  | 
| 2598 |  | 
| 2599         /* All views: standard link format*/ |  | 
| 2600         a:link |  | 
| 2601         { |  | 
| 2602           color: #284FA8; |  | 
| 2603           text-decoration: underline; |  | 
| 2604         } |  | 
| 2605 |  | 
| 2606         /* All views: standard link - visited format */ |  | 
| 2607         a:visited |  | 
| 2608         { |  | 
| 2609           color: #00CB40; |  | 
| 2610           text-decoration: underline; |  | 
| 2611         } |  | 
| 2612 |  | 
| 2613         /* All views: standard link - activated format */ |  | 
| 2614         a:active |  | 
| 2615         { |  | 
| 2616           color: #FF0040; |  | 
| 2617           text-decoration: underline; |  | 
| 2618         } |  | 
| 2619 |  | 
| 2620         /* All views: main title format */ |  | 
| 2621         td.title |  | 
| 2622         { |  | 
| 2623           text-align: center; |  | 
| 2624           padding-bottom: 10px; |  | 
| 2625           font-family: sans-serif; |  | 
| 2626           font-size: 20pt; |  | 
| 2627           font-style: italic; |  | 
| 2628           font-weight: bold; |  | 
| 2629         } |  | 
| 2630 |  | 
| 2631         /* All views: header item format */ |  | 
| 2632         td.headerItem |  | 
| 2633         { |  | 
| 2634           text-align: right; |  | 
| 2635           padding-right: 6px; |  | 
| 2636           font-family: sans-serif; |  | 
| 2637           font-weight: bold; |  | 
| 2638           vertical-align: top; |  | 
| 2639           white-space: nowrap; |  | 
| 2640         } |  | 
| 2641 |  | 
| 2642         /* All views: header item value format */ |  | 
| 2643         td.headerValue |  | 
| 2644         { |  | 
| 2645           text-align: left; |  | 
| 2646           color: #284FA8; |  | 
| 2647           font-family: sans-serif; |  | 
| 2648           font-weight: bold; |  | 
| 2649           white-space: nowrap; |  | 
| 2650         } |  | 
| 2651 |  | 
| 2652         /* All views: header item coverage table heading */ |  | 
| 2653         td.headerCovTableHead |  | 
| 2654         { |  | 
| 2655           text-align: center; |  | 
| 2656           padding-right: 6px; |  | 
| 2657           padding-left: 6px; |  | 
| 2658           padding-bottom: 0px; |  | 
| 2659           font-family: sans-serif; |  | 
| 2660           font-size: 80%; |  | 
| 2661           white-space: nowrap; |  | 
| 2662         } |  | 
| 2663 |  | 
| 2664         /* All views: header item coverage table entry */ |  | 
| 2665         td.headerCovTableEntry |  | 
| 2666         { |  | 
| 2667           text-align: right; |  | 
| 2668           color: #284FA8; |  | 
| 2669           font-family: sans-serif; |  | 
| 2670           font-weight: bold; |  | 
| 2671           white-space: nowrap; |  | 
| 2672           padding-left: 12px; |  | 
| 2673           padding-right: 4px; |  | 
| 2674           background-color: #DAE7FE; |  | 
| 2675         } |  | 
| 2676 |  | 
| 2677         /* All views: header item coverage table entry for high coverage rate */ |  | 
| 2678         td.headerCovTableEntryHi |  | 
| 2679         { |  | 
| 2680           text-align: right; |  | 
| 2681           color: #000000; |  | 
| 2682           font-family: sans-serif; |  | 
| 2683           font-weight: bold; |  | 
| 2684           white-space: nowrap; |  | 
| 2685           padding-left: 12px; |  | 
| 2686           padding-right: 4px; |  | 
| 2687           background-color: #A7FC9D; |  | 
| 2688         } |  | 
| 2689 |  | 
| 2690         /* All views: header item coverage table entry for medium coverage rate 
      */ |  | 
| 2691         td.headerCovTableEntryMed |  | 
| 2692         { |  | 
| 2693           text-align: right; |  | 
| 2694           color: #000000; |  | 
| 2695           font-family: sans-serif; |  | 
| 2696           font-weight: bold; |  | 
| 2697           white-space: nowrap; |  | 
| 2698           padding-left: 12px; |  | 
| 2699           padding-right: 4px; |  | 
| 2700           background-color: #FFEA20; |  | 
| 2701         } |  | 
| 2702 |  | 
| 2703         /* All views: header item coverage table entry for ow coverage rate */ |  | 
| 2704         td.headerCovTableEntryLo |  | 
| 2705         { |  | 
| 2706           text-align: right; |  | 
| 2707           color: #000000; |  | 
| 2708           font-family: sans-serif; |  | 
| 2709           font-weight: bold; |  | 
| 2710           white-space: nowrap; |  | 
| 2711           padding-left: 12px; |  | 
| 2712           padding-right: 4px; |  | 
| 2713           background-color: #FF0000; |  | 
| 2714         } |  | 
| 2715 |  | 
| 2716         /* All views: header legend value for legend entry */ |  | 
| 2717         td.headerValueLeg |  | 
| 2718         { |  | 
| 2719           text-align: left; |  | 
| 2720           color: #000000; |  | 
| 2721           font-family: sans-serif; |  | 
| 2722           font-size: 80%; |  | 
| 2723           white-space: nowrap; |  | 
| 2724           padding-top: 4px; |  | 
| 2725         } |  | 
| 2726 |  | 
| 2727         /* All views: color of horizontal ruler */ |  | 
| 2728         td.ruler |  | 
| 2729         { |  | 
| 2730           background-color: #6688D4; |  | 
| 2731         } |  | 
| 2732 |  | 
| 2733         /* All views: version string format */ |  | 
| 2734         td.versionInfo |  | 
| 2735         { |  | 
| 2736           text-align: center; |  | 
| 2737           padding-top: 2px; |  | 
| 2738           font-family: sans-serif; |  | 
| 2739           font-style: italic; |  | 
| 2740         } |  | 
| 2741 |  | 
| 2742         /* Directory view/File view (all)/Test case descriptions: |  | 
| 2743            table headline format */ |  | 
| 2744         td.tableHead |  | 
| 2745         { |  | 
| 2746           text-align: center; |  | 
| 2747           color: #FFFFFF; |  | 
| 2748           background-color: #6688D4; |  | 
| 2749           font-family: sans-serif; |  | 
| 2750           font-size: 120%; |  | 
| 2751           font-weight: bold; |  | 
| 2752           white-space: nowrap; |  | 
| 2753           padding-left: 4px; |  | 
| 2754           padding-right: 4px; |  | 
| 2755         } |  | 
| 2756 |  | 
| 2757         span.tableHeadSort |  | 
| 2758         { |  | 
| 2759           padding-right: 4px; |  | 
| 2760         } |  | 
| 2761 |  | 
| 2762         /* Directory view/File view (all): filename entry format */ |  | 
| 2763         td.coverFile |  | 
| 2764         { |  | 
| 2765           text-align: left; |  | 
| 2766           padding-left: 10px; |  | 
| 2767           padding-right: 20px; |  | 
| 2768           color: #284FA8; |  | 
| 2769           background-color: #DAE7FE; |  | 
| 2770           font-family: monospace; |  | 
| 2771         } |  | 
| 2772 |  | 
| 2773         /* Directory view/File view (all): bar-graph entry format*/ |  | 
| 2774         td.coverBar |  | 
| 2775         { |  | 
| 2776           padding-left: 10px; |  | 
| 2777           padding-right: 10px; |  | 
| 2778           background-color: #DAE7FE; |  | 
| 2779         } |  | 
| 2780 |  | 
| 2781         /* Directory view/File view (all): bar-graph outline color */ |  | 
| 2782         td.coverBarOutline |  | 
| 2783         { |  | 
| 2784           background-color: #000000; |  | 
| 2785         } |  | 
| 2786 |  | 
| 2787         /* Directory view/File view (all): percentage entry for files with |  | 
| 2788            high coverage rate */ |  | 
| 2789         td.coverPerHi |  | 
| 2790         { |  | 
| 2791           text-align: right; |  | 
| 2792           padding-left: 10px; |  | 
| 2793           padding-right: 10px; |  | 
| 2794           background-color: #A7FC9D; |  | 
| 2795           font-weight: bold; |  | 
| 2796           font-family: sans-serif; |  | 
| 2797         } |  | 
| 2798 |  | 
| 2799         /* Directory view/File view (all): line count entry for files with |  | 
| 2800            high coverage rate */ |  | 
| 2801         td.coverNumHi |  | 
| 2802         { |  | 
| 2803           text-align: right; |  | 
| 2804           padding-left: 10px; |  | 
| 2805           padding-right: 10px; |  | 
| 2806           background-color: #A7FC9D; |  | 
| 2807           white-space: nowrap; |  | 
| 2808           font-family: sans-serif; |  | 
| 2809         } |  | 
| 2810 |  | 
| 2811         /* Directory view/File view (all): percentage entry for files with |  | 
| 2812            medium coverage rate */ |  | 
| 2813         td.coverPerMed |  | 
| 2814         { |  | 
| 2815           text-align: right; |  | 
| 2816           padding-left: 10px; |  | 
| 2817           padding-right: 10px; |  | 
| 2818           background-color: #FFEA20; |  | 
| 2819           font-weight: bold; |  | 
| 2820           font-family: sans-serif; |  | 
| 2821         } |  | 
| 2822 |  | 
| 2823         /* Directory view/File view (all): line count entry for files with |  | 
| 2824            medium coverage rate */ |  | 
| 2825         td.coverNumMed |  | 
| 2826         { |  | 
| 2827           text-align: right; |  | 
| 2828           padding-left: 10px; |  | 
| 2829           padding-right: 10px; |  | 
| 2830           background-color: #FFEA20; |  | 
| 2831           white-space: nowrap; |  | 
| 2832           font-family: sans-serif; |  | 
| 2833         } |  | 
| 2834 |  | 
| 2835         /* Directory view/File view (all): percentage entry for files with |  | 
| 2836            low coverage rate */ |  | 
| 2837         td.coverPerLo |  | 
| 2838         { |  | 
| 2839           text-align: right; |  | 
| 2840           padding-left: 10px; |  | 
| 2841           padding-right: 10px; |  | 
| 2842           background-color: #FF0000; |  | 
| 2843           font-weight: bold; |  | 
| 2844           font-family: sans-serif; |  | 
| 2845         } |  | 
| 2846 |  | 
| 2847         /* Directory view/File view (all): line count entry for files with |  | 
| 2848            low coverage rate */ |  | 
| 2849         td.coverNumLo |  | 
| 2850         { |  | 
| 2851           text-align: right; |  | 
| 2852           padding-left: 10px; |  | 
| 2853           padding-right: 10px; |  | 
| 2854           background-color: #FF0000; |  | 
| 2855           white-space: nowrap; |  | 
| 2856           font-family: sans-serif; |  | 
| 2857         } |  | 
| 2858 |  | 
| 2859         /* File view (all): "show/hide details" link format */ |  | 
| 2860         a.detail:link |  | 
| 2861         { |  | 
| 2862           color: #B8D0FF; |  | 
| 2863           font-size:80%; |  | 
| 2864         } |  | 
| 2865 |  | 
| 2866         /* File view (all): "show/hide details" link - visited format */ |  | 
| 2867         a.detail:visited |  | 
| 2868         { |  | 
| 2869           color: #B8D0FF; |  | 
| 2870           font-size:80%; |  | 
| 2871         } |  | 
| 2872 |  | 
| 2873         /* File view (all): "show/hide details" link - activated format */ |  | 
| 2874         a.detail:active |  | 
| 2875         { |  | 
| 2876           color: #FFFFFF; |  | 
| 2877           font-size:80%; |  | 
| 2878         } |  | 
| 2879 |  | 
| 2880         /* File view (detail): test name entry */ |  | 
| 2881         td.testName |  | 
| 2882         { |  | 
| 2883           text-align: right; |  | 
| 2884           padding-right: 10px; |  | 
| 2885           background-color: #DAE7FE; |  | 
| 2886           font-family: sans-serif; |  | 
| 2887         } |  | 
| 2888 |  | 
| 2889         /* File view (detail): test percentage entry */ |  | 
| 2890         td.testPer |  | 
| 2891         { |  | 
| 2892           text-align: right; |  | 
| 2893           padding-left: 10px; |  | 
| 2894           padding-right: 10px; |  | 
| 2895           background-color: #DAE7FE; |  | 
| 2896           font-family: sans-serif; |  | 
| 2897         } |  | 
| 2898 |  | 
| 2899         /* File view (detail): test lines count entry */ |  | 
| 2900         td.testNum |  | 
| 2901         { |  | 
| 2902           text-align: right; |  | 
| 2903           padding-left: 10px; |  | 
| 2904           padding-right: 10px; |  | 
| 2905           background-color: #DAE7FE; |  | 
| 2906           font-family: sans-serif; |  | 
| 2907         } |  | 
| 2908 |  | 
| 2909         /* Test case descriptions: test name format*/ |  | 
| 2910         dt |  | 
| 2911         { |  | 
| 2912           font-family: sans-serif; |  | 
| 2913           font-weight: bold; |  | 
| 2914         } |  | 
| 2915 |  | 
| 2916         /* Test case descriptions: description table body */ |  | 
| 2917         td.testDescription |  | 
| 2918         { |  | 
| 2919           padding-top: 10px; |  | 
| 2920           padding-left: 30px; |  | 
| 2921           padding-bottom: 10px; |  | 
| 2922           padding-right: 30px; |  | 
| 2923           background-color: #DAE7FE; |  | 
| 2924         } |  | 
| 2925 |  | 
| 2926         /* Source code view: function entry */ |  | 
| 2927         td.coverFn |  | 
| 2928         { |  | 
| 2929           text-align: left; |  | 
| 2930           padding-left: 10px; |  | 
| 2931           padding-right: 20px; |  | 
| 2932           color: #284FA8; |  | 
| 2933           background-color: #DAE7FE; |  | 
| 2934           font-family: monospace; |  | 
| 2935         } |  | 
| 2936 |  | 
| 2937         /* Source code view: function entry zero count*/ |  | 
| 2938         td.coverFnLo |  | 
| 2939         { |  | 
| 2940           text-align: right; |  | 
| 2941           padding-left: 10px; |  | 
| 2942           padding-right: 10px; |  | 
| 2943           background-color: #FF0000; |  | 
| 2944           font-weight: bold; |  | 
| 2945           font-family: sans-serif; |  | 
| 2946         } |  | 
| 2947 |  | 
| 2948         /* Source code view: function entry nonzero count*/ |  | 
| 2949         td.coverFnHi |  | 
| 2950         { |  | 
| 2951           text-align: right; |  | 
| 2952           padding-left: 10px; |  | 
| 2953           padding-right: 10px; |  | 
| 2954           background-color: #DAE7FE; |  | 
| 2955           font-weight: bold; |  | 
| 2956           font-family: sans-serif; |  | 
| 2957         } |  | 
| 2958 |  | 
| 2959         /* Source code view: source code format */ |  | 
| 2960         pre.source |  | 
| 2961         { |  | 
| 2962           font-family: monospace; |  | 
| 2963           white-space: pre; |  | 
| 2964           margin-top: 2px; |  | 
| 2965         } |  | 
| 2966 |  | 
| 2967         /* Source code view: line number format */ |  | 
| 2968         span.lineNum |  | 
| 2969         { |  | 
| 2970           background-color: #EFE383; |  | 
| 2971         } |  | 
| 2972 |  | 
| 2973         /* Source code view: format for lines which were executed */ |  | 
| 2974         td.lineCov, |  | 
| 2975         span.lineCov |  | 
| 2976         { |  | 
| 2977           background-color: #CAD7FE; |  | 
| 2978         } |  | 
| 2979 |  | 
| 2980         /* Source code view: format for Cov legend */ |  | 
| 2981         span.coverLegendCov |  | 
| 2982         { |  | 
| 2983           padding-left: 10px; |  | 
| 2984           padding-right: 10px; |  | 
| 2985           padding-bottom: 2px; |  | 
| 2986           background-color: #CAD7FE; |  | 
| 2987         } |  | 
| 2988 |  | 
| 2989         /* Source code view: format for lines which were not executed */ |  | 
| 2990         td.lineNoCov, |  | 
| 2991         span.lineNoCov |  | 
| 2992         { |  | 
| 2993           background-color: #FF6230; |  | 
| 2994         } |  | 
| 2995 |  | 
| 2996         /* Source code view: format for NoCov legend */ |  | 
| 2997         span.coverLegendNoCov |  | 
| 2998         { |  | 
| 2999           padding-left: 10px; |  | 
| 3000           padding-right: 10px; |  | 
| 3001           padding-bottom: 2px; |  | 
| 3002           background-color: #FF6230; |  | 
| 3003         } |  | 
| 3004 |  | 
| 3005         /* Source code view (function table): standard link - visited format */ |  | 
| 3006         td.lineNoCov > a:visited, |  | 
| 3007         td.lineCov > a:visited |  | 
| 3008         { |  | 
| 3009           color: black; |  | 
| 3010           text-decoration: underline; |  | 
| 3011         } |  | 
| 3012 |  | 
| 3013         /* Source code view: format for lines which were executed only in a |  | 
| 3014            previous version */ |  | 
| 3015         span.lineDiffCov |  | 
| 3016         { |  | 
| 3017           background-color: #B5F7AF; |  | 
| 3018         } |  | 
| 3019 |  | 
| 3020         /* Source code view: format for branches which were executed |  | 
| 3021          * and taken */ |  | 
| 3022         span.branchCov |  | 
| 3023         { |  | 
| 3024           background-color: #CAD7FE; |  | 
| 3025         } |  | 
| 3026 |  | 
| 3027         /* Source code view: format for branches which were executed |  | 
| 3028          * but not taken */ |  | 
| 3029         span.branchNoCov |  | 
| 3030         { |  | 
| 3031           background-color: #FF6230; |  | 
| 3032         } |  | 
| 3033 |  | 
| 3034         /* Source code view: format for branches which were not executed */ |  | 
| 3035         span.branchNoExec |  | 
| 3036         { |  | 
| 3037           background-color: #FF6230; |  | 
| 3038         } |  | 
| 3039 |  | 
| 3040         /* Source code view: format for the source code heading line */ |  | 
| 3041         pre.sourceHeading |  | 
| 3042         { |  | 
| 3043           white-space: pre; |  | 
| 3044           font-family: monospace; |  | 
| 3045           font-weight: bold; |  | 
| 3046           margin: 0px; |  | 
| 3047         } |  | 
| 3048 |  | 
| 3049         /* All views: header legend value for low rate */ |  | 
| 3050         td.headerValueLegL |  | 
| 3051         { |  | 
| 3052           font-family: sans-serif; |  | 
| 3053           text-align: center; |  | 
| 3054           white-space: nowrap; |  | 
| 3055           padding-left: 4px; |  | 
| 3056           padding-right: 2px; |  | 
| 3057           background-color: #FF0000; |  | 
| 3058           font-size: 80%; |  | 
| 3059         } |  | 
| 3060 |  | 
| 3061         /* All views: header legend value for med rate */ |  | 
| 3062         td.headerValueLegM |  | 
| 3063         { |  | 
| 3064           font-family: sans-serif; |  | 
| 3065           text-align: center; |  | 
| 3066           white-space: nowrap; |  | 
| 3067           padding-left: 2px; |  | 
| 3068           padding-right: 2px; |  | 
| 3069           background-color: #FFEA20; |  | 
| 3070           font-size: 80%; |  | 
| 3071         } |  | 
| 3072 |  | 
| 3073         /* All views: header legend value for hi rate */ |  | 
| 3074         td.headerValueLegH |  | 
| 3075         { |  | 
| 3076           font-family: sans-serif; |  | 
| 3077           text-align: center; |  | 
| 3078           white-space: nowrap; |  | 
| 3079           padding-left: 2px; |  | 
| 3080           padding-right: 4px; |  | 
| 3081           background-color: #A7FC9D; |  | 
| 3082           font-size: 80%; |  | 
| 3083         } |  | 
| 3084 |  | 
| 3085         /* All views except source code view: legend format for low coverage */ |  | 
| 3086         span.coverLegendCovLo |  | 
| 3087         { |  | 
| 3088           padding-left: 10px; |  | 
| 3089           padding-right: 10px; |  | 
| 3090           padding-top: 2px; |  | 
| 3091           background-color: #FF0000; |  | 
| 3092         } |  | 
| 3093 |  | 
| 3094         /* All views except source code view: legend format for med coverage */ |  | 
| 3095         span.coverLegendCovMed |  | 
| 3096         { |  | 
| 3097           padding-left: 10px; |  | 
| 3098           padding-right: 10px; |  | 
| 3099           padding-top: 2px; |  | 
| 3100           background-color: #FFEA20; |  | 
| 3101         } |  | 
| 3102 |  | 
| 3103         /* All views except source code view: legend format for hi coverage */ |  | 
| 3104         span.coverLegendCovHi |  | 
| 3105         { |  | 
| 3106           padding-left: 10px; |  | 
| 3107           padding-right: 10px; |  | 
| 3108           padding-top: 2px; |  | 
| 3109           background-color: #A7FC9D; |  | 
| 3110         } |  | 
| 3111 END_OF_CSS |  | 
| 3112         ; |  | 
| 3113 |  | 
| 3114         # ************************************************************* |  | 
| 3115 |  | 
| 3116 |  | 
| 3117         # Remove leading tab from all lines |  | 
| 3118         $css_data =~ s/^\t//gm; |  | 
| 3119 |  | 
| 3120         print(CSS_HANDLE $css_data); |  | 
| 3121 |  | 
| 3122         close(CSS_HANDLE); |  | 
| 3123 } |  | 
| 3124 |  | 
| 3125 |  | 
| 3126 # |  | 
| 3127 # get_bar_graph_code(base_dir, cover_found, cover_hit) |  | 
| 3128 # |  | 
| 3129 # Return a string containing HTML code which implements a bar graph display |  | 
| 3130 # for a coverage rate of cover_hit * 100 / cover_found. |  | 
| 3131 # |  | 
| 3132 |  | 
| 3133 sub get_bar_graph_code($$$) |  | 
| 3134 { |  | 
| 3135         my $rate; |  | 
| 3136         my $alt; |  | 
| 3137         my $width; |  | 
| 3138         my $remainder; |  | 
| 3139         my $png_name; |  | 
| 3140         my $graph_code; |  | 
| 3141 |  | 
| 3142         # Check number of instrumented lines |  | 
| 3143         if ($_[1] == 0) { return ""; } |  | 
| 3144 |  | 
| 3145         $rate           = $_[2] * 100 / $_[1]; |  | 
| 3146         $alt            = sprintf("%.1f", $rate)."%"; |  | 
| 3147         $width          = sprintf("%.0f", $rate); |  | 
| 3148         $remainder      = sprintf("%d", 100-$width); |  | 
| 3149 |  | 
| 3150         # Decide which .png file to use |  | 
| 3151         $png_name = $rate_png[classify_rate($_[1], $_[2], $med_limit, |  | 
| 3152                                             $hi_limit)]; |  | 
| 3153 |  | 
| 3154         if ($width == 0) |  | 
| 3155         { |  | 
| 3156                 # Zero coverage |  | 
| 3157                 $graph_code = (<<END_OF_HTML) |  | 
| 3158                 <table border=0 cellspacing=0 cellpadding=1><tr><td class="cover
      BarOutline"><img src="$_[0]snow.png" width=100 height=10 alt="$alt"></td></tr></
      table> |  | 
| 3159 END_OF_HTML |  | 
| 3160                 ; |  | 
| 3161         } |  | 
| 3162         elsif ($width == 100) |  | 
| 3163         { |  | 
| 3164                 # Full coverage |  | 
| 3165                 $graph_code = (<<END_OF_HTML) |  | 
| 3166                 <table border=0 cellspacing=0 cellpadding=1><tr><td class="cover
      BarOutline"><img src="$_[0]$png_name" width=100 height=10 alt="$alt"></td></tr><
      /table> |  | 
| 3167 END_OF_HTML |  | 
| 3168                 ; |  | 
| 3169         } |  | 
| 3170         else |  | 
| 3171         { |  | 
| 3172                 # Positive coverage |  | 
| 3173                 $graph_code = (<<END_OF_HTML) |  | 
| 3174                 <table border=0 cellspacing=0 cellpadding=1><tr><td class="cover
      BarOutline"><img src="$_[0]$png_name" width=$width height=10 alt="$alt"><img src
      ="$_[0]snow.png" width=$remainder height=10 alt="$alt"></td></tr></table> |  | 
| 3175 END_OF_HTML |  | 
| 3176                 ; |  | 
| 3177         } |  | 
| 3178 |  | 
| 3179         # Remove leading tabs from all lines |  | 
| 3180         $graph_code =~ s/^\t+//gm; |  | 
| 3181         chomp($graph_code); |  | 
| 3182 |  | 
| 3183         return($graph_code); |  | 
| 3184 } |  | 
| 3185 |  | 
| 3186 # |  | 
| 3187 # sub classify_rate(found, hit, med_limit, high_limit) |  | 
| 3188 # |  | 
| 3189 # Return 0 for low rate, 1 for medium rate and 2 for hi rate. |  | 
| 3190 # |  | 
| 3191 |  | 
| 3192 sub classify_rate($$$$) |  | 
| 3193 { |  | 
| 3194         my ($found, $hit, $med, $hi) = @_; |  | 
| 3195         my $rate; |  | 
| 3196 |  | 
| 3197         if ($found == 0) { |  | 
| 3198                 return 2; |  | 
| 3199         } |  | 
| 3200         $rate = $hit * 100 / $found; |  | 
| 3201         if ($rate < $med) { |  | 
| 3202                 return 0; |  | 
| 3203         } elsif ($rate < $hi) { |  | 
| 3204                 return 1; |  | 
| 3205         } |  | 
| 3206         return 2; |  | 
| 3207 } |  | 
| 3208 |  | 
| 3209 |  | 
| 3210 # |  | 
| 3211 # write_html(filehandle, html_code) |  | 
| 3212 # |  | 
| 3213 # Write out HTML_CODE to FILEHANDLE while removing a leading tabulator mark |  | 
| 3214 # in each line of HTML_CODE. |  | 
| 3215 # |  | 
| 3216 |  | 
| 3217 sub write_html(*$) |  | 
| 3218 { |  | 
| 3219         local *HTML_HANDLE = $_[0]; |  | 
| 3220         my $html_code = $_[1]; |  | 
| 3221 |  | 
| 3222         # Remove leading tab from all lines |  | 
| 3223         $html_code =~ s/^\t//gm; |  | 
| 3224 |  | 
| 3225         print(HTML_HANDLE $html_code) |  | 
| 3226                 or die("ERROR: cannot write HTML data ($!)\n"); |  | 
| 3227 } |  | 
| 3228 |  | 
| 3229 |  | 
| 3230 # |  | 
| 3231 # write_html_prolog(filehandle, base_dir, pagetitle) |  | 
| 3232 # |  | 
| 3233 # Write an HTML prolog common to all HTML files to FILEHANDLE. PAGETITLE will |  | 
| 3234 # be used as HTML page title. BASE_DIR contains a relative path which points |  | 
| 3235 # to the base directory. |  | 
| 3236 # |  | 
| 3237 |  | 
| 3238 sub write_html_prolog(*$$) |  | 
| 3239 { |  | 
| 3240         my $basedir = $_[1]; |  | 
| 3241         my $pagetitle = $_[2]; |  | 
| 3242         my $prolog; |  | 
| 3243 |  | 
| 3244         $prolog = $html_prolog; |  | 
| 3245         $prolog =~ s/\@pagetitle\@/$pagetitle/g; |  | 
| 3246         $prolog =~ s/\@basedir\@/$basedir/g; |  | 
| 3247 |  | 
| 3248         write_html($_[0], $prolog); |  | 
| 3249 } |  | 
| 3250 |  | 
| 3251 |  | 
| 3252 # |  | 
| 3253 # write_header_prolog(filehandle, base_dir) |  | 
| 3254 # |  | 
| 3255 # Write beginning of page header HTML code. |  | 
| 3256 # |  | 
| 3257 |  | 
| 3258 sub write_header_prolog(*$) |  | 
| 3259 { |  | 
| 3260         # ************************************************************* |  | 
| 3261 |  | 
| 3262         write_html($_[0], <<END_OF_HTML) |  | 
| 3263           <table width="100%" border=0 cellspacing=0 cellpadding=0> |  | 
| 3264             <tr><td class="title">$title</td></tr> |  | 
| 3265             <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt
      =""></td></tr> |  | 
| 3266 |  | 
| 3267             <tr> |  | 
| 3268               <td width="100%"> |  | 
| 3269                 <table cellpadding=1 border=0 width="100%"> |  | 
| 3270 END_OF_HTML |  | 
| 3271         ; |  | 
| 3272 |  | 
| 3273         # ************************************************************* |  | 
| 3274 } |  | 
| 3275 |  | 
| 3276 |  | 
| 3277 # |  | 
| 3278 # write_header_line(handle, content) |  | 
| 3279 # |  | 
| 3280 # Write a header line with the specified table contents. |  | 
| 3281 # |  | 
| 3282 |  | 
| 3283 sub write_header_line(*@) |  | 
| 3284 { |  | 
| 3285         my ($handle, @content) = @_; |  | 
| 3286         my $entry; |  | 
| 3287 |  | 
| 3288         write_html($handle, "          <tr>\n"); |  | 
| 3289         foreach $entry (@content) { |  | 
| 3290                 my ($width, $class, $text, $colspan) = @{$entry}; |  | 
| 3291 |  | 
| 3292                 if (defined($width)) { |  | 
| 3293                         $width = " width=\"$width\""; |  | 
| 3294                 } else { |  | 
| 3295                         $width = ""; |  | 
| 3296                 } |  | 
| 3297                 if (defined($class)) { |  | 
| 3298                         $class = " class=\"$class\""; |  | 
| 3299                 } else { |  | 
| 3300                         $class = ""; |  | 
| 3301                 } |  | 
| 3302                 if (defined($colspan)) { |  | 
| 3303                         $colspan = " colspan=\"$colspan\""; |  | 
| 3304                 } else { |  | 
| 3305                         $colspan = ""; |  | 
| 3306                 } |  | 
| 3307                 $text = "" if (!defined($text)); |  | 
| 3308                 write_html($handle, |  | 
| 3309                            "            <td$width$class$colspan>$text</td>\n"); |  | 
| 3310         } |  | 
| 3311         write_html($handle, "          </tr>\n"); |  | 
| 3312 } |  | 
| 3313 |  | 
| 3314 |  | 
| 3315 # |  | 
| 3316 # write_header_epilog(filehandle, base_dir) |  | 
| 3317 # |  | 
| 3318 # Write end of page header HTML code. |  | 
| 3319 # |  | 
| 3320 |  | 
| 3321 sub write_header_epilog(*$) |  | 
| 3322 { |  | 
| 3323         # ************************************************************* |  | 
| 3324 |  | 
| 3325         write_html($_[0], <<END_OF_HTML) |  | 
| 3326                   <tr><td><img src="$_[1]glass.png" width=3 height=3 alt=""></td
      ></tr> |  | 
| 3327                 </table> |  | 
| 3328               </td> |  | 
| 3329             </tr> |  | 
| 3330 |  | 
| 3331             <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt
      =""></td></tr> |  | 
| 3332           </table> |  | 
| 3333 |  | 
| 3334 END_OF_HTML |  | 
| 3335         ; |  | 
| 3336 |  | 
| 3337         # ************************************************************* |  | 
| 3338 } |  | 
| 3339 |  | 
| 3340 |  | 
| 3341 # |  | 
| 3342 # write_file_table_prolog(handle, file_heading, ([heading, num_cols], ...)) |  | 
| 3343 # |  | 
| 3344 # Write heading for file table. |  | 
| 3345 # |  | 
| 3346 |  | 
| 3347 sub write_file_table_prolog(*$@) |  | 
| 3348 { |  | 
| 3349         my ($handle, $file_heading, @columns) = @_; |  | 
| 3350         my $num_columns = 0; |  | 
| 3351         my $file_width; |  | 
| 3352         my $col; |  | 
| 3353         my $width; |  | 
| 3354 |  | 
| 3355         $width = 20 if (scalar(@columns) == 1); |  | 
| 3356         $width = 10 if (scalar(@columns) == 2); |  | 
| 3357         $width = 8 if (scalar(@columns) > 2); |  | 
| 3358 |  | 
| 3359         foreach $col (@columns) { |  | 
| 3360                 my ($heading, $cols) = @{$col}; |  | 
| 3361 |  | 
| 3362                 $num_columns += $cols; |  | 
| 3363         } |  | 
| 3364         $file_width = 100 - $num_columns * $width; |  | 
| 3365 |  | 
| 3366         # Table definition |  | 
| 3367         write_html($handle, <<END_OF_HTML); |  | 
| 3368           <center> |  | 
| 3369           <table width="80%" cellpadding=1 cellspacing=1 border=0> |  | 
| 3370 |  | 
| 3371             <tr> |  | 
| 3372               <td width="$file_width%"><br></td> |  | 
| 3373 END_OF_HTML |  | 
| 3374         # Empty first row |  | 
| 3375         foreach $col (@columns) { |  | 
| 3376                 my ($heading, $cols) = @{$col}; |  | 
| 3377 |  | 
| 3378                 while ($cols-- > 0) { |  | 
| 3379                         write_html($handle, <<END_OF_HTML); |  | 
| 3380               <td width="$width%"></td> |  | 
| 3381 END_OF_HTML |  | 
| 3382                 } |  | 
| 3383         } |  | 
| 3384         # Next row |  | 
| 3385         write_html($handle, <<END_OF_HTML); |  | 
| 3386             </tr> |  | 
| 3387 |  | 
| 3388             <tr> |  | 
| 3389               <td class="tableHead">$file_heading</td> |  | 
| 3390 END_OF_HTML |  | 
| 3391         # Heading row |  | 
| 3392         foreach $col (@columns) { |  | 
| 3393                 my ($heading, $cols) = @{$col}; |  | 
| 3394                 my $colspan = ""; |  | 
| 3395 |  | 
| 3396                 $colspan = " colspan=$cols" if ($cols > 1); |  | 
| 3397                 write_html($handle, <<END_OF_HTML); |  | 
| 3398               <td class="tableHead"$colspan>$heading</td> |  | 
| 3399 END_OF_HTML |  | 
| 3400         } |  | 
| 3401         write_html($handle, <<END_OF_HTML); |  | 
| 3402             </tr> |  | 
| 3403 END_OF_HTML |  | 
| 3404 } |  | 
| 3405 |  | 
| 3406 |  | 
| 3407 # write_file_table_entry(handle, base_dir, filename, page_link, |  | 
| 3408 #                        ([ found, hit, med_limit, hi_limit, graph ], ..) |  | 
| 3409 # |  | 
| 3410 # Write an entry of the file table. |  | 
| 3411 # |  | 
| 3412 |  | 
| 3413 sub write_file_table_entry(*$$$@) |  | 
| 3414 { |  | 
| 3415         my ($handle, $base_dir, $filename, $page_link, @entries) = @_; |  | 
| 3416         my $file_code; |  | 
| 3417         my $entry; |  | 
| 3418 |  | 
| 3419         # Add link to source if provided |  | 
| 3420         if (defined($page_link) && $page_link ne "") { |  | 
| 3421                 $file_code = "<a href=\"$page_link\">$filename</a>"; |  | 
| 3422         } else { |  | 
| 3423                 $file_code = $filename; |  | 
| 3424         } |  | 
| 3425 |  | 
| 3426         # First column: filename |  | 
| 3427         write_html($handle, <<END_OF_HTML); |  | 
| 3428             <tr> |  | 
| 3429               <td class="coverFile">$file_code</td> |  | 
| 3430 END_OF_HTML |  | 
| 3431         # Columns as defined |  | 
| 3432         foreach $entry (@entries) { |  | 
| 3433                 my ($found, $hit, $med, $hi, $graph) = @{$entry}; |  | 
| 3434                 my $bar_graph; |  | 
| 3435                 my $class; |  | 
| 3436                 my $rate; |  | 
| 3437 |  | 
| 3438                 # Generate bar graph if requested |  | 
| 3439                 if ($graph) { |  | 
| 3440                         $bar_graph = get_bar_graph_code($base_dir, $found, |  | 
| 3441                                                         $hit); |  | 
| 3442                         write_html($handle, <<END_OF_HTML); |  | 
| 3443               <td class="coverBar" align="center"> |  | 
| 3444                 $bar_graph |  | 
| 3445               </td> |  | 
| 3446 END_OF_HTML |  | 
| 3447                 } |  | 
| 3448                 # Get rate color and text |  | 
| 3449                 if ($found == 0) { |  | 
| 3450                         $rate = "-"; |  | 
| 3451                         $class = "Hi"; |  | 
| 3452                 } else { |  | 
| 3453                         $rate = sprintf("%.1f %%", $hit * 100 / $found); |  | 
| 3454                         $class = $rate_name[classify_rate($found, $hit, |  | 
| 3455                                             $med, $hi)]; |  | 
| 3456                 } |  | 
| 3457                 write_html($handle, <<END_OF_HTML); |  | 
| 3458               <td class="coverPer$class">$rate</td> |  | 
| 3459               <td class="coverNum$class">$hit / $found</td> |  | 
| 3460 END_OF_HTML |  | 
| 3461         } |  | 
| 3462         # End of row |  | 
| 3463         write_html($handle, <<END_OF_HTML); |  | 
| 3464             </tr> |  | 
| 3465 END_OF_HTML |  | 
| 3466 } |  | 
| 3467 |  | 
| 3468 |  | 
| 3469 # |  | 
| 3470 # write_file_table_detail_entry(filehandle, test_name, ([found, hit], ...)) |  | 
| 3471 # |  | 
| 3472 # Write entry for detail section in file table. |  | 
| 3473 # |  | 
| 3474 |  | 
| 3475 sub write_file_table_detail_entry(*$@) |  | 
| 3476 { |  | 
| 3477         my ($handle, $test, @entries) = @_; |  | 
| 3478         my $entry; |  | 
| 3479 |  | 
| 3480         if ($test eq "") { |  | 
| 3481                 $test = "<span style=\"font-style:italic\"><unnamed></span
      >"; |  | 
| 3482         } elsif ($test =~ /^(.*),diff$/) { |  | 
| 3483                 $test = $1." (converted)"; |  | 
| 3484         } |  | 
| 3485         # Testname |  | 
| 3486         write_html($handle, <<END_OF_HTML); |  | 
| 3487             <tr> |  | 
| 3488               <td class="testName" colspan=2>$test</td> |  | 
| 3489 END_OF_HTML |  | 
| 3490         # Test data |  | 
| 3491         foreach $entry (@entries) { |  | 
| 3492                 my ($found, $hit) = @{$entry}; |  | 
| 3493                 my $rate = "-"; |  | 
| 3494 |  | 
| 3495                 if ($found > 0) { |  | 
| 3496                         $rate = sprintf("%.1f %%", $hit * 100 / $found); |  | 
| 3497                 } |  | 
| 3498                 write_html($handle, <<END_OF_HTML); |  | 
| 3499               <td class="testPer">$rate</td> |  | 
| 3500               <td class="testNum">$hit / $found</td> |  | 
| 3501 END_OF_HTML |  | 
| 3502         } |  | 
| 3503 |  | 
| 3504         write_html($handle, <<END_OF_HTML); |  | 
| 3505             </tr> |  | 
| 3506 |  | 
| 3507 END_OF_HTML |  | 
| 3508 |  | 
| 3509         # ************************************************************* |  | 
| 3510 } |  | 
| 3511 |  | 
| 3512 |  | 
| 3513 # |  | 
| 3514 # write_file_table_epilog(filehandle) |  | 
| 3515 # |  | 
| 3516 # Write end of file table HTML code. |  | 
| 3517 # |  | 
| 3518 |  | 
| 3519 sub write_file_table_epilog(*) |  | 
| 3520 { |  | 
| 3521         # ************************************************************* |  | 
| 3522 |  | 
| 3523         write_html($_[0], <<END_OF_HTML) |  | 
| 3524           </table> |  | 
| 3525           </center> |  | 
| 3526           <br> |  | 
| 3527 |  | 
| 3528 END_OF_HTML |  | 
| 3529         ; |  | 
| 3530 |  | 
| 3531         # ************************************************************* |  | 
| 3532 } |  | 
| 3533 |  | 
| 3534 |  | 
| 3535 # |  | 
| 3536 # write_test_table_prolog(filehandle, table_heading) |  | 
| 3537 # |  | 
| 3538 # Write heading for test case description table. |  | 
| 3539 # |  | 
| 3540 |  | 
| 3541 sub write_test_table_prolog(*$) |  | 
| 3542 { |  | 
| 3543         # ************************************************************* |  | 
| 3544 |  | 
| 3545         write_html($_[0], <<END_OF_HTML) |  | 
| 3546           <center> |  | 
| 3547           <table width="80%" cellpadding=2 cellspacing=1 border=0> |  | 
| 3548 |  | 
| 3549             <tr> |  | 
| 3550               <td><br></td> |  | 
| 3551             </tr> |  | 
| 3552 |  | 
| 3553             <tr> |  | 
| 3554               <td class="tableHead">$_[1]</td> |  | 
| 3555             </tr> |  | 
| 3556 |  | 
| 3557             <tr> |  | 
| 3558               <td class="testDescription"> |  | 
| 3559                 <dl> |  | 
| 3560 END_OF_HTML |  | 
| 3561         ; |  | 
| 3562 |  | 
| 3563         # ************************************************************* |  | 
| 3564 } |  | 
| 3565 |  | 
| 3566 |  | 
| 3567 # |  | 
| 3568 # write_test_table_entry(filehandle, test_name, test_description) |  | 
| 3569 # |  | 
| 3570 # Write entry for the test table. |  | 
| 3571 # |  | 
| 3572 |  | 
| 3573 sub write_test_table_entry(*$$) |  | 
| 3574 { |  | 
| 3575         # ************************************************************* |  | 
| 3576 |  | 
| 3577         write_html($_[0], <<END_OF_HTML) |  | 
| 3578           <dt>$_[1]<a name="$_[1]"> </a></dt> |  | 
| 3579           <dd>$_[2]<br><br></dd> |  | 
| 3580 END_OF_HTML |  | 
| 3581         ; |  | 
| 3582 |  | 
| 3583         # ************************************************************* |  | 
| 3584 } |  | 
| 3585 |  | 
| 3586 |  | 
| 3587 # |  | 
| 3588 # write_test_table_epilog(filehandle) |  | 
| 3589 # |  | 
| 3590 # Write end of test description table HTML code. |  | 
| 3591 # |  | 
| 3592 |  | 
| 3593 sub write_test_table_epilog(*) |  | 
| 3594 { |  | 
| 3595         # ************************************************************* |  | 
| 3596 |  | 
| 3597         write_html($_[0], <<END_OF_HTML) |  | 
| 3598                 </dl> |  | 
| 3599               </td> |  | 
| 3600             </tr> |  | 
| 3601           </table> |  | 
| 3602           </center> |  | 
| 3603           <br> |  | 
| 3604 |  | 
| 3605 END_OF_HTML |  | 
| 3606         ; |  | 
| 3607 |  | 
| 3608         # ************************************************************* |  | 
| 3609 } |  | 
| 3610 |  | 
| 3611 |  | 
| 3612 sub fmt_centered($$) |  | 
| 3613 { |  | 
| 3614         my ($width, $text) = @_; |  | 
| 3615         my $w0 = length($text); |  | 
| 3616         my $w1 = int(($width - $w0) / 2); |  | 
| 3617         my $w2 = $width - $w0 - $w1; |  | 
| 3618 |  | 
| 3619         return (" "x$w1).$text.(" "x$w2); |  | 
| 3620 } |  | 
| 3621 |  | 
| 3622 |  | 
| 3623 # |  | 
| 3624 # write_source_prolog(filehandle) |  | 
| 3625 # |  | 
| 3626 # Write start of source code table. |  | 
| 3627 # |  | 
| 3628 |  | 
| 3629 sub write_source_prolog(*) |  | 
| 3630 { |  | 
| 3631         my $lineno_heading = "         "; |  | 
| 3632         my $branch_heading = ""; |  | 
| 3633         my $line_heading = fmt_centered($line_field_width, "Line data"); |  | 
| 3634         my $source_heading = " Source code"; |  | 
| 3635 |  | 
| 3636         if ($br_coverage) { |  | 
| 3637                 $branch_heading = fmt_centered($br_field_width, "Branch data"). |  | 
| 3638                                   " "; |  | 
| 3639         } |  | 
| 3640         # ************************************************************* |  | 
| 3641 |  | 
| 3642         write_html($_[0], <<END_OF_HTML) |  | 
| 3643           <table cellpadding=0 cellspacing=0 border=0> |  | 
| 3644             <tr> |  | 
| 3645               <td><br></td> |  | 
| 3646             </tr> |  | 
| 3647             <tr> |  | 
| 3648               <td> |  | 
| 3649 <pre class="sourceHeading">${lineno_heading}${branch_heading}${line_heading} ${s
      ource_heading}</pre> |  | 
| 3650 <pre class="source"> |  | 
| 3651 END_OF_HTML |  | 
| 3652         ; |  | 
| 3653 |  | 
| 3654         # ************************************************************* |  | 
| 3655 } |  | 
| 3656 |  | 
| 3657 |  | 
| 3658 # |  | 
| 3659 # get_branch_blocks(brdata) |  | 
| 3660 # |  | 
| 3661 # Group branches that belong to the same basic block. |  | 
| 3662 # |  | 
| 3663 # Returns: [block1, block2, ...] |  | 
| 3664 # block:   [branch1, branch2, ...] |  | 
| 3665 # branch:  [block_num, branch_num, taken_count, text_length, open, close] |  | 
| 3666 # |  | 
| 3667 |  | 
| 3668 sub get_branch_blocks($) |  | 
| 3669 { |  | 
| 3670         my ($brdata) = @_; |  | 
| 3671         my $last_block_num; |  | 
| 3672         my $block = []; |  | 
| 3673         my @blocks; |  | 
| 3674         my $i; |  | 
| 3675         my $num = br_ivec_len($brdata); |  | 
| 3676 |  | 
| 3677         # Group branches |  | 
| 3678         for ($i = 0; $i < $num; $i++) { |  | 
| 3679                 my ($block_num, $branch, $taken) = br_ivec_get($brdata, $i); |  | 
| 3680                 my $br; |  | 
| 3681 |  | 
| 3682                 if (defined($last_block_num) && $block_num != $last_block_num) { |  | 
| 3683                         push(@blocks, $block); |  | 
| 3684                         $block = []; |  | 
| 3685                 } |  | 
| 3686                 $br = [$block_num, $branch, $taken, 3, 0, 0]; |  | 
| 3687                 push(@{$block}, $br); |  | 
| 3688                 $last_block_num = $block_num; |  | 
| 3689         } |  | 
| 3690         push(@blocks, $block) if (scalar(@{$block}) > 0); |  | 
| 3691 |  | 
| 3692         # Add braces to first and last branch in group |  | 
| 3693         foreach $block (@blocks) { |  | 
| 3694                 $block->[0]->[$BR_OPEN] = 1; |  | 
| 3695                 $block->[0]->[$BR_LEN]++; |  | 
| 3696                 $block->[scalar(@{$block}) - 1]->[$BR_CLOSE] = 1; |  | 
| 3697                 $block->[scalar(@{$block}) - 1]->[$BR_LEN]++; |  | 
| 3698         } |  | 
| 3699 |  | 
| 3700         return @blocks; |  | 
| 3701 } |  | 
| 3702 |  | 
| 3703 # |  | 
| 3704 # get_block_len(block) |  | 
| 3705 # |  | 
| 3706 # Calculate total text length of all branches in a block of branches. |  | 
| 3707 # |  | 
| 3708 |  | 
| 3709 sub get_block_len($) |  | 
| 3710 { |  | 
| 3711         my ($block) = @_; |  | 
| 3712         my $len = 0; |  | 
| 3713         my $branch; |  | 
| 3714 |  | 
| 3715         foreach $branch (@{$block}) { |  | 
| 3716                 $len += $branch->[$BR_LEN]; |  | 
| 3717         } |  | 
| 3718 |  | 
| 3719         return $len; |  | 
| 3720 } |  | 
| 3721 |  | 
| 3722 |  | 
| 3723 # |  | 
| 3724 # get_branch_html(brdata) |  | 
| 3725 # |  | 
| 3726 # Return a list of HTML lines which represent the specified branch coverage |  | 
| 3727 # data in source code view. |  | 
| 3728 # |  | 
| 3729 |  | 
| 3730 sub get_branch_html($) |  | 
| 3731 { |  | 
| 3732         my ($brdata) = @_; |  | 
| 3733         my @blocks = get_branch_blocks($brdata); |  | 
| 3734         my $block; |  | 
| 3735         my $branch; |  | 
| 3736         my $line_len = 0; |  | 
| 3737         my $line = [];  # [branch2|" ", branch|" ", ...] |  | 
| 3738         my @lines;      # [line1, line2, ...] |  | 
| 3739         my @result; |  | 
| 3740 |  | 
| 3741         # Distribute blocks to lines |  | 
| 3742         foreach $block (@blocks) { |  | 
| 3743                 my $block_len = get_block_len($block); |  | 
| 3744 |  | 
| 3745                 # Does this block fit into the current line? |  | 
| 3746                 if ($line_len + $block_len <= $br_field_width) { |  | 
| 3747                         # Add it |  | 
| 3748                         $line_len += $block_len; |  | 
| 3749                         push(@{$line}, @{$block}); |  | 
| 3750                         next; |  | 
| 3751                 } elsif ($block_len <= $br_field_width) { |  | 
| 3752                         # It would fit if the line was empty - add it to new |  | 
| 3753                         # line |  | 
| 3754                         push(@lines, $line); |  | 
| 3755                         $line_len = $block_len; |  | 
| 3756                         $line = [ @{$block} ]; |  | 
| 3757                         next; |  | 
| 3758                 } |  | 
| 3759                 # Split the block into several lines |  | 
| 3760                 foreach $branch (@{$block}) { |  | 
| 3761                         if ($line_len + $branch->[$BR_LEN] >= $br_field_width) { |  | 
| 3762                                 # Start a new line |  | 
| 3763                                 if (($line_len + 1 <= $br_field_width) && |  | 
| 3764                                     scalar(@{$line}) > 0 && |  | 
| 3765                                     !$line->[scalar(@$line) - 1]->[$BR_CLOSE]) { |  | 
| 3766                                         # Try to align branch symbols to be in |  | 
| 3767                                         # one # row |  | 
| 3768                                         push(@{$line}, " "); |  | 
| 3769                                 } |  | 
| 3770                                 push(@lines, $line); |  | 
| 3771                                 $line_len = 0; |  | 
| 3772                                 $line = []; |  | 
| 3773                         } |  | 
| 3774                         push(@{$line}, $branch); |  | 
| 3775                         $line_len += $branch->[$BR_LEN]; |  | 
| 3776                 } |  | 
| 3777         } |  | 
| 3778         push(@lines, $line); |  | 
| 3779 |  | 
| 3780         # Convert to HTML |  | 
| 3781         foreach $line (@lines) { |  | 
| 3782                 my $current = ""; |  | 
| 3783                 my $current_len = 0; |  | 
| 3784 |  | 
| 3785                 foreach $branch (@$line) { |  | 
| 3786                         # Skip alignment space |  | 
| 3787                         if ($branch eq " ") { |  | 
| 3788                                 $current .= " "; |  | 
| 3789                                 $current_len++; |  | 
| 3790                                 next; |  | 
| 3791                         } |  | 
| 3792 |  | 
| 3793                         my ($block_num, $br_num, $taken, $len, $open, $close) = |  | 
| 3794                            @{$branch}; |  | 
| 3795                         my $class; |  | 
| 3796                         my $title; |  | 
| 3797                         my $text; |  | 
| 3798 |  | 
| 3799                         if ($taken eq '-') { |  | 
| 3800                                 $class  = "branchNoExec"; |  | 
| 3801                                 $text   = " # "; |  | 
| 3802                                 $title  = "Branch $br_num was not executed"; |  | 
| 3803                         } elsif ($taken == 0) { |  | 
| 3804                                 $class  = "branchNoCov"; |  | 
| 3805                                 $text   = " - "; |  | 
| 3806                                 $title  = "Branch $br_num was not taken"; |  | 
| 3807                         } else { |  | 
| 3808                                 $class  = "branchCov"; |  | 
| 3809                                 $text   = " + "; |  | 
| 3810                                 $title  = "Branch $br_num was taken $taken ". |  | 
| 3811                                           "time"; |  | 
| 3812                                 $title .= "s" if ($taken > 1); |  | 
| 3813                         } |  | 
| 3814                         $current .= "[" if ($open); |  | 
| 3815                         $current .= "<span class=\"$class\" title=\"$title\">"; |  | 
| 3816                         $current .= $text."</span>"; |  | 
| 3817                         $current .= "]" if ($close); |  | 
| 3818                         $current_len += $len; |  | 
| 3819                 } |  | 
| 3820 |  | 
| 3821                 # Right-align result text |  | 
| 3822                 if ($current_len < $br_field_width) { |  | 
| 3823                         $current = (" "x($br_field_width - $current_len)). |  | 
| 3824                                    $current; |  | 
| 3825                 } |  | 
| 3826                 push(@result, $current); |  | 
| 3827         } |  | 
| 3828 |  | 
| 3829         return @result; |  | 
| 3830 } |  | 
| 3831 |  | 
| 3832 |  | 
| 3833 # |  | 
| 3834 # format_count(count, width) |  | 
| 3835 # |  | 
| 3836 # Return a right-aligned representation of count that fits in width characters. |  | 
| 3837 # |  | 
| 3838 |  | 
| 3839 sub format_count($$) |  | 
| 3840 { |  | 
| 3841         my ($count, $width) = @_; |  | 
| 3842         my $result; |  | 
| 3843         my $exp; |  | 
| 3844 |  | 
| 3845         $result = sprintf("%*.0f", $width, $count); |  | 
| 3846         while (length($result) > $width) { |  | 
| 3847                 last if ($count < 10); |  | 
| 3848                 $exp++; |  | 
| 3849                 $count = int($count/10); |  | 
| 3850                 $result = sprintf("%*s", $width, ">$count*10^$exp"); |  | 
| 3851         } |  | 
| 3852         return $result; |  | 
| 3853 } |  | 
| 3854 |  | 
| 3855 # |  | 
| 3856 # write_source_line(filehandle, line_num, source, hit_count, converted, |  | 
| 3857 #                   brdata, add_anchor) |  | 
| 3858 # |  | 
| 3859 # Write formatted source code line. Return a line in a format as needed |  | 
| 3860 # by gen_png() |  | 
| 3861 # |  | 
| 3862 |  | 
| 3863 sub write_source_line(*$$$$$$) |  | 
| 3864 { |  | 
| 3865         my ($handle, $line, $source, $count, $converted, $brdata, |  | 
| 3866             $add_anchor) = @_; |  | 
| 3867         my $source_format; |  | 
| 3868         my $count_format; |  | 
| 3869         my $result; |  | 
| 3870         my $anchor_start = ""; |  | 
| 3871         my $anchor_end = ""; |  | 
| 3872         my $count_field_width = $line_field_width - 1; |  | 
| 3873         my @br_html; |  | 
| 3874         my $html; |  | 
| 3875 |  | 
| 3876         # Get branch HTML data for this line |  | 
| 3877         @br_html = get_branch_html($brdata) if ($br_coverage); |  | 
| 3878 |  | 
| 3879         if (!defined($count)) { |  | 
| 3880                 $result         = ""; |  | 
| 3881                 $source_format  = ""; |  | 
| 3882                 $count_format   = " "x$count_field_width; |  | 
| 3883         } |  | 
| 3884         elsif ($count == 0) { |  | 
| 3885                 $result         = $count; |  | 
| 3886                 $source_format  = '<span class="lineNoCov">'; |  | 
| 3887                 $count_format   = format_count($count, $count_field_width); |  | 
| 3888         } |  | 
| 3889         elsif ($converted && defined($highlight)) { |  | 
| 3890                 $result         = "*".$count; |  | 
| 3891                 $source_format  = '<span class="lineDiffCov">'; |  | 
| 3892                 $count_format   = format_count($count, $count_field_width); |  | 
| 3893         } |  | 
| 3894         else { |  | 
| 3895                 $result         = $count; |  | 
| 3896                 $source_format  = '<span class="lineCov">'; |  | 
| 3897                 $count_format   = format_count($count, $count_field_width); |  | 
| 3898         } |  | 
| 3899         $result .= ":".$source; |  | 
| 3900 |  | 
| 3901         # Write out a line number navigation anchor every $nav_resolution |  | 
| 3902         # lines if necessary |  | 
| 3903         if ($add_anchor) |  | 
| 3904         { |  | 
| 3905                 $anchor_start   = "<a name=\"$_[1]\">"; |  | 
| 3906                 $anchor_end     = "</a>"; |  | 
| 3907         } |  | 
| 3908 |  | 
| 3909 |  | 
| 3910         # ************************************************************* |  | 
| 3911 |  | 
| 3912         $html = $anchor_start; |  | 
| 3913         $html .= "<span class=\"lineNum\">".sprintf("%8d", $line)." </span>"; |  | 
| 3914         $html .= shift(@br_html).":" if ($br_coverage); |  | 
| 3915         $html .= "$source_format$count_format : "; |  | 
| 3916         $html .= escape_html($source); |  | 
| 3917         $html .= "</span>" if ($source_format); |  | 
| 3918         $html .= $anchor_end."\n"; |  | 
| 3919 |  | 
| 3920         write_html($handle, $html); |  | 
| 3921 |  | 
| 3922         if ($br_coverage) { |  | 
| 3923                 # Add lines for overlong branch information |  | 
| 3924                 foreach (@br_html) { |  | 
| 3925                         write_html($handle, "<span class=\"lineNum\">". |  | 
| 3926                                    "         </span>$_\n"); |  | 
| 3927                 } |  | 
| 3928         } |  | 
| 3929         # ************************************************************* |  | 
| 3930 |  | 
| 3931         return($result); |  | 
| 3932 } |  | 
| 3933 |  | 
| 3934 |  | 
| 3935 # |  | 
| 3936 # write_source_epilog(filehandle) |  | 
| 3937 # |  | 
| 3938 # Write end of source code table. |  | 
| 3939 # |  | 
| 3940 |  | 
| 3941 sub write_source_epilog(*) |  | 
| 3942 { |  | 
| 3943         # ************************************************************* |  | 
| 3944 |  | 
| 3945         write_html($_[0], <<END_OF_HTML) |  | 
| 3946         </pre> |  | 
| 3947               </td> |  | 
| 3948             </tr> |  | 
| 3949           </table> |  | 
| 3950           <br> |  | 
| 3951 |  | 
| 3952 END_OF_HTML |  | 
| 3953         ; |  | 
| 3954 |  | 
| 3955         # ************************************************************* |  | 
| 3956 } |  | 
| 3957 |  | 
| 3958 |  | 
| 3959 # |  | 
| 3960 # write_html_epilog(filehandle, base_dir[, break_frames]) |  | 
| 3961 # |  | 
| 3962 # Write HTML page footer to FILEHANDLE. BREAK_FRAMES should be set when |  | 
| 3963 # this page is embedded in a frameset, clicking the URL link will then |  | 
| 3964 # break this frameset. |  | 
| 3965 # |  | 
| 3966 |  | 
| 3967 sub write_html_epilog(*$;$) |  | 
| 3968 { |  | 
| 3969         my $basedir = $_[1]; |  | 
| 3970         my $break_code = ""; |  | 
| 3971         my $epilog; |  | 
| 3972 |  | 
| 3973         if (defined($_[2])) |  | 
| 3974         { |  | 
| 3975                 $break_code = " target=\"_parent\""; |  | 
| 3976         } |  | 
| 3977 |  | 
| 3978         # ************************************************************* |  | 
| 3979 |  | 
| 3980         write_html($_[0], <<END_OF_HTML) |  | 
| 3981           <table width="100%" border=0 cellspacing=0 cellpadding=0> |  | 
| 3982             <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt
      =""></td></tr> |  | 
| 3983             <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_
      code>$lcov_version</a></td></tr> |  | 
| 3984           </table> |  | 
| 3985           <br> |  | 
| 3986 END_OF_HTML |  | 
| 3987         ; |  | 
| 3988 |  | 
| 3989         $epilog = $html_epilog; |  | 
| 3990         $epilog =~ s/\@basedir\@/$basedir/g; |  | 
| 3991 |  | 
| 3992         write_html($_[0], $epilog); |  | 
| 3993 } |  | 
| 3994 |  | 
| 3995 |  | 
| 3996 # |  | 
| 3997 # write_frameset(filehandle, basedir, basename, pagetitle) |  | 
| 3998 # |  | 
| 3999 # |  | 
| 4000 |  | 
| 4001 sub write_frameset(*$$$) |  | 
| 4002 { |  | 
| 4003         my $frame_width = $overview_width + 40; |  | 
| 4004 |  | 
| 4005         # ************************************************************* |  | 
| 4006 |  | 
| 4007         write_html($_[0], <<END_OF_HTML) |  | 
| 4008         <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"> |  | 
| 4009 |  | 
| 4010         <html lang="en"> |  | 
| 4011 |  | 
| 4012         <head> |  | 
| 4013           <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1
      "> |  | 
| 4014           <title>$_[3]</title> |  | 
| 4015           <link rel="stylesheet" type="text/css" href="$_[1]gcov.css"> |  | 
| 4016         </head> |  | 
| 4017 |  | 
| 4018         <frameset cols="$frame_width,*"> |  | 
| 4019           <frame src="$_[2].gcov.overview.$html_ext" name="overview"> |  | 
| 4020           <frame src="$_[2].gcov.$html_ext" name="source"> |  | 
| 4021           <noframes> |  | 
| 4022             <center>Frames not supported by your browser!<br></center> |  | 
| 4023           </noframes> |  | 
| 4024         </frameset> |  | 
| 4025 |  | 
| 4026         </html> |  | 
| 4027 END_OF_HTML |  | 
| 4028         ; |  | 
| 4029 |  | 
| 4030         # ************************************************************* |  | 
| 4031 } |  | 
| 4032 |  | 
| 4033 |  | 
| 4034 # |  | 
| 4035 # sub write_overview_line(filehandle, basename, line, link) |  | 
| 4036 # |  | 
| 4037 # |  | 
| 4038 |  | 
| 4039 sub write_overview_line(*$$$) |  | 
| 4040 { |  | 
| 4041         my $y1 = $_[2] - 1; |  | 
| 4042         my $y2 = $y1 + $nav_resolution - 1; |  | 
| 4043         my $x2 = $overview_width - 1; |  | 
| 4044 |  | 
| 4045         # ************************************************************* |  | 
| 4046 |  | 
| 4047         write_html($_[0], <<END_OF_HTML) |  | 
| 4048             <area shape="rect" coords="0,$y1,$x2,$y2" href="$_[1].gcov.$html_ext
      #$_[3]" target="source" alt="overview"> |  | 
| 4049 END_OF_HTML |  | 
| 4050         ; |  | 
| 4051 |  | 
| 4052         # ************************************************************* |  | 
| 4053 } |  | 
| 4054 |  | 
| 4055 |  | 
| 4056 # |  | 
| 4057 # write_overview(filehandle, basedir, basename, pagetitle, lines) |  | 
| 4058 # |  | 
| 4059 # |  | 
| 4060 |  | 
| 4061 sub write_overview(*$$$$) |  | 
| 4062 { |  | 
| 4063         my $index; |  | 
| 4064         my $max_line = $_[4] - 1; |  | 
| 4065         my $offset; |  | 
| 4066 |  | 
| 4067         # ************************************************************* |  | 
| 4068 |  | 
| 4069         write_html($_[0], <<END_OF_HTML) |  | 
| 4070         <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |  | 
| 4071 |  | 
| 4072         <html lang="en"> |  | 
| 4073 |  | 
| 4074         <head> |  | 
| 4075           <title>$_[3]</title> |  | 
| 4076           <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1
      "> |  | 
| 4077           <link rel="stylesheet" type="text/css" href="$_[1]gcov.css"> |  | 
| 4078         </head> |  | 
| 4079 |  | 
| 4080         <body> |  | 
| 4081           <map name="overview"> |  | 
| 4082 END_OF_HTML |  | 
| 4083         ; |  | 
| 4084 |  | 
| 4085         # ************************************************************* |  | 
| 4086 |  | 
| 4087         # Make $offset the next higher multiple of $nav_resolution |  | 
| 4088         $offset = ($nav_offset + $nav_resolution - 1) / $nav_resolution; |  | 
| 4089         $offset = sprintf("%d", $offset ) * $nav_resolution; |  | 
| 4090 |  | 
| 4091         # Create image map for overview image |  | 
| 4092         for ($index = 1; $index <= $_[4]; $index += $nav_resolution) |  | 
| 4093         { |  | 
| 4094                 # Enforce nav_offset |  | 
| 4095                 if ($index < $offset + 1) |  | 
| 4096                 { |  | 
| 4097                         write_overview_line($_[0], $_[2], $index, 1); |  | 
| 4098                 } |  | 
| 4099                 else |  | 
| 4100                 { |  | 
| 4101                         write_overview_line($_[0], $_[2], $index, $index - $offs
      et); |  | 
| 4102                 } |  | 
| 4103         } |  | 
| 4104 |  | 
| 4105         # ************************************************************* |  | 
| 4106 |  | 
| 4107         write_html($_[0], <<END_OF_HTML) |  | 
| 4108           </map> |  | 
| 4109 |  | 
| 4110           <center> |  | 
| 4111           <a href="$_[2].gcov.$html_ext#top" target="source">Top</a><br><br> |  | 
| 4112           <img src="$_[2].gcov.png" width=$overview_width height=$max_line alt="
      Overview" border=0 usemap="#overview"> |  | 
| 4113           </center> |  | 
| 4114         </body> |  | 
| 4115         </html> |  | 
| 4116 END_OF_HTML |  | 
| 4117         ; |  | 
| 4118 |  | 
| 4119         # ************************************************************* |  | 
| 4120 } |  | 
| 4121 |  | 
| 4122 |  | 
| 4123 # format_rate(found, hit) |  | 
| 4124 # |  | 
| 4125 # Return formatted percent string for coverage rate. |  | 
| 4126 # |  | 
| 4127 |  | 
| 4128 sub format_rate($$) |  | 
| 4129 { |  | 
| 4130         return $_[0] == 0 ? "-" : sprintf("%.1f", $_[1] * 100 / $_[0])." %"; |  | 
| 4131 } |  | 
| 4132 |  | 
| 4133 |  | 
| 4134 sub max($$) |  | 
| 4135 { |  | 
| 4136         my ($a, $b) = @_; |  | 
| 4137 |  | 
| 4138         return $a if ($a > $b); |  | 
| 4139         return $b; |  | 
| 4140 } |  | 
| 4141 |  | 
| 4142 |  | 
| 4143 # |  | 
| 4144 # write_header(filehandle, type, trunc_file_name, rel_file_name, lines_found, |  | 
| 4145 # lines_hit, funcs_found, funcs_hit, sort_type) |  | 
| 4146 # |  | 
| 4147 # Write a complete standard page header. TYPE may be (0, 1, 2, 3, 4) |  | 
| 4148 # corresponding to (directory view header, file view header, source view |  | 
| 4149 # header, test case description header, function view header) |  | 
| 4150 # |  | 
| 4151 |  | 
| 4152 sub write_header(*$$$$$$$$$$) |  | 
| 4153 { |  | 
| 4154         local *HTML_HANDLE = $_[0]; |  | 
| 4155         my $type = $_[1]; |  | 
| 4156         my $trunc_name = $_[2]; |  | 
| 4157         my $rel_filename = $_[3]; |  | 
| 4158         my $lines_found = $_[4]; |  | 
| 4159         my $lines_hit = $_[5]; |  | 
| 4160         my $fn_found = $_[6]; |  | 
| 4161         my $fn_hit = $_[7]; |  | 
| 4162         my $br_found = $_[8]; |  | 
| 4163         my $br_hit = $_[9]; |  | 
| 4164         my $sort_type = $_[10]; |  | 
| 4165         my $base_dir; |  | 
| 4166         my $view; |  | 
| 4167         my $test; |  | 
| 4168         my $base_name; |  | 
| 4169         my $style; |  | 
| 4170         my $rate; |  | 
| 4171         my @row_left; |  | 
| 4172         my @row_right; |  | 
| 4173         my $num_rows; |  | 
| 4174         my $i; |  | 
| 4175 |  | 
| 4176         $base_name = basename($rel_filename); |  | 
| 4177 |  | 
| 4178         # Prepare text for "current view" field |  | 
| 4179         if ($type == $HDR_DIR) |  | 
| 4180         { |  | 
| 4181                 # Main overview |  | 
| 4182                 $base_dir = ""; |  | 
| 4183                 $view = $overview_title; |  | 
| 4184         } |  | 
| 4185         elsif ($type == $HDR_FILE) |  | 
| 4186         { |  | 
| 4187                 # Directory overview |  | 
| 4188                 $base_dir = get_relative_base_path($rel_filename); |  | 
| 4189                 $view = "<a href=\"$base_dir"."index.$html_ext\">". |  | 
| 4190                         "$overview_title</a> - $trunc_name"; |  | 
| 4191         } |  | 
| 4192         elsif ($type == $HDR_SOURCE || $type == $HDR_FUNC) |  | 
| 4193         { |  | 
| 4194                 # File view |  | 
| 4195                 my $dir_name = dirname($rel_filename); |  | 
| 4196 |  | 
| 4197                 $base_dir = get_relative_base_path($dir_name); |  | 
| 4198                 if ($frames) |  | 
| 4199                 { |  | 
| 4200                         # Need to break frameset when clicking any of these |  | 
| 4201                         # links |  | 
| 4202                         $view = "<a href=\"$base_dir"."index.$html_ext\" ". |  | 
| 4203                                 "target=\"_parent\">$overview_title</a> - ". |  | 
| 4204                                 "<a href=\"index.$html_ext\" target=\"_parent\">
      ". |  | 
| 4205                                 "$dir_name</a> - $base_name"; |  | 
| 4206                 } |  | 
| 4207                 else |  | 
| 4208                 { |  | 
| 4209                         $view = "<a href=\"$base_dir"."index.$html_ext\">". |  | 
| 4210                                 "$overview_title</a> - ". |  | 
| 4211                                 "<a href=\"index.$html_ext\">". |  | 
| 4212                                 "$dir_name</a> - $base_name"; |  | 
| 4213                 } |  | 
| 4214 |  | 
| 4215                 # Add function suffix |  | 
| 4216                 if ($func_coverage) { |  | 
| 4217                         $view .= "<span style=\"font-size: 80%;\">"; |  | 
| 4218                         if ($type == $HDR_SOURCE) { |  | 
| 4219                                 $view .= " (source / <a href=\"$base_name.func.$
      html_ext\">functions</a>)"; |  | 
| 4220                         } elsif ($type == $HDR_FUNC) { |  | 
| 4221                                 $view .= " (<a href=\"$base_name.gcov.$html_ext\
      ">source</a> / functions)"; |  | 
| 4222                         } |  | 
| 4223                         $view .= "</span>"; |  | 
| 4224                 } |  | 
| 4225         } |  | 
| 4226         elsif ($type == $HDR_TESTDESC) |  | 
| 4227         { |  | 
| 4228                 # Test description header |  | 
| 4229                 $base_dir = ""; |  | 
| 4230                 $view = "<a href=\"$base_dir"."index.$html_ext\">". |  | 
| 4231                         "$overview_title</a> - test case descriptions"; |  | 
| 4232         } |  | 
| 4233 |  | 
| 4234         # Prepare text for "test" field |  | 
| 4235         $test = escape_html($test_title); |  | 
| 4236 |  | 
| 4237         # Append link to test description page if available |  | 
| 4238         if (%test_description && ($type != $HDR_TESTDESC)) |  | 
| 4239         { |  | 
| 4240                 if ($frames && ($type == $HDR_SOURCE || $type == $HDR_FUNC)) |  | 
| 4241                 { |  | 
| 4242                         # Need to break frameset when clicking this link |  | 
| 4243                         $test .= " ( <span style=\"font-size:80%;\">". |  | 
| 4244                                  "<a href=\"$base_dir". |  | 
| 4245                                  "descriptions.$html_ext\" target=\"_parent\">". |  | 
| 4246                                  "view descriptions</a></span> )"; |  | 
| 4247                 } |  | 
| 4248                 else |  | 
| 4249                 { |  | 
| 4250                         $test .= " ( <span style=\"font-size:80%;\">". |  | 
| 4251                                  "<a href=\"$base_dir". |  | 
| 4252                                  "descriptions.$html_ext\">". |  | 
| 4253                                  "view descriptions</a></span> )"; |  | 
| 4254                 } |  | 
| 4255         } |  | 
| 4256 |  | 
| 4257         # Write header |  | 
| 4258         write_header_prolog(*HTML_HANDLE, $base_dir); |  | 
| 4259 |  | 
| 4260         # Left row |  | 
| 4261         push(@row_left, [[ "10%", "headerItem", "Current view:" ], |  | 
| 4262                          [ "35%", "headerValue", $view ]]); |  | 
| 4263         push(@row_left, [[undef, "headerItem", "Test:"], |  | 
| 4264                          [undef, "headerValue", $test]]); |  | 
| 4265         push(@row_left, [[undef, "headerItem", "Date:"], |  | 
| 4266                          [undef, "headerValue", $date]]); |  | 
| 4267 |  | 
| 4268         # Right row |  | 
| 4269         if ($legend && ($type == $HDR_SOURCE || $type == $HDR_FUNC)) { |  | 
| 4270                 my $text = <<END_OF_HTML; |  | 
| 4271             Lines: |  | 
| 4272             <span class="coverLegendCov">hit</span> |  | 
| 4273             <span class="coverLegendNoCov">not hit</span> |  | 
| 4274 END_OF_HTML |  | 
| 4275                 if ($br_coverage) { |  | 
| 4276                         $text .= <<END_OF_HTML; |  | 
| 4277             | Branches: |  | 
| 4278             <span class="coverLegendCov">+</span> taken |  | 
| 4279             <span class="coverLegendNoCov">-</span> not taken |  | 
| 4280             <span class="coverLegendNoCov">#</span> not executed |  | 
| 4281 END_OF_HTML |  | 
| 4282                 } |  | 
| 4283                 push(@row_left, [[undef, "headerItem", "Legend:"], |  | 
| 4284                                  [undef, "headerValueLeg", $text]]); |  | 
| 4285         } elsif ($legend && ($type != $HDR_TESTDESC)) { |  | 
| 4286                 my $text = <<END_OF_HTML; |  | 
| 4287             Rating: |  | 
| 4288             <span class="coverLegendCovLo" title="Coverage rates below $med_limi
      t % are classified as low">low: < $med_limit %</span> |  | 
| 4289             <span class="coverLegendCovMed" title="Coverage rates between $med_l
      imit % and $hi_limit % are classified as medium">medium: >= $med_limit %</spa
      n> |  | 
| 4290             <span class="coverLegendCovHi" title="Coverage rates of $hi_limit % 
      and more are classified as high">high: >= $hi_limit %</span> |  | 
| 4291 END_OF_HTML |  | 
| 4292                 push(@row_left, [[undef, "headerItem", "Legend:"], |  | 
| 4293                                  [undef, "headerValueLeg", $text]]); |  | 
| 4294         } |  | 
| 4295         if ($type == $HDR_TESTDESC) { |  | 
| 4296                 push(@row_right, [[ "55%" ]]); |  | 
| 4297         } else { |  | 
| 4298                 push(@row_right, [["15%", undef, undef ], |  | 
| 4299                                   ["10%", "headerCovTableHead", "Hit" ], |  | 
| 4300                                   ["10%", "headerCovTableHead", "Total" ], |  | 
| 4301                                   ["15%", "headerCovTableHead", "Coverage"]]); |  | 
| 4302         } |  | 
| 4303         # Line coverage |  | 
| 4304         $style = $rate_name[classify_rate($lines_found, $lines_hit, |  | 
| 4305                                           $med_limit, $hi_limit)]; |  | 
| 4306         $rate = format_rate($lines_found, $lines_hit); |  | 
| 4307         push(@row_right, [[undef, "headerItem", "Lines:"], |  | 
| 4308                           [undef, "headerCovTableEntry", $lines_hit], |  | 
| 4309                           [undef, "headerCovTableEntry", $lines_found], |  | 
| 4310                           [undef, "headerCovTableEntry$style", $rate]]) |  | 
| 4311                         if ($type != $HDR_TESTDESC); |  | 
| 4312         # Function coverage |  | 
| 4313         if ($func_coverage) { |  | 
| 4314                 $style = $rate_name[classify_rate($fn_found, $fn_hit, |  | 
| 4315                                                   $fn_med_limit, $fn_hi_limit)]; |  | 
| 4316                 $rate = format_rate($fn_found, $fn_hit); |  | 
| 4317                 push(@row_right, [[undef, "headerItem", "Functions:"], |  | 
| 4318                                   [undef, "headerCovTableEntry", $fn_hit], |  | 
| 4319                                   [undef, "headerCovTableEntry", $fn_found], |  | 
| 4320                                   [undef, "headerCovTableEntry$style", $rate]]) |  | 
| 4321                         if ($type != $HDR_TESTDESC); |  | 
| 4322         } |  | 
| 4323         # Branch coverage |  | 
| 4324         if ($br_coverage) { |  | 
| 4325                 $style = $rate_name[classify_rate($br_found, $br_hit, |  | 
| 4326                                                   $br_med_limit, $br_hi_limit)]; |  | 
| 4327                 $rate = format_rate($br_found, $br_hit); |  | 
| 4328                 push(@row_right, [[undef, "headerItem", "Branches:"], |  | 
| 4329                                   [undef, "headerCovTableEntry", $br_hit], |  | 
| 4330                                   [undef, "headerCovTableEntry", $br_found], |  | 
| 4331                                   [undef, "headerCovTableEntry$style", $rate]]) |  | 
| 4332                         if ($type != $HDR_TESTDESC); |  | 
| 4333         } |  | 
| 4334 |  | 
| 4335         # Print rows |  | 
| 4336         $num_rows = max(scalar(@row_left), scalar(@row_right)); |  | 
| 4337         for ($i = 0; $i < $num_rows; $i++) { |  | 
| 4338                 my $left = $row_left[$i]; |  | 
| 4339                 my $right = $row_right[$i]; |  | 
| 4340 |  | 
| 4341                 if (!defined($left)) { |  | 
| 4342                         $left = [[undef, undef, undef], [undef, undef, undef]]; |  | 
| 4343                 } |  | 
| 4344                 if (!defined($right)) { |  | 
| 4345                         $right = []; |  | 
| 4346                 } |  | 
| 4347                 write_header_line(*HTML_HANDLE, @{$left}, |  | 
| 4348                                   [ $i == 0 ? "5%" : undef, undef, undef], |  | 
| 4349                                   @{$right}); |  | 
| 4350         } |  | 
| 4351 |  | 
| 4352         # Fourth line |  | 
| 4353         write_header_epilog(*HTML_HANDLE, $base_dir); |  | 
| 4354 } |  | 
| 4355 |  | 
| 4356 |  | 
| 4357 # |  | 
| 4358 # get_sorted_keys(hash_ref, sort_type) |  | 
| 4359 # |  | 
| 4360 |  | 
| 4361 sub get_sorted_keys($$) |  | 
| 4362 { |  | 
| 4363         my ($hash, $type) = @_; |  | 
| 4364 |  | 
| 4365         if ($type == $SORT_FILE) { |  | 
| 4366                 # Sort by name |  | 
| 4367                 return sort(keys(%{$hash})); |  | 
| 4368         } elsif ($type == $SORT_LINE) { |  | 
| 4369                 # Sort by line coverage |  | 
| 4370                 return sort({$hash->{$a}[7] <=> $hash->{$b}[7]} keys(%{$hash})); |  | 
| 4371         } elsif ($type == $SORT_FUNC) { |  | 
| 4372                 # Sort by function coverage; |  | 
| 4373                 return sort({$hash->{$a}[8] <=> $hash->{$b}[8]} keys(%{$hash})); |  | 
| 4374         } elsif ($type == $SORT_BRANCH) { |  | 
| 4375                 # Sort by br coverage; |  | 
| 4376                 return sort({$hash->{$a}[9] <=> $hash->{$b}[9]} keys(%{$hash})); |  | 
| 4377         } |  | 
| 4378 } |  | 
| 4379 |  | 
| 4380 sub get_sort_code($$$) |  | 
| 4381 { |  | 
| 4382         my ($link, $alt, $base) = @_; |  | 
| 4383         my $png; |  | 
| 4384         my $link_start; |  | 
| 4385         my $link_end; |  | 
| 4386 |  | 
| 4387         if (!defined($link)) { |  | 
| 4388                 $png = "glass.png"; |  | 
| 4389                 $link_start = ""; |  | 
| 4390                 $link_end = ""; |  | 
| 4391         } else { |  | 
| 4392                 $png = "updown.png"; |  | 
| 4393                 $link_start = '<a href="'.$link.'">'; |  | 
| 4394                 $link_end = "</a>"; |  | 
| 4395         } |  | 
| 4396 |  | 
| 4397         return ' <span class="tableHeadSort">'.$link_start. |  | 
| 4398                '<img src="'.$base.$png.'" width=10 height=14 '. |  | 
| 4399                'alt="'.$alt.'" title="'.$alt.'" border=0>'.$link_end.'</span>'; |  | 
| 4400 } |  | 
| 4401 |  | 
| 4402 sub get_file_code($$$$) |  | 
| 4403 { |  | 
| 4404         my ($type, $text, $sort_button, $base) = @_; |  | 
| 4405         my $result = $text; |  | 
| 4406         my $link; |  | 
| 4407 |  | 
| 4408         if ($sort_button) { |  | 
| 4409                 if ($type == $HEAD_NO_DETAIL) { |  | 
| 4410                         $link = "index.$html_ext"; |  | 
| 4411                 } else { |  | 
| 4412                         $link = "index-detail.$html_ext"; |  | 
| 4413                 } |  | 
| 4414         } |  | 
| 4415         $result .= get_sort_code($link, "Sort by name", $base); |  | 
| 4416 |  | 
| 4417         return $result; |  | 
| 4418 } |  | 
| 4419 |  | 
| 4420 sub get_line_code($$$$$) |  | 
| 4421 { |  | 
| 4422         my ($type, $sort_type, $text, $sort_button, $base) = @_; |  | 
| 4423         my $result = $text; |  | 
| 4424         my $sort_link; |  | 
| 4425 |  | 
| 4426         if ($type == $HEAD_NO_DETAIL) { |  | 
| 4427                 # Just text |  | 
| 4428                 if ($sort_button) { |  | 
| 4429                         $sort_link = "index-sort-l.$html_ext"; |  | 
| 4430                 } |  | 
| 4431         } elsif ($type == $HEAD_DETAIL_HIDDEN) { |  | 
| 4432                 # Text + link to detail view |  | 
| 4433                 $result .= ' ( <a class="detail" href="index-detail'. |  | 
| 4434                            $fileview_sortname[$sort_type].'.'.$html_ext. |  | 
| 4435                            '">show details</a> )'; |  | 
| 4436                 if ($sort_button) { |  | 
| 4437                         $sort_link = "index-sort-l.$html_ext"; |  | 
| 4438                 } |  | 
| 4439         } else { |  | 
| 4440                 # Text + link to standard view |  | 
| 4441                 $result .= ' ( <a class="detail" href="index'. |  | 
| 4442                            $fileview_sortname[$sort_type].'.'.$html_ext. |  | 
| 4443                            '">hide details</a> )'; |  | 
| 4444                 if ($sort_button) { |  | 
| 4445                         $sort_link = "index-detail-sort-l.$html_ext"; |  | 
| 4446                 } |  | 
| 4447         } |  | 
| 4448         # Add sort button |  | 
| 4449         $result .= get_sort_code($sort_link, "Sort by line coverage", $base); |  | 
| 4450 |  | 
| 4451         return $result; |  | 
| 4452 } |  | 
| 4453 |  | 
| 4454 sub get_func_code($$$$) |  | 
| 4455 { |  | 
| 4456         my ($type, $text, $sort_button, $base) = @_; |  | 
| 4457         my $result = $text; |  | 
| 4458         my $link; |  | 
| 4459 |  | 
| 4460         if ($sort_button) { |  | 
| 4461                 if ($type == $HEAD_NO_DETAIL) { |  | 
| 4462                         $link = "index-sort-f.$html_ext"; |  | 
| 4463                 } else { |  | 
| 4464                         $link = "index-detail-sort-f.$html_ext"; |  | 
| 4465                 } |  | 
| 4466         } |  | 
| 4467         $result .= get_sort_code($link, "Sort by function coverage", $base); |  | 
| 4468         return $result; |  | 
| 4469 } |  | 
| 4470 |  | 
| 4471 sub get_br_code($$$$) |  | 
| 4472 { |  | 
| 4473         my ($type, $text, $sort_button, $base) = @_; |  | 
| 4474         my $result = $text; |  | 
| 4475         my $link; |  | 
| 4476 |  | 
| 4477         if ($sort_button) { |  | 
| 4478                 if ($type == $HEAD_NO_DETAIL) { |  | 
| 4479                         $link = "index-sort-b.$html_ext"; |  | 
| 4480                 } else { |  | 
| 4481                         $link = "index-detail-sort-b.$html_ext"; |  | 
| 4482                 } |  | 
| 4483         } |  | 
| 4484         $result .= get_sort_code($link, "Sort by branch coverage", $base); |  | 
| 4485         return $result; |  | 
| 4486 } |  | 
| 4487 |  | 
| 4488 # |  | 
| 4489 # write_file_table(filehandle, base_dir, overview, testhash, testfnchash, |  | 
| 4490 #                  testbrhash, fileview, sort_type) |  | 
| 4491 # |  | 
| 4492 # Write a complete file table. OVERVIEW is a reference to a hash containing |  | 
| 4493 # the following mapping: |  | 
| 4494 # |  | 
| 4495 #   filename -> "lines_found,lines_hit,funcs_found,funcs_hit,page_link, |  | 
| 4496 #                func_link" |  | 
| 4497 # |  | 
| 4498 # TESTHASH is a reference to the following hash: |  | 
| 4499 # |  | 
| 4500 #   filename -> \%testdata |  | 
| 4501 #   %testdata: name of test affecting this file -> \%testcount |  | 
| 4502 #   %testcount: line number -> execution count for a single test |  | 
| 4503 # |  | 
| 4504 # Heading of first column is "Filename" if FILEVIEW is true, "Directory name" |  | 
| 4505 # otherwise. |  | 
| 4506 # |  | 
| 4507 |  | 
| 4508 sub write_file_table(*$$$$$$$) |  | 
| 4509 { |  | 
| 4510         local *HTML_HANDLE = $_[0]; |  | 
| 4511         my $base_dir = $_[1]; |  | 
| 4512         my $overview = $_[2]; |  | 
| 4513         my $testhash = $_[3]; |  | 
| 4514         my $testfnchash = $_[4]; |  | 
| 4515         my $testbrhash = $_[5]; |  | 
| 4516         my $fileview = $_[6]; |  | 
| 4517         my $sort_type = $_[7]; |  | 
| 4518         my $filename; |  | 
| 4519         my $bar_graph; |  | 
| 4520         my $hit; |  | 
| 4521         my $found; |  | 
| 4522         my $fn_found; |  | 
| 4523         my $fn_hit; |  | 
| 4524         my $br_found; |  | 
| 4525         my $br_hit; |  | 
| 4526         my $page_link; |  | 
| 4527         my $testname; |  | 
| 4528         my $testdata; |  | 
| 4529         my $testfncdata; |  | 
| 4530         my $testbrdata; |  | 
| 4531         my %affecting_tests; |  | 
| 4532         my $line_code = ""; |  | 
| 4533         my $func_code; |  | 
| 4534         my $br_code; |  | 
| 4535         my $file_code; |  | 
| 4536         my @head_columns; |  | 
| 4537 |  | 
| 4538         # Determine HTML code for column headings |  | 
| 4539         if (($base_dir ne "") && $show_details) |  | 
| 4540         { |  | 
| 4541                 my $detailed = keys(%{$testhash}); |  | 
| 4542 |  | 
| 4543                 $file_code = get_file_code($detailed ? $HEAD_DETAIL_HIDDEN : |  | 
| 4544                                         $HEAD_NO_DETAIL, |  | 
| 4545                                         $fileview ? "Filename" : "Directory", |  | 
| 4546                                         $sort && $sort_type != $SORT_FILE, |  | 
| 4547                                         $base_dir); |  | 
| 4548                 $line_code = get_line_code($detailed ? $HEAD_DETAIL_SHOWN : |  | 
| 4549                                         $HEAD_DETAIL_HIDDEN, |  | 
| 4550                                         $sort_type, |  | 
| 4551                                         "Line Coverage", |  | 
| 4552                                         $sort && $sort_type != $SORT_LINE, |  | 
| 4553                                         $base_dir); |  | 
| 4554                 $func_code = get_func_code($detailed ? $HEAD_DETAIL_HIDDEN : |  | 
| 4555                                         $HEAD_NO_DETAIL, |  | 
| 4556                                         "Functions", |  | 
| 4557                                         $sort && $sort_type != $SORT_FUNC, |  | 
| 4558                                         $base_dir); |  | 
| 4559                 $br_code = get_br_code($detailed ? $HEAD_DETAIL_HIDDEN : |  | 
| 4560                                         $HEAD_NO_DETAIL, |  | 
| 4561                                         "Branches", |  | 
| 4562                                         $sort && $sort_type != $SORT_BRANCH, |  | 
| 4563                                         $base_dir); |  | 
| 4564         } else { |  | 
| 4565                 $file_code = get_file_code($HEAD_NO_DETAIL, |  | 
| 4566                                         $fileview ? "Filename" : "Directory", |  | 
| 4567                                         $sort && $sort_type != $SORT_FILE, |  | 
| 4568                                         $base_dir); |  | 
| 4569                 $line_code = get_line_code($HEAD_NO_DETAIL, $sort_type, "Line Co
      verage", |  | 
| 4570                                         $sort && $sort_type != $SORT_LINE, |  | 
| 4571                                         $base_dir); |  | 
| 4572                 $func_code = get_func_code($HEAD_NO_DETAIL, "Functions", |  | 
| 4573                                         $sort && $sort_type != $SORT_FUNC, |  | 
| 4574                                         $base_dir); |  | 
| 4575                 $br_code = get_br_code($HEAD_NO_DETAIL, "Branches", |  | 
| 4576                                         $sort && $sort_type != $SORT_BRANCH, |  | 
| 4577                                         $base_dir); |  | 
| 4578         } |  | 
| 4579         push(@head_columns, [ $line_code, 3 ]); |  | 
| 4580         push(@head_columns, [ $func_code, 2]) if ($func_coverage); |  | 
| 4581         push(@head_columns, [ $br_code, 2]) if ($br_coverage); |  | 
| 4582 |  | 
| 4583         write_file_table_prolog(*HTML_HANDLE, $file_code, @head_columns); |  | 
| 4584 |  | 
| 4585         foreach $filename (get_sorted_keys($overview, $sort_type)) |  | 
| 4586         { |  | 
| 4587                 my @columns; |  | 
| 4588                 ($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit, |  | 
| 4589                  $page_link) = @{$overview->{$filename}}; |  | 
| 4590 |  | 
| 4591                 # Line coverage |  | 
| 4592                 push(@columns, [$found, $hit, $med_limit, $hi_limit, 1]); |  | 
| 4593                 # Function coverage |  | 
| 4594                 if ($func_coverage) { |  | 
| 4595                         push(@columns, [$fn_found, $fn_hit, $fn_med_limit, |  | 
| 4596                                         $fn_hi_limit, 0]); |  | 
| 4597                 } |  | 
| 4598                 # Branch coverage |  | 
| 4599                 if ($br_coverage) { |  | 
| 4600                         push(@columns, [$br_found, $br_hit, $br_med_limit, |  | 
| 4601                                         $br_hi_limit, 0]); |  | 
| 4602                 } |  | 
| 4603                 write_file_table_entry(*HTML_HANDLE, $base_dir, $filename, |  | 
| 4604                                        $page_link, @columns); |  | 
| 4605 |  | 
| 4606                 $testdata = $testhash->{$filename}; |  | 
| 4607                 $testfncdata = $testfnchash->{$filename}; |  | 
| 4608                 $testbrdata = $testbrhash->{$filename}; |  | 
| 4609 |  | 
| 4610                 # Check whether we should write test specific coverage |  | 
| 4611                 # as well |  | 
| 4612                 if (!($show_details && $testdata)) { next; } |  | 
| 4613 |  | 
| 4614                 # Filter out those tests that actually affect this file |  | 
| 4615                 %affecting_tests = %{ get_affecting_tests($testdata, |  | 
| 4616                                         $testfncdata, $testbrdata) }; |  | 
| 4617 |  | 
| 4618                 # Does any of the tests affect this file at all? |  | 
| 4619                 if (!%affecting_tests) { next; } |  | 
| 4620 |  | 
| 4621                 foreach $testname (keys(%affecting_tests)) |  | 
| 4622                 { |  | 
| 4623                         my @results; |  | 
| 4624                         ($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) = |  | 
| 4625                                 split(",", $affecting_tests{$testname}); |  | 
| 4626 |  | 
| 4627                         # Insert link to description of available |  | 
| 4628                         if ($test_description{$testname}) |  | 
| 4629                         { |  | 
| 4630                                 $testname = "<a href=\"$base_dir". |  | 
| 4631                                             "descriptions.$html_ext#$testname\">
      ". |  | 
| 4632                                             "$testname</a>"; |  | 
| 4633                         } |  | 
| 4634 |  | 
| 4635                         push(@results, [$found, $hit]); |  | 
| 4636                         push(@results, [$fn_found, $fn_hit]) if ($func_coverage)
      ; |  | 
| 4637                         push(@results, [$br_found, $br_hit]) if ($br_coverage); |  | 
| 4638                         write_file_table_detail_entry(*HTML_HANDLE, $testname, |  | 
| 4639                                 @results); |  | 
| 4640                 } |  | 
| 4641         } |  | 
| 4642 |  | 
| 4643         write_file_table_epilog(*HTML_HANDLE); |  | 
| 4644 } |  | 
| 4645 |  | 
| 4646 |  | 
| 4647 # |  | 
| 4648 # get_found_and_hit(hash) |  | 
| 4649 # |  | 
| 4650 # Return the count for entries (found) and entries with an execution count |  | 
| 4651 # greater than zero (hit) in a hash (linenumber -> execution count) as |  | 
| 4652 # a list (found, hit) |  | 
| 4653 # |  | 
| 4654 |  | 
| 4655 sub get_found_and_hit($) |  | 
| 4656 { |  | 
| 4657         my %hash = %{$_[0]}; |  | 
| 4658         my $found = 0; |  | 
| 4659         my $hit = 0; |  | 
| 4660 |  | 
| 4661         # Calculate sum |  | 
| 4662         $found = 0; |  | 
| 4663         $hit = 0; |  | 
| 4664 |  | 
| 4665         foreach (keys(%hash)) |  | 
| 4666         { |  | 
| 4667                 $found++; |  | 
| 4668                 if ($hash{$_}>0) { $hit++; } |  | 
| 4669         } |  | 
| 4670 |  | 
| 4671         return ($found, $hit); |  | 
| 4672 } |  | 
| 4673 |  | 
| 4674 |  | 
| 4675 # |  | 
| 4676 # get_func_found_and_hit(sumfnccount) |  | 
| 4677 # |  | 
| 4678 # Return (f_found, f_hit) for sumfnccount |  | 
| 4679 # |  | 
| 4680 |  | 
| 4681 sub get_func_found_and_hit($) |  | 
| 4682 { |  | 
| 4683         my ($sumfnccount) = @_; |  | 
| 4684         my $function; |  | 
| 4685         my $fn_found; |  | 
| 4686         my $fn_hit; |  | 
| 4687 |  | 
| 4688         $fn_found = scalar(keys(%{$sumfnccount})); |  | 
| 4689         $fn_hit = 0; |  | 
| 4690         foreach $function (keys(%{$sumfnccount})) { |  | 
| 4691                 if ($sumfnccount->{$function} > 0) { |  | 
| 4692                         $fn_hit++; |  | 
| 4693                 } |  | 
| 4694         } |  | 
| 4695         return ($fn_found, $fn_hit); |  | 
| 4696 } |  | 
| 4697 |  | 
| 4698 |  | 
| 4699 # |  | 
| 4700 # br_taken_to_num(taken) |  | 
| 4701 # |  | 
| 4702 # Convert a branch taken value .info format to number format. |  | 
| 4703 # |  | 
| 4704 |  | 
| 4705 sub br_taken_to_num($) |  | 
| 4706 { |  | 
| 4707         my ($taken) = @_; |  | 
| 4708 |  | 
| 4709         return 0 if ($taken eq '-'); |  | 
| 4710         return $taken + 1; |  | 
| 4711 } |  | 
| 4712 |  | 
| 4713 |  | 
| 4714 # |  | 
| 4715 # br_num_to_taken(taken) |  | 
| 4716 # |  | 
| 4717 # Convert a branch taken value in number format to .info format. |  | 
| 4718 # |  | 
| 4719 |  | 
| 4720 sub br_num_to_taken($) |  | 
| 4721 { |  | 
| 4722         my ($taken) = @_; |  | 
| 4723 |  | 
| 4724         return '-' if ($taken == 0); |  | 
| 4725         return $taken - 1; |  | 
| 4726 } |  | 
| 4727 |  | 
| 4728 |  | 
| 4729 # |  | 
| 4730 # br_taken_add(taken1, taken2) |  | 
| 4731 # |  | 
| 4732 # Return the result of taken1 + taken2 for 'branch taken' values. |  | 
| 4733 # |  | 
| 4734 |  | 
| 4735 sub br_taken_add($$) |  | 
| 4736 { |  | 
| 4737         my ($t1, $t2) = @_; |  | 
| 4738 |  | 
| 4739         return $t1 if (!defined($t2)); |  | 
| 4740         return $t2 if (!defined($t1)); |  | 
| 4741         return $t1 if ($t2 eq '-'); |  | 
| 4742         return $t2 if ($t1 eq '-'); |  | 
| 4743         return $t1 + $t2; |  | 
| 4744 } |  | 
| 4745 |  | 
| 4746 |  | 
| 4747 # |  | 
| 4748 # br_taken_sub(taken1, taken2) |  | 
| 4749 # |  | 
| 4750 # Return the result of taken1 - taken2 for 'branch taken' values. Return 0 |  | 
| 4751 # if the result would become negative. |  | 
| 4752 # |  | 
| 4753 |  | 
| 4754 sub br_taken_sub($$) |  | 
| 4755 { |  | 
| 4756         my ($t1, $t2) = @_; |  | 
| 4757 |  | 
| 4758         return $t1 if (!defined($t2)); |  | 
| 4759         return undef if (!defined($t1)); |  | 
| 4760         return $t1 if ($t1 eq '-'); |  | 
| 4761         return $t1 if ($t2 eq '-'); |  | 
| 4762         return 0 if $t2 > $t1; |  | 
| 4763         return $t1 - $t2; |  | 
| 4764 } |  | 
| 4765 |  | 
| 4766 |  | 
| 4767 # |  | 
| 4768 # br_ivec_len(vector) |  | 
| 4769 # |  | 
| 4770 # Return the number of entries in the branch coverage vector. |  | 
| 4771 # |  | 
| 4772 |  | 
| 4773 sub br_ivec_len($) |  | 
| 4774 { |  | 
| 4775         my ($vec) = @_; |  | 
| 4776 |  | 
| 4777         return 0 if (!defined($vec)); |  | 
| 4778         return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES; |  | 
| 4779 } |  | 
| 4780 |  | 
| 4781 |  | 
| 4782 # |  | 
| 4783 # br_ivec_get(vector, number) |  | 
| 4784 # |  | 
| 4785 # Return an entry from the branch coverage vector. |  | 
| 4786 # |  | 
| 4787 |  | 
| 4788 sub br_ivec_get($$) |  | 
| 4789 { |  | 
| 4790         my ($vec, $num) = @_; |  | 
| 4791         my $block; |  | 
| 4792         my $branch; |  | 
| 4793         my $taken; |  | 
| 4794         my $offset = $num * $BR_VEC_ENTRIES; |  | 
| 4795 |  | 
| 4796         # Retrieve data from vector |  | 
| 4797         $block  = vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH); |  | 
| 4798         $branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH); |  | 
| 4799         $taken  = vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH); |  | 
| 4800 |  | 
| 4801         # Decode taken value from an integer |  | 
| 4802         $taken = br_num_to_taken($taken); |  | 
| 4803 |  | 
| 4804         return ($block, $branch, $taken); |  | 
| 4805 } |  | 
| 4806 |  | 
| 4807 |  | 
| 4808 # |  | 
| 4809 # br_ivec_push(vector, block, branch, taken) |  | 
| 4810 # |  | 
| 4811 # Add an entry to the branch coverage vector. If an entry with the same |  | 
| 4812 # branch ID already exists, add the corresponding taken values. |  | 
| 4813 # |  | 
| 4814 |  | 
| 4815 sub br_ivec_push($$$$) |  | 
| 4816 { |  | 
| 4817         my ($vec, $block, $branch, $taken) = @_; |  | 
| 4818         my $offset; |  | 
| 4819         my $num = br_ivec_len($vec); |  | 
| 4820         my $i; |  | 
| 4821 |  | 
| 4822         $vec = "" if (!defined($vec)); |  | 
| 4823 |  | 
| 4824         # Check if branch already exists in vector |  | 
| 4825         for ($i = 0; $i < $num; $i++) { |  | 
| 4826                 my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i); |  | 
| 4827 |  | 
| 4828                 next if ($v_block != $block || $v_branch != $branch); |  | 
| 4829 |  | 
| 4830                 # Add taken counts |  | 
| 4831                 $taken = br_taken_add($taken, $v_taken); |  | 
| 4832                 last; |  | 
| 4833         } |  | 
| 4834 |  | 
| 4835         $offset = $i * $BR_VEC_ENTRIES; |  | 
| 4836         $taken = br_taken_to_num($taken); |  | 
| 4837 |  | 
| 4838         # Add to vector |  | 
| 4839         vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block; |  | 
| 4840         vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch; |  | 
| 4841         vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken; |  | 
| 4842 |  | 
| 4843         return $vec; |  | 
| 4844 } |  | 
| 4845 |  | 
| 4846 |  | 
| 4847 # |  | 
| 4848 # get_br_found_and_hit(sumbrcount) |  | 
| 4849 # |  | 
| 4850 # Return (br_found, br_hit) for sumbrcount |  | 
| 4851 # |  | 
| 4852 |  | 
| 4853 sub get_br_found_and_hit($) |  | 
| 4854 { |  | 
| 4855         my ($sumbrcount) = @_; |  | 
| 4856         my $line; |  | 
| 4857         my $br_found = 0; |  | 
| 4858         my $br_hit = 0; |  | 
| 4859 |  | 
| 4860         foreach $line (keys(%{$sumbrcount})) { |  | 
| 4861                 my $brdata = $sumbrcount->{$line}; |  | 
| 4862                 my $i; |  | 
| 4863                 my $num = br_ivec_len($brdata); |  | 
| 4864 |  | 
| 4865                 for ($i = 0; $i < $num; $i++) { |  | 
| 4866                         my $taken; |  | 
| 4867 |  | 
| 4868                         (undef, undef, $taken) = br_ivec_get($brdata, $i); |  | 
| 4869 |  | 
| 4870                         $br_found++; |  | 
| 4871                         $br_hit++ if ($taken ne "-" && $taken > 0); |  | 
| 4872                 } |  | 
| 4873         } |  | 
| 4874 |  | 
| 4875         return ($br_found, $br_hit); |  | 
| 4876 } |  | 
| 4877 |  | 
| 4878 |  | 
| 4879 # |  | 
| 4880 # get_affecting_tests(testdata, testfncdata, testbrdata) |  | 
| 4881 # |  | 
| 4882 # HASHREF contains a mapping filename -> (linenumber -> exec count). Return |  | 
| 4883 # a hash containing mapping filename -> "lines found, lines hit" for each |  | 
| 4884 # filename which has a nonzero hit count. |  | 
| 4885 # |  | 
| 4886 |  | 
| 4887 sub get_affecting_tests($$$) |  | 
| 4888 { |  | 
| 4889         my ($testdata, $testfncdata, $testbrdata) = @_; |  | 
| 4890         my $testname; |  | 
| 4891         my $testcount; |  | 
| 4892         my $testfnccount; |  | 
| 4893         my $testbrcount; |  | 
| 4894         my %result; |  | 
| 4895         my $found; |  | 
| 4896         my $hit; |  | 
| 4897         my $fn_found; |  | 
| 4898         my $fn_hit; |  | 
| 4899         my $br_found; |  | 
| 4900         my $br_hit; |  | 
| 4901 |  | 
| 4902         foreach $testname (keys(%{$testdata})) |  | 
| 4903         { |  | 
| 4904                 # Get (line number -> count) hash for this test case |  | 
| 4905                 $testcount = $testdata->{$testname}; |  | 
| 4906                 $testfnccount = $testfncdata->{$testname}; |  | 
| 4907                 $testbrcount = $testbrdata->{$testname}; |  | 
| 4908 |  | 
| 4909                 # Calculate sum |  | 
| 4910                 ($found, $hit) = get_found_and_hit($testcount); |  | 
| 4911                 ($fn_found, $fn_hit) = get_func_found_and_hit($testfnccount); |  | 
| 4912                 ($br_found, $br_hit) = get_br_found_and_hit($testbrcount); |  | 
| 4913 |  | 
| 4914                 if ($hit>0) |  | 
| 4915                 { |  | 
| 4916                         $result{$testname} = "$found,$hit,$fn_found,$fn_hit,". |  | 
| 4917                                              "$br_found,$br_hit"; |  | 
| 4918                 } |  | 
| 4919         } |  | 
| 4920 |  | 
| 4921         return(\%result); |  | 
| 4922 } |  | 
| 4923 |  | 
| 4924 |  | 
| 4925 sub get_hash_reverse($) |  | 
| 4926 { |  | 
| 4927         my ($hash) = @_; |  | 
| 4928         my %result; |  | 
| 4929 |  | 
| 4930         foreach (keys(%{$hash})) { |  | 
| 4931                 $result{$hash->{$_}} = $_; |  | 
| 4932         } |  | 
| 4933 |  | 
| 4934         return \%result; |  | 
| 4935 } |  | 
| 4936 |  | 
| 4937 # |  | 
| 4938 # write_source(filehandle, source_filename, count_data, checksum_data, |  | 
| 4939 #              converted_data, func_data, sumbrcount) |  | 
| 4940 # |  | 
| 4941 # Write an HTML view of a source code file. Returns a list containing |  | 
| 4942 # data as needed by gen_png(). |  | 
| 4943 # |  | 
| 4944 # Die on error. |  | 
| 4945 # |  | 
| 4946 |  | 
| 4947 sub write_source($$$$$$$) |  | 
| 4948 { |  | 
| 4949         local *HTML_HANDLE = $_[0]; |  | 
| 4950         local *SOURCE_HANDLE; |  | 
| 4951         my $source_filename = $_[1]; |  | 
| 4952         my %count_data; |  | 
| 4953         my $line_number; |  | 
| 4954         my @result; |  | 
| 4955         my $checkdata = $_[3]; |  | 
| 4956         my $converted = $_[4]; |  | 
| 4957         my $funcdata  = $_[5]; |  | 
| 4958         my $sumbrcount = $_[6]; |  | 
| 4959         my $datafunc = get_hash_reverse($funcdata); |  | 
| 4960         my $add_anchor; |  | 
| 4961 |  | 
| 4962         if ($_[2]) |  | 
| 4963         { |  | 
| 4964                 %count_data = %{$_[2]}; |  | 
| 4965         } |  | 
| 4966 |  | 
| 4967         open(SOURCE_HANDLE, "<".$source_filename) |  | 
| 4968                 or die("ERROR: cannot open $source_filename for reading!\n"); |  | 
| 4969 |  | 
| 4970         write_source_prolog(*HTML_HANDLE); |  | 
| 4971 |  | 
| 4972         for ($line_number = 1; <SOURCE_HANDLE> ; $line_number++) |  | 
| 4973         { |  | 
| 4974                 chomp($_); |  | 
| 4975 |  | 
| 4976                 # Also remove CR from line-end |  | 
| 4977                 s/\015$//; |  | 
| 4978 |  | 
| 4979                 # Source code matches coverage data? |  | 
| 4980                 if (defined($checkdata->{$line_number}) && |  | 
| 4981                     ($checkdata->{$line_number} ne md5_base64($_))) |  | 
| 4982                 { |  | 
| 4983                         die("ERROR: checksum mismatch  at $source_filename:". |  | 
| 4984                             "$line_number\n"); |  | 
| 4985                 } |  | 
| 4986 |  | 
| 4987                 $add_anchor = 0; |  | 
| 4988                 if ($frames) { |  | 
| 4989                         if (($line_number - 1) % $nav_resolution == 0) { |  | 
| 4990                                 $add_anchor = 1; |  | 
| 4991                         } |  | 
| 4992                 } |  | 
| 4993                 if ($func_coverage) { |  | 
| 4994                         if ($line_number == 1) { |  | 
| 4995                                 $add_anchor = 1; |  | 
| 4996                         } elsif (defined($datafunc->{$line_number + |  | 
| 4997                                                      $func_offset})) { |  | 
| 4998                                 $add_anchor = 1; |  | 
| 4999                         } |  | 
| 5000                 } |  | 
| 5001                 push (@result, |  | 
| 5002                       write_source_line(HTML_HANDLE, $line_number, |  | 
| 5003                                         $_, $count_data{$line_number}, |  | 
| 5004                                         $converted->{$line_number}, |  | 
| 5005                                         $sumbrcount->{$line_number}, $add_anchor
      )); |  | 
| 5006         } |  | 
| 5007 |  | 
| 5008         close(SOURCE_HANDLE); |  | 
| 5009         write_source_epilog(*HTML_HANDLE); |  | 
| 5010         return(@result); |  | 
| 5011 } |  | 
| 5012 |  | 
| 5013 |  | 
| 5014 sub funcview_get_func_code($$$) |  | 
| 5015 { |  | 
| 5016         my ($name, $base, $type) = @_; |  | 
| 5017         my $result; |  | 
| 5018         my $link; |  | 
| 5019 |  | 
| 5020         if ($sort && $type == 1) { |  | 
| 5021                 $link = "$name.func.$html_ext"; |  | 
| 5022         } |  | 
| 5023         $result = "Function Name"; |  | 
| 5024         $result .= get_sort_code($link, "Sort by function name", $base); |  | 
| 5025 |  | 
| 5026         return $result; |  | 
| 5027 } |  | 
| 5028 |  | 
| 5029 sub funcview_get_count_code($$$) |  | 
| 5030 { |  | 
| 5031         my ($name, $base, $type) = @_; |  | 
| 5032         my $result; |  | 
| 5033         my $link; |  | 
| 5034 |  | 
| 5035         if ($sort && $type == 0) { |  | 
| 5036                 $link = "$name.func-sort-c.$html_ext"; |  | 
| 5037         } |  | 
| 5038         $result = "Hit count"; |  | 
| 5039         $result .= get_sort_code($link, "Sort by hit count", $base); |  | 
| 5040 |  | 
| 5041         return $result; |  | 
| 5042 } |  | 
| 5043 |  | 
| 5044 # |  | 
| 5045 # funcview_get_sorted(funcdata, sumfncdata, sort_type) |  | 
| 5046 # |  | 
| 5047 # Depending on the value of sort_type, return a list of functions sorted |  | 
| 5048 # by name (type 0) or by the associated call count (type 1). |  | 
| 5049 # |  | 
| 5050 |  | 
| 5051 sub funcview_get_sorted($$$) |  | 
| 5052 { |  | 
| 5053         my ($funcdata, $sumfncdata, $type) = @_; |  | 
| 5054 |  | 
| 5055         if ($type == 0) { |  | 
| 5056                 return sort(keys(%{$funcdata})); |  | 
| 5057         } |  | 
| 5058         return sort({$sumfncdata->{$b} <=> $sumfncdata->{$a}} |  | 
| 5059                     keys(%{$sumfncdata})); |  | 
| 5060 } |  | 
| 5061 |  | 
| 5062 # |  | 
| 5063 # write_function_table(filehandle, source_file, sumcount, funcdata, |  | 
| 5064 #                      sumfnccount, testfncdata, sumbrcount, testbrdata, |  | 
| 5065 #                      base_name, base_dir, sort_type) |  | 
| 5066 # |  | 
| 5067 # Write an HTML table listing all functions in a source file, including |  | 
| 5068 # also function call counts and line coverages inside of each function. |  | 
| 5069 # |  | 
| 5070 # Die on error. |  | 
| 5071 # |  | 
| 5072 |  | 
| 5073 sub write_function_table(*$$$$$$$$$$) |  | 
| 5074 { |  | 
| 5075         local *HTML_HANDLE = $_[0]; |  | 
| 5076         my $source = $_[1]; |  | 
| 5077         my $sumcount = $_[2]; |  | 
| 5078         my $funcdata = $_[3]; |  | 
| 5079         my $sumfncdata = $_[4]; |  | 
| 5080         my $testfncdata = $_[5]; |  | 
| 5081         my $sumbrcount = $_[6]; |  | 
| 5082         my $testbrdata = $_[7]; |  | 
| 5083         my $name = $_[8]; |  | 
| 5084         my $base = $_[9]; |  | 
| 5085         my $type = $_[10]; |  | 
| 5086         my $func; |  | 
| 5087         my $func_code; |  | 
| 5088         my $count_code; |  | 
| 5089 |  | 
| 5090         # Get HTML code for headings |  | 
| 5091         $func_code = funcview_get_func_code($name, $base, $type); |  | 
| 5092         $count_code = funcview_get_count_code($name, $base, $type); |  | 
| 5093         write_html(*HTML_HANDLE, <<END_OF_HTML) |  | 
| 5094           <center> |  | 
| 5095           <table width="60%" cellpadding=1 cellspacing=1 border=0> |  | 
| 5096             <tr><td><br></td></tr> |  | 
| 5097             <tr> |  | 
| 5098               <td width="80%" class="tableHead">$func_code</td> |  | 
| 5099               <td width="20%" class="tableHead">$count_code</td> |  | 
| 5100             </tr> |  | 
| 5101 END_OF_HTML |  | 
| 5102         ; |  | 
| 5103 |  | 
| 5104         # Get a sorted table |  | 
| 5105         foreach $func (funcview_get_sorted($funcdata, $sumfncdata, $type)) { |  | 
| 5106                 if (!defined($funcdata->{$func})) |  | 
| 5107                 { |  | 
| 5108                         next; |  | 
| 5109                 } |  | 
| 5110 |  | 
| 5111                 my $startline = $funcdata->{$func} - $func_offset; |  | 
| 5112                 my $name = $func; |  | 
| 5113                 my $count = $sumfncdata->{$name}; |  | 
| 5114                 my $countstyle; |  | 
| 5115 |  | 
| 5116                 # Demangle C++ function names if requested |  | 
| 5117                 if ($demangle_cpp) { |  | 
| 5118                         $name = `c++filt "$name"`; |  | 
| 5119                         chomp($name); |  | 
| 5120                 } |  | 
| 5121                 # Escape any remaining special characters |  | 
| 5122                 $name = escape_html($name); |  | 
| 5123                 if ($startline < 1) { |  | 
| 5124                         $startline = 1; |  | 
| 5125                 } |  | 
| 5126                 if ($count == 0) { |  | 
| 5127                         $countstyle = "coverFnLo"; |  | 
| 5128                 } else { |  | 
| 5129                         $countstyle = "coverFnHi"; |  | 
| 5130                 } |  | 
| 5131 |  | 
| 5132                 write_html(*HTML_HANDLE, <<END_OF_HTML) |  | 
| 5133             <tr> |  | 
| 5134               <td class="coverFn"><a href="$source#$startline">$name</a></td> |  | 
| 5135               <td class="$countstyle">$count</td> |  | 
| 5136             </tr> |  | 
| 5137 END_OF_HTML |  | 
| 5138                 ; |  | 
| 5139         } |  | 
| 5140         write_html(*HTML_HANDLE, <<END_OF_HTML) |  | 
| 5141           </table> |  | 
| 5142           <br> |  | 
| 5143           </center> |  | 
| 5144 END_OF_HTML |  | 
| 5145         ; |  | 
| 5146 } |  | 
| 5147 |  | 
| 5148 |  | 
| 5149 # |  | 
| 5150 # info(printf_parameter) |  | 
| 5151 # |  | 
| 5152 # Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag |  | 
| 5153 # is not set. |  | 
| 5154 # |  | 
| 5155 |  | 
| 5156 sub info(@) |  | 
| 5157 { |  | 
| 5158         if (!$quiet) |  | 
| 5159         { |  | 
| 5160                 # Print info string |  | 
| 5161                 printf(@_); |  | 
| 5162         } |  | 
| 5163 } |  | 
| 5164 |  | 
| 5165 |  | 
| 5166 # |  | 
| 5167 # subtract_counts(data_ref, base_ref) |  | 
| 5168 # |  | 
| 5169 |  | 
| 5170 sub subtract_counts($$) |  | 
| 5171 { |  | 
| 5172         my %data = %{$_[0]}; |  | 
| 5173         my %base = %{$_[1]}; |  | 
| 5174         my $line; |  | 
| 5175         my $data_count; |  | 
| 5176         my $base_count; |  | 
| 5177         my $hit = 0; |  | 
| 5178         my $found = 0; |  | 
| 5179 |  | 
| 5180         foreach $line (keys(%data)) |  | 
| 5181         { |  | 
| 5182                 $found++; |  | 
| 5183                 $data_count = $data{$line}; |  | 
| 5184                 $base_count = $base{$line}; |  | 
| 5185 |  | 
| 5186                 if (defined($base_count)) |  | 
| 5187                 { |  | 
| 5188                         $data_count -= $base_count; |  | 
| 5189 |  | 
| 5190                         # Make sure we don't get negative numbers |  | 
| 5191                         if ($data_count<0) { $data_count = 0; } |  | 
| 5192                 } |  | 
| 5193 |  | 
| 5194                 $data{$line} = $data_count; |  | 
| 5195                 if ($data_count > 0) { $hit++; } |  | 
| 5196         } |  | 
| 5197 |  | 
| 5198         return (\%data, $found, $hit); |  | 
| 5199 } |  | 
| 5200 |  | 
| 5201 |  | 
| 5202 # |  | 
| 5203 # subtract_fnccounts(data, base) |  | 
| 5204 # |  | 
| 5205 # Subtract function call counts found in base from those in data. |  | 
| 5206 # Return (data, f_found, f_hit). |  | 
| 5207 # |  | 
| 5208 |  | 
| 5209 sub subtract_fnccounts($$) |  | 
| 5210 { |  | 
| 5211         my %data; |  | 
| 5212         my %base; |  | 
| 5213         my $func; |  | 
| 5214         my $data_count; |  | 
| 5215         my $base_count; |  | 
| 5216         my $fn_hit = 0; |  | 
| 5217         my $fn_found = 0; |  | 
| 5218 |  | 
| 5219         %data = %{$_[0]} if (defined($_[0])); |  | 
| 5220         %base = %{$_[1]} if (defined($_[1])); |  | 
| 5221         foreach $func (keys(%data)) { |  | 
| 5222                 $fn_found++; |  | 
| 5223                 $data_count = $data{$func}; |  | 
| 5224                 $base_count = $base{$func}; |  | 
| 5225 |  | 
| 5226                 if (defined($base_count)) { |  | 
| 5227                         $data_count -= $base_count; |  | 
| 5228 |  | 
| 5229                         # Make sure we don't get negative numbers |  | 
| 5230                         if ($data_count < 0) { |  | 
| 5231                                 $data_count = 0; |  | 
| 5232                         } |  | 
| 5233                 } |  | 
| 5234 |  | 
| 5235                 $data{$func} = $data_count; |  | 
| 5236                 if ($data_count > 0) { |  | 
| 5237                         $fn_hit++; |  | 
| 5238                 } |  | 
| 5239         } |  | 
| 5240 |  | 
| 5241         return (\%data, $fn_found, $fn_hit); |  | 
| 5242 } |  | 
| 5243 |  | 
| 5244 |  | 
| 5245 # |  | 
| 5246 # apply_baseline(data_ref, baseline_ref) |  | 
| 5247 # |  | 
| 5248 # Subtract the execution counts found in the baseline hash referenced by |  | 
| 5249 # BASELINE_REF from actual data in DATA_REF. |  | 
| 5250 # |  | 
| 5251 |  | 
| 5252 sub apply_baseline($$) |  | 
| 5253 { |  | 
| 5254         my %data_hash = %{$_[0]}; |  | 
| 5255         my %base_hash = %{$_[1]}; |  | 
| 5256         my $filename; |  | 
| 5257         my $testname; |  | 
| 5258         my $data; |  | 
| 5259         my $data_testdata; |  | 
| 5260         my $data_funcdata; |  | 
| 5261         my $data_checkdata; |  | 
| 5262         my $data_testfncdata; |  | 
| 5263         my $data_testbrdata; |  | 
| 5264         my $data_count; |  | 
| 5265         my $data_testfnccount; |  | 
| 5266         my $data_testbrcount; |  | 
| 5267         my $base; |  | 
| 5268         my $base_checkdata; |  | 
| 5269         my $base_sumfnccount; |  | 
| 5270         my $base_sumbrcount; |  | 
| 5271         my $base_count; |  | 
| 5272         my $sumcount; |  | 
| 5273         my $sumfnccount; |  | 
| 5274         my $sumbrcount; |  | 
| 5275         my $found; |  | 
| 5276         my $hit; |  | 
| 5277         my $fn_found; |  | 
| 5278         my $fn_hit; |  | 
| 5279         my $br_found; |  | 
| 5280         my $br_hit; |  | 
| 5281 |  | 
| 5282         foreach $filename (keys(%data_hash)) |  | 
| 5283         { |  | 
| 5284                 # Get data set for data and baseline |  | 
| 5285                 $data = $data_hash{$filename}; |  | 
| 5286                 $base = $base_hash{$filename}; |  | 
| 5287 |  | 
| 5288                 # Skip data entries for which no base entry exists |  | 
| 5289                 if (!defined($base)) |  | 
| 5290                 { |  | 
| 5291                         next; |  | 
| 5292                 } |  | 
| 5293 |  | 
| 5294                 # Get set entries for data and baseline |  | 
| 5295                 ($data_testdata, undef, $data_funcdata, $data_checkdata, |  | 
| 5296                  $data_testfncdata, undef, $data_testbrdata) = |  | 
| 5297                         get_info_entry($data); |  | 
| 5298                 (undef, $base_count, undef, $base_checkdata, undef, |  | 
| 5299                  $base_sumfnccount, undef, $base_sumbrcount) = |  | 
| 5300                         get_info_entry($base); |  | 
| 5301 |  | 
| 5302                 # Check for compatible checksums |  | 
| 5303                 merge_checksums($data_checkdata, $base_checkdata, $filename); |  | 
| 5304 |  | 
| 5305                 # sumcount has to be calculated anew |  | 
| 5306                 $sumcount = {}; |  | 
| 5307                 $sumfnccount = {}; |  | 
| 5308                 $sumbrcount = {}; |  | 
| 5309 |  | 
| 5310                 # For each test case, subtract test specific counts |  | 
| 5311                 foreach $testname (keys(%{$data_testdata})) |  | 
| 5312                 { |  | 
| 5313                         # Get counts of both data and baseline |  | 
| 5314                         $data_count = $data_testdata->{$testname}; |  | 
| 5315                         $data_testfnccount = $data_testfncdata->{$testname}; |  | 
| 5316                         $data_testbrcount = $data_testbrdata->{$testname}; |  | 
| 5317 |  | 
| 5318                         ($data_count, undef, $hit) = |  | 
| 5319                                 subtract_counts($data_count, $base_count); |  | 
| 5320                         ($data_testfnccount) = |  | 
| 5321                                 subtract_fnccounts($data_testfnccount, |  | 
| 5322                                                    $base_sumfnccount); |  | 
| 5323                         ($data_testbrcount) = |  | 
| 5324                                 combine_brcount($data_testbrcount, |  | 
| 5325                                                  $base_sumbrcount, $BR_SUB); |  | 
| 5326 |  | 
| 5327 |  | 
| 5328                         # Check whether this test case did hit any line at all |  | 
| 5329                         if ($hit > 0) |  | 
| 5330                         { |  | 
| 5331                                 # Write back resulting hash |  | 
| 5332                                 $data_testdata->{$testname} = $data_count; |  | 
| 5333                                 $data_testfncdata->{$testname} = |  | 
| 5334                                         $data_testfnccount; |  | 
| 5335                                 $data_testbrdata->{$testname} = |  | 
| 5336                                         $data_testbrcount; |  | 
| 5337                         } |  | 
| 5338                         else |  | 
| 5339                         { |  | 
| 5340                                 # Delete test case which did not impact this |  | 
| 5341                                 # file |  | 
| 5342                                 delete($data_testdata->{$testname}); |  | 
| 5343                                 delete($data_testfncdata->{$testname}); |  | 
| 5344                                 delete($data_testbrdata->{$testname}); |  | 
| 5345                         } |  | 
| 5346 |  | 
| 5347                         # Add counts to sum of counts |  | 
| 5348                         ($sumcount, $found, $hit) = |  | 
| 5349                                 add_counts($sumcount, $data_count); |  | 
| 5350                         ($sumfnccount, $fn_found, $fn_hit) = |  | 
| 5351                                 add_fnccount($sumfnccount, $data_testfnccount); |  | 
| 5352                         ($sumbrcount, $br_found, $br_hit) = |  | 
| 5353                                 combine_brcount($sumbrcount, $data_testbrcount, |  | 
| 5354                                                 $BR_ADD); |  | 
| 5355                 } |  | 
| 5356 |  | 
| 5357                 # Write back resulting entry |  | 
| 5358                 set_info_entry($data, $data_testdata, $sumcount, $data_funcdata, |  | 
| 5359                                $data_checkdata, $data_testfncdata, $sumfnccount, |  | 
| 5360                                $data_testbrdata, $sumbrcount, $found, $hit, |  | 
| 5361                                $fn_found, $fn_hit, $br_found, $br_hit); |  | 
| 5362 |  | 
| 5363                 $data_hash{$filename} = $data; |  | 
| 5364         } |  | 
| 5365 |  | 
| 5366         return (\%data_hash); |  | 
| 5367 } |  | 
| 5368 |  | 
| 5369 |  | 
| 5370 # |  | 
| 5371 # remove_unused_descriptions() |  | 
| 5372 # |  | 
| 5373 # Removes all test descriptions from the global hash %test_description which |  | 
| 5374 # are not present in %info_data. |  | 
| 5375 # |  | 
| 5376 |  | 
| 5377 sub remove_unused_descriptions() |  | 
| 5378 { |  | 
| 5379         my $filename;           # The current filename |  | 
| 5380         my %test_list;          # Hash containing found test names |  | 
| 5381         my $test_data;          # Reference to hash test_name -> count_data |  | 
| 5382         my $before;             # Initial number of descriptions |  | 
| 5383         my $after;              # Remaining number of descriptions |  | 
| 5384 |  | 
| 5385         $before = scalar(keys(%test_description)); |  | 
| 5386 |  | 
| 5387         foreach $filename (keys(%info_data)) |  | 
| 5388         { |  | 
| 5389                 ($test_data) = get_info_entry($info_data{$filename}); |  | 
| 5390                 foreach (keys(%{$test_data})) |  | 
| 5391                 { |  | 
| 5392                         $test_list{$_} = ""; |  | 
| 5393                 } |  | 
| 5394         } |  | 
| 5395 |  | 
| 5396         # Remove descriptions for tests which are not in our list |  | 
| 5397         foreach (keys(%test_description)) |  | 
| 5398         { |  | 
| 5399                 if (!defined($test_list{$_})) |  | 
| 5400                 { |  | 
| 5401                         delete($test_description{$_}); |  | 
| 5402                 } |  | 
| 5403         } |  | 
| 5404 |  | 
| 5405         $after = scalar(keys(%test_description)); |  | 
| 5406         if ($after < $before) |  | 
| 5407         { |  | 
| 5408                 info("Removed ".($before - $after). |  | 
| 5409                      " unused descriptions, $after remaining.\n"); |  | 
| 5410         } |  | 
| 5411 } |  | 
| 5412 |  | 
| 5413 |  | 
| 5414 # |  | 
| 5415 # apply_prefix(filename, prefix) |  | 
| 5416 # |  | 
| 5417 # If FILENAME begins with PREFIX, remove PREFIX from FILENAME and return |  | 
| 5418 # resulting string, otherwise return FILENAME. |  | 
| 5419 # |  | 
| 5420 |  | 
| 5421 sub apply_prefix($$) |  | 
| 5422 { |  | 
| 5423         my $filename = $_[0]; |  | 
| 5424         my $prefix = $_[1]; |  | 
| 5425 |  | 
| 5426         if (defined($prefix) && ($prefix ne "")) |  | 
| 5427         { |  | 
| 5428                 if ($filename =~ /^\Q$prefix\E\/(.*)$/) |  | 
| 5429                 { |  | 
| 5430                         return substr($filename, length($prefix) + 1); |  | 
| 5431                 } |  | 
| 5432         } |  | 
| 5433 |  | 
| 5434         return $filename; |  | 
| 5435 } |  | 
| 5436 |  | 
| 5437 |  | 
| 5438 # |  | 
| 5439 # system_no_output(mode, parameters) |  | 
| 5440 # |  | 
| 5441 # Call an external program using PARAMETERS while suppressing depending on |  | 
| 5442 # the value of MODE: |  | 
| 5443 # |  | 
| 5444 #   MODE & 1: suppress STDOUT |  | 
| 5445 #   MODE & 2: suppress STDERR |  | 
| 5446 # |  | 
| 5447 # Return 0 on success, non-zero otherwise. |  | 
| 5448 # |  | 
| 5449 |  | 
| 5450 sub system_no_output($@) |  | 
| 5451 { |  | 
| 5452         my $mode = shift; |  | 
| 5453         my $result; |  | 
| 5454         local *OLD_STDERR; |  | 
| 5455         local *OLD_STDOUT; |  | 
| 5456 |  | 
| 5457         # Save old stdout and stderr handles |  | 
| 5458         ($mode & 1) && open(OLD_STDOUT, ">>&STDOUT"); |  | 
| 5459         ($mode & 2) && open(OLD_STDERR, ">>&STDERR"); |  | 
| 5460 |  | 
| 5461         # Redirect to /dev/null |  | 
| 5462         ($mode & 1) && open(STDOUT, ">/dev/null"); |  | 
| 5463         ($mode & 2) && open(STDERR, ">/dev/null"); |  | 
| 5464 |  | 
| 5465         system(@_); |  | 
| 5466         $result = $?; |  | 
| 5467 |  | 
| 5468         # Close redirected handles |  | 
| 5469         ($mode & 1) && close(STDOUT); |  | 
| 5470         ($mode & 2) && close(STDERR); |  | 
| 5471 |  | 
| 5472         # Restore old handles |  | 
| 5473         ($mode & 1) && open(STDOUT, ">>&OLD_STDOUT"); |  | 
| 5474         ($mode & 2) && open(STDERR, ">>&OLD_STDERR"); |  | 
| 5475 |  | 
| 5476         return $result; |  | 
| 5477 } |  | 
| 5478 |  | 
| 5479 |  | 
| 5480 # |  | 
| 5481 # read_config(filename) |  | 
| 5482 # |  | 
| 5483 # Read configuration file FILENAME and return a reference to a hash containing |  | 
| 5484 # all valid key=value pairs found. |  | 
| 5485 # |  | 
| 5486 |  | 
| 5487 sub read_config($) |  | 
| 5488 { |  | 
| 5489         my $filename = $_[0]; |  | 
| 5490         my %result; |  | 
| 5491         my $key; |  | 
| 5492         my $value; |  | 
| 5493         local *HANDLE; |  | 
| 5494 |  | 
| 5495         if (!open(HANDLE, "<$filename")) |  | 
| 5496         { |  | 
| 5497                 warn("WARNING: cannot read configuration file $filename\n"); |  | 
| 5498                 return undef; |  | 
| 5499         } |  | 
| 5500         while (<HANDLE>) |  | 
| 5501         { |  | 
| 5502                 chomp; |  | 
| 5503                 # Skip comments |  | 
| 5504                 s/#.*//; |  | 
| 5505                 # Remove leading blanks |  | 
| 5506                 s/^\s+//; |  | 
| 5507                 # Remove trailing blanks |  | 
| 5508                 s/\s+$//; |  | 
| 5509                 next unless length; |  | 
| 5510                 ($key, $value) = split(/\s*=\s*/, $_, 2); |  | 
| 5511                 if (defined($key) && defined($value)) |  | 
| 5512                 { |  | 
| 5513                         $result{$key} = $value; |  | 
| 5514                 } |  | 
| 5515                 else |  | 
| 5516                 { |  | 
| 5517                         warn("WARNING: malformed statement in line $. ". |  | 
| 5518                              "of configuration file $filename\n"); |  | 
| 5519                 } |  | 
| 5520         } |  | 
| 5521         close(HANDLE); |  | 
| 5522         return \%result; |  | 
| 5523 } |  | 
| 5524 |  | 
| 5525 |  | 
| 5526 # |  | 
| 5527 # apply_config(REF) |  | 
| 5528 # |  | 
| 5529 # REF is a reference to a hash containing the following mapping: |  | 
| 5530 # |  | 
| 5531 #   key_string => var_ref |  | 
| 5532 # |  | 
| 5533 # where KEY_STRING is a keyword and VAR_REF is a reference to an associated |  | 
| 5534 # variable. If the global configuration hash CONFIG contains a value for |  | 
| 5535 # keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. |  | 
| 5536 # |  | 
| 5537 |  | 
| 5538 sub apply_config($) |  | 
| 5539 { |  | 
| 5540         my $ref = $_[0]; |  | 
| 5541 |  | 
| 5542         foreach (keys(%{$ref})) |  | 
| 5543         { |  | 
| 5544                 if (defined($config->{$_})) |  | 
| 5545                 { |  | 
| 5546                         ${$ref->{$_}} = $config->{$_}; |  | 
| 5547                 } |  | 
| 5548         } |  | 
| 5549 } |  | 
| 5550 |  | 
| 5551 |  | 
| 5552 # |  | 
| 5553 # get_html_prolog(FILENAME) |  | 
| 5554 # |  | 
| 5555 # If FILENAME is defined, return contents of file. Otherwise return default |  | 
| 5556 # HTML prolog. Die on error. |  | 
| 5557 # |  | 
| 5558 |  | 
| 5559 sub get_html_prolog($) |  | 
| 5560 { |  | 
| 5561         my $filename = $_[0]; |  | 
| 5562         my $result = ""; |  | 
| 5563 |  | 
| 5564         if (defined($filename)) |  | 
| 5565         { |  | 
| 5566                 local *HANDLE; |  | 
| 5567 |  | 
| 5568                 open(HANDLE, "<".$filename) |  | 
| 5569                         or die("ERROR: cannot open html prolog $filename!\n"); |  | 
| 5570                 while (<HANDLE>) |  | 
| 5571                 { |  | 
| 5572                         $result .= $_; |  | 
| 5573                 } |  | 
| 5574                 close(HANDLE); |  | 
| 5575         } |  | 
| 5576         else |  | 
| 5577         { |  | 
| 5578                 $result = <<END_OF_HTML |  | 
| 5579 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |  | 
| 5580 |  | 
| 5581 <html lang="en"> |  | 
| 5582 |  | 
| 5583 <head> |  | 
| 5584   <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |  | 
| 5585   <title>\@pagetitle\@</title> |  | 
| 5586   <link rel="stylesheet" type="text/css" href="\@basedir\@gcov.css"> |  | 
| 5587 </head> |  | 
| 5588 |  | 
| 5589 <body> |  | 
| 5590 |  | 
| 5591 END_OF_HTML |  | 
| 5592                 ; |  | 
| 5593         } |  | 
| 5594 |  | 
| 5595         return $result; |  | 
| 5596 } |  | 
| 5597 |  | 
| 5598 |  | 
| 5599 # |  | 
| 5600 # get_html_epilog(FILENAME) |  | 
| 5601 # |  | 
| 5602 # If FILENAME is defined, return contents of file. Otherwise return default |  | 
| 5603 # HTML epilog. Die on error. |  | 
| 5604 # |  | 
| 5605 sub get_html_epilog($) |  | 
| 5606 { |  | 
| 5607         my $filename = $_[0]; |  | 
| 5608         my $result = ""; |  | 
| 5609 |  | 
| 5610         if (defined($filename)) |  | 
| 5611         { |  | 
| 5612                 local *HANDLE; |  | 
| 5613 |  | 
| 5614                 open(HANDLE, "<".$filename) |  | 
| 5615                         or die("ERROR: cannot open html epilog $filename!\n"); |  | 
| 5616                 while (<HANDLE>) |  | 
| 5617                 { |  | 
| 5618                         $result .= $_; |  | 
| 5619                 } |  | 
| 5620                 close(HANDLE); |  | 
| 5621         } |  | 
| 5622         else |  | 
| 5623         { |  | 
| 5624                 $result = <<END_OF_HTML |  | 
| 5625 |  | 
| 5626 </body> |  | 
| 5627 </html> |  | 
| 5628 END_OF_HTML |  | 
| 5629                 ; |  | 
| 5630         } |  | 
| 5631 |  | 
| 5632         return $result; |  | 
| 5633 |  | 
| 5634 } |  | 
| 5635 |  | 
| 5636 sub warn_handler($) |  | 
| 5637 { |  | 
| 5638         my ($msg) = @_; |  | 
| 5639 |  | 
| 5640         warn("$tool_name: $msg"); |  | 
| 5641 } |  | 
| 5642 |  | 
| 5643 sub die_handler($) |  | 
| 5644 { |  | 
| 5645         my ($msg) = @_; |  | 
| 5646 |  | 
| 5647         die("$tool_name: $msg"); |  | 
| 5648 } |  | 
| OLD | NEW | 
|---|