mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 569365 - Remove preprocessor.pl and replace it with Preprocessor.py. r=ted
--HG-- rename : config/Expression.py => js/src/config/Expression.py rename : config/Preprocessor.py => js/src/config/Preprocessor.py
This commit is contained in:
parent
a733c6b3cf
commit
2d708facec
@ -116,12 +116,12 @@ $(DIST)/branding:
|
||||
|
||||
libs::
|
||||
@if test -f "$(LOCALE_SRCDIR)/existing-profile-defaults.js"; then \
|
||||
$(PERL) $(topsrcdir)/config/preprocessor.pl $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(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 \
|
||||
$(PERL) $(topsrcdir)/config/preprocessor.pl $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
|
||||
$(LOCALE_SRCDIR)/existing-profile-defaults.js > $(DESTDIR)$(mozappdir)/defaults/existing-profile-defaults.js; \
|
||||
fi
|
||||
|
||||
|
@ -121,7 +121,7 @@ endif
|
||||
ifdef WRAP_SYSTEM_INCLUDES
|
||||
export::
|
||||
if test ! -d system_wrappers; then mkdir system_wrappers; fi
|
||||
$(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) \
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \
|
||||
-DBUILD_STATIC_LIBS=$(BUILD_STATIC_LIBS) \
|
||||
-DMOZ_TREE_CAIRO=$(MOZ_TREE_CAIRO) \
|
||||
-DMOZ_TREE_PIXMAN=$(MOZ_TREE_PIXMAN) \
|
||||
|
@ -1,671 +0,0 @@
|
||||
#!/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.
|
||||
########################################################################
|
@ -1,252 +0,0 @@
|
||||
Preprocessor
|
||||
============
|
||||
|
||||
This is a very primitive line based preprocessor, for times when using
|
||||
a C preprocessor isn't an option.
|
||||
|
||||
|
||||
Instructions
|
||||
------------
|
||||
|
||||
Any line starting with a hash # and a letter is considered to be a
|
||||
preprocessor instruction. Other lines starting with a hash are ignored
|
||||
as comments.
|
||||
|
||||
The following preprocessor instructions are recognised.
|
||||
|
||||
#define VARIABLE
|
||||
#define VARIABLE STRING
|
||||
#undef VARIABLE
|
||||
#ifdef VARIABLE
|
||||
#ifndef VARIABLE
|
||||
#if VARIABLE
|
||||
#if !VARIABLE
|
||||
#if VARIABLE==STRING
|
||||
#if VARIABLE!=STRING
|
||||
#else
|
||||
#elifdef VARIABLE
|
||||
#elifndef VARIABLE
|
||||
#elif VARIABLE
|
||||
#elif !VARIABLE
|
||||
#elif VARIABLE==STRING
|
||||
#elif VARIABLE!=STRING
|
||||
#endif
|
||||
#error STRING
|
||||
#include FILENAME
|
||||
#includesubst @VAR@FILENAME
|
||||
#expand STRING
|
||||
#literal STRING
|
||||
#filter FILTER1 FILTER2 ... FILTERn
|
||||
#unfilter FILTER1 FILTER2 ... FILTERn
|
||||
|
||||
Whitespace is significant -- for instance, '#define TEST foo' is not
|
||||
the same as '#define TEST foo '. The first defines TEST to be a three
|
||||
character string, the second defines it to be four characters long.
|
||||
|
||||
The conditionals (#ifdef, #ifndef, #if, #else, #elifdef, #elifndef,
|
||||
#elif, #endif) can be nested to arbitrary depth.
|
||||
|
||||
The #elifdef, #elifndef, and #elif instructions are equivalent to
|
||||
#else instructions combined with the relevant conditional. For
|
||||
example,
|
||||
|
||||
#ifdef foo
|
||||
block 1
|
||||
#elifdef bar
|
||||
block 2
|
||||
#endif
|
||||
|
||||
...could be written as:
|
||||
|
||||
#ifdef foo
|
||||
block 1
|
||||
#else
|
||||
#ifdef bar
|
||||
block 2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
An #else block is included if all previous conditions were false, and
|
||||
is equivalent to #elif 1, i.e.:
|
||||
|
||||
#ifdef foo
|
||||
foo is defined
|
||||
#else
|
||||
foo is not defined
|
||||
#endif
|
||||
|
||||
...is equivalent to:
|
||||
|
||||
#ifdef foo
|
||||
foo is defined
|
||||
#elif 1
|
||||
foo is not defined
|
||||
#endif
|
||||
|
||||
#else is not required to be the last condition in an if/el*/endif
|
||||
series. In particular, along with #else's equivalence to #elif 1
|
||||
this means that the following holds:
|
||||
|
||||
#if 0
|
||||
never included
|
||||
#else
|
||||
always included
|
||||
#else
|
||||
never included
|
||||
#elif 1
|
||||
never included
|
||||
#endif
|
||||
|
||||
The #error instruction stops execution at this point with a fatal
|
||||
error. The error message will include the given STRING.
|
||||
|
||||
The #include instruction causes the specified file FILENAME to be
|
||||
recursively processed, as if it was inserted at the current position
|
||||
in the file. This means conditionals can be started in one file and
|
||||
ended in another, although this practice is strongly discouraged.
|
||||
There is no predefined limit to the depth of #includes, and there is
|
||||
no restriction on self-inclusion, so care should be taken to avoid
|
||||
infinite loops.
|
||||
|
||||
The #includesubst instruction behaves like #include, except that any
|
||||
variables in @ATSIGNS@ are expanded, like the substitution filter.
|
||||
|
||||
The #expand instruction will print the given STRING with variable
|
||||
substitutions. See the substitution section below.
|
||||
|
||||
The #literal instruction will print the given STRING with a newline,
|
||||
with absolutely no other fixups, guaranteed. This can be used to
|
||||
output lines starting with a #, which would otherwise be stripped out
|
||||
as comments.
|
||||
|
||||
The #filter instruction enables the specified filters. You can turn
|
||||
off filters using #unfilter. See the Filters section below.
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variables consist of any alphanumeric string. They are defined using
|
||||
the -D command line argument and the #define instruction.
|
||||
|
||||
To define all environment variables, so that you can use __HOME__,
|
||||
etc, with #expand, use the -E argument. Note that arguments that use
|
||||
non-word characters (like "!") are not included. (In particular,
|
||||
cygwin is known to include all kinds of weird characters in its
|
||||
environment variables.)
|
||||
|
||||
Two special variables are predefined, FILE and LINE. They can be
|
||||
passed to #define and #undef, but FILE is automatically redefined at
|
||||
the top of each file, and LINE is increased by one at the start of
|
||||
each line.
|
||||
|
||||
The variable '1' is predefined with value 1. The variable '0' is not
|
||||
defined. This allows constructs such as
|
||||
|
||||
#if 0
|
||||
...
|
||||
#endif
|
||||
|
||||
...to be used to quickly comment out large sections. Note, however,
|
||||
that these are simply variables, and can be redefined. This is
|
||||
strongly discouraged.
|
||||
|
||||
|
||||
Substitution
|
||||
------------
|
||||
|
||||
In any line starting with the instruction #expand, variable names
|
||||
contained between double underscores, like __THIS__, are expanded to
|
||||
their string values, or the empty string if they are not defined.
|
||||
|
||||
For example to print the current filename:
|
||||
|
||||
#expand <!-- This file is automatically generated from __FILE__ -->
|
||||
|
||||
Normal lines are not affected.
|
||||
|
||||
See also the substitution filter below.
|
||||
|
||||
|
||||
Filters
|
||||
-------
|
||||
|
||||
The following filters are supported:
|
||||
|
||||
emptyLines
|
||||
Strips blank lines from the output.
|
||||
|
||||
slashslash
|
||||
Strips everything from the first two consecutive slash (/)
|
||||
characters until the end of the line.
|
||||
|
||||
spaces
|
||||
Collapses sequences of spaces into a single space.
|
||||
|
||||
substitution
|
||||
Replaces occurrences of "@foo@" by the value of the variable
|
||||
"foo". If @foo@ is not defined, the preprocessor will terminate
|
||||
with a fatal error.
|
||||
|
||||
attemptSubstitution
|
||||
Replaces occurrences of "@foo@" by the value of the variable
|
||||
"foo". If @foo@ is not defined, the empty string is used instead.
|
||||
|
||||
Filters are run in alphabetical order, on a per-line basis.
|
||||
|
||||
|
||||
Command Line Arguments
|
||||
----------------------
|
||||
|
||||
Syntax:
|
||||
preprocessor.pl [-Dvariable[=value]] [-E] [-Ffilter]
|
||||
[-Ifilename] [-d] [--marker=<c>] [--] filenames...
|
||||
|
||||
-Dvariable
|
||||
Set variable to 1 before processing the files.
|
||||
|
||||
-Dvariable=value
|
||||
Set variable to value before processing the files.
|
||||
|
||||
-E
|
||||
Define all environment variables.
|
||||
|
||||
-Ffilter
|
||||
Enables the specified filter.
|
||||
|
||||
-Ifilename
|
||||
Include filename before any other files.
|
||||
|
||||
-d
|
||||
Run through the files on the command line, listing the files they
|
||||
depend on given the specified environment variables and filters.
|
||||
Doesn't recurse into those files. The output is given as one
|
||||
dependency per line, and filenames are given relative to the
|
||||
current directory.
|
||||
|
||||
--line-endings=type
|
||||
Set the type of line endings to use. "type" can be either "cr",
|
||||
"lf", or "crlf". The default is whatever your platform uses for
|
||||
perl's "\n" character.
|
||||
|
||||
--marker=<c>
|
||||
Use the character <c> instead of '#' as the marker for preprocessor
|
||||
instructions.
|
||||
|
||||
--
|
||||
Indicates the end of non-filename arguments.
|
||||
|
||||
-
|
||||
Indicates that input should come from standard input.
|
||||
|
||||
If no filenames are provided, standard input is used instead. If many
|
||||
files are provided, they are processed sequentially, as if they were
|
||||
one big file. -I files are handled before the other files, in the
|
||||
order specified, but after handling any -D, -E, -F, and -d arguments.
|
||||
|
||||
|
||||
Contact Details
|
||||
---------------
|
||||
|
||||
Feel free to e-mail me if you have any questions:
|
||||
Ian Hickson <preprocessor@software.hixie.ch>
|
209
js/src/config/Expression.py
Normal file
209
js/src/config/Expression.py
Normal file
@ -0,0 +1,209 @@
|
||||
# ***** 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 *****
|
||||
|
||||
"""
|
||||
Parses and evaluates simple statements for Preprocessor:
|
||||
|
||||
Expression currently supports the following grammar, whitespace is ignored:
|
||||
|
||||
expression :
|
||||
unary ( ( '==' | '!=' ) unary ) ? ;
|
||||
unary :
|
||||
'!'? value ;
|
||||
value :
|
||||
[0-9]+ # integer
|
||||
| \w+ # string identifier or value;
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
class Expression:
|
||||
def __init__(self, expression_string):
|
||||
"""
|
||||
Create a new expression with this string.
|
||||
The expression will already be parsed into an Abstract Syntax Tree.
|
||||
"""
|
||||
self.content = expression_string
|
||||
self.offset = 0
|
||||
self.__ignore_whitespace()
|
||||
self.e = self.__get_equality()
|
||||
if self.content:
|
||||
raise Expression.ParseError, self
|
||||
|
||||
def __get_equality(self):
|
||||
"""
|
||||
Production: unary ( ( '==' | '!=' ) unary ) ?
|
||||
"""
|
||||
if not len(self.content):
|
||||
return None
|
||||
rv = Expression.__AST("equality")
|
||||
# unary
|
||||
rv.append(self.__get_unary())
|
||||
self.__ignore_whitespace()
|
||||
if not re.match('[=!]=', self.content):
|
||||
# no equality needed, short cut to our prime unary
|
||||
return rv[0]
|
||||
# append operator
|
||||
rv.append(Expression.__ASTLeaf('op', self.content[:2]))
|
||||
self.__strip(2)
|
||||
self.__ignore_whitespace()
|
||||
rv.append(self.__get_unary())
|
||||
self.__ignore_whitespace()
|
||||
return rv
|
||||
|
||||
def __get_unary(self):
|
||||
"""
|
||||
Production: '!'? value
|
||||
"""
|
||||
# eat whitespace right away, too
|
||||
not_ws = re.match('!\s*', self.content)
|
||||
if not not_ws:
|
||||
return self.__get_value()
|
||||
rv = Expression.__AST('not')
|
||||
self.__strip(not_ws.end())
|
||||
rv.append(self.__get_value())
|
||||
self.__ignore_whitespace()
|
||||
return rv
|
||||
|
||||
def __get_value(self):
|
||||
"""
|
||||
Production: ( [0-9]+ | \w+)
|
||||
Note that the order is important, and the expression is kind-of
|
||||
ambiguous as \w includes 0-9. One could make it unambiguous by
|
||||
removing 0-9 from the first char of a string literal.
|
||||
"""
|
||||
rv = None
|
||||
word_len = re.match('[0-9]*', self.content).end()
|
||||
if word_len:
|
||||
value = int(self.content[:word_len])
|
||||
rv = Expression.__ASTLeaf('int', value)
|
||||
else:
|
||||
word_len = re.match('\w*', self.content).end()
|
||||
if word_len:
|
||||
rv = Expression.__ASTLeaf('string', self.content[:word_len])
|
||||
else:
|
||||
raise Expression.ParseError, self
|
||||
self.__strip(word_len)
|
||||
self.__ignore_whitespace()
|
||||
return rv
|
||||
|
||||
def __ignore_whitespace(self):
|
||||
ws_len = re.match('\s*', self.content).end()
|
||||
self.__strip(ws_len)
|
||||
return
|
||||
|
||||
def __strip(self, length):
|
||||
"""
|
||||
Remove a given amount of chars from the input and update
|
||||
the offset.
|
||||
"""
|
||||
self.content = self.content[length:]
|
||||
self.offset += length
|
||||
|
||||
def evaluate(self, context):
|
||||
"""
|
||||
Evaluate the expression with the given context
|
||||
"""
|
||||
|
||||
# Helper function to evaluate __get_equality results
|
||||
def eval_equality(tok):
|
||||
left = opmap[tok[0].type](tok[0])
|
||||
right = opmap[tok[2].type](tok[2])
|
||||
rv = left == right
|
||||
if tok[1].value == '!=':
|
||||
rv = not rv
|
||||
return rv
|
||||
# Mapping from token types to evaluator functions
|
||||
# Apart from (non-)equality, all these can be simple lambda forms.
|
||||
opmap = {
|
||||
'equality': eval_equality,
|
||||
'not': lambda tok: not opmap[tok[0].type](tok[0]),
|
||||
'string': lambda tok: context[tok.value],
|
||||
'int': lambda tok: tok.value}
|
||||
|
||||
return opmap[self.e.type](self.e);
|
||||
|
||||
class __AST(list):
|
||||
"""
|
||||
Internal class implementing Abstract Syntax Tree nodes
|
||||
"""
|
||||
def __init__(self, type):
|
||||
self.type = type
|
||||
super(self.__class__, self).__init__(self)
|
||||
|
||||
class __ASTLeaf:
|
||||
"""
|
||||
Internal class implementing Abstract Syntax Tree leafs
|
||||
"""
|
||||
def __init__(self, type, value):
|
||||
self.value = value
|
||||
self.type = type
|
||||
def __str__(self):
|
||||
return self.value.__str__()
|
||||
def __repr__(self):
|
||||
return self.value.__repr__()
|
||||
|
||||
class ParseError(StandardError):
|
||||
"""
|
||||
Error raised when parsing fails.
|
||||
It has two members, offset and content, which give the offset of the
|
||||
error and the offending content.
|
||||
"""
|
||||
def __init__(self, expression):
|
||||
self.offset = expression.offset
|
||||
self.content = expression.content[:3]
|
||||
def __str__(self):
|
||||
return 'Unexpected content at offset %i, "%s"'%(self.offset, self.content)
|
||||
|
||||
class Context(dict):
|
||||
"""
|
||||
This class holds variable values by subclassing dict, and while it
|
||||
truthfully reports True and False on
|
||||
|
||||
name in context
|
||||
|
||||
it returns the variable name itself on
|
||||
|
||||
context["name"]
|
||||
|
||||
to reflect the ambiguity between string literals and preprocessor
|
||||
variables.
|
||||
"""
|
||||
def __getitem__(self, key):
|
||||
if key in self:
|
||||
return super(self.__class__, self).__getitem__(key)
|
||||
return key
|
@ -93,7 +93,7 @@ endif
|
||||
ifdef WRAP_SYSTEM_INCLUDES
|
||||
export::
|
||||
if test ! -d system_wrappers_js; then mkdir system_wrappers_js; fi
|
||||
$(PERL) $(srcdir)/preprocessor.pl $(DEFINES) $(ACDEFINES) \
|
||||
$(PYTHON) $(srcdir)/Preprocessor.py $(DEFINES) $(ACDEFINES) \
|
||||
-DBUILD_STATIC_LIBS=$(BUILD_STATIC_LIBS) \
|
||||
$(srcdir)/system-headers | $(PERL) $(srcdir)/make-system-wrappers.pl system_wrappers_js
|
||||
$(INSTALL) system_wrappers_js $(DIST)
|
||||
|
477
js/src/config/Preprocessor.py
Normal file
477
js/src/config/Preprocessor.py
Normal file
@ -0,0 +1,477 @@
|
||||
"""
|
||||
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()
|
@ -1,671 +0,0 @@
|
||||
#!/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.
|
||||
########################################################################
|
@ -189,7 +189,7 @@ langpack-%: XPI_NAME=locale-$*
|
||||
langpack-%: libs-%
|
||||
@echo "Making langpack $(LANGPACK_FILE)"
|
||||
$(NSINSTALL) -D $(DIST)/$(PKG_LANGPACK_PATH)
|
||||
$(PERL) $(MOZILLA_DIR)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) -I$(TK_DEFINES) -I$(APP_DEFINES) $(srcdir)/generic/install.rdf > $(FINAL_TARGET)/install.rdf
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(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
|
||||
|
||||
|
@ -212,7 +212,7 @@ endif
|
||||
|
||||
# XXX applications would need to supply this file
|
||||
#export:: brand.dtd.in
|
||||
# $(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $^ > brand.dtd
|
||||
# $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $^ > brand.dtd
|
||||
|
||||
export::
|
||||
$(NSINSTALL) -D $(DIST)/branding
|
||||
|
@ -61,7 +61,7 @@ include $(topsrcdir)/config/rules.mk
|
||||
libs:: stage-package
|
||||
|
||||
%.plist: %.plist.in
|
||||
$(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $< > $@
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@
|
||||
|
||||
PACKAGER_NO_LIBS=1
|
||||
_APPNAME = XUL.framework
|
||||
|
Loading…
Reference in New Issue
Block a user