sub
eval_or_die($) {
$Mpp::Rule::unsafe
= 1;
Mpp::Subs::eval_or_die
$_
[0],
$Mpp::Subs::rule
->{MAKEFILE},
$Mpp::Subs::rule
->{RULE_SOURCE};
}
our
(
$install_date
,
$install_log
);
sub
perform(&$;$) {
if
(
eval
{ &{
$_
[0]} } && !$@ ) {
print
STDERR
"$0: $_[1]\n"
if
$Mpp::verbose
;
if
(
$install_log
) {
my
$msg
=
$_
[1];
my
$cwd
= absolute_filename
$CWD_INFO
;
$msg
=~ s|`(?=[^/`][^`]*$)|`
$cwd
/|;
if
(
$Mpp::Event::max_proc
> 1 ) {
flock
$install_log
, 2;
if
(
$install_date
=~ /^ / ) {
if
( (
stat
$install_log
)[7] >
tell
$install_log
) {
seek
$install_log
, 0, 2;
print
$install_log
"$install_date $msg\n"
or
die
$!;
}
else
{
print
$install_log
" $msg\n"
or
die
$!;
}
}
else
{
seek
$install_log
, 0, 2;
print
$install_log
"$install_date $msg\n"
or
die
$!;
$install_date
=
" $install_date"
;
}
flock
$install_log
, 8;
}
else
{
print
$install_log
"$install_date $msg\n"
or
die
$!;
}
$install_date
=
''
;
}
1;
}
elsif
( !
$_
[2] ) {
die
"could not $_[1]--"
. ($@ || $!) .
"\n"
;
}
}
sub
_rm {
my
@dirs
;
perform {
unlink
}
"delete `$_'"
for
grep
{ -l || !-d _ ?
$_
: !
push
@dirs
,
$_
}
@_
;
perform {
rmdir
}
"delete directory `$_'"
for
sort
{
my
(
$A
,
$B
) = (
$a
,
$b
); (
$B
=~
tr
:/::d) <=> (
$A
=~
tr
:/::d) }
@dirs
;
}
my
(
$noescape
,
$force
,
$inpipe
,
$print
,
$print_nl
,
$synclines
,
$last_file
,
$last_line
);
sub
print
{
if
(
defined
and
length
) {
if
(
$synclines
) {
if
(
$last_file
ne
$ARGV
) {
$print_nl
or
$print
.=
"\n"
;
$print
.=
"#line $. \"$ARGV\"\n"
;
$last_file
=
$ARGV
;
$last_line
= $.;
}
elsif
( ++
$last_line
!= $. ) {
$print_nl
or
$print
.=
"\n"
;
$print
.=
"#line $.\n"
;
$last_line
= $.;
}
if
( /^\s*
$_
.=
'#line '
. ($. + 1) . ($1 ?
" \"$ARGV\"\n"
:
"\n"
);
}
else
{
s/\n(?!\z)/\n
}
$print_nl
= /\n\z/;
}
$print
.=
$_
;
if
( 8 * 1024 <
length
$print
) {
syswrite
select
,
$print
or
die
$!;
$print
=
''
;
}
}
}
sub
frame(&@) {
my
(
$code
,
@opts
,
@stdopts
) =
@_
;
local
$Mpp::verbose
=
$Mpp::verbose
;
my
(
$infail
,
$inout
,
$output
,
$pipe
,
$select
,
$outfail
,
$separator
);
my
%opt
=
(
E
=> [
'E'
,
qr/no[-_]?escape/
, \
$noescape
],
f
=> [
qw(f force)
, \
$force
],
i
=> [
qw(i inpipe)
, \
$inpipe
, 1],
I
=> [
qw(I infail)
, \
$infail
],
o
=> [
qw(o output)
, \
$output
, 1],
O
=> [
qw(O outfail)
, \
$outfail
],
r
=> [
'r'
,
qr/record[-_]?size/
, \
$separator
, 1,
sub
{
$separator
=
eval
"\\$separator"
}],
s
=> [
qw(s separator)
, \
$separator
, 1],
S
=> [
'S'
,
qr/sync[-_]?lines/
, \
$synclines
]);
@opts
=
grep
{
ref
or !
push
@stdopts
,
$opt
{
$_
};
}
@opts
;
Mpp::Text::getopts
@opts
,
@stdopts
,
[
qw(v verbose)
, \
$Mpp::verbose
];
local
$/ =
$separator
if
defined
$separator
;
if
(
$inpipe
) {
$inpipe
=~ s/\|$//s;
perform {
open
STDIN,
'-|'
,
$inpipe
}
"call `$inpipe|'"
;
}
local
$SIG
{__WARN__} =
sub
{
if
(
$_
[0] =~ /^Can't
open
(.*?): $! at/ ) {
die
"$0: cannot open `$1'--$!\n"
;
}
else
{
warn
$_
[0];
}
};
$print
=
''
;
$print_nl
= 1;
$last_file
=
''
if
$synclines
;
local
*STDOUT
if
$output
;
if
(
$output
) {
my
$first
=
ord
$output
;
$pipe
=
$first
==
ord
'|'
;
if
(
$pipe
or
$first
!=
ord
'+'
or
$output
!~ /^\+</ ) {
if
( !
$pipe
and
$force
) {
my
$file
=
$output
;
$file
=~ s/^>\s*//;
_rm
$file
if
-e
$file
;
}
perform {
open
STDOUT, (
$pipe
or
$first
==
ord
'>'
) ?
$output
:
">$output"
}
"write `$output'"
;
}
else
{
$output
=~ s/^\+<((.*?)[^\/]+)$/$1/;
$inout
=
"$2.makepp.$$"
.
substr
rand
, 1;
perform {
open
STDIN,
$output
and
open
STDOUT,
'>'
,
$inout
}
"read `$output' and write to tempfile"
;
}
$select
=
select
STDOUT;
}
local
$SIG
{PIPE} =
'IGNORE'
if
$pipe
;
my
@res
=
eval
{
&$code
};
my
$err
= $@;
sub
_closedie($) {
die
"`$_[0]' "
,
$! ?
"failed to close--$!"
:
($? & 127) ?
"died with signal "
. ($? & 127) :
"exited with value "
. ($? >> 8);
}
if
(
$inpipe
&&
$infail
or
$inout
) {
close
STDIN or _closedie
$inpipe
;
open
STDIN,
'/dev/null'
;
}
print
$print
or
die
$!
if
length
$print
;
$print
=
''
;
if
(
$output
) {
close
STDOUT or
$outfail
&& _closedie
$output
;
perform {
rename
$inout
,
$output
}
"rename tempfile to `$output'"
if
$inout
;
select
$select
;
}
undef
${
$$_
[2]}
for
@stdopts
;
die
$err
if
$err
;
@res
;
}
sub
_chomp(\$) {
return
''
if
ref
$/;
my
$tail
= ${
$_
[0]};
my
$len
=
chomp
${
$_
[0]};
return
''
unless
$len
;
substr
$tail
, -
$len
;
}
sub
c_cat {
local
@ARGV
=
@_
;
frame {
if
(
$synclines
) {
local
$/ = \8192;
while
( <> ) {
if
( $. == 1 ) {
print
$print_nl
?
''
:
"\n"
,
"#line 1 \"$ARGV\"\n$_"
;
}
else
{
print
;
}
$print_nl
= /\n\z/;
close
ARGV
if
eof
;
}
}
else
{
perform { File::Copy::copy(
$_
, \
*STDOUT
) }
"copy `$_'"
for
@ARGV
;
}
}
'f'
,
qw(i I o O S)
;
}
sub
c_chmod {
local
@ARGV
=
@_
;
frame {
my
$mode
=
oct
shift
@ARGV
;
perform {
chmod
$mode
,
$_
}
"set mode for `$_'"
for
@ARGV
;
};
}
sub
c_cp {
my
$mv
;
local
@ARGV
=
@_
;
$mv
=
shift
@ARGV
if
ref
$_
[0];
my
(
$link
,
$symbolic
);
frame {
my
$dest
=
@ARGV
== 1 ?
'.'
:
pop
@ARGV
;
my
$cmd
=
$mv
?
'move'
:
'copy'
;
$mv
=
$mv
? \
&File::Copy::move
: \
&File::Copy::syscopy
;
for
(
@ARGV
) {
my
$d
= -d
$dest
;
my
$dirdest
=
$d
?
$dest
.
'/'
. f_notdir
$_
:
$dest
;
_rm
$dirdest
if
$force
&& (
$d
? -e(
$dirdest
) :
defined
$d
);
$link
&& perform {
link
$_
,
$dirdest
}
"link `$_' to `$dirdest'"
, 1
or
$symbolic
&& perform {
symlink
f_relative_to(
$_
.
','
. f_dir
$dirdest
),
$dirdest
}
"link `$_' to `$dirdest' symbolically"
, 1
or perform {
&$mv
(
$_
,
$dirdest
) }
"$cmd `$_' to `$dirdest'"
;
}
}
'f'
,
$mv
? () :
([
qw(l link)
, \
$link
],
[
's'
,
qr/sym(?:bolic(?:[-_]?link)?|link)/
, \
$symbolic
]);
}
sub
c_mv { c_cp \1,
@_
}
sub
c_cut {
local
@ARGV
=
@_
;
my
(
$delimiter
,
$characters
,
$fields
,
$lines
,
$matching
,
$printf
,
$only_delim
) =
"\t"
;
my
$err
=
"one of --characters, --fields or --lines must be given\n"
;
frame {
my
$split
=
eval
'sub { @::F = '
. (!
$characters
?
"split /\Q$delimiter\E/, \$_, -1 }"
:
Mpp::is_perl_5_6 ?
'split //, $_, -1 }'
:
'unpack "(a1)*", $_ }'
);
my
(
@idxs
,
$eol
);
local
@::F;
@idxs
= eval_or_die
$fields
unless
$fields
=~ /^[-+.,\d\s]+$/ &&
$fields
=~ s/((?:,|^)\d+\.\.)-/
"$1\$#::F+"
. (
defined
$lines
?
'2-'
:
'1-'
)/eg;
if
(
defined
$lines
) {
warn
"options --matching or --printf make no sence with --lines\n"
if
$matching
||
$only_delim
||
$printf
;
while
( <> ) {
push
@::F,
$_
;
if
(
eof
) {
for
my
$line
(
@idxs
?
@idxs
: eval_or_die
$fields
) {
$line
or
die
"$0: line numbers start at 1, not 0\n"
;
$. =
$line
> 0 ?
$line
: @::F + 1 +
$line
;
$_
= $::F[$. - 1];
&print
;
}
close
ARGV;
@::F = ();
}
}
}
elsif
(
defined
$fields
) {
if
(
$printf
&& !
$noescape
) {
$printf
=~ s/([\$\@!])/\\$1/g;
$printf
=
eval
"qq!$printf!"
;
die
$@
if
$@;
}
while
( <> ) {
$eol
= _chomp
$_
;
&$split
;
if
( @::F > 1 ) {
@::F =
map
{
defined
() ?
$_
:
$matching
?
next
:
''
} @::F[
@idxs
?
@idxs
: eval_or_die
$fields
];
$_
=
$printf
?
sprintf
(
$printf
, @::F ) :
join
(
$delimiter
, @::F ) .
$eol
;
}
elsif
(
$matching
||
$only_delim
) {
next
;
}
else
{
$_
.=
$eol
;
}
&print
;
close
ARGV
if
$synclines
&&
eof
;
}
}
else
{
die
$err
;
}
}
qw(E f i I o O r s S)
,
[
qw(c characters)
, \
$characters
, 1,
sub
{
$delimiter
=
''
;
warn
$err
if
defined
$fields
;
$fields
=
$characters
}],
[
qw(d delimiter)
, \
$delimiter
, 1],
[
qw(f fields)
, \
$fields
, 1,
sub
{
warn
$err
if
defined
$characters
or
defined
$lines
}],
[
qw(l lines)
, \
$lines
, 1,
sub
{
warn
$err
if
defined
$fields
;
$fields
=
$lines
}],
[
qw(m matching)
, \
$matching
],
[
qw(p printf)
, \
$printf
, 1],
[
's'
,
qr/only[-_]?delimited/
, \
$only_delim
];
}
sub
c_echo {
my
$cmd
= 0;
local
@ARGV
=
@_
;
$cmd
= ${
shift
@ARGV
}
if
ref
$_
[0];
my
$nonewline
;
frame {
my
$res
;
if
(
$cmd
== 1 ) {
$res
= eval_or_die
"@ARGV"
if
@ARGV
;
$res
=
''
unless
defined
$res
;
}
else
{
$res
=
$cmd
== 2 ?
shift
@ARGV
:
"@ARGV"
;
unless
(
$noescape
) {
$res
=~ s/([\$\@!])/\\$1/g;
$res
=
eval
"qq!$res!"
;
die
$@
if
$@;
}
$res
=
sprintf
$res
,
@ARGV
if
$cmd
== 2;
}
if
(
$cmd
== 3 ) {
$res
||=
'y'
;
1
while
print
$res
,
$nonewline
? () :
"\n"
;
}
else
{
print
$res
,
$nonewline
||
$cmd
== 2 ? () :
"\n"
or
die
$!;
}
die
"false\n"
if
$cmd
== 1 && !
$res
;
}
qw(f o O)
,
$cmd
!= 1 ?
'E'
: (),
$cmd
!= 2 ? [
'n'
,
qr/no[-_]?newline/
, \
$nonewline
] : ();
}
sub
c_expr { c_echo \1,
@_
}
sub
c_printf { c_echo \2,
@_
}
sub
c_yes { c_echo \3,
@_
}
sub
c_grep {
my
$cmd
;
local
@ARGV
=
@_
;
$cmd
= ${
shift
@ARGV
}
if
ref
$_
[0];
my
(
$fn
,
$n
,
$revert
,
$count
,
$list
,
$waste
) = (0, 0, 0);
frame {
my
$prog
= eval_or_die
'sub {'
.
shift
(
@ARGV
) .
"\n}"
;
perform {
open
my
$fh
,
'>'
,
$waste
;
$waste
=
$fh
;
}
"write `$waste'"
if
$waste
;
while
( <> ) {
if
(
$cmd
) {
&$prog
;
&print
if
$cmd
== 2;
}
elsif
(
$revert
== 1 ? !
&$prog
:
&$prog
) {
$n
++;
if
( !
$list
) {
$count
or
&print
;
}
elsif
(
$revert
== 2 ) {
$fn
++ ;
}
else
{
print
"$ARGV\n"
or
die
$!;
close
ARGV;
}
}
elsif
(
$waste
) {
print
$waste
$_
or
die
$!;
}
if
(
$list
&&
$revert
> 1 &&
eof
) {
print
"$ARGV\n"
or
die
$!
if
!
$fn
;
$fn
= 0;
}
close
ARGV
if
$synclines
&&
eof
;
}
print
"$n\n"
or
die
$!
if
$count
;
close
$waste
if
$waste
;
die
"no matches\n"
unless
$cmd
or
$n
or
$count
;
}
qw(f i I o O r s S)
,
(
$cmd
? () :
([
qw(c count)
, \
$count
],
[
'l'
,
qr/list|files[-_]?with[-_]?matches/
, \
$list
],
[
'v'
,
qr/vice[-_]?versa|(?:re|in)vert[-_]?match/
, \
$revert
],
[
'w'
,
qr/waste[-_]?file/
, \
$waste
, 1]));
}
sub
c_perl { c_grep \1,
@_
}
sub
c_sed { c_grep \2,
@_
}
sub
c_install {
local
@ARGV
=
@_
;
my
$dest
=
pop
@ARGV
;
my
(
$mode
,
$gid
,
$uid
,
$copy
,
$link
,
$symbolic
,
$resolve
,
$log
,
$directory
,
$strip
) = 755;
frame {
my
$i
= 2;
--
$i
,
defined
() && !/^\d+$/ and
defined
(
$_
=
$i
?
getpwnam
(
$_
) :
getgrnam
(
$_
)) ||
die
$i
?
'user'
:
'group'
,
" unknown\n"
for
$uid
,
$gid
;
local
$install_date
=
localtime
() .
" [$$]\n"
;
my
$fh
;
$log
||=
$ENV
{INSTALL_LOG} ||
(
$CWD_INFO
->{ROOT} ? relative_filename(
$CWD_INFO
->{ROOT} ) :
'.'
) .
'/.install_log'
;
perform {
open
$fh
,
'>>'
,
$log
}
"append to `$log'"
;
local
$install_log
=
$fh
;
my
@dest
;
if
(
$directory
) {
warn
"options --copy, --link or --strip make no sence with --directory\n"
if
$copy
||
$link
||
$symbolic
||
$resolve
||
$strip
;
@dest
= c_mkdir(
'-pm'
,
$mode
,
@ARGV
,
$dest
);
}
else
{
(
$copy
,
$link
) =
$link
? (\
&c_cp
,
'-l'
) :
$copy
? \
&c_cp
:
$symbolic
? (\
&c_ln
,
'-s'
) :
$resolve
? (\
&c_ln
,
'-r'
) :
\
&c_mv
;
for
(
@ARGV
) {
&$copy
(
$link
?
$link
: (),
$_
,
$dest
);
-d(
$dest
) ? s!^(?:.*/)?!
$dest
/! : (
$_
=
$dest
);
push
@dest
,
$_
;
}
perform {
system
'strip'
,
@dest
}
"strip `@dest'"
if
$strip
;
c_chmod
$mode
,
@dest
;
}
if
(
defined
$uid
||
defined
$gid
) {
perform {
chown
defined
$uid
?
$uid
: (
stat
)[4],
defined
$gid
?
$gid
: (
stat
)[5],
$_
}
defined
$uid
&&
defined
$gid
?
"set owner $uid and group $gid for `$_'"
:
defined
$uid
?
"set owner $uid for `$_'"
:
"set group $gid for `$_'"
for
@dest
;
}
} [
qw(c copy)
, \
$copy
],
[
qw(d directory)
, \
$directory
],
[
qw(g group)
, \
$gid
, 1],
[
qw(l link)
, \
$link
],
[
undef
,
qr/log(?:file)?/
, \
$log
, 1],
[
qw(m mode)
, \
$mode
, 1],
[
qw(o owner)
, \
$uid
, 1],
[
'S'
,
qr/sym(?:bolic(?:[-_]?link)?|link)/
, \
$symbolic
],
[
'r'
,
qr/resolve[-_]?(?:sym(?:bolic(?:[-_]?link)?|link))?/
, \
$resolve
],
[
qw(s strip)
, \
$strip
];
}
sub
c_ln {
local
@ARGV
=
@_
;
my
(
$symbolic
,
$resolve
);
frame {
my
$dest
=
@ARGV
== 1 ?
'.'
:
pop
@ARGV
;
$dest
=~ s|/+$||;
my
$d
= -d
$dest
;
for
(
@ARGV
) {
my
$dirdest
=
$d
?
$dest
.
'/'
. f_notdir
$_
:
$dest
;
_rm
$dirdest
if
$force
&& (
$d
? -l(
$dirdest
) || -e _ :
defined
$d
);
if
(
$ENV
{MAKEPP_LN_CP} and
$ENV
{MAKEPP_LN_CP} & (
$resolve
||
$symbolic
? 1 : 2) ) {
$_
= f_relative_filename f_dir(
$dirdest
) .
$_
if
$symbolic
&& !
$resolve
;
perform { File::Copy::syscopy(
$_
,
$dirdest
) }
"copy `$_' to `$dirdest'"
;
}
elsif
(
$resolve
||
$symbolic
) {
$_
= f_relative_to
$_
.
','
. f_dir
$dirdest
if
$resolve
;
perform {
symlink
$_
,
$dirdest
}
"link `$_' to `$dirdest' symbolically"
;
}
else
{
perform {
link
$_
,
$dirdest
}
"link `$_' to `$dirdest'"
;
}
}
}
'f'
,
[
'r'
,
qr/resolve[-_]?(?:sym(?:bolic(?:[-_]?link)?|link))?/
, \
$resolve
],
[
's'
,
qr/sym(?:bolic(?:[-_]?link)?|link)/
, \
$symbolic
];
}
sub
c_mkdir {
local
@ARGV
=
@_
;
my
$mode
= 755;
my
$parent
;
frame {
$mode
=
oct
$mode
;
my
$umask
=
umask
0;
my
@created
;
for
(
@ARGV
) {
if
(
$parent
) {
my
$dir
=
''
;
for
(
split
/(?=\/)/ ) {
$dir
.=
$_
;
next
if
-d
$dir
;
_rm
$dir
if
$force
&& -e _;
perform { (
my
$d
=
$dir
) =~ s!/+$!!;
mkdir
$d
,
$mode
or $! == POSIX::EEXIST && -d
$dir
}
"create directory `$dir'"
;
push
@created
,
$dir
;
}
}
elsif
( ! -d ) {
_rm
$_
if
$force
&& -e _;
perform { (
my
$d
=
$_
) =~ s!/+$!!;
mkdir
$d
,
$mode
}
"create directory `$_'"
;
push
@created
,
$_
;
}
}
umask
$umask
;
@created
;
}
'f'
,
[
qw(m mode)
, \
$mode
, 1],
[
qw(p parent)
, \
$parent
];
}
my
$package_seed
= 0;
sub
c_preprocess {
$Mpp::Rule::unsafe
= 1;
local
@ARGV
=
@_
;
my
(
$command_line_vars
,
$assignment
,
$tmp
) = {};
frame {
my
$re
=
$assignment
?
qr/f_|s_(?:_?include|(?:make)?(?:perl|sub)|perl_begin|define|(?:un)?export)/
:
qr/f_|s_(?:_?include|(?:make)?(?:perl|sub)|perl_begin)/
;
my
$cwd
=
$CWD_INFO
;
for
(
@ARGV
) {
perform {
local
$Mpp::Makefile::c_preprocess
=
$assignment
? 1 : 2;
my
$finfo
= file_info
$_
,
$cwd
;
local
$Mpp::Makefile::makefile
=
bless
{
MAKEFILE
=>
$finfo
,
PACKAGE
=>
'preprocess_'
.
$package_seed
++,
CWD
=>
$finfo
->{
'..'
},
COMMAND_LINE_VARS
=>
$command_line_vars
,
ENVIRONMENT
=>
$Mpp::Subs::rule
->{MAKEFILE}{ENVIRONMENT},
RE_COUNT
=> 0
},
'Mpp::Makefile'
;
chdir
$finfo
->{
'..'
};
eval
"package $Mpp::Makefile::makefile->{PACKAGE}; use Mpp::Subs \$re"
;
Mpp::Makefile::read_makefile(
$Mpp::Makefile::makefile
,
$finfo
); 1;
}
"preprocess `$_'"
;
}
}
$command_line_vars
,
qw(f o O S)
,
[
qw(a assignment)
, \
$assignment
],
[
qw(h hashref)
, \
$tmp
, 1,
sub
{
$tmp
= eval_or_die
$tmp
;
$command_line_vars
->{
$_
} =
$tmp
->{
$_
}
for
keys
%$tmp
}];
}
sub
c_rm {
local
@ARGV
=
@_
;
my
$meta
;
frame {
my
%makepp
;
if
(
$meta
) {
for
(
@ARGV
) {
m!(.*?)([^/]+)$!;
$makepp
{
"$1.makepp"
} = 1
if
unlink
"$1.makepp/$2.mk"
;
}
}
@ARGV
=
grep
-e || -l,
@ARGV
if
$force
;
rmdir
for
keys
%makepp
;
_rm
@ARGV
;
}
'f'
,
[
qw(m metainfo)
, \
$meta
];
}
sub
c_sort {
local
@ARGV
=
@_
;
my
(
$uniq
,
$cmp
,
$rev
,
$transform
,
$detransform
) =
''
;
frame {
$uniq
&&=
'grep { $a = $_, 1 if !defined $a or '
. (
$cmp
?
"do { \$b = \$_; $cmp }}"
:
'$a cmp $_ }'
);
$uniq
.=
' reverse'
if
$rev
;
print
$transform
? eval_or_die
"map { $detransform } $uniq sort "
. (
$cmp
?
"{ $cmp } "
:
''
) .
"map { $transform } <>"
:
$cmp
? eval_or_die
"$uniq sort { $cmp } <>"
:
$uniq
? eval_or_die
"$uniq sort <>"
:
$rev
?
reverse
sort
<> :
sort
<>
or
die
$!;
eval_or_die
'undef $a'
if
$uniq
;
}
qw(f i I o O r s)
,
[
qw(c compare)
, \
$cmp
, 1],
[
'n'
,
qr/num(?:eric(?:[-_]?sort)?)?/
, \
$cmp
,
undef
,
q{ do { no warnings; $a <=> $b }
}],
[
qw(r reverse)
, \
$rev
],
[
qw(t transform)
, \
$transform
, 1],
[
qw(d detransform)
, \
$detransform
, 1],
[
'u'
,
qr/uniq(?:ue)?/
, \
$uniq
];
}
sub
c_template {
local
@ARGV
=
@_
;
my
(
%macros
,
$tmp
);
my
(
$pre
,
$suf
,
$Pre
,
$Suf
,
$afterPre
,
$afterSuf
,
$re
) =
qw(@ @(?:\\\\\n)
? @@ @@ @@);
frame {
$re
=
$re
?
join
(
'|'
,
keys
%macros
) :
qr/\w[-\w.]*/
;
my
$pre_re
=
length
(
$Pre
) ? (
length
(
$pre
) ?
qr/$Pre()|$pre/
:
qr/$Pre()/
) :
qr/$pre|$pre()/
;
my
$suf_re
=
length
(
$Suf
) ? (
length
(
$suf
) ?
qr/(?(2)(?:$Suf()|$suf)|$suf)/
:
qr/$Suf()/
) :
qr/$suf/
;
my
$handler
=
sub
{
if
(
defined
$_
[3] ) {
if
(
exists
$macros
{
$_
[3]} ) {
return
''
if
$_
[4];
}
else
{
$re
= (
$re
?
"$re|"
:
''
) .
$_
[3];
}
$macros
{
$_
[3]} =
$_
[6] ? eval_or_die(
"sub $_[6]"
) :
$_
[5];
''
;
}
elsif
(
defined
$_
[2] ) {
eval_or_die
$_
[2];
}
else
{
my
$repl
=
$macros
{
$_
[0]};
if
( !
defined
$repl
) {
$repl
=
''
;
}
else
{
my
@args
=
map
{ s/
$pre
(
$re
)
$suf
/
$macros
{$1}/g;
$_
}
split
','
,
$_
[1]
if
$_
[1];
if
(
ref
$repl
) {
$repl
=
&$repl
(
@args
);
}
elsif
(
$_
[1] ) {
$repl
=~ s/\$([1-9])/$1 >
@args
?
''
:
$args
[$1-1]/ge;
$repl
=~ s/\$\{([1-9]\d*)\}/$1 >
@args
?
''
:
$args
[$1-1]/ge;
}
}
$repl
;
}
};
while
( <> ) {
my
$line
;
while
( s/(.*?)
$pre_re
(?:(
$re
)(?:\((.*?)\))? | \{(.*?)\} | (\w[-\w.]*)(?:(\?)?=(.*?) | \s*(\{.*?\})))
$suf_re
//x ) {
if
(
defined
$line
) {
$line
.= $1;
}
else
{
$line
= $1;
}
@_
= ($3, $4, $5, $6, $7, $8, $9);
if
(
defined
$2 &&
defined
$10 ) {
my
$end
=
$afterSuf
?
qr/$_[0]$afterSuf/
:
''
;
until
( s/.*?
$afterPre
$end
// ) {
if
(
eof
) {
warn
"$ARGV:$.: $Pre$_[0]$Suf unterminated\n"
;
$_
=
''
;
last
;
}
$_
= <>;
}
}
$line
.=
&$handler
;
}
substr
$_
, 0, 0,
$line
if
defined
$line
;
&print
;
close
ARGV
if
$synclines
&&
eof
;
}
} \
%macros
,
qw(f i I o O S)
,
[
qw(h hashref)
, \
$tmp
, 1,
sub
{
$tmp
= eval_or_die
$tmp
;
$macros
{
$_
} =
$tmp
->{
$_
}
for
keys
%$tmp
}],
[
qw(s simple)
, \
$pre
, 1,
sub
{
(
undef
,
$pre
,
$suf
) =
split
quotemeta
(
substr
$pre
, 0, 1 ),
$pre
;
}],
[
qw(m multiline)
, \
$Pre
, 1,
sub
{
(
undef
,
$Pre
,
$Suf
,
$afterPre
,
$afterSuf
) =
split
quotemeta
(
substr
$Pre
, 0, 1 ),
$Pre
;
}],
[
qw(d defined)
, \
$re
];
}
sub
c_touch {
local
@ARGV
=
@_
;
frame {
my
$time
=
time
;
for
(
@ARGV
) {
if
( -f ) {
perform {
utime
$time
,
$time
,
$_
}
"update timestamp on `$_'"
;
}
else
{
perform {
open
my
$fh
,
'>'
,
$_
}
"create `$_'"
;
}
}
};
}
sub
c_uninstall {
local
@ARGV
=
@_
;
frame {
@ARGV
=
$ENV
{INSTALL_LOG} ||
(
$CWD_INFO
->{ROOT} ? relative_filename(
$CWD_INFO
->{ROOT} ) :
'.'
) .
'/.install_log'
unless
$inpipe
||
@ARGV
;
my
%files
;
/^ .* `(.+)'/ and
$files
{$1} = 1
while
<>;
eval
{ _rm
sort
keys
%files
};
}
'i'
,
'I'
;
}
sub
c_uniq {
local
@ARGV
=
@_
;
my
$cmp
;
frame {
$cmp
= eval_or_die
"sub {$cmp\n}"
if
$cmp
;
no
strict
'refs'
;
local
*a
= \${
"$Mpp::Subs::rule->{MAKEFILE}{PACKAGE}::a"
};
local
*b
= \${
"$Mpp::Subs::rule->{MAKEFILE}{PACKAGE}::b"
};
local
*_
= \
$b
;
undef
$a
;
while
(
$b
= <> ) {
&print
if
!
defined
$a
or
$cmp
?
&$cmp
() :
$a
ne
$b
;
$a
=
$b
;
close
ARGV
if
$synclines
&&
eof
;
}
}
qw(f i I o O r s S)
,
[
qw(c compare)
, \
$cmp
, 1];
}
1;