+
+# (Recursively) resolve conditinal includes <?...>...</?>.
+# Expects two arguments: The (part of the) template we are expanding and
+# wether or not this part will be displayed. When this last argument is false,
+# this part of the template will not be displayed, but is still parsed to
+# properly resolve nested conditions.
+#
+# This will resolve and substitute all conditionals on the "current level".
+# This effectively means, the routine will search for and resolve all tags it
+# finds (with proper nesting), until it finds a closing tag (</?>) for which
+# it has not seen the opening tag, or there are no more opening tags in the
+# file.
+#
+# This function will return the template with all conditionals on the current
+# level resolved. This will guarantee that if there are any opening or closing
+# tags left in the template, the first one will be a closing tag (which can
+# then be resolved in the upper level).
+sub _resolve_nested {
+ my $template = shift;
+ my $display = shift;
+
+ while (1) {
+ if ($template !~ /(.*?)<\?(\!?\$\w+(?:::\w+)*)(?:\s+?(.+?))?>(.*)/s) {
+ return $template; # No open tags, normal text
+ }
+
+ my $head = $1;
+ my $var = $2;
+ my $attr = $3;
+ my $tail = $4;
+
+ if ($head =~ /<\/\?>/s) {
+ return $template; # There is a closing tag before the first open tag,
+ # we're done.
+ }
+
+ my $displayitem = $display;
+ if ($displayitem) { # Don't care about these tests if we're not displayed anyway.
+ my $negated = ($var =~ s/^\!//); # Remove negation mark
+ if ($negated || !$attr) {
+ if ($attr) {
+ warn("<?!$var $attr>: Negated expression can't have attributes, ignoring them.");
+ }
+ $displayitem = eval("defined $var");
+ if ($negated) { $displayitem = !$displayitem; }
+ } else {
+ $displayitem = _test(eval($var), $attr);
+ }
+ }
+
+
+ $tail = _resolve_nested($tail, $displayitem);
+
+ if ($tail !~ /<\/\?>/s) { # Is there no closing tag?
+ warn("Invalid nesting: <?$var $attr> missing closing tag.");
+ }
+ if ($displayitem)
+ {
+ $tail =~ s/<\/\?>//s; # Remove the closing tag
+ } else {
+ $tail =~ s/.*?<\/\?>//s; # Remove up to the closing tag
+ }
+ $template = $head . $tail;
+ }
+ return $template;
+}
+
+