#!/usr/bin/perl
# <@LICENSE>
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# </@LICENSE>
#
# This script isn't supposed to be run by hand, it's used by `make` as a pre-
# processor. It currently accepts these options on the command line:
#
# -M<module> Enables <module>
# -D<variable>=<value> Defines the <variable> to be <value>; if the value
# doesn't contain an equal sign, it is interpreted
# as a file and all of its lines containing equal
# signs are taken as <variable>=<value> pairs
#
# and some more to help with non-UNIX platforms, where command-line input
# and output redirection are not always available:
#
# -i<file> Read from input file <file>
# -o<file> Write to output file <file>
#
# -I<dir> Read from input directory <dir>
# -O<dir> Write to output directory <dir>
# <filename> ... Process named files from -I<dir> to -O<dir>
#
# -m<perm> Use chmod permissions <perm> for files
#
# Those modules are currently implemented:
# conditional Comments out every line containing the string
# REMOVEFORINST
# vars Replaces variables: upper case strings surrounded
# by double at-signs, eg. @@VERSION@@. The values are
# taken from the environment and can be overwritten with
# the -D switch. Empty/undefined variables are removed.
# sharpbang Does some sharpbang (#!) replacement. Uses PERL_BIN and
# PERL_WARN.
use
strict;
use
warnings;
my
%modules
= ();
my
%defines
= ();
my
@infiles
= ();
my
$infile
;
my
$outfile
;
my
$indir
;
my
$outdir
;
my
$mode
;
# Each environment variable counts as an own defined var for us.
foreach
(
keys
%ENV
) {
$defines
{
$_
} =
$ENV
{
$_
};
}
foreach
(
@ARGV
) {
if
(/^-M([a-z]+)$/) {
$modules
{$1} = 1; }
elsif
(/^-D([A-Z_]+)=(.*)$/) {
$defines
{$1} = $2; }
elsif
(/^-D([^=]+)$/) { read_defs($1); }
elsif
(/^-i(.+)$/) {
$infile
= $1; }
elsif
(/^-o(.+)$/) {
$outfile
= $1; }
elsif
(/^-I(.+)$/) {
$indir
= $1; }
elsif
(/^-m(.*)$/) {
$mode
=
'0'
.$1; }
elsif
(/^-O(.+)$/) {
$outdir
= $1; }
elsif
(/^(.+)$/) {
push
(
@infiles
, $1); }
}
# On Windows, we get -m without an arg. avoid problems with that
# by just ignoring that switch.
$mode
=
undef
unless
$mode
;
if
(
defined
(
$indir
) &&
defined
(
$outdir
) &&
scalar
@infiles
> 0) {
my
$fname
;
while
(
$fname
=
shift
@infiles
) {
my
$in
= File::Spec->catfile (
$indir
,
$fname
);
my
$out
= File::Spec->catfile (
$outdir
,
$fname
);
do_file (
$in
,
$out
);
}
}
elsif
(
defined
(
$infile
) &&
defined
(
$outfile
)) {
do_file (
$infile
,
$outfile
);
}
else
{
# just do STDIN/STDOUT . Not recommended for portability as
# it requires "<" and ">" for Makefile to do its work.
#
do_stdin();
}
sub
read_defs {
my
(
$in
) =
@_
;
open
(DEFS,
"<$in"
) or
die
"Cannot open $in: $!"
;
foreach
(<DEFS>) {
$_
=~ s/^\s+|\s+$//g;
next
if
/^
#/;
next
unless
/=/;
my
(
$var
,
$val
) =
split
(/\s*=\s*/,
$_
, 2);
$var
=~
tr
/A-Z_//cd;
$defines
{
$var
} =
$val
;
}
close
(DEFS);
}
sub
do_file {
my
(
$in
,
$out
) =
@_
;
open
(FOOIN,
"<$in"
) or
die
"Cannot open $in: $!"
;
open
(FOOOUT,
">$out"
) or
die
"Cannot open $out: $!"
;
do_it();
close
(FOOIN);
close
(FOOOUT);
if
(
defined
$mode
) {
chmod
(
oct
$mode
,
$out
) or
die
"Cannot chmod $mode $out: $!"
;
}
}
sub
do_stdin {
open
(FOOIN,
"<&STDIN"
) or
die
"Cannot dup stdin: $!"
;
open
(FOOOUT,
">&STDOUT"
) or
die
"Cannot dup stdout: $!"
;
do_it();
close
(FOOIN);
close
(FOOOUT);
}
sub
do_it {
# The perlpath can be overwritten via -DPERL_BIN=<perlpath>
my
$perl
;
if
(
$defines
{
'PERL_BIN'
} && (
$defines
{PERL_BIN} ne
'this'
)) {
$perl
=
$defines
{
'PERL_BIN'
};
unless
(-x
$perl
) {
warn
(
"No such PERL_BIN: $perl"
);
}
}
else
{
# use eval so the module is not loaded unless needed; it's slow
eval
'use Config; $perl = $Config{"perlpath"};'
;
}
# Warnings are enabled per default
my
$perl_warn
=
' -w'
;
# The warnings can be overwritten via -DPERL_WARN=<yes|no>
if
(
$defines
{
'PERL_WARN'
} and
$defines
{
'PERL_WARN'
} eq
'no'
) {
$perl_warn
=
''
;
}
# Taint mode is enabled per default except on 5.005
my
$perl_taint
=
' -T'
;
# The taint mode can be disabled with -DPERL_TAINT=<yes|no>
if
(
$defines
{
'PERL_TAINT'
} and
$defines
{
'PERL_TAINT'
} eq
'no'
) {
$perl_taint
=
''
;
}
$defines
{PERL_MAJOR_VER} =
sub
{
$] =~ /^(\d\.\d\d\d)/ or
die
"bad perl ver $]"
;
return
$1;
};
$defines
{PLUGIN_POD} =
sub
{
# Grab active plugin list
my
@plugin_pod
= ();
foreach
my
$pre
(<rules/*.pre>) {
if
(
open
(INIT,
$pre
)) {
while
(<INIT>) {
if
(/^loadplugin\s+(.*?)\s*$/) {
push
(
@plugin_pod
,
" $1\n"
); }
}
close
(INIT);
}
}
return
join
(
''
,
sort
@plugin_pod
);
};
my
$towrite
=
''
;
while
(<FOOIN>) {
$_
=
pack
(
"C0A*"
,
$_
);
# turn off UTF8-ness
# Conditional compiling
if
(
$modules
{
'conditional'
}) {
# DELETE lines carrying the REMOVE_ON_BUILD or (deprecated) REMOVEFORINST tag
if
(/\bREMOVE(?:FORINST|_ON_BUILD)\b/) {
next
;
}
}
$towrite
.=
$_
;
}
# Sharpbang (#!) replacement (see also ExtUtils::MY->fixin)
if
(
$modules
{
'sharpbang'
}) {
$towrite
=~ s/^
#![^\n]*perl[^\n]*\n/#!${perl}${perl_taint}${perl_warn}\n/;
}
# Variable replacement (do in one invocation)
if
(
$modules
{
'vars'
}) {
# Replace all @@VARS@@
while
(
$towrite
=~ /\@\@([A-Z][A-Z0-9_]*)\@\@/) {
my
$what
= $1;
my
$d
=
$defines
{
$what
} ||
''
;
if
(
ref
(
$d
) =~ /^CODE/) {
$d
=
$d
->(); }
$towrite
=~ s/\@\@${what}\@\@/
$d
/g;
}
}
FOOOUT
$towrite
;
}