2 # A really simple template engine
3 # (c) 2004--2008 Martin Mares <mj@ucw.cz>
16 my ($r,$left,$right) = @_;
21 if ($$r =~ /\G([^$left$right]+)/cgs) {
22 } elsif ($$r =~ /\G([$left])/cgs) {
24 } elsif ($$r =~ /\G([$right])/cgs) {
27 die "File ended when looking for matching $right";
37 my $res = eval "package T; $x";
38 return $res unless $@;
39 die "Error evaluating $x: $@";
47 if ($f =~ /^(if|fi|else|elif)$/) {
49 $a ne "()" or die "\@if requires an argument";
51 unshift @cond, (eval_if_ok($a) ? 1 : -1);
55 } elsif ($f eq "fi") {
56 $a eq "()" or die "\@fi takes no arguments";
57 $#cond or die "\@fi without \@if";
59 } elsif ($f eq "else") {
60 $a eq "()" or die "\@else takes no arguments";
61 $#cond or die "\@else without \@if";
63 } elsif ($f eq "elif") {
64 $a ne "()" or die "\@elif requires an argument";
65 $#cond or die "\@elif without \@if";
68 } elsif ($cond[0] < 0) {
70 $cond[0] = (eval_if_ok($a) ? 1 : -1);
73 # print "Cond stack: @cond\n";
75 my $res = eval_if_ok("$f($a)");
76 print $res if defined $res;
84 if ($t =~ /\G([^\@]+)/cgs) {
85 print $1 if $cond[0] > 0;
86 } elsif ($t =~ /\G\@\s*\n/cgs) {
87 # @ at end of line is ignored and eats the end of line
88 } elsif ($t =~ /\G\@#[^\n]*\n/cgs) {
89 # a comment, which is ignored
90 } elsif ($t =~ /\G\@\@/cgs) {
92 } elsif ($t =~ /\G\@{/cgs) {
93 my $x = get_nested(\$t, "{", "}");
95 } elsif ($t =~ /\G\@\[/cgs) {
96 my $x = get_nested(\$t, '\[', '\]');
100 } elsif ($t =~ /\G\@(\w+)\(/cgs) {
102 my $args = get_nested(\$t, '(', ')');
103 eval_func($func, $args);
104 } elsif ($t =~ /\G\@(\w+)([^\n]*)\n/cgs) {
105 eval_func($1, "($2)");
106 } elsif ($t =~ /\G\@(\$\w+)/cgs) {
107 print eval_if_ok($1);
108 } elsif ($t =~ /\G(\@[^\n]*)/cgs) {
109 die "Unknown control sequence $1";
110 } elsif ($t =~ /\G$/cgs) {
112 } elsif ($t =~ /\G([^\n]*)/cgs) {
113 die "Internal parser error at $1 (pos " . pos($t) . ")";
120 my $fh = new IO::File $name;
121 die "Unable to open $name: $!" unless defined $fh;
123 { local $/; undef $/; $text = <$fh>; }
135 $#cond and die "Unterminated \@if (depth $#cond)";
138 sub process_file($) {
144 sub process_string($) {
150 ### Perl commands embedded in the templates are evaluated in this package ###
161 UCW::Temple::eval_if_ok("\$$v = \$temp");
163 UCW::Temple::parse_file($fn);
169 (!defined($f) || @_) and die "\@load requires only one argument";