scan-build revision 23cfca3760c482f8543daab62051f5eaa1f98fb4
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
2923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenekmy $UseColor = (($ENV{'TERM'} eq 'xterm-color') and -t STDOUT);
3023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
3123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub Diag {
3223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
3323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, MAGENTA "$Prog: @_";
3423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
3523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
3623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
3723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: @_";
3823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }  
3923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
4023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
4123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremeneksub DieDiag {
4223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  if ($UseColor) {
4323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print BOLD, RED "$Prog: ";
4423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET, RED @_;
4523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print RESET;
4623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
4723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  else {
4823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    print "$Prog: ", @_;
4923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  }
5023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  exit(0);
5123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek}
5223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek
539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
549cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# GetHTMLRunDir - Construct an HTML directory name for the current run.
559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
57a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub GetHTMLRunDir {  
589cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
599cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Not enough arguments." if (@_ == 0);
609cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
619cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift @_;
629cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
639cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Get current date and time.
649cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my @CurrentTime = localtime();
669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $year  = $CurrentTime[5] + 1900;
689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $day   = $CurrentTime[3];
699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $month = $CurrentTime[4] + 1;
709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
719d7405fafd5bc08d38bc75579927bf414570bd61Ted Kremenek  my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Determine the run number.
749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $RunNumber;
769cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (-d $Dir) {
789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (! -r $Dir) {
8023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("directory '$Dir' exists but is not readable.\n");
819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # Iterate over all files in the specified directory.
849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    my $max = 0;
869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    opendir(DIR, $Dir);
889cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    my @FILES= readdir(DIR); 
899cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    closedir(DIR);
909cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
919cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    foreach my $f (@FILES) {
929cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
939cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      my @x = split/-/, $f;
949cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
959cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if (scalar(@x) != 4);
969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[0] != $year);
979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[1] != $month);
989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      next if ($x[2] != $day);
999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      
1009cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      if ($x[3] > $max) {
1019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        $max = $x[3];
1029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek      }      
1039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = $max + 1;
1069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  else {
1089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (-x $Dir) {
11023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'$Dir' exists but is not a directory.\n");
1119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
1129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # $Dir does not exist.  It will be automatically created by the 
1149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    # clang driver.  Set the run number to 1.  
1159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
1169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $RunNumber = 1;
1179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "RunNumber must be defined!" if (!defined($RunNumber));
1209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Append the run number.
1229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  return "$Dir/$DateString-$RunNumber";  
1249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
126a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub SetHtmlEnv {
1279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "Wrong number of arguments." if (scalar(@_) != 2);
1299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Args = shift;
1319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
1329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No build command." if (scalar(@$Args) == 0);
1349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1359cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Cmd = $$Args[0];
1369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Cmd =~ /configure/) {
1389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
1399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($Verbose) {
14223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Emitting reports for this run to '$Dir'.\n");
1439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
1449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
1459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_HTML'} = $Dir;
1469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
1479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
1489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
14957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# ComputeDigest - Compute a digest of the specified file.
15057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
15157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
15257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremeneksub ComputeDigest {
15357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $FName = shift;
15423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);  
155a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
156a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Use Digest::MD5.  We don't have to be cryptographically secure.  We're
1577ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # just looking for duplicate files that come from a non-malicious source.
1587ea02e6822fadcda31014c55f58cbc04e24d5abfTed Kremenek  # We use Digest::MD5 because it is a standard Perl module that should
159a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # come bundled on most systems.
160a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
16123cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
162a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  binmode FILE;
163a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
164a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  close(FILE);
165a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
166a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  # Return the digest.
167a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  
168a6e24811207ad2179b0dabe3d7e6ec551e6686dfTed Kremenek  return $Result;
16957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek}
17057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
17157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek##----------------------------------------------------------------------------##
1727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdatePrefix - Compute the common prefix of files.
1737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
1747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
1757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenekmy $Prefix;
1767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
1777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdatePrefix {
1787a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
1797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $x = shift;
1807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $y = basename($x);
1817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  $x =~ s/\Q$y\E$//;
1827a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
1837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  # Ignore /usr, /Library, /System, /Developer
1847a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
1857a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return if ( $x =~ /^\/usr/ or $x =~ /^\/Library/
1867a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek              or $x =~ /^\/System/ or $x =~ /^\/Developer/);
1877a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
1887a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
1897a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (!defined $Prefix) {
1907a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $Prefix = $x;
1917a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    return;
1927a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
1937a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
1947a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  chop $Prefix while (!($x =~ /^$Prefix/));
1957a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
1967a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
1977a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub GetPrefix {
1987a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  return $Prefix;
1997a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2007a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2017a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2027a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek#  UpdateInFilePath - Update the path in the report file.
2037a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2047a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2057a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremeneksub UpdateInFilePath {
2067a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $fname = shift;
2077a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex = shift;
2087a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $newtext = shift;
2097a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2107a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (RIN, $fname) or die "cannot open $fname";
2117a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  open (ROUT, ">$fname.tmp") or die "cannot open $fname.tmp";
2127a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2137a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  while (<RIN>) {
2147a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    s/$regex/$newtext/;
2157a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print ROUT $_;
2167a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }
2177a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
2187a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (ROUT);
2197a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  close (RIN);
2207a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  `mv $fname.tmp $fname`;
2217a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek}
2227a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
2237a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek##----------------------------------------------------------------------------##
2245744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek# ScanFile - Scan a report file for various identifying attributes.
2255744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
2265744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
22757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# Sometimes a source file is scanned more than once, and thus produces
22857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek# multiple error reports.  We use a cache to solve this problem.
22957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
23057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenekmy %AlreadyScanned;
23157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
2325744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremeneksub ScanFile {
2335744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
2345744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Index = shift;
2355744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $Dir = shift;
2365744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = shift;
2375744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
23857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # Compute a digest for the report file.  Determine if we have already
23957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  # scanned a file that looks just like it.
24057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
24157cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  my $digest = ComputeDigest("$Dir/$FName");
24257cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek
24357cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  if (defined($AlreadyScanned{$digest})) {
24457cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    # Redundant file.  Remove it.
24557cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    `rm -f $Dir/$FName`;
24657cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek    return;
24757cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  }
24857cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
24957cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  $AlreadyScanned{$digest} = 1;
25057cf446d344bb2649e8742cedf1cf4342ed78aa9Ted Kremenek  
251809709f46f2516b4054681f0b76284055a84a50fTed Kremenek  # At this point the report file is not world readable.  Make it happen.
252684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  `chmod 644 $Dir/$FName`;
253684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
254684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Scan the report file for tags.
25523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
2565744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
2575744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $BugDesc = "";
25822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugFile = "";
25922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugPathLength = 1;
26022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $BugLine = 0;
2615744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
2625744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  while (<IN>) {
2635744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
2645744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    if (/<!-- BUGDESC (.*) -->$/) {
2655744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek      $BugDesc = $1;
2665744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
26722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGFILE (.*) -->$/) {
26822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugFile = $1;
2697a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdatePrefix($BugFile);
27022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
27122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
27222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugPathLength = $1;
27322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
27422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    elsif (/<!-- BUGLINE (.*) -->$/) {
27522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek      $BugLine = $1;    
27622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    }
2775744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
2785744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
2795744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(IN);
2805744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
28122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  push @$Index,[ $FName, $BugDesc, $BugFile, $BugLine, $BugPathLength ];
28222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek}
28322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
28422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
28522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek# CopyJS - Copy JavaScript code to target directory.
28622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek##----------------------------------------------------------------------------##
28722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
28822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremeneksub CopyJS {
28922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
29022d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  my $Dir = shift;
29122d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
29223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Cannot find 'sorttable.js'.\n")
29322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$RealBin/sorttable.js");  
29422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
29522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  `cp $RealBin/sorttable.js $Dir`;
29622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek
29723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
29822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    if (! -r "$Dir/sorttable.js");
2995744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek}
3005744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
3015744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek##----------------------------------------------------------------------------##
3029cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess - Postprocess the results of an analysis scan.
3039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
3049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
305a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub Postprocess {
3069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $Dir = shift;
308684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  my $BaseDir = shift;
3099cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  die "No directory specified." if (!defined($Dir));
311684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  die "No base directory specified." if (!defined($BaseDir));
3129cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (! -d $Dir) {
31423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
3159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
3169cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
3179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
3189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  opendir(DIR, $Dir);
3199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my @files = grep(/^report-.*\.html$/,readdir(DIR));
3209cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  closedir(DIR);
3219cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
3229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (scalar(@files) == 0) {
32323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Removing directory '$Dir' because it contains no reports.\n");
3249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    `rm -fR $Dir`;
32523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    
32623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    # Remove the base directory if it contains no files (don't use '-R').
32723cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    `rm -f $BaseDir`;
32823cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    
32923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("No bugs found.\n");
3309cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    return;
3319cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
3325744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3335744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  # Scan each report file and build an index.
3345744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3355744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my @Index;
3365744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
3375744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
3385744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3395744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  # Generate an index.html file.
3405744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3415744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  my $FName = "$Dir/index.html";
3425744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
34323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  open(OUT, ">$FName") or DieDiag("Cannot create file '$FName'\n");
3445744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
3456e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the header.
3466e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
3475744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint OUT <<ENDTEXT;
3485744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<html>
3495744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek<head>
3507f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek<style type="text/css">
3517f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek body { color:#000000; background-color:#ffffff }
35222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek body { font-family: Helvetica, sans-serif; font-size:9pt }
3537f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek h1 { font-size:12pt }
35422d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek table.sortable thead {
35522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek   background-color:#eee; color:#666666;
35622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek   font-weight: bold; cursor: default;
357bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   text-align:center;
358bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   border-top: 2px solid #000000;
359bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   border-bottom: 2px solid #000000;
360bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek   font-weight: bold; font-family: Verdana
361bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek } 
36222d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek table.sortable { border: 1px #000000 solid }
36322d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek table.sortable { border-collapse: collapse; border-spacing: 0px }
3647f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek td { border-bottom: 1px #000000 dotted }
36522d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek td { padding:5px; padding-left:8px; padding-right:8px }
366d8c6d0c8a5f970240cc4cbf8eddeae037d1b29eaTed Kremenek td { text-align:left; font-size:9pt }
36722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek td.View   { padding-left: 10px }
3687f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek</style>
36922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<script src="sorttable.js"></script>
3706e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<script language='javascript' type="text/javascript">
3716e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction SetDisplay(RowClass, DisplayVal)
3726e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek{
3736e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  var Rows = document.getElementsByTagName("tr");
3746e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for ( var i = 0 ; i < Rows.length; ++i ) {
3756e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (Rows[i].className == RowClass) {
3766e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      Rows[i].style.display = DisplayVal;
3776e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
3786e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
3796e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
3806e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
3816e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekfunction ToggleDisplay(CheckButton, ClassName) {
3826e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  if (CheckButton.checked) {
3836e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "");
3846e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
3856e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  else {
3866e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    SetDisplay(ClassName, "none");
3876e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
3886e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek}
3896e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</script>
3906e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</head>
3916e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<body>
3926e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
3936e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
3946e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the summary table.
3956e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
3966e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  my %Totals;
3976e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
3986e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for my $row ( @Index ) {
3996e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
400432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    #my $bug_type = lc($row->[1]);
401432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    my $bug_type = ($row->[1]);
4026e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
4036e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    if (!defined($Totals{$bug_type})) {
4046e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      $Totals{$bug_type} = 1;
4056e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
4066e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    else {
4076e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek      $Totals{$bug_type}++;
4086e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    }
4096e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
410f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
411f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  print OUT "<h3>Summary</h3>";
412f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    
413f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  if (defined($BuildName)) {
414f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
415f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
416f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  
4176e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
4186e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<table class="sortable">
4196e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<tr>
4206e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  <td>Bug Type</td>
4216e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  <td>Quantity</td>
4226e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  <td "sorttable_nosort">Display?</td>
4236e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</tr>
4246e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted KremenekENDTEXT
4256e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  
4266e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  for my $key ( sort { $a cmp $b } keys %Totals ) {
427bdf66c7373159aa80403d313629330fd11d4c48aTed Kremenek    my $x = lc($key);
428bdf66c7373159aa80403d313629330fd11d4c48aTed Kremenek    $x =~ s/\s[,]/_/g;
4296e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    print OUT "<tr><td>$key</td><td>$Totals{$key}</td><td><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></td></tr>\n";
4306e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  }
4316e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
4326e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek  # Print out the table of errors.
4336e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek
4346e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenekprint OUT <<ENDTEXT;
4356e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek</table>
4366e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek<h3>Reports</h3>
43722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek<table class="sortable">
4387f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek<tr>
439bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>Bug Type</td>
440bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>File</td>
441bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>Line</td>
442bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td>Path Length</td>
443bba1cf550015b088f94c2d3a60a769806f84cd15Ted Kremenek  <td "sorttable_nosort"></td>
4447f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek</tr>
4455744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekENDTEXT
4469cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
4477a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $prefix = GetPrefix();
4487a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $regex;
4497a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $InFileRegex;
4507a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  my $InFilePrefix = "File:</td><td>";
4517a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  
4527a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  if (defined($prefix)) { 
4537a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $regex = qr/^\Q$prefix\E/is;    
4547a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
4557a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek  }    
4567a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
4575744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  for my $row ( sort { $a->[1] cmp $b->[1] } @Index ) {
4585744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
4596e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    my $x = lc($row->[1]);
460bdf66c7373159aa80403d313629330fd11d4c48aTed Kremenek    $x =~ s/\s[,]/_/g;
4616e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    
4626e6eff7aaac376a08cdb3c6ae9d177491f800ca8Ted Kremenek    print OUT "<tr class=\"bt_$x\">\n";
4635744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek
4645744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    my $ReportFile = $row->[0];
4659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
46622d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    print OUT " <td class=\"DESC\">";
467432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    #print OUT lc($row->[1]);
468432af5985a22e098cbc2329c021d5e23c944fb91Ted Kremenek    print OUT $row->[1];
46922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    print OUT "</td>\n";
4705744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
4717a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    # Update the file prefix.
4727a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    
4737a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    my $fname = $row->[2];
4747a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    if (defined($regex)) {      
4757a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      $fname =~ s/$regex//;
4767a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek      UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
4777a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    }
4783e56e0b8b285e86eed4d191b1da93ded7382a847Ted Kremenek
4797a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    print OUT "<td>$fname</td>\n";
4807a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek
4817a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    # Print the rest of the columns.
4827a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    
4837a4648df321be70bb009a8dc56e0162c3f13c18cTed Kremenek    for my $j ( 3 .. $#{$row} ) {
4845744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek      print OUT "<td>$row->[$j]</td>\n"
4855744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    }
4867f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
4877f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    # Emit the "View" link.
4887f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    
48922d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek    print OUT " <td class=\"View\"><a href=\"$ReportFile#EndPath\">View</a></td>\n";
4905744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    
4917f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    # End the row.
4925744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    print OUT "</tr>\n";
4935744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  }
4945744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  
4955744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  print OUT "</table>\n</body></html>\n";  
4965744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek  close(OUT);
49722d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  
49822d6a639ce04ababc6900ea8b50ed7167db0f39cTed Kremenek  CopyJS($Dir);
499684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  
500684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  # Make sure $Dir and $BaseDir is world readable/executable.
501684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  `chmod 755 $Dir`;
502684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenek  `chmod 755 $BaseDir`;
50323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  
50423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  my $Num = scalar(@Index);
50523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("$Num bugs found.\n")
5069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
5079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
5089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
509dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek# RunBuildCommand - Run the build command.
510dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
511dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
5126b6289848e215ff12d4d54fe0602d3371db52788Ted Kremeneksub AddIfNotPresent {
5136b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Args = shift;
5146b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $Arg = shift;  
5156b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  my $found = 0;
5166b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
5176b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  foreach my $k (@$Args) {
5186b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    if ($k eq $Arg) {
5196b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      $found = 1;
5206b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      last;
5216b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    }
5226b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
5236b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
5246b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($found == 0) {
5256b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    push @$Args, $Arg;
5266b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
5276b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek}
5286b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek
529dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremeneksub RunBuildCommand {
530dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
531dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Args = shift;
5327442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  my $IgnoreErrors = shift;
533dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  my $Cmd = $Args->[0];
5346195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek  my $CCAnalyzer = shift;
535dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
5366a43ba9cd247811b6d48ffbd4ee3c911c8c4b458Ted Kremenek  if ($Cmd eq "gcc" or $Cmd eq "cc" or $Cmd eq "llvm-gcc") {
537dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek    shift @$Args;
5386195c373b86963b029a2d1d2501f899789d74ba8Ted Kremenek    unshift @$Args, $CCAnalyzer;
539dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  }
5407442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek  elsif ($IgnoreErrors) {
5417442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    if ($Cmd eq "make" or $Cmd eq "gmake") {
5426b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-k");
5438912b5427a22d9032cad959c5c22cd9d28d4a66cTed Kremenek      AddIfNotPresent($Args,"-i");
5447442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
5457442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    elsif ($Cmd eq "xcodebuild") {
5466b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek      AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
5477442ca6b274f1a935c31e34221fbd0a68077ddc5Ted Kremenek    }
5486b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  } 
5496b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  
5506b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  if ($Cmd eq "xcodebuild") {
551cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable distributed builds for xcodebuild.
5526b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek    AddIfNotPresent($Args,"-nodistribute");
553cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek
554cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    # Disable PCH files until clang supports them.
555cfd4c7bef7a76c568ec033e91ba3f521e10bcbb3Ted Kremenek    AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
556915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    
557915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
558915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # linking C++ object files.  Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
559915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    # when linking such files.
560915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    my $LDPLUSPLUS = `which g++`;
561915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $LDPLUSPLUS =~ s/\015?\012//;  # strip newlines
562915e972098f1e67c7559613ccde7205cee582e61Ted Kremenek    $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS;    
5636b6289848e215ff12d4d54fe0602d3371db52788Ted Kremenek  }
564dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  
565dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  system(@$Args);
566dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek}
567dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek
568dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek##----------------------------------------------------------------------------##
5699cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# DisplayHelp - Utility function to display all help options.
5709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
5719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
572a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishopsub DisplayHelp {
5739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
5745744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenekprint <<ENDTEXT;
575a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopUSAGE: $Prog [options] <build command> [build options]
5762b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
577f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted KremenekENDTEXT
578f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
579f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  if (defined($BuildName)) {
580f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek    print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
581f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek  }
582f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenek
583f4cdf41fc7a9026b24d369ba932396e7c51209b7Ted Kremenekprint <<ENDTEXT;
5842b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekOPTIONS:
5852b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
5861262fc4d66584224234691d30d779f8ff004585cTed Kremenek  -a            - The analysis to run.  The default is 'checker-cfref'.
5871262fc4d66584224234691d30d779f8ff004585cTed Kremenek                  Valid options are: 'checker-cfref', 'fsyntax-only'
5881262fc4d66584224234691d30d779f8ff004585cTed Kremenek
5892b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  -o            - Target directory for HTML report files.  Subdirectories
590a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop                  will be created as needed to represent separate "runs" of
5912b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  the analyzer.  If this option is not specified, a directory
5922b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek                  is created in /tmp to store the reports.
5931262fc4d66584224234691d30d779f8ff004585cTed Kremenek
59410f883fe7ef74139f8778e49acacf0ce408e7088Ted Kremenek  -h            - Display this message.
5952b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  --help
5961262fc4d66584224234691d30d779f8ff004585cTed Kremenek
597af08f64abc38af5914d96106aeb014a2e06eb865Ted Kremenek  -k            - Add a "keep on going" option to the specified build command.
598f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek  --keep-going    This option currently supports make and xcodebuild.
599f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  This is a convenience option; one can specify this
600f02e8dbf7e3bddac4efec77b0ea3f07b26eaa955Ted Kremenek                  behavior directly using build options.
6012b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
602dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek  -v            - Verbose output from $Prog and the analyzer.
603dab111099e5e21b4f8eb929c7af9a7a0241eca98Ted Kremenek                  A second "-v" increases verbosity.
6042b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
6057f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  -V            - View analysis results in a web browser when the build
6067f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  --view          completes.
6077f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
6082b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekBUILD OPTIONS
6092b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
61039eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek  You can specify any build option acceptable to the build command.
61139eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek
6125744dc294e2d658a904e6bb258c0875fbac0d4a1Ted KremenekEXAMPLE
6132b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
6145744dc294e2d658a904e6bb258c0875fbac0d4a1Ted Kremenek    $Prog -o /tmp/myhtmldir make -j4
6152b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek     
61639eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek  The above example causes analysis reports to be deposited into
61739eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek  a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
61839eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek  A different subdirectory is created each time $Prog analyzes a project.
61939eefde0ae1851c8b35896ee468deb3d802d03d1Ted Kremenek  The analyzer should support most parallel builds, but not distributed builds.
6202b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek
6212b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed KremenekENDTEXT
6229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
6239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
6249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
6259cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Process command-line arguments.
6269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek##----------------------------------------------------------------------------##
6279cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
6289cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $HtmlDir;           # Parent directory to store HTML files.
6299cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekmy $IgnoreErrors = 0;  # Ignore build errors.
6307f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekmy $ViewResults  = 0;  # View results when the build terminates.
6311262fc4d66584224234691d30d779f8ff004585cTed Kremenekmy $Analysis = "checker-cfref";
6329cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
6339cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
6349cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
635a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
6369cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
6379cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
6389cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekwhile (@ARGV) {
6399cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
6409cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  # Scan for options we recognize.
6419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
6429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  my $arg = $ARGV[0];
6439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
6442f2418eacfdc68e09a75f4343ed93ba292e8d895Sam Bishop  if ($arg eq "-h" or $arg eq "--help") {
6459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    DisplayHelp();
646a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop    exit 0;
6479cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
6489cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
6491262fc4d66584224234691d30d779f8ff004585cTed Kremenek  if ($arg eq "-a") {
6501262fc4d66584224234691d30d779f8ff004585cTed Kremenek    shift @ARGV;
6511262fc4d66584224234691d30d779f8ff004585cTed Kremenek
6521262fc4d66584224234691d30d779f8ff004585cTed Kremenek    if (!@ARGV) {
65323cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-a' option requires an analysis type.\n");
6541262fc4d66584224234691d30d779f8ff004585cTed Kremenek    }
6551262fc4d66584224234691d30d779f8ff004585cTed Kremenek    
6561262fc4d66584224234691d30d779f8ff004585cTed Kremenek    $Analysis = shift @ARGV;
6571262fc4d66584224234691d30d779f8ff004585cTed Kremenek    
6581262fc4d66584224234691d30d779f8ff004585cTed Kremenek    if (!($Analysis eq "checker-cfref" or $Analysis eq "fsyntax-only")) {
65923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("Invalid argument '$Analysis' to -a.\n");
6601262fc4d66584224234691d30d779f8ff004585cTed Kremenek    }
6611262fc4d66584224234691d30d779f8ff004585cTed Kremenek    
6621262fc4d66584224234691d30d779f8ff004585cTed Kremenek    next;
6631262fc4d66584224234691d30d779f8ff004585cTed Kremenek  }
6641262fc4d66584224234691d30d779f8ff004585cTed Kremenek  
6659cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-o") {
6669cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
6679cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek        
6689cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    if (!@ARGV) {
66923cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek      DieDiag("'-o' option requires a target directory name.\n");
6709cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    }
6719cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    
6729cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $HtmlDir = shift @ARGV;
6739cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
6749cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
6759cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
6762b74ab6fdf0e3ed455bf6e0d30e24845f0c2846eTed Kremenek  if ($arg eq "-k" or $arg eq "--keep-going") {
6779cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
6789cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $IgnoreErrors = 1;
6799cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
6809cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
6819cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
6829cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if ($arg eq "-v") {
6839cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    shift @ARGV;
6849cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    $Verbose++;
6859cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek    next;
6869cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
6879cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
6887f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  if ($arg eq "-V" or $arg eq "--view") {
6897f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    shift @ARGV;
6907f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    $ViewResults = 1;    
6917f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek    next;
6927f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  }
6937f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  
69423cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
6950062ad4f47d152def1f720878aaf5904b22aefbfTed Kremenek  
6969cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  last;
6979cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
6989cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
6999cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!@ARGV) {
70023cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("No build command specified.\n\n");
7019cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  DisplayHelp();
702a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  exit 1;
7039cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7049cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7059cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Determine the output directory for the HTML reports.
7069cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7079cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif (!defined($HtmlDir)) {
7089cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
709a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop  $HtmlDir = mkdtemp("/tmp/$Prog-XXXXXX");
7109cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7119cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (!defined($HtmlDir)) {
71223cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    DieDiag("Cannot create HTML directory in /tmp.\n");
7139cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
7149cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  
7159cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  if (!$Verbose) {
71623cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek    Diag("Using '$HtmlDir' as base HTML report directory.\n");
7179cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  }
7189cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7199cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
720684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted Kremenekmy $BaseDir = $HtmlDir;
721a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam Bishop$HtmlDir = GetHTMLRunDir($HtmlDir);
7229cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7239cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Set the appropriate environment variables.
7249cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
725a0e226621b424e9fcaf6bf145c6ab439fbb7b8e6Sam BishopSetHtmlEnv(\@ARGV, $HtmlDir);
7269cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7270b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenekmy $Cmd = "$RealBin/ccc-analyzer";
7280b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
72923cfca3760c482f8543daab62051f5eaa1f98fb4Ted KremenekDieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n")
7300b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek  if (! -x $Cmd);
731f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek  
732f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenekmy $Clang = "$RealBin/clang";
733f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek
734f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenekif (! -x $Clang) {
73523cfca3760c482f8543daab62051f5eaa1f98fb4Ted Kremenek  Diag("'clang' executable not found in '$RealBin'.  Using 'clang' from path.\n");
736f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek  $Clang = "clang";
737f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek}
7380b6c15349121a030ce914e5192bb3621c79a0656Ted Kremenek
7394f4b17da43d3be87a248e1e10bf0b7d8b5891efdTed Kremenek$ENV{'CC'} = $Cmd;
740f22eacb11b50e647e7d08531ca5648d3c84c38c3Ted Kremenek$ENV{'CLANG'} = $Clang;
7419cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7429cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenekif ($Verbose >= 2) {
7439cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek  $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
7449cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek}
7459cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
746a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenekif ($Verbose >= 3) {
747a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek  $ENV{'CCC_ANALYZER_LOG'} = 1;
748a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek}
749a9525c929b280f12bd4f92a1732f981b82a62d25Ted Kremenek
7501262fc4d66584224234691d30d779f8ff004585cTed Kremenek$ENV{'CCC_ANALYZER_ANALYSIS'} = $Analysis;
7511262fc4d66584224234691d30d779f8ff004585cTed Kremenek
7529cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Run the build.
7539cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7546195c373b86963b029a2d1d2501f899789d74ba8Ted KremenekRunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
7559cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
7569cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek# Postprocess the HTML directory.
7579cc8c2cc79d8c91627c0dcc5cb679aad4e37c7f5Ted Kremenek
758684bb097fbb51fe4e8852925d93d6fd2adec31c7Ted KremenekPostprocess($HtmlDir, $BaseDir);
7597f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek
7607f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenekif ($ViewResults and -r "$HtmlDir/index.html") {
7617f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  # Only works on Mac OS X (for now).
7627f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  print "Viewing analysis results: '$HtmlDir/index.html'\n";
7637f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek  `open $HtmlDir/index.html`
7647f8a32572e1ee7cf96c1a65bf0eddb0f2f9b3769Ted Kremenek}
765