line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
2
|
|
|
2
|
|
1950
|
use strict;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
93
|
|
2
|
2
|
|
|
2
|
|
12
|
use warnings;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
129
|
|
3
|
|
|
|
|
|
|
require 5.006;
|
4
|
|
|
|
|
|
|
package Parse::Template;
|
5
|
|
|
|
|
|
|
$Parse::Template::VERSION = '3.08';
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
22
|
use Carp;
|
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
273
|
|
8
|
2
|
|
|
2
|
|
14
|
use constant DEBUG => 0;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
148
|
|
9
|
2
|
|
|
2
|
|
12
|
use vars qw/$AUTOLOAD/;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
201
|
|
10
|
|
|
|
|
|
|
sub AUTOLOAD {
|
11
|
0
|
|
|
0
|
|
0
|
my($class, $part) = ($AUTOLOAD =~ /(.*)::(.*)$/);
|
12
|
2
|
|
|
2
|
|
11
|
no strict 'refs';
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
257
|
|
13
|
0
|
|
0
|
0
|
|
0
|
*$AUTOLOAD = sub { (ref $_[0] || $class)->eval("$part", @_) };
|
|
0
|
|
|
|
|
0
|
|
14
|
0
|
|
|
|
|
0
|
goto &$AUTOLOAD;
|
15
|
|
|
|
|
|
|
}
|
16
|
|
|
|
|
|
|
|
17
|
2
|
|
|
2
|
|
2094
|
use Symbol qw(delete_package);
|
|
2
|
|
|
|
|
2630
|
|
|
2
|
|
|
|
|
310
|
|
18
|
0
|
|
|
0
|
0
|
0
|
{ my $id = 0; sub getid { $id++ } }
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
my $PACKAGE = __PACKAGE__;
|
21
|
|
|
|
|
|
|
sub new {
|
22
|
0
|
|
|
0
|
1
|
0
|
my $receiver = shift;
|
23
|
0
|
|
|
|
|
0
|
my $class = $PACKAGE . '::Sym' . getid();
|
24
|
0
|
|
|
|
|
0
|
my $self = bless {}, $class; # absolutely nothing in $self
|
25
|
2
|
|
|
2
|
|
15
|
no strict 'refs';
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
299
|
|
26
|
0
|
|
|
|
|
0
|
%{"${class}::template"} = (); # so no 'used only once' warning
|
|
0
|
|
|
|
|
0
|
|
27
|
0
|
|
|
|
|
0
|
${"${class}::ancestor"} = ''; # so no 'used only once' warning
|
|
0
|
|
|
|
|
0
|
|
28
|
|
|
|
|
|
|
|
29
|
0
|
|
0
|
|
|
0
|
@{"${class}::ISA"} = ref $receiver || $receiver;
|
|
0
|
|
|
|
|
0
|
|
30
|
0
|
|
|
|
|
0
|
${"${class}::ancestor"} = $receiver; # reverse the destruction order
|
|
0
|
|
|
|
|
0
|
|
31
|
0
|
|
|
|
|
0
|
*{"${class}::AUTOLOAD"} = \&AUTOLOAD; # so no warning for procedural calls
|
|
0
|
|
|
|
|
0
|
|
32
|
0
|
|
|
|
|
0
|
%{"${class}::template"} = @_ ;
|
|
0
|
|
|
|
|
0
|
|
33
|
0
|
|
|
|
|
0
|
$self;
|
34
|
|
|
|
|
|
|
}
|
35
|
2
|
|
|
2
|
|
13
|
use constant TRACE_ENV => 0;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
241
|
|
36
|
|
|
|
|
|
|
sub env {
|
37
|
0
|
|
|
0
|
1
|
0
|
my $self = shift;
|
38
|
0
|
|
0
|
|
|
0
|
my $class = ref $self || $self;
|
39
|
0
|
|
|
|
|
0
|
my $symbol = shift;
|
40
|
0
|
0
|
|
|
|
0
|
if ($symbol =~ /\W/) {
|
41
|
0
|
|
|
|
|
0
|
Carp::croak "invalid symbol name: $symbol"
|
42
|
|
|
|
|
|
|
}
|
43
|
2
|
|
|
2
|
|
11
|
no strict;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
1636
|
|
44
|
0
|
0
|
|
|
|
0
|
if (@_) {
|
|
0
|
0
|
|
|
|
0
|
|
45
|
0
|
|
|
|
|
0
|
do {
|
46
|
0
|
|
|
|
|
0
|
my $value = shift;
|
47
|
0
|
|
|
|
|
0
|
print STDERR "${class}::$symbol\t$value\n" if TRACE_ENV;
|
48
|
0
|
0
|
|
|
|
0
|
if (ref $value) {
|
49
|
0
|
|
|
|
|
0
|
*{"${class}::$symbol"} = $value;
|
|
0
|
|
|
|
|
0
|
|
50
|
|
|
|
|
|
|
} else { # scalar value
|
51
|
0
|
|
|
|
|
0
|
*{"${class}::$symbol"} = \$value;
|
|
0
|
|
|
|
|
0
|
|
52
|
|
|
|
|
|
|
}
|
53
|
0
|
0
|
|
|
|
0
|
$symbol = shift if @_;
|
54
|
0
|
0
|
|
|
|
0
|
if ($symbol =~ /\W/) {
|
55
|
0
|
|
|
|
|
0
|
Carp::croak "invalid symbol name: $symbol";
|
56
|
|
|
|
|
|
|
}
|
57
|
|
|
|
|
|
|
} while (@_);
|
58
|
|
|
|
|
|
|
}
|
59
|
|
|
|
|
|
|
elsif (defined *{"${class}::$symbol"}) { # borrowed from Exporter.pm
|
60
|
0
|
0
|
|
|
|
0
|
return \&{"${class}::$symbol"} unless $symbol =~ s/^(\W)//;
|
|
0
|
|
|
|
|
0
|
|
61
|
0
|
|
|
|
|
0
|
my $type = $1;
|
62
|
|
|
|
|
|
|
return
|
63
|
0
|
|
|
|
|
0
|
$type eq '*' ? *{"${class}::$symbol"} :
|
|
0
|
|
|
|
|
0
|
|
64
|
0
|
|
|
|
|
0
|
$type eq "\$" ? \${"${class}::$symbol"} :
|
65
|
0
|
|
|
|
|
0
|
$type eq '%' ? \%{"${class}::$symbol"} :
|
66
|
0
|
|
|
|
|
0
|
$type eq '@' ? \@{"${class}::$symbol"} :
|
67
|
|
|
|
|
|
|
$type eq '&' ? \&{"${class}::$symbol"} :
|
68
|
0
|
0
|
|
|
|
0
|
do { Carp::croak("Can\'t find symbol: $type$symbol") };
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
69
|
|
|
|
|
|
|
}
|
70
|
|
|
|
|
|
|
else {
|
71
|
0
|
|
|
|
|
0
|
undef;
|
72
|
|
|
|
|
|
|
}
|
73
|
|
|
|
|
|
|
}
|
74
|
|
|
|
|
|
|
sub DESTROY {
|
75
|
0
|
|
|
0
|
|
0
|
print STDERR "destroy(@_): ", ref $_[0], "\n" if DEBUG;
|
76
|
0
|
|
|
|
|
0
|
delete_package(ref $_[0]);
|
77
|
|
|
|
|
|
|
}
|
78
|
|
|
|
|
|
|
# Purpose: validate the regexp and replace "!" by "\!", and "/" by "\/"
|
79
|
|
|
|
|
|
|
# if not already escaped
|
80
|
|
|
|
|
|
|
# Arguments: a regexp
|
81
|
|
|
|
|
|
|
# Returns: the preprocessed regexp
|
82
|
|
|
|
|
|
|
sub ppregexp {
|
83
|
|
|
|
|
|
|
# my $self = $_[0]; # useless
|
84
|
19
|
|
|
19
|
1
|
1513
|
my $regexp = $_[1];
|
85
|
19
|
|
|
|
|
28
|
eval { '' =~ /$regexp/ };
|
|
19
|
|
|
|
|
235
|
|
86
|
19
|
100
|
|
|
|
62
|
if ($@) {
|
87
|
1
|
|
|
|
|
11
|
$@ =~ s/\s+at\s+[^\s]+\s+line\s+\d+[.]\n$//; # annoying info
|
88
|
1
|
|
|
|
|
199
|
Carp::croak $@;
|
89
|
|
|
|
|
|
|
}
|
90
|
18
|
|
|
|
|
35
|
for ($regexp) {
|
91
|
18
|
|
|
|
|
211
|
s{
|
92
|
|
|
|
|
|
|
( (?: \G | [^\\] ) (?: \\{2} )* ) # even number of back-slashes
|
93
|
|
|
|
|
|
|
( [!/\"] ) # used delimiters
|
94
|
|
|
|
|
|
|
}{$1\\$2}xg;
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# replace back exceptions (?!...), (?
|
97
|
18
|
|
|
|
|
69
|
s{
|
98
|
|
|
|
|
|
|
( \( \? ) # (? or (?<
|
99
|
|
|
|
|
|
|
\\ # inserted by first replace
|
100
|
|
|
|
|
|
|
( ! ) # delimiter
|
101
|
|
|
|
|
|
|
}{$1$2}xg; # remove back-slash
|
102
|
|
|
|
|
|
|
}
|
103
|
18
|
|
|
|
|
705
|
$regexp;
|
104
|
|
|
|
|
|
|
}
|
105
|
|
|
|
|
|
|
sub getPart {
|
106
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
107
|
0
|
|
|
|
|
|
my $part = shift;
|
108
|
0
|
|
0
|
|
|
|
my $class = ref $self || $self;
|
109
|
0
|
|
|
|
|
|
my $text = '';
|
110
|
2
|
|
|
2
|
|
46
|
no strict 'refs';
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
311
|
|
111
|
0
|
0
|
|
|
|
|
unless (defined($text = ${"${class}::template"}{$part})) {
|
|
0
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
my $parent = ${"${class}::ISA"}[0]; # delegation
|
|
0
|
|
|
|
|
|
|
113
|
0
|
0
|
|
|
|
|
unless (defined $parent) {
|
114
|
0
|
|
|
|
|
|
Carp::croak("'$part' template part is not defined");
|
115
|
|
|
|
|
|
|
}
|
116
|
0
|
|
|
|
|
|
$text = $parent->getPart($part);
|
117
|
|
|
|
|
|
|
}
|
118
|
0
|
|
|
|
|
|
$text;
|
119
|
|
|
|
|
|
|
}
|
120
|
|
|
|
|
|
|
sub setPart {
|
121
|
0
|
|
|
0
|
1
|
|
my $self = shift;
|
122
|
0
|
|
|
|
|
|
my $part = shift;
|
123
|
0
|
|
0
|
|
|
|
my $class = ref $self || $self;
|
124
|
2
|
|
|
2
|
|
11
|
no strict 'refs';
|
|
2
|
|
|
|
|
15
|
|
|
2
|
|
|
|
|
932
|
|
125
|
0
|
|
|
|
|
|
${"${class}::template"}{$part} = shift;
|
|
0
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
}
|
127
|
|
|
|
|
|
|
$Parse::Template::CONFESS = 1;
|
128
|
|
|
|
|
|
|
my $Already_shown = 0;
|
129
|
|
|
|
|
|
|
my $__DIE__ = sub {
|
130
|
|
|
|
|
|
|
if (not($Parse::Template::CONFESS) and $Already_shown) {
|
131
|
|
|
|
|
|
|
# Reset when the eval() processing is finished
|
132
|
|
|
|
|
|
|
$Already_shown = 0 if defined($^S);
|
133
|
|
|
|
|
|
|
return;
|
134
|
|
|
|
|
|
|
}
|
135
|
|
|
|
|
|
|
# evaluated expressions are not always available in (caller(1))[6];
|
136
|
|
|
|
|
|
|
if (defined($1) and $1 ne '') {
|
137
|
|
|
|
|
|
|
my $expr = $1; # what is the template expression?
|
138
|
|
|
|
|
|
|
{ package DB; # what is the part name?
|
139
|
|
|
|
|
|
|
@DB::caller = caller(1);
|
140
|
|
|
|
|
|
|
@DB::caller = caller(2) unless @DB::args;
|
141
|
|
|
|
|
|
|
};
|
142
|
|
|
|
|
|
|
#local $1;
|
143
|
|
|
|
|
|
|
$expr =~ s/package\s+${PACKAGE}::\w+\s*;//o;
|
144
|
|
|
|
|
|
|
my $line = 0;
|
145
|
|
|
|
|
|
|
$expr =~ s/^/sprintf "%2s ", ++$line/egm;
|
146
|
|
|
|
|
|
|
$expr =~ s/\n;$//;
|
147
|
|
|
|
|
|
|
my $part = defined $DB::args[1] ? $DB::args[1] : '';
|
148
|
|
|
|
|
|
|
if ($Already_shown) {
|
149
|
|
|
|
|
|
|
print STDERR "call from part '$part':\n$expr\n";
|
150
|
|
|
|
|
|
|
} else {
|
151
|
|
|
|
|
|
|
print STDERR "Error in part '$part':\n$expr\n";
|
152
|
|
|
|
|
|
|
}
|
153
|
|
|
|
|
|
|
}
|
154
|
|
|
|
|
|
|
else {
|
155
|
|
|
|
|
|
|
print STDERR "\$1 not defined";
|
156
|
|
|
|
|
|
|
}
|
157
|
|
|
|
|
|
|
print STDERR "\$1: $1\n";
|
158
|
|
|
|
|
|
|
# ignore Already_shown if you won't confess your exception
|
159
|
|
|
|
|
|
|
$Already_shown = 1 unless $Parse::Template::CONFESS;
|
160
|
|
|
|
|
|
|
};
|
161
|
|
|
|
|
|
|
$Parse::Template::SIG{__WARN__} = sub { # don't know how to suppress this:
|
162
|
|
|
|
|
|
|
print STDERR "$_[0]"
|
163
|
|
|
|
|
|
|
unless ($_[0] =~ /^Use of uninitialized value in substitution iterator/)
|
164
|
|
|
|
|
|
|
};
|
165
|
|
|
|
|
|
|
|
166
|
2
|
|
|
2
|
|
12
|
use constant EVAL_TRACE => 0;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
103
|
|
167
|
2
|
|
|
2
|
|
12
|
use constant SHOW_PART => 0;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
95
|
|
168
|
2
|
|
|
2
|
|
11
|
use constant SIGN_PART => 0;
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
990
|
|
169
|
|
|
|
|
|
|
$Parse::Template::SIGN_START = "# Template %s {\n"; # not documented
|
170
|
|
|
|
|
|
|
$Parse::Template::SIGN_END = "# } Template %s\n"; # not documented
|
171
|
|
|
|
|
|
|
my $indent = 0;
|
172
|
|
|
|
|
|
|
my @part = ();
|
173
|
|
|
|
|
|
|
sub eval {
|
174
|
0
|
|
|
0
|
1
|
|
print STDERR do {
|
175
|
|
|
|
|
|
|
local $" = q!', '! ; '..' x ++$indent, "=>eval('@_')\n"
|
176
|
|
|
|
|
|
|
} if EVAL_TRACE;
|
177
|
0
|
|
|
|
|
|
my $self = shift;
|
178
|
0
|
|
|
|
|
|
my $part = shift; # can't declare $part in eval()
|
179
|
0
|
|
|
|
|
|
push @part, $part;
|
180
|
0
|
|
0
|
|
|
|
my $class = ref $self || $self;
|
181
|
0
|
|
|
|
|
|
my $text = $self->getPart($part);
|
182
|
0
|
|
|
|
|
|
print STDERR qq!$part content: $text\n! if SHOW_PART;
|
183
|
0
|
|
|
|
|
|
if (SIGN_PART) { # not documented
|
184
|
|
|
|
|
|
|
$text =~ s!^!sprintf $Parse::Template::SIGN_START, $part!e;
|
185
|
|
|
|
|
|
|
$text =~ s!$!sprintf $Parse::Template::SIGN_END, $part!e;
|
186
|
|
|
|
|
|
|
}
|
187
|
0
|
|
|
|
|
|
local $SIG{__DIE__} = $__DIE__;
|
188
|
|
|
|
|
|
|
# eval expression in class
|
189
|
0
|
|
|
|
|
|
$text =~ s( %% (.*?) %% ){ # the magical substitution
|
190
|
0
|
|
|
|
|
|
print STDERR '..' x $indent, "Eval part name: $part\n" if EVAL_TRACE;
|
191
|
0
|
|
|
|
|
|
print STDERR '..' x $indent, " expr: package $class;\n$1\n" if EVAL_TRACE;
|
192
|
0
|
|
|
|
|
|
"package $class; $1";
|
193
|
|
|
|
|
|
|
}eegsx;
|
194
|
0
|
|
|
|
|
|
print STDERR "after: $class - $1\n" if EVAL_TRACE;
|
195
|
0
|
0
|
|
|
|
|
die "$@" if $@; # caught by __DIE__
|
196
|
0
|
|
|
|
|
|
pop @part; $part = $part[-1];
|
|
0
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
|
--$indent if EVAL_TRACE;
|
198
|
0
|
|
|
|
|
|
$text;
|
199
|
|
|
|
|
|
|
}
|
200
|
|
|
|
|
|
|
1;
|
201
|
|
|
|
|
|
|
__END__
|