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<BR />
" .
"$dynbeg[1]<BR />
", true);
}
} else {
// Although it would appear to make sense to check that we don't
// 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<BR />
" .
//
"$dynend[1]<BR />
", 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 hasn't 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']
= $tag;
if (!isset($this->TEMPLATE[$tag]['parsed'])
|| !$this->TEMPLATE[$tag]['parsed']) {
$this->TEMPLATE[$tag]['part'] = $this->parse_internal_1 ($tag, $this->TEMPLATE[$tag]['string']);
$this->TEMPLATE[$tag]['parsed'] = true;
}
}
}
}
//
// Description
//
class.FastTemplate.php3 compatible interface.
//
// Notes
//
I prefer the name `subst' to `parse' since during this phase we are
//
really doing variable substitution into the template.
However, at
//
some point we have to load and parse the template and `subst' will
//
do that as well...
//
function parse ($handle, $tag, $autoload = true) {
return $this->subst ($handle, $tag, $autoload);
}
//
// Description
//
Perform substitution on the template.
We do not really recurse
//
downward in the sense that we do not do subsitutions on inferior
//
templates.
For each inferior template which is a part of this
//
template, we insert the current value of their results.
//
// Notes
//
Do I want to make this return a reference?
function subst ($handle, $tag, $autoload = true) {
$append = false;
$debug = $this->DEBUGALL || $this->DEBUG['subst'];
$this->LAST = $handle;
if ($debug)
$this->logwrite ("subst (handle=$handle, tag=$tag, autoload=$autoload)");
// For compatibility with FastTemplate, the results need to overwrite
// for an array.
This really only seems to be useful in the case of
// something like
//
$t->parse ('MAIN', array ('array', 'main'));
// Where the 'main' template has a variable named MAIN which will be
// set on the first pass (i.e., when parasing 'array') and used on the
// second pass (i.e., when parsing 'main').
if (gettype($tag) == 'array') {
foreach (array_values($tag) as $t) {
if ($debug)
$this->logwrite ("subst: calling subst($handle,$t,$autoload)");
$this->subst ($handle, $t, $autoload);
}
return $this->HANDLE[$handle];
}
// Period prefix means append result to pre-existing value.
if (substr($tag,0,1) == '.') {
$append = true;
$tag = substr ($tag, 1);
if ($debug)
$this->logwrite ("subst (handle=$handle, tag=$tag, autoload=$autoload) in append mode");
}
// $this->TEMPLATE[$tag] will only be set if it was explicitly
// declared via define(); i.e., inferior templates will not have an
// entry.
if (isset($this->TEMPLATE[$tag])) {
if (!isset($this->TEMPLATE[$tag]['parsed'])
|| !$this->TEMPLATE[$tag]['parsed'])
$this->parse_internal ($tag);
} else {
if (!$this->DYNAMIC) {
$this->error ("subst (handle=$handle, tag=$tag, autoload=$autoload): " .
'no such tag and dynamic templates are turned off', true);
}
if ($autoload) {
if ($debug)
$this->logwrite ("subst: TEMPLATE[tag=$tag] not found, trying autoload");
foreach (array_keys($this->TEMPLATE) as $t) {
if ($debug)
$this->logwrite ("subst: calling parse_internal (tag=$t)");
if (!isset($this->TEMPLATE[$tag]['parsed'])
|| !$this->TEMPLATE[$tag]['parsed'])
$this->parse_internal ($t);
}
if ($debug)
$this->logwrite ('subst: retrying with autoload = false');
$this->subst ($handle, $tag, false);
if ($debug)
$this->logwrite ('subst: completed with autoload = false');
return;
} else {
$this->error ("subst (handle=$handle, tag=$tag, autoload=$autoload):
no such tag", true);
}
}
if (!$append) {
$this->TEMPLATE[$tag]['result'] = '';
if ($debug)
$this->logwrite ("subst (handle=$handle, tag=$tag, autoload=$autoload) in overwrite mode");
}
if ($debug)
$this->logwrite ('subst: type(this->TEMPLATE[$tag]['part']) => ' .
gettype($this->TEMPLATE[$tag]['part']));
// Hmmm, clear() called before subst() seems to result in this not
// being defined which leaves me a bit confused....
$result = '';
if (isset($this->TEMPLATE[$tag]['part'])) {
reset ($this->TEMPLATE[$tag]['part']);
foreach (array_keys($this->TEMPLATE[$tag]['part']) as $p) {
if ($debug)
$this->logwrite ("subst: looking at TEMPLATE[$tag]['part'][$p]");
$tmp = $this->TEMPLATE[$tag]['part'][$p];
// Don't try if ($p == 'parent')....
if (strcmp ($p, 'parent') == 0) {
if ($debug)
$this->logwrite ("subst: skipping part $p");
$tmp = '';
} else if (gettype($this->TEMPLATE[$tag]['part'][$p]) == 'string') {
if ($debug)
$this->logwrite ("subst: using part $p");
reset ($this->VAR);
// Because we treat VAR and HANDLE separately (unlike
// class.FastTemplate.php3), we have to iterate over both or we
// miss some substitutions and are not 100% compatible.
while (list($key,$val) = each ($this->VAR)) {
if ($debug)
$this->logwrite ("subst: substituting VAR $key = $val in $tag");
$key = '{'.$key.'}';
$tmp = str_replace ($key, $val, $tmp);
}
reset ($this->HANDLE);
while (list($key,$val) = each ($this->HANDLE)) {
if ($debug)
$this->logwrite ("subst: substituting HANDLE $key = $val in $tag");
$key = '{'.$key.'}';
$tmp = str_replace ($key, $val, $tmp);
}
$result .= $tmp;
} else {
$xtag = $this->TEMPLATE[$tag]['part'][$p]['tag'];
if ($debug) {
$this->logwrite ("subst: substituting other tag $xtag result in $tag");
}
// The assignment is a no-op if the result is not set, but when
// E_ALL is in effect, a warning is generated without the
// isset() test.
if (isset ($this->TEMPLATE[$xtag]['result']))
$result .= $this->TEMPLATE[$xtag]['result'];
}
}
}
if ($this->STRICT) {
// If quiet-mode is turned on, skip the check since we're not going
// to do anything anyway.
if (!$this->QUIET) {
if (preg_match ($this->REGEX_VAR, $result)) {
$this->error ("<B>unmatched tags still present in $tag</B><BR />");
}
}
} else {
$result = preg_replace ($this->REGEX_VAR, '', $result);
}
if ($append) {
if ($debug) {
$this->logwrite ("subst: appending TEMPLATE[$tag]['result'] = $result");
$this->logwrite ("subst: old HANDLE[$handle] = {$this->HANDLE[$handle]}");
$this->logwrite ("subst: old TEMPLATE[$tag]['result'] = {$this->TEMPLATE[$tag]['result']}");
}
// The isset() tests are to suppresss warning when E_ALL is in effect
// and the variables have not actually been set yet (even though the
// user specified append-mode).
if (isset ($this->HANDLE[$handle]))
$this->HANDLE[$handle] .= $result;
else
$this->HANDLE[$handle] = $result;
if (isset ($this->TEMPLATE[$tag]['result']))
$this->TEMPLATE[$tag]['result'] .= $result;
else
$this->TEMPLATE[$tag]['result'] = $result;
if ($debug) {
$this->logwrite ("subst: new HANDLE[$handle] = {$this->HANDLE[$handle]}");
$this->logwrite ("subst: new TEMPLATE[$tag]['result'] = {$this->TEMPLATE[$tag]['result']}");
}
} else {
if ($debug)
$this->logwrite ("subst: setting TEMPLATE[$tag]['result'] = $result");
$this->HANDLE[$handle]
= $result;
$this->TEMPLATE[$tag]['result'] = $result;
}
return $this->HANDLE[$handle];
}
//
// Description
//
Clear a block from a template.
The intent is to remove an inferior
//
template from a parent.
This works even if the template has already
//
been parsed since we go straight to the specified template and clear
//
the results element.
If the given template has not yet been
//
loaded, the load is forced by calling parse_internal().
//
function clear_dynamic ($tag = NULL) {
$debug = $this->DEBUGALL || $this->DEBUG['clear_dynamic'];
if (is_null ($tag)) {
// Clear all result elements.
Uhm, needs to be tested.
if ($debug)
$this->logwrite ("clear_dynamic (NULL)");
foreach (array_values ($this->TEMPLATE) as $t) {
$this->clear_dynamic ($t);
}
return;
} else if (gettype($tag) == 'array') {
if ($debug)
$this->logwrite ("clear_dynamic ($tag)");
foreach (array_values($tag) as $t) {
$this->clear_dynamic ($t);
}
return;
}
else if (!isset($this->TEMPLATE[$tag])) {
if ($debug)
$this->logwrite ("clear_dynamic ($tag) --> $tag not set, calling parse_internal");
$this->parse_internal ($tag);
// $this->TEMPLATE[$tag] = array ();
}
if ($debug)
$this->logwrite ("clear_dynamic ($tag)");
// $this->TEMPLATE[$tag]['loaded']
= true;
// $this->TEMPLATE[$tag]['string']
= '';
$this->TEMPLATE[$tag]['result'] = '';
// $this->TEMPLATE[$tag]['clear']
= true;
}
//
// Description
//
Clear the results of a handle set by parse().
The input handle can
//
be a single value, an array, or the PHP constant NULL.
For the