# Copyright (c) 2004, 2005 Denis Petrov # $Id: magic.pl,v 1.13 2005/02/28 04:31:54 Owner Exp $ # Distributed under the terms of the GNU General Public License # # Magic Template Processor # # Magic Home: http://www.denispetrov.com/magic/ use strict; # use Data::Dumper; package main; my @parsed; my $i; my $magic_warning = ''; sub ___magic_warn { $magic_warning = $_[0]; } # parameters: section type ('code' or 'text' or 'label') sub ___print_magic_warning { my $lc = &___count_lines(); my (undef,$fn,$fl) = caller(1); print STDERR "Magic warning: $fn:$fl, $_[0] section beginning at line $lc(".($fl+$lc).")\n$magic_warning\n"; $magic_warning = ''; } # \@parsed, $currentpos sub ___count_lines { my $count = 1; # first line for ( my $_i = 0; $_i < $i; $_i++ ) { $count += scalar($parsed[$_i] =~ tr/\n//); } # if the current section follows a code or label section ending in a newline, it will appear # starting on the same line as that code section, which is confusing # so treat this newline as part of preceding code section, i.e. increase line number by 1 $count++ if $parsed[$i] =~ /^\s*\n/; return $count; } sub Magic { my $label_regexp = "[a-zA-z_][a-zA-z0-9_]*"; my %labels; @parsed = ('<%_%>' . $_[0] . '<%END%>') =~ /(<%.+?(?=%>)%>)(.*?)(?=<%|$)/gs; $i = 0; my $len = scalar(@parsed); for ( $i = 0; $i < $len; $i++ ) { my $l = $parsed[$i]; if ( $l =~ /<%($label_regexp)%>/ ) { if ( exists($labels{$1}) && $labels{$1} != $i ) { $magic_warning = "Found duplicate label '$1', it has been ignored"; &___print_magic_warning('label'); } else { $labels{$1} = $i; } } elsif ( $l =~ /<%(.+)%>/s ) { my $save_sig = $SIG{__WARN__}; $SIG{__WARN__} = \&___magic_warn; my $result = eval($1); $SIG{__WARN__} = $save_sig; &___print_magic_warning('code') if $magic_warning; if ( !defined($result) ) { if ( $@ ) { $magic_warning = $@; &___print_magic_warning('code'); print STDERR "Processing of this template has stopped.\n"; return 1; } # else there's no error, just discard the undef and move on } elsif ( $result =~ /$label_regexp/ ) { if ( exists $labels{$result} ) { $i = $labels{$result}; } else { #trace labels forward my $j; my $found_label = undef; for ( $j = $i+1; $j < $len; $j++ ) { if ( $parsed[$j] =~ /<%($label_regexp)%>/ ) { if ( exists($labels{$1}) && $labels{$1} != $j ) { $magic_warning = "Found duplicate label '$1', it has been ignored"; &___print_magic_warning('label'); } else { $labels{$1} = $j; } if ( $1 eq $result ) { $i = $j; $found_label = 1; last; } } } if ( !$found_label ) { $magic_warning = "A template code section returned label '$result'" . " which does not exist in the template"; &___print_magic_warning('code'); } } } } else { $l =~ s/\"/\\\"/g; my $save_sig = $SIG{__WARN__}; $SIG{__WARN__} = \&___magic_warn; my $result = eval("\"".$l."\""); $SIG{__WARN__} = $save_sig; if ( !defined($result) ) { if ( $@ ) { $magic_warning = $@; &___print_magic_warning('text'); } } else { &___print_magic_warning('text') if $magic_warning; print( $result ); } } } # print Dumper(\@parsed); # print Dumper(%labels); return ''; } 1;