scan-build revision 386c69316668b9ea8c2591af56f994be16e3ff62
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;
27386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenekmy $CXX = 'g++';
289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
29f2f8d6c4718564dab73df3b5aa2d0be21bc6a163Ted Kremenekmy $UseColor = ((($ENV{'TERM'} eq 'xterm-color') and -t STDOUT)
30f2f8d6c4718564dab73df3b5aa2d0be21bc6a163Ted Kremenek                and defined($ENV{'SCAN_BUILD_COLOR'}));
3123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
32b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
33b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Diagnostics
34b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
35b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
3623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub Diag {
3723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
3823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, MAGENTA "$Prog: @_";
3923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
4023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
4123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
4223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: @_";
4323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }  
4423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
4523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
46991c54b9b7409656e5593364e065878b5210d556Ted Kremeneksub DiagCrashes {
47991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Dir = shift;
48991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("The analyzer crashed on some source files.\n");
49386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  Diag ("Preprocessed versions of crashed files were deposited in '$Dir/crashes'.\n");
50991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("Please consider submitting a bug report using these files:\n");
51991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  Diag ("  http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
52991c54b9b7409656e5593364e065878b5210d556Ted Kremenek}
53991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
5423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
5523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
5623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
5723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
5823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
5923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
6023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
6123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
6223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
6323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
6423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
6523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
67b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Some initial preprocessing of Clang options.
68b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
69b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
70b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $ClangSB = "$RealBin/clang";
71b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $Clang = $ClangSB;
72b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
73b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekif (! -x $ClangSB) {
74b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  $Clang = "clang";
75b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek}
76b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
77b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy %AvailableAnalyses;
78b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
79b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Query clang for analysis options.
8063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenekopen(PIPE, "-|", $Clang, "--help") or
81b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  DieDiag("Cannot execute '$Clang'");
8263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
83b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $FoundAnalysis = 0;
84b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
85b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekwhile(<PIPE>) {
86b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  if ($FoundAnalysis == 0) {
87b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    if (/Available Source Code Analyses/) {
88b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek      $FoundAnalysis = 1;
89b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
90991c54b9b7409656e5593364e065878b5210d556Ted Kremenek
91b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next;
92b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
93b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    
94b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
95b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next if ($1 =~ /-dump/ or $1 =~ /-view/ 
96b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek             or $1 =~ /-checker-simple/ or $1 =~ /-warn-uninit/);
97b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek             
98b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    $AvailableAnalyses{$1} = $2;
99b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next;
100b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
101b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  
102b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  last;
103b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek}
104b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
105b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekclose (PIPE);
106b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
107b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy %AnalysesDefaultEnabled = (
108b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  '-warn-dead-stores' => 1,
109b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  '-checker-cfref' => 1,
1109012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  '-warn-objc-methodsigs' => 1,
111bde3a051933b6829ed79d6db0118231c2c01b105Ted Kremenek  '-warn-objc-missing-dealloc' => 1,
112bde3a051933b6829ed79d6db0118231c2c01b105Ted Kremenek  '-warn-objc-unused-ivars' => 1
113b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek);
114b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
115b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
116fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
119a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
1209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
121fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift @_;
123fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    
124fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
125fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
126fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $Dir = "/tmp";
127fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
128fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
129fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my @CurrentTime = localtime();
1339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1389d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Determine the run number.
1419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (-d $Dir) {
1459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
14723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1509cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # Iterate over all files in the specified directory.
1519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    my $max = 0;
1539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
15529da6c59df7ca994e75139303a9230b24e2abaadTed Kremenek    my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
1569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    foreach my $f (@FILES) {
1599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
160fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
161fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
162fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
163fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
164fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
165fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
167fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
18323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
185fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
186fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
187fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.");
188fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
189fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
192fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
196fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
199fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
200fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    my $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
201fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    mkdir $NewDir;
202fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    return $NewDir;
203fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
204fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
205fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    return "$Dir/$DateString-$RunNumber";
206fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
2079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
209a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
2109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
2129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
2149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
2159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
2179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Cmd =~ /configure/) {
2219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
22523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
23257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
23357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
23457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
23657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
23723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
238a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
239a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2407ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2417ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
24263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
24323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
244a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
245a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
246a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
247a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
24863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
249a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
25057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
25157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
25257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2537a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2547a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  # Ignore /usr, /Library, /System, /Developer
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return if ( $x =~ /^\/usr/ or $x =~ /^\/Library/
2657a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek              or $x =~ /^\/System/ or $x =~ /^\/Developer/);
2667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2677a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2687a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2707a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  chop $Prefix while (!($x =~ /^$Prefix/));
2737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2827a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2847a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2857a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2867a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
28763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2887a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
28963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
29063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2917a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2927a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2937a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2947a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
29563c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2967a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2977a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
29820161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
2997a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
3007a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
3017a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
3025744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
3035744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3045744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
30557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
30657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
30757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
30857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
30957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3105744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3115744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3135744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3145744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3155744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
31657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
31757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
31857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
31957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
32057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
321fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
32257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
32320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
32457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
32557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
32657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
32757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
32857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
329809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
33020161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
331684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
332684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
33323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3345744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3355744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $BugDesc = "";
33622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugFile = "";
33722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugPathLength = 1;
33822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugLine = 0;
3395744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3405744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
3415744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
3425744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    if (/<!-- BUGDESC (.*) -->$/) {
3435744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek      $BugDesc = $1;
3445744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
34522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
34622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugFile = $1;
3477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
34822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
34922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
35022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
35122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
35222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
35322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
35422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3555744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3565744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3575744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
3585744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
35922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  push @$Index,[ $FName, $BugDesc, $BugFile, $BugLine, $BugPathLength ];
36022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
36122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
36322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek# CopyJS - Copy JavaScript code to target directory.
36422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
36522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremeneksub CopyJS {
36722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
36922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
37023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
37122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$RealBin/sorttable.js");  
37222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
37320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("cp", "$RealBin/sorttable.js", "$Dir");
37422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
37523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
37622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
3775744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
3785744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3795744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
3819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
3829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
383a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
3849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
386684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  my $BaseDir = shift;
3879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
388fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
3899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
39123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
392363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
3939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
3949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
396991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my $Crashes = 0;
397991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  my @files = grep { if ($_ eq "crashes") { $Crashes++; }
398991c54b9b7409656e5593364e065878b5210d556Ted Kremenek                     /^report-.*\.html$/; } readdir(DIR);
3999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
4009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
401991c54b9b7409656e5593364e065878b5210d556Ted Kremenek  if (scalar(@files) == 0 and $Crashes == 0) {
40223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
40320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-fR", $Dir);
40423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    # Remove the base directory if it contains no files (don't use '-R').
405991c54b9b7409656e5593364e065878b5210d556Ted Kremenek    system ("rm", "-f", $BaseDir) if (defined $BaseDir);
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>
5905d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</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();
607d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek        if (defined $prefix) { $srcfile =~ s/^$prefix//; }        
6085d31f83bbe990aeb070ce6c8d919d229d4eb5052Ted Kremenek        print OUT "<tr><td>$problem</td><td>$srcfile</td><td class=\"View\"><a href=\"crashes/$ppfile\">View</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.
695386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    my $LDPLUSPLUS = `$CXX`;
696915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $LDPLUSPLUS =~ s/\015?\012//;  # strip newlines
697915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS;    
6986b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
699dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
7005a4ddaf39a26f9c7e30d3aeca17c702213a29d9fTed Kremenek  return (system(@$Args) >> 8);
701dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
702dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
703dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
7049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
7059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
707a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
7089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7095744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
710a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
7112b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
712f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
713f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
714fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
715f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
716f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
717f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
718f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
7192b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
7202b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
721363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -o             - Target directory for HTML report files.  Subdirectories
722a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop                  will be created as needed to represent separate "runs" of
7232b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  the analyzer.  If this option is not specified, a directory
7242b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  is created in /tmp to store the reports.
7251262fc4d66584224234691d30d779f8ff004585cTed Kremenek
726363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -h             - Display this message.
727363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
7281262fc4d66584224234691d30d779f8ff004585cTed Kremenek
729363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -k             - Add a "keep on going" option to the specified build command.
730363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --keep-going     This option currently supports make and xcodebuild.
731f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  This is a convenience option; one can specify this
732f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  behavior directly using build options.
7332b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
734363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --status-bugs  - By default, the exit status of $Prog is the same as the
735363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  executed build command.  Specifying this option causes the
736363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  exit status of $Prog to be 1 if it found potential bugs
737363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  and 0 otherwise.
7382b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
739386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-cc [compiler path]   - By default, $Prog uses 'gcc' to compile and link
740386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-cc=[compiler path]     your C and Objective-C code. Use this option
741386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
742386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
743386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-c++ [compiler path]  - By default, $Prog uses 'g++' to compile and link
744386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek --use-c++=[compiler path]    your C++ and Objective-C++ code. Use this option
745386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                              to specify an alternate compiler.
746f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek
747363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -v             - Verbose output from $Prog and the analyzer.
748386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek                  A second and third '-v' increases verbosity.
749363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
750363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -V             - View analysis results in a web browser when the build
751363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --view           completes.
7527f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
753b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
754386c69316668b9ea8c2591af56f994be16e3ff62Ted KremenekAVAILABLE ANALYSES (multiple analyses may be specified):
755d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed Kremenek
756d52e4252264f9d1f62da0b5b89d099cd7dd7fa2fTed KremenekENDTEXT
757b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
758b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  foreach my $Analysis (sort keys %AvailableAnalyses) {
759fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if (defined $AnalysesDefaultEnabled{$Analysis}) {
760363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek      print " (+)";
761b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
762b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    else {
763363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek      print "    ";
764b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
765b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    
766b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    print " $Analysis  $AvailableAnalyses{$Analysis}\n";
767b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
768b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  
769b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
770b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
771363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek NOTE: "(+)" indicates that an analysis is enabled by default unless one
772363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek       or more analysis options are specified
773b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
7742b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
7752b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
776363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
77739eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
7785744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
7792b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
780363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek $Prog -o /tmp/myhtmldir make -j4
7812b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
782363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The above example causes analysis reports to be deposited into
783363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
784363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek A different subdirectory is created each time $Prog analyzes a project.
785363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The analyzer should support most parallel builds, but not distributed builds.
7862b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
7872b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
7889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
7929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
7959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
7967f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
797363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
798b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
7999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
8019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
802a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
8039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
8069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
8089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
8109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8112f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
8129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    DisplayHelp();
813a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop    exit 0;
8149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
816fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AvailableAnalyses{$arg}) {
8171262fc4d66584224234691d30d779f8ff004585cTed Kremenek    shift @ARGV;
818b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    push @AnalysesToRun, $arg;
8191262fc4d66584224234691d30d779f8ff004585cTed Kremenek    next;
8201262fc4d66584224234691d30d779f8ff004585cTed Kremenek  }
8211262fc4d66584224234691d30d779f8ff004585cTed Kremenek  
8229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
8239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
8249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
8259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
82623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
8279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
8289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
8299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $HtmlDir = shift @ARGV;
8309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
8319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8332b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
8349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
8359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
8369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
8379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
839f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  if ($arg =~ /^--use-cc(=(.+))?$/) {
840f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    shift @ARGV;
841f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    my $cc;
842f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
843f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    if ($2 eq "") {
844f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      if (!@ARGV) {
845f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek        DieDiag("'--use-cc' option requires a compiler executable name.\n");
846f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      }
847f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = shift @ARGV;
848f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
849f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    else {
850f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek      $cc = $2;
851f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    }
852f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    
853f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    $ENV{"CCC_CC"} = $cc;
854f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek    next;
855f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  }
856f17ef3caf19ebff18a4ee0e7984dfc6036f34b2eTed Kremenek  
857386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  if ($arg =~ /^--use-c[+][+](=(.+))?$/) {
858386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    shift @ARGV;
859386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    
860386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    if ($2 eq "") {
861386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      if (!@ARGV) {
862386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek        DieDiag("'--use-c++' option requires a compiler executable name.\n");
863386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      }
864386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      $CXX = shift @ARGV;
865386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
866386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    else {
867386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek      $CXX = $2;
868386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    }
869386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek    next;
870386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  }
871386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek  
8729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
8739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
8749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
8759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
8769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
8779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
8787f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
8797f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
8807f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
8817f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
8827f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
8837f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
884363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
885363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
886363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
887363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
888363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
889363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
89023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
8910062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
8929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
8939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
89623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
8979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
898a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
8999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
9009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
901386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
902386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek
9039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
904684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
905a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
9069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Set the appropriate environment variables.
908a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopSetHtmlEnv(\@ARGV, $HtmlDir);
9099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9100b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenekmy $Cmd = "$RealBin/ccc-analyzer";
9110b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
91223cfca3760c482f8543daab62051f5eaa1f98fb4Ted KremenekDieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n")
9130b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek  if (! -x $Cmd);
914f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
915b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekif (! -x $ClangSB) {
916b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  Diag("'clang' executable not found in '$RealBin'.\n");
917b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  Diag("Using 'clang' from path.\n");
918f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek}
9190b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
920386c69316668b9ea8c2591af56f994be16e3ff62Ted Kremenek$ENV{'CXX'} = $CXX;
9214f4b17da43d3be87a248e1e10bf0b7d8b5891efdTed Kremenek$ENV{'CC'} = $Cmd;
922f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek$ENV{'CLANG'} = $Clang;
9239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif ($Verbose >= 2) {
9259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
9269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
9279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
928a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenekif ($Verbose >= 3) {
929a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek  $ENV{'CCC_ANALYZER_LOG'} = 1;
930a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek}
931a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek
9329012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenekif (scalar(@AnalysesToRun) == 0) {
9339012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  foreach my $key (keys %AnalysesDefaultEnabled) {
9349012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek    push @AnalysesToRun,$key;
9359012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  }
93601006786e3760cc48c5e94d731b468b811b976d2Ted Kremenek}
9371262fc4d66584224234691d30d779f8ff004585cTed Kremenek
9389012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
9399012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek
9409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
9415656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
9429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
9439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess the HTML directory.
944363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $NumBugs = Postprocess($HtmlDir, $BaseDir);
9457f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
9467f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekif ($ViewResults and -r "$HtmlDir/index.html") {
9477f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  # Only works on Mac OS X (for now).
9487f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  print "Viewing analysis results: '$HtmlDir/index.html'\n";
94920161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("open", "$HtmlDir/index.html");
9507f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek}
9515656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
952363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekif ($ExitStatusFoundBugs) {
953363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  exit 1 if ($NumBugs > 0);
954363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  exit 0;
955363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
956363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
9575656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
9585656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
959