// // Description // Recursive internal parse routine. This will recursively parse a // template containing dynamic inferior templates. Each of these // inferior templates gets their own entry in the TEMPLATE array. // function &parse_internal_1 ($tag, $rest = ) { $debug = $this->DEBUGALL || $this->DEBUG[parse_internal_1]; if (empty($tag)) { $this->error ("parse_internal_1: empty tag invalid", true); } if ($debug) $this->logwrite ("parse_internal_1 (tag=$tag, rest=$rest)"); while (!empty($rest)) { if ($debug) $this->logwrite (parse_internal_1: REGEX_DYNBEG search: rest => . $rest); if (preg_match ($this->REGEX_DYNBEG, $rest, $dynbeg)) { // Found match, now split into two pieces and search the second // half for the matching END. The string which goes into the // next element includes the HTML comment which forms the BEGIN // block. if ($debug) $this->logwrite (parse_internal_1: match beg => . $dynbeg[1]); $pos = strpos ($rest, $dynbeg[1]); // See if the text on either side of the BEGIN comment is only // whitespace. If so, we delete the entire line. $okay = false; for ($offbeg = $pos - 1; $offbeg >= 0; $offbeg--) { $c = $rest{$offbeg}; if ($c == "
") { $okay = true; $offbeg++; break; } if (($c != ) && ($c != " ")) { $offbeg = $pos; break; } } if (! $okay) { $offend = $pos + strlen($dynbeg[1]); } else { $l = strlen ($rest); for ($offend = $pos + strlen($dynbeg[1]); $offend < $l; $offend++) { $c = $rest{$offend}; if ($c == "
") { $offend++; break; } if (($c != ) && ($c != " ")) { $offend = $pos + strlen($dynbeg[1]); break; } } } // This includes the contents of the REGEX_DYNBEG in the output // $part[] = substr ($rest, 0, $pos); // This preserves whitespace on the END block line(s). // $part[] = substr ($rest, 0, $pos+strlen($dynbeg[1])); // $rest = substr ($rest, $pos+strlen($dynbeg[1])); // Catch case where BEGIN block is at position 0. if ($offbeg > 0) $part[] = substr ($rest, 0, $offbeg); $rest = substr ($rest, $offend); $sub = ; if ($debug) $this->logwrite ("parse_internal_1: found at pos = $pos"); // Okay, here we are actually NOT interested in just the next // END block. We are only interested in the next END block that // matches this BEGIN block. This is not the most efficient // because we really could do this in one pass through the // string just marking BEGIN and END blocks. But the recursion // makes for a simple algorithm (if there was a reverse // preg...). $found = false; while (preg_match ($this->REGEX_DYNEND, $rest, $dynend)) { if ($debug) $this->logwrite (parse_internal_1: REGEX_DYNEND search: rest => . $rest); if ($debug) $this->logwrite (parse_internal_1: match beg => . $dynend[1]); $pos = strpos ($rest, $dynend[1]); if ($dynbeg[2] == $dynend[2]) { $found = true; // See if the text on either side of the END comment is // only whitespace. If so, we delete the entire line. $okay = false; for ($offbeg = $pos - 1; $offbeg >= 0; $offbeg--) { $c = $rest{$offbeg}; if ($c == "
") { $offbeg++; $okay = true; break; } if (($c != ) && ($c != " ")) { $offbeg = $pos; break; } } if (! $okay) { $offend = $pos + strlen($dynend[1]); } else { $l = strlen ($rest); for ($offend = $pos + strlen($dynend[1]); $offend < $l; $offend++) { $c = $rest{$offend}; if ($c == "
") { $offend++; break; } if (($c != ) && ($c != " ")) { $offend = $pos + strlen($dynend[1]); break; } } } // if ($debug) // $this->logwrite ("parse_internal_1: DYNAMIC BEGIN: (pos,len,beg,end) => ($pos, " . strlen($dynbeg[1]) . ", $offbeg, $offend) // This includes the contents of the REGEX_DYNEND in the output // $rest = substr ($rest, $pos); // This preserves whitespace on the END block line(s). // $rest = substr ($rest, $pos+strlen($dynend[1])); // $sub .= substr ($rest, 0, $pos); $sub .= substr ($rest, 0, $offbeg); $rest = substr ($rest, $offend); // Already loaded templates will not be reloaded. The // clear test was actually hiding a bug in the clear() // logic.... if (false && isset($this->TEMPLATE[$dynend[2]][clear]) && $this->TEMPLATE[$dynend[2]][clear]) { $this->TEMPLATE[$dynend[2]][string] = ; $this->TEMPLATE[$dynend[2]][result] = ; $this->TEMPLATE[$dynend[2]][part] = $this->parse_internal_1 ($dynend[2], ); } else if (!isset($this->TEMPLATE[$dynend[2]][loaded]) || !$this->TEMPLATE[$dynend[2]][loaded]) { // Omit pathological case of empty dynamic template. if (strlen($sub) > 0) { $this->TEMPLATE[$dynend[2]][string] = $sub; $this->TEMPLATE[$dynend[2]][part] = $this->parse_internal_1 ($dynend[2], $sub); $this->TEMPLATE[$dynend[2]][part][parent] = $tag; } } $this->TEMPLATE[$dynend[2]][loaded] = true; $part[] = &$this->TEMPLATE[$dynend[2]]; $this->TEMPLATE[$dynend[2]][tag] = $dynend[2]; break; } else { $sub .= substr ($rest, 0, $pos+strlen($dynend[1])); $rest = substr ($rest, $pos+strlen($dynend[1])); if ($debug) $this->logwrite ("parse_internal_1: $dynbeg[2] != $dynend[2]"); } } if (!$found) { $this->error ("malformed dynamic template, missing END
" . "$dynbeg[1]
", true); } } else { // Although it would appear to make sense to check that we dont // have a dangling END block, we will, in fact, ALWAYS appear to // have a dangling END block. We stuff the BEGIN string in the // part before the inferior template and the END string in the // part after the inferior template. So for this test to work, // we would need to look just past the final match. if (preg_match ($this->REGEX_DYNEND, $rest, $dynend)) { // $this->error ("malformed dynamic template, dangling END
" . // "$dynend[1]
", 1); } $part[] = $rest; $rest = ; } } return $part; } // // Description // Parse the template. If $tag is actually an array, we iterate over // the array elements. If it is a simple string tag, we may still // recursively parse the template if it contains dynamic templates and // we are configured to automatically load those as well. // function parse_internal ($tag) { $debug = $this->DEBUGALL || $this->DEBUG[parse_internal]; $append = false; if ($debug) $this->logwrite ("parse_internal (tag=$tag)"); // If we are handed an array of tags, iterate over all of them. This // is really a holdover from the way class.FastTemplate.php3 worked; // I think subst() already pulls that array apart for us, so this // should not be necessary unless someone calls the internal member // function directly. if (gettype($tag) == array) { reset ($tag); foreach ($tag as $t) { $this->parse_internal ($t); } } else { // Load the file if it hasnt already been loaded. It might be // nice to put in some logic that reloads the file if it has // changed since we last loaded it, but that probably gets way too // complicated and only makes sense if we start keeping it floating // around between page loads as a persistent variable. if (!isset($this->TEMPLATE[$tag][loaded])) { if ($this->TEMPLATE[$tag][dynamic]) { // Template was declared via define_dynamic(). if ($this->TEMPLATE[$tag][parent]) $tag = $this->TEMPLATE[$tag][parent]; else { // Try to find a non-dynamic template with the same file. // This would have been defined via define(array(), true) reset ($this->TEMPLATE); foreach (array_keys($this->TEMPLATE) as $ptag) { if ($debug) $this->logwrite ("parse_internal: looking for non-dynamic parent, $ptag"); if (!$this->TEMPLATE[$ptag][dynamic] && ($this->TEMPLATE[$ptag][file] == $this->TEMPLATE[$tag][file])) { $tag = $ptag; break; } } } } $this->TEMPLATE[$tag][string] = &$this->load($this->TEMPLATE[$tag][file]); $this->TEMPLATE[$tag][loaded] = 1; } // If we are supposed to automatically detect dynamic templates and the dynamic // flag is not set, scan the template for dynamic sections. Dynamic sections // markers have a very rigid syntax as HTML comments.... if ($this->DYNAMIC) { $this->TEMPLATE[$tag][tag] = $