Backed out changeset d7692aed054f
authorMitchell Field <mitchell.field@live.com.au>
Wed, 09 Mar 2011 12:29:25 +1100
changeset 63501 858c9dd4c37728faad277d2fe42a112241322896
parent 63496 d7692aed054f888d3b94fc11af2a13b76511feba
child 63502 bde78741b33b8eb08c98e156f2f77e7c73481cbb
push idunknown
push userunknown
push dateunknown
milestone2.0b13pre
backs outd7692aed054f888d3b94fc11af2a13b76511feba
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset d7692aed054f
browser/locales/Makefile.in
config/Makefile.in
config/preprocessor.pl
js/src/config/Preprocessor.py
js/src/config/preprocessor.pl
toolkit/locales/l10n.mk
tools/relic/relic
xulrunner/app/Makefile.in
xulrunner/installer/mac/Makefile.in
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -112,22 +112,22 @@ include $(topsrcdir)/toolkit/locales/l10
 
 $(STAGEDIST): $(DIST)/branding
 
 $(DIST)/branding:
 	$(NSINSTALL) -D $@
 
 libs::
 	@if test -f "$(LOCALE_SRCDIR)/existing-profile-defaults.js"; then \
-	  $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
+	  $(PERL) $(topsrcdir)/config/preprocessor.pl $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
 	    $(LOCALE_SRCDIR)/existing-profile-defaults.js > $(FINAL_TARGET)/defaults/existing-profile-defaults.js; \
 	fi
 install::
 	@if test -f "$(LOCALE_SRCDIR)/existing-profile-defaults.js"; then \
-	  $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
+	  $(PERL) $(topsrcdir)/config/preprocessor.pl $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
 	    $(LOCALE_SRCDIR)/existing-profile-defaults.js > $(DESTDIR)$(mozappdir)/defaults/existing-profile-defaults.js; \
 	fi
 
 README_FILES = \
 	README.txt \
 	$(NULL)
 
 PROFILE_FILES = \
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -118,17 +118,17 @@ ifdef MOZ_BUILD_DATE
 	printf "%s" $(MOZ_BUILD_DATE) > buildid
 else
 	$(PYTHON) $(topsrcdir)/toolkit/xre/make-platformini.py --print-buildid > buildid
 endif
 
 ifdef WRAP_SYSTEM_INCLUDES
 export::
 	if test ! -d system_wrappers; then mkdir system_wrappers; fi
-	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \
+	$(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) \
 		-DBUILD_STATIC_LIBS=$(BUILD_STATIC_LIBS) \
 		-DMOZ_TREE_CAIRO=$(MOZ_TREE_CAIRO) \
 		-DMOZ_TREE_PIXMAN=$(MOZ_TREE_PIXMAN) \
 		-DMOZ_ENABLE_LIBXUL=$(MOZ_ENABLE_LIBXUL) \
 		-DMOZ_NATIVE_HUNSPELL=$(MOZ_NATIVE_HUNSPELL) \
 		-DMOZ_NATIVE_BZ2=$(MOZ_NATIVE_BZ2) \
 		-DMOZ_NATIVE_ZLIB=$(MOZ_NATIVE_ZLIB) \
 		-DMOZ_NATIVE_PNG=$(MOZ_NATIVE_PNG) \
