scan-build revision fc1d340169265375704404a8eec1d8acf1c2038d
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;
179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekuse File::Temp qw/ :mktemp /;
1822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenekuse FindBin qw($RealBin);
19a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenekuse Digest::MD5;
207a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekuse File::Basename;
2123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor;
2223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekuse Term::ANSIColor qw(:constants);
239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Verbose = 0;       # Verbose output from this script.
259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $Prog = "scan-build";
26f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildName;
27f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekmy $BuildDate;
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
4623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
4723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
4823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
4923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
5023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
5123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
5223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
5323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
5423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
5523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
5623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
5723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
59b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Some initial preprocessing of Clang options.
60b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
61b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
62b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $ClangSB = "$RealBin/clang";
63b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $Clang = $ClangSB;
64b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
65b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekif (! -x $ClangSB) {
66b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  $Clang = "clang";
67b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek}
68b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
69b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy %AvailableAnalyses;
70b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
71b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek# Query clang for analysis options.
7263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenekopen(PIPE, "-|", $Clang, "--help") or
73b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  DieDiag("Cannot execute '$Clang'");
7463c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
75b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy $FoundAnalysis = 0;
76b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
77b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekwhile(<PIPE>) {
78b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  if ($FoundAnalysis == 0) {
79b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    if (/Available Source Code Analyses/) {
80b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek      $FoundAnalysis = 1;
81b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
82b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    
83b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next;
84b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
85b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    
86b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
87b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next if ($1 =~ /-dump/ or $1 =~ /-view/ 
88b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek             or $1 =~ /-checker-simple/ or $1 =~ /-warn-uninit/);
89b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek             
90b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    $AvailableAnalyses{$1} = $2;
91b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    next;
92b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
93b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  
94b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  last;
95b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek}
96b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
97b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekclose (PIPE);
98b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
99b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy %AnalysesDefaultEnabled = (
100b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  '-warn-dead-stores' => 1,
101b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  '-checker-cfref' => 1,
1029012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  '-warn-objc-methodsigs' => 1,
103bde3a051933b6829ed79d6db0118231c2c01b105Ted Kremenek  '-warn-objc-missing-dealloc' => 1,
104bde3a051933b6829ed79d6db0118231c2c01b105Ted Kremenek  '-warn-objc-unused-ivars' => 1
105b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek);
106b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
107b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek##----------------------------------------------------------------------------##
108fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
1099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
1109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
111a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
1129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
113fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "Not enough arguments." if (@_ == 0);  
1149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift @_;
115fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    
116fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  my $TmpMode = 0;
117fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (!defined $Dir) {
118fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $Dir = "/tmp";
119fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    $TmpMode = 1;
120fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
121fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
1239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my @CurrentTime = localtime();
1259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
1279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
1289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
1299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1309d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
1319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Determine the run number.
1339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
1359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (-d $Dir) {
1379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
13923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
1409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # Iterate over all files in the specified directory.
1439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    my $max = 0;
1459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
1479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    my @FILES= readdir(DIR); 
1489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
1499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1509cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    foreach my $f (@FILES) {
1519cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
152fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      # Strip the prefix '$Prog-' if we are dumping files to /tmp.
153fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      if ($TmpMode) {
154fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        next if (!($f =~ /^$Prog-(.+)/));
155fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek        $f = $1;
156fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      }
157fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
159fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
1619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
1629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
1639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
1649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
17523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
177fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
178fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if ($TmpMode) {
179fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek      DieDiag("The directory '/tmp' does not exist or cannot be accessed.");
180fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    }
181fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
184fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek
1859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
188fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "RunNumber must be defined!" if (!defined $RunNumber);
1899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
191fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if ($TmpMode) {
192fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    my $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
193fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    mkdir $NewDir;
194fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    return $NewDir;
195fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
196fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  else {
197fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    return "$Dir/$DateString-$RunNumber";
198fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  }
1999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
201a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
2029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
2049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
2069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
2079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
2099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
2119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Cmd =~ /configure/) {
2139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
2149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
21723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
2189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
2199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
2209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
2219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
2229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
2239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
22457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
22557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
22657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
22757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
22857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
22923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
230a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
231a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
2327ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
2337ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
23463c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # come bundled on most systems.  
23523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
236a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
237a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
238a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
239a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
24063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Return the digest.  
241a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
24257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
24357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
24457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
2457a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
2467a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2487a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
2497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2507a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
2517a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
2527a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
2537a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
2547a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  # Ignore /usr, /Library, /System, /Developer
2567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return if ( $x =~ /^\/usr/ or $x =~ /^\/Library/
2577a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek              or $x =~ /^\/System/ or $x =~ /^\/Developer/);
2587a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2597a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
2607a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
2617a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
2627a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2637a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2647a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  chop $Prefix while (!($x =~ /^$Prefix/));
2657a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2667a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2677a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
2687a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2707a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
27963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
28163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
28263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2847a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2857a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2867a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
28763c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek
2887a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2897a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
29020161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("mv", "$fname.tmp", $fname);
2917a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2927a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2937a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2945744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
2955744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
2965744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
29757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
29857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
29957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
30057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
30157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
3025744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
3035744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3045744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
3055744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
3065744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
3075744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
30857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
30957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
31057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
31157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
31257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
313fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AlreadyScanned{$digest}) {
31457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
31520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-f", "$Dir/$FName");
31657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
31757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
31857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
31957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
32057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
321809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
32220161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("chmod", "644", "$Dir/$FName");
323684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
324684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
32523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
3265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3275744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $BugDesc = "";
32822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugFile = "";
32922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugPathLength = 1;
33022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugLine = 0;
3315744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3325744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
3335744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
3345744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    if (/<!-- BUGDESC (.*) -->$/) {
3355744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek      $BugDesc = $1;
3365744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
33722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
33822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugFile = $1;
3397a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
34022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
34122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
34222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
34322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
34422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
34522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
34622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
3475744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
3485744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3495744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
3505744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
35122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  push @$Index,[ $FName, $BugDesc, $BugFile, $BugLine, $BugPathLength ];
35222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
35322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
35422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
35522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek# CopyJS - Copy JavaScript code to target directory.
35622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
35722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
35822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremeneksub CopyJS {
35922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
36122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
36223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
36322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$RealBin/sorttable.js");  
36422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system ("cp", "$RealBin/sorttable.js", "$Dir");
36622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
36723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
36822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
3695744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
3705744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3715744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
3739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
3749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
375a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
3769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
378684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  my $BaseDir = shift;
3799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
380fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  die "No directory specified." if (!defined $Dir);
3819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
38323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
384363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
3859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
3869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
3889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my @files = grep(/^report-.*\.html$/,readdir(DIR));
3899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
3909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
3919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (scalar(@files) == 0) {
39223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
39320161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek    system ("rm", "-fR", $Dir);
39423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    
39523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    # Remove the base directory if it contains no files (don't use '-R').
396fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if (defined $BaseDir) { system ("rm", "-f", $BaseDir); }
39723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    
39823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
399363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    return 0;
4009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
4015744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
4025744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  # Scan each report file and build an index.
4035744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
4045744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my @Index;
4055744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
4065744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
4075744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
40863c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  # Generate an index.html file.  
40963c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  my $FName = "$Dir/index.html";  
41063c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
4115744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
4126e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
4136e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4145744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
4155744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
4165744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
4177f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek<style type="text/css">
4187f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek body { color:#000000; background-color:#ffffff }
41922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek body { font-family: Helvetica, sans-serif; font-size:9pt }
4207f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek h1 { font-size:12pt }
42122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek table.sortable thead {
42222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek   background-color:#eee; color:#666666;
42322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek   font-weight: bold; cursor: default;
424bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   text-align:center;
425bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   border-top: 2px solid #000000;
426bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   border-bottom: 2px solid #000000;
427bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   font-weight: bold; font-family: Verdana
428bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek } 
42922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek table.sortable { border: 1px #000000 solid }
43022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek table.sortable { border-collapse: collapse; border-spacing: 0px }
4317f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek td { border-bottom: 1px #000000 dotted }
43222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek td { padding:5px; padding-left:8px; padding-right:8px }
433d8c6d0c8a5f970240cc4cbf8eddeae037d1b29eaTed Kremenek td { text-align:left; font-size:9pt }
43422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek td.View   { padding-left: 10px }
4357f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek</style>
43622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
4376e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
4386e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
4396e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
4406e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
4416e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
4426e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
4436e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
4446e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
4456e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4466e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
4476e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4486e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
4496e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
4506e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
4516e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4526e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
4536e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
4546e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4556e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
4566e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
4576e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
4586e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
4596e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
4606e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
4616e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the summary table.
4626e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4636e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  my %Totals;
4646e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4656e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for my $row ( @Index ) {
4666e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
467432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    #my $bug_type = lc($row->[1]);
468432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    my $bug_type = ($row->[1]);
4696e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
470fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if (!defined $Totals{$bug_type}) {
4716e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      $Totals{$bug_type} = 1;
4726e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
4736e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    else {
4746e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      $Totals{$bug_type}++;
4756e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
4766e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
477f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
478f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  print OUT "<h3>Summary</h3>";
479f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    
480fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
481f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
482f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
483f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
4846e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
4856e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<table class="sortable">
4866e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<tr>
4876e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  <td>Bug Type</td>
4886e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  <td>Quantity</td>
4892645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort">Display?</td>
4906e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</tr>
4916e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
4926e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4936e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for my $key ( sort { $a cmp $b } keys %Totals ) {
494bdf66c7373159aa80403d313629330fd11d4c48aTed Kremenek    my $x = lc($key);
4953cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek    $x =~ s/[ ,'"]+/_/g;
4966e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    print OUT "<tr><td>$key</td><td>$Totals{$key}</td><td><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></td></tr>\n";
4976e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4986e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
4996e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
5006e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
5016e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
5026e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
5036e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<h3>Reports</h3>
50422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<table class="sortable">
5057f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek<tr>
50688a96d6c3fe2b1b9d80b39c21cf7aca4aa9fcf08Ted Kremenek  <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span>
507bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
508bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>Line</td>
509bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>Path Length</td>
5102645c77072d45fabb2bdc0a3621908035c7113dcTed Kremenek  <td class="sorttable_nosort"></td>
5117f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek</tr>
5125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
5139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
5147a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $prefix = GetPrefix();
5157a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex;
5167a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $InFileRegex;
5177a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $InFilePrefix = "File:</td><td>";
5187a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
519fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $prefix) { 
5207a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $regex = qr/^\Q$prefix\E/is;    
5217a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
5227a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }    
5237a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
5245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  for my $row ( sort { $a->[1] cmp $b->[1] } @Index ) {
5255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
5266e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    my $x = lc($row->[1]);
5273cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek    $x =~ s/[ ,'"]+/_/g;
5286e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
5296e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    print OUT "<tr class=\"bt_$x\">\n";
5305744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
5315744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    my $ReportFile = $row->[0];
5329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
53322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    print OUT " <td class=\"DESC\">";
534432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    #print OUT lc($row->[1]);
535432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    print OUT $row->[1];
53622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    print OUT "</td>\n";
5375744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
5387a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    # Update the file prefix.
5397a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    
5407a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    my $fname = $row->[2];
541fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if (defined $regex) {
5427a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      $fname =~ s/$regex//;
5437a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
5447a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    }
5453e56e0b8b285e86eed4d191b1da93ded7382a847Ted Kremenek
5467a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print OUT "<td>$fname</td>\n";
5477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
5487a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    # Print the rest of the columns.
5497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    for my $j ( 3 .. $#{$row} ) {
5505744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek      print OUT "<td>$row->[$j]</td>\n"
5515744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
5527f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
5537f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    # Emit the "View" link.
55422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    print OUT " <td class=\"View\"><a href=\"$ReportFile#EndPath\">View</a></td>\n";
5553cea9ee6b77ac797ebb910bdf45d1d7f8f68e37bTed Kremenek        
5567f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    # End the row.
5575744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    print OUT "</tr>\n";
5585744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
5595744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
5605744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  print OUT "</table>\n</body></html>\n";  
5615744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
56220161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
56322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  CopyJS($Dir);
56420161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
56520161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  # Make sure $Dir and $BaseDir are world readable/executable.
56620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("chmod", "755", $Dir);
567fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
56820161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek
56923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
570150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  Diag("$Num bugs found.\n");
571150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  if ($Num > 0 && -r "$Dir/index.html") {
572150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek    Diag("Open '$Dir/index.html' to examine bug reports.\n");
573150c2120ab4a44b4ac62b401ffece9049ff9b2c0Ted Kremenek  }
574363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
575363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  return $Num;
5769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
5779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
5789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
579dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
580dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
581dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
5826b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
5836b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
5846b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
5856b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
5866b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
5876b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
5886b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
5896b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
5906b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
5916b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
5926b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
5936b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
5946b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
5956b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
5966b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
5976b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
5986b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
599dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremeneksub RunBuildCommand {
600dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
601dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
6027442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
603dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
6046195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
605dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
6063301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  # Get only the part of the command after the last '/'.
6073301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  if ($Cmd =~ /\/([^\/]+)$/) {
6083301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek    $Cmd = $1;
6093301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  }
6103301cb103d5f32056d62f13bde036988f7cf1330Ted Kremenek  
61163c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek  if ($Cmd eq "gcc" or $Cmd eq "cc" or $Cmd eq "llvm-gcc" 
61263c2017737530a7009f709f2fe822f20f63930b1Ted Kremenek   or $Cmd eq "ccc-analyzer") {
613dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
6146195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
615dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
6167442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
6177442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
6186b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
6198912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
6207442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
6217442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    elsif ($Cmd eq "xcodebuild") {
6226b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
6237442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
6246b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
6256b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
6266b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($Cmd eq "xcodebuild") {
627cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable distributed builds for xcodebuild.
6286b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    AddIfNotPresent($Args,"-nodistribute");
629cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek
630cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable PCH files until clang supports them.
631cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
632915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    
633915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
634915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
635915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # when linking such files.
636915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    my $LDPLUSPLUS = `which g++`;
637915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $LDPLUSPLUS =~ s/\015?\012//;  # strip newlines
638915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS;    
6396b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
640dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
6415656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek  return system(@$Args);
642dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
643dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
644dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
6459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
6469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
6479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
648a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
6499cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
6505744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
651a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
6522b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
653f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
654f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
655fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $BuildName) {
656f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
657f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
658f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
659f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
6602b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
6612b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
662363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -o             - Target directory for HTML report files.  Subdirectories
663a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop                  will be created as needed to represent separate "runs" of
6642b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  the analyzer.  If this option is not specified, a directory
6652b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  is created in /tmp to store the reports.
6661262fc4d66584224234691d30d779f8ff004585cTed Kremenek
667363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -h             - Display this message.
668363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --help
6691262fc4d66584224234691d30d779f8ff004585cTed Kremenek
670363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -k             - Add a "keep on going" option to the specified build command.
671363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --keep-going     This option currently supports make and xcodebuild.
672f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  This is a convenience option; one can specify this
673f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  behavior directly using build options.
6742b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
675363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --status-bugs  - By default, the exit status of $Prog is the same as the
676363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  executed build command.  Specifying this option causes the
677363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  exit status of $Prog to be 1 if it found potential bugs
678363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  and 0 otherwise.
6792b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
680363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -v             - Verbose output from $Prog and the analyzer.
681363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek                  A second and third "-v" increases verbosity.
682363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
683363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek -V             - View analysis results in a web browser when the build
684363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek --view           completes.
6857f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
686b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted KremenekENDTEXT
687b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
688363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  print " Available Source Code Analyses (multiple analyses may be specified):\n\n";
689b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
690b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  foreach my $Analysis (sort keys %AvailableAnalyses) {
691fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek    if (defined $AnalysesDefaultEnabled{$Analysis}) {
692363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek      print " (+)";
693b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
694b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    else {
695363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek      print "    ";
696b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    }
697b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    
698b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    print " $Analysis  $AvailableAnalyses{$Analysis}\n";
699b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  }
700b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  
701b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekprint <<ENDTEXT
702b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
703363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek NOTE: "(+)" indicates that an analysis is enabled by default unless one
704363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek       or more analysis options are specified
705b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek
7062b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
7072b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
708363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek You can specify any build option acceptable to the build command.
70939eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
7105744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
7112b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
712363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek $Prog -o /tmp/myhtmldir make -j4
7132b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
714363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The above example causes analysis reports to be deposited into
715363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
716363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek A different subdirectory is created each time $Prog analyzes a project.
717363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek The analyzer should support most parallel builds, but not distributed builds.
7182b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
7192b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
7209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
7249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
7259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
7279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
7287f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
729363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
730b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekmy @AnalysesToRun;
7319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
732363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
7339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
7349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
735a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
7369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
7399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
7419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
7439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7442f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
7459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    DisplayHelp();
746a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop    exit 0;
7479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
7489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
749fc1d340169265375704404a8eec1d8acf1c2038dTed Kremenek  if (defined $AvailableAnalyses{$arg}) {
7501262fc4d66584224234691d30d779f8ff004585cTed Kremenek    shift @ARGV;
751b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek    push @AnalysesToRun, $arg;
7521262fc4d66584224234691d30d779f8ff004585cTed Kremenek    next;
7531262fc4d66584224234691d30d779f8ff004585cTed Kremenek  }
7541262fc4d66584224234691d30d779f8ff004585cTed Kremenek  
7559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
7569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
7579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
7589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
75923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
7609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
7619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
7629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $HtmlDir = shift @ARGV;
7639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
7649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
7659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7662b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
7679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
7689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
7699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
7709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
7719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
7739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
7749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
7759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
7769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
7779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7787f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
7797f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
7807f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
7817f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
7827f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
7837f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
784363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  if ($arg eq "--status-bugs") {
785363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    shift @ARGV;
786363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    $ExitStatusFoundBugs = 1;
787363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek    next;
788363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  }
789363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  
79023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
7910062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
7929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
7939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
79623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
7979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
798a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
7999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
802684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
803a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
8049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Set the appropriate environment variables.
806a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopSetHtmlEnv(\@ARGV, $HtmlDir);
8079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8080b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenekmy $Cmd = "$RealBin/ccc-analyzer";
8090b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
81023cfca3760c482f8543daab62051f5eaa1f98fb4Ted KremenekDieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n")
8110b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek  if (! -x $Cmd);
812f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
813b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenekif (! -x $ClangSB) {
814b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  Diag("'clang' executable not found in '$RealBin'.\n");
815b7770c0b4970606b53cca14ae3ca0588a0bfcb30Ted Kremenek  Diag("Using 'clang' from path.\n");
816f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek}
8170b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
8184f4b17da43d3be87a248e1e10bf0b7d8b5891efdTed Kremenek$ENV{'CC'} = $Cmd;
819f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek$ENV{'CLANG'} = $Clang;
8209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif ($Verbose >= 2) {
8229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
8239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
8249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
825a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenekif ($Verbose >= 3) {
826a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek  $ENV{'CCC_ANALYZER_LOG'} = 1;
827a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek}
828a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek
8299012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenekif (scalar(@AnalysesToRun) == 0) {
8309012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  foreach my $key (keys %AnalysesDefaultEnabled) {
8319012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek    push @AnalysesToRun,$key;
8329012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek  }
83301006786e3760cc48c5e94d731b468b811b976d2Ted Kremenek}
8341262fc4d66584224234691d30d779f8ff004585cTed Kremenek
8359012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
8369012599f4ccfe066c093cf0885fd3994bdc256d1Ted Kremenek
8379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
8385656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekmy $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
8399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
8409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess the HTML directory.
841363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekmy $NumBugs = Postprocess($HtmlDir, $BaseDir);
8427f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
8437f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekif ($ViewResults and -r "$HtmlDir/index.html") {
8447f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  # Only works on Mac OS X (for now).
8457f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  print "Viewing analysis results: '$HtmlDir/index.html'\n";
84620161e9ed795fa7ff2f7855324aa836a927fb0f5Ted Kremenek  system("open", "$HtmlDir/index.html");
8477f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek}
8485656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
849363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenekif ($ExitStatusFoundBugs) {
850363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  exit 1 if ($NumBugs > 0);
851363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek  exit 0;
852363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek}
853363dc3f40ffc4cc71fb3a04087cf627aeb6918d4Ted Kremenek
8545656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenekexit $ExitStatus;
8555656a985574c00aa9b77fec51d41023e27e7a81fTed Kremenek
856