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();
34 my ($r,$left,$right) = @_;
39 if ($$r =~ /\G([^$left$right]+)/cgs) {
40 } elsif ($$r =~ /\G([$left])/cgs) {
42 } elsif ($$r =~ /\G([$right])/cgs) {
45 die "File ended when looking for matching $right";
55 my $res = eval "package T; $x";
56 return $res unless $@;
57 die "Error evaluating $x: $@";
65 if ($f =~ /^(if|fi|else|elif)$/) {
67 $a ne "()" or die "\@if requires an argument";
69 unshift @cond, (eval_if_ok($a) ? 1 : -1);
73 } elsif ($f eq "fi") {
74 $a eq "()" or die "\@fi takes no arguments";
75 $#cond or die "\@fi without \@if";
77 } elsif ($f eq "else") {
78 $a eq "()" or die "\@else takes no arguments";
79 $#cond or die "\@else without \@if";
81 } elsif ($f eq "elif") {
82 $a ne "()" or die "\@elif requires an argument";
83 $#cond or die "\@elif without \@if";
86 } elsif ($cond[0] < 0) {
88 $cond[0] = (eval_if_ok($a) ? 1 : -1);
91 # print "Cond stack: @cond\n";
93 my $res = eval_if_ok("$f $a");
94 out $res if defined $res;
102 if ($t =~ /\G([^\@]+)/cgs) {
103 out $1 if $cond[0] > 0;
104 } elsif ($t =~ /\G\@\s*\n/cgs) {
105 # @ at end of line is ignored and eats the end of line
106 } elsif ($t =~ /\G\@#[^\n]*\n/cgs) {
107 # a comment, which is ignored
108 } elsif ($t =~ /\G\@\@/cgs) {
109 out "\@" if $cond[0] > 0;
110 } elsif ($t =~ /\G\@{/cgs) {
111 my $x = get_nested(\$t, "{", "}");
113 } elsif ($t =~ /\G\@\[/cgs) {
114 my $x = get_nested(\$t, '\[', '\]');
118 } elsif ($t =~ /\G\@\(/cgs) {
119 my $x = get_nested(\$t, '\(', '\)');
122 out (defined($arguments->{$x}) ? $arguments->{$x} : "");
123 } elsif ($t =~ /\G\@(\w+)\(/cgs) {
125 my $args = get_nested(\$t, '(', ')');
126 eval_func($func, $args);
127 } elsif ($t =~ /\G\@(\w+)([^\n]*)\n/cgs) {
128 eval_func($1, "($2)");
129 } elsif ($t =~ /\G\@(\$\w+)/cgs) {
131 } elsif ($t =~ /\G(\@[^\n]*)/cgs) {
132 die "Unknown control sequence $1";
133 } elsif ($t =~ /\G$/cgs) {
135 } elsif ($t =~ /\G([^\n]*)/cgs) {
136 die "Internal parser error at $1 (pos " . pos($t) . ")";
144 my $fh = new IO::File $name;
145 die "Unable to open $name: $!" unless defined $fh;
147 { local $/; undef $/; $text = <$fh>; }
160 $#cond and die "Unterminated \@if (depth $#cond)";
163 sub process_file($;$) {
164 my ($name, $args) = @_;
170 sub process_string($;$) {
171 my ($string, $args) = @_;
173 parse_string($string);
177 ### Perl commands embedded in the templates are evaluated in this package ###
184 our $out_func = sub { print @_; };
191 UCW::Temple::eval_if_ok("\$$v = \$temp");
193 UCW::Temple::parse_file($fn);
199 (!defined($f) || @_) and die "\@load requires only one argument";
200 UCW::Temple::add_depend($f);