new file mode 100644
--- /dev/null
+++ b/config/preprocessor.pl
@@ -0,0 +1,671 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*-
+#
+# Preprocessor
+# Version 1.1
+#
+# Copyright (c) 2002, 2003, 2004 by Ian Hickson
+#
+# This program 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.
+#
+# This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Thanks to bryner and bsmedberg for suggestions.
+# Thanks to jon rekai for a patch to not require File::Spec 0.8.
+
+use strict;
+
+# takes as arguments the files to process
+# defaults to stdin
+# output to stdout
+
+my $stack = new stack;
+my $marker = '#';
+
+# command line arguments
+my @includes;
+while ($_ = $ARGV[0], defined($_) && /^-./) {
+    shift;
+    last if /^--$/os;
+    if (/^-D(.*)$/os) { 
+        for ($1) {
+            if (/^([\w\.]+)=(.*)$/os) {
+                $stack->define($1, $2);
+            } elsif (/^([\w\.]+)$/os) {
+                $stack->define($1, 1);
+            } else {
+                die "$0: invalid argument to -D: $_\n";
+            }
+        }
+    } elsif (/^-F(.*)$/os) { 
+        for ($1) {
+            if (/^(\w+)$/os) {
+                $stack->filter($1, 1);
+            } else {
+                die "$0: invalid argument to -F: $_\n";
+            }
+        }
+    } elsif (/^-I(.*)$/os) { 
+        push(@includes, $1);
+    } elsif (/^-E$/os) { 
+        foreach (keys %ENV) {
+            # define all variables that have valid names
+            $stack->define($_, $ENV{$_}) unless m/\W/;
+        }
+    } elsif (/^-d$/os) { 
+        $stack->{'dependencies'} = 1;
+    } elsif (/^--line-endings=crlf$/os) { 
+        $stack->{'lineEndings'} = "\x0D\x0A";
+    } elsif (/^--line-endings=cr$/os) { 
+        $stack->{'lineEndings'} = "\x0D";
+    } elsif (/^--line-endings=lf$/os) { 
+        $stack->{'lineEndings'} = "\x0A";
+    } elsif (/^--line-endings=(.+)$/os) { 
+        die "$0: unrecognised line ending: $1\n";
+    } elsif (/^--marker=(.)$/os) {
+        $marker = $1;
+    } else {
+        die "$0: invalid argument: $_\n";
+    }
+}
+unshift(@ARGV, '-') unless @ARGV;
+unshift(@ARGV, @includes);
+
+# do the work
+foreach (@ARGV) { include($stack, $_); }
+exit(0);
+
+########################################################################
+
+package main;
+use File::Spec;
+use File::Spec::Unix; # on all platforms, because the #include syntax is unix-based
+
+# Note: Ideally we would use File::Spec 0.8. When this becomes
+# possible, add "0.8" to the first "use" line above, then replace
+# occurrences of "::_0_8::" with "->" below. And remove the code for
+# File::Spec 0.8 much lower down the file.
+
+sub include {
+    my($stack, $filename) = @_;
+    my $directory = $stack->{'variables'}->{'DIRECTORY'};
+    if ($filename ne '-') {
+        $filename = File::Spec::_0_8::rel2abs($filename, $directory);
+        # splitpath expects forward-slash paths on windows, so we have to
+        # change the slashes if using Activestate Perl.
+        $filename =~ s?\\?/?g if "$^O" eq "MSWin32";
+        my($volume, $path) = File::Spec::_0_8::splitpath($filename);
+        $directory = File::Spec::_0_8::catpath($volume, $path, '');
+    }
+    local $stack->{'variables'}->{'DIRECTORY'} = $directory;
+    local $stack->{'variables'}->{'FILE'} = $filename;
+    local $stack->{'variables'}->{'LINE'} = 0;
+    local *FILE;
+    open(FILE, $filename) or die "Couldn't open $filename: $!\n";
+    my $lineout = 0;
+    while (<FILE>) {
+        # on cygwin, line endings are screwed up, so normalise them.
+        s/[\x0D\x0A]+$/\n/os if ($^O eq 'msys' || $^O eq 'cygwin' || "$^O" eq "MSWin32");
+        $stack->newline;
+        if (/^\Q$marker\E([a-z]+)\n?$/os) { # argumentless processing instruction
+            process($stack, $1);
+        } elsif (/^\Q$marker\E([a-z]+)\s(.*?)\n?$/os) { # processing instruction with arguments
+            process($stack, $1, $2);
+        } elsif (/^\Q$marker\E/os) { # comment
+            # ignore it
+        } elsif ($stack->enabled) {
+            next if $stack->{'dependencies'};
+
+            # set the current line number in JavaScript if necessary
+            my $linein = $stack->{'variables'}->{'LINE'};
+            if (++$lineout != $linein) {
+                if ($filename =~ /\.js(|\.in)$/o) {
+                    $stack->print("//\@line $linein \"$filename\"\n")
+                }
+                $lineout = $linein;
+            }
+
+            # print it, including any newlines
+            $stack->print(filtered($stack, $_));
+        }
+    }
+    close(FILE);
+}
+
+sub process {
+    my($stack, $instruction, @arguments) = @_;
+    my $method = 'preprocessor'->can($instruction);
+    if (not defined($method)) {
+        fatal($stack, 'unknown instruction', $instruction);
+    }
+    eval { &$method($stack, @arguments) };
+    if ($@) {
+        fatal($stack, "error evaluating $instruction:", $@);
+    }
+}
+
+sub filtered {
+    my($stack, $text) = @_;
+    foreach my $filter (sort keys %{$stack->{'filters'}}) {
+        next unless $stack->{'filters'}->{$filter};
+        my $method = 'filter'->can($filter);
+        if (not defined($method)) {
+            fatal($stack, 'unknown filter', $filter);
+        }
+        $text = eval { &$method($stack, $text) };
+        if ($@) {
+            fatal($stack, "error using $filter:", $@);
+        }                
+    }
+    return $text;
+}
+
+sub fatal {
+    my $stack = shift;
+    my $filename = $stack->{'variables'}->{'FILE'};
+    local $" = ' ';
+    print STDERR "$0:$filename:$.: @_\n";
+    exit(1);
+}
+
+
+########################################################################
+
+package stack;
+
+# condition evaluated just prior to this context was false
+use constant COND_FALSE => 0;
+
+# condition evaluated just prior to this context was true
+use constant COND_TRUE => 1;
+
+# some prior condition at this level already evaluated to true (or a
+# parent condition evaluated to false or must be ignored), so we're
+# ignoring all remaining conditions at current level (and nested
+# conditions, too)
+use constant COND_COMPLETED => 2;
+
+sub new {
+    return bless {
+        'variables' => {
+            # %ENV,
+            'LINE' => 0, # the line number in the source file
+            'DIRECTORY' => '', # current directory
+            'FILE' => '', # source filename
+            '1' => 1, # for convenience (the constant '1' is thus true)
+        },
+        'filters' => {
+            # filters
+        },
+        'values' => [], # the value of the last condition evaluated at the nth level
+        'lastConditionState' => [], # whether the condition in the nth-level context was true, false, or not applicable
+        'conditionState' => COND_TRUE,
+        'dependencies' => 0, # whether we are showing dependencies
+        'lineEndings' => "\n", # default to platform conventions
+    };
+}
+
+sub newline {
+    my $self = shift;
+    $self->{'variables'}->{'LINE'}++;
+}
+
+sub define {
+    my $self = shift;
+    my($variable, $value) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    $self->{'variables'}->{$variable} = $value;
+}
+
+sub defined {
+    my $self = shift;
+    my($variable) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    return defined($self->{'variables'}->{$variable});
+}
+
+sub undefine {
+    my $self = shift;
+    my($variable) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    delete($self->{'variables'}->{$variable});
+}
+
+sub get {
+    my $self = shift;
+    my($variable, $required) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    my $value = $self->{'variables'}->{$variable};
+    if (defined($value)) {
+        return $value;
+    } else {
+        die "variable '$variable' is not defined\n" if $required;
+        return '';
+    }
+}
+
+sub replace {
+    my $self = shift;
+    my ($value) = @_;
+
+    ${$self->{'values'}}[-1] = $value;
+    $self->{'conditionState'} = $self->{'conditionState'} != COND_FALSE
+                              ? COND_COMPLETED
+                              : $value ? COND_TRUE : COND_FALSE;
+}
+
+sub push {
+    my $self = shift;
+    my($value) = @_;
+
+    push(@{$self->{'values'}}, $value);
+    my $lastCondition = $self->{'conditionState'};
+    push(@{$self->{'lastConditionState'}}, $lastCondition);
+    $self->{'conditionState'} = $lastCondition != COND_TRUE
+                              ? COND_COMPLETED
+                              : $value ? COND_TRUE : COND_FALSE;
+}
+
+sub pop {
+    my $self = shift;
+    $self->{'conditionState'} = pop(@{$self->{'lastConditionState'}});
+    return pop(@{$self->{'values'}});
+}
+
+sub enabled {
+    my $self = shift;
+    return $self->{'conditionState'} == COND_TRUE;
+}
+
+sub disabled {
+    my $self = shift;
+    return $self->{'conditionState'} != COND_TRUE;
+}
+
+sub filter {
+    my $self = shift;
+    my($filter, $value) = @_;
+    die "not a valid filter name: '$filter'\n" if $filter =~ m/\W/;
+    $self->{'filters'}->{$filter} = $value;
+}
+
+sub expand {
+    my $self = shift;
+    my($line) = @_;
+    $line =~ s/__(\w+)__/$self->get($1)/gose;
+    return $line;
+}
+
+sub print {
+    my $self = shift;
+    return if $self->{'dependencies'};
+    foreach my $line (@_) {
+        if (chomp $line) {
+            CORE::print("$line$self->{'lineEndings'}");
+        } else {
+            CORE::print($line);
+        }
+    }
+}
+
+sub visit {
+    my $self = shift;
+    my($filename) = @_;
+    my $directory = $stack->{'variables'}->{'DIRECTORY'};
+    $filename = File::Spec::_0_8::abs2rel(File::Spec::_0_8::rel2abs($filename, $directory));
+    CORE::print("$filename\n");
+}
+
+########################################################################
+
+package preprocessor;
+
+sub define {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $argument = shift;
+    for ($argument) {
+        /^(\w+)\s(.*)$/os && do {
+            return $stack->define($1, $2);
+        };
+        /^(\w+)$/os && do {
+            return $stack->define($1, 1);
+        };
+        die "invalid argument: '$_'\n";
+    }
+}
+
+sub undef {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    $stack->undefine(@_);
+}
+
+sub ifdef {
+    my $stack = shift;
+    my $variable = shift;
+    my $replace = defined(shift);
+    die "argument expected\n" unless defined($variable);
+    if ($replace) {
+        $stack->replace($stack->defined($variable));
+    } else {
+        $stack->push($stack->defined($variable));
+    }
+}
+
+sub ifndef {
+    my $stack = shift;
+    my $variable = shift;
+    my $replace = defined(shift);
+    die "argument expected\n" unless defined($variable);
+    if ($replace) {
+        $stack->replace(not $stack->defined($variable));
+    } else {
+        $stack->push(not $stack->defined($variable));
+    }
+}
+
+sub if {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    my $argument = shift;
+    my $replace = defined(shift);
+    for ($argument) {
+        /^(\w+)==(.*)$/os && do {
+            # equality
+            if ($replace) {
+                return $stack->replace($stack->get($1) eq $2);
+            } else {
+                return $stack->push($stack->get($1) eq $2);
+            }
+        };
+        /^(\w+)!=(.*)$/os && do {
+            # inequality
+            if ($replace) {
+                return $stack->replace($stack->get($1) ne $2);
+            } else {
+                return $stack->push($stack->get($1) ne $2);
+            }
+        };
+        /^(\w+)$/os && do {
+            # true value
+            if ($replace) {
+                return $stack->replace($stack->get($1));
+            } else {
+                return $stack->push($stack->get($1));
+            }
+        };
+        /^!(\w+)$/os && do {
+            # false value
+            if ($replace) {
+                return $stack->replace(not $stack->get($1));
+            } else {
+                return $stack->push(not $stack->get($1));
+            }
+        };
+        die "invalid argument: '$_'\n";
+    }
+}
+
+sub else {
+    my $stack = shift;
+    die "argument unexpected\n" if @_;
+    $stack->replace(1);
+}
+
+sub elif {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    &if($stack, @_, 1);
+}
+
+sub elifdef {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    &ifdef($stack, @_, 1);
+}
+
+sub elifndef {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    &ifndef($stack, @_, 1);
+}
+
+sub endif {
+    my $stack = shift;
+    die "argument unexpected\n" if @_;
+    $stack->pop;
+}
+
+sub error {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $line = $stack->expand(@_);
+    die "$line\n";
+}
+
+sub expand {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $line = $stack->expand(@_);
+    $stack->print("$line\n");
+}
+
+sub literal {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $line = shift;
+    $stack->print("$line\n");
+}
+
+sub include {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath(@_));
+    if ($stack->{'dependencies'}) {
+        $stack->visit($filename);
+    } else {
+        main::include($stack, $filename);
+    }
+}
+
+sub includesubst {
+    my ($stack, $filename) = @_;
+    return if $stack->disabled;
+    die "argument expected\n" unless $filename;
+    $filename =~ s/@(\w+)@/$stack->get($1, 1)/gose;
+    $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath($filename));
+    if ($stack->{'dependencies'}) {
+        $stack->visit($filename);
+    } else {
+        main::include($stack, $filename);
+    }
+}
+
+sub filter {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    foreach (split(/\s/os, shift)) {
+        $stack->filter($_, 1);
+    }
+}
+
+sub unfilter {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    foreach (split(/\s/os, shift)) {
+        $stack->filter($_, 0);
+    }
+}
+
+
+########################################################################
+
+package filter;
+
+sub emptyLines {
+    my($stack, $text) = @_;
+    $text = "" if $text eq "\n";
+    return $text;
+}
+
+sub spaces {
+    my($stack, $text) = @_;
+    $text =~ s/ +/ /gos; # middle spaces
+    $text =~ s/^ //gos; # start spaces
+    $text =~ s/ (\n?)$/$1/gos; # end spaces
+    return $text;
+}
+
+sub slashslash {
+    my($stack, $text) = @_;
+    $text =~ s|//.*?(\n?)$|$1|gos;
+    return $text;
+}
+
+sub substitution {
+    my($stack, $text) = @_;
+    $text =~ s/@(\w+)@/$stack->get($1, 1)/gose;
+    return $text;
+}
+
+sub attemptSubstitution {
+    my($stack, $text) = @_;
+    $text =~ s/@(\w+)@/$stack->get($1, 0)/gose;
+    return $text;
+}
+
+########################################################################
+
+########################################################################
+# This code is from File::Spec::Unix 0.8.
+# It is not considered a part of the preprocessor.pl source file
+# This code is licensed under the same license as File::Spec itself.
+
+package File::Spec::_0_8;
+
+use Cwd;
+
+sub rel2abs {
+    my ($path, $base) = @_;
+    if ( ! File::Spec->file_name_is_absolute( $path ) ) {
+        if ( !defined( $base ) || $base eq '' ) {
+            $base = cwd() ;
+        } elsif ( ! File::Spec->file_name_is_absolute( $base ) ) {
+            $base = rel2abs( $base );
+        } else {
+            $base = File::Spec->canonpath( $base );
+        }
+        $path = File::Spec->catdir( $base, $path );
+    }
+    return File::Spec->canonpath( $path );
+}
+
+sub splitdir {
+    return split m|/|, $_[1], -1;  # Preserve trailing fields
+}
+
+sub splitpath {
+    my ($path, $nofile) = @_;
+
+    my ($volume,$directory,$file) = ('','','');
+
+    if ( $nofile ) {
+        $directory = $path;
+    }
+    else {
+        $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs;
+        $directory = $1;
+        $file      = $2;
+    }
+
+    return ($volume,$directory,$file);
+}
+
+sub catpath {
+    my ($volume,$directory,$file) = @_;
+
+    if ( $directory ne ''                && 
+         $file ne ''                     && 
+         substr( $directory, -1 ) ne '/' && 
+         substr( $file, 0, 1 ) ne '/' 
+    ) {
+        $directory .= "/$file" ;
+    }
+    else {
+        $directory .= $file ;
+    }
+
+    return $directory ;
+}
+
+sub abs2rel {
+    my($path,$base) = @_;
+
+    # Clean up $path
+    if ( ! File::Spec->file_name_is_absolute( $path ) ) {
+        $path = rel2abs( $path ) ;
+    }
+    else {
+        $path = File::Spec->canonpath( $path ) ;
+    }
+
+    # Figure out the effective $base and clean it up.
+    if ( !defined( $base ) || $base eq '' ) {
+        $base = cwd();
+    }
+    elsif ( ! File::Spec->file_name_is_absolute( $base ) ) {
+        $base = rel2abs( $base ) ;
+    }
+    else {
+        $base = File::Spec->canonpath( $base ) ;
+    }
+
+    # Now, remove all leading components that are the same
+    my @pathchunks = File::Spec::_0_8::splitdir( $path);
+    my @basechunks = File::Spec::_0_8::splitdir( $base);
+
+    while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
+        shift @pathchunks ;
+        shift @basechunks ;
+    }
+
+    $path = CORE::join( '/', @pathchunks );
+    $base = CORE::join( '/', @basechunks );
+
+    # $base now contains the directories the resulting relative path 
+    # must ascend out of before it can descend to $path_directory.  So, 
+    # replace all names with $parentDir
+    $base =~ s|[^/]+|..|g ;
+
+    # Glue the two together, using a separator if necessary, and preventing an
+    # empty result.
+    if ( $path ne '' && $base ne '' ) {
+        $path = "$base/$path" ;
+    } else {
+        $path = "$base$path" ;
+    }
+
+    return File::Spec->canonpath( $path ) ;
+}
+
+# End code from File::Spec::Unix 0.8.
+########################################################################
deleted file mode 100644
--- a/js/src/config/Preprocessor.py
+++ /dev/null
@@ -1,477 +0,0 @@
-"""
-This is a very primitive line based preprocessor, for times when using
-a C preprocessor isn't an option.
-"""
-
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is Mozilla build system.
-#
-# The Initial Developer of the Original Code is
-# Mozilla Foundation.
-# Portions created by the Initial Developer are Copyright (C) 2007
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#  Axel Hecht <axel@pike.org>
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-import sys
-import os
-import os.path
-import re
-from optparse import OptionParser
-
-# hack around win32 mangling our line endings
-# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443
-if sys.platform == "win32":
-  import msvcrt
-  msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
-  os.linesep = '\n'
-
-import Expression
-
-__all__ = ['Preprocessor', 'preprocess']
-
-
-class Preprocessor:
-  """
-  Class for preprocessing text files.
-  """
-  class Error(RuntimeError):
-    def __init__(self, cpp, MSG, context):
-      self.file = cpp.context['FILE']
-      self.line = cpp.context['LINE']
-      self.key = MSG
-      RuntimeError.__init__(self, (self.file, self.line, self.key, context))
-  def __init__(self):
-    self.context = Expression.Context()
-    for k,v in {'FILE': '',
-                'LINE': 0,
-                'DIRECTORY': os.path.abspath('.')}.iteritems():
-      self.context[k] = v
-    self.disableLevel = 0
-    # ifStates can be
-    #  0: hadTrue
-    #  1: wantsTrue
-    #  2: #else found
-    self.ifStates = []
-    self.checkLineNumbers = False
-    self.writtenLines = 0
-    self.filters = []
-    self.cmds = {}
-    for cmd, level in {'define': 0,
-                       'undef': 0,
-                       'if': sys.maxint,
-                       'ifdef': sys.maxint,
-                       'ifndef': sys.maxint,
-                       'else': 1,
-                       'elif': 1,
-                       'elifdef': 1,
-                       'elifndef': 1,
-                       'endif': sys.maxint,
-                       'expand': 0,
-                       'literal': 0,
-                       'filter': 0,
-                       'unfilter': 0,
-                       'include': 0,
-                       'includesubst': 0,
-                       'error': 0}.iteritems():
-      self.cmds[cmd] = (level, getattr(self, 'do_' + cmd))
-    self.out = sys.stdout
-    self.setMarker('#')
-    self.LE = '\n'
-    self.varsubst = re.compile('@(?P<VAR>\w+)@', re.U)
-  
-  def setLineEndings(self, aLE):
-    """
-    Set the line endings to be used for output.
-    """
-    self.LE = {'cr': '\x0D', 'lf': '\x0A', 'crlf': '\x0D\x0A'}[aLE]
-  
-  def setMarker(self, aMarker):
-    """
-    Set the marker to be used for processing directives.
-    Used for handling CSS files, with pp.setMarker('%'), for example.
-    """
-    self.marker = aMarker
-    self.instruction = re.compile('%s(?P<cmd>[a-z]+)(?:\s(?P<args>.*))?$'%aMarker, re.U)
-    self.comment = re.compile(aMarker, re.U)
-  
-  def clone(self):
-    """
-    Create a clone of the current processor, including line ending
-    settings, marker, variable definitions, output stream.
-    """
-    rv = Preprocessor()
-    rv.context.update(self.context)
-    rv.setMarker(self.marker)
-    rv.LE = self.LE
-    rv.out = self.out
-    return rv
-  
-  def write(self, aLine):
-    """
-    Internal method for handling output.
-    """
-    if self.checkLineNumbers:
-      self.writtenLines += 1
-      ln = self.context['LINE']
-      if self.writtenLines != ln:
-        self.out.write('//@line %(line)d "%(file)s"%(le)s'%{'line': ln,
-                                                            'file': self.context['FILE'],
-                                                            'le': self.LE})
-        self.writtenLines = ln
-    for f in self.filters:
-      aLine = f[1](aLine)
-    # ensure our line ending. Only need to handle \n, as we're reading
-    # with universal line ending support, at least for files.
-    aLine = re.sub('\n', self.LE, aLine)
-    self.out.write(aLine)
-  
-  def handleCommandLine(self, args, defaultToStdin = False):
-    """
-    Parse a commandline into this parser.
-    Uses OptionParser internally, no args mean sys.argv[1:].
-    """
-    p = self.getCommandLineParser()
-    (options, args) = p.parse_args(args=args)
-    includes = options.I
-    if defaultToStdin and len(args) == 0:
-      args = [sys.stdin]
-    includes.extend(args)
-    for f in includes:
-      self.do_include(f)
-    pass
-
-  def getCommandLineParser(self, unescapeDefines = False):
-    escapedValue = re.compile('".*"$')
-    numberValue = re.compile('\d+$')
-    def handleE(option, opt, value, parser):
-      for k,v in os.environ.iteritems():
-        self.context[k] = v
-    def handleD(option, opt, value, parser):
-      vals = value.split('=', 1)
-      if len(vals) == 1:
-        vals.append(1)
-      elif unescapeDefines and escapedValue.match(vals[1]):
-        # strip escaped string values
-        vals[1] = vals[1][1:-1]
-      elif numberValue.match(vals[1]):
-        vals[1] = int(vals[1])
-      self.context[vals[0]] = vals[1]
-    def handleU(option, opt, value, parser):
-      del self.context[value]
-    def handleF(option, opt, value, parser):
-      self.do_filter(value)
-    def handleLE(option, opt, value, parser):
-      self.setLineEndings(value)
-    def handleMarker(option, opt, value, parser):
-      self.setMarker(value)
-    p = OptionParser()
-    p.add_option('-I', action='append', type="string", default = [],
-                 metavar="FILENAME", help='Include file')
-    p.add_option('-E', action='callback', callback=handleE,
-                 help='Import the environment into the defined variables')
-    p.add_option('-D', action='callback', callback=handleD, type="string",
-                 metavar="VAR[=VAL]", help='Define a variable')
-    p.add_option('-U', action='callback', callback=handleU, type="string",
-                 metavar="VAR", help='Undefine a variable')
-    p.add_option('-F', action='callback', callback=handleF, type="string",
-                 metavar="FILTER", help='Enable the specified filter')
-    p.add_option('--line-endings', action='callback', callback=handleLE,
-                 type="string", metavar="[cr|lr|crlf]",
-                 help='Use the specified line endings [Default: OS dependent]')
-    p.add_option('--marker', action='callback', callback=handleMarker,
-                 type="string",
-                 help='Use the specified marker instead of #')
-    return p
-
-  def handleLine(self, aLine):
-    """
-    Handle a single line of input (internal).
-    """
-    m = self.instruction.match(aLine)
-    if m:
-      args = None
-      cmd = m.group('cmd')
-      try:
-        args = m.group('args')
-      except IndexError:
-        pass
-      if cmd not in self.cmds:
-        raise Preprocessor.Error(self, 'INVALID_CMD', aLine)
-      level, cmd = self.cmds[cmd]
-      if (level >= self.disableLevel):
-        cmd(args)
-    elif self.disableLevel == 0 and not self.comment.match(aLine):
-      self.write(aLine)
-    pass
-
-  # Instruction handlers
-  # These are named do_'instruction name' and take one argument
-  
-  # Variables
-  def do_define(self, args):
-    m = re.match('(?P<name>\w+)(?:\s(?P<value>.*))?', args, re.U)
-    if not m:
-      raise Preprocessor.Error(self, 'SYNTAX_DEF', args)
-    val = 1
-    if m.group('value'):
-      val = m.group('value')
-      try:
-        val = int(val)
-      except:
-        pass
-    self.context[m.group('name')] = val
-  def do_undef(self, args):
-    m = re.match('(?P<name>\w+)$', args, re.U)
-    if not m:
-      raise Preprocessor.Error(self, 'SYNTAX_DEF', args)
-    if args in self.context:
-      del self.context[args]
-  # Logic
-  def ensure_not_else(self):
-    if len(self.ifStates) == 0 or self.ifStates[-1] == 2:
-      sys.stderr.write('WARNING: bad nesting of #else\n')
-  def do_if(self, args, replace=False):
-    if self.disableLevel and not replace:
-      self.disableLevel += 1
-      return
-    val = None
-    try:
-      e = Expression.Expression(args)
-      val = e.evaluate(self.context)
-    except Exception:
-      # XXX do real error reporting
-      raise Preprocessor.Error(self, 'SYNTAX_ERR', args)
-    if type(val) == str:
-      # we're looking for a number value, strings are false
-      val = False
-    if not val:
-      self.disableLevel = 1
-    if replace:
-      if val:
-        self.disableLevel = 0
-      self.ifStates[-1] = self.disableLevel
-    else:
-      self.ifStates.append(self.disableLevel)
-    pass
-  def do_ifdef(self, args, replace=False):
-    if self.disableLevel and not replace:
-      self.disableLevel += 1
-      return
-    if re.match('\W', args, re.U):
-      raise Preprocessor.Error(self, 'INVALID_VAR', args)
-    if args not in self.context:
-      self.disableLevel = 1
-    if replace:
-      if args in self.context:
-        self.disableLevel = 0
-      self.ifStates[-1] = self.disableLevel
-    else:
-      self.ifStates.append(self.disableLevel)
-    pass
-  def do_ifndef(self, args, replace=False):
-    if self.disableLevel and not replace:
-      self.disableLevel += 1
-      return
-    if re.match('\W', args, re.U):
-      raise Preprocessor.Error(self, 'INVALID_VAR', args)
-    if args in self.context:
-      self.disableLevel = 1
-    if replace:
-      if args not in self.context:
-        self.disableLevel = 0
-      self.ifStates[-1] = self.disableLevel
-    else:
-      self.ifStates.append(self.disableLevel)
-    pass
-  def do_else(self, args, ifState = 2):
-    self.ensure_not_else()
-    hadTrue = self.ifStates[-1] == 0
-    self.ifStates[-1] = ifState # in-else
-    if hadTrue:
-      self.disableLevel = 1
-      return
-    self.disableLevel = 0
-  def do_elif(self, args):
-    if self.disableLevel == 1:
-      if self.ifStates[-1] == 1:
-        self.do_if(args, replace=True)
-    else:
-      self.do_else(None, self.ifStates[-1])
-  def do_elifdef(self, args):
-    if self.disableLevel == 1:
-      if self.ifStates[-1] == 1:
-        self.do_ifdef(args, replace=True)
-    else:
-      self.do_else(None, self.ifStates[-1])
-  def do_elifndef(self, args):
-    if self.disableLevel == 1:
-      if self.ifStates[-1] == 1:
-        self.do_ifndef(args, replace=True)
-    else:
-      self.do_else(None, self.ifStates[-1])
-  def do_endif(self, args):
-    if self.disableLevel > 0:
-      self.disableLevel -= 1
-    if self.disableLevel == 0:
-      self.ifStates.pop()
-  # output processing
-  def do_expand(self, args):
-    lst = re.split('__(\w+)__', args, re.U)
-    do_replace = False
-    def vsubst(v):
-      if v in self.context:
-        return str(self.context[v])
-      return ''
-    for i in range(1, len(lst), 2):
-      lst[i] = vsubst(lst[i])
-    lst.append('\n') # add back the newline
-    self.write(reduce(lambda x, y: x+y, lst, ''))
-  def do_literal(self, args):
-    self.write(args + self.LE)
-  def do_filter(self, args):
-    filters = [f for f in args.split(' ') if hasattr(self, 'filter_' + f)]
-    if len(filters) == 0:
-      return
-    current = dict(self.filters)
-    for f in filters:
-      current[f] = getattr(self, 'filter_' + f)
-    filterNames = current.keys()
-    filterNames.sort()
-    self.filters = [(fn, current[fn]) for fn in filterNames]
-    return
-  def do_unfilter(self, args):
-    filters = args.split(' ')
-    current = dict(self.filters)
-    for f in filters:
-      if f in current:
-        del current[f]
-    filterNames = current.keys()
-    filterNames.sort()
-    self.filters = [(fn, current[fn]) for fn in filterNames]
-    return
-  # Filters
-  #
-  # emptyLines
-  #   Strips blank lines from the output.
-  def filter_emptyLines(self, aLine):
-    if aLine == '\n':
-      return ''
-    return aLine
-  # slashslash
-  #   Strips everything after //
-  def filter_slashslash(self, aLine):
-    [aLine, rest] = aLine.split('//', 1)
-    if rest:
-      aLine += '\n'
-    return aLine
-  # spaces
-  #   Collapses sequences of spaces into a single space
-  def filter_spaces(self, aLine):
-    return re.sub(' +', ' ', aLine).strip(' ')
-  # substition
-  #   helper to be used by both substition and attemptSubstitution
-  def filter_substitution(self, aLine, fatal=True):
-    def repl(matchobj):
-      varname = matchobj.group('VAR')
-      if varname in self.context:
-        return str(self.context[varname])
-      if fatal:
-        raise Preprocessor.Error(self, 'UNDEFINED_VAR', varname)
-      return ''
-    return self.varsubst.sub(repl, aLine)
-  def filter_attemptSubstitution(self, aLine):
-    return self.filter_substitution(aLine, fatal=False)
-  # File ops
-  def do_include(self, args):
-    """
-    Preprocess a given file.
-    args can either be a file name, or a file-like object.
-    Files should be opened, and will be closed after processing.
-    """
-    isName = type(args) == str or type(args) == unicode
-    oldWrittenLines = self.writtenLines
-    oldCheckLineNumbers = self.checkLineNumbers
-    self.checkLineNumbers = False
-    if isName:
-      try:
-        args = str(args)
-        if not os.path.isabs(args):
-          args = os.path.join(self.context['DIRECTORY'], args)
-        args = open(args, 'rU')
-      except:
-        raise Preprocessor.Error(self, 'FILE_NOT_FOUND', str(args))
-    self.checkLineNumbers = bool(re.search('\.js(?:\.in)?$', args.name))
-    oldFile = self.context['FILE']
-    oldLine = self.context['LINE']
-    oldDir = self.context['DIRECTORY']
-    if args.isatty():
-      # we're stdin, use '-' and '' for file and dir
-      self.context['FILE'] = '-'
-      self.context['DIRECTORY'] = ''
-    else:
-      abspath = os.path.abspath(args.name)
-      self.context['FILE'] = abspath
-      self.context['DIRECTORY'] = os.path.dirname(abspath)
-    self.context['LINE'] = 0
-    self.writtenLines = 0
-    for l in args:
-      self.context['LINE'] += 1
-      self.handleLine(l)
-    args.close()
-    self.context['FILE'] = oldFile
-    self.checkLineNumbers = oldCheckLineNumbers
-    self.writtenLines = oldWrittenLines
-    self.context['LINE'] = oldLine
-    self.context['DIRECTORY'] = oldDir
-  def do_includesubst(self, args):
-    args = self.filter_substitution(args)
-    self.do_include(args)
-  def do_error(self, args):
-    raise Preprocessor.Error(self, 'Error: ', str(args))
-
-def main():
-  pp = Preprocessor()
-  pp.handleCommandLine(None, True)
-  return
-
-def preprocess(includes=[sys.stdin], defines={},
-               output = sys.stdout,
-               line_endings='\n', marker='#'):
-  pp = Preprocessor()
-  pp.context.update(defines)
-  pp.setLineEndings(line_endings)
-  pp.setMarker(marker)
-  pp.out = output
-  for f in includes:
-    pp.do_include(f)
-
-if __name__ == "__main__":
-  main()
new file mode 100644
--- /dev/null
+++ b/js/src/config/preprocessor.pl
@@ -0,0 +1,671 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*-
+#
+# Preprocessor
+# Version 1.1
+#
+# Copyright (c) 2002, 2003, 2004 by Ian Hickson
+#
+# This program 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.
+#
+# This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Thanks to bryner and bsmedberg for suggestions.
+# Thanks to jon rekai for a patch to not require File::Spec 0.8.
+
+use strict;
+
+# takes as arguments the files to process
+# defaults to stdin
+# output to stdout
+
+my $stack = new stack;
+my $marker = '#';
+
+# command line arguments
+my @includes;
+while ($_ = $ARGV[0], defined($_) && /^-./) {
+    shift;
+    last if /^--$/os;
+    if (/^-D(.*)$/os) { 
+        for ($1) {
+            if (/^([\w\.]+)=(.*)$/os) {
+                $stack->define($1, $2);
+            } elsif (/^([\w\.]+)$/os) {
+                $stack->define($1, 1);
+            } else {
+                die "$0: invalid argument to -D: $_\n";
+            }
+        }
+    } elsif (/^-F(.*)$/os) { 
+        for ($1) {
+            if (/^(\w+)$/os) {
+                $stack->filter($1, 1);
+            } else {
+                die "$0: invalid argument to -F: $_\n";
+            }
+        }
+    } elsif (/^-I(.*)$/os) { 
+        push(@includes, $1);
+    } elsif (/^-E$/os) { 
+        foreach (keys %ENV) {
+            # define all variables that have valid names
+            $stack->define($_, $ENV{$_}) unless m/\W/;
+        }
+    } elsif (/^-d$/os) { 
+        $stack->{'dependencies'} = 1;
+    } elsif (/^--line-endings=crlf$/os) { 
+        $stack->{'lineEndings'} = "\x0D\x0A";
+    } elsif (/^--line-endings=cr$/os) { 
+        $stack->{'lineEndings'} = "\x0D";
+    } elsif (/^--line-endings=lf$/os) { 
+        $stack->{'lineEndings'} = "\x0A";
+    } elsif (/^--line-endings=(.+)$/os) { 
+        die "$0: unrecognised line ending: $1\n";
+    } elsif (/^--marker=(.)$/os) {
+        $marker = $1;
+    } else {
+        die "$0: invalid argument: $_\n";
+    }
+}
+unshift(@ARGV, '-') unless @ARGV;
+unshift(@ARGV, @includes);
+
+# do the work
+foreach (@ARGV) { include($stack, $_); }
+exit(0);
+
+########################################################################
+
+package main;
+use File::Spec;
+use File::Spec::Unix; # on all platforms, because the #include syntax is unix-based
+
+# Note: Ideally we would use File::Spec 0.8. When this becomes
+# possible, add "0.8" to the first "use" line above, then replace
+# occurrences of "::_0_8::" with "->" below. And remove the code for
+# File::Spec 0.8 much lower down the file.
+
+sub include {
+    my($stack, $filename) = @_;
+    my $directory = $stack->{'variables'}->{'DIRECTORY'};
+    if ($filename ne '-') {
+        $filename = File::Spec::_0_8::rel2abs($filename, $directory);
+        # splitpath expects forward-slash paths on windows, so we have to
+        # change the slashes if using Activestate Perl.
+        $filename =~ s?\\?/?g if "$^O" eq "MSWin32";
+        my($volume, $path) = File::Spec::_0_8::splitpath($filename);
+        $directory = File::Spec::_0_8::catpath($volume, $path, '');
+    }
+    local $stack->{'variables'}->{'DIRECTORY'} = $directory;
+    local $stack->{'variables'}->{'FILE'} = $filename;
+    local $stack->{'variables'}->{'LINE'} = 0;
+    local *FILE;
+    open(FILE, $filename) or die "Couldn't open $filename: $!\n";
+    my $lineout = 0;
+    while (<FILE>) {
+        # on cygwin, line endings are screwed up, so normalise them.
+        s/[\x0D\x0A]+$/\n/os if ($^O eq 'msys' || $^O eq 'cygwin' || "$^O" eq "MSWin32");
+        $stack->newline;
+        if (/^\Q$marker\E([a-z]+)\n?$/os) { # argumentless processing instruction
+            process($stack, $1);
+        } elsif (/^\Q$marker\E([a-z]+)\s(.*?)\n?$/os) { # processing instruction with arguments
+            process($stack, $1, $2);
+        } elsif (/^\Q$marker\E/os) { # comment
+            # ignore it
+        } elsif ($stack->enabled) {
+            next if $stack->{'dependencies'};
+
+            # set the current line number in JavaScript if necessary
+            my $linein = $stack->{'variables'}->{'LINE'};
+            if (++$lineout != $linein) {
+                if ($filename =~ /\.js(|\.in)$/o) {
+                    $stack->print("//\@line $linein \"$filename\"\n")
+                }
+                $lineout = $linein;
+            }
+
+            # print it, including any newlines
+            $stack->print(filtered($stack, $_));
+        }
+    }
+    close(FILE);
+}
+
+sub process {
+    my($stack, $instruction, @arguments) = @_;
+    my $method = 'preprocessor'->can($instruction);
+    if (not defined($method)) {
+        fatal($stack, 'unknown instruction', $instruction);
+    }
+    eval { &$method($stack, @arguments) };
+    if ($@) {
+        fatal($stack, "error evaluating $instruction:", $@);
+    }
+}
+
+sub filtered {
+    my($stack, $text) = @_;
+    foreach my $filter (sort keys %{$stack->{'filters'}}) {
+        next unless $stack->{'filters'}->{$filter};
+        my $method = 'filter'->can($filter);
+        if (not defined($method)) {
+            fatal($stack, 'unknown filter', $filter);
+        }
+        $text = eval { &$method($stack, $text) };
+        if ($@) {
+            fatal($stack, "error using $filter:", $@);
+        }                
+    }
+    return $text;
+}
+
+sub fatal {
+    my $stack = shift;
+    my $filename = $stack->{'variables'}->{'FILE'};
+    local $" = ' ';
+    print STDERR "$0:$filename:$.: @_\n";
+    exit(1);
+}
+
+
+########################################################################
+
+package stack;
+
+# condition evaluated just prior to this context was false
+use constant COND_FALSE => 0;
+
+# condition evaluated just prior to this context was true
+use constant COND_TRUE => 1;
+
+# some prior condition at this level already evaluated to true (or a
+# parent condition evaluated to false or must be ignored), so we're
+# ignoring all remaining conditions at current level (and nested
+# conditions, too)
+use constant COND_COMPLETED => 2;
+
+sub new {
+    return bless {
+        'variables' => {
+            # %ENV,
+            'LINE' => 0, # the line number in the source file
+            'DIRECTORY' => '', # current directory
+            'FILE' => '', # source filename
+            '1' => 1, # for convenience (the constant '1' is thus true)
+        },
+        'filters' => {
+            # filters
+        },
+        'values' => [], # the value of the last condition evaluated at the nth level
+        'lastConditionState' => [], # whether the condition in the nth-level context was true, false, or not applicable
+        'conditionState' => COND_TRUE,
+        'dependencies' => 0, # whether we are showing dependencies
+        'lineEndings' => "\n", # default to platform conventions
+    };
+}
+
+sub newline {
+    my $self = shift;
+    $self->{'variables'}->{'LINE'}++;
+}
+
+sub define {
+    my $self = shift;
+    my($variable, $value) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    $self->{'variables'}->{$variable} = $value;
+}
+
+sub defined {
+    my $self = shift;
+    my($variable) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    return defined($self->{'variables'}->{$variable});
+}
+
+sub undefine {
+    my $self = shift;
+    my($variable) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    delete($self->{'variables'}->{$variable});
+}
+
+sub get {
+    my $self = shift;
+    my($variable, $required) = @_;
+    die "not a valid variable name: '$variable'\n" if $variable =~ m/[^\w\.]/;
+    my $value = $self->{'variables'}->{$variable};
+    if (defined($value)) {
+        return $value;
+    } else {
+        die "variable '$variable' is not defined\n" if $required;
+        return '';
+    }
+}
+
+sub replace {
+    my $self = shift;
+    my ($value) = @_;
+
+    ${$self->{'values'}}[-1] = $value;
+    $self->{'conditionState'} = $self->{'conditionState'} != COND_FALSE
+                              ? COND_COMPLETED
+                              : $value ? COND_TRUE : COND_FALSE;
+}
+
+sub push {
+    my $self = shift;
+    my($value) = @_;
+
+    push(@{$self->{'values'}}, $value);
+    my $lastCondition = $self->{'conditionState'};
+    push(@{$self->{'lastConditionState'}}, $lastCondition);
+    $self->{'conditionState'} = $lastCondition != COND_TRUE
+                              ? COND_COMPLETED
+                              : $value ? COND_TRUE : COND_FALSE;
+}
+
+sub pop {
+    my $self = shift;
+    $self->{'conditionState'} = pop(@{$self->{'lastConditionState'}});
+    return pop(@{$self->{'values'}});
+}
+
+sub enabled {
+    my $self = shift;
+    return $self->{'conditionState'} == COND_TRUE;
+}
+
+sub disabled {
+    my $self = shift;
+    return $self->{'conditionState'} != COND_TRUE;
+}
+
+sub filter {
+    my $self = shift;
+    my($filter, $value) = @_;
+    die "not a valid filter name: '$filter'\n" if $filter =~ m/\W/;
+    $self->{'filters'}->{$filter} = $value;
+}
+
+sub expand {
+    my $self = shift;
+    my($line) = @_;
+    $line =~ s/__(\w+)__/$self->get($1)/gose;
+    return $line;
+}
+
+sub print {
+    my $self = shift;
+    return if $self->{'dependencies'};
+    foreach my $line (@_) {
+        if (chomp $line) {
+            CORE::print("$line$self->{'lineEndings'}");
+        } else {
+            CORE::print($line);
+        }
+    }
+}
+
+sub visit {
+    my $self = shift;
+    my($filename) = @_;
+    my $directory = $stack->{'variables'}->{'DIRECTORY'};
+    $filename = File::Spec::_0_8::abs2rel(File::Spec::_0_8::rel2abs($filename, $directory));
+    CORE::print("$filename\n");
+}
+
+########################################################################
+
+package preprocessor;
+
+sub define {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $argument = shift;
+    for ($argument) {
+        /^(\w+)\s(.*)$/os && do {
+            return $stack->define($1, $2);
+        };
+        /^(\w+)$/os && do {
+            return $stack->define($1, 1);
+        };
+        die "invalid argument: '$_'\n";
+    }
+}
+
+sub undef {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    $stack->undefine(@_);
+}
+
+sub ifdef {
+    my $stack = shift;
+    my $variable = shift;
+    my $replace = defined(shift);
+    die "argument expected\n" unless defined($variable);
+    if ($replace) {
+        $stack->replace($stack->defined($variable));
+    } else {
+        $stack->push($stack->defined($variable));
+    }
+}
+
+sub ifndef {
+    my $stack = shift;
+    my $variable = shift;
+    my $replace = defined(shift);
+    die "argument expected\n" unless defined($variable);
+    if ($replace) {
+        $stack->replace(not $stack->defined($variable));
+    } else {
+        $stack->push(not $stack->defined($variable));
+    }
+}
+
+sub if {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    my $argument = shift;
+    my $replace = defined(shift);
+    for ($argument) {
+        /^(\w+)==(.*)$/os && do {
+            # equality
+            if ($replace) {
+                return $stack->replace($stack->get($1) eq $2);
+            } else {
+                return $stack->push($stack->get($1) eq $2);
+            }
+        };
+        /^(\w+)!=(.*)$/os && do {
+            # inequality
+            if ($replace) {
+                return $stack->replace($stack->get($1) ne $2);
+            } else {
+                return $stack->push($stack->get($1) ne $2);
+            }
+        };
+        /^(\w+)$/os && do {
+            # true value
+            if ($replace) {
+                return $stack->replace($stack->get($1));
+            } else {
+                return $stack->push($stack->get($1));
+            }
+        };
+        /^!(\w+)$/os && do {
+            # false value
+            if ($replace) {
+                return $stack->replace(not $stack->get($1));
+            } else {
+                return $stack->push(not $stack->get($1));
+            }
+        };
+        die "invalid argument: '$_'\n";
+    }
+}
+
+sub else {
+    my $stack = shift;
+    die "argument unexpected\n" if @_;
+    $stack->replace(1);
+}
+
+sub elif {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    &if($stack, @_, 1);
+}
+
+sub elifdef {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    &ifdef($stack, @_, 1);
+}
+
+sub elifndef {
+    my $stack = shift;
+    die "argument expected\n" unless @_;
+    &ifndef($stack, @_, 1);
+}
+
+sub endif {
+    my $stack = shift;
+    die "argument unexpected\n" if @_;
+    $stack->pop;
+}
+
+sub error {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $line = $stack->expand(@_);
+    die "$line\n";
+}
+
+sub expand {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $line = $stack->expand(@_);
+    $stack->print("$line\n");
+}
+
+sub literal {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $line = shift;
+    $stack->print("$line\n");
+}
+
+sub include {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    my $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath(@_));
+    if ($stack->{'dependencies'}) {
+        $stack->visit($filename);
+    } else {
+        main::include($stack, $filename);
+    }
+}
+
+sub includesubst {
+    my ($stack, $filename) = @_;
+    return if $stack->disabled;
+    die "argument expected\n" unless $filename;
+    $filename =~ s/@(\w+)@/$stack->get($1, 1)/gose;
+    $filename = File::Spec::_0_8::catpath(File::Spec::_0_8::splitpath($filename));
+    if ($stack->{'dependencies'}) {
+        $stack->visit($filename);
+    } else {
+        main::include($stack, $filename);
+    }
+}
+
+sub filter {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    foreach (split(/\s/os, shift)) {
+        $stack->filter($_, 1);
+    }
+}
+
+sub unfilter {
+    my $stack = shift;
+    return if $stack->disabled;
+    die "argument expected\n" unless @_;
+    foreach (split(/\s/os, shift)) {
+        $stack->filter($_, 0);
+    }
+}
+
+
+########################################################################
+
+package filter;
+
+sub emptyLines {
+    my($stack, $text) = @_;
+    $text = "" if $text eq "\n";
+    return $text;
+}
+
+sub spaces {
+    my($stack, $text) = @_;
+    $text =~ s/ +/ /gos; # middle spaces
+    $text =~ s/^ //gos; # start spaces
+    $text =~ s/ (\n?)$/$1/gos; # end spaces
+    return $text;
+}
+
+sub slashslash {
+    my($stack, $text) = @_;
+    $text =~ s|//.*?(\n?)$|$1|gos;
+    return $text;
+}
+
+sub substitution {
+    my($stack, $text) = @_;
+    $text =~ s/@(\w+)@/$stack->get($1, 1)/gose;
+    return $text;
+}
+
+sub attemptSubstitution {
+    my($stack, $text) = @_;
+    $text =~ s/@(\w+)@/$stack->get($1, 0)/gose;
+    return $text;
+}
+
+########################################################################
+
+########################################################################
+# This code is from File::Spec::Unix 0.8.
+# It is not considered a part of the preprocessor.pl source file
+# This code is licensed under the same license as File::Spec itself.
+
+package File::Spec::_0_8;
+
+use Cwd;
+
+sub rel2abs {
+    my ($path, $base) = @_;
+    if ( ! File::Spec->file_name_is_absolute( $path ) ) {
+        if ( !defined( $base ) || $base eq '' ) {
+            $base = cwd() ;
+        } elsif ( ! File::Spec->file_name_is_absolute( $base ) ) {
+            $base = rel2abs( $base );
+        } else {
+            $base = File::Spec->canonpath( $base );
+        }
+        $path = File::Spec->catdir( $base, $path );
+    }
+    return File::Spec->canonpath( $path );
+}
+
+sub splitdir {
+    return split m|/|, $_[1], -1;  # Preserve trailing fields
+}
+
+sub splitpath {
+    my ($path, $nofile) = @_;
+
+    my ($volume,$directory,$file) = ('','','');
+
+    if ( $nofile ) {
+        $directory = $path;
+    }
+    else {
+        $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs;
+        $directory = $1;
+        $file      = $2;
+    }
+
+    return ($volume,$directory,$file);
+}
+
+sub catpath {
+    my ($volume,$directory,$file) = @_;
+
+    if ( $directory ne ''                && 
+         $file ne ''                     && 
+         substr( $directory, -1 ) ne '/' && 
+         substr( $file, 0, 1 ) ne '/' 
+    ) {
+        $directory .= "/$file" ;
+    }
+    else {
+        $directory .= $file ;
+    }
+
+    return $directory ;
+}
+
+sub abs2rel {
+    my($path,$base) = @_;
+
+    # Clean up $path
+    if ( ! File::Spec->file_name_is_absolute( $path ) ) {
+        $path = rel2abs( $path ) ;
+    }
+    else {
+        $path = File::Spec->canonpath( $path ) ;
+    }
+
+    # Figure out the effective $base and clean it up.
+    if ( !defined( $base ) || $base eq '' ) {
+        $base = cwd();
+    }
+    elsif ( ! File::Spec->file_name_is_absolute( $base ) ) {
+        $base = rel2abs( $base ) ;
+    }
+    else {
+        $base = File::Spec->canonpath( $base ) ;
+    }
+
+    # Now, remove all leading components that are the same
+    my @pathchunks = File::Spec::_0_8::splitdir( $path);
+    my @basechunks = File::Spec::_0_8::splitdir( $base);
+
+    while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) {
+        shift @pathchunks ;
+        shift @basechunks ;
+    }
+
+    $path = CORE::join( '/', @pathchunks );
+    $base = CORE::join( '/', @basechunks );
+
+    # $base now contains the directories the resulting relative path 
+    # must ascend out of before it can descend to $path_directory.  So, 
+    # replace all names with $parentDir
+    $base =~ s|[^/]+|..|g ;
+
+    # Glue the two together, using a separator if necessary, and preventing an
+    # empty result.
+    if ( $path ne '' && $base ne '' ) {
+        $path = "$base/$path" ;
+    } else {
+        $path = "$base$path" ;
+    }
+
+    return File::Spec->canonpath( $path ) ;
+}
+
+# End code from File::Spec::Unix 0.8.
+########################################################################
--- a/toolkit/locales/l10n.mk
+++ b/toolkit/locales/l10n.mk
@@ -185,17 +185,17 @@ TK_DEFINES = $(firstword \
    $(MOZILLA_DIR)/toolkit/locales/en-US/defines.inc)
 
 langpack-%: LANGPACK_FILE=$(_ABS_DIST)/$(PKG_LANGPACK_PATH)$(PKG_LANGPACK_BASENAME).xpi
 langpack-%: AB_CD=$*
 langpack-%: XPI_NAME=locale-$*
 langpack-%: libs-%
 	@echo "Making langpack $(LANGPACK_FILE)"
 	$(NSINSTALL) -D $(DIST)/$(PKG_LANGPACK_PATH)
