2 # A really simple template engine
3 # (c) 2004--2008 Martin Mares <mj@ucw.cz>
13 our @ISA = qw(Exporter);
14 our @EXPORT = qw(out);
15 our @EXPORT_OK = qw();
28 my ($r,$left,$right) = @_;
33 if ($$r =~ /\G([^$left$right]+)/cgs) {
34 } elsif ($$r =~ /\G([$left])/cgs) {
36 } elsif ($$r =~ /\G([$right])/cgs) {
39 die "File ended when looking for matching $right";
49 my $res = eval "package T; $x";
50 return $res unless $@;
51 die "Error evaluating $x: $@";
59 if ($f =~ /^(if|fi|else|elif)$/) {
61 $a ne "()" or die "\@if requires an argument";
63 unshift @cond, (eval_if_ok($a) ? 1 : -1);
67 } elsif ($f eq "fi") {
68 $a eq "()" or die "\@fi takes no arguments";
69 $#cond or die "\@fi without \@if";
71 } elsif ($f eq "else") {
72 $a eq "()" or die "\@else takes no arguments";
73 $#cond or die "\@else without \@if";
75 } elsif ($f eq "elif") {
76 $a ne "()" or die "\@elif requires an argument";
77 $#cond or die "\@elif without \@if";
80 } elsif ($cond[0] < 0) {
82 $cond[0] = (eval_if_ok($a) ? 1 : -1);
85 # print "Cond stack: @cond\n";
87 my $res = eval_if_ok("$f $a");
88 out $res if defined $res;
96 if ($t =~ /\G([^\@]+)/cgs) {
97 out $1 if $cond[0] > 0;
98 } elsif ($t =~ /\G\@\s*\n/cgs) {
99 # @ at end of line is ignored and eats the end of line
100 } elsif ($t =~ /\G\@#[^\n]*\n/cgs) {
101 # a comment, which is ignored
102 } elsif ($t =~ /\G\@\@/cgs) {
103 out "\@" if $cond[0] > 0;
104 } elsif ($t =~ /\G\@{/cgs) {
105 my $x = get_nested(\$t, "{", "}");
107 } elsif ($t =~ /\G\@\[/cgs) {
108 my $x = get_nested(\$t, '\[', '\]');
112 } elsif ($t =~ /\G\@\(/cgs) {
113 my $x = get_nested(\$t, '\(', '\)');
116 out (defined($arguments->{$x}) ? $arguments->{$x} : "");
117 } elsif ($t =~ /\G\@(\w+)\(/cgs) {
119 my $args = get_nested(\$t, '(', ')');
120 eval_func($func, $args);
121 } elsif ($t =~ /\G\@(\w+)([^\n]*)\n/cgs) {
122 eval_func($1, "($2)");
123 } elsif ($t =~ /\G\@(\$\w+)/cgs) {
125 } elsif ($t =~ /\G(\@[^\n]*)/cgs) {
126 die "Unknown control sequence $1";
127 } elsif ($t =~ /\G$/cgs) {
129 } elsif ($t =~ /\G([^\n]*)/cgs) {
130 die "Internal parser error at $1 (pos " . pos($t) . ")";
137 my $fh = new IO::File $name;
138 die "Unable to open $name: $!" unless defined $fh;
140 { local $/; undef $/; $text = <$fh>; }
153 $#cond and die "Unterminated \@if (depth $#cond)";
156 sub process_file($;$) {
157 my ($name, $args) = @_;
163 sub process_string($;$) {
164 my ($string, $args) = @_;
166 parse_string($string);
170 ### Perl commands embedded in the templates are evaluated in this package ###
177 our $out_func = sub { print @_; };
184 UCW::Temple::eval_if_ok("\$$v = \$temp");
186 UCW::Temple::parse_file($fn);
192 (!defined($f) || @_) and die "\@load requires only one argument";