| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/perl -w | |
| 2 # | |
| 3 # Copyright (c) International Business Machines Corp., 2002 | |
| 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 # genpng | |
| 21 # | |
| 22 # This script creates an overview PNG image of a source code file by | |
| 23 # representing each source code character by a single pixel. | |
| 24 # | |
| 25 # Note that the PERL module GD.pm is required for this script to work. | |
| 26 # It may be obtained from http://www.cpan.org | |
| 27 # | |
| 28 # History: | |
| 29 # 2002-08-26: created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com> | |
| 30 # | |
| 31 | |
| 32 use strict; | |
| 33 use File::Basename; | |
| 34 use Getopt::Long; | |
| 35 | |
| 36 | |
| 37 # Constants | |
| 38 our $lcov_version = 'LCOV version 1.9'; | |
| 39 our $lcov_url = "http://ltp.sourceforge.net/coverage/lcov.php"; | |
| 40 our $tool_name = basename($0); | |
| 41 | |
| 42 | |
| 43 # Prototypes | |
| 44 sub gen_png($$$@); | |
| 45 sub check_and_load_module($); | |
| 46 sub genpng_print_usage(*); | |
| 47 sub genpng_process_file($$$$); | |
| 48 sub genpng_warn_handler($); | |
| 49 sub genpng_die_handler($); | |
| 50 | |
| 51 | |
| 52 # | |
| 53 # Code entry point | |
| 54 # | |
| 55 | |
| 56 # Prettify version string | |
| 57 $lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/; | |
| 58 | |
| 59 # Check whether required module GD.pm is installed | |
| 60 if (check_and_load_module("GD")) | |
| 61 { | |
| 62 # Note: cannot use die() to print this message because inserting this | |
| 63 # code into another script via do() would not fail as required! | |
| 64 print(STDERR <<END_OF_TEXT) | |
| 65 ERROR: required module GD.pm not found on this system (see www.cpan.org). | |
| 66 END_OF_TEXT | |
| 67 ; | |
| 68 exit(2); | |
| 69 } | |
| 70 | |
| 71 # Check whether we're called from the command line or from another script | |
| 72 if (!caller) | |
| 73 { | |
| 74 my $filename; | |
| 75 my $tab_size = 4; | |
| 76 my $width = 80; | |
| 77 my $out_filename; | |
| 78 my $help; | |
| 79 my $version; | |
| 80 | |
| 81 $SIG{__WARN__} = \&genpng_warn_handler; | |
| 82 $SIG{__DIE__} = \&genpng_die_handler; | |
| 83 | |
| 84 # Parse command line options | |
| 85 if (!GetOptions("tab-size=i" => \$tab_size, | |
| 86 "width=i" => \$width, | |
| 87 "output-filename=s" => \$out_filename, | |
| 88 "help" => \$help, | |
| 89 "version" => \$version)) | |
| 90 { | |
| 91 print(STDERR "Use $tool_name --help to get usage ". | |
| 92 "information\n"); | |
| 93 exit(1); | |
| 94 } | |
| 95 | |
| 96 $filename = $ARGV[0]; | |
| 97 | |
| 98 # Check for help flag | |
| 99 if ($help) | |
| 100 { | |
| 101 genpng_print_usage(*STDOUT); | |
| 102 exit(0); | |
| 103 } | |
| 104 | |
| 105 # Check for version flag | |
| 106 if ($version) | |
| 107 { | |
| 108 print("$tool_name: $lcov_version\n"); | |
| 109 exit(0); | |
| 110 } | |
| 111 | |
| 112 # Check options | |
| 113 if (!$filename) | |
| 114 { | |
| 115 die("No filename specified\n"); | |
| 116 } | |
| 117 | |
| 118 # Check for output filename | |
| 119 if (!$out_filename) | |
| 120 { | |
| 121 $out_filename = "$filename.png"; | |
| 122 } | |
| 123 | |
| 124 genpng_process_file($filename, $out_filename, $width, $tab_size); | |
| 125 exit(0); | |
| 126 } | |
| 127 | |
| 128 | |
| 129 # | |
| 130 # genpng_print_usage(handle) | |
| 131 # | |
| 132 # Write out command line usage information to given filehandle. | |
| 133 # | |
| 134 | |
| 135 sub genpng_print_usage(*) | |
| 136 { | |
| 137 local *HANDLE = $_[0]; | |
| 138 | |
| 139 print(HANDLE <<END_OF_USAGE) | |
| 140 Usage: $tool_name [OPTIONS] SOURCEFILE | |
| 141 | |
| 142 Create an overview image for a given source code file of either plain text | |
| 143 or .gcov file format. | |
| 144 | |
| 145 -h, --help Print this help, then exit | |
| 146 -v, --version Print version number, then exit | |
| 147 -t, --tab-size TABSIZE Use TABSIZE spaces in place of tab | |
| 148 -w, --width WIDTH Set width of output image to WIDTH pixel | |
| 149 -o, --output-filename FILENAME Write image to FILENAME | |
| 150 | |
| 151 For more information see: $lcov_url | |
| 152 END_OF_USAGE | |
| 153 ; | |
| 154 } | |
| 155 | |
| 156 | |
| 157 # | |
| 158 # check_and_load_module(module_name) | |
| 159 # | |
| 160 # Check whether a module by the given name is installed on this system | |
| 161 # and make it known to the interpreter if available. Return undefined if it | |
| 162 # is installed, an error message otherwise. | |
| 163 # | |
| 164 | |
| 165 sub check_and_load_module($) | |
| 166 { | |
| 167 eval("use $_[0];"); | |
| 168 return $@; | |
| 169 } | |
| 170 | |
| 171 | |
| 172 # | |
| 173 # genpng_process_file(filename, out_filename, width, tab_size) | |
| 174 # | |
| 175 | |
| 176 sub genpng_process_file($$$$) | |
| 177 { | |
| 178 my $filename = $_[0]; | |
| 179 my $out_filename = $_[1]; | |
| 180 my $width = $_[2]; | |
| 181 my $tab_size = $_[3]; | |
| 182 local *HANDLE; | |
| 183 my @source; | |
| 184 | |
| 185 open(HANDLE, "<$filename") | |
| 186 or die("ERROR: cannot open $filename!\n"); | |
| 187 | |
| 188 # Check for .gcov filename extension | |
| 189 if ($filename =~ /^(.*).gcov$/) | |
| 190 { | |
| 191 # Assume gcov text format | |
| 192 while (<HANDLE>) | |
| 193 { | |
| 194 if (/^\t\t(.*)$/) | |
| 195 { | |
| 196 # Uninstrumented line | |
| 197 push(@source, ":$1"); | |
| 198 } | |
| 199 elsif (/^ ###### (.*)$/) | |
| 200 { | |
| 201 # Line with zero execution count | |
| 202 push(@source, "0:$1"); | |
| 203 } | |
| 204 elsif (/^( *)(\d*) (.*)$/) | |
| 205 { | |
| 206 # Line with positive execution count | |
| 207 push(@source, "$2:$3"); | |
| 208 } | |
| 209 } | |
| 210 } | |
| 211 else | |
| 212 { | |
| 213 # Plain text file | |
| 214 while (<HANDLE>) { push(@source, ":$_"); } | |
| 215 } | |
| 216 close(HANDLE); | |
| 217 | |
| 218 gen_png($out_filename, $width, $tab_size, @source); | |
| 219 } | |
| 220 | |
| 221 | |
| 222 # | |
| 223 # gen_png(filename, width, tab_size, source) | |
| 224 # | |
| 225 # Write an overview PNG file to FILENAME. Source code is defined by SOURCE | |
| 226 # which is a list of lines <count>:<source code> per source code line. | |
| 227 # The output image will be made up of one pixel per character of source, | |
| 228 # coloring will be done according to execution counts. WIDTH defines the | |
| 229 # image width. TAB_SIZE specifies the number of spaces to use as replacement | |
| 230 # string for tabulator signs in source code text. | |
| 231 # | |
| 232 # Die on error. | |
| 233 # | |
| 234 | |
| 235 sub gen_png($$$@) | |
| 236 { | |
| 237 my $filename = shift(@_); # Filename for PNG file | |
| 238 my $overview_width = shift(@_); # Imagewidth for image | |
| 239 my $tab_size = shift(@_); # Replacement string for tab signs | |
| 240 my @source = @_; # Source code as passed via argument 2 | |
| 241 my $height = scalar(@source); # Height as define by source size | |
| 242 my $overview; # Source code overview image data | |
| 243 my $col_plain_back; # Color for overview background | |
| 244 my $col_plain_text; # Color for uninstrumented text | |
| 245 my $col_cov_back; # Color for background of covered lines | |
| 246 my $col_cov_text; # Color for text of covered lines | |
| 247 my $col_nocov_back; # Color for background of lines which | |
| 248 # were not covered (count == 0) | |
| 249 my $col_nocov_text; # Color for test of lines which were not | |
| 250 # covered (count == 0) | |
| 251 my $col_hi_back; # Color for background of highlighted lines | |
| 252 my $col_hi_text; # Color for text of highlighted lines | |
| 253 my $line; # Current line during iteration | |
| 254 my $row = 0; # Current row number during iteration | |
| 255 my $column; # Current column number during iteration | |
| 256 my $color_text; # Current text color during iteration | |
| 257 my $color_back; # Current background color during iteration | |
| 258 my $last_count; # Count of last processed line | |
| 259 my $count; # Count of current line | |
| 260 my $source; # Source code of current line | |
| 261 my $replacement; # Replacement string for tabulator chars | |
| 262 local *PNG_HANDLE; # Handle for output PNG file | |
| 263 | |
| 264 # Create image | |
| 265 $overview = new GD::Image($overview_width, $height) | |
| 266 or die("ERROR: cannot allocate overview image!\n"); | |
| 267 | |
| 268 # Define colors | |
| 269 $col_plain_back = $overview->colorAllocate(0xff, 0xff, 0xff); | |
| 270 $col_plain_text = $overview->colorAllocate(0xaa, 0xaa, 0xaa); | |
| 271 $col_cov_back = $overview->colorAllocate(0xaa, 0xa7, 0xef); | |
| 272 $col_cov_text = $overview->colorAllocate(0x5d, 0x5d, 0xea); | |
| 273 $col_nocov_back = $overview->colorAllocate(0xff, 0x00, 0x00); | |
| 274 $col_nocov_text = $overview->colorAllocate(0xaa, 0x00, 0x00); | |
| 275 $col_hi_back = $overview->colorAllocate(0x00, 0xff, 0x00); | |
| 276 $col_hi_text = $overview->colorAllocate(0x00, 0xaa, 0x00); | |
| 277 | |
| 278 # Visualize each line | |
| 279 foreach $line (@source) | |
| 280 { | |
| 281 # Replace tabs with spaces to keep consistent with source | |
| 282 # code view | |
| 283 while ($line =~ /^([^\t]*)(\t)/) | |
| 284 { | |
| 285 $replacement = " "x($tab_size - ((length($1) - 1) % | |
| 286 $tab_size)); | |
| 287 $line =~ s/^([^\t]*)(\t)/$1$replacement/; | |
| 288 } | |
| 289 | |
| 290 # Skip lines which do not follow the <count>:<line> | |
| 291 # specification, otherwise $1 = count, $2 = source code | |
| 292 if (!($line =~ /(\*?)(\d*):(.*)$/)) { next; } | |
| 293 $count = $2; | |
| 294 $source = $3; | |
| 295 | |
| 296 # Decide which color pair to use | |
| 297 | |
| 298 # If this line was not instrumented but the one before was, | |
| 299 # take the color of that line to widen color areas in | |
| 300 # resulting image | |
| 301 if (($count eq "") && defined($last_count) && | |
| 302 ($last_count ne "")) | |
| 303 { | |
| 304 $count = $last_count; | |
| 305 } | |
| 306 | |
| 307 if ($count eq "") | |
| 308 { | |
| 309 # Line was not instrumented | |
| 310 $color_text = $col_plain_text; | |
| 311 $color_back = $col_plain_back; | |
| 312 } | |
| 313 elsif ($count == 0) | |
| 314 { | |
| 315 # Line was instrumented but not executed | |
| 316 $color_text = $col_nocov_text; | |
| 317 $color_back = $col_nocov_back; | |
| 318 } | |
| 319 elsif ($1 eq "*") | |
| 320 { | |
| 321 # Line was highlighted | |
| 322 $color_text = $col_hi_text; | |
| 323 $color_back = $col_hi_back; | |
| 324 } | |
| 325 else | |
| 326 { | |
| 327 # Line was instrumented and executed | |
| 328 $color_text = $col_cov_text; | |
| 329 $color_back = $col_cov_back; | |
| 330 } | |
| 331 | |
| 332 # Write one pixel for each source character | |
| 333 $column = 0; | |
| 334 foreach (split("", $source)) | |
| 335 { | |
| 336 # Check for width | |
| 337 if ($column >= $overview_width) { last; } | |
| 338 | |
| 339 if ($_ eq " ") | |
| 340 { | |
| 341 # Space | |
| 342 $overview->setPixel($column++, $row, | |
| 343 $color_back); | |
| 344 } | |
| 345 else | |
| 346 { | |
| 347 # Text | |
| 348 $overview->setPixel($column++, $row, | |
| 349 $color_text); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 # Fill rest of line | |
| 354 while ($column < $overview_width) | |
| 355 { | |
| 356 $overview->setPixel($column++, $row, $color_back); | |
| 357 } | |
| 358 | |
| 359 $last_count = $2; | |
| 360 | |
| 361 $row++; | |
| 362 } | |
| 363 | |
| 364 # Write PNG file | |
| 365 open (PNG_HANDLE, ">$filename") | |
| 366 or die("ERROR: cannot write png file $filename!\n"); | |
| 367 binmode(*PNG_HANDLE); | |
| 368 print(PNG_HANDLE $overview->png()); | |
| 369 close(PNG_HANDLE); | |
| 370 } | |
| 371 | |
| 372 sub genpng_warn_handler($) | |
| 373 { | |
| 374 my ($msg) = @_; | |
| 375 | |
| 376 warn("$tool_name: $msg"); | |
| 377 } | |
| 378 | |
| 379 sub genpng_die_handler($) | |
| 380 { | |
| 381 my ($msg) = @_; | |
| 382 | |
| 383 die("$tool_name: $msg"); | |
| 384 } | |
| OLD | NEW |