<p> <code> for ($offend = $pos + strlen($dynend[1]); $offend < $l; $offend++) {<br /> $c = $rest{$offend};<br /> if ($c == "\n") {<br />  $offend++;<br />  break;<br /> }<br /> if (($c != ' ') && ($c != "\t")) {<br />  $offend = $pos + strlen($dynend[1]);<br />  break;<br /> }<br />  }<br /> }<br /> // if ($debug)<br /> // $this->logwrite ("parse_internal_1: DYNAMIC BEGIN: (pos,len,beg,end) => ($pos, " . strlen($dynbeg[1]) . ", $offbeg, $offend)<br /> // This includes the contents of the REGEX_DYNEND in the output<br /> // $rest = substr ($rest, $pos);<br /> // This preserves whitespace on the END block line(s).<br /> // $rest = substr ($rest, $pos+strlen($dynend[1]));<br /> // $sub .= substr ($rest, 0, $pos);<br /> $sub .= substr ($rest, 0, $offbeg);<br /> $rest = substr ($rest, $offend);<br /> // Already loaded templates will not be reloaded. The<br /> // 'clear' test was actually hiding a bug in the clear()<br /> // logic....<br /> if (false && isset($this->TEMPLATE[$dynend[2]]['clear'])<br /> && $this->TEMPLATE[$dynend[2]]['clear']) {<br />  $this->TEMPLATE[$dynend[2]]['string'] = '';<br />  $this->TEMPLATE[$dynend[2]]['result'] = '';<br />  $this->TEMPLATE[$dynend[2]]['part'] =<br /> $this->parse_internal_1 ($dynend[2], ' ');<br /> } else if (!isset($this->TEMPLATE[$dynend[2]]['loaded'])<br />  || !$this->TEMPLATE[$dynend[2]]['loaded']) {<br />  // Omit pathological case of empty dynamic template.<br />  if (strlen($sub) > 0) {<br /> $this->TEMPLATE[$dynend[2]]['string'] = $sub;<br /> $this->TEMPLATE[$dynend[2]]['part']  =<br />  $this->parse_internal_1 ($dynend[2], $sub);<br /> $this->TEMPLATE[$dynend[2]]['part']['parent'] = $tag;<br />  }<br /> }<br /> $this->TEMPLATE[$dynend[2]]['loaded'] = true;<br /> $part[] = &$this->TEMPLATE[$dynend[2]];<br /> $this->TEMPLATE[$dynend[2]]['tag'] = $dynend[2];<br /> break;<br />  } else {<br /> $sub .= substr ($rest, 0, $pos+strlen($dynend[1]));<br /> $rest = substr ($rest, $pos+strlen($dynend[1]));<br /> if ($debug)<br />  $this->logwrite ("parse_internal_1: $dynbeg[2] != $dynend[2]");<br />  }<br /> }<br /> if (!$found) {<br />  $this->error ("malformed dynamic template, missing END<BR />\n" .<br />  "$dynbeg[1]<BR />\n", true);<br /> }<br />  } else {<br /> // Although it would appear to make sense to check that we don't<br /> // have a dangling END block, we will, in fact, ALWAYS appear to<br /> // have a dangling END block. We stuff the BEGIN string in the<br /> // part before the inferior template and the END string in the<br /> // part after the inferior template. So for this test to work,<br /> // we would need to look just past the final match.<br /> if (preg_match ($this->REGEX_DYNEND, $rest, $dynend)) {<br />  // $this->error ("malformed dynamic template, dangling END<BR />\n" .<br />  // "$dynend[1]<BR />\n", 1);<br /> }<br /> $part[] = $rest;<br /> $rest = '';<br />  }<br /> }<br /> return $part;<br />  }<br />  //<br />  // Description<br />  // Parse the template. If $tag is actually an array, we iterate over<br />  // the array elements. If it is a simple string tag, we may still<br />  // recursively parse the template if it contains dynamic templates and<br />  // we are configured to automatically load those as well.<br />  //<br />  function parse_internal ($tag) {<br /> $debug = $this->DEBUGALL || $this->DEBUG['parse_internal'];<br /> $append = false;<br /> if ($debug)<br />  $this->logwrite ("parse_internal (tag=$tag)");<br /> // If we are handed an array of tags, iterate over all of them. This<br /> // is really a holdover from the way class.FastTemplate.php3 worked;<br /> // I think subst() already pulls that array apart for us, so this<br /> // should not be necessary unless someone calls the internal member<br /> // function directly.<br /> if (gettype($tag) == 'array') {<br />  reset ($tag);<br />  foreach ($tag as $t) {<br /> $this->parse_internal ($t);<br />  }<br /> } else {<br />  // Load the file if it hasn't already been loaded. It might be<br />  // nice to put in some logic that reloads the file if it has<br />  // changed since we last loaded it, but that probably gets way too<br />  // complicated and only makes sense if we start keeping it floating<br />  // around between page loads as a persistent variable.<br />  if (!isset($this->TEMPLATE[$tag]['loaded'])) {<br /> if ($this->TEMPLATE[$tag]['dynamic']) {<br />  // Template was declared via define_dynamic().<br />  if ($this->TEMPLATE[$tag]['parent'])<br /> $tag = $this->TEMPLATE[$tag]['parent'];<br />  else {<br /> // Try to find a non-dynamic template with the same file.<br /> // This would have been defined via define(array(), true)<br /> reset ($this->TEMPLATE);<br /> foreach (array_keys($this->TEMPLATE) as $ptag) {<br />  if ($debug)<br /> $this->logwrite ("parse_internal: looking for non-dynamic parent, $ptag");<br />  if (!$this->TEMPLATE[$ptag]['dynamic']<br />  && ($this->TEMPLATE[$ptag]['file'] == $this->TEMPLATE[$tag]['file'])) {<br /> $tag = $ptag;<br /> break;<br />  }<br /> }<br />  }<br /> }<br /> $this->TEMPLATE[$tag]['string'] = &$this->load($this->TEMPLATE[$tag]['file']);<br /> $this->TEMPLATE[$tag]['loaded'] = 1;<br />  }<br />  // If we are supposed to automatically detect dynamic templates and the dynamic<br />  // flag is not set, scan the template for dynamic sections. Dynamic sections<br />  // markers have a very rigid syntax as HTML comments....<br />  if ($this->DYNAMIC) {<br /> $this->TEMPLATE[$tag]['tag'] = $tag;<br /> if (!isset($this->TEMPLATE[$tag]['parsed'])<br /> || !$this->TEMPLATE[$tag]['parsed']) {<br />  $this->TEMPLATE[$tag]['part'] = $this->parse_internal_1 ($tag, $this->TEMPLATE[$tag]['string']);<br />  $this->TEMPLATE[$tag]['parsed'] = true;<br /> }<br />  }<br /> }<br />  }<br />  //<br />  // Description<br />  // class.FastTemplate.php3 compatible interface.<br />  //<br />  // Notes<br />  // I prefer the name `subst' to `parse' since during this phase we are<br />  // really doing variable substitution into the template. However, at<br />  // some point we have to load and parse the template and `subst' will<br />  // do that as well...<br />  //<br />  function parse ($handle, $tag, $autoload = true) {<br /> return $this->subst ($handle, $tag, $autoload);<br />  }<br />  //<br />  // Description<br />  // Perform substitution on the template. We do not really recurse<br />  // downward in the sense that we do not do subsitutions on inferior<br />  // templates. For each inferior template which is a part of this<br />  // template, we insert the current value of their results.<br />  //<br />  // Notes<br />  // Do I want to make this return a reference?<br />  function subst ($handle, $tag, $autoload = true) {<br /> $append = false;<br /> $debug = $this->DEBUGALL || $this->DEBUG['subst'];<br /> $this->LAST = $handle;<br /> if ($debug)<br />  $this->logwrite ("subst (handle=$handle, tag=$tag, autoload=$autoload)");<br /> // For compatibility with FastTemplate, the results need to overwrite<br /> // for an array. This really only seems to be useful in the case of<br /> // something like<br /> //  $t->parse ('MAIN', array ('array', 'main'));<br /> // Where the 'main' template has a variable named MAIN which will be<br /> // set on the first pass (i.e., when parasing 'array') and used on the<br /> // second pass (i.e., when parsing 'main').<br /> if (gettype($tag) == 'array') {<br />  foreach (array_values($tag) as $t) {<br /> if ($debug)<br />  $this->logwrite ("subst: calling subst($handle,$t,$autoload)");<br /> $this->subst ($handle, $t, $autoload);<br />  }<br />  return $this->HANDLE[$handle];<br /> }<br /> // Period prefix means append result to pre-existing value.<br /> if (substr($tag,0,1) == '.') {<br />  $append = true;<br />  $tag = substr ($tag, 1);<br />  if ($debug)<br /> $this->logwrite ("subst (handle=$handle, tag=$tag, autoload=$autoload) in append mode");<br /> }<br /> // $this->TEMPLATE[$tag] will only be set if it was explicitly<br /> // declared via define(); i.e., inferior templates will not have an<br /> // entry.<br /> if (isset($this->TEMPLATE[$tag])) {<br />  if (!isset($this->TEMPLATE[$tag]['parsed'])<br />  || !$this->TEMPLATE[$tag]['parsed'])<br /> $this->parse_internal ($tag);<br /> } else {<br />  if (!$this->DYNAMIC) {<br /> $this->error ("subst (handle=$handle, tag=$tag, autoload=$autoload): " .<br /> 'no such tag and dynamic templates are turned off', true);<br />  }<br />  if ($autoload) {<br /> if ($debug)<br />  $this->logwrite ("subst: TEMPLATE[tag=$tag] not found, trying autoload");<br /> foreach (array_keys($this->TEMPLATE) as $t) {<br />  if ($debug)<br /> $this->logwrite ("subst: calling parse_internal (tag=$t)");<br />  if (!isset($this->TEMPLATE[$tag]['parsed'])<br />  || !$this->TEMPLATE[$tag]['parsed'])<br /> $this->parse_internal ($t);<br /> }<br /> if ($debug)<br />  $this->logwrite ('subst: retrying with autoload = false');<br /> $this->subst ($handle, $tag, false);<br /> if ($debug)<br />  $this->logwrite ('subst: completed with autoload = false');<br /> return;<br />  } else {<br /> $this->error ("subst (handle=$handle, tag=$tag, autoload=$autoload): no such tag", true);<br />  }<br /> }<br /> if (!$append) {<br />  $this->TEMPLATE[$tag]['result'] = '';<br />  if ($debug)<br /> $this->logwrite ("subst (handle=$handle, tag=$tag, autoload=$autoload) in overwrite mode");<br /> }<br /> if ($debug)<br />  $this->logwrite ('subst: type(this->TEMPLATE[$tag][\'part\']) => ' .<br /> gettype($this->TEMPLATE[$tag]['part']));<br /> // Hmmm, clear() called before subst() seems to result in this not<br /> // being defined which leaves me a bit confused....<br /> $result = '';<br /> if (isset($this->TEMPLATE[$tag]['part'])) {<br />  reset ($this->TEMPLATE[$tag]['part']);<br />  foreach (array_keys($this->TEMPLATE[$tag]['part']) as $p) {<br /> if ($debug)<br />  $this->logwrite ("subst: looking at TEMPLATE[$tag]['part'][$p]");<br /> $tmp = $this->TEMPLATE[$tag]['part'][$p];<br /> // Don't try if ($p == 'parent')....<br /> if (strcmp ($p, 'parent') == 0) {<br />  if ($debug)<br /> $this->logwrite ("subst: skipping part $p");<br />  $tmp = '';<br /> } else if (gettype($this->TEMPLATE[$tag]['part'][$p]) == 'string') {<br />  if ($debug)<br /> $this->logwrite ("subst: using part $p");<br />  reset ($this->VAR);<br />  // Because we treat VAR and HANDLE separately (unlike<br />  // class.FastTemplate.php3), we have to iterate over both or we<br />  // miss some substitutions and are not 100% compatible.<br />  while (list($key,$val) = each ($this->VAR)) {<br /> if ($debug)<br />  $this->logwrite ("subst: substituting VAR $key = $val in $tag");<br /> $key = '{'.$key.'}';<br /> $tmp = str_replace ($key, $val, $tmp);<br />  }<br />  reset ($this->HANDLE);<br />  while (list($key,$val) = each ($this->HANDLE)) {<br /> if ($debug)<br />  $this->logwrite ("subst: substituting HANDLE $key = $val in $tag");<br /> $key = '{'.$key.'}';<br /> $tmp = str_replace ($key, $val, $tmp);<br />  }<br />  $result .= $tmp;<br /> } else {<br />  $xtag = $this->TEMPLATE[$tag]['part'][$p]['tag'];<br />  if ($debug) {<br /> $this->logwrite ("subst: substituting other tag $xtag result in $tag");<br />  }<br />  // The assignment is a no-op if the result is not set, but when<br />  // E_ALL is in effect, a warning is generated without the<br />  // isset() test.<br />  if (isset ($this->TEMPLATE[$xtag]['result']))<br /> $result .= $this->TEMPLATE[$xtag]['result'];<br /> }<br />  }<br /> }<br /> if ($this->STRICT) {<br />  // If quiet-mode is turned on, skip the check since we're not going<br />  // to do anything anyway.<br />  if (!$this->QUIET) {<br /> if (preg_match ($this->REGEX_VAR, $result)) {<br />  $this->error ("<B>unmatched tags still present in $tag</B><BR />");<br /> }<br />  }<br /> } else {<br />  $result = preg_replace ($this->REGEX_VAR, '', $result);<br /> }<br /> if ($append) {<br />  if ($debug) {<br /> $this->logwrite ("subst: appending TEMPLATE[$tag]['result'] = $result");<br /> $this->logwrite ("subst: old HANDLE[$handle] = {$this->HANDLE[$handle]}");<br /> $this->logwrite ("subst: old TEMPLATE[$tag]['result'] = {$this->TEMPLATE[$tag]['result']}");<br />  }<br />  // The isset() tests are to suppresss warning when E_ALL is in effect<br />  // and the variables have not actually been set yet (even though the<br />  // user specified append-mode).<br />  if (isset ($this->HANDLE[$handle]))<br /> $this->HANDLE[$handle] .= $result;<br />  else<br /> $this->HANDLE[$handle] = $result;<br />  if (isset ($this->TEMPLATE[$tag]['result']))<br /> $this->TEMPLATE[$tag]['result'] .= $result;<br />  else<br /> $this->TEMPLATE[$tag]['result'] = $result;<br />  if ($debug) {<br /> $this->logwrite ("subst: new HANDLE[$handle] = {$this->HANDLE[$handle]}");<br /> $this->logwrite ("subst: new TEMPLATE[$tag]['result'] = {$this->TEMPLATE[$tag]['result']}");<br />  }<br /> } else {<br />  if ($debug)<br /> $this->logwrite ("subst: setting TEMPLATE[$tag]['result'] = $result");<br />  $this->HANDLE[$handle] = $result;<br />  $this->TEMPLATE[$tag]['result'] = $result;<br /> }<br /> return $this->HANDLE[$handle];<br />  }<br />  //<br />  // Description<br />  // Clear a block from a template. The intent is to remove an inferior<br />  // template from a parent. This works even if the template has already<br />  // been parsed since we go straight to the specified template and clear<br />  // the results element. If the given template has not yet been<br />  // loaded, the load is forced by calling parse_internal().<br />  //<br />  function clear_dynamic ($tag = NULL) {<br /> $debug = $this->DEBUGALL || $this->DEBUG['clear_dynamic'];<br /> if (is_null ($tag)) {<br />  // Clear all result elements. Uhm, needs to be tested.<br />  if ($debug)<br /> $this->logwrite ("clear_dynamic (NULL)");<br />  foreach (array_values ($this->TEMPLATE) as $t) {<br /> $this->clear_dynamic ($t);<br />  }<br />  return;<br /> } else if (gettype($tag) == 'array') {<br />  if ($debug)<br /> $this->logwrite ("clear_dynamic ($tag)");<br />  foreach (array_values($tag) as $t) {<br /> $this->clear_dynamic ($t);<br />  }<br />  return;<br /> }<br /> else if (!isset($this->TEMPLATE[$tag])) {<br />  if ($debug)<br /> $this->logwrite ("clear_dynamic ($tag) --> $tag not set, calling parse_internal");<br />  $this->parse_internal ($tag);<br />  // $this->TEMPLATE[$tag] = array ();<br /> }<br /> if ($debug)<br />  $this->logwrite ("clear_dynamic ($tag)");<br /> // $this->TEMPLATE[$tag]['loaded'] = true;<br /> // $this->TEMPLATE[$tag]['string'] = '';<br /> $this->TEMPLATE[$tag]['result'] = '';<br /> // $this->TEMPLATE[$tag]['clear']  = true;<br />  }<br />  //<br />  // Description<br />  // Clear the results of a handle set by parse(). The input handle can<br />  // be a single value, an array, or the PHP constant NULL. For the<br /></p>