File Coverage

blib/lib/HTML/YaTmpl.pm
Criterion Covered Total %
statement 484 526 92.0
branch 216 298 72.4
condition 63 101 62.3
subroutine 47 48 97.9
pod 10 10 100.0
total 820 983 83.4


line stmt bran cond sub pod time code
1             package HTML::YaTmpl;
2 7     7   166149 use strict;
  7         19  
  7         238  
3 7     7   36 use warnings;
  7         14  
  7         269  
4 7     7   37 no warnings 'uninitialized';
  7         16  
  7         269  
5 7     7   3061 use HTML::YaTmpl::_parse;
  7         63  
  7         329  
6 7         127 use Class::Member::HASH qw{template file path package _extra errors onerror
7             eprefix no_eval_cache no_parse_cache _macros
8             compress debug
9 7     7   5695 -CLASS_MEMBERS};
  7         6518  
10 7     7   1314 use Config ();
  7         13  
  7         166  
11 7     7   5935 use IO::File ();
  7         90443  
  7         262  
12 7     7   61 use File::Spec ();
  7         22  
  7         183  
13 7     7   5711 use Errno ();
  7         8660  
  7         214  
14 7     7   21754 use Compress::Zlib ();
  7         520751  
  7         39696  
15              
16             our $VERSION='1.8';
17             our @CLASS_MEMBERS;
18              
19             #$SIG{INT}=sub {
20             # use Carp 'cluck';
21             # cluck "SIGINT\n";
22             #};
23              
24             sub clear_errors {
25 4     4 1 1985 my $rc=$_[0]->errors;
26 4         53 $_[0]->errors=[];
27 4         91 return @{$rc};
  4         16  
28             }
29              
30             sub _report_error {
31 3     3   9 my $I=shift;
32 3         120 my $eval=shift;
33 3 50       12 my $x=join( ' ', 'ERROR', length $I->eprefix?$I->eprefix:() ).' ';
34 3 50       35 if( length( $eval ) ) {
35 3 50       91 if( $@=~/\bline \d+\b/ ) {
36 0         0 my $nr=2;
37 0         0 $eval=~s/\n/sprintf "\n%04d: ", $nr++/ge;
  0         0  
38 0         0 $x.="while eval( \n0001: $eval\n): ";
39             } else {
40 2         7 $x.="while eval( $eval ): ";
41             }
42             } else {
43 0         0 $x.=": ";
44             }
45 2   33     6 $x.=shift || $@;
46              
47 2         2 push @{$I->errors}, $x;
  2         8  
48 2 50       25 die $x."\n" if( $I->onerror eq 'die' );
49 0 0       0 return $x if( $I->onerror eq 'output' );
50 0 0       0 return $I->onerror->( $x ) if( ref($I->onerror) eq 'CODE' );
51 0 0       0 warn $x if( $I->onerror eq 'warn' );
52 0         0 return '';
53             }
54              
55             sub new {
56 8     9 1 3000511 my $parent=shift;
57 8   33     77 my $class=ref($parent) || $parent;
58 8         37 my $I=bless {}=>$class;
59 8         46 my %o=@_;
60              
61 8 50       121 if( ref($parent) ) {
62 0         0 foreach my $m (@CLASS_MEMBERS) {
63 0         0 $I->$m=$parent->$m;
64             }
65             } else {
66 8 50       51 if( exists $ENV{HTML_TMPL_SEARCH_PATH} ) {
67 0   0     0 my $sep=$Config{path_sep} || ':';
68 0         0 $I->path=[split $sep, $ENV{HTML_TMPL_SEARCH_PATH}];
69             }
70             }
71 8         85 $I->package=(caller)[0];
72 8         268 $I->errors=[];
73 8         111 foreach my $m (@CLASS_MEMBERS) {
74 104 100       1808 $I->$m=$o{$m} if( exists $o{$m} );
75             }
76              
77 8 100       43 length $I->file and return $I->open;
78              
79 7         118 return $I;
80             }
81              
82             sub open {
83 9     9 1 33 my $I=shift;
84 9         19 my %o=@_;
85              
86 9 50       30 $I->file=$o{file} if( exists $o{file} );
87 9 50       29 $I->path=$o{path} if( exists $o{path} );
88 9         27 local *F;
89 9         35 local $/;
90 9 100       28 if( -d $I->file ) {
91 1 50 0     37 (exists($!{EISDIR}) and $!=&Errno::EISDIR) or
      33        
92             (exists($!{EACCES}) and $!=&Errno::EACCES);
93 1         22 return;
94             }
95 8 100 33     216 open F, '<'.$I->file or do {
96 8         262 my $rc=0;
97 8 50       32 unless( File::Spec->file_name_is_absolute( $I->file ) ) {
98 8 50       157 foreach my $el (@{$I->path||[]}) {
  8         31  
99 8 50       110 next unless( length $el );
100 8         57 $el=~s!/*$!!; # strip trailing slash if any
101 8         25 my $f=File::Spec->catfile( $el, $I->file );
102 8 50       601 if( -d $f ) {
    100          
103 0 0 0     0 (exists($!{EISDIR}) and $!=&Errno::EISDIR) or
      0        
104             (exists($!{EACCES}) and $!=&Errno::EACCES);
105 0         0 last;
106             } elsif( open F, '<'.$f ) {
107 7         11 $rc=1;
108 7         17 last;
109             }
110             }
111             }
112 8         32 $rc;
113             } or return;
114              
115 7         28 $I->template=;
116 7         299 close F;
117 7 50       22 return unless( defined $I->template );
118 7         121 return $I;
119             }
120              
121             sub _param {
122 254     254   338 my $name=shift;
123 254         260 my $el=shift;
124              
125 254         279 foreach my $p (reverse @{$el->[2]}) {
  254         514  
126 157 100 100     1154 return $p->[1] if( ref $p eq 'ARRAY' and lc($p->[0]) eq $name );
127             }
128 200         372 return;
129             }
130              
131             sub _fill_in {
132 115     115   184 my $I=shift;
133 115         140 my $v=shift;
134 115         129 my $clist=shift;
135 115         139 my $first=shift;
136 115         137 my $last=shift;
137 115         129 my $pre=shift;
138 115         131 my $post=shift;
139 115         138 my $gsm=shift;
140 115         122 my $h=shift;
141              
142 115         137 my @list=@{$v};
  115         350  
143 115         157 foreach my $e (@{$gsm}) {
  115         233  
144 20 50       61 if( length( $e->[1] ) ) {
145 20 100       87 if( $e->[0] eq 'grep' ) {
    100          
    50          
146 7         27 my $x=('sub { package '.$I->package.';use strict;'.$e->[1].'}');
147 7         107 $x=$I->__insert_ecache( $x, $e->[1], 1 );
148 7 50       223 @list=grep( &$x, @list ) if( ref($x) eq 'CODE' );
149             } elsif( $e->[0] eq 'map' ) {
150 7         22 my $x=('sub { package '.$I->package.';use strict;'.$e->[1].'}');
151 7         103 $x=$I->__insert_ecache( $x, $e->[1], 1 );
152 7 50       199 @list=map( &$x, @list ) if( ref($x) eq 'CODE' );
153             } elsif( $e->[0] eq 'sort' ) {
154 6         13 my $x=('sub { use strict;'.$e->[1].'}');
155 6         15 $x=$I->__insert_ecache( $x, $e->[1], 1 );
156 6 50       212 @list=sort( $x @list ) if( ref($x) eq 'CODE' );
157             }
158             }
159             }
160              
161 115         142 my @res;
162 115 100       144 push @res, $I->_eval_list( undef, $h, @{$pre} ) if( @{$pre} );
  19         74  
  115         304  
163 115 100       278 if( @list>=1 ) {
164 112         158 push @res, $I->_eval_list( $list[0], $h, @{$first} );
  112         310  
165             }
166 115 100       274 if( @list ) {
167 112         338 for( my $i=1; $i<@list-1; $i++ ) {
168 195         275 push @res, $I->_eval_list( $list[$i], $h, @{$clist} );
  195         498  
169             }
170             } else {
171 3         7 push @res, $I->_eval_list( undef, $h, @{$clist} );
  3         10  
172             }
173 115 100       306 if( @list>=2 ) {
174 111         181 push @res, $I->_eval_list( $list[$#list], $h, @{$last} );
  111         263  
175             }
176 115 100       172 push @res, $I->_eval_list( undef, $h, @{$post} ) if( @{$post} );
  19         56  
  115         276  
177 115         636 return \@res;
178             }
179              
180             sub _eval_var {
181 220     220   263 my $I=shift;
182 220         228 my $el=shift;
183 220         248 my $h=shift;
184              
185 220         397 local $_;
186 220         462 my $type=_param( type=>$el );
187 220         286 my $given=0;
188 220 100       536 if( length $type ) {
189 39         57 $type=lc $type;
190 39         52 my $found=0;
191 39         164 foreach my $t (split /\s*,\s*/, $type) {
192 44 100       164 if( $t eq 'empty' ) {
    100          
    100          
    50          
193 6         45 $found++ if( !exists $h->{$el->[1]} or
194             (ref( $h->{$el->[1]} ) eq 'ARRAY' and
195 12 100 100     101 @{$h->{$el->[1]}}==0) or
      66        
      100        
196             length( "$h->{$el->[1]}" )==0 );
197             } elsif( $t eq 'given' ) {
198             $found++ if( exists $h->{$el->[1]} and
199             ((ref( $h->{$el->[1]} ) eq 'ARRAY' and
200 4 100 66     43 @{$h->{$el->[1]}}>0) or
      33        
201             (ref( $h->{$el->[1]} ) ne 'ARRAY' and
202             length "$h->{$el->[1]}")) );
203 4         10 $given++;
204             } elsif( $t eq 'array' ) {
205 15         90 $found++ if( exists $h->{$el->[1]} and
206             ref( $h->{$el->[1]} ) eq 'ARRAY' and
207 20 100 100     206 @{$h->{$el->[1]}}>0 );
      100        
208             } elsif( $t eq 'scalar' ) {
209 8 100 66     80 $found++ if( exists $h->{$el->[1]} and
      66        
210             ref( $h->{$el->[1]} ) ne 'ARRAY' and
211             length "$h->{$el->[1]}" );
212             }
213             }
214 39 100       134 return '' unless( $found );
215             }
216              
217 202 100       446 unless( defined $el->[3] ) {
218 34         68 my $code=_param( code=>$el );
219 34 100       71 if( length $code ) {
220 15         28 $el->[3]=$code;
221             } else {
222 19         41 $el->[3]='<:/>';
223             }
224             }
225              
226 202         229 my (@clist, @first, @last, @pre, @post, @gsm); # gsm stands for grep/sort/map
227 202         253 foreach my $p (@{$el->[2]}) {
  202         461  
228 94 100       314 if( ref($p) eq 'ARRAY' ) {
229 91 50       216 $p->[1]='' unless( defined $p->[1] );
230 91 100       242 @first=$I->_parse_cached( $p->[1] ) if( lc($p->[0]) eq 'first' );
231 91 100       220 @last=$I->_parse_cached( $p->[1] ) if( lc($p->[0]) eq 'last' );
232 91 100       242 @pre=$I->_parse_cached( $p->[1] ) if( lc($p->[0]) eq 'pre' );
233 91 100       245 @post=$I->_parse_cached( $p->[1] ) if( lc($p->[0]) eq 'post' );
234 91 100 100     785 push @gsm, [lc($p->[0])=>$p->[1]]
      100        
235             if( lc($p->[0]) eq 'grep' or
236             lc($p->[0]) eq 'map' or
237             lc($p->[0]) eq 'sort' );
238             }
239             }
240              
241 202         256 my @code;
242             @clist=map {
243 202 100       720 if( $_->[0] eq ':' ) {
  464 50       980  
244 229 100 66     2351 if( lc($_->[1]) eq 'first' ) {
    100 100        
    100          
    100          
    100          
    100          
245 1 50       7 @first=$I->_parse_cached( defined $_->[3]?$_->[3]:'' );
246 1         3 ();
247             } elsif( lc($_->[1]) eq 'last' ) {
248 6 50       24 @last=$I->_parse_cached( defined $_->[3]?$_->[3]:'' );
249 6         13 ();
250             } elsif( lc($_->[1]) eq 'pre' ) {
251 6 50       28 @pre=$I->_parse_cached( defined $_->[3]?$_->[3]:'' );
252 6         18 ();
253             } elsif( lc($_->[1]) eq 'post' ) {
254 6 50       34 @post=$I->_parse_cached( defined $_->[3]?$_->[3]:'' );
255 6         16 ();
256             } elsif( lc($_->[1]) eq 'code' ) {
257 13 50       57 @code=$I->_parse_cached( defined $_->[3]?$_->[3]:'' );
258 13         26 ();
259             } elsif( lc($_->[1]) eq 'grep' or
260             lc($_->[1]) eq 'sort' or
261             lc($_->[1]) eq 'map' ) {
262 2 50       9 push @gsm, [lc($_->[1])=>(defined $_->[3]?$_->[3]:'')];
263 2         4 ();
264             } else {
265 195         428 $_;
266             }
267             } else {
268 235         514 $_;
269             }
270             } $I->_parse_cached( defined $el->[3] ? $el->[3] : '' );
271              
272 202 100       557 @clist=@code if( @code );
273 202 100       6469 @first=@clist unless( @first );
274 202 100       488 @last=@clist unless( @last );
275              
276 202 100 100     1019 if( $given or ref($h->{$el->[1]}) ne 'ARRAY' ) {
277 87         283 return $I->_eval_list( $h->{$el->[1]}, $h, @clist );
278             } else {
279 115         514 return $I->_fill_in( $h->{$el->[1]},
280             \@clist, \@first, \@last, \@pre, \@post, \@gsm,
281             $h );
282             }
283             }
284              
285             { my %ecache;
286             my %pcache;
287             my $hwm=10000;
288             my $lwm=5000;
289              
290             sub clear_cache {
291 0     0 1 0 %ecache=();
292 0         0 %pcache=();
293             }
294              
295             sub cache_highwatermark :lvalue {
296 1     1 1 11 $hwm=pop;
297 1         9 $hwm;
298             }
299              
300             sub cache_lowwatermark :lvalue {
301 1     1 1 6 $lwm=pop;
302 1         3 $lwm;
303             }
304              
305             sub cache_sizes {
306 2     2 1 18 (scalar keys %ecache, scalar keys %pcache);
307             }
308              
309             sub __insert_ecache {
310 183     183   579 my ($self, $x, $eval, $noerroroutput)=@_;
311              
312 183 50       437 if( $self->no_eval_cache ) {
313 0         0 my $rc=eval $x;
314 0 0       0 if( $@ ) {
315 0         0 $rc=$self->_report_error( $eval );
316 0 0       0 return if( $noerroroutput );
317             }
318 0         0 return $rc;
319             } else {
320 183 100       2220 unless( defined $ecache{$x} ) {
321 50 100       149 if( scalar keys %ecache >= $hwm ) {
322 1         2 local $_;
323 3         21 my @l=sort {$a->[1] <=> $b->[1]}
  3         9  
324 1         2 map {[$_, $ecache{$_}->[1]]}
325             keys %ecache;
326 1         4 delete @ecache{map {$_->[0]} @l[0 .. $hwm-$lwm-1]};
  2         15  
327             }
328 50     4   3864 $ecache{$x}=[eval( $x ), 0];
  4     4   34  
  4     4   5  
  4     4   370  
  4     2   30  
  4     2   9  
  4     2   288  
  4     2   30  
  4     2   10  
  4     2   335  
  4     2   29  
  4     2   8  
  4     2   306  
  2     2   13  
  2     2   6  
  2         156  
  2         13  
  2         3  
  2         139  
  2         13  
  2         4  
  2         156  
  2         13  
  2         7  
  2         123  
  2         12  
  2         4  
  2         122  
  2         18  
  2         4  
  2         179  
  2         15  
  2         4  
  2         151  
  2         11  
  2         2  
  2         110  
  2         14  
  2         4  
  2         86  
  2         15  
  2         3  
  2         119  
  2         17  
  2         5  
  2         153  
329 50 50       190 if( $@ ) {
330 0         0 my $rc=$self->_report_error( $eval );
331 0 0       0 return $noerroroutput ? undef : $rc;
332             }
333             }
334              
335 183         408 $ecache{$x}->[1]=time;
336 183         476 return $ecache{$x}->[0];
337             }
338             }
339              
340             sub __eval_cached {
341 193     193   363 my ($self, $eval, $v, $h, $noerroroutput)=@_;
342              
343 193 50       527 if( $self->no_eval_cache ) {
344 30         1526 my $p=$self->_extra;
345 465         75383 my $x=eval ('package '.$self->package.
346             ';use strict;local$_=[$v,$p,$h];do{'.$eval."\n}");
347 30 0       6659 if( $@ ) {
348 0         0 $x=$self->_report_error( $eval );
349 0 0       0 return if( $noerroroutput );
350             }
351 0         0 return $x;
352             } else {
353 163         2099 my $x=('sub {package '.$self->package.';use strict;'.
354             'my ($v,$p,$h)=@_;local $_=\@_;do{'.$eval."\n}}");
355 163         1972 my $f=$self->__insert_ecache( $x, $eval, $noerroroutput );
356 163 50       461 return $f unless( ref($f) eq 'CODE' );
357 163         223 my $rc=eval {
358 163         433 &{$f}( $v, $self->_extra, $h );
  163         5977  
359             };
360 163 50       415 if( $@ ) {
361 0         0 $rc=$self->_report_error( $eval );
362 0 0       0 return if( $noerroroutput );
363             }
364 163         711 return $rc;
365             }
366 0         0 return;
367             }
368              
369             sub _parse_cached {
370 938     938   1695 my ($I, $str)=@_;
371              
372 938 100       2247 $str=$I->template unless( defined $str );
373              
374 938 50       2889 if( $I->no_parse_cache ) {
375 0         0 return $I->_parse( $str );
376             } else {
377 938         22874 my $el=$pcache{$str};
378 938 100       1854 unless( defined $el ) {
379 241 100       545 if( scalar keys %pcache >= $hwm ) {
380 3         6 local $_;
381 7         24 my @l=sort {$a->[1] <=> $b->[1]}
  9         41  
382 3         11 map {[$_, $pcache{$_}->[1]]}
383             keys %pcache;
384 3         13 delete @pcache{map {$_->[0]} @l[0 .. $hwm-$lwm-1]};
  6         136  
385             }
386 241         744 $el=$pcache{$str}=[0, $I->_parse( $str )];
387             }
388              
389 938         1724 $el->[0]=time;
390 938         1252 return @{$el}[1..$#{$el}];
  938         3332  
  938         1725  
391             }
392             }
393             }
394              
395             sub _eval_v {
396 598     598   668 my $I=shift;
397 598         817 my $v=shift;
398 598         675 my $el=shift;
399 598         624 my $h=shift;
400              
401 598         841 my $eval;
402 598 100       1070 if( length $el->[3] ) {
  594 100       7952  
403 4         11 $eval=$el->[3];
404             } elsif( @{$el->[2]} ) {
405 124         261 $eval=substr( $el->[4], 2, -2 );
406             } else {
407 470         1815 return $v;
408             }
409              
410 128         873 $eval=~s/^\s+|\s+$//g;
411 128 50       301 if( length $eval ) {
412             #my $rc=$I->__eval_cached( $eval, $v, $h );
413             #use Data::Dumper; warn "$el->[1]: ", Dumper( $rc );
414             #return $rc;
415 128         289 return $I->__eval_cached( $eval, $v, $h );
416             }
417              
418 0         0 return '';
419             }
420              
421             sub __get_code_list {
422 99     99   133 my $I=shift;
423 99         114 my $el=shift;
424 99         110 local $_;
425              
426 99         103 my @l2;
427             my @l1=grep {
428 99 100 100     333 if( $_->[0] eq ':' and $_->[1]=~/^code$/i ) {
  300 50       1112  
429 43 50       171 push @l2, $I->_parse_cached( defined $_->[3] ? $_->[3] : '' );
430             }
431 300   100     2449 !($_->[0] eq ':' and $_->[1]=~/^(set|code)$/i);
432             } $I->_parse_cached( defined $el->[3] ? $el->[3] : '' );
433 99 100       571 return @l2?@l2:@l1;
434             }
435              
436             sub _eval_control {
437 758     758   907 my $I=shift;
438 758         859 my $v=shift;
439 758         3631 my $el=shift;
440 758         758 my $h=shift;
441              
442 758 100 100     3602 if( 0==length $el->[1] ) { # <: code />
    100          
    100          
    100          
    100          
    100          
    100          
    50          
443             #my $rc=$I->_eval_v( $v, $el, $h );
444             #use Data::Dumper; warn "$el->[1]: ", Dumper( $rc );
445             #return $rc;
446 598         1216 return $I->_eval_v( $v, $el, $h );
447             } elsif( $el->[1] eq 'include' ) {
448 8         15 my $file;
449 8         14 foreach my $f (@{$el->[2]}) {
  8         17  
450 8 50 33     48 if( !ref($f) and length($f) ) {
451 8         30 $file=$I->_eval_list( $v, $h, $I->_parse_cached($f) );
452 8         20 last;
453             }
454             }
455 8         31 my $nh=+{$I->_make_include_param_list( $v, $el, $h )};
456 8         43 my ($sv_file, $sv_eprefix, $sv_template)=
457             ($I->file, $I->eprefix, $I->template); # save
458 8         255 $I->file=$file;
459 8         97 $I->eprefix=join( ' ', $I->eprefix, "While including $file" );
460 8 100       204 defined($I->open) or do {
461 2         8 ($I->file, $I->eprefix, $I->template)=
462             ($sv_file, $sv_eprefix, $sv_template); # restore
463 2         59 return $I->_report_error( "<:include $file>", "$!" );
464             };
465              
466 6         10 my $rc=eval {
467 6 50       23 $I->_eval_list( $v, $nh, $I->_parse_cached( defined($I->template)
468             ? $I->template
469             : '' ) );
470             };
471 6         16 my $msg=$@;
472 6         11 undef $@;
473              
474 6         23 ($I->file, $I->eprefix, $I->template)=
475             ($sv_file, $sv_eprefix, $sv_template); # restore
476              
477 6 50       184 die $msg if( $msg ); # propagate
478              
479 6         32 return $rc;
480             } elsif( $el->[1] eq 'for' ) {
481 75         184 my $nh=+{$I->_make_include_param_list( $v, $el, $h )};
482             #warn "FOR FOR FOR: ";
483             #use Data::Dumper; warn Dumper($nh);
484 75         216 return $I->_eval_list( $v, $nh, $I->__get_code_list($el) );
485             } elsif( $el->[1] eq 'm' or $el->[1] eq 'macro' ) { # invoke macro
486 48         48 my $macro;
487 48         50 foreach my $f (@{$el->[2]}) {
  48         82  
488 48 50 33     188 if( !ref($f) and length($f) ) {
489 48         128 $macro=$I->_eval_list( $v, $h, $I->_parse_cached($f) );
490 48         83 last;
491             }
492             }
493 48 50       115 unless( exists $I->_macros->{$macro} ) {
494 0         0 return $I->_report_error( "<:macro $macro>", "Macro not defined" );
495             }
496 48         583 $macro=$I->_macros->{$macro};
497 48         495 my $nh=+{$I->_make_include_param_list( $v, $el, $h )};
498             #warn "M M M: ";
499             #use Data::Dumper; warn Dumper($nh);
500 48         65 return $I->_eval_list( $v, $nh, @{$macro} );
  48         125  
501             } elsif( $el->[1] eq 'eval' ) {
502 4         11 my $nh=+{$I->_make_include_param_list( $v, $el, $h )};
503 4         17 my $new_tmpl=$I->_eval_list( $v, $nh, $I->__get_code_list($el) );
504             #warn "new_tmpl: $new_tmpl\n";
505             #use Data::Dumper; warn Dumper($nh);
506 4 50       20 return $I->_eval_list( $v, $h, $I->_parse_cached( defined $new_tmpl
507             ? $new_tmpl
508             : '' ) );
509             } elsif( $el->[1] eq 'cond' ) {
510 18         28 my $vdecl='';
511 18         27 foreach my $x (@{$el->[2]}) {
  18         52  
512 2 50       7 unless( ref($x) ) {
513 2         9 $vdecl.=q{my $}.$x.q(=$_->[2]->{').$x.q('}; );
514             }
515             }
516 18 50       68 foreach my $c ($I->_parse_cached( defined $el->[3] ? $el->[3] : '' )) {
517 70 50 33     303 if( $c->[0] eq ':' and
      66        
518             ($c->[1] eq '' or $c->[1] eq 'case') ) {
519 35         58 my $eval=$c->[5];
520 35         278 $eval=~s/\\(.)|"/$1/g; #";#
521 35         66 $eval="$vdecl $eval";
522 35 100       84 if( $I->__eval_cached( $eval, $v, $h, 1 ) ) {
523 18         45 return $I->_eval_list( $v, $h, $I->__get_code_list($c) )
524             }
525             }
526             }
527             } elsif( $el->[1] eq 'set' ) {
528 5         7 my $name;
529 5         8 foreach my $f (@{$el->[2]}) {
  5         9  
530 5 50       13 next if( ref($f) );
531 5         9 $name=$f;
532 5         8 last;
533             }
534 5         20 my @l=$I->_make_one_param( $v, $el, $h, [$name=>$el->[3]] );
535 5         21 $h->{$l[0]}=$l[1];
536             } elsif( $el->[1] eq 'defmacro' ) { # define macro
537 2         2 my $macro;
538 2         5 foreach my $f (@{$el->[2]}) {
  2         4  
539 2 50 33     12 if( !ref($f) and length($f) ) {
540 2         6 $macro=$I->_eval_list( $v, $h, $I->_parse_cached($f) );
541 2         5 last;
542             }
543             }
544 2         8 $I->_macros->{$macro}=[$I->__get_code_list($el)];
545             }
546 7         43 return;
547             }
548              
549             sub _make_one_param {
550 192     192   239 my $I=shift;
551 192         225 my $v=shift;
552 192         193 my $el=shift;
553 192         230 my $h=shift;
554 192         249 my $p=shift;
555              
556 192 100       386 if( ref($p) eq 'ARRAY' ) {
557 125         278 my @pp=$I->_parse_cached( $p->[1] );
558 125         216 my $string='';
559 125         188 my $pl=[];
560 125         147 my $array=0;
561 125         365 foreach my $ve (@pp) {
562 136 100       299 if( !defined( $ve->[0] ) ) { # text element
563 12 100       29 if( $array ) {
564 6         10 foreach my $s (@$pl) {
565 48         67 $s.=$ve->[4];
566             }
567             } else {
568 6         18 $string.=$ve->[4];
569             }
570 12         41 next;
571             }
572 124         242 my $x;
573 124 100       252 if( $ve->[0] eq ':' ) { # control element
574 113         343 $x=$I->_eval_control( $v, $ve, $h );
575             #use Data::Dumper; warn "_eval_control returns ", Dumper($x);
576             } else {
577 11         40 $x=$I->_eval_var( $ve, $h );
578             #use Data::Dumper; warn "_eval_var returns ", Dumper($x);
579             }
580 124 100       320 if( ref($x) eq 'ARRAY' ) {
581 80 100       289 if( $array ) { # schon array mode ==> kreuzprodukt
    100          
582 2         5 my $npl;
583 2         6 foreach my $s (@$pl) {
584 8         9 foreach my $v (@{$x}) {
  8         13  
585 32         70 push @$npl, $s.$v;
586             }
587             }
588 2         16 $pl=$npl;
589             } elsif( length( $string ) ) { # noch kein array mode aber $string
590 3         4 local $_; # nicht leer
591 3         7 $pl=[map {$string.$_} @$x];
  12         26  
592 3         11 undef $string; # $string is useless in array mode
593             # save a little memory
594             } else { # noch kein array mode und $string immer noch
595 75         107 $pl=$x; # leer
596             }
597 80         427 $array=1; # turn on array mode
598             } else {
599 44 50       98 if( $array ) {
600 0         0 foreach my $s (@$pl) {
601 0         0 $s.=$x;
602             }
603             } else {
604 44 50       78 if( length $string ) {
605 0         0 $string.=$x;
606             } else {
607 44         111 $string=$x;
608             }
609             }
610             }
611             }
612 125 50       704 return ($I->_eval_list( $v, $h,
    100          
613             $I->_parse_cached(defined $p->[0] ? $p->[0] : '') )
614             =>($array ? $pl : $string));
615             } else {
616 67 100 66     321 if( $p eq ':inherit' or $p eq ':inheritparams' ) {
617 11         14 return (%{$h});
  11         97  
618             }
619             }
620 56         124 return;
621             }
622              
623             sub _make_include_param_list {
624 135     135   183 my $I=shift;
625 135         154 my $v=shift;
626 135         149 my $el=shift;
627 135         136 my $h=shift;
628              
629 135         139 my @res;
630 135         158 local $_;
631 135 100       384 foreach my $p (@{$el->[2]}, map {
  135         564  
632 305 100 100     1033 if( $_->[0] eq ':' and $_->[1] eq 'set' ) {
633 16         21 my $name;
634 16         27 foreach my $f (@{$_->[2]}) {
  16         35  
635 16 50       155 next if( ref($f) );
636 16         27 $name=$f;
637 16         19 last;
638             }
639 16         53 [$name, $_->[3]];
640             } else {
641 289         448 ();
642             }
643             } $I->_parse_cached( defined $el->[3] ? $el->[3] : '' )) {
644 187         475 push @res, $I->_make_one_param( $v, $el, $h, $p );
645             }
646              
647 135         643 return @res;
648             }
649              
650             sub _eval_list {
651 938     938   1302 my $I=shift;
652 938         1062 my $v=shift;
653 938         1201 my $h=shift;
654              
655 938         1139 my $res='';
656 938         1794 foreach my $el (@_) {
657 2166 100       6027 if( !defined( $el->[0] ) ) { # text element
    100          
658 1317         3129 $res.=$el->[4];
659             } elsif( $el->[0] eq ':' ) { # control element
660 645         1519 $res.=$I->_eval_control( $v, $el, $h );
661             } else { # variable element
662 204         621 my $el=$I->_eval_var( $el, $h );
663 204 100       613 if( ref($el) eq 'ARRAY' ) {
664 108         257 $res.=join('',@{$el});
  108         522  
665             } else {
666 96         269 $res.=$el;
667             }
668             }
669             }
670 936         4284 return $res;
671             }
672              
673             sub evaluate_as_config {
674 1     1 1 32 my $I=shift;
675 1 50       6 if( @_%2 ) {
676 0         0 $I->_extra=shift;
677             } else {
678 1         5 $I->_extra={};
679             }
680 1         12 my $h=+{@_};
681              
682 1         2 my $res={};
683              
684 1 50       5 $I->_macros={} unless( defined $I->_macros );
685 1         26 foreach my $el ($I->_parse_cached) {
686 11 100       30 if( !defined( $el->[0] ) ) { # text element: skip
    50          
687             } elsif( $el->[0] eq ':' ) { # control element: eval but ignore result
688 0         0 $I->_eval_control( undef, $el, $h );
689             } else { # variable element
690 5         16 $res->{$el->[1]}=$I->_eval_var( $el, $h );
691             }
692             }
693 1         5 return $res;
694             }
695              
696             sub evaluate {
697 54     54 1 340804 my $I=shift;
698 54 50       186 if( @_%2 ) {
699 0         0 $I->_extra=shift;
700             } else {
701 54         190 $I->_extra={};
702             }
703 54         823 my $h=+{@_};
704              
705 54 100       185 $I->_macros={} unless( defined $I->_macros );
706 54         961 my $rc=$I->_eval_list( undef, $h, $I->_parse_cached );
707              
708 52 100       242 if( $I->compress=~/gz$/ ) {
709 1         19 return Compress::Zlib::memGzip $rc;
710             } else {
711 51         895 return $rc;
712             }
713             }
714              
715             sub evaluate_to_file {
716 2     2 1 47 my $I=shift;
717 2         4 my $fh=shift;
718              
719 2         4 my $text;
720 2         7 $text=$I->evaluate( @_ );
721              
722 2 50       614 if( UNIVERSAL::isa($fh, 'GLOB') ) {
723 0         0 return print $fh $text;
724             }
725 2 50       10 if( UNIVERSAL::isa($fh, 'CODE') ) {
726 0         0 return $fh->( $text );
727             }
728 2 50 33     8 if( ref($fh) and UNIVERSAL::can( $fh, 'print' ) ) {
729 0         0 return $fh->print( $text );
730             }
731              
732 2 100       8 if( $I->compress=~/gz$/ ) {
733 1         20 my $ext=$I->compress;
734 1         27 $fh=~s/\Q$ext\E$//;
735 1         4 $fh.=$ext;
736             }
737 2 50       30 $fh=IO::File->new( $fh, 'w' ) or return;
738 2 50       462 print $fh $text or return;
739 2         135 return 1;
740             }
741              
742             1;