-	$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) -I$(TK_DEFINES) -I$(APP_DEFINES) $(srcdir)/generic/install.rdf > $(FINAL_TARGET)/install.rdf
+	$(PERL) $(MOZILLA_DIR)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) -I$(TK_DEFINES) -I$(APP_DEFINES) $(srcdir)/generic/install.rdf > $(FINAL_TARGET)/install.rdf
 	cd $(DIST)/xpi-stage/locale-$(AB_CD) && \
 	  $(ZIP) -r9D $(LANGPACK_FILE) install.rdf chrome chrome.manifest -x chrome/$(AB_CD).manifest
 
 
 # This variable is to allow the wget-en-US target to know which ftp server to download from
 ifndef EN_US_BINARY_URL 
 EN_US_BINARY_URL = $(error You must set EN_US_BINARY_URL)
 endif
--- a/tools/relic/relic
+++ b/tools/relic/relic
@@ -192,16 +192,17 @@ log = logging.getLogger("relic")
     "toolkit/content/license.html",
     
     # Ben Bucksch - files are tri-licensed with an extra clause.
     "netwerk/streamconv/converters/mozTXTToHTMLConv.cpp",
     "netwerk/streamconv/converters/mozTXTToHTMLConv.h",
     "netwerk/streamconv/public/mozITXTToHTMLConv.idl",
     
     # GPLed build tools
