File Coverage

blib/lib/PAB3.pm
Criterion Covered Total %
statement 55 331 16.6
branch 5 152 3.2
condition 3 77 3.9
subroutine 15 28 53.5
pod 8 12 66.6
total 86 600 14.3


line stmt bran cond sub pod time code
1             package PAB3;
2             # =============================================================================
3             # Perl Application Builder
4             # Module: PAB3
5             # Use "perldoc PAB3" for documentation
6             # =============================================================================
7 2     2   10070 use Carp ();
  2         4  
  2         61  
8 2     2   1789 use Symbol ();
  2         2031  
  2         52  
9              
10 2     2   24 use strict;
  2         4  
  2         88  
11 2     2   10 no strict 'refs';
  2         3  
  2         48  
12 2     2   9 use warnings;
  2         5  
  2         72  
13 2     2   12 no warnings 'uninitialized';
  2         3  
  2         84  
14              
15 2     2   9 use vars qw($VERSION %SC $_CURRENT);
  2         4  
  2         164  
16              
17             use constant {
18 2         345 SCALAR => 1,
19             ARRAY => 2,
20             HASH => 3,
21             FUNC => 4,
22 2     2   12 };
  2         4  
23              
24             BEGIN {
25 2     2   5 $VERSION = '3.201';
26 2         11 require XSLoader;
27 2         1317 XSLoader::load( __PACKAGE__, $VERSION );
28 2 50       20 if( ! $PAB3::CGI::VERSION ) {
29 2         13 $SIG{'__DIE__'} = \&_die_handler;
30 2         11 $SIG{'__WARN__'} = \&_warn_handler;
31             }
32 2         5214 *print_r = \&print_var;
33             }
34              
35             END {
36 2     2   0 &_cleanup();
37             }
38              
39             1;
40              
41             sub import {
42 2     2   20 my $pkg = shift;
43 2         7 my $callpkg = caller();
44 2 0 33     16 if( $_[0] and $pkg eq __PACKAGE__ and $_[0] eq 'import' ) {
      33        
45 0         0 *{$callpkg . '::import'} = \&import;
  0         0  
46 0         0 return;
47             }
48 2         9 foreach( @_ ) {
49 0 0 0     0 if( $_ eq ':const' || $_ eq ':default' ) {
50 0         0 *{$callpkg . '::PAB_SCALAR'} = \&{$pkg . '::SCALAR'};
  0         0  
  0         0  
51 0         0 *{$callpkg . '::PAB_ARRAY'} = \&{$pkg . '::ARRAY'};
  0         0  
  0         0  
52 0         0 *{$callpkg . '::PAB_HASH'} = \&{$pkg . '::HASH'};
  0         0  
  0         0  
53 0         0 *{$callpkg . '::PAB_FUNC'} = \&{$pkg . '::FUNC'};
  0         0  
  0         0  
54             }
55 0 0       0 if( $_ eq ':default' ) {
56 0         0 *{$callpkg . '::print_var'} = \&{$pkg . '::print_var'};
  0         0  
  0         0  
57 0         0 *{$callpkg . '::print_r'} = \&{$pkg . '::print_var'};
  0         0  
  0         0  
58 0         0 *{$callpkg . '::require'} = \&{$pkg . '::require'};
  0         0  
  0         0  
59 0         0 *{$callpkg . '::require_and_run'} = \&{$pkg . '::require_and_run'};
  0         0  
  0         0  
60             }
61             }
62             }
63              
64             sub setenv {
65 0 0   0 1 0 if( $0 =~ /^(.+\/)(.+?)$/ ) {
66 0         0 $ENV{'SCRIPT_PATH'} = $1;
67 0         0 $ENV{'SCRIPT'} = $2;
68             }
69             else {
70 0         0 $ENV{'SCRIPT_PATH'} = '';
71 0         0 $ENV{'SCRIPT'} = $0;
72             }
73             }
74              
75             sub new {
76 1     1 1 7 my $proto = shift;
77 1   33     8 my $class = ref( $proto ) || $proto;
78 1 50       22 my $this = &_new( $class, @_ ) or return undef;
79 1         3 my %arg = @_;
80 1 50       6 $this->{'die'} = defined $arg{'die'} ? $arg{'die'} : 1;
81 1 50       3 $this->{'warn'} = defined $arg{'warn'} ? $arg{'warn'} : 1;
82 1         2 $this->{'path_template'} = $arg{'path_template'};
83 1         2 $this->{'path_cache'} = $arg{'path_cache'};
84 1         2 $this->{'auto_cache'} = $arg{'auto_cache'};
85 1         1 $this->{'hashmap_cache'} = $arg{'hashmap_cache'};
86 1         3 $this->{'logger'} = $arg{'logger'};
87 1         4 return $this;
88             }
89              
90             sub handle_error {
91 0     0 0 0 my( $this ) = @_;
92 0 0       0 if( $this ) {
93 0 0       0 &Carp::croak( &error( $this ) ) if $this->{'die'};
94 0 0       0 &Carp::carp( &error( $this ) ) if $this->{'warn'};
95             }
96 0         0 return 0;
97             }
98              
99             sub parse_template {
100 2 50   2 1 2792 &_parse_template( @_ ) or return handle_error( @_ );
101             }
102              
103             sub make_script_and_run {
104 0     0 1   my( $this, $template, $cache, $package ) = @_;
105 0           my( @ts, @cs, $rv, $ct, $cac, $tpl, $fh );
106 0           $_CURRENT = $this;
107 0   0       $package ||= ( CORE::caller )[0];
108 0           $tpl = $this->{'path_template'} . $template;
109 0 0 0       if( ! $cache && $this->{'auto_cache'} ) {
110 0           $cache = '_auto.' . $template . '.pl';
111 0           $cache =~ tr!/!.!;
112 0           $cache =~ tr!\\!.!;
113             }
114 0 0         if( $cache ) {
115 0           $cac = $this->{'path_cache'} . $cache;
116 0 0         if( -f $tpl ) {
117 0           @ts = stat( $tpl );
118 0 0         if( -f $cac ) {
119 0           @cs = stat( $cac );
120 0 0         if( $ts[9] == $cs[9] ) {
121 0           &require_and_run( $this, $cac, $package );
122 0           return 1;
123             }
124             }
125             }
126             }
127 0 0         if( $this->{'logger'} ) {
128 0           $this->{'logger'}->debug( "Parse template \"$tpl\"" );
129             }
130 0           ( $rv, $ct ) = &_make_script( $this, $template, $cache );
131 0 0         if( $rv == 3 ) {
    0          
    0          
    0          
132 0 0         if( $this->{'logger'} ) {
133 0           $this->{'logger'}->debug( "Save script at \"$cac\"" );
134             }
135             open( $fh, '> ' . $cac )
136 0 0         or do {
137 0           $this->set_error( "Unable to open file '$cac': $!" );
138 0           return $this->handle_error();
139             };
140 0           flock( $fh, 2 );
141 0           syswrite( $fh, $ct );
142 0           flock( $fh, 8 );
143 0           close( $fh );
144 0           utime( $ts[9], $ts[9], $cac );
145 0           &require_and_run( $this, $cac, $package );
146             }
147             elsif( $rv == 1 ) {
148 0           utime $ts[9], $ts[9], $cac;
149 0           &require_and_run( $this, $cac, $package );
150             }
151             elsif( $rv == 2 ) {
152 0 0         if( $this->{'logger'} ) {
153 0           $this->{'logger'}->debug( "Compile and run \"$tpl\"" );
154             }
155 0           $tpl =~ s/\W/_/go;
156 0           &PAB3::_create_script_cache( \$ct, $tpl, $package );
157 0           my $of = $0;
158 0           *0 = \$template;
159 0           &{"PAB3::SC::${tpl}::handler"}();
  0            
160 0           *0 = \$of;
161             }
162             elsif( ! $rv ) {
163 0           return &handle_error( $this );
164             }
165 0           return 1;
166             }
167              
168             sub add_hashmap {
169 0     0 1   my( $this, $loopid, $record, $fieldmap, $tfm ) = @_;
170 0           my( $fm, $fmc, $hmc );
171 0 0         if( ref( $fieldmap ) eq 'ARRAY' ) {
    0          
172 0           my $ifm = 0;
173 0           $fm = {};
174 0           foreach( @$fieldmap ) {
175 0           $fm->{$_} = $ifm ++;
176             }
177             }
178             elsif( ref( $fieldmap ) eq 'HASH' ) {
179 0           $fm = $fieldmap;
180             }
181             else {
182 0           &set_error( $this, 'Parameter fieldmap is invalid' );
183 0           return &handle_error( $this );
184             }
185 0 0         if( ( $hmc = $this->{'hashmap_cache'} ) ) {
186 0           $fmc = $hmc->get( $loopid, $record, $fm );
187             }
188 0 0         if( ! %$fm ) {
189 0 0         if( ! $fmc ) {
190 0           &set_error( $this, 'Hashmap is empty' );
191 0           return &handle_error( $this );
192             }
193 0           $fm = $fmc;
194             }
195 0 0         &_add_hashmap( $this, $loopid, $record, $fieldmap )
196             or return &handle_error( $this );
197 0 0 0       if( $hmc && ! $fmc ) {
198 0           $hmc->set( $loopid, $record, $fm );
199             }
200 0           $_[4] = $fm;
201 0           return 1;
202             }
203              
204             sub require {
205 0 0   0 1   my $this = shift if ref( $_[0] ) eq __PACKAGE__;
206 0           my( $file, $package, $inject_code, $args ) = @_;
207 0           my( $fid, $cache, $content, $fh, @fs, $logger );
208 0   0       $package ||= ( caller )[0];
209 0           $fid = $file . '_' . $package;
210 0           $fid =~ s/\W/_/go;
211 0 0         if( $package eq $fid ) {
212 0           &Carp::croak( 'Script requires itself' );
213             }
214 0           @fs = stat( $file );
215 0           $cache = $SC{$fid};
216 0 0 0       $logger = $this->{'logger'} if $this && $this->{'logger'};
217 0 0 0       if( ! $cache || $cache != $fs[9] ) {
218 0 0         if( $cache ) {
219 0 0         if( $logger ) {
220 0           $logger->debug( "Unloading PAB3::SC::${fid}" );
221             }
222 0           &Symbol::delete_package( "PAB3::SC::${fid}" );
223             }
224 0 0         if( $logger ) {
225 0           $logger->debug( "Compile \"$file\"" );
226             }
227 0 0         open( $fh, $file ) or &Carp::croak( "Unable to open '$file': $!" );
228 0           flock( $fh, 1 );
229 0           read( $fh, $content, $fs[7] );
230 0           flock( $fh, 8 );
231 0           close( $fh );
232 0           &_create_script_cache( \$content, $fid, $package, $file, $inject_code );
233 0           $SC{$fid} = $fs[9];
234 0 0         if( $logger ) {
235 0           $logger->debug( "Run PAB3::SC::${fid}::handler" );
236             }
237 0           my $of = $0;
238 0           *0 = \$file;
239 0 0         &{"PAB3::SC::${fid}::handler"}( ref( $args ) eq 'ARRAY' ? @$args : $args );
  0            
240 0           *0 = \$of;
241 0           return 1;
242             }
243 0           return 1;
244             }
245              
246             sub require_and_run {
247 0 0   0 1   my $this = shift if ref( $_[0] ) eq __PACKAGE__;
248 0           my( $file, $package, $inject_code, $args ) = @_;
249 0           my( $fid, $cache, $content, $fh, @fs, $of, $logger );
250 0   0       $package ||= ( caller )[0];
251 0           $fid = $file . '_' . $package;
252 0           $fid =~ s/\W/_/go;
253 0 0         if( $package eq $fid ) {
254 0           &Carp::croak( 'Script requires itself' );
255             }
256 0           @fs = stat( $file );
257 0           $cache = $SC{$fid};
258 0 0 0       $logger = $this->{'logger'} if $this && $this->{'logger'};
259 0 0 0       if( ! $cache || $cache != $fs[9] ) {
260 0 0         if( $cache ) {
261 0 0         if( $logger ) {
262 0           $logger->debug( "Unloading PAB3::SC::${fid}" );
263             }
264 0           &Symbol::delete_package( "PAB3::SC::${fid}" );
265             }
266 0 0         if( $logger ) {
267 0           $logger->debug( "Compile \"$file\"" );
268             }
269 0 0         open( $fh, $file ) or &Carp::croak( "Unable to open '$file': $!" );
270 0           flock( $fh, 1 );
271 0           read( $fh, $content, $fs[7] );
272 0           flock( $fh, 8 );
273 0           close( $fh );
274 0           &_create_script_cache( \$content, $fid, $package, $file, $inject_code );
275 0           $SC{$fid} = $fs[9];
276             }
277 0 0         if( $logger ) {
278 0           $logger->debug( "Run PAB3::SC::${fid}::handler" );
279             }
280 0           $of = $0;
281 0           *0 = \$file;
282 0 0         &{"PAB3::SC::${fid}::handler"}( ref( $args ) eq 'ARRAY' ? @$args : $args );
  0            
283 0           *0 = \$of;
284 0           return 1;
285             }
286              
287             sub _create_script_cache {
288 0     0     my( $content, $pkg_require, $pkg_caller, $filename, $inject_code ) = @_;
289 0           my( $hr, $data, $end );
290 0 0         if( ref( $content ) ) {
291 0           $content = $$content;
292             }
293 0           $content =~ s!\r!!gso;
294 0 0         if( $content =~ s/(\n__DATA__\n.*$)//s ) {
295 0           $data = $1;
296             }
297             else {
298 0           $data = '';
299             }
300 0 0         if( $content =~ s/(\n__END__\n.*$)//s ) {
301 0           $end = $1;
302             }
303             else {
304 0           $end = '';
305             }
306 0   0       $filename ||= $0;
307 0   0       $inject_code ||= '';
308 0           $content = <
309             package PAB3::SC::$pkg_require;
310             our \$VERSION = 1;
311             *handler = sub {
312             package $pkg_caller;
313             $inject_code
314             #line 1 $filename
315             $content
316             };
317             1;
318             $data
319             $end
320             EORAR01
321 0 0         if( $GLOBAL::DEBUG ) {
322 0 0         $PAB3::CGI::VERSION
323             ? &PAB3::CGI::print_code( $content, $filename )
324             : &PAB3::print_code( $content, $filename )
325             ;
326             }
327             {
328 2     2   21 no strict;
  2         4  
  2         97  
  0            
329 2     2   12 no warnings FATAL => 'all';
  2         4  
  2         2625  
330 0           local( $SIG{'__DIE__'}, $SIG{'__WARN__'} );
331 0           eval $content;
332             }
333 0 0         if( $@ ) {
334 0 0         if( ! $GLOBAL::DEBUG ) {
335 0 0         $PAB3::CGI::VERSION
336             ? &PAB3::CGI::print_code( $content, $filename )
337             : &PAB3::print_code( $content, $filename )
338             ;
339             }
340 0           &Carp::croak( $@ );
341             };
342             }
343              
344             sub print_code {
345 0     0 0   my( $t, $l, $p );
346 0           foreach $t( @_ ) {
347 0           $t =~ s!\r!!gso;
348 0 0         if( defined $t ) {
349 0           print "\n";
350 0           $p = 1;
351 0           foreach $l( split( /\n/, $t ) ) {
352 0           print $p . "\t" . $l . "\n";
353 0           $p ++;
354             }
355 0           print "\n";
356             }
357             }
358             }
359              
360             sub print_hash {
361 0     0 0   my( $hashname, $ref_table, $level ) = @_;
362 0           my( $r_hash, $r, $k );
363 0   0       $ref_table ||= [];
364 0 0         if( $hashname =~ /HASH\(0x\w+\)/ ) {
365 0           $r_hash = $hashname;
366             }
367             else {
368 0           return;
369             }
370 0           print $r_hash;
371 0 0 0       if( $ref_table->{$r_hash} && $ref_table->{$r_hash} <= $level ) {
372 0           print " [recursive loop]\n";
373 0           return;
374             }
375 0           print "\n", " " x $level, "(\n";
376 0           $ref_table->{$r_hash} = $level + 1;
377 0           foreach $k( sort { lc( $a ) cmp lc( $b ) } keys %{ $r_hash } ) {
  0            
  0            
378 0           print " " x ( $level + 1 ) . "[$k] => ";
379 0           $r = ref( $r_hash->{$k} );
380 0 0 0       if( $r && index( $r_hash->{$k}, 'ARRAY(' ) >= 0 ) {
    0 0        
381 0           &print_array( $r_hash->{$k}, $ref_table, $level + 1 );
382             }
383             elsif( $r && index( $r_hash->{$k}, 'HASH(' ) >= 0 ) {
384 0           &print_hash( $r_hash->{$k}, $ref_table, $level + 1 );
385             }
386             else {
387 0 0         print ( ! defined $r_hash->{$k} ? '(null)' : $r_hash->{ $k } );
388 0           print "\n";
389             }
390             }
391 0           print " " x $level, ")\n";
392             }
393              
394             sub print_array {
395 0     0 0   my( $arrayname, $ref_table, $level ) = @_;
396 0           my( $r_array, $r, $v, $i );
397 0   0       $ref_table ||= {};
398 0   0       $level ||= 0;
399 0 0         if( $arrayname =~ /ARRAY\(0x\w+\)/ ) {
400 0           $r_array = $arrayname;
401             }
402             else {
403 0           return;
404             }
405 0           print $r_array;
406 0 0 0       if( $ref_table->{$r_array} && $ref_table->{$r_array} <= $level ) {
407 0           print " [recursive loop]\n";
408 0           return;
409             }
410 0           print "\n", " " x $level, "(\n";
411 0           $ref_table->{$r_array} = $level + 1;
412 0           $i = 0;
413 0           foreach $v( @{ $r_array } ) {
  0            
414 0           $r = ref( $v );
415 0           print " " x ( $level + 1 ) . "[$i] => ";
416 0 0 0       if( $r && index( $v, 'ARRAY(' ) >= 0 ) {
    0 0        
417 0           &print_array( $v, $ref_table, $level + 1 );
418             }
419             elsif( $r && index( $v, 'HASH(' ) >= 0 ) {
420 0           &print_hash( $v, $ref_table, $level + 1 );
421             }
422             else {
423 0 0         print "" . ( ! defined $v ? '(null)' : $v ) . "\n";
424             }
425 0           $i ++;
426             }
427 0           print " " x $level, ")\n";
428             }
429              
430             sub print_var {
431 0     0 1   my( $v, $r, $ref_table );
432 0           $ref_table = {};
433 0           foreach $v( @_ ) {
434 0           $r = ref( $v );
435 0 0 0       if( $r && index( $v, 'ARRAY(' ) >= 0 ) {
    0 0        
    0 0        
436 0           &print_array( $v, $ref_table, 0 );
437             }
438             elsif( $r && index( $v, 'HASH(' ) >= 0 ) {
439 0           &print_hash( $v, $ref_table, 0 );
440             }
441             elsif( $r && index( $v, 'SCALAR(' ) >= 0 ) {
442 0 0         print defined $$v ? $$v : '(null)', "\n";
443             }
444             else {
445 0 0         print defined $v ? $v : '(null)', "\n";
446             }
447             }
448             }
449              
450             sub _die_handler {
451 0     0     my $str = shift;
452 0           my( @c, $step );
453 0           print "\nFatal: $str\n\n";
454 0           @c = caller();
455 0           print $c[0] . ' raised the exception at ' . $c[1] . ' line ' . $c[2] . "\n";
456 0           $step = 1;
457 0           while( @c = caller( $step ) ) {
458 0           print $c[0] . ' called ' . $c[3] . ' at ' . $c[1] . ' line ' . $c[2] . "\n";
459 0           $step ++;
460             }
461 0           print "\n";
462 0           exit( 0 );
463             }
464              
465             sub _warn_handler {
466 0     0     my $str = shift;
467 0           print "\nWarning: $str\n";
468             }
469              
470             __END__