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
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)