+    "config/preprocessor.pl",
     "intl/uconv/tools/parse-mozilla-encoding-table.pl",
     "intl/uconv/tools/gen-big5hkscs-2001-mozilla.pl",
     "js2/missing",
     
     # Files which the script doesn't handle well. All have been relicensed
     # manually.
     "xpinstall/wizard/windows/builder/readme.txt",
     "xpfe/bootstrap/icons/windows/readme.txt",
--- a/xulrunner/app/Makefile.in
+++ b/xulrunner/app/Makefile.in
@@ -229,17 +229,17 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 libs::
 	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default16.png $(DIST)/bin/chrome/icons/default
 	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default32.png $(DIST)/bin/chrome/icons/default
 	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default48.png $(DIST)/bin/chrome/icons/default
 endif
 
 # XXX applications would need to supply this file
 #export:: brand.dtd.in
-#	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $^ > brand.dtd
+#	$(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $^ > brand.dtd
 
 export::
 	$(NSINSTALL) -D $(DIST)/branding
 ifeq ($(OS_ARCH),WINNT)
 	cp $(srcdir)/xulrunner.ico   $(DIST)/branding/xulrunner.ico
 	cp $(srcdir)/xulrunner.ico   $(DIST)/branding/app.ico
 	cp $(srcdir)/document.ico  $(DIST)/branding/document.ico
 endif
--- a/xulrunner/installer/mac/Makefile.in
+++ b/xulrunner/installer/mac/Makefile.in
@@ -56,17 +56,17 @@ NO_PKG_FILES = \
 	xpt_link* \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 libs:: stage-package
 
 %.plist: %.plist.in
-	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@
+	$(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $< > $@
 
 PACKAGER_NO_LIBS=1
 _APPNAME = XUL.framework
 _BINPATH = /$(_APPNAME)/Versions/Current
 
 include $(topsrcdir)/toolkit/mozapps/installer/packager.mk
 
 _ABS_OBJDIR := $(shell pwd)