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