summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts
diff options
context:
space:
mode:
authorCary Clark <>2009-04-14 06:33:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-14 06:33:00 -0700
commit563af33bc48281d19dce701398dbb88cb54fd7ec (patch)
tree395b4502f029dea8b25b342d66dc06b5d8f99985 /WebKitTools/Scripts
parent5cfedfef172691d0f4bcf2be5ca3cddd8c9a47f4 (diff)
downloadexternal_webkit-563af33bc48281d19dce701398dbb88cb54fd7ec.zip
external_webkit-563af33bc48281d19dce701398dbb88cb54fd7ec.tar.gz
external_webkit-563af33bc48281d19dce701398dbb88cb54fd7ec.tar.bz2
AI 146110: add missing files to webkit
brings it in sync with webkit svn cl 42046 Automated import of CL 146110
Diffstat (limited to 'WebKitTools/Scripts')
-rw-r--r--WebKitTools/Scripts/SpacingHeuristics.pm101
-rw-r--r--WebKitTools/Scripts/VCSUtils.pm135
-rwxr-xr-xWebKitTools/Scripts/bisect-builds431
-rwxr-xr-xWebKitTools/Scripts/build-drawtest48
-rwxr-xr-xWebKitTools/Scripts/build-dumprendertree54
-rwxr-xr-xWebKitTools/Scripts/build-jsc78
-rwxr-xr-xWebKitTools/Scripts/build-webkit333
-rwxr-xr-xWebKitTools/Scripts/check-dom-results141
-rwxr-xr-xWebKitTools/Scripts/check-for-exit-time-destructors151
-rwxr-xr-xWebKitTools/Scripts/check-for-global-initializers135
-rwxr-xr-xWebKitTools/Scripts/check-for-weak-vtables101
-rwxr-xr-xWebKitTools/Scripts/clean-header-guards53
-rwxr-xr-xWebKitTools/Scripts/commit-log-editor189
-rwxr-xr-xWebKitTools/Scripts/compare-timing-files88
-rwxr-xr-xWebKitTools/Scripts/create-exports5
-rwxr-xr-xWebKitTools/Scripts/debug-safari38
-rwxr-xr-xWebKitTools/Scripts/detect-mismatched-virtual-const167
-rwxr-xr-xWebKitTools/Scripts/do-file-rename115
-rwxr-xr-xWebKitTools/Scripts/do-webcore-rename184
-rwxr-xr-xWebKitTools/Scripts/extract-localizable-strings351
-rwxr-xr-xWebKitTools/Scripts/find-extra-includes102
-rwxr-xr-xWebKitTools/Scripts/find-included-framework-headers10
-rwxr-xr-xWebKitTools/Scripts/gdb-safari53
-rwxr-xr-xWebKitTools/Scripts/generate-coverage-data71
-rwxr-xr-xWebKitTools/Scripts/generate-qt-inspector-resource53
-rwxr-xr-xWebKitTools/Scripts/make-js-test-wrappers165
-rwxr-xr-xWebKitTools/Scripts/num-cpus16
-rwxr-xr-xWebKitTools/Scripts/parallelcl224
-rwxr-xr-xWebKitTools/Scripts/parse-malloc-history154
-rwxr-xr-xWebKitTools/Scripts/pdevenv25
-rwxr-xr-xWebKitTools/Scripts/prepare-ChangeLog1445
-rwxr-xr-xWebKitTools/Scripts/print-msvc-project-dependencies143
-rwxr-xr-xWebKitTools/Scripts/report-include-statistics114
-rwxr-xr-xWebKitTools/Scripts/resolve-ChangeLogs513
-rwxr-xr-xWebKitTools/Scripts/run-drawtest47
-rwxr-xr-xWebKitTools/Scripts/run-iexploder-tests172
-rwxr-xr-xWebKitTools/Scripts/run-javascriptcore-tests184
-rwxr-xr-xWebKitTools/Scripts/run-jsc58
-rwxr-xr-xWebKitTools/Scripts/run-launcher67
-rwxr-xr-xWebKitTools/Scripts/run-leaks212
-rwxr-xr-xWebKitTools/Scripts/run-mangleme-tests175
-rwxr-xr-xWebKitTools/Scripts/run-pageloadtest92
-rwxr-xr-xWebKitTools/Scripts/run-safari41
-rwxr-xr-xWebKitTools/Scripts/run-sunspider131
-rwxr-xr-xWebKitTools/Scripts/run-webkit-app50
-rwxr-xr-xWebKitTools/Scripts/run-webkit-httpd127
-rwxr-xr-xWebKitTools/Scripts/run-webkit-nightly.cmd10
-rwxr-xr-xWebKitTools/Scripts/run-webkit-tests1895
-rwxr-xr-xWebKitTools/Scripts/set-webkit-configuration79
-rwxr-xr-xWebKitTools/Scripts/sort-Xcode-project-file167
-rwxr-xr-xWebKitTools/Scripts/split-file-by-class159
-rwxr-xr-xWebKitTools/Scripts/sunspider-compare-results101
-rwxr-xr-xWebKitTools/Scripts/svn-apply443
-rwxr-xr-xWebKitTools/Scripts/svn-create-patch442
-rwxr-xr-xWebKitTools/Scripts/svn-unapply374
-rwxr-xr-xWebKitTools/Scripts/update-iexploder-cssproperties112
-rwxr-xr-xWebKitTools/Scripts/update-javascriptcore-test-results73
-rw-r--r--WebKitTools/Scripts/update-sources-list.py93
-rwxr-xr-xWebKitTools/Scripts/update-webkit92
-rwxr-xr-xWebKitTools/Scripts/update-webkit-auxiliary-libs121
-rwxr-xr-xWebKitTools/Scripts/update-webkit-localizable-strings46
-rwxr-xr-xWebKitTools/Scripts/update-webkit-support-libs133
-rw-r--r--WebKitTools/Scripts/webkitdirs.pm1249
-rwxr-xr-xWebKitTools/Scripts/wkstyle89
64 files changed, 13020 insertions, 0 deletions
diff --git a/WebKitTools/Scripts/SpacingHeuristics.pm b/WebKitTools/Scripts/SpacingHeuristics.pm
new file mode 100644
index 0000000..7de0172
--- /dev/null
+++ b/WebKitTools/Scripts/SpacingHeuristics.pm
@@ -0,0 +1,101 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Used for helping remove extra blank lines from files when processing.
+# see split-class for an example usage (or other scripts in bugzilla)
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&resetSpacingHeuristics &isOnlyWhiteSpace &applySpacingHeuristicsAndPrint &setPreviousAllowedLine &setPreviousAllowedLine &printPendingEmptyLines &ignoringLine);
+ %EXPORT_TAGS = ();
+ @EXPORT_OK = ();
+}
+
+our @EXPORT_OK;
+
+my $justFoundEmptyLine = 0;
+my $previousLineWasDisallowed = 0;
+my $previousAllowedLine = "";
+my $pendingEmptyLines = "";
+
+sub resetSpacingHeuristics
+{
+ $justFoundEmptyLine = 0;
+ $previousLineWasDisallowed = 0;
+ $previousAllowedLine = "";
+ $pendingEmptyLines = "";
+}
+
+sub isOnlyWhiteSpace
+{
+ my $line = shift;
+ my $isOnlyWhiteSpace = ($line =~ m/^\s+$/);
+ $pendingEmptyLines .= $line if ($isOnlyWhiteSpace);
+ return $isOnlyWhiteSpace;
+}
+
+sub applySpacingHeuristicsAndPrint
+{
+ my ($out, $line) = @_;
+
+ printPendingEmptyLines($out, $line);
+ $previousLineWasDisallowed = 0;
+ print $out $line;
+}
+
+sub setPreviousAllowedLine
+{
+ my $line = shift;
+ $previousAllowedLine = $line;
+}
+
+sub printPendingEmptyLines
+{
+ my $out = shift;
+ my $line = shift;
+ if ($previousLineWasDisallowed) {
+ if (!($pendingEmptyLines eq "") && !($previousAllowedLine =~ m/{\s*$/) && !($line =~ m/^\s*}/)) {
+ $pendingEmptyLines = "\n";
+ } else {
+ $pendingEmptyLines = "";
+ }
+ }
+ print $out $pendingEmptyLines;
+ $pendingEmptyLines = "";
+}
+
+sub ignoringLine
+{
+ # my $line = shift; # ignoring input argument
+ $previousLineWasDisallowed = 1;
+}
+
+1; \ No newline at end of file
diff --git a/WebKitTools/Scripts/VCSUtils.pm b/WebKitTools/Scripts/VCSUtils.pm
new file mode 100644
index 0000000..5e92821
--- /dev/null
+++ b/WebKitTools/Scripts/VCSUtils.pm
@@ -0,0 +1,135 @@
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Module to share code to work with various version control systems.
+
+use strict;
+use warnings;
+use File::Spec;
+use webkitdirs;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&isGitDirectory &isGit &isSVNDirectory &isSVN &makeFilePathRelative);
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+our @EXPORT_OK;
+
+my $isGit;
+my $isSVN;
+my $gitBranch;
+my $isGitBranchBuild;
+
+sub isGitDirectory($)
+{
+ my ($dir) = @_;
+ return system("cd $dir && git rev-parse > /dev/null 2>&1") == 0;
+}
+
+sub isGit()
+{
+ return $isGit if defined $isGit;
+
+ $isGit = isGitDirectory(".");
+ return $isGit;
+}
+
+sub gitBranch()
+{
+ unless (defined $gitBranch) {
+ chomp($gitBranch = `git symbolic-ref -q HEAD`);
+ $gitBranch = "" if exitStatus($?);
+ $gitBranch =~ s#^refs/heads/##;
+ $gitBranch = "" if $gitBranch eq "master";
+ }
+
+ return $gitBranch;
+}
+
+sub isGitBranchBuild()
+{
+ my $branch = gitBranch();
+ chomp(my $override = `git config --bool branch.$branch.webKitBranchBuild`);
+ return 1 if $override eq "true";
+ return 0 if $override eq "false";
+
+ unless (defined $isGitBranchBuild) {
+ chomp(my $gitBranchBuild = `git config --bool core.webKitBranchBuild`);
+ $isGitBranchBuild = $gitBranchBuild eq "true";
+ }
+
+ return $isGitBranchBuild;
+}
+
+sub isSVNDirectory($)
+{
+ my ($dir) = @_;
+
+ return -d File::Spec->catdir($dir, ".svn");
+}
+
+sub isSVN()
+{
+ return $isSVN if defined $isSVN;
+
+ $isSVN = isSVNDirectory(".");
+ return $isSVN;
+}
+
+sub svnRevisionForDirectory($)
+{
+ my ($dir) = @_;
+ my $revision;
+
+ if (isSVNDirectory($dir)) {
+ my $svnInfo = `LC_ALL=C svn info $dir | grep Revision:`;
+ ($revision) = ($svnInfo =~ m/Revision: (\d+).*/g);
+ } elsif (isGitDirectory($dir)) {
+ my $gitLog = `cd $dir && LC_ALL=C git log --grep='git-svn-id: ' -n 1 | grep git-svn-id:`;
+ ($revision) = ($gitLog =~ m/ +git-svn-id: .+@(\d+) /g);
+ }
+ die "Unable to determine current SVN revision in $dir" unless (defined $revision);
+ return $revision;
+}
+
+my $gitRoot;
+sub makeFilePathRelative($)
+{
+ my ($path) = @_;
+ return $path unless isGit();
+
+ unless (defined $gitRoot) {
+ chomp($gitRoot = `git rev-parse --show-cdup`);
+ }
+ return $gitRoot . $path;
+}
+
+1;
diff --git a/WebKitTools/Scripts/bisect-builds b/WebKitTools/Scripts/bisect-builds
new file mode 100755
index 0000000..45fdcc4
--- /dev/null
+++ b/WebKitTools/Scripts/bisect-builds
@@ -0,0 +1,431 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script attempts to find the point at which a regression (or progression)
+# of behavior occurred by searching WebKit nightly builds.
+
+# To override the location where the nightly builds are downloaded or the path
+# to the Safari web browser, create a ~/.bisect-buildsrc file with one or more of
+# the following lines (use "~/" to specify a path from your home directory):
+#
+# $branch = "branch-name";
+# $nightlyDownloadDirectory = "~/path/to/nightly/downloads";
+# $safariPath = "/path/to/Safari.app";
+
+use strict;
+
+use File::Basename;
+use File::Path;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+use Time::HiRes qw(usleep);
+
+sub createTempFile($);
+sub downloadNightly($$$);
+sub findMacOSXVersion();
+sub findNearestNightlyIndex(\@$$);
+sub findSafariVersion($);
+sub loadSettings();
+sub makeNightlyList($$$$);
+sub max($$) { return $_[0] > $_[1] ? $_[0] : $_[1]; }
+sub mountAndRunNightly($$$$);
+sub parseRevisions($$;$);
+sub printStatus($$$);
+sub promptForTest($);
+
+loadSettings();
+
+my %validBranches = map { $_ => 1 } qw(feature-branch trunk);
+my $branch = $Settings::branch;
+my $nightlyDownloadDirectory = $Settings::nightlyDownloadDirectory;
+my $safariPath = $Settings::safariPath;
+
+my @nightlies;
+
+my $isProgression;
+my $localOnly;
+my @revisions;
+my $sanityCheck;
+my $showHelp;
+my $testURL;
+
+# Fix up -r switches in @ARGV
+@ARGV = map { /^(-r)(.+)$/ ? ($1, $2) : $_ } @ARGV;
+
+my $result = GetOptions(
+ "b|branch=s" => \$branch,
+ "d|download-directory=s" => \$nightlyDownloadDirectory,
+ "h|help" => \$showHelp,
+ "l|local!" => \$localOnly,
+ "p|progression!" => \$isProgression,
+ "r|revisions=s" => \&parseRevisions,
+ "safari-path=s" => \$safariPath,
+ "s|sanity-check!" => \$sanityCheck,
+);
+$testURL = shift @ARGV;
+
+$branch = "feature-branch" if $branch eq "feature";
+if (!exists $validBranches{$branch}) {
+ print STDERR "ERROR: Invalid branch '$branch'\n";
+ $showHelp = 1;
+}
+
+if (!$result || $showHelp || scalar(@ARGV) > 0) {
+ print STDERR "Search WebKit nightly builds for changes in behavior.\n";
+ print STDERR "Usage: " . basename($0) . " [options] [url]\n";
+ print STDERR <<END;
+ [-b|--branch name] name of the nightly build branch (default: trunk)
+ [-d|--download-directory dir] nightly build download directory (default: ~/Library/Caches/WebKit-Nightlies)
+ [-h|--help] show this help message
+ [-l|--local] only use local (already downloaded) nightlies
+ [-p|--progression] searching for a progression, not a regression
+ [-r|--revision M[:N]] specify starting (and optional ending) revisions to search
+ [--safari-path path] path to Safari application bundle (default: /Applications/Safari.app)
+ [-s|--sanity-check] verify both starting and ending revisions before bisecting
+END
+ exit 1;
+}
+
+my $nightlyWebSite = "http://nightly.webkit.org";
+my $nightlyBuildsURLBase = $nightlyWebSite . File::Spec->catdir("/builds", $branch, "mac");
+my $nightlyFilesURLBase = $nightlyWebSite . File::Spec->catdir("/files", $branch, "mac");
+
+$nightlyDownloadDirectory = glob($nightlyDownloadDirectory) if $nightlyDownloadDirectory =~ /^~/;
+$safariPath = glob($safariPath) if $safariPath =~ /^~/;
+$safariPath = File::Spec->catdir($safariPath, "Contents/MacOS/Safari") if $safariPath =~ m#\.app/*#;
+
+$nightlyDownloadDirectory = File::Spec->catdir($nightlyDownloadDirectory, $branch);
+if (! -d $nightlyDownloadDirectory) {
+ mkpath($nightlyDownloadDirectory, 0, 0755) || die "Could not create $nightlyDownloadDirectory: $!";
+}
+
+@nightlies = makeNightlyList($localOnly, $nightlyDownloadDirectory, findMacOSXVersion(), findSafariVersion($safariPath));
+
+my $startIndex = $revisions[0] ? findNearestNightlyIndex(@nightlies, $revisions[0], 'ceil') : 0;
+my $endIndex = $revisions[1] ? findNearestNightlyIndex(@nightlies, $revisions[1], 'floor') : $#nightlies;
+
+my $tempFile = createTempFile($testURL);
+
+if ($sanityCheck) {
+ my $didReproduceBug;
+
+ do {
+ printf "\nChecking starting revision r%s...\n",
+ $nightlies[$startIndex]->{rev};
+ downloadNightly($nightlies[$startIndex]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory);
+ mountAndRunNightly($nightlies[$startIndex]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile);
+ $didReproduceBug = promptForTest($nightlies[$startIndex]->{rev});
+ $startIndex-- if $didReproduceBug < 0;
+ } while ($didReproduceBug < 0);
+ die "ERROR: Bug reproduced in starting revision! Do you need to test an earlier revision or for a progression?"
+ if $didReproduceBug && !$isProgression;
+ die "ERROR: Bug not reproduced in starting revision! Do you need to test an earlier revision or for a regression?"
+ if !$didReproduceBug && $isProgression;
+
+ do {
+ printf "\nChecking ending revision r%s...\n",
+ $nightlies[$endIndex]->{rev};
+ downloadNightly($nightlies[$endIndex]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory);
+ mountAndRunNightly($nightlies[$endIndex]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile);
+ $didReproduceBug = promptForTest($nightlies[$endIndex]->{rev});
+ $endIndex++ if $didReproduceBug < 0;
+ } while ($didReproduceBug < 0);
+ die "ERROR: Bug NOT reproduced in ending revision! Do you need to test a later revision or for a progression?"
+ if !$didReproduceBug && !$isProgression;
+ die "ERROR: Bug reproduced in ending revision! Do you need to test a later revision or for a regression?"
+ if $didReproduceBug && $isProgression;
+}
+
+printStatus($nightlies[$startIndex]->{rev}, $nightlies[$endIndex]->{rev}, $isProgression);
+
+my %brokenRevisions = ();
+while (abs($endIndex - $startIndex) > 1) {
+ my $index = $startIndex + int(($endIndex - $startIndex) / 2);
+
+ my $didReproduceBug;
+ do {
+ if (exists $nightlies[$index]) {
+ my $buildsLeft = max(max(0, $endIndex - $index - 1), max(0, $index - $startIndex - 1));
+ my $plural = $buildsLeft == 1 ? "" : "s";
+ printf "\nChecking revision r%s (%d build%s left to test after this)...\n", $nightlies[$index]->{rev}, $buildsLeft, $plural;
+ downloadNightly($nightlies[$index]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory);
+ mountAndRunNightly($nightlies[$index]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile);
+ $didReproduceBug = promptForTest($nightlies[$index]->{rev});
+ }
+ if ($didReproduceBug < 0) {
+ $brokenRevisions{$nightlies[$index]->{rev}} = $nightlies[$index]->{file};
+ delete $nightlies[$index];
+ $endIndex--;
+ $index = $startIndex + int(($endIndex - $startIndex) / 2);
+ }
+ } while ($didReproduceBug < 0);
+
+ if ($didReproduceBug && !$isProgression || !$didReproduceBug && $isProgression) {
+ $endIndex = $index;
+ } else {
+ $startIndex = $index;
+ }
+
+ print "\nBroken revisions skipped: r" . join(", r", keys %brokenRevisions) . "\n"
+ if scalar keys %brokenRevisions > 0;
+ printStatus($nightlies[$startIndex]->{rev}, $nightlies[$endIndex]->{rev}, $isProgression);
+}
+
+unlink $tempFile if $tempFile;
+
+exit 0;
+
+sub createTempFile($)
+{
+ my ($url) = @_;
+
+ return undef if !$url;
+
+ my ($fh, $tempFile) = tempfile(
+ basename($0) . "-XXXXXXXX",
+ DIR => ($ENV{'TMPDIR'} || "/tmp"),
+ SUFFIX => ".html",
+ UNLINK => 0,
+ );
+ print $fh "<meta http-equiv=\"refresh\" content=\"0; $url\">\n";
+ close($fh);
+
+ return $tempFile;
+}
+
+sub downloadNightly($$$)
+{
+ my ($filename, $urlBase, $directory) = @_;
+ my $path = File::Spec->catfile($directory, $filename);
+ if (! -f $path) {
+ print "Downloading $filename to $directory...\n";
+ `curl -# -o '$path' '$urlBase/$filename'`;
+ }
+}
+
+sub findMacOSXVersion()
+{
+ my $version;
+ open(SW_VERS, "-|", "/usr/bin/sw_vers") || die;
+ while (<SW_VERS>) {
+ $version = $1 if /^ProductVersion:\s+([^\s]+)/;
+ }
+ close(SW_VERS);
+ return $version;
+}
+
+sub findNearestNightlyIndex(\@$$)
+{
+ my ($nightlies, $revision, $round) = @_;
+
+ my $lowIndex = 0;
+ my $highIndex = $#{$nightlies};
+
+ return $highIndex if uc($revision) eq 'HEAD' || $revision >= $nightlies->[$highIndex]->{rev};
+ return $lowIndex if $revision <= $nightlies->[$lowIndex]->{rev};
+
+ while (abs($highIndex - $lowIndex) > 1) {
+ my $index = $lowIndex + int(($highIndex - $lowIndex) / 2);
+ if ($revision < $nightlies->[$index]->{rev}) {
+ $highIndex = $index;
+ } elsif ($revision > $nightlies->[$index]->{rev}) {
+ $lowIndex = $index;
+ } else {
+ return $index;
+ }
+ }
+
+ return ($round eq "floor") ? $lowIndex : $highIndex;
+}
+
+sub findSafariVersion($)
+{
+ my ($path) = @_;
+ my $versionPlist = File::Spec->catdir(dirname(dirname($path)), "version.plist");
+ my $version;
+ open(PLIST, "< $versionPlist") || die;
+ while (<PLIST>) {
+ if (m#^\s*<key>CFBundleShortVersionString</key>#) {
+ $version = <PLIST>;
+ $version =~ s#^\s*<string>(.+)</string>\s*[\r\n]*#$1#;
+ }
+ }
+ close(PLIST);
+ return $version;
+}
+
+sub loadSettings()
+{
+ package Settings;
+
+ our $branch = "trunk";
+ our $nightlyDownloadDirectory = File::Spec->catdir($ENV{HOME}, "Library/Caches/WebKit-Nightlies");
+ our $safariPath = "/Applications/Safari.app";
+
+ my $rcfile = File::Spec->catdir($ENV{HOME}, ".bisect-buildsrc");
+ return if !-f $rcfile;
+
+ my $result = do $rcfile;
+ die "Could not parse $rcfile: $@" if $@;
+}
+
+sub makeNightlyList($$$$)
+{
+ my ($useLocalFiles, $localDirectory, $macOSXVersion, $safariVersion) = @_;
+ my @files;
+
+ if ($useLocalFiles) {
+ opendir(DIR, $localDirectory) || die "$!";
+ foreach my $file (readdir(DIR)) {
+ if ($file =~ /^WebKit-SVN-r([0-9]+)\.dmg$/) {
+ push(@files, +{ rev => $1, file => $file });
+ }
+ }
+ closedir(DIR);
+ } else {
+ open(NIGHTLIES, "curl -s $nightlyBuildsURLBase/all |") || die;
+
+ while (my $line = <NIGHTLIES>) {
+ chomp $line;
+ my ($revision, $timestamp, $url) = split(/,/, $line);
+ my $nightly = basename($url);
+ push(@files, +{ rev => $revision, file => $nightly });
+ }
+ close(NIGHTLIES);
+ }
+
+ if (eval "v$macOSXVersion" ge v10.5) {
+ if ($safariVersion eq "4 Public Beta") {
+ @files = grep { $_->{rev} >= 39682 } @files;
+ } elsif (eval "v$safariVersion" ge v3.2) {
+ @files = grep { $_->{rev} >= 37348 } @files;
+ } elsif (eval "v$safariVersion" ge v3.1) {
+ @files = grep { $_->{rev} >= 29711 } @files;
+ } elsif (eval "v$safariVersion" ge v3.0) {
+ @files = grep { $_->{rev} >= 25124 } @files;
+ } elsif (eval "v$safariVersion" ge v2.0) {
+ @files = grep { $_->{rev} >= 19594 } @files;
+ } else {
+ die "Requires Safari 2.0 or newer";
+ }
+ } elsif (eval "v$macOSXVersion" ge v10.4) {
+ if ($safariVersion eq "4 Public Beta") {
+ @files = grep { $_->{rev} >= 39682 } @files;
+ } elsif (eval "v$safariVersion" ge v3.2) {
+ @files = grep { $_->{rev} >= 37348 } @files;
+ } elsif (eval "v$safariVersion" ge v3.1) {
+ @files = grep { $_->{rev} >= 29711 } @files;
+ } elsif (eval "v$safariVersion" ge v3.0) {
+ @files = grep { $_->{rev} >= 19992 } @files;
+ } elsif (eval "v$safariVersion" ge v2.0) {
+ @files = grep { $_->{rev} >= 11976 } @files;
+ } else {
+ die "Requires Safari 2.0 or newer";
+ }
+ } else {
+ die "Requires Mac OS X 10.4 (Tiger) or 10.5 (Leopard)";
+ }
+
+ my $nightlycmp = sub { return $a->{rev} <=> $b->{rev}; };
+
+ return sort $nightlycmp @files;
+}
+
+sub mountAndRunNightly($$$$)
+{
+ my ($filename, $directory, $safari, $tempFile) = @_;
+ my $mountPath = "/Volumes/WebKit";
+ my $webkitApp = File::Spec->catfile($mountPath, "WebKit.app");
+ my $diskImage = File::Spec->catfile($directory, $filename);
+
+ my $i = 0;
+ while (-e $mountPath) {
+ $i++;
+ usleep 100 if $i > 1;
+ `hdiutil detach '$mountPath' 2> /dev/null`;
+ die "Could not unmount $diskImage at $mountPath" if $i > 100;
+ }
+ die "Can't mount $diskImage: $mountPath already exists!" if -e $mountPath;
+
+ print "Mounting disk image and running WebKit...\n";
+ `hdiutil attach '$diskImage'`;
+ $i = 0;
+ while (! -e $webkitApp) {
+ usleep 100;
+ $i++;
+ die "Could not mount $diskImage at $mountPath" if $i > 100;
+ }
+
+ my $frameworkPath;
+ if (-d "/Volumes/WebKit/WebKit.app/Contents/Frameworks") {
+ my $osXVersion = join('.', (split(/\./, findMacOSXVersion()))[0..1]);
+ $frameworkPath = "/Volumes/WebKit/WebKit.app/Contents/Frameworks/$osXVersion";
+ } else {
+ $frameworkPath = "/Volumes/WebKit/WebKit.app/Contents/Resources";
+ }
+
+ $tempFile ||= "";
+ `DYLD_FRAMEWORK_PATH=$frameworkPath WEBKIT_UNSET_DYLD_FRAMEWORK_PATH=YES $safari $tempFile`;
+
+ `hdiutil detach '$mountPath' 2> /dev/null`;
+}
+
+sub parseRevisions($$;$)
+{
+ my ($optionName, $value, $ignored) = @_;
+
+ if ($value =~ /^r?([0-9]+|HEAD):?$/i) {
+ push(@revisions, $1);
+ die "Too many revision arguments specified" if scalar @revisions > 2;
+ } elsif ($value =~ /^r?([0-9]+):?r?([0-9]+|HEAD)$/i) {
+ $revisions[0] = $1;
+ $revisions[1] = $2;
+ } else {
+ die "Unknown revision '$value': expected 'M' or 'M:N'";
+ }
+}
+
+sub printStatus($$$)
+{
+ my ($startRevision, $endRevision, $isProgression) = @_;
+ printf "\n%s: r%s %s: r%s\n",
+ $isProgression ? "Fails" : "Works", $startRevision,
+ $isProgression ? "Works" : "Fails", $endRevision;
+}
+
+sub promptForTest($)
+{
+ my ($revision) = @_;
+ print "Did the bug reproduce in r$revision (yes/no/broken)? ";
+ my $answer = <STDIN>;
+ return 1 if $answer =~ /^(1|y.*)$/i;
+ return -1 if $answer =~ /^(-1|b.*)$/i; # Broken
+ return 0;
+}
+
diff --git a/WebKitTools/Scripts/build-drawtest b/WebKitTools/Scripts/build-drawtest
new file mode 100755
index 0000000..fa9b7c2
--- /dev/null
+++ b/WebKitTools/Scripts/build-drawtest
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Simplified build script for WebKit Open Source Project.
+# Modified copy of build-dumprendertree. Perhaps these could share code.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+my @options = XcodeOptions();
+
+# Check to see that all the frameworks are built (w/ SVG support).
+checkFrameworks();
+checkWebCoreSVGSupport(1);
+
+# Build
+chdir "WebKitTools/DrawTest" or die;
+exit system "xcodebuild", "-project", "DrawTest.xcodeproj", @options;
diff --git a/WebKitTools/Scripts/build-dumprendertree b/WebKitTools/Scripts/build-dumprendertree
new file mode 100755
index 0000000..46e86e0
--- /dev/null
+++ b/WebKitTools/Scripts/build-dumprendertree
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+my @options = XcodeOptions();
+
+# Build
+chdir "WebKitTools/DumpRenderTree" or die;
+my $result;
+if (isAppleMacWebKit()) {
+ $result = system "xcodebuild", "-project", "DumpRenderTree.xcodeproj", @options, @ARGV;
+} elsif (isAppleWinWebKit()) {
+ $result = buildVisualStudioProject("DumpRenderTree.sln");
+} elsif (isQt() || isGtk()) {
+ # Qt and Gtk build everything in one shot. No need to build anything here.
+ $result = 0;
+} else {
+ die "Building not defined for this platform!\n";
+}
+exit exitStatus($result);
diff --git a/WebKitTools/Scripts/build-jsc b/WebKitTools/Scripts/build-jsc
new file mode 100755
index 0000000..78ed0d0
--- /dev/null
+++ b/WebKitTools/Scripts/build-jsc
@@ -0,0 +1,78 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+use strict;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+my $coverageSupport = 0;
+my $showHelp = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --[no-]coverage Toggle code coverage support (default: $coverageSupport)
+EOF
+
+GetOptions(
+ 'coverage!' => \$coverageSupport,
+ 'help' => \$showHelp
+);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+my @options = XcodeOptions();
+my @coverageSupportOptions = ($coverageSupport) ? XcodeCoverageSupportOptions() : ();
+
+chdir "JavaScriptCore" or die "Can't find JavaScriptCore directory to build from";
+my $result;
+if (isAppleMacWebKit()) {
+ $result = system "sh", "-c", 'xcodebuild -project JavaScriptCore.xcodeproj "$@" | grep -v setenv && exit ${PIPESTATUS[0]}', "xcodebuild", @options, @ARGV, @coverageSupportOptions;
+} elsif (isAppleWinWebKit()) {
+ $result = buildVisualStudioProject("JavaScriptCore.vcproj/JavaScriptCore.sln");
+} elsif (isChromium()) {
+ $result = buildSconsProject("JavaScriptCore");
+} elsif (isQt() or isGtk() or isWx()) {
+ # Qt and Gtk build everything in one-shot. No need to build anything here.
+ $result = 0;
+} else {
+ die "Building not defined for this platform!\n";
+}
+exit exitStatus($result);
diff --git a/WebKitTools/Scripts/build-webkit b/WebKitTools/Scripts/build-webkit
new file mode 100755
index 0000000..788ace0
--- /dev/null
+++ b/WebKitTools/Scripts/build-webkit
@@ -0,0 +1,333 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Build script wrapper for the WebKit Open Source Project.
+
+use strict;
+use File::Basename;
+use File::Spec;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+my $originalWorkingDirectory = getcwd();
+
+my $channelMessagingSupport = 0;
+my $databaseSupport = 1;
+my $domStorageSupport = 1;
+my $gnomeKeyringSupport = 0;
+my $iconDatabaseSupport = 1;
+my $offlineWebApplicationSupport = 1;
+my $svgSupport = 1;
+my $svgAnimationSupport = 1;
+my $svgFiltersSupport = 0;
+my $svgForeignObjectSupport = 1;
+my $svgUseSupport = 1;
+my $svgFontsSupport = 1;
+my $svgAsImageSupport = 1;
+my $xpathSupport = 1;
+my $xsltSupport = 1;
+my $wmlSupport = 0;
+my $coverageSupport = 0;
+my $videoSupport = (isAppleWebKit() || isGtk()); # Enable by default for Apple's builds and Gtk+
+my $workersSupport = (isAppleWebKit() || isGtk()); # Enable by default for Apple's builds (mac/win) and Gtk+
+my $geolocationSupport = (isAppleMacWebKit() && !isTiger() && !isLeopard());
+my $showHelp = 0;
+my $clean = 0;
+my $threeDRenderingSupport = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --cairo-win32 Build using Cairo (rather than CoreGraphics) on Windows
+ --chromium Build the Chromium port on Mac/Win/Linux
+ --clean Cleanup the build directory
+ --gtk Build the GTK+ port
+ --[no-]3d-rendering Toggle 3D rendering support (default: $threeDRenderingSupport)
+ --[no-]channel-messaging Toggle MessageChannel and MessagePort support (default: $channelMessagingSupport)
+ --[no-]offline-web-applications Toggle Offline Web Application Support (default : $offlineWebApplicationSupport)
+ --[no-]database Toggle Database Support (default: $databaseSupport)
+ --[no-]dom-storage Toggle DOM Storage Support (default: $domStorageSupport)
+ --[no-]gnomekeyring Toggle GNOME Keyring Support (GTK+ port only) (default: $gnomeKeyringSupport)
+ --[no-]icon-database Toggle Icon database support (default: $iconDatabaseSupport)
+ --[no-]svg Toggle SVG support (default: $svgSupport)
+ --[no-]svg-animation Toggle SVG animation support (default: $svgAnimationSupport, implies SVG Support)
+ --[no-]svg-filters Toggle SVG filters support (default: $svgFiltersSupport, implies SVG Support)
+ --[no-]svg-foreign-object Toggle SVG foreign object support (default: $svgForeignObjectSupport, implies SVG Support)
+ --[no-]svg-fonts Toggle SVG fonts support (default: $svgFontsSupport, implies SVG Support)
+ --[no-]svg-as-image Toggle SVG as Image support (default: $svgAsImageSupport, implies SVG Support)
+ --[no-]svg-use Toggle SVG use element support (default: $svgUseSupport, implies SVG Support)
+ --[no-]xpath Toggle XPath support (default: $xpathSupport)
+ --[no-]xslt Toggle XSLT support (default: $xsltSupport)
+ --[no-]wml Toggle WML support (default: $wmlSupport)
+ --[no-]video Toggle Video support (default: $videoSupport)
+ --[no-]workers Toggle Web Workers support (default: $workersSupport)
+ --[no-]geolocation Toggle Geolocation support (default: $geolocationSupport)
+ --[no-]coverage Toggle code coverage support (default: $coverageSupport)
+EOF
+
+GetOptions(
+ '3d-rendering!' => \$threeDRenderingSupport,
+ 'channel-messaging!' => \$channelMessagingSupport,
+ 'database!' => \$databaseSupport,
+ 'dom-storage!' => \$domStorageSupport,
+ 'gnomekeyring!' => \$gnomeKeyringSupport,
+ 'icon-database!' => \$iconDatabaseSupport,
+ 'offline-web-applications!' => \$offlineWebApplicationSupport,
+ 'svg!' => \$svgSupport,
+ 'svg-animation!' => \$svgAnimationSupport,
+ 'svg-filters!' => \$svgFiltersSupport,
+ 'svg-foreign-object!' => \$svgForeignObjectSupport,
+ 'svg-fonts!' => \$svgFontsSupport,
+ 'svg-as-image!' => \$svgAsImageSupport,
+ 'svg-use!' => \$svgUseSupport,
+ 'xpath!' => \$xpathSupport,
+ 'xslt!' => \$xsltSupport,
+ 'wml!' => \$wmlSupport,
+ 'video!' => \$videoSupport,
+ 'workers!' => \$workersSupport,
+ 'geolocation!' => \$geolocationSupport,
+ 'coverage!' => \$coverageSupport,
+ 'help' => \$showHelp,
+ 'clean' => \$clean);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+
+if (isWx()) {
+ $ENV{"WEBKITOUTPUTDIR"} = productDir();
+
+ my @opts = getWxArgs();
+
+ if ($clean) {
+ push(@opts, "clean");
+ }
+ system "WebKitTools/wx/build-wxwebkit @opts";
+ exit exitStatus($?);
+}
+
+
+my $productDir = productDir();
+my @overrideFeatureDefinesOption = ();
+
+# This needs to be kept sorted, and in sync with FEATURE_DEFINES in JavaScriptCore.xcconfig, WebCore.xcconfig
+# and WebKit.xcconfig to prevent needless rebuilding when using both Xcode and build-webkit.
+
+push @overrideFeatureDefinesOption, "ENABLE_3D_RENDERING" if $threeDRenderingSupport;
+push @overrideFeatureDefinesOption, "ENABLE_CHANNEL_MESSAGING" if $channelMessagingSupport;
+push @overrideFeatureDefinesOption, "ENABLE_DATABASE" if $databaseSupport;
+push @overrideFeatureDefinesOption, "ENABLE_DOM_STORAGE" if $domStorageSupport;
+push @overrideFeatureDefinesOption, "ENABLE_ICONDATABASE" if $iconDatabaseSupport;
+push @overrideFeatureDefinesOption, "ENABLE_OFFLINE_WEB_APPLICATIONS" if $offlineWebApplicationSupport;
+push @overrideFeatureDefinesOption, "ENABLE_SVG" if $svgSupport;
+push @overrideFeatureDefinesOption, "ENABLE_SVG_ANIMATION" if $svgAnimationSupport;
+push @overrideFeatureDefinesOption, "ENABLE_SVG_AS_IMAGE" if $svgAsImageSupport;
+push @overrideFeatureDefinesOption, "ENABLE_SVG_FILTERS" if $svgFiltersSupport;
+push @overrideFeatureDefinesOption, "ENABLE_SVG_FONTS" if $svgFontsSupport;
+push @overrideFeatureDefinesOption, "ENABLE_SVG_FOREIGN_OBJECT" if $svgForeignObjectSupport;
+push @overrideFeatureDefinesOption, "ENABLE_SVG_USE" if $svgUseSupport;
+push @overrideFeatureDefinesOption, "ENABLE_VIDEO" if $videoSupport;
+push @overrideFeatureDefinesOption, "ENABLE_WORKERS" if $workersSupport;
+push @overrideFeatureDefinesOption, "ENABLE_XPATH" if $xpathSupport;
+push @overrideFeatureDefinesOption, "ENABLE_XSLT" if $xsltSupport;
+push @overrideFeatureDefinesOption, "ENABLE_WML" if $wmlSupport;
+push @overrideFeatureDefinesOption, "ENABLE_GEOLOCATION" if $geolocationSupport;
+my $overrideFeatureDefinesString = "FEATURE_DEFINES=" . join(" ", @overrideFeatureDefinesOption);
+
+my @coverageSupportOption = ($coverageSupport) ? XcodeCoverageSupportOptions() : ();
+
+# Check that all the project directories are there.
+my @projects = ("JavaScriptCore", "WebCore", "WebKit");
+# Only Apple builds JavaScriptGlue, and only on the Mac
+push @projects, "JavaScriptGlue" if isAppleMacWebKit();
+
+my @otherDirs = ("WebKitLibraries");
+for my $dir (@projects, @otherDirs) {
+ if (! -d $dir) {
+ die "Error: No $dir directory found. Please do a fresh checkout.\n";
+ }
+}
+
+my @options = ();
+
+# enable autotool options accordingly
+if (isGtk()) {
+ push @options, autotoolsFlag($databaseSupport, "database");
+ push @options, autotoolsFlag($domStorageSupport, "dom-storage");
+ push @options, autotoolsFlag($gnomeKeyringSupport, "gnomekeyring");
+ push @options, autotoolsFlag($iconDatabaseSupport, "icon-database");
+ push @options, autotoolsFlag($offlineWebApplicationSupport, "offline-web-applications");
+ push @options, autotoolsFlag($threeDRenderingSupport, "3D-rendering");
+ push @options, autotoolsFlag($channelMessagingSupport, "channel-messaging");
+ push @options, autotoolsFlag($svgSupport, "svg");
+ push @options, autotoolsFlag($svgAnimationSupport, "svg-animation");
+ push @options, autotoolsFlag($svgFiltersSupport, "svg-filters");
+ push @options, autotoolsFlag($svgForeignObjectSupport, "svg-foreign-object");
+ push @options, autotoolsFlag($svgFontsSupport, "svg-fonts");
+ push @options, autotoolsFlag($svgAsImageSupport, "svg-as-image");
+ push @options, autotoolsFlag($svgUseSupport, "svg-use-element");
+ push @options, autotoolsFlag($xpathSupport, "xpath");
+ push @options, autotoolsFlag($xsltSupport, "xslt");
+ push @options, autotoolsFlag($wmlSupport, "wml");
+ push @options, autotoolsFlag($videoSupport, "video");
+ push @options, autotoolsFlag($workersSupport, "web-workers");
+ push @options, autotoolsFlag($coverageSupport, "coverage");
+}
+
+if (isAppleMacWebKit()) {
+
+ push(@options, XcodeOptions());
+
+ # Copy library and header from WebKitLibraries to a findable place in the product directory.
+ my $srcLib = "WebKitLibraries/libWebKitSystemInterfaceTiger.a";
+ my $lib = "$productDir/libWebKitSystemInterfaceTiger.a";
+ if (!-e $lib || -M $lib > -M $srcLib) {
+ print "Updating $lib\n";
+ system "ditto", $srcLib, $lib;
+ system "ranlib", $lib;
+ }
+
+ $srcLib = "WebKitLibraries/libWebKitSystemInterfaceLeopard.a";
+ $lib = "$productDir/libWebKitSystemInterfaceLeopard.a";
+ if (!-e $lib || -M $lib > -M $srcLib) {
+ print "Updating $lib\n";
+ system "ditto", $srcLib, $lib;
+ system "ranlib", $lib;
+ }
+
+ my $srcHeader = "WebKitLibraries/WebKitSystemInterface.h";
+ my $header = "$productDir/usr/local/include/WebKitSystemInterface.h";
+ if (!-e $header || -M $header > -M $srcHeader) {
+ print "Updating $header\n";
+ system "mkdir", "-p", "$productDir/usr/local/include";
+ system "ditto", $srcHeader, $header;
+ }
+
+ $srcLib = "WebKitLibraries/libWebCoreSQLite3.a";
+ $lib = "$productDir/libWebCoreSQLite3.a";
+ if (!-e $lib || -M $lib > -M $srcLib) {
+ print "Updating $lib\n";
+ system "ditto", $srcLib, $lib;
+ system "ranlib", $lib;
+ }
+
+ my $srcHeaderDir = "WebKitLibraries/WebCoreSQLite3";
+ my $headerDir = "$productDir/WebCoreSQLite3";
+ if (!-e $headerDir || -M $headerDir > -M $srcHeaderDir) {
+ print "Updating $headerDir\n";
+ system "ditto", $srcHeaderDir, $headerDir;
+ }
+}
+
+if (isAppleWinWebKit()) {
+ # Copy WebKitSupportLibrary to the correct location in WebKitLibraries so it can be found.
+ # Will fail if WebKitSupportLibrary.zip is not in source root.
+ (system("perl WebKitTools/Scripts/update-webkit-support-libs") == 0) or die;
+}
+
+# Force re-link of existing libraries if different than expected
+removeLibraryDependingOnSVG("WebCore", $svgSupport);
+
+# Build, and abort if the build fails.
+for my $dir (@projects) {
+ chdir $dir or die;
+ my $result = 0;
+
+ # For Gtk and Qt the WebKit project builds all others
+ if ((isGtk() || isQt()) && $dir ne "WebKit") {
+ chdir ".." or die;
+ next;
+ }
+
+ if (isGtk()) {
+ $result = buildGtkProject($dir, $clean, @options);
+ } elsif (isQt()) {
+ $result = buildQMakeQtProject($dir, $clean, @ARGV);
+ } elsif (isAppleMacWebKit()) {
+ my @xcodeOptions = ();
+ push(@xcodeOptions, @options);
+ push(@xcodeOptions, $overrideFeatureDefinesString);
+ push(@xcodeOptions, @coverageSupportOption);
+ push(@xcodeOptions, @ARGV);
+ $result = buildXCodeProject($dir, $clean, @xcodeOptions);
+ } elsif (isAppleWinWebKit()) {
+ if ($dir eq "WebKit") {
+ $result = buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean);
+ }
+ } elsif (isChromium()) {
+ $result = buildSconsProject($dir, $clean);
+ }
+
+ if (exitStatus($result)) {
+ if (isAppleWinWebKit()) {
+ print "\n\n===== BUILD FAILED ======\n\n";
+ my $scriptDir = relativeScriptsDir();
+ print "Please ensure you have run $scriptDir/update-webkit to install depenedencies.\n\n";
+ my $baseProductDir = baseProductDir();
+ print "You can view build errors by checking the BuildLog.htm files located at:\n$baseProductDir/obj/<project>/<config>.\n";
+ }
+ exit exitStatus($result);
+ }
+ chdir ".." or die;
+}
+
+# Don't report the "WebKit is now built" message after a clean operation.
+exit if $clean;
+
+# Write out congratulations message.
+
+my $launcherPath = launcherPath();
+my $launcherName = launcherName();
+
+print "\n";
+print "===========================================================\n";
+print " WebKit is now built. To run $launcherName with this newly-built\n";
+print " code, use the \"$launcherPath\" script.\n";
+if ($svgSupport) {
+ print "\n NOTE: WebKit has been built with SVG support enabled.\n";
+ print " $launcherName will have SVG viewing capabilities.\n";
+}
+if ($svgAnimationSupport or $svgFiltersSupport or $svgForeignObjectSupport or $svgFontsSupport or $svgAsImageSupport or $svgUseSupport) {
+ print " Your build supports the following (optional) SVG features: \n";
+ print " * Basic SVG animation.\n" if $svgAnimationSupport;
+ print " * SVG filters.\n" if $svgFiltersSupport;
+ print " * SVG foreign object.\n" if $svgForeignObjectSupport;
+ print " * SVG fonts.\n" if $svgFontsSupport;
+ print " * SVG as image.\n" if $svgAsImageSupport;
+ print " * SVG <use> support.\n" if $svgUseSupport;
+}
+print "===========================================================\n";
diff --git a/WebKitTools/Scripts/check-dom-results b/WebKitTools/Scripts/check-dom-results
new file mode 100755
index 0000000..0b32406
--- /dev/null
+++ b/WebKitTools/Scripts/check-dom-results
@@ -0,0 +1,141 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to check status of W3C DOM tests that are part of the WebKit tests.
+
+use strict;
+use FindBin;
+use Cwd;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+chdirWebKit();
+
+my $verbose = $ARGV[0] && $ARGV[0] eq "-v";
+
+my $workingDir = getcwd();
+my $testDirectory = "$workingDir/LayoutTests";
+
+my @suites = ( {"name" => "DOM Level 1 Core (html)", "directory" => "dom/html/level1/core"},
+ {"name" => "DOM Level 2 Core (html)", "directory" => "dom/html/level2/core"},
+ {"name" => "DOM Level 2 Events (html)", "directory" => "dom/html/level2/events"},
+ {"name" => "DOM Level 2 HTML (html)", "directory" => "dom/html/level2/html"},
+ {"name" => "DOM Level 1 Core (xhtml)", "directory" => "dom/xhtml/level1/core"},
+ {"name" => "DOM Level 2 Core (xhtml)", "directory" => "dom/xhtml/level2/core"},
+ {"name" => "DOM Level 2 Events (xhtml)", "directory" => "dom/xhtml/level2/events"},
+ {"name" => "DOM Level 2 HTML (xhtml)", "directory" => "dom/xhtml/level2/html"},
+ {"name" => "DOM Level 3 Core (xhtml)", "directory" => "dom/xhtml/level3/core"},
+ {"name" => "DOM Level 3 XPath (svg)", "directory" => "dom/svg/level3/xpath"});
+
+my $totalCount = 0;
+my $totalSuccesses = 0;
+my $totalDisabled = 0;
+my $totalFailed = 0;
+
+foreach my $suite (@suites) {
+
+ my %suite = %$suite;
+ my $directory = $suite{"directory"};
+ my $name = $suite{"name"};
+ my @results = `find "${testDirectory}/${directory}" -name "*-expected.txt"`;
+ my @disabled = `find "${testDirectory}/${directory}" -name "*-disabled"`;
+
+ my @failures = ();
+ my $count = 0;
+
+ foreach my $result (@results) {
+ $count++;
+ my $success = 0;
+ open RESULT, "<$result";
+ while (<RESULT>) {
+ if (/Success/) {
+ $success = 1;
+ last;
+ }
+ }
+ close RESULT;
+ if (!$success) {
+ push @failures, $result;
+ }
+ }
+
+ my $disabledCount = (scalar @disabled);
+ my $failureCount = (scalar @failures);
+
+ $count += $disabledCount;
+
+ my $successCount = $count - $failureCount - $disabledCount;
+ my $percentage = (sprintf "%.1f", ($successCount * 100.0 / $count));
+
+ if ($percentage == 100) {
+ print "${name}: all ${count} tests succeeded";
+ } else {
+ print "${name}: ${successCount} out of ${count} tests succeeded (${percentage}%)";
+ }
+ print " ($disabledCount disabled)" if $disabledCount;
+ print "\n";
+ if ($verbose) {
+ print "\n";
+ if (@disabled) {
+ print " Disabled:\n";
+
+ foreach my $failure (sort @disabled) {
+ $failure =~ s|.*/||;
+ $failure =~ s|-disabled||;
+ print " ${directory}/${failure}";
+ }
+ }
+ if (@failures) {
+ print " Failed:\n";
+
+ foreach my $failure (sort @failures) {
+ $directory =~ m|^dom/(\w+)|;
+ my $extension = $1;
+ $failure =~ s|.*/||;
+ $failure =~ s|-expected\.txt|.${extension}|;
+ print " ${directory}/${failure}";
+ }
+ }
+
+ print "\n";
+ }
+
+ $totalCount += $count;
+ $totalSuccesses += $successCount;
+ $totalDisabled += $disabledCount;
+ $totalFailed += $failureCount;
+}
+
+
+my $totalPercentage = (sprintf "%.1f", ($totalSuccesses * 100.0 / $totalCount));
+my $totalDisabledPercentage = (sprintf "%.1f", ($totalDisabled * 100.0 / $totalCount));
+my $totalFailedPercentage = (sprintf "%.1f", ($totalFailed * 100.0 / $totalCount));
+
+print "Total: ${totalSuccesses} out of ${totalCount} tests succeeded (${totalPercentage}%)\n";
+print " ${totalDisabled} tests disabled (${totalDisabledPercentage}%)\n";
+print " ${totalFailed} tests failed (${totalFailedPercentage}%)\n";
diff --git a/WebKitTools/Scripts/check-for-exit-time-destructors b/WebKitTools/Scripts/check-for-exit-time-destructors
new file mode 100755
index 0000000..19656b5
--- /dev/null
+++ b/WebKitTools/Scripts/check-for-exit-time-destructors
@@ -0,0 +1,151 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# "check-for-exit-time-destructors" script for WebKit Open Source Project
+
+# Intended to be invoked from an Xcode build step to check if there are
+# any exit-time destructors in a target.
+
+use warnings;
+use strict;
+
+use File::Basename;
+
+sub touch($);
+sub printFunctions($$);
+
+my $arch = $ENV{'CURRENT_ARCH'};
+my $configuration = $ENV{'CONFIGURATION'};
+my $target = $ENV{'TARGET_NAME'};
+my $variant = $ENV{'CURRENT_VARIANT'};
+my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'};
+my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'};
+
+$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH
+$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT
+
+my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}";
+
+my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp";
+my $buildTimestampAge = -M $buildTimestampPath;
+my $scriptAge = -M $0;
+
+my $list = $ENV{"LINK_FILE_LIST_${variant}_${arch}"};
+
+if (!open LIST, $list) {
+ print "Could not open $list\n";
+ exit 1;
+}
+
+my @files = <LIST>;
+chomp @files;
+close LIST;
+
+my $sawError = 0;
+
+for my $file (sort @files) {
+ if (defined $buildTimestampAge && $buildTimestampAge < $scriptAge) {
+ my $fileAge = -M $file;
+ next if defined $fileAge && $fileAge > $buildTimestampAge;
+ }
+ if (!open NM, "(nm '$file' | sed 's/^/STDOUT:/') 2>&1 |") {
+ print "Could not open $file\n";
+ $sawError = 1;
+ next;
+ }
+ my $sawAtExit = 0;
+ while (<NM>) {
+ if (/^STDOUT:/) {
+ $sawAtExit = 1 if /___cxa_atexit/;
+ } else {
+ print STDERR if $_ ne "nm: no name list\n";
+ }
+ }
+ close NM;
+ next unless $sawAtExit;
+
+ my $shortName = $file;
+ $shortName =~ s/.*\///;
+
+ $sawError = 1 if printFunctions($shortName, $file);
+}
+
+if ($sawError and !$coverageBuild) {
+ print "Use DEFINE_STATIC_LOCAL from <wtf/StdLibExtras.h>\n";
+ unlink $executablePath;
+ exit 1;
+}
+
+touch($buildTimestampPath);
+exit 0;
+
+sub touch($)
+{
+ my ($path) = @_;
+ open(TOUCH, ">", $path) or die "$!";
+ close(TOUCH);
+}
+
+sub demangle($)
+{
+ my ($symbol) = @_;
+ if (!open FILT, "c++filt $symbol |") {
+ print "Could not open c++filt\n";
+ return;
+ }
+ my $result = <FILT>;
+ close FILT;
+ chomp $result;
+ return $result;
+}
+
+sub printFunctions($$)
+{
+ my ($shortName, $path) = @_;
+ if (!open OTOOL, "otool -tV '$path' |") {
+ print "Could not open $path\n";
+ return 0;
+ }
+ my %functions;
+ my $currentSymbol = "";
+ while (<OTOOL>) {
+ $currentSymbol = $1 if /^(\w+):$/;
+ next unless $currentSymbol;
+ $functions{demangle($currentSymbol)} = 1 if /___cxa_atexit/;
+ }
+ close OTOOL;
+ my $result = 0;
+ for my $function (sort keys %functions) {
+ if (!$result) {
+ print "$shortName has exit time destructors in it! ($path)\n";
+ $result = 1;
+ }
+ print " $function\n";
+ }
+ return $result;
+}
diff --git a/WebKitTools/Scripts/check-for-global-initializers b/WebKitTools/Scripts/check-for-global-initializers
new file mode 100755
index 0000000..88894be
--- /dev/null
+++ b/WebKitTools/Scripts/check-for-global-initializers
@@ -0,0 +1,135 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# "check-for-global-initializers" script for WebKit Open Source Project
+
+# Intended to be invoked from an Xcode build step to check if there are
+# any global initializers in a target.
+
+use warnings;
+use strict;
+
+use File::Basename;
+
+sub touch($);
+
+my $arch = $ENV{'CURRENT_ARCH'};
+my $configuration = $ENV{'CONFIGURATION'};
+my $target = $ENV{'TARGET_NAME'};
+my $variant = $ENV{'CURRENT_VARIANT'};
+my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'};
+my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'};
+
+$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH
+$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT
+
+my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}";
+
+my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp";
+my $buildTimestampAge = -M $buildTimestampPath;
+my $scriptAge = -M $0;
+
+my $list = $ENV{"LINK_FILE_LIST_${variant}_${arch}"};
+
+if (!open LIST, $list) {
+ print "Could not open $list\n";
+ exit 1;
+}
+
+my @files = <LIST>;
+chomp @files;
+close LIST;
+
+my $sawError = 0;
+
+for my $file (sort @files) {
+ if (defined $buildTimestampAge && $buildTimestampAge < $scriptAge) {
+ my $fileAge = -M $file;
+ next if defined $fileAge && $fileAge > $buildTimestampAge;
+ }
+ if (!open NM, "(nm '$file' | sed 's/^/STDOUT:/') 2>&1 |") {
+ print "Could not open $file\n";
+ $sawError = 1;
+ next;
+ }
+ my $sawGlobal = 0;
+ while (<NM>) {
+ if (/^STDOUT:/) {
+ $sawGlobal = 1 if /__GLOBAL__I/;
+ } else {
+ print STDERR if $_ ne "nm: no name list\n";
+ }
+ }
+ close NM;
+ if ($sawGlobal) {
+ my $shortName = $file;
+ $shortName =~ s/.*\///;
+
+ # Special cases for files that have initializers in debug builds.
+ if ($configuration eq "Debug" or $variant eq "debug" or $debugRoot) {
+ if ($target eq "JavaScriptCore") {
+ next if $shortName eq "AllInOneFile.o";
+ next if $shortName eq "Opcode.o";
+ next if $shortName eq "Structure.o";
+ next if $shortName eq "nodes.o";
+ }
+ if ($target eq "WebCore") {
+ next if $shortName eq "CachedPage.o";
+ next if $shortName eq "CachedResource.o";
+ next if $shortName eq "Frame.o";
+ next if $shortName eq "JSCustomSQLTransactionCallback.o";
+ next if $shortName eq "JSEventListener.o";
+ next if $shortName eq "Node.o";
+ next if $shortName eq "Page.o";
+ next if $shortName eq "Range.o";
+ next if $shortName eq "RenderObject.o";
+ next if $shortName eq "SubresourceLoader.o";
+ next if $shortName eq "SVGElementInstance.o";
+ next if $shortName eq "bidi.o";
+ }
+ }
+
+ print "$shortName has a global initializer in it! ($file)\n";
+ $sawError = 1;
+ }
+}
+
+if ($sawError and !$coverageBuild) {
+ unlink $executablePath;
+ exit 1;
+}
+
+touch($buildTimestampPath);
+exit 0;
+
+sub touch($)
+{
+ my ($path) = @_;
+ open(TOUCH, ">", $path) or die "$!";
+ close(TOUCH);
+}
diff --git a/WebKitTools/Scripts/check-for-weak-vtables b/WebKitTools/Scripts/check-for-weak-vtables
new file mode 100755
index 0000000..d274b01
--- /dev/null
+++ b/WebKitTools/Scripts/check-for-weak-vtables
@@ -0,0 +1,101 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# "check-for-weak-vtables" script for WebKit Open Source Project
+
+# Intended to be invoked from an Xcode build step to check if there are
+# any weak vtables in a target.
+
+use warnings;
+use strict;
+
+use File::Basename;
+
+sub touch($);
+
+my $arch = $ENV{'CURRENT_ARCH'};
+my $configuration = $ENV{'CONFIGURATION'};
+my $target = $ENV{'TARGET_NAME'};
+my $variant = $ENV{'CURRENT_VARIANT'};
+my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'};
+my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'};
+
+$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH
+$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT
+
+my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}";
+
+my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp";
+my $buildTimestampAge = -M $buildTimestampPath;
+my $executablePathAge = -M $executablePath;
+
+my $sawError = 0;
+
+if (!defined $executablePathAge || !defined $buildTimestampAge || $executablePathAge > $buildTimestampAge) {
+ if (!open NM, "(nm -m '$executablePath' | c++filt | sed 's/^/STDOUT:/') 2>&1 |") {
+ print "Could not open $executablePath\n";
+ $sawError = 1;
+ next;
+ }
+ my @weakVTableClasses = ();
+ while (<NM>) {
+ if (/^STDOUT:/) {
+ push @weakVTableClasses, $1 if /weak external vtable for (.*)$/;
+ } else {
+ print STDERR if $_ ne "nm: no name list\n";
+ }
+ }
+ close NM;
+ if (@weakVTableClasses) {
+ my $shortName = $executablePath;
+ $shortName =~ s/.*\///;
+
+ print "$shortName has a weak vtable in it ($executablePath)\n";
+ print "Fix by making sure the first virtual function in each of these classes is not an inline:\n";
+ for my $class (sort @weakVTableClasses) {
+ print " $class\n";
+ }
+ $sawError = 1;
+ }
+}
+
+if ($sawError and !$coverageBuild) {
+ unlink $executablePath;
+ exit 1;
+}
+
+touch($buildTimestampPath);
+
+exit 0;
+
+sub touch($)
+{
+ my ($path) = @_;
+ open(TOUCH, ">", $path) or die "$!";
+ close(TOUCH);
+}
diff --git a/WebKitTools/Scripts/clean-header-guards b/WebKitTools/Scripts/clean-header-guards
new file mode 100755
index 0000000..2bad046
--- /dev/null
+++ b/WebKitTools/Scripts/clean-header-guards
@@ -0,0 +1,53 @@
+#!/usr/bin/ruby
+
+require 'find'
+require 'optparse'
+
+options = {}
+OptionParser.new do |opts|
+ opts.banner = "Usage: clean-header-guards [options]"
+
+ opts.on("--prefix [PREFIX]", "Append a header prefix to all guards") do |prefix|
+ options[:prefix] = prefix
+ end
+end.parse!
+
+IgnoredFilenamePatterns = [
+ # ignore headers which are known not to have guard
+ /WebCorePrefix/,
+ /ForwardingHeaders/,
+ %r|bindings/objc|,
+ /vcproj/, # anything inside a vcproj is in the windows wasteland
+
+ # we don't own any of these headers
+ %r|icu/unicode|,
+ %r|platform/graphics/cairo|,
+ %r|platform/image-decoders|,
+
+ /config.h/ # changing this one sounds scary
+].freeze
+
+IgnoreFileNamesPattern = Regexp.union(*IgnoredFilenamePatterns).freeze
+
+Find::find(".") do |filename|
+ next unless filename =~ /\.h$/
+ next if filename.match(IgnoreFileNamesPattern)
+
+ File.open(filename, "r+") do |file|
+ contents = file.read
+ match_results = contents.match(/#ifndef (\S+)\n#define \1/s)
+ if match_results
+ current_guard = match_results[1]
+ new_guard = File.basename(filename).sub('.', '_')
+ new_guard = options[:prefix] + '_' + new_guard if options[:prefix]
+ contents.gsub!(/#{current_guard}\b/, new_guard)
+ else
+ puts "Ignoring #{filename}, failed to find existing header guards."
+ end
+ tmp_filename = filename + ".tmp"
+ File.open(tmp_filename, "w+") do |new_file|
+ new_file.write(contents)
+ end
+ File.rename tmp_filename, filename
+ end
+end
diff --git a/WebKitTools/Scripts/commit-log-editor b/WebKitTools/Scripts/commit-log-editor
new file mode 100755
index 0000000..939b28c
--- /dev/null
+++ b/WebKitTools/Scripts/commit-log-editor
@@ -0,0 +1,189 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to put change log comments in as default check-in comment.
+
+use strict;
+use File::Basename;
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use VCSUtils;
+use webkitdirs;
+
+my $log = $ARGV[0];
+
+my $baseDir = baseProductDir();
+
+my $editor = $ENV{SVN_LOG_EDITOR};
+if (!$editor) {
+ $editor = $ENV{CVS_LOG_EDITOR};
+}
+if (!$editor) {
+ my $builtEditorApplication = "$baseDir/Release/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
+ $editor = $builtEditorApplication if -x $builtEditorApplication;
+}
+if (!$editor) {
+ my $builtEditorApplication = "$baseDir/Debug/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
+ $editor = $builtEditorApplication if -x $builtEditorApplication;
+}
+if (!$editor) {
+ my $installedEditorApplication = "$ENV{HOME}/Applications/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
+ $editor = $installedEditorApplication if -x $installedEditorApplication;
+}
+if (!$editor) {
+ $editor = $ENV{EDITOR} || "/usr/bin/vi";
+}
+
+my $inChangesToBeCommitted = !isGit();
+my @changeLogs = ();
+my $logContents = "";
+my $existingLog = 0;
+open LOG, $log or die;
+while (<LOG>) {
+ if (isGit()) {
+ if (/^# Changes to be committed:$/) {
+ $inChangesToBeCommitted = 1;
+ } elsif ($inChangesToBeCommitted && /^# \S/) {
+ $inChangesToBeCommitted = 0;
+ }
+ }
+
+ $logContents .= $_;
+ $existingLog = isGit() && !(/^#/ || /^\s*$/) unless $existingLog;
+
+ push @changeLogs, makeFilePathRelative($1) if $inChangesToBeCommitted && (/^M....(.*ChangeLog)$/ || /^#\tmodified: (.*ChangeLog)/) && !/-ChangeLog/;
+}
+close LOG;
+
+# Don't change anything if there's already a log message
+# (as can happen with git-commit --amend)
+exec $editor, @ARGV if $existingLog;
+
+my $topLevel = topLevelSourceDirectory();
+
+my %changeLogSort;
+my %changeLogContents;
+for my $changeLog (@changeLogs) {
+ open CHANGELOG, $changeLog or die "Can't open $changeLog";
+ my $contents = "";
+ my $blankLines = "";
+ while (<CHANGELOG>) {
+ if (/^\S/) {
+ last if $contents;
+ }
+ if (/\S/) {
+ $contents .= $blankLines if $contents;
+ $blankLines = "";
+ $contents .= $_;
+ } else {
+ $blankLines .= $_;
+ }
+ }
+ close CHANGELOG;
+
+ $changeLog = File::Spec->abs2rel(File::Spec->rel2abs($changeLog), $topLevel);
+
+ my $label = dirname($changeLog);
+ $label = "top level" unless length $label;
+
+ my $sortKey = lc $label;
+ if ($label eq "top level") {
+ $sortKey = "";
+ } elsif ($label eq "Tools") {
+ $sortKey = "-, just after top level";
+ } elsif ($label eq "WebBrowser") {
+ $sortKey = lc "WebKit, WebBrowser after";
+ } elsif ($label eq "WebCore") {
+ $sortKey = lc "WebFoundation, WebCore after";
+ } elsif ($label eq "LayoutTests") {
+ $sortKey = lc "~, LayoutTests last";
+ }
+
+ $changeLogSort{$sortKey} = $label;
+ $changeLogContents{$label} = $contents;
+}
+
+my $first = 1;
+open NEWLOG, ">$log.edit" or die;
+for my $sortKey (sort keys %changeLogSort) {
+ my $label = $changeLogSort{$sortKey};
+ if (keys %changeLogSort > 1) {
+ print NEWLOG "\n" if !$first;
+ $first = 0;
+ print NEWLOG "$label:\n\n";
+ }
+ print NEWLOG $changeLogContents{$label};
+}
+print NEWLOG $logContents;
+close NEWLOG;
+
+system $editor, "$log.edit";
+
+open NEWLOG, "$log.edit" or exit;
+my $foundComment = 0;
+while (<NEWLOG>) {
+ $foundComment = 1 if (/\S/ && !/^CVS:/);
+}
+close NEWLOG;
+
+if ($foundComment) {
+ open NEWLOG, "$log.edit" or die;
+ open LOG, ">$log" or die;
+ while (<NEWLOG>) {
+ print LOG;
+ }
+ close LOG;
+ close NEWLOG;
+}
+
+unlink "$log.edit";
+
+sub topLevelSourceDirectory
+{
+ if (isGit()) {
+ chomp(my $gitDir = `git rev-parse --git-dir`);
+ return dirname($gitDir);
+ } elsif (isSVN()) {
+ open(INFO, "-|", qw(svn info)) or die;
+ my ($root, $url);
+ while (my $line = <INFO>) {
+ if ($line =~ /^Repository Root: (.*)$/) {
+ $root = $1;
+ } elsif ($line =~ /^URL: (.*)$/) {
+ $url = $1;
+ }
+ }
+ close(INFO);
+
+ my $path = $url;
+ $path =~ s/^\Q$root\E//;
+ $path =~ s/^\/?(branches\/[^\/]*|trunk)\/?//;
+ return File::Spec->rel2abs(File::Spec->catdir(map { ".." } File::Spec->splitdir($path)));
+ }
+}
diff --git a/WebKitTools/Scripts/compare-timing-files b/WebKitTools/Scripts/compare-timing-files
new file mode 100755
index 0000000..11b470b
--- /dev/null
+++ b/WebKitTools/Scripts/compare-timing-files
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script takes two files that are lists of timings and compares them.
+
+use warnings;
+use strict;
+use Getopt::Long;
+
+my $usage = "compare-timing-files [-c|--count results] oldFile newFile";
+
+my $count = 1;
+GetOptions("c|count=i" => \$count);
+
+my ($file1, $file2) = @ARGV;
+die "$usage\n" unless ($file1 && $file2 && @ARGV == 2);
+
+my ($oldAverage, $oldRange, $oldRangePercent) = parseResults($file1);
+my ($newAverage, $newRange, $newRangePercent) = parseResults($file2);
+
+print "\n===== $file1 =====\n";
+if ($count == 1) {
+ print("fastest run: $oldAverage\n");
+} else {
+ print("average of fastest $count runs: $oldAverage\n");
+ printf("range of fastest $count runs: %.2f%% (%d)\n", $oldRangePercent, $oldRange);
+}
+
+print "\n===== $file2 =====\n";
+if ($count == 1) {
+ print("fastest run: $newAverage\n");
+} else {
+ print("average of fastest $count runs: $newAverage\n");
+ printf("range of fastest $count runs: %.2f%% (%d)\n", $newRangePercent, $newRange);
+}
+
+my $gainOrLoss = $newAverage <= $oldAverage ? "GAIN" : "LOSS";
+my $difference = abs($newAverage - $oldAverage);
+my $differencePercent = $difference / $oldAverage * 100;
+printf("\nperformance %s of %.2f%% (%.1f / %.1f)\n", $gainOrLoss, $differencePercent, $difference, $oldAverage);
+print "\n";
+
+sub parseResults
+{
+ my ($file) = @_;
+
+ open(FILE, $file) or die "Couldn't open file: $file";
+ my @results = <FILE>;
+ close(FILE);
+
+ @results = sort(@results);
+ my $total = 0;
+ for (my $i = 0; $i < $count; $i++) {
+ $results[$i] =~ s/\D*//; # cut out non-digits
+ $total += $results[$i];
+ }
+ my $average = $total / $count;
+ my $range = $results[$count - 1] - $results[0];
+ my $rangePercent = $range / $results[$count - 1] * 100;
+
+ return ($average, $range, $rangePercent);
+}
+
diff --git a/WebKitTools/Scripts/create-exports b/WebKitTools/Scripts/create-exports
new file mode 100755
index 0000000..c645d55
--- /dev/null
+++ b/WebKitTools/Scripts/create-exports
@@ -0,0 +1,5 @@
+#!/usr/bin/perl -w
+
+while (<>) {
+ print "$1\n" if /^\s*\"(.+)\", referenced from:$/;
+}
diff --git a/WebKitTools/Scripts/debug-safari b/WebKitTools/Scripts/debug-safari
new file mode 100755
index 0000000..52e97fe
--- /dev/null
+++ b/WebKitTools/Scripts/debug-safari
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to run Safari in the platform's debugger for the WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+exit exitStatus(runSafari(1));
diff --git a/WebKitTools/Scripts/detect-mismatched-virtual-const b/WebKitTools/Scripts/detect-mismatched-virtual-const
new file mode 100755
index 0000000..b345cb2
--- /dev/null
+++ b/WebKitTools/Scripts/detect-mismatched-virtual-const
@@ -0,0 +1,167 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# This script attempts to find instances of a problem where the signatures
+# of virtual methods fail to match because one is defined 'const', and another
+# is not. For example:
+# virtual void Base::doStuff() const;
+# virtual void Derived::doStuff();
+#
+# The lack of 'const' on the derived class gives it a different signature, and
+# it will therefore not be called when doStuff() is called on a derived object
+# via a base class pointer.
+#
+# Limitations of this script:
+# * It only works on things in the WebCore namespace
+# * Not all templatized methods may be found correctly
+# * It doesn't know anything about inheritance, or if methods are actually virtual
+# * It has lots of false positives (should add a whitelist for known-good signatures,
+# and specific methods)
+# * It's rather slow
+#
+# Added by Simon Fraser <simon.fraser@apple.com>
+#
+# Run the script like this:
+# WebKitTools/Scripts/detect-mismatched-virtual-const WebKitBuild/Debug/WebCore.framework/WebCore
+#
+# Output consists of a series of warnings like this:
+#
+# Both const and non-const versions of bgColor():
+# HTMLDocument::bgColor()
+# HTMLBodyElement::bgColor() const
+# HTMLTableElement::bgColor() const
+# HTMLTableRowElement::bgColor() const
+# HTMLTableCellElement::bgColor() const
+#
+
+use strict;
+no warnings qw /syntax/;
+
+
+my $file = $ARGV[0];
+
+print "Looking for unmatched const methods in $file\n";
+
+if (!open NM, "(nm '$file' | c++filt | sed 's/^/STDOUT:/') 2>&1 |") {
+ die "Could not open $file\n";
+}
+
+my $nestedParens;
+ $nestedParens = qr /
+ [(]
+ [^()]*
+ (?:
+ (??{ $nestedParens })
+ [^()]*
+ )*
+ [)]/x;
+
+my $nestedAngleBrackets;
+ $nestedAngleBrackets = qr /
+ [<]
+ [^<>]*
+ (?:
+ (??{ $nestedAngleBrackets })
+ [^<>]*
+ )*
+ [>]/x;
+
+my $bal;
+ $bal = qr /([^:]+
+ (??{ $nestedAngleBrackets })?
+ (??{ $nestedParens }))
+ ([^()]*)$/x;
+
+my %signature_map = ();
+
+while (<NM>) {
+ my $line = $_;
+ chomp($line);
+ if ($line =~ m/ [tT] WebCore::(.+)$/) {
+ my $method = $1;
+
+ if ($method =~ /$bal/) {
+ my $signature = $1;
+ my $const = $2 eq " const";
+
+ my $class = substr($method, 0, length($method) - length($signature) - ($const ? 6 : 0));
+
+# print "line: $line\nclass: $class\nmethod: $method\nsignature: $signature\nconst: $const\n\n";
+
+ my %method_info = (
+ 'class' => $class,
+ 'const' => $const,
+ 'method' => $method,
+ );
+
+ push @{$signature_map{$signature}}, \%method_info;
+ } else {
+ print "unmatched line $method\n\n"
+ }
+ }
+}
+close NM;
+
+my $sig;
+for $sig (keys %signature_map) {
+ #print "\n$sig\n";
+
+ my @entries = @{$signature_map{$sig}};
+# print "$#entries\n";
+
+ my $num_const = 0;
+ my $num_not_const = 0;
+ my $i;
+ for $i (0 .. $#entries) {
+ my $entry = @entries[$i];
+
+ my $class = $entry->{'class'};
+ my $const = $entry->{'const'};
+
+ if ($const) {
+ $num_const++;
+ } else {
+ $num_not_const++;
+ }
+ }
+
+ if ($#entries > 1 && $num_const > 0 && $num_not_const > 0) {
+ print "Both const and non-const versions of $sig:\n";
+
+ for $i (0 .. $#entries) {
+ my $entry = @entries[$i];
+ my $method = $entry->{'method'};
+ print "\t$method\n";
+ }
+
+ }
+}
+
+
+
diff --git a/WebKitTools/Scripts/do-file-rename b/WebKitTools/Scripts/do-file-rename
new file mode 100755
index 0000000..ac5099e
--- /dev/null
+++ b/WebKitTools/Scripts/do-file-rename
@@ -0,0 +1,115 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to do file renaming.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+use File::Find;
+
+setConfiguration();
+chdirWebKit();
+
+my %words;
+
+# find all files we want to process
+
+my @paths;
+find(\&wanted, "JavaScriptCore");
+find(\&wanted, "JavaScriptGlue");
+find(\&wanted, "WebCore");
+find(\&wanted, "WebKit");
+
+sub wanted
+{
+ my $file = $_;
+
+ if ($file eq "icu") {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ if ($file =~ /^\../) {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ return if $file =~ /^ChangeLog/;
+ return if -d $file;
+
+ push @paths, $File::Find::name;
+}
+
+my %renames = (
+);
+
+my %renamesContemplatedForTheFuture = (
+);
+
+# rename files
+
+my %newFile;
+for my $file (sort @paths) {
+ my $f = $file;
+ $f = "$1$renames{$2}" if $f =~ /^(.*\/)(\w+\.\w+)$/ && $renames{$2};
+ $newFile{$file} = $f if $f ne $file;
+}
+
+for my $file (sort @paths) {
+ if ($newFile{$file}) {
+ my $newFile = $newFile{$file};
+ print "Renaming $file to $newFile\n";
+ system "svn move $file $newFile";
+ }
+}
+
+# change all file contents
+
+for my $file (sort @paths) {
+ $file = $newFile{$file} if $newFile{$file};
+ my $contents;
+ {
+ local $/;
+ open FILE, $file or die;
+ $contents = <FILE>;
+ close FILE;
+ }
+ my $newContents = $contents;
+
+ for my $from (keys %renames) {
+ $newContents =~ s/\b\Q$from\E(?!\w)/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting
+ }
+
+ if ($newContents ne $contents) {
+ open FILE, ">", $file or die;
+ print FILE $newContents;
+ close FILE;
+ }
+}
diff --git a/WebKitTools/Scripts/do-webcore-rename b/WebKitTools/Scripts/do-webcore-rename
new file mode 100755
index 0000000..6a473df
--- /dev/null
+++ b/WebKitTools/Scripts/do-webcore-rename
@@ -0,0 +1,184 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to do a rename in JavaScriptCore, WebCore, and WebKit.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+use File::Find;
+
+setConfiguration();
+chdirWebKit();
+
+my %words;
+
+# find all files we want to process
+
+my @paths;
+find(\&wanted, "JavaScriptCore");
+find(\&wanted, "JavaScriptGlue");
+find(\&wanted, "WebCore");
+find(\&wanted, "WebKit");
+
+sub wanted
+{
+ my $file = $_;
+
+ if ($file eq "icu") {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ if ($file =~ /^\../) {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ return if $file =~ /^ChangeLog/;
+ return if -d $file;
+
+ push @paths, $File::Find::name;
+}
+
+my %renames = (
+ "JSUnprotectedEventListener" => "JSEventListener",
+ "findJSUnprotectedEventListener" => "findJSEventListener",
+ "findOrCreateJSUnprotectedEventListener" => "findOrCreateJSEventListener",
+ "UnprotectedListenersMap" => "JSListenersMap",
+ "jsUnprotectedEventListeners" => "jsEventListeners",
+ "jsUnprotectedInlineEventListeners" => "jsInlineEventListeners",
+);
+
+my %renamesContemplatedForTheFuture = (
+ "DOMObject" => "JSDOMObject",
+
+ "runtimeObjectGetter" => "pluginElementGetter",
+ "runtimeObjectPropertyGetter" => "pluginElementPropertyGetter",
+ "runtimeObjectCustomGetOwnPropertySlot" => "pluginElementCustomGetOwnPropertySlot",
+ "runtimeObjectCustomPut" => "pluginElementCustomPut",
+ "runtimeObjectImplementsCall" => "pluginElementImplementsCall",
+ "runtimeObjectCallAsFunction" => "pluginElementCallAsFunction",
+
+ "CLONE_CONTENTS" => "Clone",
+ "DELETE_CONTENTS" => "Delete",
+ "EXTRACT_CONTENTS" => "Extract",
+
+ "DateInstance" => "JSDate",
+ "ErrorInstance" => "JSError",
+
+ "KURL" => "URL",
+ "KURLCFNet" => "URLCF",
+ "KURLHash" => "URLHash",
+ "KURLMac" => "URLMac",
+ "KURL_h" => "URL_h",
+
+ "ThreadSafeShared" => "ThreadSafeRefCounted",
+ "TreeShared" => "TreeRefCounted",
+
+ "StringImpl" => "SharedString",
+
+ "RenderView" => "RenderViewport",
+
+ "ObjcFallbackObjectImp" => "ObjCFallbackObject",
+ "RuntimeObjectImp" => "ForeignObject",
+
+ "runtime_array" => "BridgedArray",
+ "runtime_method" => "BridgedFunction",
+ "runtime_object" => "BridgedObject",
+ "objc_runtime" => "ObjCBridge",
+
+ "equalIgnoringCase" => "equalFoldingCase",
+
+ "FTPDirectoryTokenizer" => "FTPDirectoryDocumentBuilder",
+ "HTMLTokenizer" => "HTMLDocumentBuilder",
+ "ImageTokenizer" => "ImageDocumentBuilder",
+ "PluginTokenizer" => "PluginDocumentBuilder",
+ "TextTokenizer" => "TextDocumentBuilder",
+ "Tokenizer" => "DocumentBuilder",
+ "Tokenizer_h" => "DocumentBuilder_h",
+ "XMLTokenizer" => "XMLDocumentBuilder",
+ "isHTMLTokenizer" => "isHTMLDocumentBuilder",
+ "m_tokenizer" => "m_builder",
+ "createTokenizer" => "createBuilder",
+ "tokenizerProcessedData" => "documentBuilderProcessedData",
+
+ "WTF_UNICODE_H" => "Unicode_h",
+ "WTF_UNICODE_ICU_H" => "UnicodeICU_h",
+ "WTF_UNICODE_QT4_H" => "UnicodeQt4_h",
+ "UnicodeIcu" => "UnicodeICU",
+
+ "m_invertibleCTM" => "m_transformIsInvertible",
+
+ "JSValuePtr" => "JSValue",
+ "ProtectedJSValuePtr" => "ProtectedJSValue",
+);
+
+# rename files
+
+my %newFile;
+for my $file (sort @paths) {
+ my $f = $file;
+ $f = "$1$renames{$2}$3" if $f =~ /^(.*\/)(\w+)(\.\w+)$/ && $renames{$2};
+ if ($f ne $file) {
+ $newFile{$file} = $f;
+ }
+}
+
+for my $file (sort @paths) {
+ if ($newFile{$file}) {
+ my $newFile = $newFile{$file};
+ print "Renaming $file to $newFile\n";
+ system "svn move $file $newFile";
+ }
+}
+
+# change all file contents
+
+for my $file (sort @paths) {
+ $file = $newFile{$file} if $newFile{$file};
+ my $contents;
+ {
+ local $/;
+ open FILE, $file or die;
+ $contents = <FILE>;
+ close FILE;
+ }
+ my $newContents = $contents;
+
+ for my $from (keys %renames) {
+ $newContents =~ s/\b$from(?!["\w])/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting
+ }
+
+ if ($newContents ne $contents) {
+ open FILE, ">", $file or die;
+ print FILE $newContents;
+ close FILE;
+ }
+}
diff --git a/WebKitTools/Scripts/extract-localizable-strings b/WebKitTools/Scripts/extract-localizable-strings
new file mode 100755
index 0000000..420624b
--- /dev/null
+++ b/WebKitTools/Scripts/extract-localizable-strings
@@ -0,0 +1,351 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script is like the genstrings tool (minus most of the options) with these differences.
+#
+# 1) It uses the names UI_STRING and UI_STRING_WITH_KEY for the macros, rather than the macros
+# from NSBundle.h, and doesn't support tables (although they would be easy to add).
+# 2) It supports UTF-8 in key strings (and hence uses "" strings rather than @"" strings;
+# @"" strings only reliably support ASCII since they are decoded based on the system encoding
+# at runtime, so give different results on US and Japanese systems for example).
+# 3) It looks for strings that are not marked for localization, using both macro names that are
+# known to be used for debugging in Intrigue source code and an exceptions file.
+# 4) It finds the files to work on rather than taking them as parameters, and also uses a
+# hardcoded location for both the output file and the exceptions file.
+# It would have been nice to use the project to find the source files, but it's too hard to
+# locate source files after parsing a .pbxproj file.
+
+# The exceptions file has a list of strings in quotes, filenames, and filename/string pairs separated by :.
+
+use strict;
+
+my %isDebugMacro = ( ASSERT_WITH_MESSAGE => 1, LOG_ERROR => 1, ERROR => 1, NSURL_ERROR => 1, FATAL => 1, LOG => 1, LOG_WARNING => 1, UI_STRING_LOCALIZE_LATER => 1, LPCTSTR_UI_STRING_LOCALIZE_LATER => 1, UNLOCALIZED_STRING => 1, UNLOCALIZED_LPCTSTR => 1, dprintf => 1, NSException => 1, NSLog => 1, printf => 1 );
+
+@ARGV >= 1 or die "Usage: extract-localizable-strings <exceptions file> [ directory... ]\nDid you mean to run extract-webkit-localizable-strings instead?\n";
+
+my $exceptionsFile = shift @ARGV;
+-f $exceptionsFile or die "Couldn't find exceptions file $exceptionsFile\n";
+
+my $fileToUpdate = shift @ARGV;
+-f $fileToUpdate or die "Couldn't find file to update $fileToUpdate\n";
+
+my @directories = ();
+my @directoriesToSkip = ();
+if (@ARGV < 1) {
+ push(@directories, ".");
+} else {
+ for my $dir (@ARGV) {
+ if ($dir =~ /^-(.*)$/) {
+ push @directoriesToSkip, $1;
+ } else {
+ push @directories, $dir;
+ }
+ }
+}
+
+my $sawError = 0;
+
+my $localizedCount = 0;
+my $keyCollisionCount = 0;
+my $notLocalizedCount = 0;
+my $NSLocalizeCount = 0;
+
+my %exception;
+my %usedException;
+
+if (open EXCEPTIONS, $exceptionsFile) {
+ while (<EXCEPTIONS>) {
+ chomp;
+ if (/^"([^\\"]|\\.)*"$/ or /^[-_\/\w.]+.(h|m|mm|c|cpp)$/ or /^[-_\/\w.]+.(h|m|mm|c|cpp):"([^\\"]|\\.)*"$/) {
+ if ($exception{$_}) {
+ print "$exceptionsFile:$.:exception for $_ appears twice\n";
+ print "$exceptionsFile:$exception{$_}:first appearance\n";
+ } else {
+ $exception{$_} = $.;
+ }
+ } else {
+ print "$exceptionsFile:$.:syntax error\n";
+ }
+ }
+ close EXCEPTIONS;
+}
+
+my $quotedDirectoriesString = '"' . join('" "', @directories) . '"';
+for my $dir (@directoriesToSkip) {
+ $quotedDirectoriesString .= ' -path "' . $dir . '" -prune';
+}
+
+my @files = ( split "\n", `find $quotedDirectoriesString -name "*.h" -o -name "*.m" -o -name "*.mm" -o -name "*.c" -o -name "*.cpp"` );
+
+for my $file (sort @files) {
+ next if $file =~ /\/WebLocalizableStrings\.h$/;
+ next if $file =~ /\/icu\//;
+
+ $file =~ s-^./--;
+
+ open SOURCE, $file or die "can't open $file\n";
+
+ my $inComment = 0;
+
+ my $expected = "";
+ my $macroLine;
+ my $macro;
+ my $UIString;
+ my $key;
+ my $comment;
+
+ my $string;
+ my $stringLine;
+ my $nestingLevel;
+
+ my $previousToken = "";
+
+ while (<SOURCE>) {
+ chomp;
+
+ # Handle continued multi-line comment.
+ if ($inComment) {
+ next unless s-.*\*/--;
+ $inComment = 0;
+ }
+
+ # Handle all the tokens in the line.
+ while (s-^\s*([#\w]+|/\*|//|[^#\w/'"()\[\],]+|.)--) {
+ my $token = $1;
+
+ if ($token eq "\"") {
+ if ($expected and $expected ne "a quoted string") {
+ print "$file:$.:ERROR:found a quoted string but expected $expected\n";
+ $sawError = 1;
+ $expected = "";
+ }
+ if (s-^(([^\\$token]|\\.)*?)$token--) {
+ if (!defined $string) {
+ $stringLine = $.;
+ $string = $1;
+ } else {
+ $string .= $1;
+ }
+ } else {
+ print "$file:$.:ERROR:mismatched quotes\n";
+ $sawError = 1;
+ $_ = "";
+ }
+ next;
+ }
+
+ if (defined $string) {
+handleString:
+ if ($expected) {
+ if (!defined $UIString) {
+ # FIXME: Validate UTF-8 here?
+ $UIString = $string;
+ $expected = ",";
+ } elsif (($macro =~ /UI_STRING_KEY$/) and !defined $key) {
+ # FIXME: Validate UTF-8 here?
+ $key = $string;
+ $expected = ",";
+ } elsif (!defined $comment) {
+ # FIXME: Validate UTF-8 here?
+ $comment = $string;
+ $expected = ")";
+ }
+ } else {
+ if (defined $nestingLevel) {
+ # In a debug macro, no need to localize.
+ } elsif ($previousToken eq "#include" or $previousToken eq "#import") {
+ # File name, no need to localize.
+ } elsif ($previousToken eq "extern" and $string eq "C") {
+ # extern "C", no need to localize.
+ } elsif ($string eq "") {
+ # Empty string can sometimes be localized, but we need not complain if not.
+ } elsif ($exception{$file}) {
+ $usedException{$file} = 1;
+ } elsif ($exception{"\"$string\""}) {
+ $usedException{"\"$string\""} = 1;
+ } elsif ($exception{"$file:\"$string\""}) {
+ $usedException{"$file:\"$string\""} = 1;
+ } else {
+ print "$file:$stringLine:\"$string\" is not marked for localization\n";
+ $notLocalizedCount++;
+ }
+ }
+ $string = undef;
+ last if !defined $token;
+ }
+
+ $previousToken = $token;
+
+ if ($token =~ /^NSLocalized/ && $token !~ /NSLocalizedDescriptionKey/ && $token !~ /NSLocalizedStringFromTableInBundle/) {
+ print "$file:$.:ERROR:found a use of an NSLocalized macro; not supported\n";
+ $nestingLevel = 0 if !defined $nestingLevel;
+ $sawError = 1;
+ $NSLocalizeCount++;
+ } elsif ($token eq "/*") {
+ if (!s-^.*?\*/--) {
+ $_ = ""; # If the comment doesn't end, discard the result of the line and set flag
+ $inComment = 1;
+ }
+ } elsif ($token eq "//") {
+ $_ = ""; # Discard the rest of the line
+ } elsif ($token eq "'") {
+ if (!s-([^\\]|\\.)'--) { #' <-- that single quote makes the Project Builder editor less confused
+ print "$file:$.:ERROR:mismatched single quote\n";
+ $sawError = 1;
+ $_ = "";
+ }
+ } else {
+ if ($expected and $expected ne $token) {
+ print "$file:$.:ERROR:found $token but expected $expected\n";
+ $sawError = 1;
+ $expected = "";
+ }
+ if ($token =~ /UI_STRING(_KEY)?$/) {
+ $expected = "(";
+ $macro = $token;
+ $UIString = undef;
+ $key = undef;
+ $comment = undef;
+ $macroLine = $.;
+ } elsif ($token eq "(" or $token eq "[") {
+ ++$nestingLevel if defined $nestingLevel;
+ $expected = "a quoted string" if $expected;
+ } elsif ($token eq ",") {
+ $expected = "a quoted string" if $expected;
+ } elsif ($token eq ")" or $token eq "]") {
+ $nestingLevel = undef if defined $nestingLevel && !--$nestingLevel;
+ if ($expected) {
+ $key = $UIString if !defined $key;
+ HandleUIString($UIString, $key, $comment, $file, $macroLine);
+ $macro = "";
+ $expected = "";
+ $localizedCount++;
+ }
+ } elsif ($isDebugMacro{$token}) {
+ $nestingLevel = 0 if !defined $nestingLevel;
+ }
+ }
+ }
+
+ }
+
+ goto handleString if defined $string;
+
+ if ($expected) {
+ print "$file:ERROR:reached end of file but expected $expected\n";
+ $sawError = 1;
+ }
+
+ close SOURCE;
+}
+
+my %stringByKey;
+my %commentByKey;
+my %fileByKey;
+my %lineByKey;
+
+sub HandleUIString
+{
+ my ($string, $key, $comment, $file, $line) = @_;
+
+ my $bad = 0;
+ if (grep { $_ == 0xFFFD } unpack "U*", $string) {
+ print "$file:$line:ERROR:string for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
+ $bad = 1;
+ }
+ if ($string ne $key && grep { $_ == 0xFFFD } unpack "U*", $key) {
+ print "$file:$line:ERROR:key has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
+ $bad = 1;
+ }
+ if (grep { $_ == 0xFFFD } unpack "U*", $comment) {
+ print "$file:$line:ERROR:comment for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
+ $bad = 1;
+ }
+ if ($bad) {
+ $sawError = 1;
+ return;
+ }
+
+ if ($stringByKey{$key} && $stringByKey{$key} ne $string) {
+ print "$file:$line:encountered the same key, \"$key\", twice, with different strings\n";
+ print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
+ $keyCollisionCount++;
+ return;
+ }
+ if ($commentByKey{$key} && $commentByKey{$key} ne $comment) {
+ print "$file:$line:encountered the same key, \"$key\", twice, with different comments\n";
+ print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
+ $keyCollisionCount++;
+ return;
+ }
+
+ $fileByKey{$key} = $file;
+ $lineByKey{$key} = $line;
+ $stringByKey{$key} = $string;
+ $commentByKey{$key} = $comment;
+}
+
+print "\n" if $sawError || $notLocalizedCount || $NSLocalizeCount;
+
+my @unusedExceptions = sort grep { !$usedException{$_} } keys %exception;
+if (@unusedExceptions) {
+ for my $unused (@unusedExceptions) {
+ print "$exceptionsFile:$exception{$unused}:exception $unused not used\n";
+ }
+ print "\n";
+}
+
+print "$localizedCount localizable strings\n" if $localizedCount;
+print "$keyCollisionCount key collisions\n" if $keyCollisionCount;
+print "$notLocalizedCount strings not marked for localization\n" if $notLocalizedCount;
+print "$NSLocalizeCount uses of NSLocalize\n" if $NSLocalizeCount;
+print scalar(@unusedExceptions), " unused exceptions\n" if @unusedExceptions;
+
+if ($sawError) {
+ print "\nErrors encountered. Exiting without writing to $fileToUpdate.\n";
+ exit 1;
+}
+
+my $localizedStrings = "";
+
+for my $key (sort keys %commentByKey) {
+ $localizedStrings .= "/* $commentByKey{$key} */\n\"$key\" = \"$stringByKey{$key}\";\n\n";
+}
+
+# Write out the strings file in UTF-16 with a BOM.
+utf8::decode($localizedStrings) if $^V ge chr(5).chr(8);
+my $output = pack "n*", (0xFEFF, unpack "U*", $localizedStrings);
+
+if (-e "$fileToUpdate") {
+ open STRINGS, ">", "$fileToUpdate" or die;
+ print STRINGS $output;
+ close STRINGS;
+} else {
+ print "$fileToUpdate does not exist\n";
+ exit 1;
+}
diff --git a/WebKitTools/Scripts/find-extra-includes b/WebKitTools/Scripts/find-extra-includes
new file mode 100755
index 0000000..4a847ed
--- /dev/null
+++ b/WebKitTools/Scripts/find-extra-includes
@@ -0,0 +1,102 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# "find-extra-includes" script for WebKit Open Source Project
+
+use strict;
+use File::Find;
+
+find(\&wanted, @ARGV ? @ARGV : ".");
+
+my %paths;
+my %includes;
+
+sub wanted
+{
+ my $file = $_;
+
+ if ($file eq "icu") {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ if ($file !~ /^\./ && $file =~ /\.(h|cpp|c|mm|m)$/) {
+ $paths{$file} = $File::Find::name;
+ open FILE, $file or die;
+ while (<FILE>) {
+ if (m-^\s*#\s*(include|import)\s+["<]((\S+/)*)(\S+)[">]-) {
+ my $include = ($2 eq "sys/" ? $2 : "") . $4;
+ $includes{$file}{$include}++;
+ }
+ }
+ close FILE;
+ }
+}
+
+my %totalIncludes;
+
+sub fillOut
+{
+ my ($file) = @_;
+
+ return if defined $totalIncludes{$file};
+
+ for my $include (keys %{ $includes{$file} }) {
+ $totalIncludes{$file}{$include} = 1;
+ fillOut($include);
+ for my $i (keys %{ $totalIncludes{$include} }) {
+ $totalIncludes{$file}{$i} = 1;
+ }
+ }
+}
+
+sub check
+{
+ my ($file) = @_;
+
+ for my $include (keys %{ $includes{$file} }) {
+ fillOut($include);
+ }
+ for my $i1 (sort keys %{ $includes{$file} }) {
+ for my $i2 (keys %{ $includes{$file} }) {
+ next if $i1 eq $i2;
+ if ($totalIncludes{$i2}{$i1}) {
+ my $b1 = $i1;
+ my $b2 = $file;
+ $b1 =~ s/\..+$//;
+ $b2 =~ s/\..+$//;
+ print "$paths{$file} does not need to include $i1, because $i2 does\n" if $b1 ne $b2;
+ last;
+ }
+ }
+ }
+}
+
+for my $file (sort keys %includes) {
+ check($file);
+}
diff --git a/WebKitTools/Scripts/find-included-framework-headers b/WebKitTools/Scripts/find-included-framework-headers
new file mode 100755
index 0000000..3e7aaf6
--- /dev/null
+++ b/WebKitTools/Scripts/find-included-framework-headers
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+FILE_EXTENSIONS_TO_SEARCH="cpp h m mm"
+
+for framework in $*; do
+ echo -e "\n$framework\n=================="
+ for ext in ${FILE_EXTENSIONS_TO_SEARCH}; do
+ find . -name "*.$ext" -exec grep $framework {} ';' | grep '\(include\|import\)' | sed -e 's|.*/\(.*\.h\).*|\1|'
+ done | sort | uniq
+done
diff --git a/WebKitTools/Scripts/gdb-safari b/WebKitTools/Scripts/gdb-safari
new file mode 100755
index 0000000..9776212
--- /dev/null
+++ b/WebKitTools/Scripts/gdb-safari
@@ -0,0 +1,53 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Simplified "run under gdb" script for WebKit Open Source Project.
+
+use strict;
+use File::Temp qw/:mktemp/;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+my $productDir = productDir();
+my $safariPath = safariPath();
+
+# Check to see that gdb is in the usual place.
+my $gdbPath = "/usr/bin/gdb";
+die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath;
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = 'YES';
+
+print "Starting Safari under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+my @architectureFlags = ("-arch", architecture()) if !isTiger();
+exec $gdbPath, @architectureFlags, $safariPath or die;
diff --git a/WebKitTools/Scripts/generate-coverage-data b/WebKitTools/Scripts/generate-coverage-data
new file mode 100755
index 0000000..7ed36aa
--- /dev/null
+++ b/WebKitTools/Scripts/generate-coverage-data
@@ -0,0 +1,71 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2007 Holger Hans Peter Freyther. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Simple script to build, run and visualize coverage information
+
+use strict;
+use File::Basename;
+use File::Spec;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# Generate a name for our results
+my $svnVersion = determineCurrentSVNRevision();
+my @timeData = localtime(time);
+my $resultName = $svnVersion . "-" . join('_', @timeData);
+my @otherOptions = ();
+
+# Move to the source directory
+# Delete old gcov files
+# Compile WebKit and run the tests
+# Generate the coverage graph...
+# Upload
+
+$ENV{'WEBKIT_COVERAGE_BUILD'} = 1;
+chdirWebKit();
+
+# Clean-up old files
+print "Cleaning up\n";
+system("if [ -d WebKitBuild ]; then find WebKitBuild -name '*.gcda' -delete; fi;") == 0 or die;
+
+
+print "Building and testing\n";
+system("WebKitTools/Scripts/build-webkit", "--coverage", @ARGV) == 0 or die;
+system "WebKitTools/Scripts/run-webkit-tests", "--no-launch-safari";
+system "WebKitTools/Scripts/run-javascriptcore-tests", "--coverage", @ARGV;
+
+# Collect the data and generate a report
+print "Collecting coverage data\n";
+system("WebKitTools/CodeCoverage/run-generate-coverage-data", $resultName, "WebKitBuild/Coverage") == 0 or die;
+system("WebKitTools/CodeCoverage/regenerate-coverage-display", "WebKitBuild/Coverage", "WebKitBuild/Coverage/html") == 0 or die;
+
+print "Done\n";
diff --git a/WebKitTools/Scripts/generate-qt-inspector-resource b/WebKitTools/Scripts/generate-qt-inspector-resource
new file mode 100755
index 0000000..a65da13
--- /dev/null
+++ b/WebKitTools/Scripts/generate-qt-inspector-resource
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2008 Holger Hans Peter Freyther
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Regenerate WebCore/inspector/front-end/WebKit.qrc from the content of WebCore/inspector/front-end/
+
+sub addFiles(@)
+{
+ my @files = @_;
+
+ foreach $file (@files) {
+ $file =~ s,WebCore/inspector/front-end/,,;
+ print WEBKIT_QRC " <file>".$file . "</file>\n";
+ }
+}
+
+# Setup
+open(WEBKIT_QRC, ">WebCore/inspector/front-end/WebKit.qrc") or die;
+print WEBKIT_QRC '<!DOCTYPE RCC><RCC version="1.0">'."\n";
+print WEBKIT_QRC '<qresource prefix="/webkit/inspector">'."\n";
+
+
+# Directory with html and js files and the images
+addFiles(<WebCore/inspector/front-end/*.{*html,js,css,svg}>);
+addFiles(<WebCore/inspector/front-end/Images/*>);
+
+print WEBKIT_QRC "</qresource>\n";
+print WEBKIT_QRC "</RCC>\n";
+close(WEBKIT_QRC);
diff --git a/WebKitTools/Scripts/make-js-test-wrappers b/WebKitTools/Scripts/make-js-test-wrappers
new file mode 100755
index 0000000..9ee8513
--- /dev/null
+++ b/WebKitTools/Scripts/make-js-test-wrappers
@@ -0,0 +1,165 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to generate HTML wrappers for JavaScript tests from templates
+
+use strict;
+
+use FindBin;
+use lib $FindBin::Bin;
+
+use File::Basename;
+use File::Find;
+use Getopt::Long;
+use webkitdirs;
+
+sub directoryFilter;
+sub findTemplateFiles(@);
+
+my $showHelp;
+
+my $result = GetOptions(
+ "help" => \$showHelp,
+);
+
+if (!$result || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] [path ...]\n";
+ exit 1;
+}
+
+setConfiguration();
+my $productDir = productDir();
+
+chdirWebKit();
+
+my @templates = findTemplateFiles(@ARGV);
+
+for my $tfile (@templates) {
+
+ my $tpath = $tfile;
+ $tpath =~ s:/resources/TEMPLATE.html$::;
+
+ print "${tpath}\n";
+
+ chdirWebKit();
+ chdir($tpath);
+
+ my @files;
+ my $fileFilter = sub {
+ push @files, $File::Find::name if substr($_, -3) eq ".js";
+ };
+ find({ preprocess => \&directoryFilter, wanted => $fileFilter }, "resources");
+
+ open TEMPLATE, "<resources/TEMPLATE.html";
+ my $template = do { local $/; <TEMPLATE> };
+ close TEMPLATE;
+
+ my $templateNegative = $template;
+ if (-e "resources/TEMPLATE-n.html") {
+ open TEMPLATE, "<resources/TEMPLATE-n.html";
+ $templateNegative = do { local $/; <TEMPLATE> };
+ close TEMPLATE;
+ }
+
+ for my $file (@files) {
+ next if $file =~ /js-test-.*\.js$/;
+ next if $file =~ /standalone-.*\.js$/;
+ next if $file =~ /SVGTestCase\.js/;
+ next if $file =~ /WMLTestCase\.js/;
+
+ next if $file =~ m:resources/bom-in-file-retains-correct-offset\.js$:; # has a custom template
+ next if $file =~ m:resources/NSResolver-exceptions\.js$:;
+ next if $file =~ m:resources/WindowProperties\.js$:;
+ next if $file =~ m:resources/altGlyph-dom\.js$:;
+ next if $file =~ m:resources/attr-case-sensitivity\.js$:;
+ next if $file =~ m:resources/codegen-temporaries-multiple-global-blocks-1\.js$:;
+ next if $file =~ m:resources/codegen-temporaries-multiple-global-blocks-2\.js$:;
+ next if $file =~ m:resources/constructors-cached-navigate\.js$:;
+ next if $file =~ m:resources/frame-loading-via-document-write\.js$:;
+ next if $file =~ m:resources/id-fastpath-almost-strict\.js$:;
+ next if $file =~ m:resources/id-fastpath-strict\.js$:;
+ next if $file =~ m:resources/intersectsNode\.js$:;
+ next if $file =~ m:resources/p-in-scope\.js$:;
+ next if $file =~ m:resources/script-element-gc\.js$:;
+ next if $file =~ m:resources/script-element-gc\.js$:;
+ next if $file =~ m:resources/script3\.js$:;
+ next if $file =~ m:resources/script4\.js$:;
+ next if $file =~ m:resources/script5\.js$:;
+ next if $file =~ m:resources/scripted-random\.js$:;
+ next if $file =~ m:resources/select-options-remove\.js$:;
+ next if $file =~ m:resources/shadow-offset\.js$:;
+ next if $file =~ m:resources/tabindex-focus-blur-all\.js$:;
+ next if $file =~ m:resources/use-instanceRoot-event-bubbling\.js$:;
+ next if $file =~ m:resources/use-instanceRoot-event-listeners\.js$:;
+ next if $file =~ m:resources/wrapper-identity-base\.js$:;
+ next if $file =~ m:resources/xhtml-scripts\.js$:;
+
+ my $html = $file;
+ $html =~ s:resources/(.*)\.js:$1.html:;
+ next if -f "$html-disabled";
+
+ system("grep -q 'successfullyParsed =' $file");
+ if ($? != 0) {
+ `echo "" >> "${file}"`;
+ `echo "var successfullyParsed = true;" >> "${file}"`;
+ }
+
+ print " ${html}\n";
+ open HTML, ">$html";
+ my $output = ($file =~ /-n\.js/) ? $templateNegative : $template;
+ $output =~ s:YOUR_JS_FILE_HERE:$file:;
+ print HTML $output;
+
+ close HTML;
+ }
+}
+
+exit 0;
+
+sub directoryFilter
+{
+ return () if basename($File::Find::dir) eq ".svn";
+ return @_;
+}
+
+sub findTemplateFiles(@) {
+ my @args = @_;
+ my @templateFiles;
+
+ push @args, "LayoutTests" if scalar(@args) == 0;
+
+ my @paths = map { -f $_ ? dirname($_) : $_ } @args;
+
+ my $fileFilter = sub {
+ push @templateFiles, $File::Find::name if $_ eq "TEMPLATE.html";
+ };
+
+ find({ preprocess => \&directoryFilter, wanted => $fileFilter }, @paths);
+
+ return @templateFiles;
+}
diff --git a/WebKitTools/Scripts/num-cpus b/WebKitTools/Scripts/num-cpus
new file mode 100755
index 0000000..c5f28a1
--- /dev/null
+++ b/WebKitTools/Scripts/num-cpus
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Win32API::Registry 0.21 qw( :ALL );
+
+
+my $key;
+my $i = 0;
+while (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\$i", 0, KEY_READ, $key)) {
+ $i++;
+ RegCloseKey($key);
+}
+
+print "$i\n";
diff --git a/WebKitTools/Scripts/parallelcl b/WebKitTools/Scripts/parallelcl
new file mode 100755
index 0000000..532079f
--- /dev/null
+++ b/WebKitTools/Scripts/parallelcl
@@ -0,0 +1,224 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Spec;
+use File::Temp;
+use POSIX;
+
+sub makeJob(\@$);
+sub forkAndCompileFiles(\@$);
+sub Exec($);
+sub waitForChild(\@);
+sub cleanup(\@);
+
+my $debug = 0;
+
+chomp(my $clexe = `cygpath -u '$ENV{'VS80COMNTOOLS'}/../../VC/bin/cl.exe'`);
+
+if ($debug) {
+ print STDERR "Received " . @ARGV . " arguments:\n";
+ foreach my $arg (@ARGV) {
+ print STDERR "$arg\n";
+ }
+}
+
+my $commandFile;
+foreach my $arg (@ARGV) {
+ if ($arg =~ /^[\/-](E|EP|P)$/) {
+ print STDERR "The invoking process wants preprocessed source, so let's hand off this whole command to the real cl.exe\n" if $debug;
+ Exec("\"$clexe\" \"" . join('" "', @ARGV) . "\"");
+ } elsif ($arg =~ /^@(.*)$/) {
+ chomp($commandFile = `cygpath -u '$1'`);
+ }
+}
+
+die "No command file specified!" unless $commandFile;
+die "Couldn't find $commandFile!" unless -f $commandFile;
+
+my @sources;
+
+open(COMMAND, '<:raw:encoding(UTF16-LE):crlf:utf8', $commandFile) or die "Couldn't open $commandFile!";
+
+# The first line of the command file contains all the options to cl.exe plus the first (possibly quoted) filename
+my $firstLine = <COMMAND>;
+$firstLine =~ s/\r?\n$//;
+
+# To find the start of the first filename, look for either the last space on the line.
+# If the filename is quoted, the last character on the line will be a quote, so look for the quote before that.
+my $firstFileIndex;
+print STDERR "Last character of first line = '" . substr($firstLine, -1, 1) . "'\n" if $debug;
+if (substr($firstLine, -1, 1) eq '"') {
+ print STDERR "First file is quoted\n" if $debug;
+ $firstFileIndex = rindex($firstLine, '"', length($firstLine) - 2);
+} else {
+ print STDERR "First file is NOT quoted\n" if $debug;
+ $firstFileIndex = rindex($firstLine, ' ') + 1;
+}
+
+my $options = substr($firstLine, 0, $firstFileIndex) . join(' ', @ARGV[1 .. $#ARGV]);
+my $possibleFirstFile = substr($firstLine, $firstFileIndex);
+if ($possibleFirstFile =~ /\.(cpp|c)/) {
+ push(@sources, $possibleFirstFile);
+} else {
+ $options .= " $possibleFirstFile";
+}
+
+print STDERR "######## Found options $options ##########\n" if $debug;
+print STDERR "####### Found first source file $sources[0] ########\n" if @sources && $debug;
+
+# The rest of the lines of the command file just contain source files, one per line
+while (my $source = <COMMAND>) {
+ chomp($source);
+ $source =~ s/^\s+//;
+ $source =~ s/\s+$//;
+ push(@sources, $source) if length($source);
+}
+close(COMMAND);
+
+my $numSources = @sources;
+exit unless $numSources > 0;
+
+my $numJobs;
+if ($options =~ s/-j\s*([0-9]+)//) {
+ $numJobs = $1;
+} else {
+ chomp($numJobs = `num-cpus`);
+}
+
+print STDERR "\n\n####### RUNNING AT MOST $numJobs PARALLEL INSTANCES OF cl.exe ###########\n\n";# if $debug;
+
+# Magic determination of job size
+# The hope is that by splitting the source files up into 2*$numJobs pieces, we
+# won't suffer too much if one job finishes much more quickly than another.
+# However, we don't want to split it up too much due to cl.exe overhead, so set
+# the minimum job size to 5.
+my $jobSize = POSIX::ceil($numSources / (2 * $numJobs));
+$jobSize = $jobSize < 5 ? 5 : $jobSize;
+
+print STDERR "######## jobSize = $jobSize ##########\n" if $debug;
+
+# Sort the source files randomly so that we don't end up with big clumps of large files (aka SVG)
+sub fisher_yates_shuffle(\@)
+{
+ my ($array) = @_;
+ for (my $i = @{$array}; --$i; ) {
+ my $j = int(rand($i+1));
+ next if $i == $j;
+ @{$array}[$i,$j] = @{$array}[$j,$i];
+ }
+}
+
+fisher_yates_shuffle(@sources); # permutes @array in place
+
+my @children;
+my @tmpFiles;
+my $status = 0;
+while (@sources) {
+ while (@sources && @children < $numJobs) {
+ my $pid;
+ my $tmpFile;
+ my $job = makeJob(@sources, $jobSize);
+ ($pid, $tmpFile) = forkAndCompileFiles(@{$job}, $options);
+
+ print STDERR "####### Spawned child with PID $pid and tmpFile $tmpFile ##########\n" if $debug;
+ push(@children, $pid);
+ push(@tmpFiles, $tmpFile);
+ }
+
+ $status |= waitForChild(@children);
+}
+
+while (@children) {
+ $status |= waitForChild(@children);
+}
+cleanup(@tmpFiles);
+
+exit WEXITSTATUS($status);
+
+
+sub makeJob(\@$)
+{
+ my ($files, $jobSize) = @_;
+
+ my @job;
+ if (@{$files} > ($jobSize * 1.5)) {
+ @job = splice(@{$files}, -$jobSize);
+ } else {
+ # Compile all the remaining files in this job to avoid having a small job later
+ @job = splice(@{$files});
+ }
+
+ return \@job;
+}
+
+sub forkAndCompileFiles(\@$)
+{
+ print STDERR "######## forkAndCompileFiles()\n" if $debug;
+ my ($files, $options) = @_;
+
+ if ($debug) {
+ foreach my $file (@{$files}) {
+ print STDERR "######## $file\n";
+ }
+ }
+
+ my (undef, $tmpFile) = File::Temp::tempfile('clcommandXXXXX', DIR => File::Spec->tmpdir, OPEN => 0);
+
+ my $pid = fork();
+ die "Fork failed" unless defined($pid);
+
+ unless ($pid) {
+ # Child process
+ open(TMP, '>:raw:encoding(UTF16-LE):crlf:utf8', $tmpFile) or die "Couldn't open $tmpFile";
+ print TMP "$options\n";
+ foreach my $file (@{$files}) {
+ print TMP "$file\n";
+ }
+ close(TMP);
+
+ chomp(my $winTmpFile = `cygpath -m $tmpFile`);
+ Exec "\"$clexe\" \@\"$winTmpFile\"";
+ } else {
+ return ($pid, $tmpFile);
+ }
+}
+
+sub Exec($)
+{
+ my ($command) = @_;
+
+ print STDERR "Exec($command)\n" if $debug;
+
+ exec($command);
+}
+
+sub waitForChild(\@)
+{
+ my ($children) = @_;
+
+ return unless @{$children};
+
+ my $deceased = wait();
+ my $status = $?;
+ print STDERR "######## Child with PID $deceased finished ###########\n" if $debug;
+ for (my $i = 0; $i < @{$children}; $i++) {
+ if ($children->[$i] == $deceased) {
+ splice(@{$children}, $i, 1);
+ last;
+ }
+ }
+
+ return $status;
+}
+
+sub cleanup(\@)
+{
+ my ($tmpFiles) = @_;
+
+ foreach my $file (@{$tmpFiles}) {
+ unlink $file;
+ }
+}
diff --git a/WebKitTools/Scripts/parse-malloc-history b/WebKitTools/Scripts/parse-malloc-history
new file mode 100755
index 0000000..76ca74b
--- /dev/null
+++ b/WebKitTools/Scripts/parse-malloc-history
@@ -0,0 +1,154 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Parses the callstacks in a file with malloc_history formatted content, sorting
+# based on total number of bytes allocated, and filtering based on command-line
+# parameters.
+
+use Getopt::Long;
+use File::Basename;
+
+use strict;
+use warnings;
+
+sub commify($);
+
+sub main()
+{
+ my $usage =
+ "Usage: " . basename($0) . " [options] malloc_history.txt\n" .
+ " --grep-regexp Include only call stacks that match this regular expression.\n" .
+ " --byte-minimum Include only call stacks with allocation sizes >= this value.\n" .
+ " --merge-regexp Merge all call stacks that match this regular expression.\n" .
+ " --merge-depth Merge all call stacks that match at this stack depth and above.\n";
+
+ my $grepRegexp = "";
+ my $byteMinimum = "";
+ my @mergeRegexps = ();
+ my $mergeDepth = "";
+ my $getOptionsResult = GetOptions(
+ "grep-regexp:s" => \$grepRegexp,
+ "byte-minimum:i" => \$byteMinimum,
+ "merge-regexp:s" => \@mergeRegexps,
+ "merge-depth:i" => \$mergeDepth
+ );
+ my $fileName = $ARGV[0];
+ die $usage if (!$getOptionsResult || !$fileName);
+
+ open FILE, "<$fileName" or die "bad file: $fileName";
+ my @file = <FILE>;
+ close FILE;
+
+ my %callstacks = ();
+ my $byteCountTotal = 0;
+
+ for (my $i = 0; $i < @file; $i++) {
+ my $line = $file[$i];
+ my ($callCount, $byteCount);
+
+ next if $line =~ /^\-/;
+
+ # First try malloc_history format
+ # 6 calls for 664 bytes thread_ffffffff |0x0 | start
+ ($callCount, $byteCount) = ($line =~ /(\d+) calls for (\d+) bytes/);
+
+ # Then try leaks format
+ # Leak: 0x0ac3ca40 size=48
+ # 0x00020001 0x00000001 0x00000000 0x00000000 ................
+ # Call stack: [thread ffffffff]: | 0x0 | start
+ if (!$callCount || !$byteCount) {
+ $callCount = 1;
+ ($byteCount) = ($line =~ /Leak: [x[:xdigit:]]* size=(\d+)/);
+
+ if ($byteCount) {
+ while (!($line =~ "Call stack: ")) {
+ $i++;
+ $line = $file[$i];
+ }
+ }
+ }
+
+ # Then give up
+ next if (!$callCount || !$byteCount);
+
+ $byteCountTotal += $byteCount;
+
+ next if ($grepRegexp && !($line =~ $grepRegexp));
+
+ my $callstackBegin = 0;
+ if ($mergeDepth) {
+ # count stack frames backwards from end of callstack
+ $callstackBegin = length($line);
+ for (my $pipeCount = 0; $pipeCount < $mergeDepth; $pipeCount++) {
+ my $rindexResult = rindex($line, "|", $callstackBegin - 1);
+ last if $rindexResult == -1;
+ $callstackBegin = $rindexResult;
+ }
+ } else {
+ # start at beginning of callstack
+ $callstackBegin = index($line, "|");
+ }
+
+ my $callstack = substr($line, $callstackBegin + 2); # + 2 skips "| "
+ for my $regexp (@mergeRegexps) {
+ if ($callstack =~ $regexp) {
+ $callstack = $regexp . "\n";
+ last;
+ }
+ }
+
+ if (!$callstacks{$callstack}) {
+ $callstacks{$callstack} = {"callCount" => 0, "byteCount" => 0};
+ }
+
+ $callstacks{$callstack}{"callCount"} += $callCount;
+ $callstacks{$callstack}{"byteCount"} += $byteCount;
+ }
+
+ my $byteCountTotalReported = 0;
+ for my $callstack (sort { $callstacks{$b}{"byteCount"} <=> $callstacks{$a}{"byteCount"} } keys %callstacks) {
+ my $callCount = $callstacks{$callstack}{"callCount"};
+ my $byteCount = $callstacks{$callstack}{"byteCount"};
+ last if ($byteMinimum && $byteCount < $byteMinimum);
+
+ $byteCountTotalReported += $byteCount;
+ print commify($callCount) . " calls for " . commify($byteCount) . " bytes: $callstack\n";
+ }
+
+ print "total: " . commify($byteCountTotalReported) . " bytes (" . commify($byteCountTotal - $byteCountTotalReported) . " bytes excluded).\n";
+}
+
+exit(main());
+
+# Copied from perldoc -- please excuse the style
+sub commify($)
+{
+ local $_ = shift;
+ 1 while s/^([-+]?\d+)(\d{3})/$1,$2/;
+ return $_;
+}
diff --git a/WebKitTools/Scripts/pdevenv b/WebKitTools/Scripts/pdevenv
new file mode 100755
index 0000000..1931211
--- /dev/null
+++ b/WebKitTools/Scripts/pdevenv
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use File::Temp qw/tempfile/;
+use FindBin;
+
+my ($fh, $path) = tempfile(UNLINK => 0, SUFFIX => '.cmd') or die;
+
+chomp(my $vcBin = `cygpath -w "$FindBin::Bin/../vcbin"`);
+
+print $fh "\@echo off\n\n";
+print $fh "call \"\%VS80COMNTOOLS\%\\vsvars32.bat\"\n\n";
+print $fh "set PATH=$vcBin;\%PATH\%\n\n";
+print $fh "IF EXIST \"\%VSINSTALLDIR\%\\Common7\\IDE\\devenv.com\" (devenv.com /useenv " . join(" ", @ARGV) . ") ELSE ";
+print $fh "VCExpress.exe /useenv " . join(" ", @ARGV) . "\n";
+
+close $fh;
+
+chmod 0755, $path;
+
+chomp($path = `cygpath -w -s '$path'`);
+
+exec("cmd /c \"call $path\"");
diff --git a/WebKitTools/Scripts/prepare-ChangeLog b/WebKitTools/Scripts/prepare-ChangeLog
new file mode 100755
index 0000000..3ecf189
--- /dev/null
+++ b/WebKitTools/Scripts/prepare-ChangeLog
@@ -0,0 +1,1445 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+#
+# Copyright (C) 2000, 2001 Eazel, Inc.
+# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+#
+# prepare-ChangeLog is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# prepare-ChangeLog is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+# Perl script to create a ChangeLog entry with names of files
+# and functions from a diff.
+#
+# Darin Adler <darin@bentspoon.com>, started 20 April 2000
+# Java support added by Maciej Stachowiak <mjs@eazel.com>
+# Objective-C, C++ and Objective-C++ support added by Maciej Stachowiak <mjs@apple.com>
+# Git support added by Adam Roben <aroben@apple.com>
+
+
+#
+# TODO:
+# List functions that have been removed too.
+# Decide what a good logical order is for the changed files
+# other than a normal text "sort" (top level first?)
+# (group directories?) (.h before .c?)
+# Handle yacc source files too (other languages?).
+# Help merge when there are ChangeLog conflicts or if there's
+# already a partly written ChangeLog entry.
+# Add command line option to put the ChangeLog into a separate
+# file or just spew it out stdout.
+# Add SVN version numbers for commit (can't do that until
+# the changes are checked in, though).
+# Work around diff stupidity where deleting a function that starts
+# with a comment makes diff think that the following function
+# has been changed (if the following function starts with a comment
+# with the same first line, such as /**)
+# Work around diff stupidity where deleting an entire function and
+# the blank lines before it makes diff think you've changed the
+# previous function.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Spec;
+use FindBin;
+use Getopt::Long;
+use lib $FindBin::Bin;
+use POSIX qw(strftime);
+use VCSUtils;
+
+sub changeLogDate($);
+sub firstDirectoryOrCwd();
+sub diffFromToString();
+sub diffCommand(@);
+sub statusCommand(@);
+sub createPatchCommand($);
+sub diffHeaderFormat();
+sub findOriginalFileFromSvn($);
+sub generateFileList(\@\@\%);
+sub gitConfig($);
+sub isModifiedStatus($);
+sub isAddedStatus($);
+sub isConflictStatus($);
+sub statusDescription($$);
+sub extractLineRange($);
+sub canonicalizePath($);
+sub testListForChangeLog(@);
+sub get_function_line_ranges($$);
+sub get_function_line_ranges_for_c($$);
+sub get_function_line_ranges_for_java($$);
+sub get_function_line_ranges_for_javascript($$);
+sub method_decl_to_selector($);
+sub processPaths(\@);
+sub reviewerAndDescriptionForGitCommit($);
+
+# Project time zone for Cupertino, CA, US
+my $changeLogTimeZone = "PST8PDT";
+
+my $gitCommit = 0;
+my $gitReviewer = "";
+my $openChangeLogs = 0;
+my $showHelp = 0;
+my $spewDiff = $ENV{"PREPARE_CHANGELOG_DIFF"};
+my $updateChangeLogs = 1;
+my $parseOptionsResult =
+ GetOptions("diff|d!" => \$spewDiff,
+ "git-commit:s" => \$gitCommit,
+ "git-reviewer:s" => \$gitReviewer,
+ "help|h!" => \$showHelp,
+ "open|o!" => \$openChangeLogs,
+ "update!" => \$updateChangeLogs);
+if (!$parseOptionsResult || $showHelp) {
+ print STDERR basename($0) . " [-d|--diff] [-h|--help] [-o|--open] [--git-commit=<committish>] [--git-reviewer=<name>] [svndir1 [svndir2 ...]]\n";
+ print STDERR " -d|--diff Spew diff to stdout when running\n";
+ print STDERR " --git-commit Populate the ChangeLogs from the specified git commit\n";
+ print STDERR " --git-reviewer When populating the ChangeLogs from a git commit claim that the spcified name reviewed the change.\n";
+ print STDERR " This option is useful when the git commit lacks a Signed-Off-By: line\n";
+ print STDERR " -h|--help Show this help message\n";
+ print STDERR " -o|--open Open ChangeLogs in an editor when done\n";
+ print STDERR " --[no-]update Update ChangeLogs from svn before adding entry (default: update)\n";
+ exit 1;
+}
+
+my %paths = processPaths(@ARGV);
+
+my $isGit = isGitDirectory(firstDirectoryOrCwd());
+my $isSVN = isSVNDirectory(firstDirectoryOrCwd());
+
+$isSVN || $isGit || die "Couldn't determine your version control system.";
+
+# Find the list of modified files
+my @changed_files;
+my $changed_files_string;
+my %changed_line_ranges;
+my %function_lists;
+my @conflict_files;
+
+my $SVN = "svn";
+my $GIT = "git";
+
+my %supportedTestExtensions = map { $_ => 1 } qw(html shtml svg xml xhtml pl php);
+my @addedRegressionTests = ();
+my $didChangeRegressionTests = 0;
+
+generateFileList(@changed_files, @conflict_files, %function_lists);
+
+if (!@changed_files && !@conflict_files && !keys %function_lists) {
+ print STDERR " No changes found.\n";
+ exit 1;
+}
+
+if (@conflict_files) {
+ print STDERR " The following files have conflicts. Run prepare-ChangeLog again after fixing the conflicts:\n";
+ print STDERR join("\n", @conflict_files), "\n";
+ exit 1;
+}
+
+if (@changed_files) {
+ $changed_files_string = "'" . join ("' '", @changed_files) . "'";
+
+ # For each file, build a list of modified lines.
+ # Use line numbers from the "after" side of each diff.
+ print STDERR " Reviewing diff to determine which lines changed.\n";
+ my $file;
+ open DIFF, "-|", diffCommand(@changed_files) or die "The diff failed: $!.\n";
+ while (<DIFF>) {
+ $file = makeFilePathRelative($1) if $_ =~ diffHeaderFormat();
+ if (defined $file) {
+ my ($start, $end) = extractLineRange($_);
+ if ($start >= 0 && $end >= 0) {
+ push @{$changed_line_ranges{$file}}, [ $start, $end ];
+ } elsif (/DO_NOT_COMMIT/) {
+ print STDERR "WARNING: file $file contains the string DO_NOT_COMMIT, line $.\n";
+ }
+ }
+ }
+ close DIFF;
+}
+
+# For each source file, convert line range to function list.
+if (%changed_line_ranges) {
+ print STDERR " Extracting affected function names from source files.\n";
+ foreach my $file (keys %changed_line_ranges) {
+ # Only look for function names in certain source files.
+ next unless $file =~ /\.(c|cpp|m|mm|h|java|js)/;
+
+ # Find all the functions in the file.
+ open SOURCE, $file or next;
+ my @function_ranges = get_function_line_ranges(\*SOURCE, $file);
+ close SOURCE;
+
+ # Find all the modified functions.
+ my @functions;
+ my %saw_function;
+ my @change_ranges = (@{$changed_line_ranges{$file}}, []);
+ my @change_range = (0, 0);
+ FUNCTION: foreach my $function_range_ref (@function_ranges) {
+ my @function_range = @$function_range_ref;
+
+ # Advance to successive change ranges.
+ for (;; @change_range = @{shift @change_ranges}) {
+ last FUNCTION unless @change_range;
+
+ # If past this function, move on to the next one.
+ next FUNCTION if $change_range[0] > $function_range[1];
+
+ # If an overlap with this function range, record the function name.
+ if ($change_range[1] >= $function_range[0]
+ and $change_range[0] <= $function_range[1]) {
+ if (!$saw_function{$function_range[2]}) {
+ $saw_function{$function_range[2]} = 1;
+ push @functions, $function_range[2];
+ }
+ next FUNCTION;
+ }
+ }
+ }
+
+ # Format the list of functions now.
+
+ if (@functions) {
+ $function_lists{$file} = "" if !defined $function_lists{$file};
+ $function_lists{$file} .= "\n (" . join("):\n (", @functions) . "):";
+ }
+ }
+}
+
+# Get some parameters for the ChangeLog we are about to write.
+my $date = changeLogDate($changeLogTimeZone);
+my $name = $ENV{CHANGE_LOG_NAME}
+ || $ENV{REAL_NAME}
+ || gitConfig("user.name")
+ || (split /\s*,\s*/, (getpwuid $<)[6])[0]
+ || "set REAL_NAME environment variable";
+my $email_address = $ENV{CHANGE_LOG_EMAIL_ADDRESS}
+ || $ENV{EMAIL_ADDRESS}
+ || gitConfig("user.email")
+ || "set EMAIL_ADDRESS environment variable";
+
+if ($gitCommit) {
+ $name = `$GIT log --max-count=1 --pretty=\"format:%an\" \"$gitCommit\"`;
+ $email_address = `$GIT log --max-count=1 --pretty=\"format:%ae\" \"$gitCommit\"`;
+}
+
+# Remove trailing parenthesized notes from user name (bit of hack).
+$name =~ s/\(.*?\)\s*$//g;
+
+# Find the change logs.
+my %has_log;
+my %files;
+foreach my $file (sort keys %function_lists) {
+ my $prefix = $file;
+ my $has_log = 0;
+ while ($prefix) {
+ $prefix =~ s-/[^/]+/?$-/- or $prefix = "";
+ $has_log = $has_log{$prefix};
+ if (!defined $has_log) {
+ $has_log = -f "${prefix}ChangeLog";
+ $has_log{$prefix} = $has_log;
+ }
+ last if $has_log;
+ }
+ if (!$has_log) {
+ print STDERR "No ChangeLog found for $file.\n";
+ } else {
+ push @{$files{$prefix}}, $file;
+ }
+}
+
+# Get the latest ChangeLog files from svn.
+my @logs = ();
+foreach my $prefix (sort keys %files) {
+ push @logs, File::Spec->catfile($prefix || ".", "ChangeLog");
+}
+
+if (@logs && $updateChangeLogs && $isSVN) {
+ print STDERR " Running 'svn update' to update ChangeLog files.\n";
+ open ERRORS, "-|", $SVN, "update", @logs
+ or die "The svn update of ChangeLog files failed: $!.\n";
+ my @conflictedChangeLogs;
+ while (my $line = <ERRORS>) {
+ print STDERR " ", $line;
+ push @conflictedChangeLogs, $1 if $line =~ m/^C\s+(.+)\s*$/;
+ }
+ close ERRORS;
+
+ if (@conflictedChangeLogs) {
+ print STDERR " Attempting to merge conflicted ChangeLogs.\n";
+ my $resolveChangeLogsPath = File::Spec->catfile(dirname($0), "resolve-ChangeLogs");
+ open RESOLVE, "-|", $resolveChangeLogsPath, "--no-warnings", @conflictedChangeLogs
+ or die "Could not open resolve-ChangeLogs script: $!.\n";
+ print STDERR " $_" while <RESOLVE>;
+ close RESOLVE;
+ }
+}
+
+# Write out a new ChangeLog file.
+foreach my $prefix (sort keys %files) {
+ my $changeLogPath = File::Spec->catfile($prefix || ".", "ChangeLog");
+ print STDERR " Editing the ${changeLogPath} file.\n";
+ open OLD_CHANGE_LOG, ${changeLogPath} or die "Could not open ${changeLogPath} file: $!.\n";
+ # It's less efficient to read the whole thing into memory than it would be
+ # to read it while we prepend to it later, but I like doing this part first.
+ my @old_change_log = <OLD_CHANGE_LOG>;
+ close OLD_CHANGE_LOG;
+ open CHANGE_LOG, "> ${changeLogPath}" or die "Could not write ${changeLogPath}\n.";
+ print CHANGE_LOG "$date $name <$email_address>\n\n";
+
+ my ($reviewer, $description) = reviewerAndDescriptionForGitCommit($gitCommit) if $gitCommit;
+ $reviewer = "NOBODY (OO" . "PS!)" if !$reviewer;
+
+ print CHANGE_LOG " Reviewed by $reviewer.\n\n";
+ print CHANGE_LOG $description . "\n" if $description;
+
+ if ($prefix =~ m/WebCore/ || `pwd` =~ m/WebCore/) {
+ if ($didChangeRegressionTests) {
+ print CHANGE_LOG testListForChangeLog(sort @addedRegressionTests);
+ } else {
+ print CHANGE_LOG " WARNING: NO TEST CASES ADDED OR CHANGED\n\n";
+ }
+ }
+
+ foreach my $file (sort @{$files{$prefix}}) {
+ my $file_stem = substr $file, length $prefix;
+ print CHANGE_LOG " * $file_stem:$function_lists{$file}\n";
+ }
+ print CHANGE_LOG "\n", @old_change_log;
+ close CHANGE_LOG;
+}
+
+# Write out another diff.
+if ($spewDiff && @changed_files) {
+ print STDERR " Running diff to help you write the ChangeLog entries.\n";
+ local $/ = undef; # local slurp mode
+ open DIFF, "-|", createPatchCommand($changed_files_string) or die "The diff failed: $!.\n";
+ print <DIFF>;
+ close DIFF;
+}
+
+# Open ChangeLogs.
+if ($openChangeLogs && @logs) {
+ print STDERR " Opening the edited ChangeLog files.\n";
+ my $editor = $ENV{"CHANGE_LOG_EDIT_APPLICATION"};
+ if ($editor) {
+ system "open", "-a", $editor, @logs;
+ } else {
+ system "open", "-e", @logs;
+ }
+}
+
+# Done.
+exit;
+
+sub canonicalizePath($)
+{
+ my ($file) = @_;
+
+ # Remove extra slashes and '.' directories in path
+ $file = File::Spec->canonpath($file);
+
+ # Remove '..' directories in path
+ my @dirs = ();
+ foreach my $dir (File::Spec->splitdir($file)) {
+ if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') {
+ pop(@dirs);
+ } else {
+ push(@dirs, $dir);
+ }
+ }
+ return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
+}
+
+sub changeLogDate($)
+{
+ my ($timeZone) = @_;
+ my $savedTimeZone = $ENV{'TZ'};
+ # Set TZ temporarily so that localtime() is in that time zone
+ $ENV{'TZ'} = $timeZone;
+ my $date = strftime("%Y-%m-%d", localtime());
+ if (defined $savedTimeZone) {
+ $ENV{'TZ'} = $savedTimeZone;
+ } else {
+ delete $ENV{'TZ'};
+ }
+ return $date;
+}
+
+sub get_function_line_ranges($$)
+{
+ my ($file_handle, $file_name) = @_;
+
+ if ($file_name =~ /\.(c|cpp|m|mm|h)$/) {
+ return get_function_line_ranges_for_c ($file_handle, $file_name);
+ } elsif ($file_name =~ /\.java$/) {
+ return get_function_line_ranges_for_java ($file_handle, $file_name);
+ } elsif ($file_name =~ /\.js$/) {
+ return get_function_line_ranges_for_javascript ($file_handle, $file_name);
+ }
+ return ();
+}
+
+
+sub method_decl_to_selector($)
+{
+ (my $method_decl) = @_;
+
+ $_ = $method_decl;
+
+ if ((my $comment_stripped) = m-([^/]*)(//|/*).*-) {
+ $_ = $comment_stripped;
+ }
+
+ s/,\s*...//;
+
+ if (/:/) {
+ my @components = split /:/;
+ pop @components if (scalar @components > 1);
+ $_ = (join ':', map {s/.*[^[:word:]]//; scalar $_;} @components) . ':';
+ } else {
+ s/\s*$//;
+ s/.*[^[:word:]]//;
+ }
+
+ return $_;
+}
+
+
+
+# Read a file and get all the line ranges of the things that look like C functions.
+# A function name is the last word before an open parenthesis before the outer
+# level open brace. A function starts at the first character after the last close
+# brace or semicolon before the function name and ends at the close brace.
+# Comment handling is simple-minded but will work for all but pathological cases.
+#
+# Result is a list of triples: [ start_line, end_line, function_name ].
+
+sub get_function_line_ranges_for_c($$)
+{
+ my ($file_handle, $file_name) = @_;
+
+ my @ranges;
+
+ my $in_comment = 0;
+ my $in_macro = 0;
+ my $in_method_declaration = 0;
+ my $in_parentheses = 0;
+ my $in_braces = 0;
+ my $brace_start = 0;
+ my $brace_end = 0;
+ my $skip_til_brace_or_semicolon = 0;
+
+ my $word = "";
+ my $interface_name = "";
+
+ my $potential_method_char = "";
+ my $potential_method_spec = "";
+
+ my $potential_start = 0;
+ my $potential_name = "";
+
+ my $start = 0;
+ my $name = "";
+
+ my $next_word_could_be_namespace = 0;
+ my $potential_namespace = "";
+ my @namespaces;
+
+ while (<$file_handle>) {
+ # Handle continued multi-line comment.
+ if ($in_comment) {
+ next unless s-.*\*/--;
+ $in_comment = 0;
+ }
+
+ # Handle continued macro.
+ if ($in_macro) {
+ $in_macro = 0 unless /\\$/;
+ next;
+ }
+
+ # Handle start of macro (or any preprocessor directive).
+ if (/^\s*\#/) {
+ $in_macro = 1 if /^([^\\]|\\.)*\\$/;
+ next;
+ }
+
+ # Handle comments and quoted text.
+ while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy
+ my $match = $1;
+ if ($match eq "/*") {
+ if (!s-/\*.*?\*/--) {
+ s-/\*.*--;
+ $in_comment = 1;
+ }
+ } elsif ($match eq "//") {
+ s-//.*--;
+ } else { # ' or "
+ if (!s-$match([^\\]|\\.)*?$match--) {
+ warn "mismatched quotes at line $. in $file_name\n";
+ s-$match.*--;
+ }
+ }
+ }
+
+
+ # continued method declaration
+ if ($in_method_declaration) {
+ my $original = $_;
+ my $method_cont = $_;
+
+ chomp $method_cont;
+ $method_cont =~ s/[;\{].*//;
+ $potential_method_spec = "${potential_method_spec} ${method_cont}";
+
+ $_ = $original;
+ if (/;/) {
+ $potential_start = 0;
+ $potential_method_spec = "";
+ $potential_method_char = "";
+ $in_method_declaration = 0;
+ s/^[^;\{]*//;
+ } elsif (/{/) {
+ my $selector = method_decl_to_selector ($potential_method_spec);
+ $potential_name = "${potential_method_char}\[${interface_name} ${selector}\]";
+
+ $potential_method_spec = "";
+ $potential_method_char = "";
+ $in_method_declaration = 0;
+
+ $_ = $original;
+ s/^[^;{]*//;
+ } elsif (/\@end/) {
+ $in_method_declaration = 0;
+ $interface_name = "";
+ $_ = $original;
+ } else {
+ next;
+ }
+ }
+
+
+ # start of method declaration
+ if ((my $method_char, my $method_spec) = m&^([-+])([^0-9;][^;]*);?$&) {
+ my $original = $_;
+
+ if ($interface_name) {
+ chomp $method_spec;
+ $method_spec =~ s/\{.*//;
+
+ $potential_method_char = $method_char;
+ $potential_method_spec = $method_spec;
+ $potential_start = $.;
+ $in_method_declaration = 1;
+ } else {
+ warn "declaring a method but don't have interface on line $. in $file_name\n";
+ }
+ $_ = $original;
+ if (/\{/) {
+ my $selector = method_decl_to_selector ($potential_method_spec);
+ $potential_name = "${potential_method_char}\[${interface_name} ${selector}\]";
+
+ $potential_method_spec = "";
+ $potential_method_char = "";
+ $in_method_declaration = 0;
+ $_ = $original;
+ s/^[^{]*//;
+ } elsif (/\@end/) {
+ $in_method_declaration = 0;
+ $interface_name = "";
+ $_ = $original;
+ } else {
+ next;
+ }
+ }
+
+
+ # Find function, interface and method names.
+ while (m&((?:[[:word:]]+::)*operator(?:[ \t]*\(\)|[^()]*)|[[:word:]:~]+|[(){}:;])|\@(?:implementation|interface|protocol)\s+(\w+)[^{]*&g) {
+ # interface name
+ if ($2) {
+ $interface_name = $2;
+ next;
+ }
+
+ # Open parenthesis.
+ if ($1 eq "(") {
+ $potential_name = $word unless $in_parentheses || $skip_til_brace_or_semicolon;
+ $in_parentheses++;
+ next;
+ }
+
+ # Close parenthesis.
+ if ($1 eq ")") {
+ $in_parentheses--;
+ next;
+ }
+
+ # C++ constructor initializers
+ if ($1 eq ":") {
+ $skip_til_brace_or_semicolon = 1 unless ($in_parentheses || $in_braces);
+ }
+
+ # Open brace.
+ if ($1 eq "{") {
+ $skip_til_brace_or_semicolon = 0;
+
+ if ($potential_namespace) {
+ push @namespaces, $potential_namespace;
+ $potential_namespace = "";
+ next;
+ }
+
+ # Promote potential name to real function name at the
+ # start of the outer level set of braces (function body?).
+ if (!$in_braces and $potential_start) {
+ $start = $potential_start;
+ $name = $potential_name;
+ if (@namespaces && (length($name) < 2 || substr($name,1,1) ne "[")) {
+ $name = join ('::', @namespaces, $name);
+ }
+ }
+
+ $in_method_declaration = 0;
+
+ $brace_start = $. if (!$in_braces);
+ $in_braces++;
+ next;
+ }
+
+ # Close brace.
+ if ($1 eq "}") {
+ if (!$in_braces && @namespaces) {
+ pop @namespaces;
+ next;
+ }
+
+ $in_braces--;
+ $brace_end = $. if (!$in_braces);
+
+ # End of an outer level set of braces.
+ # This could be a function body.
+ if (!$in_braces and $name) {
+ push @ranges, [ $start, $., $name ];
+ $name = "";
+ }
+
+ $potential_start = 0;
+ $potential_name = "";
+ next;
+ }
+
+ # Semicolon.
+ if ($1 eq ";") {
+ $skip_til_brace_or_semicolon = 0;
+ $potential_start = 0;
+ $potential_name = "";
+ $in_method_declaration = 0;
+ next;
+ }
+
+ # Ignore "const" method qualifier.
+ if ($1 eq "const") {
+ next;
+ }
+
+ if ($1 eq "namespace" || $1 eq "class" || $1 eq "struct") {
+ $next_word_could_be_namespace = 1;
+ next;
+ }
+
+ # Word.
+ $word = $1;
+ if (!$skip_til_brace_or_semicolon) {
+ if ($next_word_could_be_namespace) {
+ $potential_namespace = $word;
+ $next_word_could_be_namespace = 0;
+ } elsif ($potential_namespace) {
+ $potential_namespace = "";
+ }
+
+ if (!$in_parentheses) {
+ $potential_start = 0;
+ $potential_name = "";
+ }
+ if (!$potential_start) {
+ $potential_start = $.;
+ $potential_name = "";
+ }
+ }
+ }
+ }
+
+ warn "missing close braces in $file_name (probable start at $brace_start)\n" if ($in_braces > 0);
+ warn "too many close braces in $file_name (probable start at $brace_end)\n" if ($in_braces < 0);
+
+ warn "mismatched parentheses in $file_name\n" if $in_parentheses;
+
+ return @ranges;
+}
+
+
+
+# Read a file and get all the line ranges of the things that look like Java
+# classes, interfaces and methods.
+#
+# A class or interface name is the word that immediately follows
+# `class' or `interface' when followed by an open curly brace and not
+# a semicolon. It can appear at the top level, or inside another class
+# or interface block, but not inside a function block
+#
+# A class or interface starts at the first character after the first close
+# brace or after the function name and ends at the close brace.
+#
+# A function name is the last word before an open parenthesis before
+# an open brace rather than a semicolon. It can appear at top level or
+# inside a class or interface block, but not inside a function block.
+#
+# A function starts at the first character after the first close
+# brace or after the function name and ends at the close brace.
+#
+# Comment handling is simple-minded but will work for all but pathological cases.
+#
+# Result is a list of triples: [ start_line, end_line, function_name ].
+
+sub get_function_line_ranges_for_java($$)
+{
+ my ($file_handle, $file_name) = @_;
+
+ my @current_scopes;
+
+ my @ranges;
+
+ my $in_comment = 0;
+ my $in_macro = 0;
+ my $in_parentheses = 0;
+ my $in_braces = 0;
+ my $in_non_block_braces = 0;
+ my $class_or_interface_just_seen = 0;
+
+ my $word = "";
+
+ my $potential_start = 0;
+ my $potential_name = "";
+ my $potential_name_is_class_or_interface = 0;
+
+ my $start = 0;
+ my $name = "";
+ my $current_name_is_class_or_interface = 0;
+
+ while (<$file_handle>) {
+ # Handle continued multi-line comment.
+ if ($in_comment) {
+ next unless s-.*\*/--;
+ $in_comment = 0;
+ }
+
+ # Handle continued macro.
+ if ($in_macro) {
+ $in_macro = 0 unless /\\$/;
+ next;
+ }
+
+ # Handle start of macro (or any preprocessor directive).
+ if (/^\s*\#/) {
+ $in_macro = 1 if /^([^\\]|\\.)*\\$/;
+ next;
+ }
+
+ # Handle comments and quoted text.
+ while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy
+ my $match = $1;
+ if ($match eq "/*") {
+ if (!s-/\*.*?\*/--) {
+ s-/\*.*--;
+ $in_comment = 1;
+ }
+ } elsif ($match eq "//") {
+ s-//.*--;
+ } else { # ' or "
+ if (!s-$match([^\\]|\\.)*?$match--) {
+ warn "mismatched quotes at line $. in $file_name\n";
+ s-$match.*--;
+ }
+ }
+ }
+
+ # Find function names.
+ while (m-(\w+|[(){};])-g) {
+ # Open parenthesis.
+ if ($1 eq "(") {
+ if (!$in_parentheses) {
+ $potential_name = $word;
+ $potential_name_is_class_or_interface = 0;
+ }
+ $in_parentheses++;
+ next;
+ }
+
+ # Close parenthesis.
+ if ($1 eq ")") {
+ $in_parentheses--;
+ next;
+ }
+
+ # Open brace.
+ if ($1 eq "{") {
+ # Promote potential name to real function name at the
+ # start of the outer level set of braces (function/class/interface body?).
+ if (!$in_non_block_braces
+ and (!$in_braces or $current_name_is_class_or_interface)
+ and $potential_start) {
+ if ($name) {
+ push @ranges, [ $start, ($. - 1),
+ join ('.', @current_scopes) ];
+ }
+
+
+ $current_name_is_class_or_interface = $potential_name_is_class_or_interface;
+
+ $start = $potential_start;
+ $name = $potential_name;
+
+ push (@current_scopes, $name);
+ } else {
+ $in_non_block_braces++;
+ }
+
+ $potential_name = "";
+ $potential_start = 0;
+
+ $in_braces++;
+ next;
+ }
+
+ # Close brace.
+ if ($1 eq "}") {
+ $in_braces--;
+
+ # End of an outer level set of braces.
+ # This could be a function body.
+ if (!$in_non_block_braces) {
+ if ($name) {
+ push @ranges, [ $start, $.,
+ join ('.', @current_scopes) ];
+
+ pop (@current_scopes);
+
+ if (@current_scopes) {
+ $current_name_is_class_or_interface = 1;
+
+ $start = $. + 1;
+ $name = $current_scopes[$#current_scopes-1];
+ } else {
+ $current_name_is_class_or_interface = 0;
+ $start = 0;
+ $name = "";
+ }
+ }
+ } else {
+ $in_non_block_braces-- if $in_non_block_braces;
+ }
+
+ $potential_start = 0;
+ $potential_name = "";
+ next;
+ }
+
+ # Semicolon.
+ if ($1 eq ";") {
+ $potential_start = 0;
+ $potential_name = "";
+ next;
+ }
+
+ if ($1 eq "class" or $1 eq "interface") {
+ $class_or_interface_just_seen = 1;
+ next;
+ }
+
+ # Word.
+ $word = $1;
+ if (!$in_parentheses) {
+ if ($class_or_interface_just_seen) {
+ $potential_name = $word;
+ $potential_start = $.;
+ $class_or_interface_just_seen = 0;
+ $potential_name_is_class_or_interface = 1;
+ next;
+ }
+ }
+ if (!$potential_start) {
+ $potential_start = $.;
+ $potential_name = "";
+ }
+ $class_or_interface_just_seen = 0;
+ }
+ }
+
+ warn "mismatched braces in $file_name\n" if $in_braces;
+ warn "mismatched parentheses in $file_name\n" if $in_parentheses;
+
+ return @ranges;
+}
+
+
+
+# Read a file and get all the line ranges of the things that look like
+# JavaScript functions.
+#
+# A function name is the word that immediately follows `function' when
+# followed by an open curly brace. It can appear at the top level, or
+# inside other functions.
+#
+# An anonymous function name is the identifier chain immediately before
+# an assignment with the equals operator or object notation that has a
+# value starting with `function' followed by an open curly brace.
+#
+# A getter or setter name is the word that immediately follows `get' or
+# `set' when followed by an open curly brace .
+#
+# Comment handling is simple-minded but will work for all but pathological cases.
+#
+# Result is a list of triples: [ start_line, end_line, function_name ].
+
+sub get_function_line_ranges_for_javascript($$)
+{
+ my ($fileHandle, $fileName) = @_;
+
+ my @currentScopes;
+ my @currentIdentifiers;
+ my @currentFunctionNames;
+ my @currentFunctionDepths;
+ my @currentFunctionStartLines;
+
+ my @ranges;
+
+ my $inComment = 0;
+ my $inQuotedText = "";
+ my $parenthesesDepth = 0;
+ my $bracesDepth = 0;
+
+ my $functionJustSeen = 0;
+ my $getterJustSeen = 0;
+ my $setterJustSeen = 0;
+ my $assignmentJustSeen = 0;
+
+ my $word = "";
+
+ while (<$fileHandle>) {
+ # Handle continued multi-line comment.
+ if ($inComment) {
+ next unless s-.*\*/--;
+ $inComment = 0;
+ }
+
+ # Handle continued quoted text.
+ if ($inQuotedText ne "") {
+ next if /\\$/;
+ s-([^\\]|\\.)*?$inQuotedText--;
+ $inQuotedText = "";
+ }
+
+ # Handle comments and quoted text.
+ while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy
+ my $match = $1;
+ if ($match eq '/*') {
+ if (!s-/\*.*?\*/--) {
+ s-/\*.*--;
+ $inComment = 1;
+ }
+ } elsif ($match eq '//') {
+ s-//.*--;
+ } else { # ' or "
+ if (!s-$match([^\\]|\\.)*?$match--) {
+ $inQuotedText = $match if /\\$/;
+ warn "mismatched quotes at line $. in $fileName\n" if $inQuotedText eq "";
+ s-$match.*--;
+ }
+ }
+ }
+
+ # Find function names.
+ while (m-(\w+|[(){}=:;])-g) {
+ # Open parenthesis.
+ if ($1 eq '(') {
+ $parenthesesDepth++;
+ next;
+ }
+
+ # Close parenthesis.
+ if ($1 eq ')') {
+ $parenthesesDepth--;
+ next;
+ }
+
+ # Open brace.
+ if ($1 eq '{') {
+ push(@currentScopes, join(".", @currentIdentifiers));
+ @currentIdentifiers = ();
+
+ $bracesDepth++;
+ next;
+ }
+
+ # Close brace.
+ if ($1 eq '}') {
+ $bracesDepth--;
+
+ if (@currentFunctionDepths and $bracesDepth == $currentFunctionDepths[$#currentFunctionDepths]) {
+ pop(@currentFunctionDepths);
+
+ my $currentFunction = pop(@currentFunctionNames);
+ my $start = pop(@currentFunctionStartLines);
+
+ push(@ranges, [$start, $., $currentFunction]);
+ }
+
+ pop(@currentScopes);
+ @currentIdentifiers = ();
+
+ next;
+ }
+
+ # Semicolon.
+ if ($1 eq ';') {
+ @currentIdentifiers = ();
+ next;
+ }
+
+ # Function.
+ if ($1 eq 'function') {
+ $functionJustSeen = 1;
+
+ if ($assignmentJustSeen) {
+ my $currentFunction = join('.', (@currentScopes, @currentIdentifiers));
+ $currentFunction =~ s/\.{2,}/\./g; # Removes consecutive periods.
+
+ push(@currentFunctionNames, $currentFunction);
+ push(@currentFunctionDepths, $bracesDepth);
+ push(@currentFunctionStartLines, $.);
+ }
+
+ next;
+ }
+
+ # Getter prefix.
+ if ($1 eq 'get') {
+ $getterJustSeen = 1;
+ next;
+ }
+
+ # Setter prefix.
+ if ($1 eq 'set') {
+ $setterJustSeen = 1;
+ next;
+ }
+
+ # Assignment operator.
+ if ($1 eq '=' or $1 eq ':') {
+ $assignmentJustSeen = 1;
+ next;
+ }
+
+ next if $parenthesesDepth;
+
+ # Word.
+ $word = $1;
+ $word = "get $word" if $getterJustSeen;
+ $word = "set $word" if $setterJustSeen;
+
+ if (($functionJustSeen and !$assignmentJustSeen) or $getterJustSeen or $setterJustSeen) {
+ push(@currentIdentifiers, $word);
+
+ my $currentFunction = join('.', (@currentScopes, @currentIdentifiers));
+ $currentFunction =~ s/\.{2,}/\./g; # Removes consecutive periods.
+
+ push(@currentFunctionNames, $currentFunction);
+ push(@currentFunctionDepths, $bracesDepth);
+ push(@currentFunctionStartLines, $.);
+ } elsif ($word ne 'if' and $word ne 'for' and $word ne 'do' and $word ne 'while' and $word ne 'which' and $word ne 'var') {
+ push(@currentIdentifiers, $word);
+ }
+
+ $functionJustSeen = 0;
+ $getterJustSeen = 0;
+ $setterJustSeen = 0;
+ $assignmentJustSeen = 0;
+ }
+ }
+
+ warn "mismatched braces in $fileName\n" if $bracesDepth;
+ warn "mismatched parentheses in $fileName\n" if $parenthesesDepth;
+
+ return @ranges;
+}
+
+
+sub processPaths(\@)
+{
+ my ($paths) = @_;
+ return ("." => 1) if (!@{$paths});
+
+ my %result = ();
+
+ for my $file (@{$paths}) {
+ die "can't handle absolute paths like \"$file\"\n" if File::Spec->file_name_is_absolute($file);
+ die "can't handle empty string path\n" if $file eq "";
+ die "can't handle path with single quote in the name like \"$file\"\n" if $file =~ /'/; # ' (keep Xcode syntax highlighting happy)
+
+ my $untouchedFile = $file;
+
+ $file = canonicalizePath($file);
+
+ die "can't handle paths with .. like \"$untouchedFile\"\n" if $file =~ m|/\.\./|;
+
+ $result{$file} = 1;
+ }
+
+ return ("." => 1) if ($result{"."});
+
+ # Remove any paths that also have a parent listed.
+ for my $path (keys %result) {
+ for (my $parent = dirname($path); $parent ne '.'; $parent = dirname($parent)) {
+ if ($result{$parent}) {
+ delete $result{$path};
+ last;
+ }
+ }
+ }
+
+ return %result;
+}
+
+sub diffFromToString()
+{
+ return "" if $isSVN;
+ return $gitCommit if $gitCommit =~ m/.+\.\..+/;
+ return "\"$gitCommit^\" \"$gitCommit\"" if $gitCommit;
+ return "HEAD" if $isGit;
+}
+
+sub diffCommand(@)
+{
+ my @paths = @_;
+
+ my $pathsString = "'" . join("' '", @paths) . "'";
+
+ my $command;
+ if ($isSVN) {
+ $command = "$SVN diff --diff-cmd diff -x -N $pathsString";
+ } elsif ($isGit) {
+ $command = "$GIT diff --no-ext-diff -U0 " . diffFromToString();
+ $command .= " -- $pathsString" unless $gitCommit;
+ }
+
+ return $command;
+}
+
+sub statusCommand(@)
+{
+ my @files = @_;
+
+ my $filesString = "'" . join ("' '", @files) . "'";
+ my $command;
+ if ($isSVN) {
+ $command = "$SVN stat $filesString";
+ } elsif ($isGit) {
+ $command = "$GIT diff -r --name-status -C -C -M " . diffFromToString();
+ $command .= " -- $filesString" unless $gitCommit;
+ }
+
+ return "$command 2>&1";
+}
+
+sub createPatchCommand($)
+{
+ my ($changedFilesString) = @_;
+
+ my $command;
+ if ($isSVN) {
+ $command = "'$FindBin::Bin/svn-create-patch' $changedFilesString";
+ } elsif ($isGit) {
+ $command = "$GIT diff -C -C -M " . diffFromToString();
+ $command .= " -- $changedFilesString" unless $gitCommit;
+ }
+
+ return $command;
+}
+
+sub diffHeaderFormat()
+{
+ return qr/^Index: (\S+)$/ if $isSVN;
+ return qr/^diff --git a\/.+ b\/(.+)$/ if $isGit;
+}
+
+sub findOriginalFileFromSvn($)
+{
+ my ($file) = @_;
+ my $baseUrl;
+ open INFO, "$SVN info . |" or die;
+ while (<INFO>) {
+ if (/^URL: (.+)/) {
+ $baseUrl = $1;
+ last;
+ }
+ }
+ close INFO;
+ my $sourceFile;
+ open INFO, "$SVN info '$file' |" or die;
+ while (<INFO>) {
+ if (/^Copied From URL: (.+)/) {
+ $sourceFile = File::Spec->abs2rel($1, $baseUrl);
+ last;
+ }
+ }
+ close INFO;
+ return $sourceFile;
+}
+
+sub generateFileList(\@\@\%)
+{
+ my ($changedFiles, $conflictFiles, $functionLists) = @_;
+ print STDERR " Running status to find changed, added, or removed files.\n";
+ open STAT, "-|", statusCommand(keys %paths) or die "The status failed: $!.\n";
+ my $inGitCommitSection = 0;
+ while (<STAT>) {
+ my $status;
+ my $original;
+ my $file;
+
+ if ($isSVN) {
+ if (/^([ACDMR]).{5} (.+)$/) {
+ $status = $1;
+ $file = $2;
+ $original = findOriginalFileFromSvn($file) if substr($_, 3, 1) eq "+";
+ } else {
+ print; # error output from svn stat
+ }
+ } elsif ($isGit) {
+ if (/^([ADM])\t(.+)$/) {
+ $status = $1;
+ $file = $2;
+ } elsif (/^([CR])[0-9]{1,3}\t([^\t]+)\t([^\t\n]+)$/) { # for example: R90% newfile oldfile
+ $status = $1;
+ $original = $2;
+ $file = $3;
+ } else {
+ print; # error output from git diff
+ }
+ }
+
+ next unless $status;
+
+ $file = makeFilePathRelative($file);
+
+ if (isModifiedStatus($status) || isAddedStatus($status)) {
+ my @components = File::Spec->splitdir($file);
+ if ($components[0] eq "LayoutTests") {
+ $didChangeRegressionTests = 1;
+ push @addedRegressionTests, $file
+ if isAddedStatus($status)
+ && $file =~ /\.([a-zA-Z]+)$/
+ && $supportedTestExtensions{lc($1)}
+ && !scalar(grep(/^resources$/i, @components));
+ }
+ push @{$changedFiles}, $file if $components[$#components] ne "ChangeLog";
+ } elsif (isConflictStatus($status)) {
+ push @{$conflictFiles}, $file;
+ }
+ if (basename($file) ne "ChangeLog") {
+ my $description = statusDescription($status, $original);
+ $functionLists->{$file} = $description if defined $description;
+ }
+ }
+ close STAT;
+}
+
+sub gitConfig($)
+{
+ return unless $isGit;
+
+ my ($config) = @_;
+
+ my $result = `$GIT config $config`;
+ if (($? >> 8) != 0) {
+ $result = `$GIT repo-config $config`;
+ }
+ chomp $result;
+ return $result;
+}
+
+sub isModifiedStatus($)
+{
+ my ($status) = @_;
+
+ my %statusCodes = (
+ "M" => 1,
+ );
+
+ return $statusCodes{$status};
+}
+
+sub isAddedStatus($)
+{
+ my ($status) = @_;
+
+ my %statusCodes = (
+ "A" => 1,
+ "C" => $isGit,
+ "R" => 1,
+ );
+
+ return $statusCodes{$status};
+}
+
+sub isConflictStatus($)
+{
+ my ($status) = @_;
+
+ my %svn = (
+ "C" => 1,
+ );
+
+ my %git = (
+ "U" => 1,
+ );
+
+ return 0 if $gitCommit; # an existing commit cannot have conflicts
+ return $svn{$status} if $isSVN;
+ return $git{$status} if $isGit;
+}
+
+sub statusDescription($$)
+{
+ my ($status, $original) = @_;
+
+ my %svn = (
+ "A" => defined $original ? " Copied from \%s." : " Added.",
+ "D" => " Removed.",
+ "M" => "",
+ "R" => defined $original ? " Replaced with \%s." : " Replaced.",
+ );
+
+ my %git = %svn;
+ $git{"A"} = " Added.";
+ $git{"C"} = " Copied from \%s.";
+ $git{"R"} = " Renamed from \%s.";
+
+ return sprintf($svn{$status}, $original) if $isSVN && exists $svn{$status};
+ return sprintf($git{$status}, $original) if $isGit && exists $git{$status};
+ return undef;
+}
+
+sub extractLineRange($)
+{
+ my ($string) = @_;
+
+ my ($start, $end) = (-1, -1);
+
+ if ($isSVN && $string =~ /^\d+(,\d+)?[acd](\d+)(,(\d+))?/) {
+ $start = $2;
+ $end = $4 || $2;
+ } elsif ($isGit && $string =~ /^@@ -\d+(,\d+)? \+(\d+)(,(\d+))? @@/) {
+ $start = $2;
+ $end = defined($4) ? $4 + $2 - 1 : $2;
+ }
+
+ return ($start, $end);
+}
+
+sub firstDirectoryOrCwd()
+{
+ my $dir = ".";
+ my @dirs = keys(%paths);
+
+ $dir = -d $dirs[0] ? $dirs[0] : dirname($dirs[0]) if @dirs;
+
+ return $dir;
+}
+
+sub testListForChangeLog(@)
+{
+ my (@tests) = @_;
+
+ return "" unless @tests;
+
+ my $leadString = " Test" . (@tests == 1 ? "" : "s") . ": ";
+ my $list = $leadString;
+ foreach my $i (0..$#tests) {
+ $list .= " " x length($leadString) if $i;
+ my $test = $tests[$i];
+ $test =~ s/^LayoutTests\///;
+ $list .= "$test\n";
+ }
+ $list .= "\n";
+
+ return $list;
+}
+
+sub reviewerAndDescriptionForGitCommit($)
+{
+ my ($commit) = @_;
+
+ my $description = '';
+ my $reviewer;
+
+ my @args = qw(rev-list --pretty);
+ push @args, '-1' if $commit !~ m/.+\.\..+/;
+ my $gitLog;
+ {
+ local $/ = undef;
+ open(GIT, "-|", $GIT, @args, $commit) || die;
+ $gitLog = <GIT>;
+ close(GIT);
+ }
+
+ my @commitLogs = split(/^[Cc]ommit [a-f0-9]{40}/m, $gitLog);
+ shift @commitLogs; # Remove initial blank commit log
+ my $commitLogCount = 0;
+ foreach my $commitLog (@commitLogs) {
+ $description .= "\n" if $commitLogCount;
+ $commitLogCount++;
+ my $inHeader = 1;
+ my @lines = split(/\n/, $commitLog);
+ shift @lines; # Remove initial blank line
+ foreach my $line (@lines) {
+ if ($inHeader) {
+ if (!$line) {
+ $inHeader = 0;
+ }
+ next;
+ } elsif ($line =~ /[Ss]igned-[Oo]ff-[Bb]y: (.+)/) {
+ if (!$reviewer) {
+ $reviewer = $1;
+ } else {
+ $reviewer .= ", " . $1;
+ }
+ } elsif (length $line == 0) {
+ $description = $description . "\n";
+ } else {
+ $line =~ s/^\s*//;
+ $description = $description . " " . $line . "\n";
+ }
+ }
+ }
+ if (!$reviewer) {
+ $reviewer = $gitReviewer;
+ }
+
+ return ($reviewer, $description);
+}
diff --git a/WebKitTools/Scripts/print-msvc-project-dependencies b/WebKitTools/Scripts/print-msvc-project-dependencies
new file mode 100755
index 0000000..dbc8402
--- /dev/null
+++ b/WebKitTools/Scripts/print-msvc-project-dependencies
@@ -0,0 +1,143 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2008 Apple Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use File::Basename;
+
+sub printDependencyTree($);
+
+my $basename = basename($0);
+@ARGV or die "Usage: $basename sln1 [sln2 sln3...]";
+
+foreach my $sln (@ARGV) {
+ printDependencyTree($sln);
+}
+
+exit;
+
+sub printDependencyTree($)
+{
+ my ($sln) = @_;
+
+ unless (-f $sln) {
+ warn "Warning: Can't find $sln; skipping\n";
+ return;
+ }
+
+ unless (open SLN, "<", $sln) {
+ warn "Warning: Can't open $sln; skipping\n";
+ return;
+ }
+
+ my %projectsByUUID = ();
+ my $currentProject;
+
+ my $state = "initial";
+ foreach my $line (<SLN>) {
+ if ($state eq "initial") {
+ if ($line =~ /^Project\([^\)]+\) = "([^"]+)", "[^"]+", "([^"]+)"\r?$/) {
+ my $name = $1;
+ my $uuid = $2;
+ if (exists $projectsByUUID{$uuid}) {
+ warn "Warning: Project $name appears more than once in $sln; using first definition\n";
+ next;
+ }
+ $currentProject = {
+ name => $name,
+ uuid => $uuid,
+ dependencies => {},
+ };
+ $projectsByUUID{$uuid} = $currentProject;
+
+ $state = "inProject";
+ }
+
+ next;
+ }
+
+ if ($state eq "inProject") {
+ defined($currentProject) or die;
+
+ if ($line =~ /^\s*ProjectSection\(ProjectDependencies\) = postProject\r?$/) {
+ $state = "inDependencies";
+ } elsif ($line =~ /^EndProject\r?$/) {
+ $currentProject = undef;
+ $state = "initial";
+ }
+
+ next;
+ }
+
+ if ($state eq "inDependencies") {
+ defined($currentProject) or die;
+
+ if ($line =~ /^\s*({[^}]+}) = ({[^}]+})\r?$/) {
+ my $uuid1 = $1;
+ my $uuid2 = $2;
+ if (exists $currentProject->{dependencies}->{$uuid1}) {
+ warn "Warning: UUID $uuid1 listed more than once as dependency of project ", $currentProject->{name}, "\n";
+ next;
+ }
+
+ $uuid1 eq $uuid2 or warn "Warning: UUIDs in depedency section of project ", $currentProject->{name}, " don't match: $uuid1 $uuid2; using first UUID\n";
+
+ $currentProject->{dependencies}->{$uuid1} = 1;
+ } elsif ($line =~ /^\s*EndProjectSection\r?$/) {
+ $state = "inProject";
+ }
+
+ next;
+ }
+ }
+
+ close SLN or warn "Warning: Can't close $sln\n";
+
+ my %projectsNotDependedUpon = %projectsByUUID;
+ CANDIDATE: foreach my $candidateUUID (keys %projectsByUUID) {
+ foreach my $projectUUID (keys %projectsByUUID) {
+ next if $candidateUUID eq $projectUUID;
+ foreach my $dependencyUUID (keys %{$projectsByUUID{$projectUUID}->{dependencies}}) {
+ if ($candidateUUID eq $dependencyUUID) {
+ delete $projectsNotDependedUpon{$candidateUUID};
+ next CANDIDATE;
+ }
+ }
+ }
+ }
+
+ foreach my $project (values %projectsNotDependedUpon) {
+ printProjectAndDependencies($project, 0, \%projectsByUUID);
+ }
+}
+
+sub printProjectAndDependencies
+{
+ my ($project, $indentLevel, $projectsByUUID) = @_;
+
+ print " " x $indentLevel, $project->{name}, "\n";
+ foreach my $dependencyUUID (keys %{$project->{dependencies}}) {
+ printProjectAndDependencies($projectsByUUID->{$dependencyUUID}, $indentLevel + 1, $projectsByUUID);
+ }
+}
diff --git a/WebKitTools/Scripts/report-include-statistics b/WebKitTools/Scripts/report-include-statistics
new file mode 100755
index 0000000..17152ab
--- /dev/null
+++ b/WebKitTools/Scripts/report-include-statistics
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# "report-include-statistics" script for WebKit Open Source Project
+
+use strict;
+use File::Find;
+
+find(\&wanted, @ARGV ? @ARGV : ".");
+
+my %paths;
+my %sources;
+my %includes;
+
+sub wanted
+{
+ my $file = $_;
+
+ if ($file eq "icu") {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ if ($file !~ /^\./ && $file =~ /\.(h|cpp|c|mm|m)$/) {
+ $paths{$file} = $File::Find::name;
+ $sources{$file} = $File::Find::name if $file !~ /\.h/;
+ open FILE, $file or die;
+ while (<FILE>) {
+ if (m-^\s*#\s*(include|import)\s+["<]((\S+/)*)(\S+)[">]-) {
+ my $include = ($2 eq "sys/" ? $2 : "") . $4;
+ $includes{$file}{$include}++;
+ }
+ }
+ close FILE;
+ }
+}
+
+my %totalIncludes;
+
+sub fillOut
+{
+ my ($file) = @_;
+
+ return if defined $totalIncludes{$file};
+
+ for my $include (keys %{ $includes{$file} }) {
+ $totalIncludes{$file}{$include} = 1;
+ fillOut($include);
+ for my $i (keys %{ $totalIncludes{$include} }) {
+ $totalIncludes{$file}{$i} = 1;
+ }
+ }
+}
+
+my %inclusionCounts;
+for my $file (keys %includes) {
+ $inclusionCounts{$file} = 0;
+ fillOut($file);
+}
+
+for my $file (keys %sources) {
+ for my $include (keys %{ $totalIncludes{$file} }) {
+ $inclusionCounts{$include}++;
+ }
+}
+
+for my $file (sort mostincludedcmp keys %includes) {
+ next if !$paths{$file};
+ my $count = $inclusionCounts{$file};
+ my $numIncludes = keys %{ $includes{$file} };
+ my $numTotalIncludes = keys %{ $totalIncludes{$file} };
+ print "$file is included $count times, includes $numIncludes files directly, $numTotalIncludes files total.\n"
+}
+
+# Sort most-included files first.
+sub mostincludedcmp($$)
+{
+ my ($filea, $fileb) = @_;
+
+ my $counta = $inclusionCounts{$filea} || 0;
+ my $countb = $inclusionCounts{$fileb} || 0;
+ return $countb <=> $counta if $counta != $countb;
+
+ my $ta = keys %{ $totalIncludes{$filea} };
+ my $tb = keys %{ $totalIncludes{$fileb} };
+ return $ta <=> $tb if $ta != $tb;
+
+ return $filea cmp $fileb;
+}
diff --git a/WebKitTools/Scripts/resolve-ChangeLogs b/WebKitTools/Scripts/resolve-ChangeLogs
new file mode 100755
index 0000000..306565c
--- /dev/null
+++ b/WebKitTools/Scripts/resolve-ChangeLogs
@@ -0,0 +1,513 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Merge and resolve ChangeLog conflicts for svn and git repositories
+
+use strict;
+
+use FindBin;
+use lib $FindBin::Bin;
+
+use File::Basename;
+use File::Path;
+use File::Spec;
+use Getopt::Long;
+use POSIX;
+use VCSUtils;
+
+sub conflictFiles($);
+sub findChangeLog($);
+sub findUnmergedChangeLogs();
+sub fixChangeLogPatch($);
+sub fixMergedChangeLogs($;@);
+sub fixOneMergedChangeLog($);
+sub mergeChanges($$$);
+sub parseFixMerged($$;$);
+sub removeChangeLogArguments();
+sub resolveChangeLog($);
+sub resolveConflict($);
+sub showStatus($;$);
+sub usageAndExit();
+
+my $isGit = isGit();
+my $isSVN = isSVN();
+
+my $SVN = "svn";
+my $GIT = "git";
+
+my $fixMerged;
+my $printWarnings = 1;
+my $showHelp;
+
+my $getOptionsResult = GetOptions(
+ 'f|fix-merged:s' => \&parseFixMerged,
+ 'h|help' => \$showHelp,
+ 'w|warnings!' => \$printWarnings,
+);
+
+my @changeLogFiles = removeChangeLogArguments();
+
+if (!defined $fixMerged && scalar(@changeLogFiles) == 0) {
+ @changeLogFiles = findUnmergedChangeLogs();
+}
+
+if (scalar(@ARGV) > 0) {
+ print STDERR "ERROR: Files listed on command-line that are not ChangeLogs.\n";
+ undef $getOptionsResult;
+} elsif (!defined $fixMerged && scalar(@changeLogFiles) == 0) {
+ print STDERR "ERROR: No ChangeLog files listed on command-line or found unmerged.\n";
+ undef $getOptionsResult;
+} elsif (defined $fixMerged && !$isGit) {
+ print STDERR "ERROR: --fix-merged may only be used with a git repository\n";
+ undef $getOptionsResult;
+}
+
+sub usageAndExit()
+{
+ print STDERR <<__END__;
+Usage: @{[ basename($0) ]} [options] [path/to/ChangeLog] [path/to/another/ChangeLog ...]
+ -f|--fix-merged [revision-range] fix git-merged ChangeLog entries; if a revision-range
+ is specified, run git filter-branch on the range
+ -h|--help show this help message
+ -w|--[no-]warnings show or suppress warnings (default: show warnings)
+__END__
+ exit 1;
+}
+
+if (!$getOptionsResult || $showHelp) {
+ usageAndExit();
+}
+
+if (defined $fixMerged && length($fixMerged) > 0) {
+ my $commitRange = $fixMerged;
+ $commitRange = $commitRange . "..HEAD" if index($commitRange, "..") < 0;
+ fixMergedChangeLogs($commitRange, @changeLogFiles);
+} elsif (@changeLogFiles) {
+ for my $file (@changeLogFiles) {
+ if (defined $fixMerged) {
+ fixOneMergedChangeLog($file);
+ } else {
+ resolveChangeLog($file);
+ }
+ }
+} else {
+ print STDERR "ERROR: Unknown combination of switches and arguments.\n";
+ usageAndExit();
+}
+
+exit 0;
+
+sub conflictFiles($)
+{
+ my ($file) = @_;
+ my $fileMine;
+ my $fileOlder;
+ my $fileNewer;
+
+ if (-e $file && -e "$file.orig" && -e "$file.rej") {
+ return ("$file.rej", "$file.orig", $file);
+ }
+
+ if ($isSVN) {
+ open STAT, "-|", $SVN, "status", $file || die;
+ my $status = <STAT>;
+ close STAT;
+ if (!$status || $status !~ m/^C\s+/) {
+ print STDERR "WARNING: ${file} is not in a conflicted state.\n" if $printWarnings;
+ return ();
+ }
+
+ $fileMine = "${file}.mine" if -e "${file}.mine";
+
+ my $currentRevision;
+ open INFO, "-|", $SVN, "info", $file || die;
+ while (my $line = <INFO>) {
+ $currentRevision = $1 if $line =~ m/^Revision: ([0-9]+)/;
+ }
+ close INFO;
+ $fileNewer = "${file}.r${currentRevision}" if -e "${file}.r${currentRevision}";
+
+ my @matchingFiles = grep { $_ ne $fileNewer } glob("${file}.r[0-9][0-9]*");
+ if (scalar(@matchingFiles) > 1) {
+ print STDERR "WARNING: Too many conflict files exist for ${file}!\n" if $printWarnings;
+ } else {
+ $fileOlder = shift @matchingFiles;
+ }
+ } elsif ($isGit) {
+ my $gitPrefix = `$GIT rev-parse --show-prefix`;
+ chomp $gitPrefix;
+ open GIT, "-|", $GIT, "ls-files", "--unmerged", $file || die;
+ while (my $line = <GIT>) {
+ my ($mode, $hash, $stage, $fileName) = split(' ', $line);
+ my $outputFile;
+ if ($stage == 1) {
+ $fileOlder = "${file}.BASE.$$";
+ $outputFile = $fileOlder;
+ } elsif ($stage == 2) {
+ $fileNewer = "${file}.LOCAL.$$";
+ $outputFile = $fileNewer;
+ } elsif ($stage == 3) {
+ $fileMine = "${file}.REMOTE.$$";
+ $outputFile = $fileMine;
+ } else {
+ die "Unknown file stage: $stage";
+ }
+ system("$GIT cat-file blob :${stage}:${gitPrefix}${file} > $outputFile");
+ }
+ close GIT;
+ } else {
+ die "Unknown version control system";
+ }
+
+ if (!$fileMine && !$fileOlder && !$fileNewer) {
+ print STDERR "WARNING: ${file} does not need merging.\n" if $printWarnings;
+ } elsif (!$fileMine || !$fileOlder || !$fileNewer) {
+ print STDERR "WARNING: ${file} is missing some conflict files.\n" if $printWarnings;
+ }
+
+ return ($fileMine, $fileOlder, $fileNewer);
+}
+
+sub findChangeLog($)
+{
+ return $_[0] if basename($_[0]) eq "ChangeLog";
+
+ my $file = File::Spec->catfile($_[0], "ChangeLog");
+ return $file if -d $_[0] and -e $file;
+
+ return undef;
+}
+
+sub findUnmergedChangeLogs()
+{
+ my $statCommand = "";
+
+ if ($isSVN) {
+ $statCommand = "$SVN stat | grep '^C'";
+ } elsif ($isGit) {
+ $statCommand = "$GIT diff -r --name-status --diff-filter=U -C -C -M";
+ } else {
+ return ();
+ }
+
+ my @results = ();
+ open STAT, "-|", $statCommand or die "The status failed: $!.\n";
+ while (<STAT>) {
+ if ($isSVN) {
+ if (/^([C]).{5} (.+)$/) {
+ my $file = findChangeLog($2);
+ push @results, $file if $file;
+ } else {
+ print; # error output from svn stat
+ }
+ } elsif ($isGit) {
+ if (/^([U])\t(.+)$/) {
+ my $file = findChangeLog($2);
+ push @results, $file if $file;
+ } else {
+ print; # error output from git diff
+ }
+ }
+ }
+ close STAT;
+
+ return @results;
+}
+
+sub fixChangeLogPatch($)
+{
+ my $patch = shift;
+ my $contextLineCount = 3;
+
+ return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
+ my ($oldLineCount, $newLineCount) = ($1, $2);
+ return $patch if $oldLineCount <= $contextLineCount;
+
+ # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
+ # have lines of context at the top of a patch when the existing entry has the same
+ # date and author as the new entry. This nifty loop alters a ChangeLog patch so
+ # that the added lines ("+") in the patch always start at the beginning of the
+ # patch and there are no initial lines of context.
+ my $newPatch;
+ my $lineCountInState = 0;
+ my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
+ my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
+ my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
+ my $state = $stateHeader;
+ foreach my $line (split(/\n/, $patch)) {
+ $lineCountInState++;
+ if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
+ $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
+ $lineCountInState = 0;
+ $state = $statePreContext;
+ } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
+ $line = "+" . substr($line, 1);
+ if ($lineCountInState == $oldContentLineCountReduction) {
+ $lineCountInState = 0;
+ $state = $stateNewChanges;
+ }
+ } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
+ # No changes to these lines
+ if ($lineCountInState == $newContentLineCountWithoutContext) {
+ $lineCountInState = 0;
+ $state = $statePostContext;
+ }
+ } elsif ($state == $statePostContext) {
+ if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
+ $line = " " . substr($line, 1);
+ } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
+ next; # Discard
+ }
+ }
+ $newPatch .= $line . "\n";
+ }
+
+ return $newPatch;
+}
+
+sub fixMergedChangeLogs($;@)
+{
+ my $revisionRange = shift;
+ my @changedFiles = @_;
+
+ if (scalar(@changedFiles) < 1) {
+ # Read in list of files changed in $revisionRange
+ open GIT, "-|", $GIT, "diff", "--name-only", $revisionRange || die;
+ push @changedFiles, <GIT>;
+ close GIT || die;
+ die "No changed files in $revisionRange" if scalar(@changedFiles) < 1;
+ chomp @changedFiles;
+ }
+
+ my @changeLogs = grep { defined $_ } map { findChangeLog($_) } @changedFiles;
+ die "No changed ChangeLog files in $revisionRange" if scalar(@changeLogs) < 1;
+
+ system("$GIT filter-branch --tree-filter 'PREVIOUS_COMMIT=\`$GIT rev-parse \$GIT_COMMIT^\` && MAPPED_PREVIOUS_COMMIT=\`map \$PREVIOUS_COMMIT\` $0 -f \"" . join('" "', @changeLogs) . "\"' $revisionRange");
+
+ # On success, remove the backup refs directory
+ if (WEXITSTATUS($?) == 0) {
+ rmtree(qw(.git/refs/original));
+ }
+}
+
+sub fixOneMergedChangeLog($)
+{
+ my $file = shift;
+ my $patch;
+
+ # Read in patch for incorrectly merged ChangeLog entry
+ {
+ local $/ = undef;
+ open GIT, "-|", $GIT, "diff", ($ENV{GIT_COMMIT} || "HEAD") . "^", $file || die;
+ $patch = <GIT>;
+ close GIT || die;
+ }
+
+ # Always checkout the previous commit's copy of the ChangeLog
+ system($GIT, "checkout", $ENV{MAPPED_PREVIOUS_COMMIT} || "HEAD^", $file);
+
+ # The patch must have 0 or more lines of context, then 1 or more lines
+ # of additions, and then 1 or more lines of context. If not, we skip it.
+ if ($patch =~ /\n@@ -(\d+),(\d+) \+(\d+),(\d+) @@\n( .*\n)*((\+.*\n)+)( .*\n)+$/m) {
+ # Copy the header from the original patch.
+ my $newPatch = substr($patch, 0, index($patch, "@@ -${1},${2} +${3},${4} @@"));
+
+ # Generate a new set of line numbers and patch lengths. Our new
+ # patch will start with the lines for the fixed ChangeLog entry,
+ # then have 3 lines of context from the top of the current file to
+ # make the patch apply cleanly.
+ $newPatch .= "@@ -1,3 +1," . ($4 - $2 + 3) . " @@\n";
+
+ # We assume that top few lines of the ChangeLog entry are actually
+ # at the bottom of the list of added lines (due to the way the patch
+ # algorithm works), so we simply search through the lines until we
+ # find the date line, then move the rest of the lines to the top.
+ my @patchLines = map { $_ . "\n" } split(/\n/, $6);
+ foreach my $i (0 .. $#patchLines) {
+ if ($patchLines[$i] =~ /^\+\d{4}-\d{2}-\d{2} /) {
+ unshift(@patchLines, splice(@patchLines, $i, scalar(@patchLines) - $i));
+ last;
+ }
+ }
+
+ $newPatch .= join("", @patchLines);
+
+ # Add 3 lines of context to the end
+ open FILE, "<", $file || die;
+ for (my $i = 0; $i < 3; $i++) {
+ $newPatch .= " " . <FILE>;
+ }
+ close FILE;
+
+ # Apply the new patch
+ open(PATCH, "| patch -p1 $file > /dev/null") || die;
+ print PATCH $newPatch;
+ close(PATCH) || die;
+
+ # Run "git add" on the fixed ChangeLog file
+ system($GIT, "add", $file);
+
+ showStatus($file, 1);
+ } elsif ($patch) {
+ # Restore the current copy of the ChangeLog file since we can't repatch it
+ system($GIT, "checkout", $ENV{GIT_COMMIT} || "HEAD", $file);
+ print STDERR "WARNING: Last change to ${file} could not be fixed and re-merged.\n" if $printWarnings;
+ }
+}
+
+sub mergeChanges($$$)
+{
+ my ($fileMine, $fileOlder, $fileNewer) = @_;
+
+ my $traditionalReject = $fileMine =~ /\.rej$/ ? 1 : 0;
+
+ local $/ = undef;
+
+ my $patch;
+ if ($traditionalReject) {
+ open(DIFF, "<", $fileMine);
+ $patch = <DIFF>;
+ close(DIFF);
+ rename($fileMine, "$fileMine.save");
+ rename($fileOlder, "$fileOlder.save");
+ } else {
+ open(DIFF, "-|", qw(diff -u), $fileOlder, $fileMine) || die;
+ $patch = <DIFF>;
+ close(DIFF);
+ }
+
+ unlink("${fileNewer}.orig");
+ unlink("${fileNewer}.rej");
+
+ open(PATCH, "| patch --fuzz=3 $fileNewer > /dev/null") || die;
+ print PATCH fixChangeLogPatch($patch);
+ close(PATCH);
+
+ my $result;
+
+ # Refuse to merge the patch if it did not apply cleanly
+ if (-e "${fileNewer}.rej") {
+ unlink("${fileNewer}.rej");
+ unlink($fileNewer);
+ rename("${fileNewer}.orig", $fileNewer);
+ $result = 0;
+ } else {
+ unlink("${fileNewer}.orig");
+ $result = 1;
+ }
+
+ if ($traditionalReject) {
+ rename("$fileMine.save", $fileMine);
+ rename("$fileOlder.save", $fileOlder);
+ }
+
+ return $result;
+}
+
+sub parseFixMerged($$;$)
+{
+ my ($switchName, $key, $value) = @_;
+ if (defined $key) {
+ if (defined findChangeLog($key)) {
+ unshift(@ARGV, $key);
+ $fixMerged = "";
+ } else {
+ $fixMerged = $key;
+ }
+ } else {
+ $fixMerged = "";
+ }
+}
+
+sub removeChangeLogArguments()
+{
+ my @results = ();
+
+ for (my $i = 0; $i < scalar(@ARGV); ) {
+ my $file = findChangeLog($ARGV[$i]);
+ if (defined $file) {
+ splice(@ARGV, $i, 1);
+ push @results, $file;
+ } else {
+ $i++;
+ }
+ }
+
+ return @results;
+}
+
+sub resolveChangeLog($)
+{
+ my ($file) = @_;
+
+ my ($fileMine, $fileOlder, $fileNewer) = conflictFiles($file);
+
+ return unless $fileMine && $fileOlder && $fileNewer;
+
+ if (mergeChanges($fileMine, $fileOlder, $fileNewer)) {
+ if ($file ne $fileNewer) {
+ unlink($file);
+ rename($fileNewer, $file) || die;
+ }
+ unlink($fileMine, $fileOlder);
+ resolveConflict($file);
+ showStatus($file, 1);
+ } else {
+ showStatus($file);
+ print STDERR "WARNING: ${file} could not be merged using fuzz level 3.\n" if $printWarnings;
+ unlink($fileMine, $fileOlder, $fileNewer) if $isGit;
+ }
+}
+
+sub resolveConflict($)
+{
+ my ($file) = @_;
+
+ if ($isSVN) {
+ system($SVN, "resolved", $file);
+ } elsif ($isGit) {
+ system($GIT, "add", $file);
+ } else {
+ die "Unknown version control system";
+ }
+}
+
+sub showStatus($;$)
+{
+ my ($file, $isConflictResolved) = @_;
+
+ if ($isSVN) {
+ system($SVN, "status", $file);
+ } elsif ($isGit) {
+ my @args = qw(--name-status);
+ unshift @args, qw(--cached) if $isConflictResolved;
+ system($GIT, "diff", @args, $file);
+ } else {
+ die "Unknown version control system";
+ }
+}
diff --git a/WebKitTools/Scripts/run-drawtest b/WebKitTools/Scripts/run-drawtest
new file mode 100755
index 0000000..2cd61de
--- /dev/null
+++ b/WebKitTools/Scripts/run-drawtest
@@ -0,0 +1,47 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Simplified "run" script for WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+my $productDir = productDir();
+
+# Check to see that all the frameworks are built (w/ SVG support).
+checkFrameworks();
+checkWebCoreSVGSupport(1);
+
+# Set up DYLD_FRAMEWORK_PATH to point to the product directory.
+print "Start DrawTest with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+my $drawtestPath = "$productDir/DrawTest.app/Contents/MacOS/DrawTest";
+exec $drawtestPath or die;
diff --git a/WebKitTools/Scripts/run-iexploder-tests b/WebKitTools/Scripts/run-iexploder-tests
new file mode 100755
index 0000000..f5e8a6c
--- /dev/null
+++ b/WebKitTools/Scripts/run-iexploder-tests
@@ -0,0 +1,172 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# A script to semi-automatically run iExploder tests.
+
+use strict;
+use warnings;
+
+use Cwd;
+use FindBin;
+use Getopt::Long;
+use IPC::Open2;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub openHTTPDIfNeeded();
+sub closeHTTPD();
+sub runSafariWithIExploder();
+
+# Argument handling
+my $guardMalloc = '';
+my $httpdPort = 8000;
+my $downloadTest;
+
+GetOptions(
+ 'guard-malloc|g' => \$guardMalloc,
+ 'get=s' => \$downloadTest,
+ 'port=i' => \$httpdPort
+);
+
+
+setConfiguration();
+my $productDir = productDir();
+
+chdirWebKit();
+
+checkFrameworks();
+
+my $httpdOpen = 0;
+openHTTPDIfNeeded();
+
+if ($downloadTest) {
+ system "/usr/bin/curl -o ~/Desktop/iexploder$downloadTest.html \"http://127.0.0.1:$httpdPort/iexploder.cgi?lookup=1&test=$downloadTest\"";
+ print "Saved the test as iexploder$downloadTest.html on the desktop\n";
+} else {
+ runSafariWithIExploder();
+ print "Last generated tests:\n";
+ system "grep 'iexploder.cgi' /tmp/WebKit/access_log.txt | tail -n -5 | awk -F'[ =&\\?]' '{if (\$8 == \"lookup\") print \$11; else print \$9}'";
+}
+
+closeHTTPD();
+
+
+sub runSafariWithIExploder()
+{
+ my $redirectTo;
+ if (@ARGV) {
+ $redirectTo = "http://127.0.0.1:$httpdPort/iexploder.cgi?lookup=1&test=$ARGV[0]";
+ } else {
+ $redirectTo = "http://127.0.0.1:$httpdPort/index.html";
+ }
+
+ open REDIRECT_HTML, ">", "/tmp/WebKit/redirect.html" or die;
+ print REDIRECT_HTML "<html>\n";
+ print REDIRECT_HTML " <head>\n";
+ print REDIRECT_HTML " <meta http-equiv=\"refresh\" content=\"1;URL=$redirectTo\" />\n";
+ print REDIRECT_HTML " <script type=\"text/javascript\">\n";
+ print REDIRECT_HTML " document.location = \"$redirectTo\";\n";
+ print REDIRECT_HTML " </script>\n";
+ print REDIRECT_HTML " </head>\n";
+ print REDIRECT_HTML " <body>\n";
+ print REDIRECT_HTML " </body>\n";
+ print REDIRECT_HTML "</html>\n";
+ close REDIRECT_HTML;
+
+ local %ENV;
+ $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc;
+ system "WebKitTools/Scripts/run-safari", "-NSOpen", "/tmp/WebKit/redirect.html";
+}
+
+sub openHTTPDIfNeeded()
+{
+ return if $httpdOpen;
+
+ mkdir "/tmp/WebKit";
+
+ if (-f "/tmp/WebKit/httpd.pid") {
+ my $oldPid = `cat /tmp/WebKit/httpd.pid`;
+ chomp $oldPid;
+ if (0 != kill 0, $oldPid) {
+ print "\nhttpd is already running: pid $oldPid, killing...\n";
+ kill 15, $oldPid;
+
+ my $retryCount = 20;
+ while ((0 != kill 0, $oldPid) && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to quit" unless $retryCount;
+ }
+ }
+
+ my $testDirectory = getcwd() . "/LayoutTests";
+ my $iExploderDirectory = getcwd() . "/WebKitTools/iExploder";
+ my $httpdPath = "/usr/sbin/httpd";
+ my $httpdConfig = "$testDirectory/http/conf/httpd.conf";
+ $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|;
+ my $documentRoot = "$iExploderDirectory/htdocs";
+ my $typesConfig = "$testDirectory/http/conf/mime.types";
+ my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+ my $listen = "127.0.0.1:$httpdPort";
+
+ open2(\*HTTPDIN, \*HTTPDOUT, $httpdPath,
+ "-f", "$httpdConfig",
+ "-C", "DocumentRoot \"$documentRoot\"",
+ "-C", "Listen $listen",
+ "-c", "TypesConfig \"$typesConfig\"",
+ "-c", "CustomLog \"/tmp/WebKit/access_log.txt\" common",
+ "-c", "ErrorLog \"/tmp/WebKit/error_log.txt\"",
+ "-c", "SSLCertificateFile \"$sslCertificate\"",
+ # Apache wouldn't run CGIs with permissions==700 otherwise
+ "-c", "User \"#$<\"");
+
+ my $retryCount = 20;
+ while (system("/usr/bin/curl -q --silent --stderr - --output /dev/null $listen") && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to start" unless $retryCount;
+
+ $httpdOpen = 1;
+}
+
+sub closeHTTPD()
+{
+ return if !$httpdOpen;
+
+ close HTTPDIN;
+ close HTTPDOUT;
+
+ kill 15, `cat /tmp/WebKit/httpd.pid` if -f "/tmp/WebKit/httpd.pid";
+
+ $httpdOpen = 0;
+}
diff --git a/WebKitTools/Scripts/run-javascriptcore-tests b/WebKitTools/Scripts/run-javascriptcore-tests
new file mode 100755
index 0000000..c0cb9a4
--- /dev/null
+++ b/WebKitTools/Scripts/run-javascriptcore-tests
@@ -0,0 +1,184 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to run the WebKit Open Source Project JavaScriptCore tests (adapted from Mozilla).
+
+use strict;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# determine configuration
+setConfiguration();
+my $configuration = configuration();
+
+my $jsDriverArgs = "";
+my $root; # intentionally left undefined
+my $showHelp = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --jsDriver-args= A string of arguments to pass to jsDriver.pl
+ --root= Path to pre-built root containing jsc
+EOF
+
+GetOptions(
+ 'j|jsDriver-args=s' => \$jsDriverArgs,
+ 'root=s' => \$root,
+ 'help' => \$showHelp
+);
+
+# Assume any arguments left over from GetOptions are assumed to be build arguments
+my @buildArgs = @ARGV;
+
+# Arguments passed to --jsDriver-args (if any) are passed to jsDriver.pl
+my @jsArgs = split(" ", $jsDriverArgs);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
+
+if (!defined($root)){
+ chdirWebKit();
+
+ push(@buildArgs, argumentsForConfiguration());
+
+ print "Running: build-jsc " . join(" ", @buildArgs) . "\n";
+ my $buildResult = system "perl", "WebKitTools/Scripts/build-jsc", @buildArgs;
+ if ($buildResult) {
+ print STDERR "Compiling jsc failed!\n";
+ exit exitStatus($buildResult);
+ }
+}
+
+
+my $productDir = productDir();
+
+$productDir .= "/JavaScriptCore" if isQt();
+$productDir .= "/Programs" if isGtk();
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+setPathForRunningWebKitApp(\%ENV) if isCygwin();
+
+sub jscPath($)
+{
+ my ($productDir) = @_;
+ my $jscName = "jsc";
+ $jscName .= "_debug" if (isCygwin() && ($configuration eq "Debug"));
+ return "$productDir/$jscName";
+}
+
+sub testapiPath($)
+{
+ my ($productDir) = @_;
+ my $jscName = "testapi";
+ $jscName .= "_debug" if (isCygwin() && ($configuration eq "Debug"));
+ return "$productDir/$jscName";
+}
+
+#run api tests
+if (isAppleMacWebKit()) {
+ chdirWebKit();
+ chdir($productDir) or die;
+ my $testapiResult = system testapiPath($productDir);
+ exit exitStatus($testapiResult) if $testapiResult;
+}
+
+# Find JavaScriptCore directory
+chdirWebKit();
+chdir("JavaScriptCore");
+chdir "tests/mozilla" or die;
+printf "Running: jsDriver.pl -e squirrelfish -s %s -f actual.html %s\n", jscPath($productDir), join(" ", @jsArgs);
+my $result = system "perl", "jsDriver.pl", "-e", "squirrelfish", "-s", jscPath($productDir), "-f", "actual.html", @jsArgs;
+exit exitStatus($result) if $result;
+
+my %failures;
+
+open EXPECTED, "expected.html" or die;
+while (<EXPECTED>) {
+ last if /failures reported\.$/;
+}
+while (<EXPECTED>) {
+ chomp;
+ $failures{$_} = 1;
+}
+close EXPECTED;
+
+my %newFailures;
+
+open ACTUAL, "actual.html" or die;
+while (<ACTUAL>) {
+ last if /failures reported\.$/;
+}
+while (<ACTUAL>) {
+ chomp;
+ if ($failures{$_}) {
+ delete $failures{$_};
+ } else {
+ $newFailures{$_} = 1;
+ }
+}
+close ACTUAL;
+
+my $numNewFailures = keys %newFailures;
+if ($numNewFailures) {
+ print "\n** Danger, Will Robinson! Danger! The following failures have been introduced:\n";
+ foreach my $failure (sort keys %newFailures) {
+ print "\t$failure\n";
+ }
+}
+
+my $numOldFailures = keys %failures;
+if ($numOldFailures) {
+ print "\nYou fixed the following test";
+ print "s" if $numOldFailures != 1;
+ print ":\n";
+ foreach my $failure (sort keys %failures) {
+ print "\t$failure\n";
+ }
+}
+
+print "\n";
+
+print "$numNewFailures regression";
+print "s" if $numNewFailures != 1;
+print " found.\n";
+
+print "$numOldFailures test";
+print "s" if $numOldFailures != 1;
+print " fixed.\n";
+
+print "OK.\n" if $numNewFailures == 0;
+exit(1) if $numNewFailures;
diff --git a/WebKitTools/Scripts/run-jsc b/WebKitTools/Scripts/run-jsc
new file mode 100755
index 0000000..20dc5e8
--- /dev/null
+++ b/WebKitTools/Scripts/run-jsc
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script runs a list of scripts through jsc a specified number of times.
+
+use strict;
+use warnings;
+use FindBin;
+use lib $FindBin::Bin;
+use Getopt::Long;
+use webkitdirs;
+
+my $usage = "Usage: run-jsc [--count run_count] [--verbose] shell_file [file2...]";
+
+my $count = 1;
+my $verbose = 0;
+GetOptions("count|c=i" => \$count,
+ "verbose|v" => \$verbose);
+die "$usage\n" if (@ARGV < 1);
+
+my $jsc = productDir() . "/jsc @ARGV";
+$jsc .= " 2> /dev/null" unless $verbose;
+
+my $dyld = productDir();
+
+$ENV{"DYLD_FRAMEWORK_PATH"} = $dyld;
+print STDERR "Running $count time(s): DYLD_FRAMEWORK_PATH=$dyld $jsc\n";
+while ($count--) {
+ if (system("$jsc") != 0) {
+ last;
+ }
+}
+
diff --git a/WebKitTools/Scripts/run-launcher b/WebKitTools/Scripts/run-launcher
new file mode 100755
index 0000000..9680cc2
--- /dev/null
+++ b/WebKitTools/Scripts/run-launcher
@@ -0,0 +1,67 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2007 Staikos Computing Services, Inc. <info@staikos.net>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Simplified "run" script for WebKit Open Source Project.
+
+use strict;
+use File::Spec::Functions qw/catdir/;
+use File::Temp qw/tempfile/;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+my $productDir = productDir();
+my $launcherPath = productDir();
+my @args = @ARGV;
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+# Set paths according to the build system used
+if (isQt()) {
+ my $libDir = catdir(productDir(), 'lib');
+ $launcherPath = catdir($launcherPath, "bin", "QtLauncher");
+
+ # Set up LD_LIBRARY_PATH to point to the product directory.
+ print "Starting webkit launcher with LD_LIBRARY_PATH set to point to built WebKit in $libDir.\n";
+
+ $ENV{LD_LIBRARY_PATH} = $ENV{LD_LIBRARY_PATH} ? "$libDir:$ENV{LD_LIBRARY_PATH}" : $libDir;
+ $ENV{DYLD_LIBRARY_PATH} = $ENV{DYLD_LIBRARY_PATH} ? "$libDir:$ENV{DYLD_LIBRARY_PATH}" : $libDir;
+} else {
+
+ if (isGtk()) {
+ $launcherPath = catdir($launcherPath, "Programs", "GtkLauncher");
+ }
+
+ print "Starting webkit launcher.\n";
+}
+
+exec $launcherPath, @args or die;
+
diff --git a/WebKitTools/Scripts/run-leaks b/WebKitTools/Scripts/run-leaks
new file mode 100755
index 0000000..d8f89d3
--- /dev/null
+++ b/WebKitTools/Scripts/run-leaks
@@ -0,0 +1,212 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to run the Mac OS X leaks tool with more expressive '-exclude' lists.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use Getopt::Long;
+
+sub runLeaks($);
+sub parseLeaksOutput(\@);
+sub removeMatchingRecords(\@$\@);
+sub reportError($);
+
+sub main()
+{
+ # Read options.
+ my $usage =
+ "Usage: " . basename($0) . " [options] pid | executable name\n" .
+ " --exclude-callstack regexp Exclude leaks whose call stacks match the regular expression 'regexp'.\n" .
+ " --exclude-type regexp Exclude leaks whose data types match the regular expression 'regexp'.\n" .
+ " --help Show this help message.\n";
+
+ my @callStacksToExclude = ();
+ my @typesToExclude = ();
+ my $help = 0;
+
+ my $getOptionsResult = GetOptions(
+ 'exclude-callstack:s' => \@callStacksToExclude,
+ 'exclude-type:s' => \@typesToExclude,
+ 'help' => \$help
+ );
+ my $pidOrExecutableName = $ARGV[0];
+
+ if (!$getOptionsResult || $help) {
+ print STDERR $usage;
+ return 1;
+ }
+
+ if (!$pidOrExecutableName) {
+ reportError("Missing argument: pid | executable.");
+ print STDERR $usage;
+ return 1;
+ }
+
+ # Run leaks tool.
+ my $leaksOutput = runLeaks($pidOrExecutableName);
+ if (!$leaksOutput) {
+ return 1;
+ }
+
+ my $leakList = parseLeaksOutput(@$leaksOutput);
+ if (!$leakList) {
+ return 1;
+ }
+
+ # Filter output.
+ my $leakCount = @$leakList;
+ removeMatchingRecords(@$leakList, "callStack", @callStacksToExclude);
+ removeMatchingRecords(@$leakList, "type", @typesToExclude);
+ my $excludeCount = $leakCount - @$leakList;
+
+ # Dump results.
+ print $leaksOutput->[0];
+ print $leaksOutput->[1];
+ foreach my $leak (@$leakList) {
+ print $leak->{"leaksOutput"};
+ }
+
+ if ($excludeCount) {
+ print "$excludeCount leaks excluded (not printed)\n";
+ }
+
+ return 0;
+}
+
+exit(main());
+
+# Returns the output of the leaks tool in list form.
+sub runLeaks($)
+{
+ my ($pidOrExecutableName) = @_;
+
+ my @leaksOutput = `leaks $pidOrExecutableName`;
+ if (!@leaksOutput) {
+ reportError("Error running leaks tool.");
+ return;
+ }
+
+ return \@leaksOutput;
+}
+
+# Returns a list of hash references with the keys { address, size, type, callStack, leaksOutput }
+sub parseLeaksOutput(\@)
+{
+ my ($leaksOutput) = @_;
+
+ # Format:
+ # Process 00000: 1234 nodes malloced for 1234 KB
+ # Process 00000: XX leaks for XXX total leaked bytes.
+ # Leak: 0x00000000 size=1234 [instance of 'blah']
+ # 0x00000000 0x00000000 0x00000000 0x00000000 a..d.e.e
+ # ...
+ # Call stack: leak_caller() | leak() | malloc
+ #
+ # We treat every line except for Process 00000: and Leak: as optional
+
+ my ($leakCount) = ($leaksOutput->[1] =~ /[[:blank:]]+([0-9]+)[[:blank:]]+leaks?/);
+ if (!defined($leakCount)) {
+ reportError("Could not parse leak count reported by leaks tool.");
+ return;
+ }
+
+ my @leakList = ();
+ for my $line (@$leaksOutput) {
+ next if $line =~ /^Process/;
+ next if $line =~ /^node buffer added/;
+
+ if ($line =~ /^Leak: /) {
+ my ($address) = ($line =~ /Leak: ([[:xdigit:]x]+)/);
+ if (!defined($address)) {
+ reportError("Could not parse Leak address.");
+ return;
+ }
+
+ my ($size) = ($line =~ /size=([[:digit:]]+)/);
+ if (!defined($size)) {
+ reportError("Could not parse Leak size.");
+ return;
+ }
+
+ my ($type) = ($line =~ /'([^']+)'/); #'
+ if (!defined($type)) {
+ $type = ""; # The leaks tool sometimes omits the type.
+ }
+
+ my %leak = (
+ "address" => $address,
+ "size" => $size,
+ "type" => $type,
+ "callStack" => "", # The leaks tool sometimes omits the call stack.
+ "leaksOutput" => $line
+ );
+ push(@leakList, \%leak);
+ } else {
+ $leakList[$#leakList]->{"leaksOutput"} .= $line;
+ if ($line =~ /Call stack:/) {
+ $leakList[$#leakList]->{"callStack"} = $line;
+ }
+ }
+ }
+
+ if (@leakList != $leakCount) {
+ my $parsedLeakCount = @leakList;
+ reportError("Parsed leak count($parsedLeakCount) does not match leak count reported by leaks tool($leakCount).");
+ return;
+ }
+
+ return \@leakList;
+}
+
+sub removeMatchingRecords(\@$\@)
+{
+ my ($recordList, $key, $regexpList) = @_;
+
+ RECORD: for (my $i = 0; $i < @$recordList;) {
+ my $record = $recordList->[$i];
+
+ foreach my $regexp (@$regexpList) {
+ if ($record->{$key} =~ $regexp) {
+ splice(@$recordList, $i, 1);
+ next RECORD;
+ }
+ }
+
+ $i++;
+ }
+}
+
+sub reportError($)
+{
+ my ($errorMessage) = @_;
+
+ print STDERR basename($0) . ": $errorMessage\n";
+}
diff --git a/WebKitTools/Scripts/run-mangleme-tests b/WebKitTools/Scripts/run-mangleme-tests
new file mode 100755
index 0000000..93b7894
--- /dev/null
+++ b/WebKitTools/Scripts/run-mangleme-tests
@@ -0,0 +1,175 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# A script to semi-automatically run mangleme tests.
+
+use strict;
+use warnings;
+
+use Cwd;
+use FindBin;
+use Getopt::Long;
+use IPC::Open2;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub openHTTPDIfNeeded();
+sub closeHTTPD();
+sub runSafariWithMangleme();
+
+# Argument handling
+my $guardMalloc = '';
+my $httpdPort = 8000;
+my $downloadTest;
+
+GetOptions(
+ 'guard-malloc|g' => \$guardMalloc,
+ 'get=s' => \$downloadTest,
+ 'port=i' => \$httpdPort
+);
+
+
+setConfiguration();
+my $productDir = productDir();
+
+chdirWebKit();
+
+checkFrameworks();
+
+mkdir "WebKitBuild/mangleme";
+(system "/usr/bin/make", "-C", "WebKitTools/mangleme") == 0 or die;
+
+my $httpdOpen = 0;
+openHTTPDIfNeeded();
+
+if ($downloadTest) {
+ system "/usr/bin/curl -o ~/Desktop/mangleme$downloadTest.html http://127.0.0.1:$httpdPort/remangle.cgi?$downloadTest";
+ print "Saved the test as mangleme$downloadTest.html on the desktop\n";
+} else {
+ runSafariWithMangleme();
+ print "Last generated tests:\n";
+ system "grep 'Mangle attempt' /tmp/WebKit/error_log.txt | tail -n -5 | awk ' {print \$4}'";
+}
+
+closeHTTPD();
+
+
+sub runSafariWithMangleme()
+{
+ my $redirectTo;
+ if (@ARGV) {
+ $redirectTo = "http://127.0.0.1:$httpdPort/remangle.cgi?$ARGV[0]";
+ } else {
+ $redirectTo = "http://127.0.0.1:$httpdPort/mangle.cgi";
+ }
+
+ open REDIRECT_HTML, ">", "/tmp/WebKit/redirect.html" or die;
+ print REDIRECT_HTML "<html>\n";
+ print REDIRECT_HTML " <head>\n";
+ print REDIRECT_HTML " <meta http-equiv=\"refresh\" content=\"1;URL=$redirectTo\" />\n";
+ print REDIRECT_HTML " <script type=\"text/javascript\">\n";
+ print REDIRECT_HTML " document.location = \"$redirectTo\";\n";
+ print REDIRECT_HTML " </script>\n";
+ print REDIRECT_HTML " </head>\n";
+ print REDIRECT_HTML " <body>\n";
+ print REDIRECT_HTML " </body>\n";
+ print REDIRECT_HTML "</html>\n";
+ close REDIRECT_HTML;
+
+ local %ENV;
+ $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc;
+ system "WebKitTools/Scripts/run-safari", "-NSOpen", "/tmp/WebKit/redirect.html";
+}
+
+sub openHTTPDIfNeeded()
+{
+ return if $httpdOpen;
+
+ mkdir "/tmp/WebKit";
+
+ if (-f "/tmp/WebKit/httpd.pid") {
+ my $oldPid = `cat /tmp/WebKit/httpd.pid`;
+ chomp $oldPid;
+ if (0 != kill 0, $oldPid) {
+ print "\nhttpd is already running: pid $oldPid, killing...\n";
+ kill 15, $oldPid;
+
+ my $retryCount = 20;
+ while ((0 != kill 0, $oldPid) && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to quit" unless $retryCount;
+ }
+ }
+
+ my $testDirectory = getcwd() . "/LayoutTests";
+ my $manglemeDirectory = getcwd() . "/WebKitBuild/mangleme";
+ my $httpdPath = "/usr/sbin/httpd";
+ my $httpdConfig = "$testDirectory/http/conf/httpd.conf";
+ $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|;
+ my $documentRoot = "$manglemeDirectory";
+ my $typesConfig = "$testDirectory/http/conf/mime.types";
+ my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+ my $listen = "127.0.0.1:$httpdPort";
+
+ open2(\*HTTPDIN, \*HTTPDOUT, $httpdPath,
+ "-f", "$httpdConfig",
+ "-C", "DocumentRoot \"$documentRoot\"",
+ "-C", "Listen $listen",
+ "-c", "TypesConfig \"$typesConfig\"",
+ "-c", "CustomLog \"/tmp/WebKit/access_log.txt\" common",
+ "-c", "ErrorLog \"/tmp/WebKit/error_log.txt\"",
+ "-c", "SSLCertificateFile \"$sslCertificate\"",
+ # Apache wouldn't run CGIs with permissions==700 otherwise
+ "-c", "User \"#$<\"");
+
+ my $retryCount = 20;
+ while (system("/usr/bin/curl -q --silent --stderr - --output /dev/null $listen") && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to start" unless $retryCount;
+
+ $httpdOpen = 1;
+}
+
+sub closeHTTPD()
+{
+ return if !$httpdOpen;
+
+ close HTTPDIN;
+ close HTTPDOUT;
+
+ kill 15, `cat /tmp/WebKit/httpd.pid` if -f "/tmp/WebKit/httpd.pid";
+
+ $httpdOpen = 0;
+}
diff --git a/WebKitTools/Scripts/run-pageloadtest b/WebKitTools/Scripts/run-pageloadtest
new file mode 100755
index 0000000..ad6daa1
--- /dev/null
+++ b/WebKitTools/Scripts/run-pageloadtest
@@ -0,0 +1,92 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006 Eric Seidel (eric@webkit.org)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to run the WebKit Open Source Project page load tests (PLTs).
+
+# Run all the tests passed in on the command line.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Spec;
+use FindBin;
+use Getopt::Long;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+# Argument handling
+my $testName = 'svg';
+my $showHelp = 0;
+
+my $usage =
+ "Usage: " . basename($0) . "[options] testName\n" .
+ " --help Show this help message\n";
+
+my $getOptionsResult = GetOptions('help' => \$showHelp);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+$testName = shift @ARGV if (@ARGV);
+
+my $safariExecutablePath = safariPath();
+my $safariResourcePath = File::Spec->catdir(dirname(dirname($safariExecutablePath)), "Resources");
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+chdirWebKit();
+
+if ($testName eq 'svg') {
+ my $suiteFile = "PageLoadTests/$testName/$testName.pltsuite";
+ my $webkitPath = sourceDir();
+ `cat "$suiteFile" | perl -pe 's|WEBKIT_PATH|$webkitPath|' > $safariResourcePath/$testName.pltsuite`
+}
+
+die "Please copy ${testName}.pltsuite to ${safariResourcePath}/${testName}.pltsuite"
+ if (! -f "${safariResourcePath}/${testName}.pltsuite");
+
+setConfiguration();
+
+my $productDir = productDir();
+
+# Set up DYLD_FRAMEWORK_PATH to point to the product directory.
+print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+
+my @testCommands = ('activate');
+# Autovicki would clear history, we skip that here as this is likely an active user account
+@testCommands = (@testCommands, ("run $testName", 'emptyCache', 'wait 30'));
+@testCommands = (@testCommands, (("run $testName", 'wait 10') x 3));
+my $testCommandsString = join('; ', @testCommands);
+exec $safariExecutablePath, '--test-commands', $testCommandsString or die;
diff --git a/WebKitTools/Scripts/run-safari b/WebKitTools/Scripts/run-safari
new file mode 100755
index 0000000..d850a4a
--- /dev/null
+++ b/WebKitTools/Scripts/run-safari
@@ -0,0 +1,41 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Simplified "run" script for WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+exit exitStatus(runSafari());
diff --git a/WebKitTools/Scripts/run-sunspider b/WebKitTools/Scripts/run-sunspider
new file mode 100755
index 0000000..2e58418
--- /dev/null
+++ b/WebKitTools/Scripts/run-sunspider
@@ -0,0 +1,131 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# determine configuration, but default to "Release" instead of last-used configuration
+setConfiguration("Release");
+setConfiguration();
+my $configuration = configuration();
+
+my $root;
+my $testRuns = 10; # This number may be different from what sunspider defaults to (that's OK)
+my $runShark = 0;
+my $runShark20 = 0;
+my $runSharkCache = 0;
+my $ubench = 0;
+my $v8 = 0;
+my $setBaseline = 0;
+my $showHelp = 0;
+my $testsPattern;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --set-baseline Set baseline for future comparisons
+ --root Path to root tools build
+ --runs Number of times to run tests (default: $testRuns)
+ --tests Only run tests matching provided pattern
+ --shark Sample with the Mac OS X "Shark" performance testing tool (implies --runs=1)
+ --shark20 Like --shark, but with a 20 microsecond sampling interval
+ --shark-cache Like --shark, but performs a L2 cache-miss sample instead of time sample
+ --ubench Use microbenchmark suite instead of regular tests (to check for core execution regressions)
+ --v8 Use the V8 benchmark suite.
+EOF
+
+GetOptions('root=s' => sub { my ($x, $value) = @_; $root = $value; setConfigurationProductDir(Cwd::abs_path($root)); },
+ 'runs=i' => \$testRuns,
+ 'set-baseline' => \$setBaseline,
+ 'shark' => \$runShark,
+ 'shark20' => \$runShark20,
+ 'shark-cache' => \$runSharkCache,
+ 'ubench' => \$ubench,
+ 'v8' => \$v8,
+ 'tests=s' => \$testsPattern,
+ 'help' => \$showHelp);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+sub buildJSC
+{
+ if (!defined($root)){
+ push(@ARGV, "--" . $configuration);
+
+ chdirWebKit();
+ my $buildResult = system "WebKitTools/Scripts/build-jsc", @ARGV;
+ if ($buildResult) {
+ print STDERR "Compiling jsc failed!\n";
+ exit exitStatus($buildResult);
+ }
+ }
+}
+
+sub setupEnvironmentForExecution($)
+{
+ my ($productDir) = @_;
+ print "Starting sunspider with DYLD_FRAMEWORK_PATH set to point to built JavaScriptCore in $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ # FIXME: Other platforms may wish to augment this method to use LD_LIBRARY_PATH, etc.
+}
+
+sub jscPath($)
+{
+ my ($productDir) = @_;
+ my $jscName = "jsc";
+ $jscName .= "_debug" if (isCygwin() && ($configuration eq "Debug"));
+ return "$productDir/$jscName";
+}
+
+buildJSC();
+
+chdirWebKit();
+chdir("SunSpider");
+
+my $productDir = productDir();
+# FIXME: This hack should be pushed down into productDir()
+$productDir .= "/JavaScriptCore" if (isQt() or isGtk());
+
+setupEnvironmentForExecution($productDir);
+my @args = ("--shell", jscPath($productDir), "--runs", $testRuns);
+# This code could be removed if we chose to pass extra args to sunspider instead of Xcode
+push @args, "--set-baseline" if $setBaseline;
+push @args, "--shark" if $runShark;
+push @args, "--shark20" if $runShark20;
+push @args, "--shark-cache" if $runSharkCache;
+push @args, "--ubench" if $ubench;
+push @args, "--v8" if $v8;
+push @args, "--tests", $testsPattern if $testsPattern;
+
+exec "./sunspider", @args;
diff --git a/WebKitTools/Scripts/run-webkit-app b/WebKitTools/Scripts/run-webkit-app
new file mode 100755
index 0000000..452c44c
--- /dev/null
+++ b/WebKitTools/Scripts/run-webkit-app
@@ -0,0 +1,50 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Simplified "run" script for WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+my $productDir = productDir();
+
+die "Did not specify an application to open (e.g. run-webkit-app AppName).\n" unless length($ARGV[0]) > 0;
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+# Set up DYLD_FRAMEWORK_PATH to point to the product directory.
+print "Start $ARGV[0] with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+
+unshift(@ARGV, "-a");
+exec "open", @ARGV;
diff --git a/WebKitTools/Scripts/run-webkit-httpd b/WebKitTools/Scripts/run-webkit-httpd
new file mode 100755
index 0000000..a64eef6
--- /dev/null
+++ b/WebKitTools/Scripts/run-webkit-httpd
@@ -0,0 +1,127 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to run Apache with the same configuration as used in http layout tests.
+
+use strict;
+use warnings;
+
+use Cwd;
+use File::Basename;
+use Getopt::Long;
+use FindBin;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+# Argument handling
+my $httpdPort = 8000;
+my $allInterfaces = 0;
+my $showHelp;
+
+my $result = GetOptions(
+ 'all-interfaces|a' => \$allInterfaces,
+ 'help|h' => \$showHelp,
+ 'port=i' => \$httpdPort,
+);
+
+if (!$result || @ARGV || $showHelp) {
+ print "Usage: " . basename($0) . " [options]\n";
+ print " -a|--all-interfaces Bind to all interfaces\n";
+ print " -h|--help Show this help message\n";
+ print " -p|--port NNNN Bind to port NNNN\n";
+ exit 1;
+}
+
+setConfiguration();
+my $productDir = productDir();
+chdirWebKit();
+
+mkdir "/tmp/WebKit";
+
+if (-f "/tmp/WebKit/httpd.pid") {
+ my $oldPid = `cat /tmp/WebKit/httpd.pid`;
+ chomp $oldPid;
+ if (0 != kill 0, $oldPid) {
+ print "\nhttpd is already running: pid $oldPid, killing...\n";
+ kill 15, $oldPid;
+
+ my $retryCount = 20;
+ while ((0 != kill 0, $oldPid) && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to quit" unless $retryCount;
+ }
+}
+
+my $testDirectory = getcwd() . "/LayoutTests";
+my $httpdPath = "/usr/sbin/httpd";
+$httpdPath = "/usr/sbin/apache2" if isDebianBased();
+my $httpdConfig = "$testDirectory/http/conf/httpd.conf";
+$httpdConfig = "$testDirectory/http/conf/cygwin-httpd.conf" if isCygwin();
+$httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|;
+$httpdConfig = "$testDirectory/http/conf/apache2-debian-httpd.conf" if isDebianBased();
+my $documentRoot = "$testDirectory/http/tests";
+my $typesConfig = "$testDirectory/http/conf/mime.types";
+my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+
+my $listen = "127.0.0.1:$httpdPort";
+$listen = "$httpdPort" if ($allInterfaces);
+
+if ($allInterfaces) {
+ print "Starting httpd on port $httpdPort (all interfaces)...\n";
+} else {
+ print "Starting httpd on <http://$listen/>...\n";
+}
+print "Press Ctrl+C to stop it.\n\n";
+
+my @args = (
+ "-f", "$httpdConfig",
+ "-C", "DocumentRoot \"$documentRoot\"",
+ "-C", "Listen $listen",
+ "-c", "TypesConfig \"$typesConfig\"",
+ "-c", "CustomLog |/usr/bin/tee common",
+ "-c", "ErrorLog |/usr/bin/tee",
+ # Apache wouldn't run CGIs with permissions==700 otherwise.
+ "-c", "User \"#$<\"",
+ # Run in single-process mode, do not detach from the controlling terminal.
+ "-X",
+ # Disable Keep-Alive support. Makes testing in multiple browsers easier (no need to wait
+ # for another browser's connection to expire).
+ "-c", "KeepAlive 0"
+);
+
+# FIXME: Enable this on Windows once <rdar://problem/5345985> is fixed
+push(@args, "-c", "SSLCertificateFile \"$sslCertificate\"") unless isCygwin();
+
+system($httpdPath, @args);
+
+unlink "/tmp/WebKit/httpd.pid";
diff --git a/WebKitTools/Scripts/run-webkit-nightly.cmd b/WebKitTools/Scripts/run-webkit-nightly.cmd
new file mode 100755
index 0000000..93037ab
--- /dev/null
+++ b/WebKitTools/Scripts/run-webkit-nightly.cmd
@@ -0,0 +1,10 @@
+@echo off
+set script="%TMP%\run-webkit-nightly2.cmd"
+set vsvars="%VS80COMNTOOLS%\vsvars32.bat"
+if exist %vsvars% (
+ copy %vsvars% "%script%"
+) else (
+ del "%script%"
+)
+FindSafari.exe %1 /printSafariLauncher >> "%script%"
+call %script%
diff --git a/WebKitTools/Scripts/run-webkit-tests b/WebKitTools/Scripts/run-webkit-tests
new file mode 100755
index 0000000..d6dae4e
--- /dev/null
+++ b/WebKitTools/Scripts/run-webkit-tests
@@ -0,0 +1,1895 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+# Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com)
+# Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to run the WebKit Open Source Project layout tests.
+
+# Run all the tests passed in on the command line.
+# If no tests are passed, find all the .html, .shtml, .xml, .xhtml, .pl, .php (and svg) files in the test directory.
+
+# Run each text.
+# Compare against the existing file xxx-expected.txt.
+# If there is a mismatch, generate xxx-actual.txt and xxx-diffs.txt.
+
+# At the end, report:
+# the number of tests that got the expected results
+# the number of tests that ran, but did not get the expected results
+# the number of tests that failed to run
+# the number of tests that were run but had no expected results to compare against
+
+use strict;
+use warnings;
+
+use Cwd;
+use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
+use File::Basename;
+use File::Copy;
+use File::Find;
+use File::Path;
+use File::Spec;
+use File::Spec::Functions;
+use FindBin;
+use Getopt::Long;
+use IPC::Open2;
+use IPC::Open3;
+use Time::HiRes qw(time usleep);
+
+use List::Util 'shuffle';
+
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+sub openDumpTool();
+sub closeDumpTool();
+sub dumpToolDidCrash();
+sub closeHTTPD();
+sub countAndPrintLeaks($$$);
+sub fileNameWithNumber($$);
+sub numericcmp($$);
+sub openHTTPDIfNeeded();
+sub pathcmp($$);
+sub processIgnoreTests($$);
+sub slowestcmp($$);
+sub splitpath($);
+sub stripExtension($);
+sub isTextOnlyTest($);
+sub expectedDirectoryForTest($;$;$);
+sub countFinishedTest($$$$);
+sub testCrashedOrTimedOut($$$$$);
+sub sampleDumpTool();
+sub printFailureMessageForTest($$);
+sub toURL($);
+sub toWindowsPath($);
+sub closeCygpaths();
+sub validateSkippedArg($$;$);
+sub htmlForResultsSection(\@$&);
+sub deleteExpectedAndActualResults($);
+sub recordActualResultsAndDiff($$);
+sub buildPlatformResultHierarchy();
+sub buildPlatformTestHierarchy(@);
+sub epiloguesAndPrologues($$);
+sub parseLeaksandPrintUniqueLeaks();
+sub readFromDumpToolWithTimer(*;$);
+sub setFileHandleNonBlocking(*$);
+sub writeToFile($$);
+
+# Argument handling
+my $addPlatformExceptions = 0;
+my $complexText = 0;
+my $guardMalloc = '';
+my $httpdPort = 8000;
+my $httpdSSLPort = 8443;
+my $ignoreTests = '';
+my $launchSafari = 1;
+my $platform;
+my $pixelTests = '';
+my $quiet = '';
+my $report10Slowest = 0;
+my $resetResults = 0;
+my $shouldCheckLeaks = 0;
+my $showHelp = 0;
+my $testsPerDumpTool;
+my $testHTTP = 1;
+my $testMedia = 1;
+my $testResultsDirectory = "/tmp/layout-test-results";
+my $threaded = 0;
+my $tolerance = 0;
+my $treatSkipped = "default";
+my $verbose = 0;
+my $useValgrind = 0;
+my $strictTesting = 0;
+my $generateNewResults = isAppleMacWebKit() ? 1 : 0;
+my $stripEditingCallbacks = isCygwin();
+my $runSample = 1;
+my $root;
+my $reverseTests = 0;
+my $randomizeTests = 0;
+my $mergeDepth;
+my @leaksFilenames;
+
+# Default to --no-http for Qt, Gtk and wx for now.
+$testHTTP = 0 if (isQt() || isGtk() || isWx());
+
+my $expectedTag = "expected";
+my $actualTag = "actual";
+my $diffsTag = "diffs";
+my $errorTag = "stderr";
+
+my @macPlatforms = ("mac-tiger", "mac-leopard", "mac-snowleopard", "mac");
+
+if (isTiger()) {
+ $platform = "mac-tiger";
+ $tolerance = 1.0;
+} elsif (isLeopard()) {
+ $platform = "mac-leopard";
+ $tolerance = 0.1;
+} elsif (isSnowLeopard()) {
+ $platform = "mac-snowleopard";
+ $tolerance = 0.1;
+} elsif (isAppleMacWebKit()) {
+ $platform = "mac";
+} elsif (isQt()) {
+ $platform = "qt";
+} elsif (isGtk()) {
+ $platform = "gtk";
+} elsif (isCygwin()) {
+ $platform = "win";
+}
+
+if (!defined($platform)) {
+ print "WARNING: Your platform is not recognized. Any platform-specific results will be generated in platform/undefined.\n";
+ $platform = "undefined";
+}
+
+my $programName = basename($0);
+my $launchSafariDefault = $launchSafari ? "launch" : "do not launch";
+my $httpDefault = $testHTTP ? "run" : "do not run";
+my $sampleDefault = $runSample ? "run" : "do not run";
+
+# FIXME: "--strict" should be renamed to qt-mac-comparison, or something along those lines.
+my $usage = <<EOF;
+Usage: $programName [options] [testdir|testpath ...]
+ --add-platform-exceptions Put new results for non-platform-specific failing tests into the platform-specific results directory
+ --complex-text Use the complex text code path for all text (Mac OS X and Windows only)
+ -c|--configuration config Set DumpRenderTree build configuration
+ -g|--guard-malloc Enable malloc guard
+ --help Show this help message
+ --[no-]http Run (or do not run) http tests (default: $httpDefault)
+ -i|--ignore-tests Comma-separated list of directories or tests to ignore
+ --[no-]launch-safari Launch (or do not launch) Safari to display test results (default: $launchSafariDefault)
+ -l|--leaks Enable leaks checking
+ --[no-]new-test-results Generate results for new tests
+ -p|--pixel-tests Enable pixel tests
+ --tolerance t Ignore image differences less than this percentage (default: $tolerance)
+ --platform Override the detected platform to use for tests and results (default: $platform)
+ --port Web server port to use with http tests
+ -q|--quiet Less verbose output
+ --reset-results Reset ALL results (including pixel tests if --pixel-tests is set)
+ -o|--results-directory Output results directory (default: $testResultsDirectory)
+ --random Run the tests in a random order
+ --reverse Run the tests in reverse alphabetical order
+ --root Path to root tools build
+ --[no-]sample-on-timeout Run sample on timeout (default: $sampleDefault) (Mac OS X only)
+ -1|--singly Isolate each test case run (implies --verbose)
+ --skipped=[default|ignore|only] Specifies how to treat the Skipped file
+ default: Tests/directories listed in the Skipped file are not tested
+ ignore: The Skipped file is ignored
+ only: Only those tests/directories listed in the Skipped file will be run
+ --slowest Report the 10 slowest tests
+ --strict Do a comparison with the output on Mac (Qt only)
+ --[no-]strip-editing-callbacks Remove editing callbacks from expected results
+ -t|--threaded Run a concurrent JavaScript thead with each test
+ --valgrind Run DumpRenderTree inside valgrind (Qt/Linux only)
+ -v|--verbose More verbose output (overrides --quiet)
+ -m|--merge-leak-depth arg Merges leak callStacks and prints the number of unique leaks beneath a callstack depth of arg. Defaults to 5.
+EOF
+
+setConfiguration();
+
+my $getOptionsResult = GetOptions(
+ 'complex-text' => \$complexText,
+ 'guard-malloc|g' => \$guardMalloc,
+ 'help' => \$showHelp,
+ 'http!' => \$testHTTP,
+ 'ignore-tests|i=s' => \$ignoreTests,
+ 'launch-safari!' => \$launchSafari,
+ 'leaks|l' => \$shouldCheckLeaks,
+ 'pixel-tests|p' => \$pixelTests,
+ 'platform=s' => \$platform,
+ 'port=i' => \$httpdPort,
+ 'quiet|q' => \$quiet,
+ 'reset-results' => \$resetResults,
+ 'new-test-results!' => \$generateNewResults,
+ 'results-directory|o=s' => \$testResultsDirectory,
+ 'singly|1' => sub { $testsPerDumpTool = 1; },
+ 'nthly=i' => \$testsPerDumpTool,
+ 'skipped=s' => \&validateSkippedArg,
+ 'slowest' => \$report10Slowest,
+ 'threaded|t' => \$threaded,
+ 'tolerance=f' => \$tolerance,
+ 'verbose|v' => \$verbose,
+ 'valgrind' => \$useValgrind,
+ 'sample-on-timeout!' => \$runSample,
+ 'strict' => \$strictTesting,
+ 'strip-editing-callbacks!' => \$stripEditingCallbacks,
+ 'random' => \$randomizeTests,
+ 'reverse' => \$reverseTests,
+ 'root=s' => \$root,
+ 'add-platform-exceptions' => \$addPlatformExceptions,
+ 'merge-leak-depth|m:5' => \$mergeDepth,
+);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+my $ignoreSkipped = $treatSkipped eq "ignore";
+my $skippedOnly = $treatSkipped eq "only";
+
+!$skippedOnly || @ARGV == 0 or die "--skipped=only cannot be used when tests are specified on the command line.";
+
+my $configuration = configuration();
+
+$testsPerDumpTool = 1000 if !$testsPerDumpTool;
+
+$verbose = 1 if $testsPerDumpTool == 1;
+
+if ($shouldCheckLeaks && $testsPerDumpTool > 1000) {
+ print STDERR "\nWARNING: Running more than 1000 tests at a time with MallocStackLogging enabled may cause a crash.\n\n";
+}
+
+# Stack logging does not play well with QuickTime on Tiger (rdar://problem/5537157)
+$testMedia = 0 if $shouldCheckLeaks && isTiger();
+
+setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
+my $productDir = productDir();
+$productDir .= "/bin" if isQt();
+$productDir .= "/Programs" if isGtk();
+
+chdirWebKit();
+
+if (!defined($root)) {
+ # Push the parameters to build-dumprendertree as an array
+ my @args = argumentsForConfiguration();
+
+ my $buildResult = system "WebKitTools/Scripts/build-dumprendertree", @args;
+ if ($buildResult) {
+ print STDERR "Compiling DumpRenderTree failed!\n";
+ exit exitStatus($buildResult);
+ }
+}
+
+my $dumpToolName = "DumpRenderTree";
+$dumpToolName .= "_debug" if isCygwin() && $configuration ne "Release";
+my $dumpTool = "$productDir/$dumpToolName";
+die "can't find executable $dumpToolName (looked in $productDir)\n" unless -x $dumpTool;
+
+my $imageDiffTool = "$productDir/ImageDiff";
+$imageDiffTool .= "_debug" if isCygwin() && $configuration ne "Release";
+die "can't find executable $imageDiffTool (looked in $productDir)\n" if $pixelTests && !-x $imageDiffTool;
+
+checkFrameworks() unless isCygwin();
+
+my $layoutTestsName = "LayoutTests";
+my $testDirectory = File::Spec->rel2abs($layoutTestsName);
+my $expectedDirectory = $testDirectory;
+my $platformBaseDirectory = catdir($testDirectory, "platform");
+my $platformTestDirectory = catdir($platformBaseDirectory, $platform);
+my @platformResultHierarchy = buildPlatformResultHierarchy();
+my @platformTestHierarchy = buildPlatformTestHierarchy(@platformResultHierarchy);
+
+$expectedDirectory = $ENV{"WebKitExpectedTestResultsDirectory"} if $ENV{"WebKitExpectedTestResultsDirectory"};
+
+my $testResults = catfile($testResultsDirectory, "results.html");
+
+print "Running tests from $testDirectory\n";
+if ($pixelTests) {
+ print "Enabling pixel tests with a tolerance of $tolerance%\n";
+ if (isDarwin()) {
+ print "WARNING: Temporarily changing the main display color profile:\n";
+ print "\tThe colors on your screen will change for the duration of the testing.\n";
+ print "\tThis allows the pixel tests to have consistent color values across all machines.\n";
+
+ if (isPerianInstalled()) {
+ print "WARNING: Perian's QuickTime component is installed and this may affect pixel test results!\n";
+ print "\tYou should avoid generating new pixel results in this environment.\n";
+ print "\tSee https://bugs.webkit.org/show_bug.cgi?id=22615 for details.\n";
+ }
+ }
+}
+
+my @tests = ();
+my %testType = ();
+
+system "ln", "-s", $testDirectory, "/tmp/LayoutTests" unless -x "/tmp/LayoutTests";
+
+my %ignoredFiles = ();
+my %ignoredDirectories = map { $_ => 1 } qw(platform);
+my %ignoredLocalDirectories = map { $_ => 1 } qw(.svn _svn resources);
+my %supportedFileExtensions = map { $_ => 1 } qw(html shtml xml xhtml pl php);
+
+# FIXME: We should fix webkitdirs.pm:hasSVG/WMLSupport() to do the correct feature detection for Cygwin.
+if (checkWebCoreSVGSupport(0)) {
+ $supportedFileExtensions{'svg'} = 1;
+} elsif (isCygwin()) {
+ $supportedFileExtensions{'svg'} = 1;
+} else {
+ $ignoredLocalDirectories{'svg'} = 1;
+}
+
+if (checkWebCoreWMLSupport(0)) {
+ $supportedFileExtensions{'wml'} = 1;
+} else {
+ $ignoredDirectories{'http/tests/wml'} = 1;
+ $ignoredDirectories{'fast/wml'} = 1;
+ $ignoredDirectories{'wml'} = 1;
+}
+
+if (!$testHTTP) {
+ $ignoredDirectories{'http'} = 1;
+}
+
+if (!$testMedia) {
+ $ignoredDirectories{'media'} = 1;
+ $ignoredDirectories{'http/tests/media'} = 1;
+}
+
+if (!checkWebCoreAcceleratedCompositingSupport(0)) {
+ $ignoredDirectories{'compositing'} = 1;
+}
+
+if (!checkWebCore3DRenderingSupport(0)) {
+ $ignoredDirectories{'animations/3d'} = 1;
+ $ignoredDirectories{'transforms/3d'} = 1;
+}
+
+if ($ignoreTests) {
+ processIgnoreTests($ignoreTests, "ignore-tests");
+}
+
+if (!$ignoreSkipped) {
+ foreach my $level (@platformTestHierarchy) {
+ if (open SKIPPED, "<", "$level/Skipped") {
+ if ($verbose && !$skippedOnly) {
+ my ($dir, $name) = splitpath($level);
+ print "Skipped tests in $name:\n";
+ }
+
+ while (<SKIPPED>) {
+ my $skipped = $_;
+ chomp $skipped;
+ $skipped =~ s/^[ \n\r]+//;
+ $skipped =~ s/[ \n\r]+$//;
+ if ($skipped && $skipped !~ /^#/) {
+ if ($skippedOnly) {
+ push(@ARGV, $skipped);
+ } else {
+ if ($verbose) {
+ print " $skipped\n";
+ }
+ processIgnoreTests($skipped, "Skipped");
+ }
+ }
+ }
+ close SKIPPED;
+ }
+ }
+}
+
+
+my $directoryFilter = sub {
+ return () if exists $ignoredLocalDirectories{basename($File::Find::dir)};
+ return () if exists $ignoredDirectories{File::Spec->abs2rel($File::Find::dir, $testDirectory)};
+ return @_;
+};
+
+my $fileFilter = sub {
+ my $filename = $_;
+ if ($filename =~ /\.([^.]+)$/) {
+ if (exists $supportedFileExtensions{$1}) {
+ my $path = File::Spec->abs2rel(catfile($File::Find::dir, $filename), $testDirectory);
+ push @tests, $path if !exists $ignoredFiles{$path};
+ }
+ }
+};
+
+for my $test (@ARGV) {
+ $test =~ s/^($layoutTestsName|$testDirectory)\///;
+ my $fullPath = catfile($testDirectory, $test);
+ if (file_name_is_absolute($test)) {
+ print "can't run test $test outside $testDirectory\n";
+ } elsif (-f $fullPath) {
+ my ($filename, $pathname, $fileExtension) = fileparse($test, qr{\.[^.]+$});
+ if (!exists $supportedFileExtensions{substr($fileExtension, 1)}) {
+ print "test $test does not have a supported extension\n";
+ } elsif ($testHTTP || $pathname !~ /^http\//) {
+ push @tests, $test;
+ }
+ } elsif (-d $fullPath) {
+ find({ preprocess => $directoryFilter, wanted => $fileFilter }, $fullPath);
+
+ for my $level (@platformTestHierarchy) {
+ my $platformPath = catfile($level, $test);
+ find({ preprocess => $directoryFilter, wanted => $fileFilter }, $platformPath) if (-d $platformPath);
+ }
+ } else {
+ print "test $test not found\n";
+ }
+}
+if (!scalar @ARGV) {
+ find({ preprocess => $directoryFilter, wanted => $fileFilter }, $testDirectory);
+
+ for my $level (@platformTestHierarchy) {
+ find({ preprocess => $directoryFilter, wanted => $fileFilter }, $level);
+ }
+}
+
+die "no tests to run\n" if !@tests;
+
+@tests = sort pathcmp @tests;
+
+my %counts;
+my %tests;
+my %imagesPresent;
+my %imageDifferences;
+my %durations;
+my $count = 0;
+my $leaksOutputFileNumber = 1;
+my $totalLeaks = 0;
+
+my @toolArgs = ();
+push @toolArgs, "--pixel-tests" if $pixelTests;
+push @toolArgs, "--threaded" if $threaded;
+push @toolArgs, "--complex-text" if $complexText;
+push @toolArgs, "-";
+
+my @diffToolArgs = ();
+push @diffToolArgs, "--tolerance", $tolerance;
+
+$| = 1;
+
+my $imageDiffToolPID;
+if ($pixelTests) {
+ local %ENV;
+ $ENV{MallocStackLogging} = 1 if $shouldCheckLeaks;
+ $imageDiffToolPID = open2(\*DIFFIN, \*DIFFOUT, $imageDiffTool, @diffToolArgs) or die "unable to open $imageDiffTool\n";
+ $ENV{MallocStackLogging} = 0 if $shouldCheckLeaks;
+}
+
+my $dumpToolPID;
+my $isDumpToolOpen = 0;
+my $dumpToolCrashed = 0;
+
+my $atLineStart = 1;
+my $lastDirectory = "";
+
+my $isHttpdOpen = 0;
+
+sub catch_pipe { $dumpToolCrashed = 1; }
+$SIG{"PIPE"} = "catch_pipe";
+
+print "Testing ", scalar @tests, " test cases.\n";
+my $overallStartTime = time;
+
+my %expectedResultPaths;
+
+# Reverse the tests
+@tests = reverse @tests if $reverseTests;
+
+# Shuffle the array
+@tests = shuffle(@tests) if $randomizeTests;
+
+for my $test (@tests) {
+ next if $test eq 'results.html';
+
+ my $newDumpTool = not $isDumpToolOpen;
+ openDumpTool();
+
+ my $base = stripExtension($test);
+ my $expectedExtension = ".txt";
+
+ my $dir = $base;
+ $dir =~ s|/[^/]+$||;
+
+ if ($newDumpTool || $dir ne $lastDirectory) {
+ foreach my $logue (epiloguesAndPrologues($newDumpTool ? "" : $lastDirectory, $dir)) {
+ if (isCygwin()) {
+ $logue = toWindowsPath($logue);
+ } else {
+ $logue = canonpath($logue);
+ }
+ if ($verbose) {
+ print "running epilogue or prologue $logue\n";
+ }
+ print OUT "$logue\n";
+ # Throw away output from DumpRenderTree.
+ # Once for the test output and once for pixel results (empty)
+ while (<IN>) {
+ last if /#EOF/;
+ }
+ while (<IN>) {
+ last if /#EOF/;
+ }
+ }
+ }
+
+ if ($verbose) {
+ print "running $test -> ";
+ $atLineStart = 0;
+ } elsif (!$quiet) {
+ if ($dir ne $lastDirectory) {
+ print "\n" unless $atLineStart;
+ print "$dir ";
+ }
+ print ".";
+ $atLineStart = 0;
+ }
+
+ $lastDirectory = $dir;
+
+ my $result;
+
+ my $startTime = time if $report10Slowest;
+
+ # Try to read expected hash file for pixel tests
+ my $suffixExpectedHash = "";
+ if ($pixelTests && !$resetResults) {
+ my $expectedPixelDir = expectedDirectoryForTest($base, 0, "png");
+ if (open EXPECTEDHASH, "$expectedPixelDir/$base-$expectedTag.checksum") {
+ my $expectedHash = <EXPECTEDHASH>;
+ chomp($expectedHash);
+ close EXPECTEDHASH;
+
+ # Format expected hash into a suffix string that is appended to the path / URL passed to DRT
+ $suffixExpectedHash = "'$expectedHash";
+ }
+ }
+
+ if ($test !~ /^http\//) {
+ my $testPath = "$testDirectory/$test";
+ if (isCygwin()) {
+ $testPath = toWindowsPath($testPath);
+ } else {
+ $testPath = canonpath($testPath);
+ }
+ print OUT "$testPath$suffixExpectedHash\n";
+ } else {
+ openHTTPDIfNeeded();
+ if ($test !~ /^http\/tests\/local\// && $test !~ /^http\/tests\/ssl\// && $test !~ /^http\/tests\/wml\// && $test !~ /^http\/tests\/media\//) {
+ my $path = canonpath($test);
+ $path =~ s/^http\/tests\///;
+ print OUT "http://127.0.0.1:$httpdPort/$path$suffixExpectedHash\n";
+ } elsif ($test =~ /^http\/tests\/ssl\//) {
+ my $path = canonpath($test);
+ $path =~ s/^http\/tests\///;
+ print OUT "https://127.0.0.1:$httpdSSLPort/$path$suffixExpectedHash\n";
+ } else {
+ my $testPath = "$testDirectory/$test";
+ if (isCygwin()) {
+ $testPath = toWindowsPath($testPath);
+ } else {
+ $testPath = canonpath($testPath);
+ }
+ print OUT "$testPath$suffixExpectedHash\n";
+ }
+ }
+
+ # DumpRenderTree is expected to dump two "blocks" to stdout for each test.
+ # Each block is terminated by a #EOF on a line by itself.
+ # The first block is the output of the test (in text, RenderTree or other formats).
+ # The second block is for optional pixel data in PNG format, and may be empty if
+ # pixel tests are not being run, or the test does not dump pixels (e.g. text tests).
+
+ my $actualRead = readFromDumpToolWithTimer(IN);
+ my $errorRead = readFromDumpToolWithTimer(ERROR, $actualRead->{status} eq "timedOut");
+
+ my $actual = $actualRead->{output};
+ my $error = $errorRead->{output};
+
+ $expectedExtension = $actualRead->{extension};
+ my $expectedFileName = "$base-$expectedTag.$expectedExtension";
+
+ my $isText = isTextOnlyTest($actual);
+
+ my $expectedDir = expectedDirectoryForTest($base, $isText, $expectedExtension);
+ $expectedResultPaths{$base} = "$expectedDir/$expectedFileName";
+
+ unless ($actualRead->{status} eq "success" && $errorRead->{status} eq "success") {
+ my $crashed = $actualRead->{status} eq "crashed" || $errorRead->{status} eq "crashed";
+ testCrashedOrTimedOut($test, $base, $crashed, $actual, $error);
+ countFinishedTest($test, $base, $crashed ? "crash" : "timedout", 0);
+ next;
+ }
+
+ $durations{$test} = time - $startTime if $report10Slowest;
+
+ my $expected;
+
+ if (!$resetResults && open EXPECTED, "<", "$expectedDir/$expectedFileName") {
+ $expected = "";
+ while (<EXPECTED>) {
+ next if $stripEditingCallbacks && $_ =~ /^EDITING DELEGATE:/;
+ $expected .= $_;
+ }
+ close EXPECTED;
+ }
+ my $expectedMac;
+ if (!isAppleMacWebKit() && $strictTesting && !$isText) {
+ if (!$resetResults && open EXPECTED, "<", "$testDirectory/platform/mac/$expectedFileName") {
+ $expectedMac = "";
+ while (<EXPECTED>) {
+ $expectedMac .= $_;
+ }
+ close EXPECTED;
+ }
+ }
+
+ if ($shouldCheckLeaks && $testsPerDumpTool == 1) {
+ print " $test -> ";
+ }
+
+ my $actualPNG = "";
+ my $diffPNG = "";
+ my $diffPercentage = "";
+ my $diffResult = "passed";
+
+ my $actualHash = "";
+ my $expectedHash = "";
+ my $actualPNGSize = 0;
+
+ while (<IN>) {
+ last if /#EOF/;
+ if (/ActualHash: ([a-f0-9]{32})/) {
+ $actualHash = $1;
+ } elsif (/ExpectedHash: ([a-f0-9]{32})/) {
+ $expectedHash = $1;
+ } elsif (/Content-Length: (\d+)\s*/) {
+ $actualPNGSize = $1;
+ read(IN, $actualPNG, $actualPNGSize);
+ }
+ }
+
+ if ($verbose && $pixelTests && !$resetResults && $actualPNGSize) {
+ if ($actualHash eq "" && $expectedHash eq "") {
+ printFailureMessageForTest($test, "WARNING: actual & expected pixel hashes are missing!");
+ } elsif ($actualHash eq "") {
+ printFailureMessageForTest($test, "WARNING: actual pixel hash is missing!");
+ } elsif ($expectedHash eq "") {
+ printFailureMessageForTest($test, "WARNING: expected pixel hash is missing!");
+ }
+ }
+
+ if ($actualPNGSize > 0) {
+ my $expectedPixelDir = expectedDirectoryForTest($base, 0, "png");
+
+ if (!$resetResults && ($expectedHash ne $actualHash || ($actualHash eq "" && $expectedHash eq ""))) {
+ if (-f "$expectedPixelDir/$base-$expectedTag.png") {
+ my $expectedPNGSize = -s "$expectedPixelDir/$base-$expectedTag.png";
+ my $expectedPNG = "";
+ open EXPECTEDPNG, "$expectedPixelDir/$base-$expectedTag.png";
+ read(EXPECTEDPNG, $expectedPNG, $expectedPNGSize);
+
+ print DIFFOUT "Content-Length: $actualPNGSize\n";
+ print DIFFOUT $actualPNG;
+
+ print DIFFOUT "Content-Length: $expectedPNGSize\n";
+ print DIFFOUT $expectedPNG;
+
+ while (<DIFFIN>) {
+ last if /^error/ || /^diff:/;
+ if (/Content-Length: (\d+)\s*/) {
+ read(DIFFIN, $diffPNG, $1);
+ }
+ }
+
+ if (/^diff: (.+)% (passed|failed)/) {
+ $diffPercentage = $1;
+ $imageDifferences{$base} = $diffPercentage;
+ $diffResult = $2;
+ }
+
+ if ($diffPercentage == 0) {
+ printFailureMessageForTest($test, "pixel hash failed (but pixel test still passes)");
+ }
+ } elsif ($verbose) {
+ printFailureMessageForTest($test, "WARNING: expected image is missing!");
+ }
+ }
+
+ if ($resetResults || !-f "$expectedPixelDir/$base-$expectedTag.png") {
+ mkpath catfile($expectedPixelDir, dirname($base)) if $testDirectory ne $expectedPixelDir;
+ writeToFile("$expectedPixelDir/$base-$expectedTag.png", $actualPNG);
+ }
+
+ if ($actualHash ne "" && ($resetResults || !-f "$expectedPixelDir/$base-$expectedTag.checksum")) {
+ writeToFile("$expectedPixelDir/$base-$expectedTag.checksum", $actualHash);
+ }
+ }
+
+ if (!isAppleMacWebKit() && $strictTesting && !$isText) {
+ if (defined $expectedMac) {
+ my $simplified_actual;
+ $simplified_actual = $actual;
+ $simplified_actual =~ s/at \(-?[0-9]+,-?[0-9]+\) *//g;
+ $simplified_actual =~ s/size -?[0-9]+x-?[0-9]+ *//g;
+ $simplified_actual =~ s/text run width -?[0-9]+: //g;
+ $simplified_actual =~ s/text run width -?[0-9]+ [a-zA-Z ]+: //g;
+ $simplified_actual =~ s/RenderButton {BUTTON} .*/RenderButton {BUTTON}/g;
+ $simplified_actual =~ s/RenderImage {INPUT} .*/RenderImage {INPUT}/g;
+ $simplified_actual =~ s/RenderBlock {INPUT} .*/RenderBlock {INPUT}/g;
+ $simplified_actual =~ s/RenderTextControl {INPUT} .*/RenderTextControl {INPUT}/g;
+ $simplified_actual =~ s/\([0-9]+px/px/g;
+ $simplified_actual =~ s/ *" *\n +" */ /g;
+ $simplified_actual =~ s/" +$/"/g;
+
+ $simplified_actual =~ s/- /-/g;
+ $simplified_actual =~ s/\n( *)"\s+/\n$1"/g;
+ $simplified_actual =~ s/\s+"\n/"\n/g;
+
+ $expectedMac =~ s/at \(-?[0-9]+,-?[0-9]+\) *//g;
+ $expectedMac =~ s/size -?[0-9]+x-?[0-9]+ *//g;
+ $expectedMac =~ s/text run width -?[0-9]+: //g;
+ $expectedMac =~ s/text run width -?[0-9]+ [a-zA-Z ]+: //g;
+ $expectedMac =~ s/RenderButton {BUTTON} .*/RenderButton {BUTTON}/g;
+ $expectedMac =~ s/RenderImage {INPUT} .*/RenderImage {INPUT}/g;
+ $expectedMac =~ s/RenderBlock {INPUT} .*/RenderBlock {INPUT}/g;
+ $expectedMac =~ s/RenderTextControl {INPUT} .*/RenderTextControl {INPUT}/g;
+ $expectedMac =~ s/\([0-9]+px/px/g;
+ $expectedMac =~ s/ *" *\n +" */ /g;
+ $expectedMac =~ s/" +$/"/g;
+
+ $expectedMac =~ s/- /-/g;
+ $expectedMac =~ s/\n( *)"\s+/\n$1"/g;
+ $expectedMac =~ s/\s+"\n/"\n/g;
+
+ if ($simplified_actual ne $expectedMac) {
+ writeToFile("/tmp/actual.txt", $simplified_actual);
+ writeToFile("/tmp/expected.txt", $expectedMac);
+ system "diff -u \"/tmp/expected.txt\" \"/tmp/actual.txt\" > \"/tmp/simplified.diff\"";
+
+ $diffResult = "failed";
+ if ($verbose) {
+ print "\n";
+ system "cat /tmp/simplified.diff";
+ print "failed!!!!!";
+ }
+ }
+ }
+ }
+
+ if (dumpToolDidCrash()) {
+ $result = "crash";
+ testCrashedOrTimedOut($test, $base, 1, $actual, $error);
+ } elsif (!defined $expected) {
+ if ($verbose) {
+ print "new " . ($resetResults ? "result" : "test") ."\n";
+ $atLineStart = 1;
+ }
+ $result = "new";
+
+ if ($generateNewResults || $resetResults) {
+ mkpath catfile($expectedDir, dirname($base)) if $testDirectory ne $expectedDir;
+ writeToFile("$expectedDir/$expectedFileName", $actual);
+ }
+ deleteExpectedAndActualResults($base);
+ if ($generateNewResults && !$resetResults) {
+ # Always print the file name for new tests, as they will probably need some manual inspection.
+ # in verbose mode we already printed the test case, so no need to do it again.
+ unless ($verbose) {
+ print "\n" unless $atLineStart;
+ print "$test -> ";
+ }
+ my $resultsDir = catdir($expectedDir, dirname($base));
+ print "new (results generated in $resultsDir)\n";
+ $atLineStart = 1;
+ }
+ } elsif ($actual eq $expected && $diffResult eq "passed") {
+ if ($verbose) {
+ print "succeeded\n";
+ $atLineStart = 1;
+ }
+ $result = "match";
+ deleteExpectedAndActualResults($base);
+ } else {
+ $result = "mismatch";
+
+ my $message = $actual eq $expected ? "pixel test failed" : "failed";
+
+ if ($actual ne $expected && $addPlatformExceptions) {
+ my $testBase = catfile($testDirectory, $base);
+ my $expectedBase = catfile($expectedDir, $base);
+ my $testIsMaximallyPlatformSpecific = $testBase =~ m|^\Q$platformTestDirectory\E/|;
+ my $expectedResultIsMaximallyPlatformSpecific = $expectedBase =~ m|^\Q$platformTestDirectory\E/|;
+ if (!$testIsMaximallyPlatformSpecific && !$expectedResultIsMaximallyPlatformSpecific) {
+ mkpath catfile($platformTestDirectory, dirname($base));
+ my $expectedFile = catfile($platformTestDirectory, "$expectedFileName");
+ writeToFile("$expectedFile", $actual);
+ $message .= " (results generated in $platformTestDirectory)";
+ }
+ }
+
+ printFailureMessageForTest($test, $message);
+
+ my $dir = "$testResultsDirectory/$base";
+ $dir =~ s|/([^/]+)$|| or die "Failed to find test name from base\n";
+ my $testName = $1;
+ mkpath $dir;
+
+ deleteExpectedAndActualResults($base);
+ recordActualResultsAndDiff($base, $actual);
+
+ if ($pixelTests && $diffPNG && $diffPNG ne "") {
+ $imagesPresent{$base} = 1;
+
+ writeToFile("$testResultsDirectory/$base-$actualTag.png", $actualPNG);
+ writeToFile("$testResultsDirectory/$base-$diffsTag.png", $diffPNG);
+
+ my $expectedPixelDir = expectedDirectoryForTest($base, 0, "png");
+ copy("$expectedPixelDir/$base-$expectedTag.png", "$testResultsDirectory/$base-$expectedTag.png");
+
+ open DIFFHTML, ">$testResultsDirectory/$base-$diffsTag.html" or die;
+ print DIFFHTML "<html>\n";
+ print DIFFHTML "<head>\n";
+ print DIFFHTML "<title>$base Image Compare</title>\n";
+ print DIFFHTML "<script language=\"Javascript\" type=\"text/javascript\">\n";
+ print DIFFHTML "var currentImage = 0;\n";
+ print DIFFHTML "var imageNames = new Array(\"Actual\", \"Expected\");\n";
+ print DIFFHTML "var imagePaths = new Array(\"$testName-$actualTag.png\", \"$testName-$expectedTag.png\");\n";
+ if (-f "$testDirectory/$base-w3c.png") {
+ copy("$testDirectory/$base-w3c.png", "$testResultsDirectory/$base-w3c.png");
+ print DIFFHTML "imageNames.push(\"W3C\");\n";
+ print DIFFHTML "imagePaths.push(\"$testName-w3c.png\");\n";
+ }
+ print DIFFHTML "function animateImage() {\n";
+ print DIFFHTML " var image = document.getElementById(\"animatedImage\");\n";
+ print DIFFHTML " var imageText = document.getElementById(\"imageText\");\n";
+ print DIFFHTML " image.src = imagePaths[currentImage];\n";
+ print DIFFHTML " imageText.innerHTML = imageNames[currentImage] + \" Image\";\n";
+ print DIFFHTML " currentImage = (currentImage + 1) % imageNames.length;\n";
+ print DIFFHTML " setTimeout('animateImage()',2000);\n";
+ print DIFFHTML "}\n";
+ print DIFFHTML "</script>\n";
+ print DIFFHTML "</head>\n";
+ print DIFFHTML "<body onLoad=\"animateImage();\">\n";
+ print DIFFHTML "<table>\n";
+ if ($diffPercentage) {
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td>Difference between images: <a href=\"$testName-$diffsTag.png\">$diffPercentage%</a></td>\n";
+ print DIFFHTML "</tr>\n";
+ }
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td><a href=\"" . toURL("$testDirectory/$test") . "\">test file</a></td>\n";
+ print DIFFHTML "</tr>\n";
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td id=\"imageText\" style=\"text-weight: bold;\">Actual Image</td>\n";
+ print DIFFHTML "</tr>\n";
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td><img src=\"$testName-$actualTag.png\" id=\"animatedImage\"></td>\n";
+ print DIFFHTML "</tr>\n";
+ print DIFFHTML "</table>\n";
+ print DIFFHTML "</body>\n";
+ print DIFFHTML "</html>\n";
+ }
+ }
+
+ if ($error) {
+ my $dir = "$testResultsDirectory/$base";
+ $dir =~ s|/([^/]+)$|| or die "Failed to find test name from base\n";
+ mkpath $dir;
+
+ writeToFile("$testResultsDirectory/$base-$errorTag.txt", $error);
+
+ $counts{error}++;
+ push @{$tests{error}}, $test;
+ }
+
+ countFinishedTest($test, $base, $result, $isText);
+}
+printf "\n%0.2fs total testing time\n", (time - $overallStartTime) . "";
+
+!$isDumpToolOpen || die "Failed to close $dumpToolName.\n";
+
+closeHTTPD();
+
+# Because multiple instances of this script are running concurrently we cannot
+# safely delete this symlink.
+# system "rm /tmp/LayoutTests";
+
+# FIXME: Do we really want to check the image-comparison tool for leaks every time?
+if ($shouldCheckLeaks && $pixelTests) {
+ $totalLeaks += countAndPrintLeaks("ImageDiff", $imageDiffToolPID, "$testResultsDirectory/ImageDiff-leaks.txt");
+}
+
+if ($totalLeaks) {
+ if ($mergeDepth) {
+ parseLeaksandPrintUniqueLeaks();
+ }
+ else {
+ print "\nWARNING: $totalLeaks total leaks found!\n";
+ print "See above for individual leaks results.\n" if ($leaksOutputFileNumber > 2);
+ }
+}
+
+close IN;
+close OUT;
+close ERROR;
+
+if ($report10Slowest) {
+ print "\n\nThe 10 slowest tests:\n\n";
+ my $count = 0;
+ for my $test (sort slowestcmp keys %durations) {
+ printf "%0.2f secs: %s\n", $durations{$test}, $test;
+ last if ++$count == 10;
+ }
+}
+
+print "\n";
+
+if ($skippedOnly && $counts{"match"}) {
+ print "The following tests are in the Skipped file (" . File::Spec->abs2rel("$platformTestDirectory/Skipped", $testDirectory) . "), but succeeded:\n";
+ foreach my $test (@{$tests{"match"}}) {
+ print " $test\n";
+ }
+}
+
+if ($resetResults || ($counts{match} && $counts{match} == $count)) {
+ print "all $count test cases succeeded\n";
+ unlink $testResults;
+ exit;
+}
+
+
+my %text = (
+ match => "succeeded",
+ mismatch => "had incorrect layout",
+ new => "were new",
+ timedout => "timed out",
+ crash => "crashed",
+ error => "had stderr output"
+);
+
+for my $type ("match", "mismatch", "new", "timedout", "crash", "error") {
+ my $c = $counts{$type};
+ if ($c) {
+ my $t = $text{$type};
+ my $message;
+ if ($c == 1) {
+ $t =~ s/were/was/;
+ $message = sprintf "1 test case (%d%%) %s\n", 1 * 100 / $count, $t;
+ } else {
+ $message = sprintf "%d test cases (%d%%) %s\n", $c, $c * 100 / $count, $t;
+ }
+ $message =~ s-\(0%\)-(<1%)-;
+ print $message;
+ }
+}
+
+mkpath $testResultsDirectory;
+
+open HTML, ">", $testResults or die;
+print HTML "<html>\n";
+print HTML "<head>\n";
+print HTML "<title>Layout Test Results</title>\n";
+print HTML "</head>\n";
+print HTML "<body>\n";
+
+print HTML htmlForResultsSection(@{$tests{mismatch}}, "Tests where results did not match expected results", \&linksForMismatchTest);
+print HTML htmlForResultsSection(@{$tests{timedout}}, "Tests that timed out", \&linksForErrorTest);
+print HTML htmlForResultsSection(@{$tests{crash}}, "Tests that caused the DumpRenderTree tool to crash", \&linksForErrorTest);
+print HTML htmlForResultsSection(@{$tests{error}}, "Tests that had stderr output", \&linksForErrorTest);
+print HTML htmlForResultsSection(@{$tests{new}}, "Tests that had no expected results (probably new)", \&linksForNewTest);
+
+print HTML "</body>\n";
+print HTML "</html>\n";
+close HTML;
+
+my @configurationArgs = argumentsForConfiguration();
+
+if (isQt() || isGtk()) {
+ system "WebKitTools/Scripts/run-launcher", @configurationArgs, "file://".$testResults if $launchSafari;
+} elsif (isCygwin()) {
+ system "cygstart", $testResults if $launchSafari;
+} else {
+ system "WebKitTools/Scripts/run-safari", @configurationArgs, "-NSOpen", $testResults if $launchSafari;
+}
+
+closeCygpaths() if isCygwin();
+
+exit 1;
+
+sub countAndPrintLeaks($$$)
+{
+ my ($dumpToolName, $dumpToolPID, $leaksFilePath) = @_;
+
+ print "\n" unless $atLineStart;
+ $atLineStart = 1;
+
+ # We are excluding the following reported leaks so they don't get in our way when looking for WebKit leaks:
+ # This allows us ignore known leaks and only be alerted when new leaks occur. Some leaks are in the old
+ # versions of the system frameworks that are being used by the leaks bots. Even though a leak has been
+ # fixed, it will be listed here until the bot has been updated with the newer frameworks.
+
+ my @typesToExclude = (
+ );
+
+ my @callStacksToExclude = (
+ "Flash_EnforceLocalSecurity" # leaks in Flash plug-in code, rdar://problem/4449747
+ );
+
+ if (isTiger()) {
+ # Leak list for the version of Tiger used on the build bot.
+ push @callStacksToExclude, (
+ "CFRunLoopRunSpecific \\| malloc_zone_malloc", "CFRunLoopRunSpecific \\| CFAllocatorAllocate ", # leak in CFRunLoopRunSpecific, rdar://problem/4670839
+ "CGImageSourceGetPropertiesAtIndex", # leak in ImageIO, rdar://problem/4628809
+ "FOGetCoveredUnicodeChars", # leak in ATS, rdar://problem/3943604
+ "GetLineDirectionPreference", "InitUnicodeUtilities", # leaks tool falsely reporting leak in CFNotificationCenterAddObserver, rdar://problem/4964790
+ "ICCFPrefWrapper::GetPrefDictionary", # leaks in Internet Config. code, rdar://problem/4449794
+ "NSHTTPURLProtocol setResponseHeader:", # leak in multipart/mixed-replace handling in Foundation, no Radar, but fixed in Leopard
+ "NSURLCache cachedResponseForRequest", # leak in CFURL cache, rdar://problem/4768430
+ "PCFragPrepareClosureFromFile", # leak in Code Fragment Manager, rdar://problem/3426998
+ "WebCore::Selection::toRange", # bug in 'leaks', rdar://problem/4967949
+ "WebCore::SubresourceLoader::create", # bug in 'leaks', rdar://problem/4985806
+ "_CFPreferencesDomainDeepCopyDictionary", # leak in CFPreferences, rdar://problem/4220786
+ "_objc_msgForward", # leak in NSSpellChecker, rdar://problem/4965278
+ "gldGetString", # leak in OpenGL, rdar://problem/5013699
+ "_setDefaultUserInfoFromURL", # leak in NSHTTPAuthenticator, rdar://problem/5546453
+ "SSLHandshake", # leak in SSL, rdar://problem/5546440
+ "SecCertificateCreateFromData", # leak in SSL code, rdar://problem/4464397
+ );
+ push @typesToExclude, (
+ "THRD", # bug in 'leaks', rdar://problem/3387783
+ "DRHT", # ditto (endian little hate i)
+ );
+ }
+
+ if (isLeopard()) {
+ # Leak list for the version of Leopard used on the build bot.
+ push @callStacksToExclude, (
+ "CFHTTPMessageAppendBytes", # leak in CFNetwork, rdar://problem/5435912
+ "sendDidReceiveDataCallback", # leak in CFNetwork, rdar://problem/5441619
+ "_CFHTTPReadStreamReadMark", # leak in CFNetwork, rdar://problem/5441468
+ "httpProtocolStart", # leak in CFNetwork, rdar://problem/5468837
+ "_CFURLConnectionSendCallbacks", # leak in CFNetwork, rdar://problem/5441600
+ "DispatchQTMsg", # leak in QuickTime, PPC only, rdar://problem/5667132
+ "QTMovieContentView createVisualContext", # leak in QuickTime, PPC only, rdar://problem/5667132
+ "_CopyArchitecturesForJVMVersion", # leak in Java, rdar://problem/5910823
+ );
+ }
+
+ my $leaksTool = sourceDir() . "/WebKitTools/Scripts/run-leaks";
+ my $excludeString = "--exclude-callstack '" . (join "' --exclude-callstack '", @callStacksToExclude) . "'";
+ $excludeString .= " --exclude-type '" . (join "' --exclude-type '", @typesToExclude) . "'" if @typesToExclude;
+
+ print " ? checking for leaks in $dumpToolName\n";
+ my $leaksOutput = `$leaksTool $excludeString $dumpToolPID`;
+ my ($count, $bytes) = $leaksOutput =~ /Process $dumpToolPID: (\d+) leaks? for (\d+) total/;
+ my ($excluded) = $leaksOutput =~ /(\d+) leaks? excluded/;
+
+ my $adjustedCount = $count;
+ $adjustedCount -= $excluded if $excluded;
+
+ if (!$adjustedCount) {
+ print " - no leaks found\n";
+ unlink $leaksFilePath;
+ return 0;
+ } else {
+ my $dir = $leaksFilePath;
+ $dir =~ s|/[^/]+$|| or die;
+ mkpath $dir;
+
+ if ($excluded) {
+ print " + $adjustedCount leaks ($bytes bytes including $excluded excluded leaks) were found, details in $leaksFilePath\n";
+ } else {
+ print " + $count leaks ($bytes bytes) were found, details in $leaksFilePath\n";
+ }
+
+ writeToFile($leaksFilePath, $leaksOutput);
+
+ push( @leaksFilenames, $leaksFilePath );
+ }
+
+ return $adjustedCount;
+}
+
+sub writeToFile($$)
+{
+ my ($filePath, $contents) = @_;
+ open NEWFILE, ">", "$filePath" or die "could not create $filePath\n";
+ print NEWFILE $contents;
+ close NEWFILE;
+}
+
+# Break up a path into the directory (with slash) and base name.
+sub splitpath($)
+{
+ my ($path) = @_;
+
+ my $pathSeparator = "/";
+ my $dirname = dirname($path) . $pathSeparator;
+ $dirname = "" if $dirname eq "." . $pathSeparator;
+
+ return ($dirname, basename($path));
+}
+
+# Sort first by directory, then by file, so all paths in one directory are grouped
+# rather than being interspersed with items from subdirectories.
+# Use numericcmp to sort directory and filenames to make order logical.
+sub pathcmp($$)
+{
+ my ($patha, $pathb) = @_;
+
+ my ($dira, $namea) = splitpath($patha);
+ my ($dirb, $nameb) = splitpath($pathb);
+
+ return numericcmp($dira, $dirb) if $dira ne $dirb;
+ return numericcmp($namea, $nameb);
+}
+
+# Sort numeric parts of strings as numbers, other parts as strings.
+# Makes 1.33 come after 1.3, which is cool.
+sub numericcmp($$)
+{
+ my ($aa, $bb) = @_;
+
+ my @a = split /(\d+)/, $aa;
+ my @b = split /(\d+)/, $bb;
+
+ # Compare one chunk at a time.
+ # Each chunk is either all numeric digits, or all not numeric digits.
+ while (@a && @b) {
+ my $a = shift @a;
+ my $b = shift @b;
+
+ # Use numeric comparison if chunks are non-equal numbers.
+ return $a <=> $b if $a =~ /^\d/ && $b =~ /^\d/ && $a != $b;
+
+ # Use string comparison if chunks are any other kind of non-equal string.
+ return $a cmp $b if $a ne $b;
+ }
+
+ # One of the two is now empty; compare lengths for result in this case.
+ return @a <=> @b;
+}
+
+# Sort slowest tests first.
+sub slowestcmp($$)
+{
+ my ($testa, $testb) = @_;
+
+ my $dura = $durations{$testa};
+ my $durb = $durations{$testb};
+ return $durb <=> $dura if $dura != $durb;
+ return pathcmp($testa, $testb);
+}
+
+sub openDumpTool()
+{
+ return if $isDumpToolOpen;
+
+ # Save some requires variables for the linux environment...
+ my $homeDir = $ENV{'HOME'};
+ my $libraryPath = $ENV{'LD_LIBRARY_PATH'};
+ my $dyldLibraryPath = $ENV{'DYLD_LIBRARY_PATH'};
+ my $dbusAddress = $ENV{'DBUS_SESSION_BUS_ADDRESS'};
+ my $display = $ENV{'DISPLAY'};
+ my $testfonts = $ENV{'WEBKIT_TESTFONTS'};
+
+ my $homeDrive = $ENV{'HOMEDRIVE'};
+ my $homePath = $ENV{'HOMEPATH'};
+
+ local %ENV;
+ if (isQt() || isGtk()) {
+ if (defined $display) {
+ $ENV{DISPLAY} = $display;
+ } else {
+ $ENV{DISPLAY} = ":1";
+ }
+ $ENV{'WEBKIT_TESTFONTS'} = $testfonts if defined($testfonts);
+ $ENV{HOME} = $homeDir;
+ if (defined $libraryPath) {
+ $ENV{LD_LIBRARY_PATH} = $libraryPath;
+ }
+ if (defined $dyldLibraryPath) {
+ $ENV{DYLD_LIBRARY_PATH} = $dyldLibraryPath;
+ }
+ if (defined $dbusAddress) {
+ $ENV{DBUS_SESSION_BUS_ADDRESS} = $dbusAddress;
+ }
+ }
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{XML_CATALOG_FILES} = ""; # work around missing /etc/catalog <rdar://problem/4292995>
+ $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc;
+
+ if (isCygwin()) {
+ $ENV{HOMEDRIVE} = $homeDrive;
+ $ENV{HOMEPATH} = $homePath;
+ if ($testfonts) {
+ $ENV{WEBKIT_TESTFONTS} = $testfonts;
+ }
+ setPathForRunningWebKitApp(\%ENV) if isCygwin();
+ }
+
+ my @args = ($dumpTool, @toolArgs);
+
+ if ($useValgrind) {
+ unshift @args, "valgrind";
+ }
+
+ $ENV{MallocStackLogging} = 1 if $shouldCheckLeaks;
+ $dumpToolPID = open3(\*OUT, \*IN, \*ERROR, @args) or die "Failed to start tool: $dumpTool\n";
+ $ENV{MallocStackLogging} = 0 if $shouldCheckLeaks;
+ $isDumpToolOpen = 1;
+ $dumpToolCrashed = 0;
+}
+
+sub closeDumpTool()
+{
+ return if !$isDumpToolOpen;
+
+ close IN;
+ close OUT;
+ waitpid $dumpToolPID, 0;
+
+ # check for WebCore counter leaks.
+ if ($shouldCheckLeaks) {
+ while (<ERROR>) {
+ print;
+ }
+ }
+ close ERROR;
+ $isDumpToolOpen = 0;
+}
+
+sub dumpToolDidCrash()
+{
+ return 1 if $dumpToolCrashed;
+ return 0 unless $isDumpToolOpen;
+
+ my $pid = waitpid(-1, WNOHANG);
+ return 1 if ($pid == $dumpToolPID);
+
+ # On Mac OS X, crashing may be significantly delayed by crash reporter.
+ return 0 unless isAppleMacWebKit();
+
+ my $tryingToExit = 0;
+ open PS, "ps -o state -p $dumpToolPID |";
+ <PS>; # skip header
+ $tryingToExit = 1 if <PS> =~ /E/;
+ close PS;
+ return $tryingToExit;
+}
+
+sub openHTTPDIfNeeded()
+{
+ return if $isHttpdOpen;
+
+ mkdir "/tmp/WebKit";
+
+ if (-f "/tmp/WebKit/httpd.pid") {
+ my $oldPid = `cat /tmp/WebKit/httpd.pid`;
+ chomp $oldPid;
+ if (0 != kill 0, $oldPid) {
+ print "\nhttpd is already running: pid $oldPid, killing...\n";
+ kill 15, $oldPid;
+
+ my $retryCount = 20;
+ while ((0 != kill 0, $oldPid) && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to quit" unless $retryCount;
+ }
+ }
+
+ my $httpdPath = "/usr/sbin/httpd";
+ my $httpdConfig;
+ if (isCygwin()) {
+ my $windowsConfDirectory = "$testDirectory/http/conf/";
+ unless (-x "/usr/lib/apache/libphp4.dll") {
+ copy("$windowsConfDirectory/libphp4.dll", "/usr/lib/apache/libphp4.dll");
+ chmod(0755, "/usr/lib/apache/libphp4.dll");
+ }
+ $httpdConfig = "$windowsConfDirectory/cygwin-httpd.conf";
+ } elsif (isDebianBased()) {
+ $httpdPath = "/usr/sbin/apache2";
+ $httpdConfig = "$testDirectory/http/conf/apache2-debian-httpd.conf";
+ } else {
+ $httpdConfig = "$testDirectory/http/conf/httpd.conf";
+ $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|;
+ }
+ my $documentRoot = "$testDirectory/http/tests";
+ my $typesConfig = "$testDirectory/http/conf/mime.types";
+ my $listen = "127.0.0.1:$httpdPort";
+ my $absTestResultsDirectory = File::Spec->rel2abs(glob $testResultsDirectory);
+ my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+
+ mkpath $absTestResultsDirectory;
+
+ my @args = (
+ "-f", "$httpdConfig",
+ "-C", "DocumentRoot \"$documentRoot\"",
+ "-C", "Listen $listen",
+ "-c", "TypesConfig \"$typesConfig\"",
+ "-c", "CustomLog \"$absTestResultsDirectory/access_log.txt\" common",
+ "-c", "ErrorLog \"$absTestResultsDirectory/error_log.txt\"",
+ # Apache wouldn't run CGIs with permissions==700 otherwise
+ "-c", "User \"#$<\""
+ );
+
+ # FIXME: Enable this on Windows once <rdar://problem/5345985> is fixed
+ # The version of Apache we use with Cygwin does not support SSL
+ push(@args, "-c", "SSLCertificateFile \"$sslCertificate\"") unless isCygwin();
+
+ open2(\*HTTPDIN, \*HTTPDOUT, $httpdPath, @args);
+
+ my $retryCount = 20;
+ while (system("/usr/bin/curl -q --silent --stderr - --output /dev/null $listen") && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to start" unless $retryCount;
+
+ $isHttpdOpen = 1;
+}
+
+sub closeHTTPD()
+{
+ return if !$isHttpdOpen;
+
+ close HTTPDIN;
+ close HTTPDOUT;
+
+ kill 15, `cat /tmp/WebKit/httpd.pid` if -f "/tmp/WebKit/httpd.pid";
+
+ $isHttpdOpen = 0;
+}
+
+sub fileNameWithNumber($$)
+{
+ my ($base, $number) = @_;
+ return "$base$number" if ($number > 1);
+ return $base;
+}
+
+sub processIgnoreTests($$) {
+ my @ignoreList = split(/\s*,\s*/, shift);
+ my $listName = shift;
+
+ my $disabledSuffix = "-disabled";
+
+ my $addIgnoredDirectories = sub {
+ return () if exists $ignoredLocalDirectories{basename($File::Find::dir)};
+ $ignoredDirectories{File::Spec->abs2rel($File::Find::dir, $testDirectory)} = 1;
+ return @_;
+ };
+ foreach my $item (@ignoreList) {
+ my $path = catfile($testDirectory, $item);
+ if (-d $path) {
+ $ignoredDirectories{$item} = 1;
+ find({ preprocess => $addIgnoredDirectories, wanted => sub {} }, $path);
+ }
+ elsif (-f $path) {
+ $ignoredFiles{$item} = 1;
+ } elsif (-f $path . $disabledSuffix) {
+ # The test is disabled, so do nothing.
+ } else {
+ print "$listName list contained '$item', but no file of that name could be found\n";
+ }
+ }
+}
+
+sub stripExtension($)
+{
+ my ($test) = @_;
+
+ $test =~ s/\.[a-zA-Z]+$//;
+ return $test;
+}
+
+sub isTextOnlyTest($)
+{
+ my ($actual) = @_;
+ my $isText;
+ if ($actual =~ /^layer at/ms) {
+ $isText = 0;
+ } else {
+ $isText = 1;
+ }
+ return $isText;
+}
+
+sub expectedDirectoryForTest($;$;$)
+{
+ my ($base, $isText, $expectedExtension) = @_;
+
+ my @directories = @platformResultHierarchy;
+ push @directories, map { catdir($platformBaseDirectory, $_) } qw(mac-snowleopard mac) if isCygwin();
+ push @directories, $expectedDirectory;
+
+ # If we already have expected results, just return their location.
+ foreach my $directory (@directories) {
+ return $directory if (-f "$directory/$base-$expectedTag.$expectedExtension");
+ }
+
+ # For cross-platform tests, text-only results should go in the cross-platform directory,
+ # while render tree dumps should go in the least-specific platform directory.
+ return $isText ? $expectedDirectory : $platformResultHierarchy[$#platformResultHierarchy];
+}
+
+sub countFinishedTest($$$$) {
+ my ($test, $base, $result, $isText) = @_;
+
+ if (($count + 1) % $testsPerDumpTool == 0 || $count == $#tests) {
+ if ($shouldCheckLeaks) {
+ my $fileName;
+ if ($testsPerDumpTool == 1) {
+ $fileName = "$testResultsDirectory/$base-leaks.txt";
+ } else {
+ $fileName = "$testResultsDirectory/" . fileNameWithNumber($dumpToolName, $leaksOutputFileNumber) . "-leaks.txt";
+ }
+ my $leakCount = countAndPrintLeaks($dumpToolName, $dumpToolPID, $fileName);
+ $totalLeaks += $leakCount;
+ $leaksOutputFileNumber++ if ($leakCount);
+ }
+
+ closeDumpTool();
+ }
+
+ $count++;
+ $counts{$result}++;
+ push @{$tests{$result}}, $test;
+ $testType{$test} = $isText;
+}
+
+sub testCrashedOrTimedOut($$$$$)
+{
+ my ($test, $base, $didCrash, $actual, $error) = @_;
+
+ printFailureMessageForTest($test, $didCrash ? "crashed" : "timed out");
+
+ sampleDumpTool() unless $didCrash;
+
+ my $dir = "$testResultsDirectory/$base";
+ $dir =~ s|/([^/]+)$|| or die "Failed to find test name from base\n";
+ mkpath $dir;
+
+ deleteExpectedAndActualResults($base);
+
+ if (defined($error) && length($error)) {
+ writeToFile("$testResultsDirectory/$base-$errorTag.txt", $error);
+ }
+
+ recordActualResultsAndDiff($base, $actual);
+
+ kill 9, $dumpToolPID unless $didCrash;
+
+ closeDumpTool();
+}
+
+sub printFailureMessageForTest($$)
+{
+ my ($test, $description) = @_;
+
+ unless ($verbose) {
+ print "\n" unless $atLineStart;
+ print "$test -> ";
+ }
+ print "$description\n";
+ $atLineStart = 1;
+}
+
+my %cygpaths = ();
+
+sub openCygpathIfNeeded($)
+{
+ my ($options) = @_;
+
+ return unless isCygwin();
+ return $cygpaths{$options} if $cygpaths{$options} && $cygpaths{$options}->{"open"};
+
+ local (*CYGPATHIN, *CYGPATHOUT);
+ my $pid = open2(\*CYGPATHIN, \*CYGPATHOUT, "cygpath -f - $options");
+ my $cygpath = {
+ "pid" => $pid,
+ "in" => *CYGPATHIN,
+ "out" => *CYGPATHOUT,
+ "open" => 1
+ };
+
+ $cygpaths{$options} = $cygpath;
+
+ return $cygpath;
+}
+
+sub closeCygpaths()
+{
+ return unless isCygwin();
+
+ foreach my $cygpath (values(%cygpaths)) {
+ close $cygpath->{"in"};
+ close $cygpath->{"out"};
+ waitpid($cygpath->{"pid"}, 0);
+ $cygpath->{"open"} = 0;
+
+ }
+}
+
+sub convertPathUsingCygpath($$)
+{
+ my ($path, $options) = @_;
+
+ my $cygpath = openCygpathIfNeeded($options);
+ local *inFH = $cygpath->{"in"};
+ local *outFH = $cygpath->{"out"};
+ print outFH $path . "\n";
+ chomp(my $convertedPath = <inFH>);
+ return $convertedPath;
+}
+
+sub toWindowsPath($)
+{
+ my ($path) = @_;
+ return unless isCygwin();
+
+ return convertPathUsingCygpath($path, "-w");
+}
+
+sub toURL($)
+{
+ my ($path) = @_;
+ return $path unless isCygwin();
+
+ return "file:///" . convertPathUsingCygpath($path, "-m");
+}
+
+sub validateSkippedArg($$;$)
+{
+ my ($option, $value, $value2) = @_;
+ my %validSkippedValues = map { $_ => 1 } qw(default ignore only);
+ $value = lc($value);
+ die "Invalid argument '" . $value . "' for option $option" unless $validSkippedValues{$value};
+ $treatSkipped = $value;
+}
+
+sub htmlForResultsSection(\@$&)
+{
+ my ($tests, $description, $linkGetter) = @_;
+
+ my @html = ();
+ return join("\n", @html) unless @{$tests};
+
+ push @html, "<p>$description:</p>";
+ push @html, "<table>";
+ foreach my $test (@{$tests}) {
+ push @html, "<tr>";
+ push @html, "<td><a href=\"" . toURL("$testDirectory/$test") . "\">$test</a></td>";
+ foreach my $link (@{&{$linkGetter}($test)}) {
+ push @html, "<td><a href=\"$link->{href}\">$link->{text}</a></td>";
+ }
+ push @html, "</tr>";
+ }
+ push @html, "</table>";
+
+ return join("\n", @html);
+}
+
+sub linksForExpectedAndActualResults($)
+{
+ my ($base) = @_;
+
+ my @links = ();
+
+ return \@links unless -s "$testResultsDirectory/$base-$diffsTag.txt";
+
+ my $expectedResultPath = $expectedResultPaths{$base};
+ my ($expectedResultFileName, $expectedResultsDirectory, $expectedResultExtension) = fileparse($expectedResultPath, qr{\.[^.]+$});
+
+ push @links, { href => "$base-$expectedTag$expectedResultExtension", text => "expected" };
+ push @links, { href => "$base-$actualTag$expectedResultExtension", text => "actual" };
+ push @links, { href => "$base-$diffsTag.txt", text => "diffs" };
+
+ return \@links;
+}
+
+sub linksForMismatchTest
+{
+ my ($test) = @_;
+
+ my @links = ();
+
+ my $base = stripExtension($test);
+
+ push @links, @{linksForExpectedAndActualResults($base)};
+ return \@links unless $pixelTests && $imagesPresent{$base};
+
+ push @links, { href => "$base-$expectedTag.png", text => "expected image" };
+ push @links, { href => "$base-$diffsTag.html", text => "image diffs" };
+ push @links, { href => "$base-$diffsTag.png", text => "$imageDifferences{$base}%" };
+
+ return \@links;
+}
+
+sub linksForErrorTest
+{
+ my ($test) = @_;
+
+ my @links = ();
+
+ my $base = stripExtension($test);
+
+ push @links, @{linksForExpectedAndActualResults($base)};
+ push @links, { href => "$base-$errorTag.txt", text => "stderr" };
+
+ return \@links;
+}
+
+sub linksForNewTest
+{
+ my ($test) = @_;
+
+ my @links = ();
+
+ my $base = stripExtension($test);
+ my $expectedResultPath = $expectedResultPaths{$base};
+ my $expectedResultPathMinusExtension = stripExtension($expectedResultPath);
+
+ push @links, { href => toURL($expectedResultPath), text => "results" };
+ if ($pixelTests && -f "$expectedResultPathMinusExtension.png") {
+ push @links, { href => toURL("$expectedResultPathMinusExtension.png"), text => "image" };
+ }
+
+ return \@links;
+}
+
+sub deleteExpectedAndActualResults($)
+{
+ my ($base) = @_;
+
+ unlink "$testResultsDirectory/$base-$actualTag.txt";
+ unlink "$testResultsDirectory/$base-$diffsTag.txt";
+ unlink "$testResultsDirectory/$base-$errorTag.txt";
+}
+
+sub recordActualResultsAndDiff($$)
+{
+ my ($base, $actualResults) = @_;
+
+ return unless defined($actualResults) && length($actualResults);
+
+ my $expectedResultPath = $expectedResultPaths{$base};
+ my ($expectedResultFileNameMinusExtension, $expectedResultDirectoryPath, $expectedResultExtension) = fileparse($expectedResultPath, qr{\.[^.]+$});
+ my $actualResultsPath = "$testResultsDirectory/$base-$actualTag$expectedResultExtension";
+ my $copiedExpectedResultsPath = "$testResultsDirectory/$base-$expectedTag$expectedResultExtension";
+ writeToFile("$actualResultsPath", $actualResults);
+ copy("$expectedResultPath", "$copiedExpectedResultsPath");
+
+ system "diff -u \"$copiedExpectedResultsPath\" \"$actualResultsPath\" > \"$testResultsDirectory/$base-$diffsTag.txt\"";
+}
+
+sub buildPlatformResultHierarchy()
+{
+ mkpath($platformTestDirectory) if ($platform eq "undefined" && !-d "$platformTestDirectory");
+
+ my @platforms;
+ if ($platform =~ /^mac-/) {
+ my $i;
+ for ($i = 0; $i < @macPlatforms; $i++) {
+ last if $macPlatforms[$i] eq $platform;
+ }
+ for (; $i < @macPlatforms; $i++) {
+ push @platforms, $macPlatforms[$i];
+ }
+ } else {
+ @platforms = $platform;
+ }
+
+ my @hierarchy;
+ for (my $i = 0; $i < @platforms; $i++) {
+ my $scoped = catdir($platformBaseDirectory, $platforms[$i]);
+ push(@hierarchy, $scoped) if (-d $scoped);
+ }
+
+ return @hierarchy;
+}
+
+sub buildPlatformTestHierarchy(@)
+{
+ my (@platformHierarchy) = @_;
+ return @platformHierarchy if (@platformHierarchy < 2);
+
+ return ($platformHierarchy[0], $platformHierarchy[$#platformHierarchy]);
+}
+
+sub epiloguesAndPrologues($$) {
+ my ($lastDirectory, $directory) = @_;
+ my @lastComponents = split('/', $lastDirectory);
+ my @components = split('/', $directory);
+
+ while (@lastComponents) {
+ if (!defined($components[0]) || $lastComponents[0] ne $components[0]) {
+ last;
+ }
+ shift @components;
+ shift @lastComponents;
+ }
+
+ my @result;
+ my $leaving = $lastDirectory;
+ foreach (@lastComponents) {
+ my $epilogue = $leaving . "/resources/run-webkit-tests-epilogue.html";
+ foreach (@platformResultHierarchy) {
+ push @result, catdir($_, $epilogue) if (stat(catdir($_, $epilogue)));
+ }
+ push @result, catdir($testDirectory, $epilogue) if (stat(catdir($testDirectory, $epilogue)));
+ $leaving =~ s|(^\|/)[^/]+$||;
+ }
+
+ my $entering = $leaving;
+ foreach (@components) {
+ $entering .= '/' . $_;
+ my $prologue = $entering . "/resources/run-webkit-tests-prologue.html";
+ push @result, catdir($testDirectory, $prologue) if (stat(catdir($testDirectory, $prologue)));
+ foreach (reverse @platformResultHierarchy) {
+ push @result, catdir($_, $prologue) if (stat(catdir($_, $prologue)));
+ }
+ }
+ return @result;
+}
+
+sub parseLeaksandPrintUniqueLeaks() {
+ return unless @leaksFilenames;
+
+ my $mergedFilenames = join " ", @leaksFilenames;
+ my $parseMallocHistoryTool = sourceDir() . "/WebKitTools/Scripts/parse-malloc-history";
+
+ open MERGED_LEAKS, "cat $mergedFilenames | $parseMallocHistoryTool --merge-depth $mergeDepth - |" ;
+ my @leakLines = <MERGED_LEAKS>;
+ close MERGED_LEAKS;
+
+ my $uniqueLeakCount = 0;
+ my $totalBytes;
+ foreach my $line (@leakLines) {
+ ++$uniqueLeakCount if ($line =~ /^(\d*)\scalls/);
+ $totalBytes = $1 if $line =~ /^total\:\s(.*)\s\(/;
+ }
+
+ print "\nWARNING: $totalLeaks total leaks found for a total of $totalBytes!\n";
+ print "WARNING: $uniqueLeakCount unique leaks found!\n";
+ print "See above for individual leaks results.\n" if ($leaksOutputFileNumber > 2);
+
+}
+
+sub extensionForMimeType($)
+{
+ my ($mimeType) = @_;
+
+ if ($mimeType eq "application/x-webarchive") {
+ return "webarchive";
+ } elsif ($mimeType eq "application/pdf") {
+ return "pdf";
+ }
+ return "txt";
+}
+
+# Read up to the first #EOF (the content block of the test), or until detecting crashes or timeouts.
+sub readFromDumpToolWithTimer(*;$)
+{
+ my ($fh, $dontWaitForTimeOut) = @_;
+
+ setFileHandleNonBlocking($fh, 1);
+
+ my $maximumSecondsWithoutOutput = 15;
+ $maximumSecondsWithoutOutput *= 10 if $guardMalloc;
+ my $microsecondsToWaitBeforeReadingAgain = 1000;
+
+ my $timeOfLastSuccessfulRead = time;
+
+ my @output = ();
+ my $status = "success";
+ my $mimeType = "text/plain";
+ # We don't have a very good way to know when the "headers" stop
+ # and the content starts, so we use this as a hack:
+ my $haveSeenContentType = 0;
+
+ while (1) {
+ if (time - $timeOfLastSuccessfulRead > $maximumSecondsWithoutOutput) {
+ $status = dumpToolDidCrash() ? "crashed" : "timedOut";
+ last;
+ }
+
+ my $line = readline($fh);
+ if (!defined($line)) {
+ if ($! != EAGAIN) {
+ $status = "crashed";
+ last;
+ }
+
+ if ($dontWaitForTimeOut) {
+ last;
+ }
+
+ # No data ready
+ usleep($microsecondsToWaitBeforeReadingAgain);
+ next;
+ }
+
+ $timeOfLastSuccessfulRead = time;
+
+ if (!$haveSeenContentType && $line =~ /^Content-Type: (\S+)$/) {
+ $mimeType = $1;
+ $haveSeenContentType = 1;
+ next;
+ }
+ last if ($line =~ /#EOF/);
+
+ push @output, $line;
+ }
+
+ setFileHandleNonBlocking($fh, 0);
+ return {
+ output => join("", @output),
+ status => $status,
+ mimeType => $mimeType,
+ extension => extensionForMimeType($mimeType)
+ };
+}
+
+sub setFileHandleNonBlocking(*$)
+{
+ my ($fh, $nonBlocking) = @_;
+
+ my $flags = fcntl($fh, F_GETFL, 0) or die "Couldn't get filehandle flags";
+
+ if ($nonBlocking) {
+ $flags |= O_NONBLOCK;
+ } else {
+ $flags &= ~O_NONBLOCK;
+ }
+
+ fcntl($fh, F_SETFL, $flags) or die "Couldn't set filehandle flags";
+
+ return 1;
+}
+
+sub sampleDumpTool()
+{
+ return unless isAppleMacWebKit();
+ return unless $runSample;
+
+ my $outputDirectory = "$ENV{HOME}/Library/Logs/DumpRenderTree";
+ -d $outputDirectory or mkdir $outputDirectory;
+
+ my $outputFile = "$outputDirectory/HangReport.txt";
+ system "/usr/bin/sample", $dumpToolPID, qw(10 10 -file), $outputFile;
+}
diff --git a/WebKitTools/Scripts/set-webkit-configuration b/WebKitTools/Scripts/set-webkit-configuration
new file mode 100755
index 0000000..4992256
--- /dev/null
+++ b/WebKitTools/Scripts/set-webkit-configuration
@@ -0,0 +1,79 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options]
+ --32-bit Set the default architecture to 32-bit
+ --64-bit Set the default architecture to 64-bit
+ --debug Set the default configuration to debug
+ --release Set the default configuration to release
+EOF
+
+my $configuration = passedConfiguration();
+my $architecture = passedArchitecture();
+
+if (!$architecture) {
+ # Handle --64-bit explicitly here, as we don't want our other scripts to accept it
+ for my $i (0 .. $#ARGV) {
+ my $opt = $ARGV[$i];
+ if ($opt =~ /^--64-bit$/i) {
+ splice(@ARGV, $i, 1);
+ $architecture = 'x86_64';
+ }
+ }
+}
+
+if (!$configuration && !$architecture) {
+ print STDERR $usage;
+ exit 1;
+}
+
+my $baseProductDir = baseProductDir();
+system "mkdir", "-p", "$baseProductDir";
+
+if ($configuration) {
+ open CONFIGURATION, ">", "$baseProductDir/Configuration" or die;
+ print CONFIGURATION $configuration;
+ close CONFIGURATION;
+}
+
+if ($architecture) {
+ if ($architecture ne "x86_64") {
+ open ARCHITECTURE, ">", "$baseProductDir/Architecture" or die;
+ print ARCHITECTURE $architecture;
+ close ARCHITECTURE;
+ } else {
+ unlink "$baseProductDir/Architecture";
+ }
+}
diff --git a/WebKitTools/Scripts/sort-Xcode-project-file b/WebKitTools/Scripts/sort-Xcode-project-file
new file mode 100755
index 0000000..52a3df1
--- /dev/null
+++ b/WebKitTools/Scripts/sort-Xcode-project-file
@@ -0,0 +1,167 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Script to sort "children" and "files" sections in Xcode project.pbxproj files
+
+use strict;
+
+use File::Basename;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+sub sortChildrenByFileName($$);
+sub sortFilesByFileName($$);
+
+# Files (or products) without extensions
+my %isFile = map { $_ => 1 } qw(
+ create_hash_table
+ jsc
+ minidom
+ testapi
+ testjsglue
+);
+
+my $printWarnings = 1;
+my $showHelp;
+
+my $getOptionsResult = GetOptions(
+ 'h|help' => \$showHelp,
+ 'w|warnings!' => \$printWarnings,
+);
+
+if (scalar(@ARGV) == 0) {
+ print STDERR "ERROR: No Xcode project files (project.pbxproj) listed on command-line.\n";
+ undef $getOptionsResult;
+}
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR <<__END__;
+Usage: @{[ basename($0) ]} [options] path/to/project.pbxproj [path/to/project.pbxproj ...]
+ -h|--help show this help message
+ -w|--[no-]warnings show or suppress warnings (default: show warnings)
+__END__
+ exit 1;
+}
+
+for my $projectFile (@ARGV) {
+ if (basename($projectFile) ne "project.pbxproj") {
+ print STDERR "WARNING: Not an Xcode project file: $projectFile\n" if $printWarnings;
+ next;
+ }
+
+ # Grab the mainGroup for the project file
+ my $mainGroup = "";
+ open(IN, "< $projectFile") || die "Could not open $projectFile: $!";
+ while (my $line = <IN>) {
+ $mainGroup = $2 if $line =~ m#^(\s*)mainGroup = ([0-9A-F]{24} /\* .+ \*/);$#;
+ }
+ close(IN);
+
+ my ($OUT, $tempFileName) = tempfile(
+ basename($projectFile) . "-XXXXXXXX",
+ DIR => dirname($projectFile),
+ UNLINK => 0,
+ );
+
+ # Clean up temp file in case of die()
+ $SIG{__DIE__} = sub {
+ close(IN);
+ close($OUT);
+ unlink($tempFileName);
+ };
+
+ my @lastTwo = ();
+ open(IN, "< $projectFile") || die "Could not open $projectFile: $!";
+ while (my $line = <IN>) {
+ if ($line =~ /^(\s*)files = \(\s*$/) {
+ print $OUT $line;
+ my $endMarker = $1 . ");";
+ my @files;
+ while (my $fileLine = <IN>) {
+ if ($fileLine =~ /^\Q$endMarker\E\s*$/) {
+ $endMarker = $fileLine;
+ last;
+ }
+ push @files, $fileLine;
+ }
+ print $OUT sort sortFilesByFileName @files;
+ print $OUT $endMarker;
+ } elsif ($line =~ /^(\s*)children = \(\s*$/) {
+ print $OUT $line;
+ my $endMarker = $1 . ");";
+ my @children;
+ while (my $childLine = <IN>) {
+ if ($childLine =~ /^\Q$endMarker\E\s*$/) {
+ $endMarker = $childLine;
+ last;
+ }
+ push @children, $childLine;
+ }
+ if ($lastTwo[0] =~ m#^\s+\Q$mainGroup\E = \{$#) {
+ # Don't sort mainGroup
+ print $OUT @children;
+ } else {
+ print $OUT sort sortChildrenByFileName @children;
+ }
+ print $OUT $endMarker;
+ } else {
+ print $OUT $line;
+ }
+
+ push @lastTwo, $line;
+ shift @lastTwo if scalar(@lastTwo) > 2;
+ }
+ close(IN);
+ close($OUT);
+
+ unlink($projectFile) || die "Could not delete $projectFile: $!";
+ rename($tempFileName, $projectFile) || die "Could not rename $tempFileName to $projectFile: $!";
+}
+
+exit 0;
+
+sub sortChildrenByFileName($$)
+{
+ my ($a, $b) = @_;
+ my $aFileName = $1 if $a =~ /^\s*[A-Z0-9]{24} \/\* (.+) \*\/,$/;
+ my $bFileName = $1 if $b =~ /^\s*[A-Z0-9]{24} \/\* (.+) \*\/,$/;
+ my $aSuffix = $1 if $aFileName =~ m/\.([^.]+)$/;
+ my $bSuffix = $1 if $bFileName =~ m/\.([^.]+)$/;
+ if ((!$aSuffix && !$isFile{$aFileName} && $bSuffix) || ($aSuffix && !$bSuffix && !$isFile{$bFileName})) {
+ return !$aSuffix ? -1 : 1;
+ }
+ return $aFileName cmp $bFileName;
+}
+
+sub sortFilesByFileName($$)
+{
+ my ($a, $b) = @_;
+ my $aFileName = $1 if $a =~ /^\s*[A-Z0-9]{24} \/\* (.+) in /;
+ my $bFileName = $1 if $b =~ /^\s*[A-Z0-9]{24} \/\* (.+) in /;
+ return $aFileName cmp $bFileName;
+}
diff --git a/WebKitTools/Scripts/split-file-by-class b/WebKitTools/Scripts/split-file-by-class
new file mode 100755
index 0000000..b6aeb68
--- /dev/null
+++ b/WebKitTools/Scripts/split-file-by-class
@@ -0,0 +1,159 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Used for splitting a single file into multiple class files
+# Usage: split-class <header file>
+
+use strict;
+use File::Copy;
+use FindBin;
+use lib $FindBin::Bin;
+use SpacingHeuristics;
+
+
+for my $filename (@ARGV) {
+
+ $filename =~ m/^(\w+)\.h$/ or die "Command line args must be .h files.\n";
+ my $basename = $1;
+
+ open(OLDFILE, "<", $filename) or die "File does not exist: $filename\n";
+ print "Splitting class $filename.{h,cpp}:\n";
+
+ my $currentClassName = "";
+ my $classIndent = "";
+ my $fileContent = "";
+ my %classDefs = ();
+ while (my $line = <OLDFILE>) {
+ if ($currentClassName) {
+ $classDefs{$currentClassName} .= $line;
+ if ($line =~ /^$classIndent};\s*$/) {
+ $currentClassName = "";
+ }
+ } else {
+ if ($line =~ /^(\s*)class\s+(\w+)\s+[^;]*$/) {
+ $classIndent = $1;
+ $currentClassName = $2;
+ $classDefs{$currentClassName} .= $line;
+ $fileContent .= "###CLASS###$currentClassName\n";
+ } else {
+ $fileContent .= $line;
+ }
+ }
+ }
+ close(OLDFILE);
+
+ if (scalar(keys(%classDefs)) == 1) { # degenerate case
+ my ($classname) = keys(%classDefs);
+ if (!($classname eq $basename)) {
+ print "Skipping $filename, already correctly named.\n";
+ } else {
+ print "$filename only includes one class, renaming to $classname.h\n";
+ system("svn rm --force $classname.h") if (-r "$classname.h");
+ system "svn mv $basename.h $classname.h";
+ }
+ } else {
+ while (my ($classname, $classDef) = each(%classDefs)) {
+ if (($classname eq $basename)) {
+ print "Skipping $filename, already correctly named.\n";
+ } else {
+ print "Using SVN to copy $basename.{h,cpp} to $classname.{h,cpp}\n";
+
+ system("svn rm --force $classname.h") if (-r "$classname.h");
+ system "svn cp $basename.h $classname.h";
+
+ system("svn rm --force $classname.cpp") if (-r "$classname.cpp");
+ system "svn cp $basename.cpp $classname.cpp";
+ }
+
+ print "Fixing $classname.h as much as possible.\n";
+ open(NEWHEADER, ">", "$classname.h") or die "File does not exist: $filename\n";
+ my @lines = split("\n", $fileContent);
+ foreach my $line (@lines) {
+ if ($line =~ /^###CLASS###(\w+)/) {
+ if ($1 eq $classname) {
+ print NEWHEADER $classDef . "\n";
+ }
+ } else {
+ print NEWHEADER $line . "\n";
+ }
+ }
+ close(NEWHEADER);
+
+ print "Fixing $classname.cpp as much as possible.\n";
+ copy("$classname.cpp", "$classname.cpp.original");
+ open(OLDCPP, "<", "$classname.cpp.original") or die "Failed to copy file for reading: $filename\n";
+ open(NEWCPP, ">", "$classname.cpp") or die "File does not exist: $filename\n";
+ my $insideMemberFunction = 0;
+ my $shouldPrintMemberFunction = 0;
+ resetSpacingHeuristics();
+ while (my $line = <OLDCPP>) {
+ if ($insideMemberFunction) {
+ if ($shouldPrintMemberFunction) {
+ print NEWCPP $line;
+ #setPreviousAllowedLine($line);
+ } else {
+ ignoringLine($line);
+ }
+ if ($line =~ /^}\s*$/) {
+ $insideMemberFunction = 0;
+ }
+ } elsif ($line =~ /$filename/) {
+ print NEWCPP "#include \"config.h\"\n";
+ print NEWCPP "#include \"$classname.h\"\n";
+ } elsif ($line =~ /#include/ || $line =~ /#import/) {
+ next; # skip includes, they're generally wrong or unecessary anyway.
+ } else {
+ $line =~ s/DOM:://;
+ $line =~ s/khtml:://;
+ $line =~ s/namespace DOM/namespace WebCore/;
+ $line =~ s/namespace khtml/namespace WebCore/;
+
+ if ($line =~ /^(.*?\s+)?(\*|&)?(\w+)::(~)?\w+\s*\(/) {
+ $insideMemberFunction = 1;
+ $shouldPrintMemberFunction = ($classname eq $3);
+ if ($shouldPrintMemberFunction) {
+ printPendingEmptyLines(*NEWCPP, $line);
+ print NEWCPP $line;
+ }
+ } else {
+ next if isOnlyWhiteSpace($line);
+ next if ($line =~ m/------------/);
+ printPendingEmptyLines(*NEWCPP, $line);
+ applySpacingHeuristicsAndPrint(*NEWCPP, $line);
+ }
+ }
+ }
+ close(NEWCPP);
+ close(OLDCPP);
+ unlink("$classname.cpp.original");
+ }
+ }
+
+ print "Opening new files...\n";
+ system("open " . join(".* ", keys(%classDefs)) . ".*");
+} \ No newline at end of file
diff --git a/WebKitTools/Scripts/sunspider-compare-results b/WebKitTools/Scripts/sunspider-compare-results
new file mode 100755
index 0000000..ec0863a
--- /dev/null
+++ b/WebKitTools/Scripts/sunspider-compare-results
@@ -0,0 +1,101 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use File::Spec;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# determine configuration, but default to "Release" instead of last-used configuration to match run-sunspider
+setConfiguration("Release");
+setConfiguration();
+my $configuration = configuration();
+
+my $root;
+my $showHelp = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] FILE FILE
+ --help Show this help message
+ --root Path to root tools build
+EOF
+
+GetOptions('root=s' => sub { my ($argName, $value); setConfigurationProductDir(Cwd::abs_path($value)); },
+ 'help' => \$showHelp);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+@ARGV = map { File::Spec->rel2abs($_) } @ARGV;
+
+sub buildJSC
+{
+ if (!defined($root)){
+ chdirWebKit();
+ my $buildResult = system "WebKitTools/Scripts/build-jsc", "--" . $configuration;
+ if ($buildResult) {
+ print STDERR "Compiling jsc failed!\n";
+ exit WEXITSTATUS($buildResult);
+ }
+ }
+}
+
+sub setupEnvironmentForExecution($)
+{
+ my ($productDir) = @_;
+ print "Starting sunspider-compare-results with DYLD_FRAMEWORK_PATH set to point to built JavaScriptCore in $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ # FIXME: Other platforms may wish to augment this method to use LD_LIBRARY_PATH, etc.
+}
+
+sub jscPath($)
+{
+ my ($productDir) = @_;
+ my $jscName = "jsc";
+ $jscName .= "_debug" if (isCygwin() && ($configuration eq "Debug"));
+ return "$productDir/$jscName";
+}
+
+buildJSC();
+
+chdirWebKit();
+chdir("SunSpider");
+
+my $productDir = productDir();
+# FIXME: This hack should be pushed down into productDir()
+$productDir .= "/JavaScriptCore" if (isQt() or isGtk());
+
+setupEnvironmentForExecution($productDir);
+my @args = ("--shell", jscPath($productDir));
+# This code could be removed if we chose to pass extra args to sunspider instead of Xcode
+
+exec "./sunspider-compare-results", @args, @ARGV;
diff --git a/WebKitTools/Scripts/svn-apply b/WebKitTools/Scripts/svn-apply
new file mode 100755
index 0000000..009bdd0
--- /dev/null
+++ b/WebKitTools/Scripts/svn-apply
@@ -0,0 +1,443 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# "patch" script for WebKit Open Source Project, used to apply patches.
+
+# Differences from invoking "patch -p0":
+#
+# Handles added files (does a svn add with logic to handle local changes).
+# Handles added directories (does a svn add).
+# Handles removed files (does a svn rm with logic to handle local changes).
+# Handles removed directories--those with no more files or directories left in them
+# (does a svn rm).
+# Has mode where it will roll back to svn version numbers in the patch file so svn
+# can do a 3-way merge.
+# Paths from Index: lines are used rather than the paths on the patch lines, which
+# makes patches generated by "cvs diff" work (increasingly unimportant since we
+# use Subversion now).
+# ChangeLog patches use --fuzz=3 to prevent rejects, and the entry date is set in
+# the patch to today's date using $changeLogTimeZone.
+# Handles binary files (requires patches made by svn-create-patch).
+# Handles copied and moved files (requires patches made by svn-create-patch).
+# Handles git-diff patches (without binary changes) created at the top-level directory
+#
+# Missing features:
+#
+# Handle property changes.
+# Handle copied and moved directories (would require patches made by svn-create-patch).
+# When doing a removal, check that old file matches what's being removed.
+# Notice a patch that's being applied at the "wrong level" and make it work anyway.
+# Do a dry run on the whole patch and don't do anything if part of the patch is
+# going to fail (probably too strict unless we exclude ChangeLog).
+# Handle git-diff patches with binary changes
+
+use strict;
+use warnings;
+
+use Cwd;
+use Digest::MD5;
+use File::Basename;
+use File::Spec;
+use Getopt::Long;
+use MIME::Base64;
+use POSIX qw(strftime);
+
+sub addDirectoriesIfNeeded($);
+sub applyPatch($$;$);
+sub checksum($);
+sub fixChangeLogPatch($);
+sub gitdiff2svndiff($);
+sub handleBinaryChange($$);
+sub isDirectoryEmptyForRemoval($);
+sub patch($);
+sub removeDirectoriesIfNeeded();
+sub setChangeLogDateAndReviewer($$);
+sub svnStatus($);
+
+# Project time zone for Cupertino, CA, US
+my $changeLogTimeZone = "PST8PDT";
+
+my $merge = 0;
+my $showHelp = 0;
+my $reviewer;
+if (!GetOptions("merge!" => \$merge, "help!" => \$showHelp, "reviewer=s" => \$reviewer) || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] [-m|--merge] [-r|--reviewer name] patch1 [patch2 ...]\n";
+ exit 1;
+}
+
+my %removeDirectoryIgnoreList = (
+ '.' => 1,
+ '..' => 1,
+ '.svn' => 1,
+ '_svn' => 1,
+);
+
+my %checkedDirectories;
+my %copiedFiles;
+my @patches;
+my %versions;
+
+my $copiedFromPath;
+my $filter;
+my $indexPath;
+my $patch;
+while (<>) {
+ s/([\n\r]+)$//mg;
+ my $eol = $1;
+ if (!defined($indexPath) && m#^diff --git a/#) {
+ $filter = \&gitdiff2svndiff;
+ }
+ $_ = &$filter($_) if $filter;
+ if (/^Index: (.+)/) {
+ $indexPath = $1;
+ if ($patch) {
+ if (!$copiedFromPath) {
+ push @patches, $patch;
+ }
+ $copiedFromPath = "";
+ $patch = "";
+ }
+ }
+ if ($indexPath) {
+ # Fix paths on diff, ---, and +++ lines to match preceding Index: line.
+ s/\S+$/$indexPath/ if /^diff/;
+ s/^--- \S+/--- $indexPath/;
+ if (/^--- .+\(from (\S+):(\d+)\)$/) {
+ $copiedFromPath = $1;
+ $copiedFiles{$indexPath} = $copiedFromPath;
+ $versions{$copiedFromPath} = $2 if ($2 != 0);
+ }
+ elsif (/^--- .+\(revision (\d+)\)$/) {
+ $versions{$indexPath} = $1 if ($1 != 0);
+ }
+ if (s/^\+\+\+ \S+/+++ $indexPath/) {
+ $indexPath = "";
+ }
+ }
+ $patch .= $_;
+ $patch .= $eol;
+}
+
+if ($patch && !$copiedFromPath) {
+ push @patches, $patch;
+}
+
+if ($merge) {
+ for my $file (sort keys %versions) {
+ print "Getting version $versions{$file} of $file\n";
+ system "svn", "update", "-r", $versions{$file}, $file;
+ }
+}
+
+# Handle copied and moved files first since moved files may have their source deleted before the move.
+for my $file (keys %copiedFiles) {
+ addDirectoriesIfNeeded(dirname($file));
+ system "svn", "copy", $copiedFiles{$file}, $file;
+}
+
+for $patch (@patches) {
+ patch($patch);
+}
+
+removeDirectoriesIfNeeded();
+
+exit 0;
+
+sub addDirectoriesIfNeeded($)
+{
+ my ($path) = @_;
+ my @dirs = File::Spec->splitdir($path);
+ my $dir = ".";
+ while (scalar @dirs) {
+ $dir = File::Spec->catdir($dir, shift @dirs);
+ next if exists $checkedDirectories{$dir};
+ if (! -e $dir) {
+ mkdir $dir or die "Failed to create required directory '$dir' for path '$path'\n";
+ system "svn", "add", $dir;
+ $checkedDirectories{$dir} = 1;
+ }
+ elsif (-d $dir) {
+ my $svnOutput = svnStatus($dir);
+ if ($svnOutput && $svnOutput =~ m#\?\s+$dir\n#) {
+ system "svn", "add", $dir;
+ }
+ $checkedDirectories{$dir} = 1;
+ }
+ else {
+ die "'$dir' is not a directory";
+ }
+ }
+}
+
+sub applyPatch($$;$)
+{
+ my ($patch, $fullPath, $options) = @_;
+ $options = [] if (! $options);
+ my $command = "patch " . join(" ", "-p0", @{$options});
+ open PATCH, "| $command" or die "Failed to patch $fullPath\n";
+ print PATCH $patch;
+ close PATCH;
+}
+
+sub checksum($)
+{
+ my $file = shift;
+ open(FILE, $file) or die "Can't open '$file': $!";
+ binmode(FILE);
+ my $checksum = Digest::MD5->new->addfile(*FILE)->hexdigest();
+ close(FILE);
+ return $checksum;
+}
+
+sub fixChangeLogPatch($)
+{
+ my $patch = shift;
+ my $contextLineCount = 3;
+
+ return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
+ my ($oldLineCount, $newLineCount) = ($1, $2);
+ return $patch if $oldLineCount <= $contextLineCount;
+
+ # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
+ # have lines of context at the top of a patch when the existing entry has the same
+ # date and author as the new entry. This nifty loop alters a ChangeLog patch so
+ # that the added lines ("+") in the patch always start at the beginning of the
+ # patch and there are no initial lines of context.
+ my $newPatch;
+ my $lineCountInState = 0;
+ my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
+ my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
+ my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
+ my $state = $stateHeader;
+ foreach my $line (split(/\n/, $patch)) {
+ $lineCountInState++;
+ if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
+ $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
+ $lineCountInState = 0;
+ $state = $statePreContext;
+ } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
+ $line = "+" . substr($line, 1);
+ if ($lineCountInState == $oldContentLineCountReduction) {
+ $lineCountInState = 0;
+ $state = $stateNewChanges;
+ }
+ } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
+ # No changes to these lines
+ if ($lineCountInState == $newContentLineCountWithoutContext) {
+ $lineCountInState = 0;
+ $state = $statePostContext;
+ }
+ } elsif ($state == $statePostContext) {
+ if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
+ $line = " " . substr($line, 1);
+ } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
+ next; # Discard
+ }
+ }
+ $newPatch .= $line . "\n";
+ }
+
+ return $newPatch;
+}
+
+sub gitdiff2svndiff($)
+{
+ $_ = shift @_;
+ if (m#^diff --git a/(.+) b/(.+)#) {
+ return "Index: $1";
+ } elsif (m/^new file.*/) {
+ return "";
+ } elsif (m#^index [0-9a-f]{7}\.\.[0-9a-f]{7} [0-9]{6}#) {
+ return "===================================================================";
+ } elsif (m#^--- a/(.+)#) {
+ return "--- $1";
+ } elsif (m#^\+\+\+ b/(.+)#) {
+ return "+++ $1";
+ }
+ return $_;
+}
+
+sub handleBinaryChange($$)
+{
+ my ($fullPath, $contents) = @_;
+ if ($contents =~ m#((\n[A-Za-z0-9+/]{76})+\n[A-Za-z0-9+/=]{4,76}\n)#) {
+ # Addition or Modification
+ open FILE, ">", $fullPath or die;
+ print FILE decode_base64($1);
+ close FILE;
+ my $svnOutput = svnStatus($fullPath);
+ if ($svnOutput && substr($svnOutput, 0, 1) eq "?") {
+ # Addition
+ system "svn", "add", $fullPath;
+ } else {
+ # Modification
+ print $svnOutput if $svnOutput;
+ }
+ } else {
+ # Deletion
+ system "svn", "rm", $fullPath;
+ }
+}
+
+sub isDirectoryEmptyForRemoval($)
+{
+ my ($dir) = @_;
+ my $directoryIsEmpty = 1;
+ opendir DIR, $dir or die "Could not open '$dir' to list files: $?";
+ for (my $item = readdir DIR; $item && $directoryIsEmpty; $item = readdir DIR) {
+ next if exists $removeDirectoryIgnoreList{$item};
+ if (! -d File::Spec->catdir($dir, $item)) {
+ $directoryIsEmpty = 0;
+ } else {
+ my $svnOutput = svnStatus(File::Spec->catdir($dir, $item));
+ next if $svnOutput && substr($svnOutput, 0, 1) eq "D";
+ $directoryIsEmpty = 0;
+ }
+ }
+ closedir DIR;
+ return $directoryIsEmpty;
+}
+
+sub patch($)
+{
+ my ($patch) = @_;
+ return if !$patch;
+
+ unless ($patch =~ m|^Index: ([^\n]+)|) {
+ my $separator = '-' x 67;
+ warn "Failed to find 'Index:' in:\n$separator\n$patch\n$separator\n";
+ return;
+ }
+ my $fullPath = $1;
+
+ my $deletion = 0;
+ my $addition = 0;
+ my $isBinary = 0;
+
+ $addition = 1 if ($patch =~ /\n--- .+\(revision 0\)\n/ || $patch =~ /\n@@ -0,0 .* @@/);
+ $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/;
+ $isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./;
+
+ if (!$addition && !$deletion && !$isBinary) {
+ # Standard patch, patch tool can handle this.
+ if (basename($fullPath) eq "ChangeLog") {
+ my $changeLogDotOrigExisted = -f "${fullPath}.orig";
+ applyPatch(setChangeLogDateAndReviewer(fixChangeLogPatch($patch), $reviewer), $fullPath, ["--fuzz=3"]);
+ unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted);
+ } else {
+ applyPatch($patch, $fullPath);
+ }
+ } else {
+ # Either a deletion, an addition or a binary change.
+
+ addDirectoriesIfNeeded(dirname($fullPath));
+
+ if ($isBinary) {
+ # Binary change
+ handleBinaryChange($fullPath, $patch);
+ } elsif ($deletion) {
+ # Deletion
+ applyPatch($patch, $fullPath, ["--force"]);
+ system "svn", "rm", "--force", $fullPath;
+ } else {
+ # Addition
+ rename($fullPath, "$fullPath.orig") if -e $fullPath;
+ applyPatch($patch, $fullPath);
+ unlink("$fullPath.orig") if -e "$fullPath.orig" && checksum($fullPath) eq checksum("$fullPath.orig");
+ system "svn", "add", $fullPath;
+ system "svn", "stat", "$fullPath.orig" if -e "$fullPath.orig";
+ }
+ }
+}
+
+sub removeDirectoriesIfNeeded()
+{
+ foreach my $dir (reverse sort keys %checkedDirectories) {
+ if (isDirectoryEmptyForRemoval($dir)) {
+ my $svnOutput;
+ open SVN, "svn rm '$dir' |" or die;
+ # Only save the last line since Subversion lists all changed statuses below $dir
+ while (<SVN>) {
+ $svnOutput = $_;
+ }
+ close SVN;
+ print $svnOutput if $svnOutput;
+ }
+ }
+}
+
+sub setChangeLogDateAndReviewer($$)
+{
+ my $patch = shift;
+ my $reviewer = shift;
+ my $savedTimeZone = $ENV{'TZ'};
+ # Set TZ temporarily so that localtime() is in that time zone
+ $ENV{'TZ'} = $changeLogTimeZone;
+ my $newDate = strftime("%Y-%m-%d", localtime());
+ if (defined $savedTimeZone) {
+ $ENV{'TZ'} = $savedTimeZone;
+ } else {
+ delete $ENV{'TZ'};
+ }
+ $patch =~ s/(\n\+)\d{4}-[^-]{2}-[^-]{2}( )/$1$newDate$2/;
+ if (defined($reviewer)) {
+ $patch =~ s/NOBODY \(OOPS!\)/$reviewer/;
+ }
+ return $patch;
+}
+
+sub svnStatus($)
+{
+ my ($fullPath) = @_;
+ my $svnStatus;
+ open SVN, "svn status --non-interactive --non-recursive '$fullPath' |" or die;
+ if (-d $fullPath) {
+ # When running "svn stat" on a directory, we can't assume that only one
+ # status will be returned (since any files with a status below the
+ # directory will be returned), and we can't assume that the directory will
+ # be first (since any files with unknown status will be listed first).
+ my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath));
+ while (<SVN>) {
+ chomp;
+ my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7)));
+ if ($normalizedFullPath eq $normalizedStatPath) {
+ $svnStatus = $_;
+ last;
+ }
+ }
+ # Read the rest of the svn command output to avoid a broken pipe warning.
+ local $/ = undef;
+ <SVN>;
+ }
+ else {
+ # Files will have only one status returned.
+ $svnStatus = <SVN>;
+ }
+ close SVN;
+ return $svnStatus;
+}
diff --git a/WebKitTools/Scripts/svn-create-patch b/WebKitTools/Scripts/svn-create-patch
new file mode 100755
index 0000000..365737a
--- /dev/null
+++ b/WebKitTools/Scripts/svn-create-patch
@@ -0,0 +1,442 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Extended "svn diff" script for WebKit Open Source Project, used to make patches.
+
+# Differences from standard "svn diff":
+#
+# Uses the real diff, not svn's built-in diff.
+# Always passes "-p" to diff so it will try to include function names.
+# Handles binary files (encoded as a base64 chunk of text).
+# Sorts the diffs alphabetically by text files, then binary files.
+# Handles copied and moved files.
+#
+# Missing features:
+#
+# Handle copied and moved directories.
+
+use strict;
+use warnings;
+
+use Config;
+use Cwd;
+use File::Basename;
+use File::Spec;
+use File::stat;
+use Getopt::Long;
+use MIME::Base64;
+use POSIX qw(:errno_h);
+use Time::gmtime;
+
+sub binarycmp($$);
+sub canonicalizePath($);
+sub findBaseUrl($);
+sub findMimeType($;$);
+sub findModificationType($);
+sub findSourceFileAndRevision($);
+sub fixChangeLogPatch($);
+sub generateDiff($);
+sub generateFileList($\%);
+sub isBinaryMimeType($);
+sub manufacturePatchForAdditionWithHistory($);
+sub numericcmp($$);
+sub outputBinaryContent($);
+sub patchpathcmp($$);
+sub pathcmp($$);
+sub processPaths(\@);
+sub splitpath($);
+sub testfilecmp($$);
+
+$ENV{'LC_ALL'} = 'C';
+
+my $showHelp;
+
+my $result = GetOptions(
+ "help" => \$showHelp,
+);
+if (!$result || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] [svndir1 [svndir2 ...]]\n";
+ exit 1;
+}
+
+# Sort the diffs for easier reviewing.
+my %paths = processPaths(@ARGV);
+
+# Generate a list of files requiring diffs.
+my %diffFiles;
+for my $path (keys %paths) {
+ generateFileList($path, %diffFiles);
+}
+
+# Generate the diffs, in a order chosen for easy reviewing.
+for my $path (sort patchpathcmp values %diffFiles) {
+ generateDiff($path);
+}
+
+exit 0;
+
+# Overall sort, considering multiple criteria.
+sub patchpathcmp($$)
+{
+ my ($a, $b) = @_;
+
+ # All binary files come after all non-binary files.
+ my $result = binarycmp($a, $b);
+ return $result if $result;
+
+ # All test files come after all non-test files.
+ $result = testfilecmp($a, $b);
+ return $result if $result;
+
+ # Final sort is a "smart" sort by directory and file name.
+ return pathcmp($a, $b);
+}
+
+# Sort so text files appear before binary files.
+sub binarycmp($$)
+{
+ my ($fileDataA, $fileDataB) = @_;
+ return $fileDataA->{isBinary} <=> $fileDataB->{isBinary};
+}
+
+sub canonicalizePath($)
+{
+ my ($file) = @_;
+
+ # Remove extra slashes and '.' directories in path
+ $file = File::Spec->canonpath($file);
+
+ # Remove '..' directories in path
+ my @dirs = ();
+ foreach my $dir (File::Spec->splitdir($file)) {
+ if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') {
+ pop(@dirs);
+ } else {
+ push(@dirs, $dir);
+ }
+ }
+ return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
+}
+
+sub findBaseUrl($)
+{
+ my ($infoPath) = @_;
+ my $baseUrl;
+ open INFO, "svn info '$infoPath' |" or die;
+ while (<INFO>) {
+ if (/^URL: (.+)/) {
+ $baseUrl = $1;
+ last;
+ }
+ }
+ close INFO;
+ return $baseUrl;
+}
+
+sub findMimeType($;$)
+{
+ my ($file, $revision) = @_;
+ my $args = $revision ? "--revision $revision" : "";
+ open PROPGET, "svn propget svn:mime-type $args '$file' |" or die;
+ my $mimeType = <PROPGET>;
+ close PROPGET;
+ chomp $mimeType if $mimeType;
+ return $mimeType;
+}
+
+sub findModificationType($)
+{
+ my ($stat) = @_;
+ my $fileStat = substr($stat, 0, 1);
+ my $propertyStat = substr($stat, 1, 1);
+ if ($fileStat eq "A") {
+ my $additionWithHistory = substr($stat, 3, 1);
+ return $additionWithHistory eq "+" ? "additionWithHistory" : "addition";
+ }
+ return "modification" if ($fileStat eq "M" || $propertyStat eq "M");
+ return "deletion" if ($fileStat eq "D");
+ return undef;
+}
+
+sub findSourceFileAndRevision($)
+{
+ my ($file) = @_;
+ my $baseUrl = findBaseUrl(".");
+ my $sourceFile;
+ my $sourceRevision;
+ open INFO, "svn info '$file' |" or die;
+ while (<INFO>) {
+ if (/^Copied From URL: (.+)/) {
+ $sourceFile = File::Spec->abs2rel($1, $baseUrl);
+ } elsif (/^Copied From Rev: ([0-9]+)/) {
+ $sourceRevision = $1;
+ }
+ }
+ close INFO;
+ return ($sourceFile, $sourceRevision);
+}
+
+sub fixChangeLogPatch($)
+{
+ my $patch = shift;
+ my $contextLineCount = 3;
+
+ return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
+ my ($oldLineCount, $newLineCount) = ($1, $2);
+ return $patch if $oldLineCount <= $contextLineCount;
+
+ # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
+ # have lines of context at the top of a patch when the existing entry has the same
+ # date and author as the new entry. This nifty loop alters a ChangeLog patch so
+ # that the added lines ("+") in the patch always start at the beginning of the
+ # patch and there are no initial lines of context.
+ my $newPatch;
+ my $lineCountInState = 0;
+ my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
+ my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
+ my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
+ my $state = $stateHeader;
+ foreach my $line (split(/\n/, $patch)) {
+ $lineCountInState++;
+ if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
+ $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
+ $lineCountInState = 0;
+ $state = $statePreContext;
+ } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
+ $line = "+" . substr($line, 1);
+ if ($lineCountInState == $oldContentLineCountReduction) {
+ $lineCountInState = 0;
+ $state = $stateNewChanges;
+ }
+ } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
+ # No changes to these lines
+ if ($lineCountInState == $newContentLineCountWithoutContext) {
+ $lineCountInState = 0;
+ $state = $statePostContext;
+ }
+ } elsif ($state == $statePostContext) {
+ if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
+ $line = " " . substr($line, 1);
+ } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
+ next; # Discard
+ }
+ }
+ $newPatch .= $line . "\n";
+ }
+
+ return $newPatch;
+}
+
+sub generateDiff($)
+{
+ my ($fileData) = @_;
+ my $file = $fileData->{path};
+ my $patch;
+ if ($fileData->{modificationType} eq "additionWithHistory") {
+ manufacturePatchForAdditionWithHistory($fileData);
+ }
+ open DIFF, "svn diff --diff-cmd diff -x -uaNp '$file' |" or die;
+ while (<DIFF>) {
+ $patch .= $_;
+ }
+ close DIFF;
+ $patch = fixChangeLogPatch($patch) if basename($file) eq "ChangeLog";
+ print $patch if $patch;
+ if ($fileData->{isBinary}) {
+ print "\n" if ($patch && $patch =~ m/\n\S+$/m);
+ outputBinaryContent($file);
+ }
+}
+
+sub generateFileList($\%)
+{
+ my ($statPath, $diffFiles) = @_;
+ my %testDirectories = map { $_ => 1 } qw(LayoutTests);
+ open STAT, "svn stat '$statPath' |" or die;
+ while (my $line = <STAT>) {
+ chomp $line;
+ my $stat = substr($line, 0, 7);
+ my $path = substr($line, 7);
+ next if -d $path;
+ my $modificationType = findModificationType($stat);
+ if ($modificationType) {
+ $diffFiles->{$path}->{path} = $path;
+ $diffFiles->{$path}->{modificationType} = $modificationType;
+ $diffFiles->{$path}->{isBinary} = isBinaryMimeType($path);
+ $diffFiles->{$path}->{isTestFile} = exists $testDirectories{(File::Spec->splitdir($path))[0]} ? 1 : 0;
+ if ($modificationType eq "additionWithHistory") {
+ my ($sourceFile, $sourceRevision) = findSourceFileAndRevision($path);
+ $diffFiles->{$path}->{sourceFile} = $sourceFile;
+ $diffFiles->{$path}->{sourceRevision} = $sourceRevision;
+ }
+ } else {
+ print STDERR $line, "\n";
+ }
+ }
+ close STAT;
+}
+
+sub isBinaryMimeType($)
+{
+ my ($file) = @_;
+ my $mimeType = findMimeType($file);
+ return 0 if (!$mimeType || substr($mimeType, 0, 5) eq "text/");
+ return 1;
+}
+
+sub manufacturePatchForAdditionWithHistory($)
+{
+ my ($fileData) = @_;
+ my $file = $fileData->{path};
+ print "Index: ${file}\n";
+ print "=" x 67, "\n";
+ my $sourceFile = $fileData->{sourceFile};
+ my $sourceRevision = $fileData->{sourceRevision};
+ print "--- ${file}\t(revision ${sourceRevision})\t(from ${sourceFile}:${sourceRevision})\n";
+ print "+++ ${file}\t(working copy)\n";
+ if ($fileData->{isBinary}) {
+ print "\nCannot display: file marked as a binary type.\n";
+ my $mimeType = findMimeType($file, $sourceRevision);
+ print "svn:mime-type = ${mimeType}\n\n";
+ } else {
+ print `svn cat ${sourceFile} | diff -u /dev/null - | tail -n +3`;
+ }
+}
+
+# Sort numeric parts of strings as numbers, other parts as strings.
+# Makes 1.33 come after 1.3, which is cool.
+sub numericcmp($$)
+{
+ my ($aa, $bb) = @_;
+
+ my @a = split /(\d+)/, $aa;
+ my @b = split /(\d+)/, $bb;
+
+ # Compare one chunk at a time.
+ # Each chunk is either all numeric digits, or all not numeric digits.
+ while (@a && @b) {
+ my $a = shift @a;
+ my $b = shift @b;
+
+ # Use numeric comparison if chunks are non-equal numbers.
+ return $a <=> $b if $a =~ /^\d/ && $b =~ /^\d/ && $a != $b;
+
+ # Use string comparison if chunks are any other kind of non-equal string.
+ return $a cmp $b if $a ne $b;
+ }
+
+ # One of the two is now empty; compare lengths for result in this case.
+ return @a <=> @b;
+}
+
+sub outputBinaryContent($)
+{
+ my ($path) = @_;
+ # Deletion
+ return if (! -e $path);
+ # Addition or Modification
+ my $buffer;
+ open BINARY, $path or die;
+ while (read(BINARY, $buffer, 60*57)) {
+ print encode_base64($buffer);
+ }
+ close BINARY;
+ print "\n";
+}
+
+# Sort first by directory, then by file, so all paths in one directory are grouped
+# rather than being interspersed with items from subdirectories.
+# Use numericcmp to sort directory and filenames to make order logical.
+# Also include a special case for ChangeLog, which comes first in any directory.
+sub pathcmp($$)
+{
+ my ($fileDataA, $fileDataB) = @_;
+
+ my ($dira, $namea) = splitpath($fileDataA->{path});
+ my ($dirb, $nameb) = splitpath($fileDataB->{path});
+
+ return numericcmp($dira, $dirb) if $dira ne $dirb;
+ return -1 if $namea eq "ChangeLog" && $nameb ne "ChangeLog";
+ return +1 if $namea ne "ChangeLog" && $nameb eq "ChangeLog";
+ return numericcmp($namea, $nameb);
+}
+
+sub processPaths(\@)
+{
+ my ($paths) = @_;
+ return ("." => 1) if (!@{$paths});
+
+ my %result = ();
+
+ for my $file (@{$paths}) {
+ die "can't handle absolute paths like \"$file\"\n" if File::Spec->file_name_is_absolute($file);
+ die "can't handle empty string path\n" if $file eq "";
+ die "can't handle path with single quote in the name like \"$file\"\n" if $file =~ /'/; # ' (keep Xcode syntax highlighting happy)
+
+ my $untouchedFile = $file;
+
+ $file = canonicalizePath($file);
+
+ die "can't handle paths with .. like \"$untouchedFile\"\n" if $file =~ m|/\.\./|;
+
+ $result{$file} = 1;
+ }
+
+ return ("." => 1) if ($result{"."});
+
+ # Remove any paths that also have a parent listed.
+ for my $path (keys %result) {
+ for (my $parent = dirname($path); $parent ne '.'; $parent = dirname($parent)) {
+ if ($result{$parent}) {
+ delete $result{$path};
+ last;
+ }
+ }
+ }
+
+ return %result;
+}
+
+# Break up a path into the directory (with slash) and base name.
+sub splitpath($)
+{
+ my ($path) = @_;
+
+ my $pathSeparator = "/";
+ my $dirname = dirname($path) . $pathSeparator;
+ $dirname = "" if $dirname eq "." . $pathSeparator;
+
+ return ($dirname, basename($path));
+}
+
+# Sort so source code files appear before test files.
+sub testfilecmp($$)
+{
+ my ($fileDataA, $fileDataB) = @_;
+ return $fileDataA->{isTestFile} <=> $fileDataB->{isTestFile};
+}
diff --git a/WebKitTools/Scripts/svn-unapply b/WebKitTools/Scripts/svn-unapply
new file mode 100755
index 0000000..35111ce
--- /dev/null
+++ b/WebKitTools/Scripts/svn-unapply
@@ -0,0 +1,374 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# "unpatch" script for WebKit Open Source Project, used to remove patches.
+
+# Differences from invoking "patch -p0 -R":
+#
+# Handles added files (does a svn revert with additional logic to handle local changes).
+# Handles added directories (does a svn revert and a rmdir).
+# Handles removed files (does a svn revert with additional logic to handle local changes).
+# Handles removed directories (does a svn revert).
+# Paths from Index: lines are used rather than the paths on the patch lines, which
+# makes patches generated by "cvs diff" work (increasingly unimportant since we
+# use Subversion now).
+# ChangeLog patches use --fuzz=3 to prevent rejects, and the entry date is reset in
+# the patch before it is applied (svn-apply sets it when applying a patch).
+# Handles binary files (requires patches made by svn-create-patch).
+# Handles copied and moved files (requires patches made by svn-create-patch).
+# Handles git-diff patches (without binary changes) created at the top-level directory
+#
+# Missing features:
+#
+# Handle property changes.
+# Handle copied and moved directories (would require patches made by svn-create-patch).
+# Use version numbers in the patch file and do a 3-way merge.
+# When reversing an addition, check that the file matches what's being removed.
+# Notice a patch that's being unapplied at the "wrong level" and make it work anyway.
+# Do a dry run on the whole patch and don't do anything if part of the patch is
+# going to fail (probably too strict unless we exclude ChangeLog).
+# Handle git-diff patches with binary changes
+
+use strict;
+use warnings;
+
+use Cwd;
+use Digest::MD5;
+use Fcntl qw(:DEFAULT :seek);
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+sub checksum($);
+sub fixChangeLogPatch($);
+sub gitdiff2svndiff($);
+sub patch($);
+sub revertDirectories();
+sub svnStatus($);
+sub unapplyPatch($$;$);
+sub unsetChangeLogDate($$);
+
+my $showHelp = 0;
+if (!GetOptions("help!" => \$showHelp) || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] patch1 [patch2 ...]\n";
+ exit 1;
+}
+
+my @copiedFiles;
+my %directoriesToCheck;
+
+my $copiedFromPath;
+my $filter;
+my $indexPath;
+my $patch;
+while (<>) {
+ s/([\n\r]+)$//mg;
+ my $eol = $1;
+ if (!defined($indexPath) && m#^diff --git a/#) {
+ $filter = \&gitdiff2svndiff;
+ }
+ $_ = &$filter($_) if $filter;
+ if (/^Index: (.*)/) {
+ $indexPath = $1;
+ if ($patch) {
+ if ($copiedFromPath) {
+ push @copiedFiles, $patch;
+ } else {
+ patch($patch);
+ }
+ $copiedFromPath = "";
+ $patch = "";
+ }
+ }
+ if ($indexPath) {
+ # Fix paths on diff, ---, and +++ lines to match preceding Index: line.
+ s/^--- \S+/--- $indexPath/;
+ if (/^--- .+\(from (\S+):\d+\)$/) {
+ $copiedFromPath = $1;
+ }
+ if (s/^\+\+\+ \S+/+++ $indexPath/) {
+ $indexPath = "";
+ }
+ }
+ $patch .= $_;
+ $patch .= $eol;
+}
+
+if ($patch) {
+ if ($copiedFromPath) {
+ push @copiedFiles, $patch;
+ } else {
+ patch($patch);
+ }
+}
+
+# Handle copied and moved files last since they may have had post-copy changes that have now been unapplied
+for $patch (@copiedFiles) {
+ patch($patch);
+}
+
+revertDirectories();
+
+exit 0;
+
+sub checksum($)
+{
+ my $file = shift;
+ open(FILE, $file) or die "Can't open '$file': $!";
+ binmode(FILE);
+ my $checksum = Digest::MD5->new->addfile(*FILE)->hexdigest();
+ close(FILE);
+ return $checksum;
+}
+
+sub fixChangeLogPatch($)
+{
+ my $patch = shift;
+ my $contextLineCount = 3;
+
+ return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
+ my ($oldLineCount, $newLineCount) = ($1, $2);
+ return $patch if $oldLineCount <= $contextLineCount;
+
+ # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
+ # have lines of context at the top of a patch when the existing entry has the same
+ # date and author as the new entry. This nifty loop alters a ChangeLog patch so
+ # that the added lines ("+") in the patch always start at the beginning of the
+ # patch and there are no initial lines of context.
+ my $newPatch;
+ my $lineCountInState = 0;
+ my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
+ my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
+ my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
+ my $state = $stateHeader;
+ foreach my $line (split(/\n/, $patch)) {
+ $lineCountInState++;
+ if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
+ $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
+ $lineCountInState = 0;
+ $state = $statePreContext;
+ } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
+ $line = "+" . substr($line, 1);
+ if ($lineCountInState == $oldContentLineCountReduction) {
+ $lineCountInState = 0;
+ $state = $stateNewChanges;
+ }
+ } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
+ # No changes to these lines
+ if ($lineCountInState == $newContentLineCountWithoutContext) {
+ $lineCountInState = 0;
+ $state = $statePostContext;
+ }
+ } elsif ($state == $statePostContext) {
+ if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
+ $line = " " . substr($line, 1);
+ } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
+ next; # Discard
+ }
+ }
+ $newPatch .= $line . "\n";
+ }
+
+ return $newPatch;
+}
+
+sub gitdiff2svndiff($)
+{
+ $_ = shift @_;
+ if (m#^diff --git a/(.+) b/(.+)#) {
+ return "Index: $1";
+ } elsif (m/^new file.*/) {
+ return "";
+ } elsif (m#^index [0-9a-f]{7}\.\.[0-9a-f]{7} [0-9]{6}#) {
+ return "===================================================================";
+ } elsif (m#^--- a/(.+)#) {
+ return "--- $1";
+ } elsif (m#^\+\+\+ b/(.+)#) {
+ return "+++ $1";
+ }
+ return $_;
+}
+
+sub patch($)
+{
+ my ($patch) = @_;
+ return if !$patch;
+
+ unless ($patch =~ m|^Index: ([^\n]+)|) {
+ my $separator = '-' x 67;
+ warn "Failed to find 'Index:' in:\n$separator\n$patch\n$separator\n";
+ return;
+ }
+ my $fullPath = $1;
+ $directoriesToCheck{dirname($fullPath)} = 1;
+
+ my $deletion = 0;
+ my $addition = 0;
+ my $isBinary = 0;
+
+ $addition = 1 if ($patch =~ /\n--- .+\(revision 0\)\n/ || $patch =~ /\n@@ -0,0 .* @@/);
+ $deletion = 1 if $patch =~ /\n@@ .* \+0,0 @@/;
+ $isBinary = 1 if $patch =~ /\nCannot display: file marked as a binary type\./;
+
+ if (!$addition && !$deletion && !$isBinary) {
+ # Standard patch, patch tool can handle this.
+ if (basename($fullPath) eq "ChangeLog") {
+ my $changeLogDotOrigExisted = -f "${fullPath}.orig";
+ unapplyPatch(unsetChangeLogDate($fullPath, fixChangeLogPatch($patch)), $fullPath, ["--fuzz=3"]);
+ unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted);
+ } else {
+ unapplyPatch($patch, $fullPath);
+ }
+ } else {
+ # Either a deletion, an addition or a binary change.
+
+ if ($isBinary) {
+ # Reverse binary change
+ unlink($fullPath) if (-e $fullPath);
+ system "svn", "revert", $fullPath;
+ } elsif ($deletion) {
+ # Reverse deletion
+ rename($fullPath, "$fullPath.orig") if -e $fullPath;
+
+ unapplyPatch($patch, $fullPath);
+
+ # If we don't ask for the filehandle here, we always get a warning.
+ my ($fh, $tempPath) = tempfile(basename($fullPath) . "-XXXXXXXX",
+ DIR => dirname($fullPath), UNLINK => 1);
+ close($fh);
+
+ # Keep the version from the patch in case it's different from svn.
+ rename($fullPath, $tempPath);
+ system "svn", "revert", $fullPath;
+ rename($tempPath, $fullPath);
+
+ # This works around a bug in the svn client.
+ # [Issue 1960] file modifications get lost due to FAT 2s time resolution
+ # http://subversion.tigris.org/issues/show_bug.cgi?id=1960
+ system "touch", $fullPath;
+
+ # Remove $fullPath.orig if it is the same as $fullPath
+ unlink("$fullPath.orig") if -e "$fullPath.orig" && checksum($fullPath) eq checksum("$fullPath.orig");
+
+ # Show status if the file is modifed
+ system "svn", "stat", $fullPath;
+ } else {
+ # Reverse addition
+ unapplyPatch($patch, $fullPath, ["--force"]);
+ unlink($fullPath) if -z $fullPath;
+ system "svn", "revert", $fullPath;
+ }
+ }
+}
+
+sub revertDirectories()
+{
+ my %checkedDirectories;
+ foreach my $path (reverse sort keys %directoriesToCheck) {
+ my @dirs = File::Spec->splitdir($path);
+ while (scalar @dirs) {
+ my $dir = File::Spec->catdir(@dirs);
+ pop(@dirs);
+ next if (exists $checkedDirectories{$dir});
+ if (-d $dir) {
+ my $svnOutput = svnStatus($dir);
+ if ($svnOutput && $svnOutput =~ m#A\s+$dir\n#) {
+ system "svn", "revert", $dir;
+ rmdir $dir;
+ }
+ elsif ($svnOutput && $svnOutput =~ m#D\s+$dir\n#) {
+ system "svn", "revert", $dir;
+ }
+ else {
+ # Modification
+ print $svnOutput if $svnOutput;
+ }
+ $checkedDirectories{$dir} = 1;
+ }
+ else {
+ die "'$dir' is not a directory";
+ }
+ }
+ }
+}
+
+sub svnStatus($)
+{
+ my ($fullPath) = @_;
+ my $svnStatus;
+ open SVN, "svn status --non-interactive --non-recursive '$fullPath' |" or die;
+ if (-d $fullPath) {
+ # When running "svn stat" on a directory, we can't assume that only one
+ # status will be returned (since any files with a status below the
+ # directory will be returned), and we can't assume that the directory will
+ # be first (since any files with unknown status will be listed first).
+ my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath));
+ while (<SVN>) {
+ chomp;
+ my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7)));
+ if ($normalizedFullPath eq $normalizedStatPath) {
+ $svnStatus = $_;
+ last;
+ }
+ }
+ # Read the rest of the svn command output to avoid a broken pipe warning.
+ local $/ = undef;
+ <SVN>;
+ }
+ else {
+ # Files will have only one status returned.
+ $svnStatus = <SVN>;
+ }
+ close SVN;
+ return $svnStatus;
+}
+
+sub unapplyPatch($$;$)
+{
+ my ($patch, $fullPath, $options) = @_;
+ $options = [] if (! $options);
+ my $command = "patch " . join(" ", "-p0", "-R", @{$options});
+ open PATCH, "| $command" or die "Failed to patch $fullPath: $!";
+ print PATCH $patch;
+ close PATCH;
+}
+
+sub unsetChangeLogDate($$)
+{
+ my $fullPath = shift;
+ my $patch = shift;
+ my $newDate;
+ sysopen(CHANGELOG, $fullPath, O_RDONLY) or die "Failed to open $fullPath: $!";
+ sysseek(CHANGELOG, 0, SEEK_SET);
+ my $byteCount = sysread(CHANGELOG, $newDate, 10);
+ die "Failed reading $fullPath: $!" if !$byteCount || $byteCount != 10;
+ close(CHANGELOG);
+ $patch =~ s/(\n\+)\d{4}-[^-]{2}-[^-]{2}( )/$1$newDate$2/;
+ return $patch;
+}
diff --git a/WebKitTools/Scripts/update-iexploder-cssproperties b/WebKitTools/Scripts/update-iexploder-cssproperties
new file mode 100755
index 0000000..b7ae6cb
--- /dev/null
+++ b/WebKitTools/Scripts/update-iexploder-cssproperties
@@ -0,0 +1,112 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This script updates WebKitTools/iExploder/htdocs/cssproperties.in based on
+# WebCore/css/CSSPropertyNames.in.
+
+use warnings;
+use strict;
+
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+use File::Spec;
+
+sub generateSectionFromCSSPropertyNamesFile();
+sub readiExploderFile();
+sub svnRevision($);
+sub writeiExploderFile();
+
+my $iExploderFile = File::Spec->catfile(sourceDir(), split("/", "WebKitTools/iExploder/htdocs/cssproperties.in"));
+my $cssPropertyNamesFile = File::Spec->catfile(sourceDir(), split("/", "WebCore/css/CSSPropertyNames.in"));
+
+my @sections = readiExploderFile();
+$sections[0] = generateSectionFromCSSPropertyNamesFile();
+writeiExploderFile();
+
+print `svn stat $iExploderFile`;
+print "Successfully updated!\n";
+
+exit 0;
+
+sub generateSectionFromCSSPropertyNamesFile()
+{
+ my $revision = svnRevision($cssPropertyNamesFile);
+ my $path = File::Spec->abs2rel($cssPropertyNamesFile, sourceDir());
+ my $result = "# From WebKit svn r" . $revision . " (" . $path . ")\n";
+
+ my @properties = ();
+
+ open(IN, $cssPropertyNamesFile) || die "$!";
+ while (my $l = <IN>) {
+ chomp $l;
+ next if $l =~ m/^\s*#/ || $l =~ m/^\s*$/;
+ push(@properties, $l);
+ }
+ close(IN);
+
+ $result .= join("\n", sort { $a cmp $b } @properties) . "\n\n";
+
+ return $result;
+}
+
+sub readiExploderFile()
+{
+ my @sections = ();
+ local $/ = "\n\n";
+
+ open(IN, $iExploderFile) || die "$!";
+ @sections = <IN>;
+ close(IN);
+
+ return @sections;
+}
+
+sub svnRevision($)
+{
+ my ($file) = @_;
+ my $revision = "";
+
+ open INFO, "svn info '$file' |" or die;
+ while (<INFO>) {
+ if (/^Revision: (.+)/) {
+ $revision = $1;
+ }
+ }
+ close INFO;
+
+ return $revision ? $revision : "UNKNOWN";
+}
+
+sub writeiExploderFile()
+{
+ open(OUT, "> $iExploderFile") || die "$!";
+ print OUT join("", @sections);
+ close(OUT);
+}
diff --git a/WebKitTools/Scripts/update-javascriptcore-test-results b/WebKitTools/Scripts/update-javascriptcore-test-results
new file mode 100755
index 0000000..dd8b9b6
--- /dev/null
+++ b/WebKitTools/Scripts/update-javascriptcore-test-results
@@ -0,0 +1,73 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use FindBin;
+use Getopt::Long;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+chdirWebKit();
+chdir "JavaScriptCore/tests/mozilla" or die;
+
+my $force = 0;
+GetOptions('force' => \$force);
+
+open EXPECTED, "expected.html" or die;
+while (<EXPECTED>) {
+ last if /failures reported\.$/;
+}
+my %expected;
+while (<EXPECTED>) {
+ chomp;
+ $expected{$_} = 1;
+}
+close EXPECTED;
+
+open ACTUAL, "actual.html" or die;
+my $actual;
+while (<ACTUAL>) {
+ $actual .= $_;
+ last if /failures reported\.$/;
+}
+my $failed = 0;
+while (<ACTUAL>) {
+ $actual .= $_;
+ chomp;
+ if (!$expected{$_}) {
+ $failed = 1;
+ print "failure not expected: $_\n";
+ }
+}
+close ACTUAL;
+
+die "won't update, failures introduced\n" if $failed && !$force;
+
+open EXPECTED, ">expected.html";
+print EXPECTED $actual;
+close EXPECTED;
diff --git a/WebKitTools/Scripts/update-sources-list.py b/WebKitTools/Scripts/update-sources-list.py
new file mode 100644
index 0000000..e565059
--- /dev/null
+++ b/WebKitTools/Scripts/update-sources-list.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+
+# Copyright (C) 2007 Kevin Ollivier All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Make sure any port-independent files added to the Bakefile are
+# added to GTK, QT, etc. so that file updates can happen in one place.
+
+import os, sys
+from xml.dom import minidom
+
+scriptDir = os.path.abspath(sys.path[0])
+wkroot = os.path.abspath(os.path.join(scriptDir, "../.."))
+
+def getWebCoreFilesDict():
+ """
+ This method parses the WebCoreSources.bkl file, which has a list of all sources not specific
+ to any port, and returns the result as a dictionary with items of the form
+ (groupName, groupFiles).
+ """
+ sources = {}
+ sources_prefix = "WEBCORE_"
+ filepath = os.path.join(wkroot, "WebCore/WebCoreSources.bkl")
+ assert(os.path.exists(filepath))
+
+ doc = minidom.parse(filepath)
+ for sourceGroup in doc.getElementsByTagName("set"):
+ groupName = ""
+ if sourceGroup.attributes.has_key("var"):
+ groupName = sourceGroup.attributes["var"].value
+ groupName = groupName.replace(sources_prefix, "")
+
+ sourcesList = []
+ for node in sourceGroup.childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ sourcesText = node.nodeValue.strip()
+ sourcesList = sourcesText.split("\n")
+
+ assert(groupName != "")
+ assert(sourcesList != [])
+
+ sources[groupName] = sourcesList
+
+ return sources
+
+def generateWebCoreSourcesGTKAndQT(sources):
+ """
+ Convert the dictionary obtained from getWebCoreFilesDict() into a Unix makefile syntax,
+ which IIUC is suitable for both GTK and QT build systems. To take advantage of this,
+ QT and GTK would have to include the file "WebCore/sources.inc" into their makefiles.
+ """
+ makefileString = ""
+
+ for key in sources.keys():
+ makefileString += key + "+="
+ for source in sources[key]:
+ makefileString += " \\\n\t\t" + source.strip()
+
+ makefileString += "\n\n"
+
+ makefileString += "BASE_SOURCES +="
+ for key in sources.keys():
+ makefileString += " \\\n\t\t" + key
+
+ outfile = os.path.join(wkroot, "WebCore/sources.inc")
+ sourcefile = open(outfile, "w")
+ sourcefile.write(makefileString)
+ sourcefile.close()
+
+sources = getWebCoreFilesDict()
+generateWebCoreSourcesGTKAndQT(sources)
+
+# Coming soon - MSVC and hopefully XCode support!
diff --git a/WebKitTools/Scripts/update-webkit b/WebKitTools/Scripts/update-webkit
new file mode 100755
index 0000000..c236934
--- /dev/null
+++ b/WebKitTools/Scripts/update-webkit
@@ -0,0 +1,92 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Update script for WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use File::Basename;
+use File::Spec;
+use Getopt::Long;
+use webkitdirs;
+
+sub runSvnUpdate();
+
+# Handle options
+my $quiet = '';
+my $showHelp;
+
+my $getOptionsResult = GetOptions(
+ 'h|help' => \$showHelp,
+ 'q|quiet' => \$quiet,
+);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR <<__END__;
+Usage: @{[ basename($0) ]} [options]
+ -h|--help show the help message
+ -q|--quiet pass -q to svn update for quiet updates
+__END__
+ exit 1;
+}
+
+my @svnOptions = ();
+push @svnOptions, '-q' if $quiet;
+
+chdirWebKit();
+print "Updating OpenSource\n" unless $quiet;
+runSvnUpdate();
+
+if (-d "../Internal") {
+ chdir("../Internal");
+ print "Updating Internal\n" unless $quiet;
+ runSvnUpdate();
+} elsif (isAppleWinWebKit()) {
+ system("perl", "WebKitTools/Scripts/update-webkit-auxiliary-libs") == 0 or die;
+}
+
+exit 0;
+
+sub runSvnUpdate()
+{
+ open UPDATE, "-|", "svn", "update", @svnOptions or die;
+ my @conflictedChangeLogs;
+ while (my $line = <UPDATE>) {
+ print $line;
+ push @conflictedChangeLogs, $1 if $line =~ m/^C\s+(.+)\s*$/ && basename($1) eq "ChangeLog";
+ }
+ close UPDATE or die;
+
+ if (@conflictedChangeLogs) {
+ print "Attempting to merge conflicted ChangeLogs.\n";
+ my $resolveChangeLogsPath = File::Spec->catfile(dirname($0), "resolve-ChangeLogs");
+ (system($resolveChangeLogsPath, "--no-warnings", @conflictedChangeLogs) == 0)
+ or die "Could not open resolve-ChangeLogs script: $!.\n";
+ }
+}
diff --git a/WebKitTools/Scripts/update-webkit-auxiliary-libs b/WebKitTools/Scripts/update-webkit-auxiliary-libs
new file mode 100755
index 0000000..1d6943c
--- /dev/null
+++ b/WebKitTools/Scripts/update-webkit-auxiliary-libs
@@ -0,0 +1,121 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Updates a development environment to the new WebKitAuxiliaryLibrary
+
+use strict;
+use warnings;
+
+use HTTP::Date qw(str2time);
+use File::Find;
+use File::Temp;
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub lastModifiedToUnixTime($);
+
+# Time in seconds that the new zip file must be newer than the old for us to
+# consider them to be different. If the difference in modification time is less
+# than this threshold, we assume that the files are the same. We need this
+# because the zip file is served from a set of mirrors with slightly different
+# Last-Modified times.
+my $newnessThreshold = 30;
+
+my $sourceDir = sourceDir();
+my $file = "WebKitAuxiliaryLibrary";
+my $zipFile = "$file.zip";
+my $auxiliaryLibsURL = "http://developer.apple.com/opensource/internet/$zipFile";
+my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win";
+my $tmpDir = File::Spec->rel2abs(File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1));
+
+print "Checking Last-Modified date of $zipFile...\n";
+
+my $result = system "curl -s -I $auxiliaryLibsURL | grep Last-Modified > \"$tmpDir/$file.headers\"";
+print STDERR "Couldn't check Last-Modified date of new $zipFile.\n" if $result;
+
+if (!$result && open NEW, "$tmpDir/$file.headers") {
+ my $new = lastModifiedToUnixTime(<NEW>);
+ close NEW;
+
+ if (defined $new && open OLD, "$webkitLibrariesDir/$file.headers") {
+ my $old = lastModifiedToUnixTime(<OLD>);
+ close OLD;
+ if (defined $old && abs($new - $old) < $newnessThreshold) {
+ print "Current $file is up to date\n";
+ exit 0;
+ }
+ }
+}
+
+print "Downloading $zipFile...\n\n";
+$result = system "curl -o \"$tmpDir/$zipFile\" $auxiliaryLibsURL";
+die "Couldn't download $zipFile!" if $result;
+
+$result = system "unzip", "-q", "-d", $tmpDir, "$tmpDir/$zipFile";
+die "Couldn't unzip $zipFile." if $result;
+
+print "\nInstalling $file...\n";
+
+sub wanted
+{
+ my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpDir/$file/win");
+ my $destination = "$webkitLibrariesDir/$relativeName";
+
+ if (-d $_) {
+ mkdir $destination;
+ return;
+ }
+
+ system "cp", $_, $destination;
+}
+
+File::Find::find(\&wanted, "$tmpDir/$file");
+
+$result = system "mv", "$tmpDir/$file.headers", $webkitLibrariesDir;
+print STDERR "Couldn't move $file.headers to $webkitLibrariesDir" . ".\n" if $result;
+
+print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n";
+exit;
+
+sub toUnixPath
+{
+ my $path = shift;
+ return unless $path;
+ chomp($path = `cygpath -u '$path'`);
+ return $path;
+}
+
+sub lastModifiedToUnixTime($)
+{
+ my ($str) = @_;
+
+ $str =~ /^Last-Modified: (.*)$/ or return;
+ return str2time($1);
+}
diff --git a/WebKitTools/Scripts/update-webkit-localizable-strings b/WebKitTools/Scripts/update-webkit-localizable-strings
new file mode 100755
index 0000000..350bf21
--- /dev/null
+++ b/WebKitTools/Scripts/update-webkit-localizable-strings
@@ -0,0 +1,46 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my @directoriesToScan = ("WebKit/mac", "WebKit/win");
+my $fileToUpdate = "WebKit/English.lproj/Localizable.strings";
+my $exceptionsFile = "WebKit/StringsNotToBeLocalized.txt";
+
+@ARGV == 0 or die "Usage: " . basename($0) . "\n";
+
+chdirWebKit();
+
+system "sort -u $exceptionsFile -o $exceptionsFile";
+exec "extract-localizable-strings", $exceptionsFile, $fileToUpdate, @directoriesToScan;
diff --git a/WebKitTools/Scripts/update-webkit-support-libs b/WebKitTools/Scripts/update-webkit-support-libs
new file mode 100755
index 0000000..c4555f3
--- /dev/null
+++ b/WebKitTools/Scripts/update-webkit-support-libs
@@ -0,0 +1,133 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple Computer, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Updates a development environment to the new WebKitSupportLibrary
+
+use strict;
+use warnings;
+
+use File::Find;
+use File::Temp;
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my $expectedMD5 = "a1341aadbcce1ef26dad2b2895457314";
+
+my $sourceDir = sourceDir();
+my $file = "WebKitSupportLibrary";
+my $zipFile = "$file.zip";
+my $zipDirectory = toUnixPath($ENV{'WEBKITSUPPORTLIBRARIESZIPDIR'}) || $sourceDir;
+my $pathToZip = File::Spec->catfile($zipDirectory, $zipFile);
+my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win";
+my $tmpDir = File::Spec->rel2abs(File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1));
+
+# Make sure the file zipfile exists and matches the expected MD5 before doing anything.
+
+-f $pathToZip or dieAndInstructToDownload("$zipFile could not be find in your root source directory.");
+
+`md5sum "$pathToZip"` =~ /^([0-9a-fA-F]{32}).*/ or die "Error running md5sum on \"$pathToZip\"";
+my $actualMD5 = $1;
+$actualMD5 eq $expectedMD5 or dieAndInstructToDownload("$zipFile is out of date.");
+
+print "Checking mod-date of $zipFile...\n";
+open MOD, ">$tmpDir/$file.modified" or die "Couldn't open $tmpDir/$file.modified for writing";
+print MOD (stat $pathToZip)[9] . "\n";
+close MOD;
+
+if (open NEW, "$tmpDir/$file.modified") {
+ my $new = <NEW>;
+ close NEW;
+
+ if (open OLD, "$webkitLibrariesDir/$file.modified") {
+ my $old = <OLD>;
+ close OLD;
+ if ($old eq $new) {
+ print "Current $file is up to date\n";
+ exit 0;
+ }
+ }
+}
+
+my $result = system "unzip", "-q", "-d", $tmpDir, $pathToZip;
+die "Couldn't unzip $zipFile." if $result;
+
+print "\nInstalling $file...\n";
+
+sub wanted
+{
+ my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpDir/$file/win");
+ my $destination = "$webkitLibrariesDir/$relativeName";
+
+ if (-d $_) {
+ mkdir $destination;
+ return;
+ }
+
+ system "cp", $_, $destination;
+}
+
+File::Find::find(\&wanted, "$tmpDir/$file");
+
+$result = system "mv", "$tmpDir/$file.modified", $webkitLibrariesDir;
+print STDERR "Couldn't move $file.modified to $webkitLibrariesDir" . ".\n" if $result;
+
+print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n";
+exit;
+
+sub toUnixPath
+{
+ my $path = shift;
+ return unless $path;
+ chomp($path = `cygpath -u '$path'`);
+ return $path;
+}
+
+sub dieAndInstructToDownload
+{
+ my $message = shift;
+
+ die <<EOF;
+
+===============================================================================
+$message
+Please download $zipFile from:
+
+ http://developer.apple.com/opensource/internet/webkit_sptlib_agree.html
+
+and place it in:
+
+ $sourceDir
+
+Then run build-webkit again.
+===============================================================================
+
+EOF
+
+}
diff --git a/WebKitTools/Scripts/webkitdirs.pm b/WebKitTools/Scripts/webkitdirs.pm
new file mode 100644
index 0000000..f9f05d3
--- /dev/null
+++ b/WebKitTools/Scripts/webkitdirs.pm
@@ -0,0 +1,1249 @@
+# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Module to share code to get to WebKit directories.
+
+use strict;
+use warnings;
+use FindBin;
+use File::Basename;
+use POSIX;
+use VCSUtils;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&chdirWebKit &baseProductDir &productDir &XcodeOptions &XcodeOptionString &XcodeOptionStringNoConfig &passedConfiguration &setConfiguration &safariPath &checkFrameworks &currentSVNRevision);
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+our @EXPORT_OK;
+
+my $architecture;
+my $baseProductDir;
+my @baseProductDirOption;
+my $configuration;
+my $configurationForVisualStudio;
+my $configurationProductDir;
+my $sourceDir;
+my $currentSVNRevision;
+my $osXVersion;
+my $isQt;
+my $isGtk;
+my $isWx;
+my @wxArgs;
+my $isChromium;
+
+# Variables for Win32 support
+my $vcBuildPath;
+my $windowsTmpPath;
+
+sub determineSourceDir
+{
+ return if $sourceDir;
+ $sourceDir = $FindBin::Bin;
+ $sourceDir =~ s|/+$||; # Remove trailing '/' as we would die later
+
+ # walks up path checking each directory to see if it is the main WebKit project dir,
+ # defined by containing JavaScriptCore, WebCore, and WebKit
+ until ((-d "$sourceDir/JavaScriptCore" && -d "$sourceDir/WebCore" && -d "$sourceDir/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource"))
+ {
+ if ($sourceDir !~ s|/[^/]+$||) {
+ die "Could not find top level webkit directory above source directory using FindBin.\n";
+ }
+ }
+
+ $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource";
+}
+
+# used for scripts which are stored in a non-standard location
+sub setSourceDir($)
+{
+ ($sourceDir) = @_;
+}
+
+sub determineBaseProductDir
+{
+ return if defined $baseProductDir;
+ determineSourceDir();
+ if (isAppleMacWebKit()) {
+ open PRODUCT, "defaults read com.apple.Xcode PBXApplicationwideBuildSettings 2> /dev/null |" or die;
+ $baseProductDir = join '', <PRODUCT>;
+ close PRODUCT;
+
+ $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s;
+ undef $baseProductDir unless $baseProductDir =~ /^\//;
+
+ if (!defined($baseProductDir)) {
+ open PRODUCT, "defaults read com.apple.Xcode PBXProductDirectory 2> /dev/null |" or die;
+ $baseProductDir = <PRODUCT>;
+ close PRODUCT;
+ if ($baseProductDir) {
+ chomp $baseProductDir;
+ undef $baseProductDir unless $baseProductDir =~ /^\//;
+ }
+ }
+ } else {
+ $baseProductDir = $ENV{"WEBKITOUTPUTDIR"};
+ if (isAppleWinWebKit() && $baseProductDir) {
+ my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
+ chomp $unixBuildPath;
+ $baseProductDir = $unixBuildPath;
+ }
+ }
+
+ if ($baseProductDir && isAppleMacWebKit()) {
+ $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
+ $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
+ $baseProductDir =~ s|^~/|$ENV{HOME}/|;
+ die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
+ die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
+ @baseProductDirOption = ();
+ }
+
+ if (!defined($baseProductDir)) {
+ $baseProductDir = "$sourceDir/WebKitBuild";
+
+ if (isGit() && isGitBranchBuild()) {
+ my $branch = gitBranch();
+ $baseProductDir = "$baseProductDir/$branch";
+ }
+
+ @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir") if (isAppleMacWebKit());
+ if (isCygwin()) {
+ my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
+ chomp $dosBuildPath;
+ $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
+ }
+ }
+}
+
+sub setBaseProductDir($)
+{
+ ($baseProductDir) = @_;
+}
+
+sub determineConfiguration
+{
+ return if defined $configuration;
+ determineBaseProductDir();
+ if (open CONFIGURATION, "$baseProductDir/Configuration") {
+ $configuration = <CONFIGURATION>;
+ close CONFIGURATION;
+ }
+ if ($configuration) {
+ chomp $configuration;
+ # compatibility for people who have old Configuration files
+ $configuration = "Release" if $configuration eq "Deployment";
+ $configuration = "Debug" if $configuration eq "Development";
+ } else {
+ $configuration = "Release";
+ }
+}
+
+sub determineArchitecture
+{
+ return if defined $architecture;
+ # make sure $architecture is defined for non-apple-mac builds
+ $architecture = "";
+ return unless isAppleMacWebKit();
+
+ determineBaseProductDir();
+ if (open ARCHITECTURE, "$baseProductDir/Architecture") {
+ $architecture = <ARCHITECTURE>;
+ close ARCHITECTURE;
+ }
+ if ($architecture) {
+ chomp $architecture;
+ } else {
+ if (isTiger() or isLeopard()) {
+ $architecture = `arch`;
+ } else {
+ my $supports64Bit = `sysctl -n hw.optional.x86_64`;
+ chomp $supports64Bit;
+ $architecture = $supports64Bit ? 'x86_64' : `arch`;
+ }
+ chomp $architecture;
+ }
+}
+
+sub argumentsForConfiguration()
+{
+ determineConfiguration();
+ determineArchitecture();
+
+ my @args = ();
+ push(@args, '--debug') if $configuration eq "Debug";
+ push(@args, '--release') if $configuration eq "Release";
+ push(@args, '--32-bit') if $architecture ne "x86_64";
+ push(@args, '--qt') if isQt();
+ push(@args, '--gtk') if isGtk();
+ push(@args, '--wx') if isWx();
+ push(@args, '--chromium') if isChromium();
+ return @args;
+}
+
+sub determineConfigurationForVisualStudio
+{
+ return if defined $configurationForVisualStudio;
+ determineConfiguration();
+ $configurationForVisualStudio = $configuration;
+ return unless $configuration eq "Debug";
+ setupCygwinEnv();
+ chomp(my $dir = `cygpath -ua '$ENV{WEBKITLIBRARIESDIR}'`);
+ $configurationForVisualStudio = "Debug_Internal" if -f "$dir/bin/CoreFoundation_debug.dll";
+}
+
+sub determineConfigurationProductDir
+{
+ return if defined $configurationProductDir;
+ determineBaseProductDir();
+ determineConfiguration();
+ if (isAppleWinWebKit() && !isWx()) {
+ $configurationProductDir = "$baseProductDir/bin";
+ } else {
+ $configurationProductDir = "$baseProductDir/$configuration";
+ }
+}
+
+sub setConfigurationProductDir($)
+{
+ ($configurationProductDir) = @_;
+}
+
+sub determineCurrentSVNRevision
+{
+ return if defined $currentSVNRevision;
+ determineSourceDir();
+ $currentSVNRevision = svnRevisionForDirectory($sourceDir);
+ return $currentSVNRevision;
+}
+
+
+sub chdirWebKit
+{
+ determineSourceDir();
+ chdir $sourceDir or die;
+}
+
+sub baseProductDir
+{
+ determineBaseProductDir();
+ return $baseProductDir;
+}
+
+sub sourceDir
+{
+ determineSourceDir();
+ return $sourceDir;
+}
+
+sub productDir
+{
+ determineConfigurationProductDir();
+ return $configurationProductDir;
+}
+
+sub configuration()
+{
+ determineConfiguration();
+ return $configuration;
+}
+
+sub configurationForVisualStudio()
+{
+ determineConfigurationForVisualStudio();
+ return $configurationForVisualStudio;
+}
+
+sub currentSVNRevision
+{
+ determineCurrentSVNRevision();
+ return $currentSVNRevision;
+}
+
+sub XcodeOptions
+{
+ determineBaseProductDir();
+ determineConfiguration();
+ determineArchitecture();
+ return (@baseProductDirOption, "-configuration", $configuration, "ARCHS=$architecture");
+}
+
+sub XcodeOptionString
+{
+ return join " ", XcodeOptions();
+}
+
+sub XcodeOptionStringNoConfig
+{
+ return join " ", @baseProductDirOption;
+}
+
+sub XcodeCoverageSupportOptions()
+{
+ my @coverageSupportOptions = ();
+ push @coverageSupportOptions, "GCC_GENERATE_TEST_COVERAGE_FILES=YES";
+ push @coverageSupportOptions, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES";
+ push @coverageSupportOptions, "EXTRA_LINK= \$(EXTRA_LINK) -ftest-coverage -fprofile-arcs";
+ push @coverageSupportOptions, "OTHER_CFLAGS= \$(OTHER_CFLAGS) -MD";
+ push @coverageSupportOptions, "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ftest-coverage -fprofile-arcs -framework AppKit";
+ return @coverageSupportOptions;
+}
+
+my $passedConfiguration;
+my $searchedForPassedConfiguration;
+sub determinePassedConfiguration
+{
+ return if $searchedForPassedConfiguration;
+ $searchedForPassedConfiguration = 1;
+
+ my $isWinCairo = checkForArgumentAndRemoveFromARGV("--cairo-win32");
+
+ for my $i (0 .. $#ARGV) {
+ my $opt = $ARGV[$i];
+ if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) {
+ splice(@ARGV, $i, 1);
+ $passedConfiguration = "Debug";
+ $passedConfiguration .= "_Cairo" if ($isWinCairo && isCygwin());
+ return;
+ }
+ if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) {
+ splice(@ARGV, $i, 1);
+ $passedConfiguration = "Release";
+ $passedConfiguration .= "_Cairo" if ($isWinCairo && isCygwin());
+ return;
+ }
+ if ($opt =~ /^--profil(e|ing)$/i) {
+ splice(@ARGV, $i, 1);
+ $passedConfiguration = "Profiling";
+ $passedConfiguration .= "_Cairo" if ($isWinCairo && isCygwin());
+ return;
+ }
+ }
+ $passedConfiguration = undef;
+}
+
+sub passedConfiguration
+{
+ determinePassedConfiguration();
+ return $passedConfiguration;
+}
+
+sub setConfiguration
+{
+ setArchitecture();
+
+ if (my $config = shift @_) {
+ $configuration = $config;
+ return;
+ }
+
+ determinePassedConfiguration();
+ $configuration = $passedConfiguration if $passedConfiguration;
+}
+
+
+my $passedArchitecture;
+my $searchedForPassedArchitecture;
+sub determinePassedArchitecture
+{
+ return if $searchedForPassedArchitecture;
+ $searchedForPassedArchitecture = 1;
+
+ for my $i (0 .. $#ARGV) {
+ my $opt = $ARGV[$i];
+ if ($opt =~ /^--32-bit$/i) {
+ splice(@ARGV, $i, 1);
+ if (isAppleMacWebKit()) {
+ $passedArchitecture = `arch`;
+ chomp $passedArchitecture;
+ }
+ return;
+ }
+ }
+ $passedArchitecture = undef;
+}
+
+sub passedArchitecture
+{
+ determinePassedArchitecture();
+ return $passedArchitecture;
+}
+
+sub architecture()
+{
+ determineArchitecture();
+ return $architecture;
+}
+
+sub setArchitecture
+{
+ if (my $arch = shift @_) {
+ $architecture = $arch;
+ return;
+ }
+
+ determinePassedArchitecture();
+ $architecture = $passedArchitecture if $passedArchitecture;
+}
+
+
+sub safariPathFromSafariBundle
+{
+ my ($safariBundle) = @_;
+
+ return "$safariBundle/Contents/MacOS/Safari" if isAppleMacWebKit();
+ return $safariBundle if isAppleWinWebKit();
+}
+
+sub installedSafariPath
+{
+ my $safariBundle;
+
+ if (isAppleMacWebKit()) {
+ $safariBundle = "/Applications/Safari.app";
+ } elsif (isAppleWinWebKit()) {
+ $safariBundle = `"$configurationProductDir/FindSafari.exe"`;
+ $safariBundle =~ s/[\r\n]+$//;
+ $safariBundle = `cygpath -u '$safariBundle'`;
+ $safariBundle =~ s/[\r\n]+$//;
+ $safariBundle .= "Safari.exe";
+ }
+
+ return safariPathFromSafariBundle($safariBundle);
+}
+
+# Locate Safari.
+sub safariPath
+{
+ # Use WEBKIT_SAFARI environment variable if present.
+ my $safariBundle = $ENV{WEBKIT_SAFARI};
+ if (!$safariBundle) {
+ determineConfigurationProductDir();
+ # Use Safari.app in product directory if present (good for Safari development team).
+ if (isAppleMacWebKit() && -d "$configurationProductDir/Safari.app") {
+ $safariBundle = "$configurationProductDir/Safari.app";
+ } elsif (isAppleWinWebKit() && -x "$configurationProductDir/bin/Safari.exe") {
+ $safariBundle = "$configurationProductDir/bin/Safari.exe";
+ } else {
+ return installedSafariPath();
+ }
+ }
+ my $safariPath = safariPathFromSafariBundle($safariBundle);
+ die "Can't find executable at $safariPath.\n" if isAppleMacWebKit() && !-x $safariPath;
+ return $safariPath;
+}
+
+sub builtDylibPathForName
+{
+ my $libraryName = shift;
+ determineConfigurationProductDir();
+ if (isQt() or isChromium()) {
+ return "$configurationProductDir/$libraryName";
+ }
+ if (isGtk()) {
+ return "$configurationProductDir/$libraryName/../.libs/libwebkit-1.0.so";
+ }
+ if (isAppleMacWebKit()) {
+ return "$configurationProductDir/$libraryName.framework/Versions/A/$libraryName";
+ }
+ if (isAppleWinWebKit()) {
+ if ($libraryName eq "JavaScriptCore") {
+ return "$baseProductDir/lib/$libraryName.lib";
+ } else {
+ return "$baseProductDir/$libraryName.intermediate/$configuration/$libraryName.intermediate/$libraryName.lib";
+ }
+ }
+
+ die "Unsupported platform, can't determine built library locations.";
+}
+
+# Check to see that all the frameworks are built.
+sub checkFrameworks
+{
+ return if isCygwin();
+ my @frameworks = ("JavaScriptCore", "WebCore");
+ push(@frameworks, "WebKit") if isAppleMacWebKit();
+ for my $framework (@frameworks) {
+ my $path = builtDylibPathForName($framework);
+ die "Can't find built framework at \"$path\".\n" unless -x $path;
+ }
+}
+
+sub hasSVGSupport
+{
+ return 0 if isCygwin();
+
+ my $path = shift;
+
+ if (isQt()) {
+ return 1;
+ }
+
+ my $hasSVGSupport = 0;
+ if (-e $path) {
+ open NM, "-|", "nm", $path or die;
+ while (<NM>) {
+ $hasSVGSupport = 1 if /SVGElement/;
+ }
+ close NM;
+ }
+ return $hasSVGSupport;
+}
+
+sub removeLibraryDependingOnSVG
+{
+ my $frameworkName = shift;
+ my $shouldHaveSVG = shift;
+
+ my $path = builtDylibPathForName($frameworkName);
+ return unless -x $path;
+
+ my $hasSVG = hasSVGSupport($path);
+ system "rm -f $path" if ($shouldHaveSVG xor $hasSVG);
+}
+
+sub checkWebCoreSVGSupport
+{
+ my $required = shift;
+ my $framework = "WebCore";
+ my $path = builtDylibPathForName($framework);
+ my $hasSVG = hasSVGSupport($path);
+ if ($required && !$hasSVG) {
+ die "$framework at \"$path\" does not include SVG Support, please run build-webkit --svg\n";
+ }
+ return $hasSVG;
+}
+
+sub hasAcceleratedCompositingSupport
+{
+ return 0 if isCygwin() || isQt();
+
+ my $path = shift;
+
+ my $useAcceleratedCompositing = 0;
+ if (-e $path) {
+ open NM, "-|", "nm", $path or die;
+ while (<NM>) {
+ $useAcceleratedCompositing = 1 if /GraphicsLayer/;
+ }
+ close NM;
+ }
+ return $useAcceleratedCompositing;
+}
+
+sub checkWebCoreAcceleratedCompositingSupport
+{
+ my $required = shift;
+ my $framework = "WebCore";
+ my $path = builtDylibPathForName($framework);
+ my $hasAcceleratedCompositing = hasAcceleratedCompositingSupport($path);
+ if ($required && !$hasAcceleratedCompositing) {
+ die "$framework at \"$path\" does not use accelerated compositing\n";
+ }
+ return $hasAcceleratedCompositing;
+}
+
+sub has3DRenderingSupport
+{
+ return 0 if isCygwin() || isQt();
+
+ my $path = shift;
+
+ my $has3DRenderingSupport = 0;
+ if (-e $path) {
+ open NM, "-|", "nm", $path or die;
+ while (<NM>) {
+ $has3DRenderingSupport = 1 if /WebCoreHas3DRendering/;
+ }
+ close NM;
+ }
+ return $has3DRenderingSupport;
+}
+
+sub checkWebCore3DRenderingSupport
+{
+ my $required = shift;
+ my $framework = "WebCore";
+ my $path = builtDylibPathForName($framework);
+ my $has3DRendering = has3DRenderingSupport($path);
+ if ($required && !$has3DRendering) {
+ die "$framework at \"$path\" does not include 3D rendering Support, please run build-webkit --3d-rendering\n";
+ }
+ return $has3DRendering;
+}
+
+sub hasWMLSupport
+{
+ return 0 if isCygwin();
+
+ my $path = shift;
+
+ if (isQt()) {
+ # FIXME: Check built library for WML support, just like Gtk does it below.
+ return 0;
+ }
+
+ my $hasWMLSupport = 0;
+ if (-e $path) {
+ open NM, "-|", "nm", $path or die;
+ while (<NM>) {
+ $hasWMLSupport = 1 if /WMLElement/;
+ }
+ close NM;
+ }
+ return $hasWMLSupport;
+}
+
+sub removeLibraryDependingOnWML
+{
+ my $frameworkName = shift;
+ my $shouldHaveWML = shift;
+
+ my $path = builtDylibPathForName($frameworkName);
+ return unless -x $path;
+
+ my $hasWML = hasWMLSupport($path);
+ system "rm -f $path" if ($shouldHaveWML xor $hasWML);
+}
+
+sub checkWebCoreWMLSupport
+{
+ my $required = shift;
+ my $framework = "WebCore";
+ my $path = builtDylibPathForName($framework);
+ my $hasWML = hasWMLSupport($path);
+ if ($required && !$hasWML) {
+ die "$framework at \"$path\" does not include WML Support, please run build-webkit --wml\n";
+ }
+ return $hasWML;
+}
+
+sub isQt()
+{
+ determineIsQt();
+ return $isQt;
+}
+
+sub checkForArgumentAndRemoveFromARGV
+{
+ my $argToCheck = shift;
+ foreach my $opt (@ARGV) {
+ if ($opt =~ /^$argToCheck$/i ) {
+ @ARGV = grep(!/^$argToCheck$/i, @ARGV);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub determineIsQt()
+{
+ return if defined($isQt);
+
+ # Allow override in case QTDIR is not set.
+ if (checkForArgumentAndRemoveFromARGV("--qt")) {
+ $isQt = 1;
+ return;
+ }
+
+ # The presence of QTDIR only means Qt if --gtk is not on the command-line
+ if (isGtk()) {
+ $isQt = 0;
+ return;
+ }
+
+ $isQt = defined($ENV{'QTDIR'});
+}
+
+sub isGtk()
+{
+ determineIsGtk();
+ return $isGtk;
+}
+
+sub determineIsGtk()
+{
+ return if defined($isGtk);
+ $isGtk = checkForArgumentAndRemoveFromARGV("--gtk");
+}
+
+sub isWx()
+{
+ determineIsWx();
+ return $isWx;
+}
+
+sub determineIsWx()
+{
+ return if defined($isWx);
+ $isWx = checkForArgumentAndRemoveFromARGV("--wx");
+}
+
+sub getWxArgs()
+{
+ if (!@wxArgs) {
+ @wxArgs = ("");
+ my $rawWxArgs = "";
+ foreach my $opt (@ARGV) {
+ if ($opt =~ /^--wx-args/i ) {
+ @ARGV = grep(!/^--wx-args/i, @ARGV);
+ $rawWxArgs = $opt;
+ $rawWxArgs =~ s/--wx-args=//i;
+ }
+ }
+ @wxArgs = split(/,/, $rawWxArgs);
+ }
+ return @wxArgs;
+}
+
+# Determine if this is debian, ubuntu, linspire, or something similar.
+sub isDebianBased()
+{
+ return -e "/etc/debian_version";
+}
+
+sub isChromium()
+{
+ determineIsChromium();
+ return $isChromium;
+}
+
+sub determineIsChromium()
+{
+ return if defined($isChromium);
+ $isChromium = checkForArgumentAndRemoveFromARGV("--chromium");
+}
+
+sub isCygwin()
+{
+ return ($^O eq "cygwin") || 0;
+}
+
+sub isDarwin()
+{
+ return ($^O eq "darwin") || 0;
+}
+
+sub isAppleWebKit()
+{
+ return !(isQt() or isGtk() or isWx() or isChromium());
+}
+
+sub isAppleMacWebKit()
+{
+ return isAppleWebKit() && isDarwin();
+}
+
+sub isAppleWinWebKit()
+{
+ return isAppleWebKit() && isCygwin();
+}
+
+sub isPerianInstalled()
+{
+ if (!isAppleWebKit()) {
+ return 0;
+ }
+
+ if (-d "/Library/QuickTime/Perian.component") {
+ return 1;
+ }
+
+ if (-d "$ENV{HOME}/Library/QuickTime/Perian.component") {
+ return 1;
+ }
+
+ return 0;
+}
+
+sub determineOSXVersion()
+{
+ return if $osXVersion;
+
+ if (!isDarwin()) {
+ $osXVersion = -1;
+ return;
+ }
+
+ my $version = `sw_vers -productVersion`;
+ my @splitVersion = split(/\./, $version);
+ @splitVersion >= 2 or die "Invalid version $version";
+ $osXVersion = {
+ "major" => $splitVersion[0],
+ "minor" => $splitVersion[1],
+ "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0),
+ };
+}
+
+sub osXVersion()
+{
+ determineOSXVersion();
+ return $osXVersion;
+}
+
+sub isTiger()
+{
+ return isDarwin() && osXVersion()->{"minor"} == 4;
+}
+
+sub isLeopard()
+{
+ return isDarwin() && osXVersion()->{"minor"} == 5;
+}
+
+sub isSnowLeopard()
+{
+ return isDarwin() && osXVersion()->{"minor"} == 6;
+}
+
+sub relativeScriptsDir()
+{
+ my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel(dirname($0), getcwd()), "");
+ if ($scriptDir eq "") {
+ $scriptDir = ".";
+ }
+ return $scriptDir;
+}
+
+sub launcherPath()
+{
+ my $relativeScriptsPath = relativeScriptsDir();
+ if (isGtk() || isQt()) {
+ return "$relativeScriptsPath/run-launcher";
+ } elsif (isAppleWebKit()) {
+ return "$relativeScriptsPath/run-safari";
+ }
+}
+
+sub launcherName()
+{
+ if (isGtk()) {
+ return "GtkLauncher";
+ } elsif (isQt()) {
+ return "QtLauncher";
+ } elsif (isAppleWebKit()) {
+ return "Safari";
+ }
+}
+
+sub checkRequiredSystemConfig
+{
+ if (isDarwin()) {
+ chomp(my $productVersion = `sw_vers -productVersion`);
+ if ($productVersion lt "10.4") {
+ print "*************************************************************\n";
+ print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
+ print "You have " . $productVersion . ", thus the build will most likely fail.\n";
+ print "*************************************************************\n";
+ }
+ my $xcodeVersion = `xcodebuild -version`;
+ if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) {
+ print "*************************************************************\n";
+ print "Xcode Version 2.3 or later is required to build WebKit.\n";
+ print "You have an earlier version of Xcode, thus the build will\n";
+ print "most likely fail. The latest Xcode is available from the web:\n";
+ print "http://developer.apple.com/tools/xcode\n";
+ print "*************************************************************\n";
+ }
+ } elsif (isGtk() or isQt() or isWx()) {
+ my @cmds = qw(flex bison gperf);
+ my @missing = ();
+ foreach my $cmd (@cmds) {
+ if (not `$cmd --version`) {
+ push @missing, $cmd;
+ }
+ }
+ if (@missing) {
+ my $list = join ", ", @missing;
+ die "ERROR: $list missing but required to build WebKit.\n";
+ }
+ }
+ # Win32 and other platforms may want to check for minimum config
+}
+
+sub setupCygwinEnv()
+{
+ return if !isCygwin();
+ return if $vcBuildPath;
+
+ my $programFilesPath = `cygpath "$ENV{'PROGRAMFILES'}"`;
+ chomp $programFilesPath;
+ $vcBuildPath = "$programFilesPath/Microsoft Visual Studio 8/Common7/IDE/devenv.com";
+ if (! -e $vcBuildPath) {
+ # VC++ not found, try VC++ Express
+ my $vsInstallDir;
+ if ($ENV{'VSINSTALLDIR'}) {
+ $vsInstallDir = $ENV{'VSINSTALLDIR'};
+ } else {
+ $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
+ $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
+ }
+ $vsInstallDir = `cygpath "$vsInstallDir"`;
+ chomp $vsInstallDir;
+ $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe";
+ if (! -e $vcBuildPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$vcBuildPath'\n";
+ print "Please execute the file 'vcvars32.bat' from\n";
+ print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
+ print "to setup the necessary environment variables.\n";
+ print "*************************************************************\n";
+ die;
+ }
+ }
+
+ my $qtSDKPath = "$programFilesPath/QuickTime SDK";
+ if (0 && ! -e $qtSDKPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$qtSDKPath'\n";
+ print "Please download the QuickTime SDK for Windows from\n";
+ print "http://developer.apple.com/quicktime/download/\n";
+ print "*************************************************************\n";
+ die;
+ }
+
+ chomp($ENV{'WEBKITLIBRARIESDIR'} = `cygpath -wa "$sourceDir/WebKitLibraries/win"`) unless $ENV{'WEBKITLIBRARIESDIR'};
+
+ $windowsTmpPath = `cygpath -w /tmp`;
+ chomp $windowsTmpPath;
+ print "Building results into: ", baseProductDir(), "\n";
+ print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
+ print "WEBKITLIBRARIESDIR is set to: ", $ENV{"WEBKITLIBRARIESDIR"}, "\n";
+}
+
+sub buildXCodeProject($$@)
+{
+ my ($project, $clean, @extraOptions) = @_;
+
+ if ($clean) {
+ push(@extraOptions, "-alltargets");
+ push(@extraOptions, "clean");
+ }
+
+ return system "xcodebuild", "-project", "$project.xcodeproj", @extraOptions;
+}
+
+sub buildVisualStudioProject
+{
+ my ($project, $clean) = @_;
+ setupCygwinEnv();
+
+ my $config = configurationForVisualStudio();
+
+ chomp(my $winProjectPath = `cygpath -w "$project"`);
+
+ my $command = "/build";
+ if ($clean) {
+ $command = "/clean";
+ }
+
+ print "$vcBuildPath $winProjectPath /build $config\n";
+ return system $vcBuildPath, $winProjectPath, $command, $config;
+}
+
+sub buildSconsProject
+{
+ my ($project, $shouldClean) = @_;
+ print "Building from $project/$project.scons\n";
+
+ my $sconsCommand = "scons";
+ if (isCygwin()) {
+ # HACK: Launch scons with Win32 python instead of CYGWIN python
+ # Scons + MSVC only works under Win32 python
+ # http://scons.tigris.org/issues/show_bug.cgi?id=2266
+ $sconsCommand = "cmd /c 'C:\\Python26\\Scripts\\scons'";
+ }
+ if ($shouldClean) {
+ return system $sconsCommand, "--clean";
+ }
+ return system $sconsCommand;
+}
+
+sub retrieveQMakespecVar
+{
+ my $mkspec = $_[0];
+ my $varname = $_[1];
+
+ my $compiler = "unknown";
+ #print "retrieveMakespecVar " . $mkspec . ", " . $varname . "\n";
+
+ local *SPEC;
+ open SPEC, "<$mkspec" or return "make";
+ while (<SPEC>) {
+ if ($_ =~ /\s*include\((.+)\)/) {
+ # open the included mkspec
+ my $oldcwd = getcwd();
+ (my $volume, my $directories, my $file) = File::Spec->splitpath($mkspec);
+ chdir "$volume$directories";
+ $compiler = retrieveQMakespecVar($1, $varname);
+ chdir $oldcwd;
+ } elsif ($_ =~ /$varname\s*=\s*([^\s]+)/) {
+ $compiler = $1;
+ last;
+ }
+ }
+ close SPEC;
+ return $compiler;
+}
+
+sub qtMakeCommand($)
+{
+ my ($qmakebin) = @_;
+ chomp(my $mkspec = `$qmakebin -query QMAKE_MKSPECS`);
+ $mkspec .= "/default";
+ my $compiler = retrieveQMakespecVar("$mkspec/qmake.conf", "QMAKE_CC");
+
+ #print "default spec: " . $mkspec . "\n";
+ #print "compiler found: " . $compiler . "\n";
+
+ if ($compiler eq "cl") {
+ return "nmake";
+ }
+
+ return "make";
+}
+
+sub autotoolsFlag($$)
+{
+ my ($flag, $feature) = @_;
+ my $prefix = $flag ? "--enable" : "--disable";
+
+ return $prefix . '-' . $feature;
+}
+
+sub buildAutotoolsProject($@)
+{
+ my ($clean, @buildArgs) = @_;
+
+ my $make = 'make';
+ my $dir = productDir();
+ my $config = passedConfiguration() || configuration();
+ my $prefix = $ENV{"WebKitInstallationPrefix"};
+
+ push @buildArgs, "--prefix=" . $prefix if defined($prefix);
+
+ # check if configuration is Debug
+ if ($config =~ m/debug/i) {
+ push @buildArgs, "--enable-debug";
+ } else {
+ push @buildArgs, "--disable-debug";
+ }
+
+ # Use rm to clean the build directory since distclean may miss files
+ if ($clean && -d $dir) {
+ system "rm", "-rf", "$dir";
+ }
+
+ if (! -d $dir) {
+ system "mkdir", "-p", "$dir";
+ if (! -d $dir) {
+ die "Failed to create build directory " . $dir;
+ }
+ }
+
+ chdir $dir or die "Failed to cd into " . $dir . "\n";
+
+ my $result;
+ if ($clean) {
+ #$result = system $make, "distclean";
+ return 0;
+ }
+
+ print "Calling configure in " . $dir . "\n\n";
+ print "Installation directory: $prefix\n" if(defined($prefix));
+
+ # Make the path relative since it will appear in all -I compiler flags.
+ # Long argument lists cause bizarre slowdowns in libtool.
+ my $relSourceDir = File::Spec->abs2rel($sourceDir);
+ $relSourceDir = "." if !$relSourceDir;
+
+ $result = system "$relSourceDir/autogen.sh", @buildArgs;
+ if ($result ne 0) {
+ die "Failed to setup build environment using 'autotools'!\n";
+ }
+
+ my $makeArgs = $ENV{"WebKitMakeArguments"} || "";
+
+ $result = system "$make $makeArgs";
+ if ($result ne 0) {
+ die "\nFailed to build WebKit using '$make'!\n";
+ }
+
+ chdir ".." or die;
+ return $result;
+}
+
+sub buildQMakeProject($@)
+{
+ my ($clean, @buildParams) = @_;
+
+ my @buildArgs = ("-r");
+
+ push @buildArgs, "DEFINES+=QT_SHARED";
+
+ my $qmakebin = "qmake"; # Allow override of the qmake binary from $PATH
+ my $makeargs = "";
+ for my $i (0 .. $#buildParams) {
+ my $opt = $buildParams[$i];
+ if ($opt =~ /^--qmake=(.*)/i ) {
+ $qmakebin = $1;
+ } elsif ($opt =~ /^--qmakearg=(.*)/i ) {
+ push @buildArgs, $1;
+ } elsif ($opt =~ /^--makeargs=(.*)/i ) {
+ $makeargs = $1;
+ } else {
+ push @buildArgs, $opt;
+ }
+ }
+
+ my $make = qtMakeCommand($qmakebin);
+ my $config = configuration();
+ my $prefix = $ENV{"WebKitInstallationPrefix"};
+
+ push @buildArgs, "OUTPUT_DIR=" . baseProductDir() . "/$config";
+ push @buildArgs, sourceDir() . "/WebKit.pro";
+ if ($config =~ m/debug/i) {
+ push @buildArgs, "CONFIG-=release";
+ push @buildArgs, "CONFIG+=debug";
+ } else {
+ push @buildArgs, "CONFIG+=release";
+ push @buildArgs, "CONFIG-=debug";
+ }
+
+ my $dir = baseProductDir();
+ if (! -d $dir) {
+ system "mkdir", "-p", "$dir";
+ if (! -d $dir) {
+ die "Failed to create product directory " . $dir;
+ }
+ }
+ $dir = $dir . "/$config";
+ if (! -d $dir) {
+ system "mkdir", "-p", "$dir";
+ if (! -d $dir) {
+ die "Failed to create build directory " . $dir;
+ }
+ }
+
+ chdir $dir or die "Failed to cd into " . $dir . "\n";
+
+ print "Calling '$qmakebin @buildArgs' in " . $dir . "\n\n";
+ print "Installation directory: $prefix\n" if(defined($prefix));
+
+ my $result = system $qmakebin, @buildArgs;
+ if ($result ne 0) {
+ die "Failed to setup build environment using $qmakebin!\n";
+ }
+
+ if ($clean) {
+ $result = system "$make $makeargs distclean";
+ } else {
+ $result = system "$make $makeargs";
+ }
+
+ chdir ".." or die;
+ return $result;
+}
+
+sub buildQMakeQtProject($$@)
+{
+ my ($project, $clean, @buildArgs) = @_;
+
+ push @buildArgs, "CONFIG+=qt-port";
+
+ return buildQMakeProject($clean, @buildArgs);
+}
+
+sub buildGtkProject($$@)
+{
+ my ($project, $clean, @buildArgs) = @_;
+
+ if ($project ne "WebKit") {
+ die "The Gtk port builds JavaScriptCore, WebCore and WebKit in one shot! Only call it for 'WebKit'.\n";
+ }
+
+ return buildAutotoolsProject($clean, @buildArgs);
+}
+
+sub setPathForRunningWebKitApp
+{
+ my ($env) = @_;
+
+ return unless isAppleWinWebKit();
+
+ $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), $env->{PATH} || "");
+}
+
+sub exitStatus($)
+{
+ my ($returnvalue) = @_;
+ if ($^O eq "MSWin32") {
+ return $returnvalue >> 8;
+ }
+ return WEXITSTATUS($returnvalue);
+}
+
+sub runSafari
+{
+ my ($debugger) = @_;
+
+ if (isAppleMacWebKit()) {
+ return system "$FindBin::Bin/gdb-safari", @ARGV if $debugger;
+
+ my $productDir = productDir();
+ print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+ if (architecture()) {
+ return system "arch", "-" . architecture(), safariPath(), @ARGV;
+ } else {
+ return system safariPath(), @ARGV;
+ }
+ }
+
+ if (isAppleWinWebKit()) {
+ my $script = "run-webkit-nightly.cmd";
+ my $result = system "cp", "$FindBin::Bin/$script", productDir();
+ return $result if $result;
+
+ my $cwd = getcwd();
+ chdir productDir();
+
+ my $debuggerFlag = $debugger ? "/debugger" : "";
+ $result = system "cmd", "/c", "call $script $debuggerFlag";
+ chdir $cwd;
+ return $result;
+ }
+
+ return 1;
+}
+
+1;
diff --git a/WebKitTools/Scripts/wkstyle b/WebKitTools/Scripts/wkstyle
new file mode 100755
index 0000000..4b3447f
--- /dev/null
+++ b/WebKitTools/Scripts/wkstyle
@@ -0,0 +1,89 @@
+
+# Copyright (C) 2006 Michael Emmel<mike.emmel@gmail.com> All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+cmdcpp="astyle \
+--unpad=paren \
+--style=linux \
+--brackets=linux \
+--indent=spaces=4 \
+--indent-switches \
+--convert-tabs"
+
+cmdh="astyle \
+--unpad=paren \
+--style=linux \
+--brackets=break \
+--indent=spaces=4 \
+--convert-tabs"
+
+#astyle does not support unpadding so we use sed
+for i in $@
+do
+echo $i
+
+ext=`echo $i|awk -F . '{print $NF}'`
+
+cmd=$cmdcpp
+
+if [ $ext == "h" ] ; then
+ cmd=$cmdh
+fi
+
+$cmd $i
+
+#first print the changes we are making
+sed -n -e '
+/( .*/p
+s/( /(/gp
+/*. )/p
+s/ )/)/gp
+#supress printing this
+#/^namespace WebCore/{
+#N
+#s/\n{/ {/p
+#}
+' $i
+
+#do it for real
+sed -e '
+#unpad leading spaces
+s/( /(/g
+#unpad traling spaces
+s/ )/)/g
+#fixup the namspec decl
+/^namespace WebCore/{
+N
+s/\n{/ {/
+}
+#fixup extra tab in constructor initalizer
+/^ \+,/{s/^ //}
+/^ \+:/{s/^ //}
+' $i > $i.sed
+mv $i.sed $i
+done
+
+