scan-build revision 9f9b1fded49acff77e61b3ed1afc8bbaaefe6f34
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);
229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Verbose = 0;       # Verbose output from this script.
249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Prog = "scan-build";
25f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildName;
26f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildDate;
2795aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenekmy $CXX;  # Leave undefined initially.
289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
290e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $TERM = $ENV{'TERM'};
300e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenekmy $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT
310e6893840fdd69a8a4d6561663a5a29af237ae08Ted Kremenek                and defined $ENV{'SCAN_BUILD_COLOR'});
3223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
33b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
34b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Diagnostics
35b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
36b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
3723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub Diag {
3823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
3923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, MAGENTA "$Prog: @_";
4023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
4123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
4223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
4323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: @_";
4423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }  
4523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
4623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
47991c54b9b7409656e5593364e065878b5210d556Ted Kremeneksub DiagCrashes {
48991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Dir = shift;
49991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("The analyzer crashed on some source files.\n");
50386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  Diag ("Preprocessed versions of crashed files were deposited in '$Dir/crashes'.\n");
51991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("Please consider submitting a bug report using these files:\n");
52991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("  http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
53991c54b9b7409656e5593364e065878b5210d556Ted Kremenek}
54991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
5523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
5623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
5723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
5823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
5923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
6023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
6123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
6223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
6323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
6423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
6523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
6623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
68b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Some initial preprocessing of Clang options.
69b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
70b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
71b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $ClangSB = "$RealBin/clang";
72b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $Clang = $ClangSB;
73b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
74b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekif (! -x $ClangSB) {
75b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  $Clang = "clang";
76b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek}
77b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
78b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy %AvailableAnalyses;
79b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
80b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Query clang for analysis options.
8163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenekopen(PIPE, "-|", $Clang, "--help") or
82b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  DieDiag("Cannot execute '$Clang'");
8363c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
84b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $FoundAnalysis = 0;
85b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
86b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekwhile(<PIPE>) {
87b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  if ($FoundAnalysis == 0) {
88b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    if (/Available Source Code Analyses/) {
89b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek      $FoundAnalysis = 1;
90b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
91991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
92b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next;
93b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
94b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    
95b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
96b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next if ($1 =~ /-dump/ or $1 =~ /-view/ 
97b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek             or $1 =~ /-checker-simple/ or $1 =~ /-warn-uninit/);
98b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek             
99b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    $AvailableAnalyses{$1} = $2;
100b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next;
101b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
102b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  
103b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  last;
104b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek}
105b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
106b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekclose (PIPE);
107b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
108b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy %AnalysesDefaultEnabled = (
109b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  '-warn-dead-stores' => 1,
110b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  '-checker-cfref' => 1,
1119012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  '-warn-objc-methodsigs' => 1,
112bde3a051933b6829ed79d6db0118231c2c01b105Ted Kremenek  '-warn-objc-missing-dealloc' => 1,
113bde3a051933b6829ed79d6db0118231c2c01b105Ted Kremenek  '-warn-objc-unused-ivars' => 1
114b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek);
115b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
116b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
117fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
120a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
1219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
122fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift @_;
124fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    
125fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
126fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
127fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $Dir = "/tmp";
128fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
129fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
130fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my @CurrentTime = localtime();
1349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1399d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Determine the run number.
1429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (-d $Dir) {
1469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
14823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1509cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # Iterate over all files in the specified directory.
1529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    my $max = 0;
1549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
15629da6c59df7ca994e75139303a9230b24e2abaadTed Kremenek    my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
1579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    foreach my $f (@FILES) {
1609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
161fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
162fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
163fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
164fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
165fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
166fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
168fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
18423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
186fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
187fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
188fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.");
189fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
190fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
193fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
197fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
200fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  my $NewDir;
201fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
202fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
203fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
204fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
205fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek    $NewDir = "$Dir/$DateString-$RunNumber";
206fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
207fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  system 'mkdir','-p',$NewDir;
208fc0898a6529f3d6bc9a4effdb3202aee13170fe3Ted Kremenek  return $NewDir;
2099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
211a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
2129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
2149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
2169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
2179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
2199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Cmd =~ /configure/) {
2239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
22723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
23457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
23557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
23657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
23857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
23923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
240a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
241a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2427ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2437ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
24463c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
24523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
246a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
247a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
248a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
249a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
25063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
251a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
25257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
25357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
25457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2657a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  # Ignore /usr, /Library, /System, /Developer
2667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return if ( $x =~ /^\/usr/ or $x =~ /^\/Library/
2677a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek              or $x =~ /^\/System/ or $x =~ /^\/Developer/);
2687a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2707a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
27420b2bae90c102f405ba70f602c45660ce1cd0c4eTed Kremenek  chop $Prefix while (!($x =~ /^\Q$Prefix/));
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2827a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2847a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2857a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2867a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2877a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2887a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
28963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2907a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
29163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
29263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2937a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2947a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2957a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2967a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
29763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2987a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2997a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
30020161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
3017a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
3027a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
3037a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
3045744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
3055744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3065744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
30757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
30857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
30957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
31057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
31157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3135744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3145744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3155744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3165744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3175744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
31857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
31957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
32057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
32157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
32257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
323fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
32457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
32520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
32657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
32757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
32857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
32957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
33057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
331809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
33220161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
333684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
334684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
33523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3365744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3375744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $BugDesc = "";
33822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugFile = "";
33922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugPathLength = 1;
34022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugLine = 0;
3415744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3425744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
3435744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
3445744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    if (/<!-- BUGDESC (.*) -->$/) {
3455744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek      $BugDesc = $1;
3465744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
34722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
34822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugFile = $1;
3497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
35022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
35122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
35222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
35322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
35422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
35522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
35622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3575744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3585744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3595744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
3605744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
36122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  push @$Index,[ $FName, $BugDesc, $BugFile, $BugLine, $BugPathLength ];
36222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
36322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
36522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek# CopyJS - Copy JavaScript code to target directory.
36622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
36722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremeneksub CopyJS {
36922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
37022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
37122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
37223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
37322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$RealBin/sorttable.js");  
37422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
37520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("cp", "$RealBin/sorttable.js", "$Dir");
37622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
37723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
37822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
3795744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
3805744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3815744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
3839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
3849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
385a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
3869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
388684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  my $BaseDir = shift;
3899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
390fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
3919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
39323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
394363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
3959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
3969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
398991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Crashes = 0;
399991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my @files = grep { if ($_ eq "crashes") { $Crashes++; }
400991c54b9b7409656e5593364e065878b5210d556Ted Kremenek                     /^report-.*\.html$/; } readdir(DIR);
4019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
4029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
403991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if (scalar(@files) == 0 and $Crashes == 0) {
40423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
40520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-fR", $Dir);
406363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
4085744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
409991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  # Scan each report file and build an index.  
410991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my @Index;    
4115744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
4125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
413d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  # Scan the crashes directory and use the information in the .info files
414d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  # to update the common prefix directory.
415d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  if (-d "$Dir/crashes") {
416d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    opendir(DIR, "$Dir/crashes");
417d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    my @files = grep { /[.]info$/; } readdir(DIR);
418d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    closedir(DIR);
419d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    foreach my $file (@files) {
420d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      open IN, "$Dir/crashes/$file" or DieDiag("cannot open $file\n");
421d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      my $Path = <IN>;
422d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      if (defined $Path) { UpdatePrefix($Path); }
423d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek      close IN;
424d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek    }    
425d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  }
426d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek  
42763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Generate an index.html file.  
42863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  my $FName = "$Dir/index.html";  
42963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
4305744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
4316e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
4326e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4335744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
4345744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
4355744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
4367f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek<style type="text/css">
4377f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek body { color:#000000; background-color:#ffffff }
43822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek body { font-family: Helvetica, sans-serif; font-size:9pt }
4397f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek h1 { font-size:12pt }
440991c54b9b7409656e5593364e065878b5210d556Ted Kremenek table thead {
44122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek   background-color:#eee; color:#666666;
44222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek   font-weight: bold; cursor: default;
443bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   text-align:center;
444bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   border-top: 2px solid #000000;
445bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   border-bottom: 2px solid #000000;
446bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   font-weight: bold; font-family: Verdana
447bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek } 
448991c54b9b7409656e5593364e065878b5210d556Ted Kremenek table { border: 1px #000000 solid }
449991c54b9b7409656e5593364e065878b5210d556Ted Kremenek table { border-collapse: collapse; border-spacing: 0px }
4507f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek td { border-bottom: 1px #000000 dotted }
45122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek td { padding:5px; padding-left:8px; padding-right:8px }
452d8c6d0c8a5f970240cc4cbf8eddeae037d1b29eaTed Kremenek td { text-align:left; font-size:9pt }
45322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek td.View   { padding-left: 10px }
4547f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek</style>
45522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
4566e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
4576e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
4586e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
4596e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
4606e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
4616e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
4626e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
4636e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
4646e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4656e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
4666e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4676e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
4686e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
4696e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
4706e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4716e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
4726e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
4736e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4746e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
4756e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
4766e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
4776e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
4786e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
4796e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
480991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if (scalar(@files)) {
481991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    # Print out the summary table.
482991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my %Totals;
4836e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
484991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $row ( @Index ) {
485991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      #my $bug_type = lc($row->[1]);
486991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $bug_type = ($row->[1]);
4876e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
488991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      if (!defined $Totals{$bug_type}) { $Totals{$bug_type} = 1; }
489991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      else { $Totals{$bug_type}++; }
4906e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
491991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
492991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    print OUT "<h3>Bug Summary</h3>";
493991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
494991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $BuildName) {
495991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
4966e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
497f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
4986e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
4996e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<table class="sortable">
5006e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<tr>
5016e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  <td>Bug Type</td>
5026e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  <td>Quantity</td>
5032645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort">Display?</td>
5046e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</tr>
5056e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
5066e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
507991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $key ( sort { $a cmp $b } keys %Totals ) {
508991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $x = lc($key);
509991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $x =~ s/[ ,'"]+/_/g;
510991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "<tr><td>$key</td><td>$Totals{$key}</td><td><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></td></tr>\n";
511991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
5126e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
5136e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
5146e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
5156e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
5166e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
5176e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<h3>Reports</h3>
51822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<table class="sortable">
5197f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek<tr>
52088a96d6c3fe2b1b9d80b39c21cf7aca4aa9fcf08Ted Kremenek  <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span>
521bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
522bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>Line</td>
523bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>Path Length</td>
5242645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort"></td>
5257f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek</tr>
5265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
5279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
528991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $prefix = GetPrefix();
529991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $regex;
530991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFileRegex;
531991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my $InFilePrefix = "File:</td><td>";
5327a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
533991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (defined $prefix) { 
534991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $regex = qr/^\Q$prefix\E/is;    
535991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
536991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }    
5377a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
538991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    for my $row ( sort { $a->[1] cmp $b->[1] } @Index ) {
5395744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
540991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $x = lc($row->[1]);
541991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      $x =~ s/[ ,'"]+/_/g;
5426e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
543991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "<tr class=\"bt_$x\">\n";
5445744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
545991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $ReportFile = $row->[0];
5469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
547991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT " <td class=\"DESC\">";
548991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      #print OUT lc($row->[1]);
549991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT $row->[1];
550991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "</td>\n";
5515744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
552991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Update the file prefix.
5537a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    
554991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      my $fname = $row->[2];
555991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      if (defined $regex) {
556991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        $fname =~ s/$regex//;
557991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
558991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
5593e56e0b8b285e86eed4d191b1da93ded7382a847Ted Kremenek
560991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "<td>$fname</td>\n";
5617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
562991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Print the rest of the columns.
563991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      for my $j ( 3 .. $#{$row} ) {
564991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        print OUT "<td>$row->[$j]</td>\n"
565991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
5667f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
567991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # Emit the "View" link.
568991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT " <td class=\"View\"><a href=\"$ReportFile#EndPath\">View</a></td>\n";
5693cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek        
570991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      # End the row.
571991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT "</tr>\n";
572991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
573991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
574991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    print OUT "</table>\n";
575991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  }
576991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
577991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if ($Crashes) {
578991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    # Read the crash directory for files.
579991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    opendir(DIR, "$Dir/crashes");
580991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    my @files = grep { /[.]info$/ } readdir(DIR);
581991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    closedir(DIR);
582991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
583991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    if (scalar(@files)) {
584991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT <<ENDTEXT;
5855d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek<h3>Analyzer Failures</h3>
586991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
5875d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek<p>The analyzer had problems processing the following files:</p>
588991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
589991c54b9b7409656e5593364e065878b5210d556Ted Kremenek<table>
5909f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>
591991c54b9b7409656e5593364e065878b5210d556Ted KremenekENDTEXT
592991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
593991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      foreach my $file (sort @files) {
594991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        $file =~ /(.+).info$/;
595991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Get the preprocessed file.
596991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $ppfile = $1;
597991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Open the info file and get the name of the source file.
598991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        open (INFO, "$Dir/crashes/$file") or
599991c54b9b7409656e5593364e065878b5210d556Ted Kremenek          die "Cannot open $Dir/crashes/$file\n";
600991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        my $srcfile = <INFO>;
6015d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $srcfile;
6025d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        my $problem = <INFO>;
6035d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        chomp $problem;
604991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        close (INFO);
605991c54b9b7409656e5593364e065878b5210d556Ted Kremenek        # Print the information in the table.
606d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek        my $prefix = GetPrefix();
6079f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek        if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
6089f9b1fded49acff77e61b3ed1afc8bbaaefe6f34Ted Kremenek        print OUT "<tr><td>$problem</td><td>$srcfile</td><td><a href=\"crashes/$ppfile\">$ppfile</a></td><td><a href=\"crashes/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
609991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      }
610991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
611991c54b9b7409656e5593364e065878b5210d556Ted Kremenek      print OUT <<ENDTEXT;
612991c54b9b7409656e5593364e065878b5210d556Ted Kremenek</table>
613991c54b9b7409656e5593364e065878b5210d556Ted Kremenek<p>Please consider submitting preprocessed files as <a href="http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs">bug reports</a>.</p>
614991c54b9b7409656e5593364e065878b5210d556Ted KremenekENDTEXT
615991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    }
6165744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
6175744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
618991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  print OUT "</body></html>\n";  
6195744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
62022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  CopyJS($Dir);
62120161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
62220161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  # Make sure $Dir and $BaseDir are world readable/executable.
62320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("chmod", "755", $Dir);
624fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
62520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
62623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
627150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  Diag("$Num bugs found.\n");
628150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  if ($Num > 0 && -r "$Dir/index.html") {
629150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek    Diag("Open '$Dir/index.html' to examine bug reports.\n");
630150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  }
631363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
632991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  DiagCrashes($Dir) if ($Crashes);
633991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  
634363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  return $Num;
6359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
6369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
6379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
638dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
639dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
640dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
6416b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
6426b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
6436b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
6446b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
6456b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
6466b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
6476b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
6486b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
6496b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
6506b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
6516b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
6526b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
6536b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
6546b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
6556b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
6566b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
6576b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
658dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremeneksub RunBuildCommand {
659dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
660dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
6617442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
662dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
6636195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
664dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
6653301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  # Get only the part of the command after the last '/'.
6663301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  if ($Cmd =~ /\/([^\/]+)$/) {
6673301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek    $Cmd = $1;
6683301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  }
6693301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  
67063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  if ($Cmd eq "gcc" or $Cmd eq "cc" or $Cmd eq "llvm-gcc" 
67163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek   or $Cmd eq "ccc-analyzer") {
672dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
6736195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
674dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
6757442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
6767442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
6776b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
6788912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
6797442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
6807442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    elsif ($Cmd eq "xcodebuild") {
6816b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
6827442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
6836b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
6846b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
6856b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($Cmd eq "xcodebuild") {
686cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable distributed builds for xcodebuild.
6876b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    AddIfNotPresent($Args,"-nodistribute");
688cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek
689cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable PCH files until clang supports them.
690cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
691915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    
692915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
693915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
694915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # when linking such files.
69595aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek    die if (!defined $CXX);
69695aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek    my $LDPLUSPLUS = `which $CXX`;
697915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $LDPLUSPLUS =~ s/\015?\012//;  # strip newlines
698915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS;    
6996b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
700dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
7015a4ddaf39a26f9c7e30d3aeca17c702213a29d9fTed Kremenek  return (system(@$Args) >> 8);
702dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
703dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
704dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
7059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
7069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
708a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
7099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7105744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
711a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
7122b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
713f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
714f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
715fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
716f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
717f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
718f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
719f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
7202b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
7212b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
722363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -o             - Target directory for HTML report files.  Subdirectories
723a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop                  will be created as needed to represent separate "runs" of
7242b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  the analyzer.  If this option is not specified, a directory
7252b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  is created in /tmp to store the reports.
7261262fc4d66584224234691d30d779f8ff004585cTed Kremenek
727363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -h             - Display this message.
728363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
7291262fc4d66584224234691d30d779f8ff004585cTed Kremenek
730363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -k             - Add a "keep on going" option to the specified build command.
731363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --keep-going     This option currently supports make and xcodebuild.
732f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  This is a convenience option; one can specify this
733f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  behavior directly using build options.
7342b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
735363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --status-bugs  - By default, the exit status of $Prog is the same as the
736363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  executed build command.  Specifying this option causes the
737363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  exit status of $Prog to be 1 if it found potential bugs
738363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  and 0 otherwise.
7392b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
740386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-cc [compiler path]   - By default, $Prog uses 'gcc' to compile and link
741386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-cc=[compiler path]     your C and Objective-C code. Use this option
742386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
743386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
744386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-c++ [compiler path]  - By default, $Prog uses 'g++' to compile and link
745386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-c++=[compiler path]    your C++ and Objective-C++ code. Use this option
746386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
747f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek
748363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -v             - Verbose output from $Prog and the analyzer.
749386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                  A second and third '-v' increases verbosity.
750363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
751363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -V             - View analysis results in a web browser when the build
752363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --view           completes.
7537f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
754b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
755386c69316668b9ea8c2591af56f994be16e3ff62Ted KremenekAVAILABLE ANALYSES (multiple analyses may be specified):
756d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek
757d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed KremenekENDTEXT
758b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
759b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  foreach my $Analysis (sort keys %AvailableAnalyses) {
760fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if (defined $AnalysesDefaultEnabled{$Analysis}) {
761363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek      print " (+)";
762b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
763b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    else {
764363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek      print "    ";
765b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
766b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    
767b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    print " $Analysis  $AvailableAnalyses{$Analysis}\n";
768b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
769b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  
770b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
771b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
772363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek NOTE: "(+)" indicates that an analysis is enabled by default unless one
773363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek       or more analysis options are specified
774b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
7752b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
7762b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
777363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
77839eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
7795744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
7802b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
781363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek $Prog -o /tmp/myhtmldir make -j4
7822b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
783363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The above example causes analysis reports to be deposited into
784363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
785363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek A different subdirectory is created each time $Prog analyzes a project.
786363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The analyzer should support most parallel builds, but not distributed builds.
7872b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
7882b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
7899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
7939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
7969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
7977f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
798363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
799b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
8009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
8029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
803a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
8049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
8079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
8099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
8119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8122f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
8139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    DisplayHelp();
814a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop    exit 0;
8159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
817fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AvailableAnalyses{$arg}) {
8181262fc4d66584224234691d30d779f8ff004585cTed Kremenek    shift @ARGV;
819b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    push @AnalysesToRun, $arg;
8201262fc4d66584224234691d30d779f8ff004585cTed Kremenek    next;
8211262fc4d66584224234691d30d779f8ff004585cTed Kremenek  }
8221262fc4d66584224234691d30d779f8ff004585cTed Kremenek  
8239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
8249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
8259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
8269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
82723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
8289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
8299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
8309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $HtmlDir = shift @ARGV;
8319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
8329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8342b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
8359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
8369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
8379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
8389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
840f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  if ($arg =~ /^--use-cc(=(.+))?$/) {
841f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    shift @ARGV;
842f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    my $cc;
843f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
844f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    if ($2 eq "") {
845f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      if (!@ARGV) {
846f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek        DieDiag("'--use-cc' option requires a compiler executable name.\n");
847f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      }
848f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = shift @ARGV;
849f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
850f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    else {
851f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = $2;
852f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
853f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
854f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    $ENV{"CCC_CC"} = $cc;
855f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    next;
856f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  }
857f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  
858386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  if ($arg =~ /^--use-c[+][+](=(.+))?$/) {
859386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    shift @ARGV;
860386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    
861386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    if ($2 eq "") {
862386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      if (!@ARGV) {
863386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek        DieDiag("'--use-c++' option requires a compiler executable name.\n");
864386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      }
865386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      $CXX = shift @ARGV;
866386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
867386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    else {
868386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      $CXX = $2;
869386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
870386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    next;
871386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  }
872386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  
8739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
8749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
8759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
8769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
8779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8797f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
8807f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
8817f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
8827f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
8837f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
8847f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
885363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
886363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
887363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
888363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
889363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
890363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
89123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
8920062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
8939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
8949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
89723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
8989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
899a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
9009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
9019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
902386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
903386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
9049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
905684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
906a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
9079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Set the appropriate environment variables.
909a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopSetHtmlEnv(\@ARGV, $HtmlDir);
9109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9110b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenekmy $Cmd = "$RealBin/ccc-analyzer";
9120b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
91323cfca3760c482f8543daab62051f5eaa1f98fb4Ted KremenekDieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n")
9140b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek  if (! -x $Cmd);
915f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
916b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekif (! -x $ClangSB) {
917b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  Diag("'clang' executable not found in '$RealBin'.\n");
918b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  Diag("Using 'clang' from path.\n");
919f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek}
9200b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
92195aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenekif (defined $CXX) {
92295aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek  $ENV{'CXX'} = $CXX;
92395aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek}
92495aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenekelse {
92595aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek  $CXX = 'g++';  # This variable is used by other parts of scan-build
92695aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek                 # that need to know a default C++ compiler to fall back to.
92795aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek}
92895aa1050cd170f9729ca66a1b2e2f0219458671eTed Kremenek  
9294f4b17da43d3be87a248e1e10bf0b7d8b5891efdTed Kremenek$ENV{'CC'} = $Cmd;
930f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek$ENV{'CLANG'} = $Clang;
9319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif ($Verbose >= 2) {
9339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
9349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
9359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
936a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenekif ($Verbose >= 3) {
937a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek  $ENV{'CCC_ANALYZER_LOG'} = 1;
938a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek}
939a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek
9409012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenekif (scalar(@AnalysesToRun) == 0) {
9419012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  foreach my $key (keys %AnalysesDefaultEnabled) {
9429012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek    push @AnalysesToRun,$key;
9439012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  }
94401006786e3760cc48c5e94d731b468b811b976d2Ted Kremenek}
9451262fc4d66584224234691d30d779f8ff004585cTed Kremenek
9469012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
9479012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek
9489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
9495656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
9509cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess the HTML directory.
952363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $NumBugs = Postprocess($HtmlDir, $BaseDir);
9537f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
9547f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekif ($ViewResults and -r "$HtmlDir/index.html") {
9557f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  # Only works on Mac OS X (for now).
9567f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  print "Viewing analysis results: '$HtmlDir/index.html'\n";
95720161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("open", "$HtmlDir/index.html");
9587f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek}
9595656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
960363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekif ($ExitStatusFoundBugs) {
961363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  exit 1 if ($NumBugs > 0);
962363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  exit 0;
963363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
964363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
9655656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
9665656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
967