scan-build revision 4cd6ea9989989e9f3a87b22c794ce76c6899d0a1
19cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#!/usr/bin/env perl
29cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
39cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#                     The LLVM Compiler Infrastructure
49cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
59cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# This file is distributed under the University of Illinois Open Source
69cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# License. See LICENSE.TXT for details.
79cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
89cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##===----------------------------------------------------------------------===##
99cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# A script designed to wrap a build so that all calls to gcc are intercepted
119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# and piped to the static analyzer.
129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek#
139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##===----------------------------------------------------------------------===##
149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekuse strict;
169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekuse warnings;
1722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenekuse FindBin qw($RealBin);
18a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenekuse Digest::MD5;
197a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekuse File::Basename;
2023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor;
2123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor qw(:constants);
22cd25c13ade3afa829c87ca1ed0ed0d379f426251Ted Kremenekuse Cwd qw/ getcwd abs_path /;
237cba11262458df05951432b54997eb40a35dbf9eTed Kremenekuse Sys::Hostname;
249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Verbose = 0;       # Verbose output from this script.
269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Prog = "scan-build";
27f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildName;
28f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildDate;
299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
300e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $TERM = $ENV{'TERM'};
310e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT
320e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenek                and defined $ENV{'SCAN_BUILD_COLOR'});
3323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
347cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $UserName = HtmlEscape(getpwuid($<) || 'unknown');
357cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HostName = HtmlEscape(hostname() || 'unknown');
367cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDir = HtmlEscape(getcwd());
377cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CurrentDirSuffix = basename($CurrentDir);
387cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
397cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $CmdArgs;
407cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
417cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $HtmlTitle;
427cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
437cba11262458df05951432b54997eb40a35dbf9eTed Kremenekmy $Date = localtime();
447cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
45b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
46b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Diagnostics
47b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
48b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
4923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub Diag {
5023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
5123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, MAGENTA "$Prog: @_";
5223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
5323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
5423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
5523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: @_";
5623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }  
5723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
5823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
59991c54b9b7409656e5593364e065878b5210d556Ted Kremeneksub DiagCrashes {
60991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Dir = shift;
61938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("The analyzer encountered problems on some source files.\n");
62938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  Diag ("Preprocessed versions of these sources were deposited in '$Dir/failures'.\n");
63991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("Please consider submitting a bug report using these files:\n");
64991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("  http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
65991c54b9b7409656e5593364e065878b5210d556Ted Kremenek}
66991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
6823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
6923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
7023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
7123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
7223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
7423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
7523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
7623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
7723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
7823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
80b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Some initial preprocessing of Clang options.
81b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
82b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
832a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek# Find 'clang'
84fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenekmy $ClangSB = Cwd::realpath("$RealBin/bin/clang");
858d10cdd9aa1d58f1898adf7752a7026f151ebc04Ted Kremenekif (!defined $ClangSB || ! -x $ClangSB) {
86fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek  $ClangSB = Cwd::realpath("$RealBin/clang");
87fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek}
88e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekmy $Clang;
89e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekif (!defined $ClangSB || ! -x $ClangSB) {
90e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenek  # Default to looking for 'clang' in the path.
916492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  $Clang = `which clang`;
926492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  chomp $Clang;
936492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  if ($Clang eq "") {
946492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek    DieDiag("No 'clang' executable found in path.");
956492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  }
962a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek}
97e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekelse {
98e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenek  $Clang = $ClangSB;
99e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenek}
100e01ca51f4167b5a7fd1d6230f2e2f1f177fd68e3Ted Kremenekmy $ClangCXX = $Clang . "++";
101fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek
102b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
103fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
106a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
107fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1082a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my $Dir = shift @_;    
109fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
110fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
111ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    if (`uname` =~ /Darwin/) {
112ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      $Dir = $ENV{'TMPDIR'};
113ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      if (!defined $Dir) { $Dir = "/tmp"; }
114ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    }
115ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek    else {
116ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek      $Dir = "/tmp";
1172a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
118fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
119fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
120bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  
121bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  # Chop off any trailing '/' characters.
122bf762c9b48673e9686a97fe6ca144d891316164eTed Kremenek  while ($Dir =~ /\/$/) { chop $Dir; }
123fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1252a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  my @CurrentTime = localtime();  
1269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1299d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1312a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  # Determine the run number.  
1329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1342a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek  if (-d $Dir) {    
1359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
13623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1372a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    }    
1382a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    # Iterate over all files in the specified directory.    
1392a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    my $max = 0;    
1409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
14129da6c59df7ca994e75139303a9230b24e2abaadTed Kremenek    my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
1429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1442a3a8b9f47b0a8f3fdd57bc4fbd08684feb4fa85Ted Kremenek    foreach my $f (@FILES) {
145fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
146fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
147fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
148fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
149fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
150fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
1529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
16723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
169fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
170fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
171445fa776d2bc9207c33a9b9ab4afb9513f6b81b0Ted Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.\n");
172fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
173fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
176fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
180fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
183fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  my $NewDir;
184fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
185fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
186fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
187fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
188fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$DateString-$RunNumber";
189fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
190fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  system 'mkdir','-p',$NewDir;
191fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  return $NewDir;
1929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
194a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
1959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
1979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
1999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
2009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
2029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2049e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek
2059e4a1bb0084bf3bf64595f57effe496cb2cf1863Ted Kremenek  if ($Cmd =~ /configure/ || $Cmd =~ /autogen/) {
2069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
21023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
21757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
21857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
21957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
22057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
22157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
22223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
223a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
224a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2257ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2267ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
22763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
22823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
229a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
230a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
231a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
232a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
23363c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
234a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
23557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
23657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2387a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2397a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2407a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2417a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2427a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2437a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2447a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2457a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2467a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2487a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2507a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2517a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2527a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
25320b2bae90c102f405ba70f602c45660ce1cd0c4eTed Kremenek  chop $Prefix while (!($x =~ /^\Q$Prefix/));
2547a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2657a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2677a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
26863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
27063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
27163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
27663c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
27920161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
2807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2827a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2834f2b10b24bab0049020d268382eda144e2aa064cTom Care# AddStatLine - Decode and insert a statistics line into the database.
2844f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
2854f2b10b24bab0049020d268382eda144e2aa064cTom Care
2864f2b10b24bab0049020d268382eda144e2aa064cTom Caresub AddStatLine {
2874f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Line  = shift;
2884f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
2894f2b10b24bab0049020d268382eda144e2aa064cTom Care
2904f2b10b24bab0049020d268382eda144e2aa064cTom Care  print $Line . "\n";
2914f2b10b24bab0049020d268382eda144e2aa064cTom Care
2924f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
2934f2b10b24bab0049020d268382eda144e2aa064cTom Care      \ CFGBlocks:\ (\d+)\ \|\ Aborted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
2944f2b10b24bab0049020d268382eda144e2aa064cTom Care      \ (yes|no)/x;
2954f2b10b24bab0049020d268382eda144e2aa064cTom Care
2964f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($Line !~ $Regex) {
2974f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
2984f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
2994f2b10b24bab0049020d268382eda144e2aa064cTom Care
3004f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Create a hash of the interesting fields
3014f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Row = {
3024f2b10b24bab0049020d268382eda144e2aa064cTom Care    Filename    => $1,
3034f2b10b24bab0049020d268382eda144e2aa064cTom Care    Function    => $2,
3044f2b10b24bab0049020d268382eda144e2aa064cTom Care    Total       => $3,
3054f2b10b24bab0049020d268382eda144e2aa064cTom Care    Unreachable => $4,
3064f2b10b24bab0049020d268382eda144e2aa064cTom Care    Aborted     => $5,
3074f2b10b24bab0049020d268382eda144e2aa064cTom Care    Empty       => $6
3084f2b10b24bab0049020d268382eda144e2aa064cTom Care  };
3094f2b10b24bab0049020d268382eda144e2aa064cTom Care
3104f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Add them to the stats array
3114f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @$Stats, $Row;
3124f2b10b24bab0049020d268382eda144e2aa064cTom Care}
3134f2b10b24bab0049020d268382eda144e2aa064cTom Care
3144f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
3155744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
3165744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3175744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
31857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
31957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
32057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
32157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
32257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3235744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3275744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3284f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
3295744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
33057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
33157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
33257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
33357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
33457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
335fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
33657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
33720161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
33857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
33957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
34057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
34157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
34257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
343809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
34420161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
345684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
346684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
34723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3485744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3494f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugType        = "";
3504f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugFile        = "";
3514f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugCategory    = "";
3524f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugDescription = "";
3534f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugPathLength  = 1;
3544f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BugLine        = 0;
355ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
3565744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
357d658e67b438c60fbe3bd1773a3172fd0f082c483Ted Kremenek    last if (/<!-- BUGMETAEND -->/);
358ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
359a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek    if (/<!-- BUGTYPE (.*) -->$/) {
360a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek      $BugType = $1;
3615744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
36222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
363990c2f45e566d8ff097fa90176ba90036892b3cdTed Kremenek      $BugFile = abs_path($1);
3647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
36522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
36622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
36722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
36822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
36922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
37022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
371ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    }
372ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    elsif (/<!-- BUGCATEGORY (.*) -->$/) {
373ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $BugCategory = $1;
37422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3754f2b10b24bab0049020d268382eda144e2aa064cTom Care    elsif (/<!-- BUGDESC (.*) -->$/) {
3764f2b10b24bab0049020d268382eda144e2aa064cTom Care      $BugDescription = $1;
3774f2b10b24bab0049020d268382eda144e2aa064cTom Care    }
3785744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3795744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3805744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
381ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  
382ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  if (!defined $BugCategory) {
383ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    $BugCategory = "Other";
384ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  }
3854f2b10b24bab0049020d268382eda144e2aa064cTom Care
3864f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Don't add internal statistics to the bug reports
3874f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($BugCategory =~ /statistics/i) {
3884f2b10b24bab0049020d268382eda144e2aa064cTom Care    AddStatLine($BugDescription, $Stats);
3894f2b10b24bab0049020d268382eda144e2aa064cTom Care    return;
3904f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
3914f2b10b24bab0049020d268382eda144e2aa064cTom Care  
392a26ddabc0eb8cf8ea4de1878f84d3b920fc2349fTed Kremenek  push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
39381983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek                 $BugPathLength ];
39422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
39522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
39622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
3973ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek# CopyFiles - Copy resource files to target directory.
39822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
39922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
4003ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremeneksub CopyFiles {
40122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
40222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
403e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek
404e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $JS = Cwd::realpath("$RealBin/sorttable.js");
40522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
40623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
407e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $JS);  
40822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
409e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $JS, "$Dir");
41022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
41123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
41222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
4133ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek    
414e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  my $CSS = Cwd::realpath("$RealBin/scanview.css");
415e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
4163ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Cannot find 'scanview.css'.\n")
417e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4183ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
419e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  system ("cp", $CSS, "$Dir");
4203ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek
4213ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  DieDiag("Could not copy 'scanview.css' to '$Dir'.\n")
422e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    if (! -r $CSS);
4235744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
4245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
4255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
4264f2b10b24bab0049020d268382eda144e2aa064cTom Care# CalcStats - Calculates visitation statistics and returns the string.
4274f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4284f2b10b24bab0049020d268382eda144e2aa064cTom Care
4294f2b10b24bab0049020d268382eda144e2aa064cTom Caresub CalcStats {
4304f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Stats = shift;
4314f2b10b24bab0049020d268382eda144e2aa064cTom Care
4324f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalBlocks = 0;
4334f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $UnreachedBlocks = 0;
4344f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFunctions = scalar(@$Stats);
4354f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BlockAborted = 0;
4364f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $WorkListAborted = 0;
4374f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Aborted = 0;
4384f2b10b24bab0049020d268382eda144e2aa064cTom Care
4394f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculate the unique files
4404f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $FilesHash = {};
4414f2b10b24bab0049020d268382eda144e2aa064cTom Care
4424f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $Row (@$Stats) {
4434f2b10b24bab0049020d268382eda144e2aa064cTom Care    $FilesHash->{$Row->{Filename}} = 1;
4444f2b10b24bab0049020d268382eda144e2aa064cTom Care    $TotalBlocks += $Row->{Total};
4454f2b10b24bab0049020d268382eda144e2aa064cTom Care    $UnreachedBlocks += $Row->{Unreachable};
4464f2b10b24bab0049020d268382eda144e2aa064cTom Care    $BlockAborted++ if $Row->{Aborted} eq 'yes';
4474f2b10b24bab0049020d268382eda144e2aa064cTom Care    $WorkListAborted++ if $Row->{Empty} eq 'no';
4484f2b10b24bab0049020d268382eda144e2aa064cTom Care    $Aborted++ if $Row->{Aborted} eq 'yes' || $Row->{Empty} eq 'no';
4494f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
4504f2b10b24bab0049020d268382eda144e2aa064cTom Care
4514f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $TotalFiles = scalar(keys(%$FilesHash));
4524f2b10b24bab0049020d268382eda144e2aa064cTom Care
4534f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Calculations
4544f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentAborted = sprintf("%.2f", $Aborted / $TotalFunctions * 100);
4554f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlockAborted = sprintf("%.2f", $BlockAborted / $TotalFunctions
4564f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4574f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentWorkListAborted = sprintf("%.2f", $WorkListAborted /
4584f2b10b24bab0049020d268382eda144e2aa064cTom Care      $TotalFunctions * 100);
4594f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $PercentBlocksUnreached = sprintf("%.2f", $UnreachedBlocks / $TotalBlocks
4604f2b10b24bab0049020d268382eda144e2aa064cTom Care      * 100);
4614f2b10b24bab0049020d268382eda144e2aa064cTom Care
4624f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $StatsString = "Analyzed $TotalBlocks blocks in $TotalFunctions functions"
4634f2b10b24bab0049020d268382eda144e2aa064cTom Care    . " in $TotalFiles files\n"
4644f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$Aborted functions aborted early ($PercentAborted%)\n"
4654f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$BlockAborted had aborted blocks ($PercentBlockAborted%)\n"
4664f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$WorkListAborted had unfinished worklists ($PercentWorkListAborted%)\n"
4674f2b10b24bab0049020d268382eda144e2aa064cTom Care    . "$UnreachedBlocks blocks were never reached ($PercentBlocksUnreached%)\n";
4684f2b10b24bab0049020d268382eda144e2aa064cTom Care
4694f2b10b24bab0049020d268382eda144e2aa064cTom Care  return $StatsString;
4704f2b10b24bab0049020d268382eda144e2aa064cTom Care}
4714f2b10b24bab0049020d268382eda144e2aa064cTom Care
4724f2b10b24bab0049020d268382eda144e2aa064cTom Care##----------------------------------------------------------------------------##
4739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
4749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
4759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
476a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
4779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4784f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $Dir           = shift;
4794f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $BaseDir       = shift;
4804f2b10b24bab0049020d268382eda144e2aa064cTom Care  my $AnalyzerStats = shift;
4819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
482fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
4839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
48523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
486363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
4889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
4899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
490938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @files = grep { /^report-.*\.html$/ } readdir(DIR);
4919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
4929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
493938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar(@files) == 0 and ! -e "$Dir/failures") {
49423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
49520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-fR", $Dir);
496363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
4985744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
499991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  # Scan each report file and build an index.  
5004f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Index;
5014f2b10b24bab0049020d268382eda144e2aa064cTom Care  my @Stats;
5024f2b10b24bab0049020d268382eda144e2aa064cTom Care  foreach my $file (@files) { ScanFile(\@Index, $Dir, $file, \@Stats); }
5035744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
504938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  # Scan the failures directory and use the information in the .info files
505d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  # to update the common prefix directory.
506938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @failures;
507938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  my @attributes_ignored;
508938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (-d "$Dir/failures") {
509938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");
510938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @failures = grep { /[.]info.txt$/ && !/attribute_ignored/; } readdir(DIR);
511d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    closedir(DIR);
512938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    opendir(DIR, "$Dir/failures");        
513938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    @attributes_ignored = grep { /^attribute_ignored/; } readdir(DIR);
514938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    closedir(DIR);
515938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    foreach my $file (@failures) {
516938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      open IN, "$Dir/failures/$file" or DieDiag("cannot open $file\n");
517d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      my $Path = <IN>;
518d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      if (defined $Path) { UpdatePrefix($Path); }
519d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      close IN;
520d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    }    
521d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  }
522d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  
52363c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Generate an index.html file.  
52463c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  my $FName = "$Dir/index.html";  
52563c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
5265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
5276e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
5286e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
5295744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
5305744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
5315744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
5327cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<title>${HtmlTitle}</title>
533f143545ce5ce125e7c1aa6fca9df372bfb604e9cTed Kremenek<link type="text/css" rel="stylesheet" href="scanview.css"/>
53422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
5356e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
5366e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
5376e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
5386e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
5396e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
5406e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
5416e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
5426e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
5436e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5446e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
545ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
5462350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenekfunction CopyCheckedStateToCheckButtons(SummaryCheckButton) {
5472350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  var Inputs = document.getElementsByTagName("input");
5482350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  for ( var i = 0 ; i < Inputs.length; ++i ) {
5492350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    if (Inputs[i].type == "checkbox") {
5502350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      if(Inputs[i] != SummaryCheckButton) {
5512350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].checked = SummaryCheckButton.checked;
5522350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek        Inputs[i].onclick();
5532350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek	  }
5542350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek    }
5552350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  }
5562350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek}
5572350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek
558999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekfunction returnObjById( id ) {
559999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (document.getElementById) 
560999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.getElementById(id);
561999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.all)
562999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.all[id];
563999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    else if (document.layers) 
564999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek        var returnVar = document.layers[id];
565999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    return returnVar; 
566999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek}
567999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
568999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenekvar NumUnchecked = 0;
569999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek
5706e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
5716e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
5726e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
573999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    if (--NumUnchecked == 0) {
574999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek      returnObjById("AllBugsCheck").checked = true;
575999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    }
5766e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5776e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
5786e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
579999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    NumUnchecked++;
580999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek    returnObjById("AllBugsCheck").checked = false;
5816e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
5826e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
5836e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
5841d1abb1dec3d0b7609809d876a16a64a021e96e7Ted Kremenek<!-- SUMMARYENDHEAD -->
5856e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
5866e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
5877cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h1>${HtmlTitle}</h1>
5887cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5897cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<table>
5907cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
5917cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
5927cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
5937cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<tr><th>Date:</th><td>${Date}</td></tr>
5947cba11262458df05951432b54997eb40a35dbf9eTed KremenekENDTEXT
5957cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5967cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT "<tr><th>Version:</th><td>${BuildName} (${BuildDate})</td></tr>\n"
5977cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if (defined($BuildName) && defined($BuildDate));
5987cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
5997cba11262458df05951432b54997eb40a35dbf9eTed Kremenekprint OUT <<ENDTEXT;
6007cba11262458df05951432b54997eb40a35dbf9eTed Kremenek</table>
6016e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6026e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
603991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if (scalar(@files)) {
604991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    # Print out the summary table.
605991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my %Totals;
606ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
607991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $row ( @Index ) {
608ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_type = ($row->[2]);
609ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $bug_category = ($row->[1]);
610ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $key = "$bug_category:$bug_type";
611ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
612ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $Totals{$key}) { $Totals{$key} = [1,$bug_category,$bug_type]; }
613ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else { $Totals{$key}->[0]++; }
6146e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
615991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
6167cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    print OUT "<h2>Bug Summary</h2>";
617991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
618991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $BuildName) {
619991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
6206e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
621f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
6222350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek  my $TotalBugs = scalar(@Index);
6236e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
624ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table>
625ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr><td>Bug Type</td><td>Quantity</td><td class="sorttable_nosort">Display?</td></tr></thead>
626999e120c1f5bb4064fa9961d82c2b02b6c41cb0dTed Kremenek<tr style="font-weight:bold"><td class="SUMM_DESC">All Bugs</td><td class="Q">$TotalBugs</td><td><center><input type="checkbox" id="AllBugsCheck" onClick="CopyCheckedStateToCheckButtons(this);" checked/></center></td></tr>
6276e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
6286e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
629ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    my $last_category;
630ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
631ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $key (
632ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      sort {
633ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $x = $Totals{$a};
634ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $y = $Totals{$b};
635ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        my $res = $x->[1] cmp $y->[1];
636ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res = $x->[2] cmp $y->[2] if ($res == 0);
637ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $res
638ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      } keys %Totals ) 
639ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    {
640ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $val = $Totals{$key};
641ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $category = $val->[1];
642ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if (!defined $last_category or $last_category ne $category) {
643ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        $last_category = $category;
644ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<tr><th>$category</th><th colspan=2></th></tr>\n";
645ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }      
646ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = lc $key;
647ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
648ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr><td class=\"SUMM_DESC\">";
649ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[2];
6502350a46bec7c581b2e3808e205aa3f3f5fae71ccTed Kremenek      print OUT "</td><td class=\"Q\">";
651ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $val->[0];
652ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td><td><center><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></center></td></tr>\n";
653991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
6546e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6556e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
6566e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
6576e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
6586e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
6597cba11262458df05951432b54997eb40a35dbf9eTed Kremenek<h2>Reports</h2>
660ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
661ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<table class="sortable" style="table-layout:automatic">
662ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<thead><tr>
663ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td>Bug Group</td>
664ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span></td>
665bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
666ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <td class="Q">Line</td>
66781983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek  <td class="Q">Path Length</td>
6682645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort"></td>
669ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek  <!-- REPORTBUGCOL -->
670ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek</tr></thead>
671ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek<tbody>
6725744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
6739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
674991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $prefix = GetPrefix();
675991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $regex;
676991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFileRegex;
677991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFilePrefix = "File:</td><td>";
6787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
679991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $prefix) { 
680991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $regex = qr/^\Q$prefix\E/is;    
681991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
682991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }    
6837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
684ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    for my $row ( sort { $a->[2] cmp $b->[2] } @Index ) {
685ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $x = "$row->[1]:$row->[2]";
686ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x = lc $x;
687ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      $x =~ s/[ ,'":\/()]+/_/g;
6886e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
689991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $ReportFile = $row->[0];
690ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          
691ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<tr class=\"bt_$x\">";
692ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
693991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT $row->[1];
694ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
695ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "<td class=\"DESC\">";
696ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT $row->[2];
697ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
698ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
699ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Update the file prefix.      
700ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my $fname = $row->[3];
701ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek
702991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      if (defined $regex) {
703991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        $fname =~ s/$regex//;
704991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
705991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
706ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
70791639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      print OUT "<td>";      
708ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      my @fname = split /\//,$fname;
709ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      if ($#fname > 0) {
710ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        while ($#fname >= 0) {
711ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          my $x = shift @fname;
712ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          print OUT $x;
713ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          if ($#fname >= 0) {
714ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek            print OUT "<span class=\"W\"> </span>/";
715ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek          }
716ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        }
717ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
718ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      else {
719ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT $fname;
72091639ef5aa2bd94c14ae872cf747c58174ffe9b8Ted Kremenek      }      
721ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "</td>";
722ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
723ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      # Print out the quantities.
72481983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for my $j ( 4 .. 5 ) {
725ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td class=\"Q\">$row->[$j]</td>";        
726ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      }
727ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      
728991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Print the rest of the columns.
72981983111dfa43e5f6b21b221c959586a6a766e76Ted Kremenek      for (my $j = 6; $j <= $#{$row}; ++$j) {
730ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek        print OUT "<td>$row->[$j]</td>"
731991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
7327f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
733991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Emit the "View" link.
73468005ddb49b88c2f6cdd88185d72d8b411d2dbc9Ted Kremenek      print OUT "<td><a href=\"$ReportFile#EndPath\">View Report</a></td>";
7353cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek        
736e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar      # Emit REPORTBUG markers.
737ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek      print OUT "\n<!-- REPORTBUG id=\"$ReportFile\" -->\n";
738e43038ec3d0ef187fcdddf101ef653bbbdb1069aDaniel Dunbar        
739991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # End the row.
740991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "</tr>\n";
741991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
742991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
743ebb7413bbe518fa6230eddebf6e51857b47b5cd3Ted Kremenek    print OUT "</tbody>\n</table>\n\n";
744991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  }
745991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
746938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  if (scalar (@failures) || scalar(@attributes_ignored)) {
747938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    print OUT "<h2>Analyzer Failures</h2>\n";
748938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
749938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @attributes_ignored) {
750938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "The analyzer's parser ignored the following attributes:<p>\n";
751938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
752938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Attribute</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
753938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @attributes_ignored) {
754938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        die "cannot demangle attribute name\n" if (! ($file =~ /^attribute_ignored_(.+).txt/));
755938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $attribute = $1;
756938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the attribute file to get the first file that failed.
757938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (!open (ATTR, "$Dir/failures/$file"));
758938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile = <ATTR>;
759938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $ppfile;
760938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close ATTR;
761938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        next if (! -e "$Dir/failures/$ppfile");
762938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Open the info file and get the name of the source file.
763938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$ppfile.info.txt") or
764938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$ppfile.info.txt\n";
765938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $srcfile = <INFO>;
766938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        chomp $srcfile;
767938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        close (INFO);
768938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        # Print the information in the table.
769938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $prefix = GetPrefix();
770938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
771938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "<tr><td>$attribute</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
772938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        my $ppfile_clang = $ppfile;
773938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
774938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
775938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      }
776938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
777938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }
778938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    
779938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    if (scalar @failures) {
780938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<p>The analyzer had problems processing the following files:</p>\n";
781938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<table>\n";
782938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
783938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      foreach my $file (sort @failures) {
78482a1253077cd0832e4d347062b911cd305ab62d1Ted Kremenek        $file =~ /(.+).info.txt$/;
785991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Get the preprocessed file.
786991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $ppfile = $1;
787991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Open the info file and get the name of the source file.
788938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        open (INFO, "$Dir/failures/$file") or
789938eef139ad43345248235da31f78a759dd18f13Ted Kremenek          die "Cannot open $Dir/failures/$file\n";
790991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $srcfile = <INFO>;
7915d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $srcfile;
7925d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        my $problem = <INFO>;
7935d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $problem;
794991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        close (INFO);
795991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Print the information in the table.
796d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek        my $prefix = GetPrefix();
7979f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
798938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "<tr><td>$problem</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
799ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        my $ppfile_clang = $ppfile;
800ce723ce2346fccb102d4dc93b80356824544d1afDaniel Dunbar        $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
801938eef139ad43345248235da31f78a759dd18f13Ted Kremenek        print OUT "  <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
802991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
803938eef139ad43345248235da31f78a759dd18f13Ted Kremenek      print OUT "</table>\n";
804938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    }    
805938eef139ad43345248235da31f78a759dd18f13Ted Kremenek    print OUT "<p>Please consider submitting preprocessed files as <a href=\"http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\">bug reports</a>. <!-- REPORTCRASHES --> </p>\n";
8065744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
8075744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
808991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  print OUT "</body></html>\n";  
8095744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
8103ce1207f90340f9f773ace4d475b99b75ff65088Ted Kremenek  CopyFiles($Dir);
81120161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
81220161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  # Make sure $Dir and $BaseDir are world readable/executable.
81320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("chmod", "755", $Dir);
814fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
81520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
8164f2b10b24bab0049020d268382eda144e2aa064cTom Care  # Print statistics
8174f2b10b24bab0049020d268382eda144e2aa064cTom Care  print CalcStats(\@Stats) if $AnalyzerStats;
8184f2b10b24bab0049020d268382eda144e2aa064cTom Care
81923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
820150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  Diag("$Num bugs found.\n");
821150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  if ($Num > 0 && -r "$Dir/index.html") {
8225950b3f93a6e8a6ae8bd59a0ef5797e9f88f0bc3Ted Kremenek    Diag("Run 'scan-view $Dir' to examine bug reports.\n");
823150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  }
824363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
825938eef139ad43345248235da31f78a759dd18f13Ted Kremenek  DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
826991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
827363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  return $Num;
8289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
831dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
832dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
833dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
8346b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
8356b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
8366b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
8376b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
8386b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8396b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
8406b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
8416b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
8426b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
8436b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
8446b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8456b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
8466b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
8476b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
8486b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
8496b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
8506b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
851dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremeneksub RunBuildCommand {
852dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
853dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
8547442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
855dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
8566195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
857524c308506e77e173092e87a0724a27817311428Ted Kremenek  my $CXXAnalyzer = shift;
858dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
8593301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  # Get only the part of the command after the last '/'.
8603301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  if ($Cmd =~ /\/([^\/]+)$/) {
8613301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek    $Cmd = $1;
8623301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  }
8633301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  
86492548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek  if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or 
86592548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?cc[^\/]*$)/ or
86692548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
86705acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek      $Cmd =~ /(.*\/?clang$)/ or 
86892548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek      $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) {
86992548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek
87092548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) {
87151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CC"} = $1;      
87292548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek    }
87392548fed40519a09a1c016ceb6ab078384ab5ebcTed Kremenek        
874dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
8756195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
876dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
87751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  elsif ($Cmd =~ /(.*\/?g\+\+[^\/]*$)/ or 
87851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+[^\/]*$)/ or
87951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?llvm-g\+\+[^\/]*$)/ or
88005acf8b689257d8b7349ffdfe309b4d7f7d6ae13Ted Kremenek        $Cmd =~ /(.*\/?clang\+\+$)/ or
88151365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek        $Cmd =~ /(.*\/?c\+\+-analyzer[^\/]*$)/) {
88251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    if (!($Cmd =~ /c\+\+-analyzer/) and !defined $ENV{"CCC_CXX"}) {
88351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $ENV{"CCC_CXX"} = $1;      
88451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    }        
88551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    shift @$Args;
886524c308506e77e173092e87a0724a27817311428Ted Kremenek    unshift @$Args, $CXXAnalyzer;
88751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  }
8887442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
8897442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
8906fba85dc6509069ff7735283464bd02da2da6eebTed Kremenek      AddIfNotPresent($Args, "CC=$CCAnalyzer");
891524c308506e77e173092e87a0724a27817311428Ted Kremenek      AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
8926b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
8938912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
8947442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
8957442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    elsif ($Cmd eq "xcodebuild") {
8966b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
8977442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
8986b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
8996b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
9006b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($Cmd eq "xcodebuild") {
90187752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    # Check if using iPhone SDK 3.0 (simulator).  If so the compiler being
90287752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    # used should be gcc-4.2.
90387752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    if (!defined $ENV{"CCC_CC"}) {
90487752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek      for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
90587752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek        if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
90687752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek          if (@$Args[$i+1] =~ /^iphonesimulator3/) {
90787752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek            $ENV{"CCC_CC"} = "gcc-4.2";
90851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek            $ENV{"CCC_CXX"} = "g++-4.2";            
90987752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek          }
91087752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek        }
91187752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek      }
91287752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek    }
91387752b2442260fcf569e7a1447a04cd8955494c5Ted Kremenek
914cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable PCH files until clang supports them.
915cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
916915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    
917915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
918915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
919524c308506e77e173092e87a0724a27817311428Ted Kremenek    # (via c++-analyzer) when linking such files.
920524c308506e77e173092e87a0724a27817311428Ted Kremenek    $ENV{"LDPLUSPLUS"} = $CXXAnalyzer;
9216b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
922dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
9235a4ddaf39a26f9c7e30d3aeca17c702213a29d9fTed Kremenek  return (system(@$Args) >> 8);
924dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
925dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
926dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
9279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
9289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
9299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
930a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
9319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
9325744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
933a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
9342b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
935f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
936f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
937fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
938f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
939f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
940f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
941f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
9422b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
9432b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
944e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek -analyze-headers - Also analyze functions in #included files.
9458382cf57b722f130f1a6b45380639871c07271c1Ted Kremenek 
946363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -o             - Target directory for HTML report files.  Subdirectories
947a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop                  will be created as needed to represent separate "runs" of
9482b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  the analyzer.  If this option is not specified, a directory
949ffda0b44eb02ddf2f168df8e14ae98de790f2b05Ted Kremenek                  is created in /tmp (TMPDIR on Mac OS X) to store the reports.
950db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek                  
951363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -h             - Display this message.
952363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
9531262fc4d66584224234691d30d779f8ff004585cTed Kremenek
954363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -k             - Add a "keep on going" option to the specified build command.
955363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --keep-going     This option currently supports make and xcodebuild.
956f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  This is a convenience option; one can specify this
957f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  behavior directly using build options.
9582b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
9597cba11262458df05951432b54997eb40a35dbf9eTed Kremenek --html-title [title]       - Specify the title used on generated HTML pages.
9607cba11262458df05951432b54997eb40a35dbf9eTed Kremenek --html-title=[title]         If not specified, a default title will be used.
9617cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
962db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek -plist         - By default the output of scan-build is a set of HTML files.
963db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek                  This option outputs the results as a set of .plist files.
964db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
965363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --status-bugs  - By default, the exit status of $Prog is the same as the
966363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  executed build command.  Specifying this option causes the
967363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  exit status of $Prog to be 1 if it found potential bugs
968363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  and 0 otherwise.
9692b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
970386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-cc [compiler path]   - By default, $Prog uses 'gcc' to compile and link
971386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-cc=[compiler path]     your C and Objective-C code. Use this option
972386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
973386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
974386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-c++ [compiler path]  - By default, $Prog uses 'g++' to compile and link
975386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-c++=[compiler path]    your C++ and Objective-C++ code. Use this option
976386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
977f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek
978363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -v             - Verbose output from $Prog and the analyzer.
979386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                  A second and third '-v' increases verbosity.
980363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
981363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -V             - View analysis results in a web browser when the build
982363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --view           completes.
9837f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
984be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed KremenekADVANCED OPTIONS:
985be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek
9869f4ecb34d502f6aad7d635dd3aec24a373ef5c9bTed Kremenek -constraints [model] - Specify the contraint engine used by the analyzer.
9879f4ecb34d502f6aad7d635dd3aec24a373ef5c9bTed Kremenek                        By default the 'range' model is used.  Specifying 
9889f4ecb34d502f6aad7d635dd3aec24a373ef5c9bTed Kremenek                        'basic' uses a simpler, less powerful constraint model
989d4c7684f19703d75b989364da80727d635f99b53Ted Kremenek                        used by checker-0.160 and earlier.
990be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek
991be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek -store [model] - Specify the store model used by the analyzer. By default,
992b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  the 'region' store model is used. 'region' specifies a field-
993b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  sensitive store model. Users can also specify 'basic', which
994b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  is far less precise but can more quickly analyze code.
995b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  'basic' was the default store model for checker-0.221 and
996b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek                  earlier.
997b8bb3e797c5687715c6d9d960ee573e4d0e62230Ted Kremenek
998e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek -no-failure-reports - Do not create a 'failures' subdirectory that includes
999e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek                       analyzer crash reports and preprocessed source files.
1000b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
10014f2b10b24bab0049020d268382eda144e2aa064cTom Care -stats - Generates visitation statistics for the project being analyzed.
10024f2b10b24bab0049020d268382eda144e2aa064cTom Care
10034f2b10b24bab0049020d268382eda144e2aa064cTom Care -maxloop N - specifiy the number of times a block can be visited before giving
10044f2b10b24bab0049020d268382eda144e2aa064cTom Care              up. Default is 3. Increase for more comprehensive coverage at a
10054f2b10b24bab0049020d268382eda144e2aa064cTom Care              cost of speed.
1006d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed KremenekENDTEXT
1007b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1008ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for list of checkers that are enabled.
1009ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy %EnabledCheckers;
1010ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekforeach my $lang ("c", "objective-c", "objective-c++", "c++") {
1011ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  pipe(FROM_CHILD, TO_PARENT);
1012ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  my $pid = fork();
1013ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if ($pid == 0) {
1014ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    close FROM_CHILD;
1015ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDOUT,">&", \*TO_PARENT);
1016ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    open(STDERR,">&", \*TO_PARENT);
1017ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    exec $Clang, ('--analyze', '-x', $lang, '-', '-###');
1018ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1019ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(TO_PARENT);
1020ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
1021ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    foreach my $val (split /\s+/) {
1022ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $val =~ s/\"//g;
1023ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($val =~ /-analyzer-checker\=([^\s]+)/) {
1024ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $EnabledCheckers{$1} = 1;
1025ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1026ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1027ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1028ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  waitpid($pid,0);
1029ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close(FROM_CHILD);
1030ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1031ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1032ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Query clang for complete list of checkers.
1033ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekpipe(FROM_CHILD, TO_PARENT);
1034ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $pid = fork();
1035ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif ($pid == 0) {
1036ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  close FROM_CHILD;
1037ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  open(STDOUT,">&", \*TO_PARENT);
1038ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  open(STDERR,">&", \*TO_PARENT);
1039ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  exec $Clang, ('-cc1', '-analyzer-checker-help');
1040ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1041ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekclose(TO_PARENT);
1042ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $foundCheckers = 0;
1043ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekwhile(<FROM_CHILD>) {
1044ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  if (/CHECKERS:/) {
1045ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $foundCheckers = 1;
1046ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    last;
1047ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  }
1048ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1049ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!$foundCheckers) {
1050ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  print "  *** Could not query Clang for the list of available checkers.";
1051ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1052ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekelse {
1053ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  print("\nAVAILABLE CHECKERS:\n\n");
1054ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  my $skip = 0;
1055ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  while(<FROM_CHILD>) {
10564cd6ea9989989e9f3a87b22c794ce76c6899d0a1Ted Kremenek    if (/experimental/) {
1057ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $skip = 1;
1058ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      next;
1059ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1060ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    if ($skip) {
1061ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      next if (!/^\s\s[^\s]/);
1062ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      $skip = 0;
1063ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1064ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    s/^\s\s//;
1065ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    if (/^([^\s]+)/) {
1066ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      # Is the checker enabled?
1067ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $checker = $1;
1068ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $enabled = 0;
1069ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      my $aggregate = "";
1070ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      foreach my $domain (split /\./, $checker) {
1071ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        $aggregate .= $domain;
1072ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        if ($EnabledCheckers{$aggregate}) {
1073ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek          $enabled =1;
1074ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek          last;
1075ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        }        
1076ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1077ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      
1078ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      if ($enabled) {
1079ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print " + ";
1080ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1081ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      else {
1082ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek        print "   ";
1083ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      }
1084ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1085ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    else {
1086ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek      print "   ";
1087ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    }
1088ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    print $_;
1089ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  } 
1090ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1091ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekwaitpid($pid,0);
1092ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekclose(FROM_CHILD);
10937fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1094b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
1095b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
1096ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek NOTE: "+" indicates that an analysis is enabled by default.
1097b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
10982b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
10992b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1100363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
110139eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
11025744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
11032b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
1104363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek $Prog -o /tmp/myhtmldir make -j4
11052b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
1106363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The above example causes analysis reports to be deposited into
1107363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
1108363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek A different subdirectory is created each time $Prog analyzes a project.
1109363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The analyzer should support most parallel builds, but not distributed builds.
11102b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
11112b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
11129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
11139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
11149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
11157cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# HtmlEscape - HTML entity encode characters that are special in HTML
11167cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11177cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11187cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub HtmlEscape {
11197cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
11207cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
11217cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $tmp = $arg;
112287f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/&/&amp;/g;
112387f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/</&lt;/g;
112487f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  $tmp =~ s/>/&gt;/g;
11257cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  return $tmp;
11267cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
11277cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11287cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11297cba11262458df05951432b54997eb40a35dbf9eTed Kremenek# ShellEscape - backslash escape characters that are special to the shell
11307cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11317cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11327cba11262458df05951432b54997eb40a35dbf9eTed Kremeneksub ShellEscape {
11337cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  # copy argument to new variable so we don't clobber the original
11347cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  my $arg = shift || '';
113587f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  if ($arg =~ /["\s]/) { return "'" . $arg . "'"; }
113687f8de72a3c5d61736a14dca271504aaa5020d6fTed Kremenek  return $arg;
11377cba11262458df05951432b54997eb40a35dbf9eTed Kremenek}
11387cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11397cba11262458df05951432b54997eb40a35dbf9eTed Kremenek##----------------------------------------------------------------------------##
11409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
11419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
11429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1143e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenekmy $AnalyzeHeaders = 0;
11449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
11459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
11467f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
1147363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
1148b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
114907c3767be59472e19183c7b51fae76481465cb51Zhongxing Xumy $StoreModel;
1150be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekmy $ConstraintsModel;
11518d8bc9157fccab6a4089c41cdad9e12045edd736Ted Kremenekmy $OutputFormat = "html";
11524f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $AnalyzerStats = 0;
11534f2b10b24bab0049020d268382eda144e2aa064cTom Caremy $MaxLoop = 0;
11549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
11559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
11569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1157a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
11589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
11599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1160ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1161ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekmy $displayHelp = 0;
1162ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
11639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
11649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
11659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
11669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
11679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
11689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
11692f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
1170ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    $displayHelp = 1;
1171ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    shift @ARGV;
1172ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek    next;
11739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
11749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1175e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  if ($arg eq '-analyze-headers') {
1176e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    shift @ARGV;    
1177e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    $AnalyzeHeaders = 1;
1178e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek    next;
1179e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  }
1180e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  
11819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
11829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
11839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
11849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
118523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
11869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
11879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1188db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # Construct an absolute path.  Uses the current working directory
1189db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    # as a base if the original path was not absolute.
1190db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    $HtmlDir = abs_path(shift @ARGV);
1191db51a55c4922b055a90a370ce9906455887a8564Ted Kremenek    
11929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
11939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
11947cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
11957cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--html-title(=(.+))?$/) {
11967cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    shift @ARGV;
11977cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
1198278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq '') {
11997cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      if (!@ARGV) {
12007cba11262458df05951432b54997eb40a35dbf9eTed Kremenek        DieDiag("'--html-title' option requires a string.\n");
12017cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      }
12027cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12037cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = shift @ARGV;
12047cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    } else {
12057cba11262458df05951432b54997eb40a35dbf9eTed Kremenek      $HtmlTitle = $2;
12067cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    }
12077cba11262458df05951432b54997eb40a35dbf9eTed Kremenek
12087cba11262458df05951432b54997eb40a35dbf9eTed Kremenek    next;
12097cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  }
12109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12112b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
12129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
12139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
12149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
12159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12167fe679f300bd063d7edf7071d14c7f3823ef8cceTed Kremenek
1217f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  if ($arg =~ /^--use-cc(=(.+))?$/) {
1218f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    shift @ARGV;
1219f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    my $cc;
1220f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1221278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1222f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      if (!@ARGV) {
1223f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek        DieDiag("'--use-cc' option requires a compiler executable name.\n");
1224f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      }
1225f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = shift @ARGV;
1226f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1227f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    else {
1228f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = $2;
1229f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
1230f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
1231f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    $ENV{"CCC_CC"} = $cc;
1232f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    next;
1233f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  }
1234f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  
12357cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  if ($arg =~ /^--use-c\+\+(=(.+))?$/) {
1236386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    shift @ARGV;
123751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    my $cxx;    
1238386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    
1239278a55103a66e3a83530f15d0df3d4b80ed4cfeeTed Kremenek    if (!defined $2 || $2 eq "") {
1240386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      if (!@ARGV) {
1241386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek        DieDiag("'--use-c++' option requires a compiler executable name.\n");
1242386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      }
124351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = shift @ARGV;
1244386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
1245386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    else {
124651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek      $cxx = $2;
1247386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
124851365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    
124951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek    $ENV{"CCC_CXX"} = $cxx;
1250386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    next;
1251386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  }
1252386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  
12539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
12549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
12559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
12569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
12579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
12589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
12597f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
12607f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
12617f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
12627f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
12637f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
12647f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
1265363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
1266363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
1267363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
1268363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
1269363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
127007c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu
127107c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  if ($arg eq "-store") {
127207c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    shift @ARGV;
1273be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $StoreModel = shift @ARGV;
1274be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    next;
1275be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  }
1276be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  
1277be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  if ($arg eq "-constraints") {
1278be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    shift @ARGV;
1279be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek    $ConstraintsModel = shift @ARGV;
128007c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu    next;
128107c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  }
1282363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
1283db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  if ($arg eq "-plist") {
1284db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    shift @ARGV;
1285db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    $OutputFormat = "plist";
1286db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek    next;
1287db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
12887753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  if ($arg eq "-plist-html") {
12897753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    shift @ARGV;
12907753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    $OutputFormat = "plist-html";
12917753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    next;
12927753b352366778d01c5cda4117356f181d3dd468Ted Kremenek  }
1293e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  
1294e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  if ($arg eq "-no-failure-reports") {
1295e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    $ENV{"CCC_REPORT_FAILURES"} = 0;
1296e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek    next;
1297e600bedcfea91622a0003fdb5f66c500b2f9f17dTed Kremenek  }
12984f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-stats") {
12994f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
13004f2b10b24bab0049020d268382eda144e2aa064cTom Care    $AnalyzerStats = 1;
13014f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
13024f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
13034f2b10b24bab0049020d268382eda144e2aa064cTom Care  if ($arg eq "-maxloop") {
13044f2b10b24bab0049020d268382eda144e2aa064cTom Care    shift @ARGV;
13054f2b10b24bab0049020d268382eda144e2aa064cTom Care    $MaxLoop = shift @ARGV;
13064f2b10b24bab0049020d268382eda144e2aa064cTom Care    next;
13074f2b10b24bab0049020d268382eda144e2aa064cTom Care  }
13087753b352366778d01c5cda4117356f181d3dd468Ted Kremenek
130923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
13100062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
13119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
13129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
13139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1314ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif (!@ARGV and $displayHelp == 0) {
131523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
1316ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek  $displayHelp = 1;
1317ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek}
1318ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek
1319ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenekif ($displayHelp) {
13209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
1321a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
13229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
13239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1324ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine where results go.
13257cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
13267cba11262458df05951432b54997eb40a35dbf9eTed Kremenek$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
13277cba11262458df05951432b54997eb40a35dbf9eTed Kremenek  unless (defined($HtmlTitle));
1328386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
13299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
1330684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
1331a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
13329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1333ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Determine the location of ccc-analyzer.
133451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $AbsRealBin = Cwd::realpath($RealBin);
133551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $Cmd = "$AbsRealBin/libexec/ccc-analyzer";
133651365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekmy $CmdCXX = "$AbsRealBin/libexec/c++-analyzer";
133751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek
1338ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenekif (!defined $Cmd || ! -x $Cmd) {
133951365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $Cmd = "$AbsRealBin/ccc-analyzer";
13406b89636db873142f562cf576df9bc195c5b8674bTed Kremenek  DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
1341ce87b929703cac0b3f236b0b0d1c7b78d8af38f2Ted Kremenek}
134251365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenekif (!defined $CmdCXX || ! -x $CmdCXX) {
134351365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  $CmdCXX = "$AbsRealBin/c++-analyzer";
134451365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek  DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
134551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek}
1346f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
1347fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenekif (!defined $ClangSB || ! -x $ClangSB) {
1348fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek  Diag("'clang' executable not found in '$RealBin/bin'.\n");
13496492200c313937adf8c9dd206790933a228e3ef3Ted Kremenek  Diag("Using 'clang' from path: $Clang\n");
1350fd9df0eddd7d2b190f740f33a3d08f611c0be3f0Ted Kremenek}
13510b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
1352ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted Kremenek# Set the appropriate environment variables.
1353ba90e8a12e6e8889035ed57fb49b40b9cd4ef990Ted KremenekSetHtmlEnv(\@ARGV, $HtmlDir);
13544f4b17da43d3be87a248e1e10bf0b7d8b5891efdTed Kremenek$ENV{'CC'} = $Cmd;
135551365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek$ENV{'CXX'} = $CmdCXX;
1356f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek$ENV{'CLANG'} = $Clang;
135751365b5f74977c13c4902991c076dff8fddc96b7Ted Kremenek$ENV{'CLANG_CXX'} = $ClangCXX;
13589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif ($Verbose >= 2) {
13599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
13609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1361a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenekif ($Verbose >= 3) {
1362a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek  $ENV{'CCC_ANALYZER_LOG'} = 1;
1363a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek}
1364e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenekif ($AnalyzeHeaders) {
1365e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek  push @AnalysesToRun,"-analyzer-opt-analyze-headers";  
1366e15fa2736413224dfdaf457e0fd7204d7c056b3dTed Kremenek}
13674f2b10b24bab0049020d268382eda144e2aa064cTom Careif ($AnalyzerStats) {
13684f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @AnalysesToRun, '-analyzer-stats';
13694f2b10b24bab0049020d268382eda144e2aa064cTom Care}
13704f2b10b24bab0049020d268382eda144e2aa064cTom Careif ($MaxLoop > 0) {
13714f2b10b24bab0049020d268382eda144e2aa064cTom Care  push @AnalysesToRun, '-analyzer-max-loop ' . $MaxLoop;
13724f2b10b24bab0049020d268382eda144e2aa064cTom Care}
13734f2b10b24bab0049020d268382eda144e2aa064cTom Care
13749012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
13759012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek
13763cab2b1c3798f2a6aa3526875801a02aebf6fc1dZhongxing Xuif (defined $StoreModel) {
137707c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu  $ENV{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
137807c3767be59472e19183c7b51fae76481465cb51Zhongxing Xu}
1379be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenekif (defined $ConstraintsModel) {
1380be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek  $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
1381be1fe1eb12a1cb91c8e3a9fcc2db4dfe989def6cTed Kremenek}
1382db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenekif (defined $OutputFormat) {
1383db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
1384db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek}
1385db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
13869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
1387524c308506e77e173092e87a0724a27817311428Ted Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX);
13889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
13897753b352366778d01c5cda4117356f181d3dd468Ted Kremenekif (defined $OutputFormat) {
13901182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  if ($OutputFormat =~ /plist/) {
13911182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis run complete.\n";
13921182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar    Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
13931182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  }
13941182502c78ad61693995f5b3ff516fdf983b5cd7Daniel Dunbar  elsif ($OutputFormat =~ /html/) {
13957753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    # Postprocess the HTML directory.
13964f2b10b24bab0049020d268382eda144e2aa064cTom Care    my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats);
13977753b352366778d01c5cda4117356f181d3dd468Ted Kremenek
13987753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ViewResults and -r "$HtmlDir/index.html") {
13997753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Analysis run complete.\n";
14007753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
14017753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      my $ScanView = Cwd::realpath("$RealBin/scan-view");
14027753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      if (! -x $ScanView) { $ScanView = "scan-view"; }
14037753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exec $ScanView, "$HtmlDir";
14047753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1405db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek
14067753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    if ($ExitStatusFoundBugs) {
14077753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 1 if ($NumBugs > 0);
14087753b352366778d01c5cda4117356f181d3dd468Ted Kremenek      exit 0;
14097753b352366778d01c5cda4117356f181d3dd468Ted Kremenek    }
1410db4f5f26182c522e659af655e2582cc5ea35a971Ted Kremenek  }
1411363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
1412363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
14135656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
14145656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
1415