line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::FillIn; |
2
|
1
|
|
|
1
|
|
634
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
82
|
|
3
|
1
|
|
|
1
|
|
657
|
use FileHandle; |
|
1
|
|
|
|
|
11318
|
|
|
1
|
|
|
|
|
6
|
|
4
|
1
|
|
|
1
|
|
403
|
use strict; |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
31
|
|
5
|
1
|
|
|
1
|
|
5
|
use vars qw($VERSION %DEFAULT); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1597
|
|
6
|
|
|
|
|
|
|
$VERSION = '0.05'; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# Set a bunch of defaults |
9
|
|
|
|
|
|
|
%DEFAULT = ( |
10
|
|
|
|
|
|
|
'path' => ['.'], |
11
|
|
|
|
|
|
|
'$hook' => 'find_value', |
12
|
|
|
|
|
|
|
'&hook' => 'run_function', |
13
|
|
|
|
|
|
|
'Ldelim' => '[[', |
14
|
|
|
|
|
|
|
'Rdelim' => ']]', |
15
|
|
|
|
|
|
|
'text' => '', |
16
|
|
|
|
|
|
|
'properties' => {}, |
17
|
|
|
|
|
|
|
'object' => undef, |
18
|
|
|
|
|
|
|
); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new { |
21
|
24
|
|
|
24
|
1
|
57338
|
my $package = shift; |
22
|
24
|
|
|
|
|
107
|
my $text = shift; |
23
|
|
|
|
|
|
|
|
24
|
24
|
|
|
|
|
416
|
my $self = { |
25
|
|
|
|
|
|
|
%DEFAULT, |
26
|
|
|
|
|
|
|
'text' => $text, |
27
|
|
|
|
|
|
|
}; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Copy the special structures so we don't share their memory |
30
|
24
|
|
|
|
|
53
|
$self->{'properties'} = { %{$self->{'properties'}} }; |
|
24
|
|
|
|
|
92
|
|
31
|
24
|
|
|
|
|
46
|
$self->{'path'} = [ @{$self->{'path'}} ]; |
|
24
|
|
|
|
|
84
|
|
32
|
|
|
|
|
|
|
|
33
|
24
|
|
|
|
|
229
|
return bless ($self, $package); |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub get_file { |
37
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
38
|
0
|
|
|
|
|
0
|
my $file = shift; |
39
|
|
|
|
|
|
|
|
40
|
0
|
0
|
|
|
|
0
|
if ($file eq 'null') { |
41
|
0
|
|
|
|
|
0
|
$self->{'text'} = ''; |
42
|
0
|
|
|
|
|
0
|
return; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Find out what file to open: |
46
|
0
|
|
|
|
|
0
|
my $realfile; |
47
|
0
|
0
|
|
|
|
0
|
if ($file =~ /^\//) { |
48
|
0
|
|
|
|
|
0
|
$realfile = $file; |
49
|
|
|
|
|
|
|
} else { |
50
|
0
|
|
|
|
|
0
|
foreach my $dir ($self->path()) { |
51
|
0
|
0
|
|
|
|
0
|
if ( -f "$dir/$file" ) { |
52
|
0
|
|
|
|
|
0
|
$realfile = "$dir/$file"; |
53
|
0
|
|
|
|
|
0
|
last; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
0
|
0
|
0
|
|
|
0
|
unless ($realfile and -f $realfile) { |
59
|
0
|
|
|
|
|
0
|
warn ("Can't find file '$file' in (@{[$self->path()]})"); |
|
0
|
|
|
|
|
0
|
|
60
|
0
|
|
|
|
|
0
|
return 0; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
0
|
my $fh = new FileHandle($realfile); |
64
|
0
|
0
|
|
|
|
0
|
unless ( defined $fh ) { |
65
|
0
|
|
|
|
|
0
|
warn ("Can't open $realfile: $!"); |
66
|
0
|
|
|
|
|
0
|
$self->{'text'} = ''; |
67
|
0
|
|
|
|
|
0
|
return 0; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
0
|
|
|
|
|
0
|
$self->{'text'} = join('', $fh->getlines ); |
71
|
0
|
|
|
|
|
0
|
return 1; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
113
|
|
|
113
|
1
|
134
|
sub Ldelim { my $s = shift; $s->_prop('Ldelim', @_) } |
|
113
|
|
|
|
|
250
|
|
75
|
112
|
|
|
112
|
1
|
171
|
sub Rdelim { my $s = shift; $s->_prop('Rdelim', @_) } |
|
112
|
|
|
|
|
217
|
|
76
|
0
|
|
|
0
|
1
|
0
|
sub text { my $s = shift; $s->_prop('text', @_) } |
|
0
|
|
|
|
|
0
|
|
77
|
39
|
|
|
39
|
1
|
133
|
sub object { my $s = shift; $s->_prop('object', @_) } |
|
39
|
|
|
|
|
254
|
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub hook { |
80
|
38
|
|
|
38
|
1
|
103
|
my $self = shift; |
81
|
38
|
|
|
|
|
48
|
my $char = shift; |
82
|
38
|
|
|
|
|
193
|
return $self->_prop($char.'hook', @_); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub path { |
86
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
87
|
0
|
0
|
|
|
|
0
|
return @{ (@_ ? $self->_prop('path', [@_]) : $self->_prop('path')) }; |
|
0
|
|
|
|
|
0
|
|
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub property { |
91
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
92
|
0
|
|
|
|
|
0
|
my $prop = shift; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Which SV we should get or set - this object only, or the default |
95
|
0
|
0
|
|
|
|
0
|
my $get_set = (ref $self ? \($self->{'properties'}{$prop}) : \($DEFAULT{'properties'}{$prop})); |
96
|
|
|
|
|
|
|
|
97
|
0
|
0
|
|
|
|
0
|
if (@_) { |
98
|
|
|
|
|
|
|
# Set the property |
99
|
0
|
|
|
|
|
0
|
$$get_set = shift; |
100
|
|
|
|
|
|
|
} |
101
|
0
|
|
|
|
|
0
|
return $$get_set; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub interpret { |
106
|
14
|
|
|
14
|
1
|
37
|
my $self = shift; |
107
|
14
|
|
|
|
|
186
|
$self->_interpret_engine('collect'); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub interpret_and_print { |
111
|
10
|
|
|
10
|
1
|
3611
|
my $self = shift; |
112
|
10
|
|
|
|
|
29
|
$self->_interpret_engine('print'); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# Deprecated - use text() |
116
|
|
|
|
|
|
|
sub set_text { |
117
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
118
|
0
|
|
|
|
|
0
|
my $text = shift; |
119
|
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
0
|
$self->{'text'} = $text; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Deprecated - use text() |
124
|
|
|
|
|
|
|
sub get_text { |
125
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
126
|
|
|
|
|
|
|
|
127
|
0
|
|
|
|
|
0
|
return $self->{'text'}; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# Deprecated - use property() |
131
|
|
|
|
|
|
|
sub get_property { |
132
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
133
|
0
|
|
|
|
|
0
|
my $prop_name = shift; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
0
|
return $self->{'properties'}->{$prop_name}; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Deprecated - use property() |
139
|
|
|
|
|
|
|
sub set_property { |
140
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
141
|
0
|
|
|
|
|
0
|
my $prop_name = shift; |
142
|
0
|
|
|
|
|
0
|
my $prop_val = shift; |
143
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
0
|
$self->{'properties'}->{$prop_name} = $prop_val; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
############################# Private functions |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub _prop { |
152
|
302
|
|
|
302
|
|
326
|
my $self = shift; |
153
|
302
|
|
|
|
|
364
|
my $prop = shift; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Which SV we should get or set - this object only, or the default |
156
|
302
|
100
|
|
|
|
901
|
my $get_set = (ref $self ? \($self->{$prop}) : \($DEFAULT{$prop})); |
157
|
|
|
|
|
|
|
|
158
|
302
|
100
|
|
|
|
713
|
if (@_) { |
159
|
|
|
|
|
|
|
# Set the property |
160
|
6
|
|
|
|
|
20
|
$$get_set = shift; |
161
|
|
|
|
|
|
|
} |
162
|
302
|
|
|
|
|
1212
|
return $$get_set; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _deal_with { |
166
|
48
|
|
|
48
|
|
107
|
my ($text, $style, $outref) = @_; |
167
|
48
|
100
|
|
|
|
138
|
if ($style eq 'print') { |
|
|
50
|
|
|
|
|
|
168
|
20
|
|
|
|
|
119
|
print $text; |
169
|
|
|
|
|
|
|
} elsif ($style eq 'collect') { |
170
|
28
|
|
|
|
|
42
|
${$outref} .= $text; |
|
28
|
|
|
|
|
72
|
|
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub _interpret_engine { |
175
|
|
|
|
|
|
|
|
176
|
24
|
|
|
24
|
|
36
|
my $self = shift; |
177
|
24
|
|
|
|
|
62
|
my $style = shift; |
178
|
24
|
|
|
|
|
28
|
my ($first_right, $first_left, $last_left, $out_text, $save); |
179
|
24
|
|
|
|
|
34
|
my $debug = 0; |
180
|
24
|
|
|
|
|
81
|
my $text = $self->{'text'}; # Duplicates memory, I'll clean up later |
181
|
|
|
|
|
|
|
|
182
|
24
|
|
|
|
|
61
|
my ($ld, $rd) = ($self->Ldelim(), $self->Rdelim()); |
183
|
24
|
50
|
|
|
|
58
|
warn "Delimiters are $ld and $rd" if $debug; |
184
|
|
|
|
|
|
|
|
185
|
24
|
|
|
|
|
31
|
while (1) { |
186
|
|
|
|
|
|
|
|
187
|
86
|
50
|
|
|
|
344
|
warn ("interpreting '$text'") if $debug; |
188
|
|
|
|
|
|
|
# Shave off any leading plain text before the first real [[ |
189
|
86
|
|
|
|
|
89
|
my ($prelength, $pretext); |
190
|
86
|
|
|
|
|
190
|
$first_left = &_real_index($text, $ld); |
191
|
86
|
50
|
|
|
|
267
|
warn ("first left is at $first_left") if $debug; |
192
|
86
|
100
|
|
|
|
572
|
if ( $first_left == -1 ) { |
|
|
100
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# No more to do, just spit out the text |
194
|
24
|
|
|
|
|
67
|
$self->_unquote(\$text); |
195
|
24
|
|
|
|
|
90
|
&_deal_with($text, $style, \$out_text); |
196
|
24
|
|
|
|
|
49
|
last; |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
} elsif ($first_left > 0) { # There's a real [[ here |
199
|
24
|
|
|
|
|
77
|
$pretext = substr($text, 0, $first_left); |
200
|
24
|
|
|
|
|
69
|
$self->_unquote(\$pretext); |
201
|
24
|
|
|
|
|
169
|
&_deal_with($pretext, $style, \$out_text); |
202
|
24
|
|
|
|
|
54
|
substr($text, 0, $first_left) = ''; |
203
|
24
|
|
|
|
|
46
|
next; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# There's now a real [[ at position 0. |
207
|
|
|
|
|
|
|
# Find the first right delimiter and fill in before it: |
208
|
38
|
|
|
|
|
71
|
$first_right = &_real_index($text, $rd); |
209
|
38
|
50
|
|
|
|
88
|
warn ("first right is at $first_right") if $debug; |
210
|
38
|
|
|
|
|
143
|
$last_left = &_real_index(substr($text, 0, $first_right), $ld, 1); |
211
|
38
|
50
|
|
|
|
98
|
warn ("last left is at $last_left") if $debug; |
212
|
|
|
|
|
|
|
|
213
|
38
|
50
|
|
|
|
86
|
if ($first_right == -1) { # Something's amiss, abort |
214
|
0
|
|
|
|
|
0
|
warn ("Problem interpreting text " . substr($text, 0, $first_right)); |
215
|
0
|
|
|
|
|
0
|
&_deal_with($text, $style, \$out_text); |
216
|
0
|
|
|
|
|
0
|
last; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
# Fill in the text in between the first right delimiter and the last left delimiter before it: |
219
|
38
|
|
|
|
|
173
|
substr($text, $last_left, $first_right - $last_left + length($rd)) = |
220
|
|
|
|
|
|
|
$self->_do_interpret(substr($text, $last_left, $first_right - $last_left + length($rd))); |
221
|
|
|
|
|
|
|
} |
222
|
24
|
|
|
|
|
374
|
return $out_text; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub _real_index { |
226
|
|
|
|
|
|
|
# Finds the first occurrence of $exp in $text before |
227
|
|
|
|
|
|
|
# position $before that doesn't follow a backslash |
228
|
|
|
|
|
|
|
|
229
|
162
|
|
|
162
|
|
325
|
my $text = shift; |
230
|
162
|
|
|
|
|
318
|
my $exp = shift; |
231
|
162
|
|
|
|
|
179
|
my $last = shift; |
232
|
|
|
|
|
|
|
|
233
|
162
|
100
|
|
|
|
324
|
if ($last) { |
234
|
38
|
50
|
|
|
|
436
|
if ($text =~ / (.*)(^|[^\\]) \Q$exp/sx) { |
235
|
38
|
|
|
|
|
116
|
return(length($1) + length($2)); |
236
|
|
|
|
|
|
|
} else { |
237
|
0
|
|
|
|
|
0
|
return -1; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
} else { |
240
|
124
|
100
|
|
|
|
3118
|
if ($text =~ / (.*?)(^|[^\\]) \Q$exp/sx) { |
241
|
100
|
|
|
|
|
970
|
return (length($1) + length($2)); |
242
|
|
|
|
|
|
|
} else { |
243
|
24
|
|
|
|
|
55
|
return -1; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub _unquote { |
249
|
48
|
|
|
48
|
|
55
|
my $self = shift; |
250
|
48
|
|
|
|
|
54
|
my $textref = shift; |
251
|
|
|
|
|
|
|
|
252
|
48
|
|
|
|
|
103
|
my ($ldx, $rdx) = map {quotemeta} ($self->Ldelim(), $self->Rdelim()); |
|
96
|
|
|
|
|
266
|
|
253
|
48
|
|
|
|
|
66
|
${$textref} =~ s/ \\( $ldx | $rdx ) /$1/xgs; |
|
48
|
|
|
|
|
414
|
|
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub _do_interpret { |
257
|
38
|
|
|
38
|
|
51
|
my $self = shift; |
258
|
38
|
|
|
|
|
93
|
my $string = shift; |
259
|
|
|
|
|
|
|
|
260
|
38
|
|
|
|
|
80
|
my ($ldx, $rdx) = map {quotemeta} ($self->Ldelim(), $self->Rdelim()); |
|
76
|
|
|
|
|
211
|
|
261
|
|
|
|
|
|
|
|
262
|
38
|
50
|
|
|
|
463
|
unless ($string =~ /^ $ldx \s* ([\W]) (.*?) \s* $rdx $/sx ) { |
263
|
|
|
|
|
|
|
# Looks like we weren't meant to see this - but we can't interpret it again either |
264
|
0
|
|
|
|
|
0
|
carp ("Can't interpret template chunk '$string'"); |
265
|
0
|
|
|
|
|
0
|
return; |
266
|
|
|
|
|
|
|
} |
267
|
38
|
|
|
|
|
91
|
my ($char, $guts) = ($1, $2); |
268
|
|
|
|
|
|
|
|
269
|
38
|
|
|
|
|
50
|
my ($hook, $object); |
270
|
38
|
50
|
|
|
|
109
|
if (defined ($hook = $self->hook($char))) { |
271
|
1
|
|
|
1
|
|
6
|
no strict('refs'); # Allow symbolic name substitution for a little while |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
210
|
|
272
|
38
|
100
|
|
|
|
98
|
if (defined ($object = $self->object())) { |
273
|
1
|
|
|
|
|
6
|
return $object->$hook($guts, $char); |
274
|
|
|
|
|
|
|
} else { |
275
|
37
|
|
|
|
|
45
|
return &{$hook}($guts, $char); |
|
37
|
|
|
|
|
149
|
|
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
} else { |
278
|
0
|
|
|
|
|
0
|
croak ("No interpret hook defined for type '$1'"); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
############################ Sample hook functions ########################## |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
|
286
|
31
|
|
|
31
|
0
|
256
|
sub find_value { $main::TVars{ $_[0] } } |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub run_function { |
289
|
|
|
|
|
|
|
# Usage: $result = &run_function("some_function(param1,param2,param3)"); |
290
|
6
|
|
|
6
|
0
|
14
|
my $text = shift; |
291
|
6
|
50
|
|
|
|
76
|
my ($function_name, $args) = $text =~ /(\w+)\((.*)\)/ |
292
|
|
|
|
|
|
|
or die ("Can't understand function call '$text'"); |
293
|
1
|
|
|
1
|
|
5
|
no strict('refs'); # Allow symbolic name substitution for a little while |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
89
|
|
294
|
6
|
|
|
|
|
23
|
return &{"TExport::$function_name"}( split(/,/, $args) ); |
|
6
|
|
|
|
|
46
|
|
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
1; |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
__END__ |