| 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 |