Location: PHPKode > scripts > PclTemplate > pcltemplate.class.php
<?php
// -----------------------------------------------------------------------------
// PhpConcept Template Engine - pcltemplate.class.php
// -----------------------------------------------------------------------------
// License GNU/LGPL - Vincent Blavet - November 2006
// http://www.phpconcept.net
// -----------------------------------------------------------------------------
// Overview :
//   See http://www.phpconcept.net/pcltemplate for more information
// -----------------------------------------------------------------------------
// CVS : $Id$
// -----------------------------------------------------------------------------
  
  // ----- Global Constants
  define('PCL_TEMPLATE_VERSION', '0.1');
  define('PCL_TEMPLATE_START', '<!--(');
  define('PCL_TEMPLATE_STOP', ')-->');
  
  // ---------------------------------------------------------------------------
  // Class : PclTemplate
  // Description :
  // Attributes :
  // Methods :
  // ---------------------------------------------------------------------------
  class PclTemplate
  {
    // ----- $template_name
    // Filename of the template. When the template is not a string.
    var $template_name;
    
    // ----- $token_start & $token_stop
    // The tokens delimiters. They have default values. But can be changed
    // dynamically.
    var $token_start;
    var $token_stop;
    
    // ----- $tokens
    // The recursive array that contain the template in memory after parsing
    // The format of this array is :
    // tokens[]['type'] : Type of the token. The valid types are :
    //                    'line' : A text beetwen 2 tokens
    //                    'token' : A single reference to remplace by the real 
    //                              value.
    //                    'list' : A part of the template that will be 
    //                             associated to an array
    //                    'item' : A part of the template that will be repeated
    //                             for each element of an array
    //                    'ifempty' : A part of the template, associated to an
    //                                array that will be used if the array is
    //                                empty.
    //                    'ifnotempty' : A part of the template, associated to 
    //                                   an array that will be used if the
    //                                   array is not empty.
    //                    'if' : A part of the template that will be used if a
    //                           condition matches.
    //                    'ifnot' : A part of the template that will be used if
    //                              a condition does not match.
    // tokens[]['name'] : The name of the token to identify it. The same name
    //                    will be used in that structure that will fill the 
    //                    template.
    // tokens[]['text'] : The text that follow the token (same as 'line').    
    // tokens[]['tokens'] : Array of childs tokens
    var $tokens;
    
    // -------------------------------------------------------------------------
    // Function : PclTemplate()
    // Description :
    // -------------------------------------------------------------------------
    function PclTemplate()
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::PclTemplate', '');

      $this->template_name = '';
      $this->tokens = array();
      $this->token_start = PCL_TEMPLATE_START;
      $this->token_stop = PCL_TEMPLATE_STOP;
      
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 1);
      return;
    }
    // -------------------------------------------------------------------------
  
    // -------------------------------------------------------------------------
    // Function : changeDelimiters()
    // Description :
    // -------------------------------------------------------------------------
    function changeDelimiters($p_start_delimiter, $p_stop_delimiter)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::changeDelimiters', 'start="'.$p_start_delimiter.'", stop="'.$p_stop_delimiter.'"');
      
      $this->token_start = $p_start_delimiter;
      $this->token_stop = $p_stop_delimiter;

      $v_result=1;
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------
  
    // -------------------------------------------------------------------------
    // Function : parseFile()
    // Description :
    // -------------------------------------------------------------------------
    function parseFile($p_template)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::parseFile', 'template="'.$p_template.'"');
      $v_result = 1;
      
      $this->template_name = $p_template;
      
      $handle = @fopen($this->template_name, "r");
      if (!$handle) {
        $v_result = 0;
        //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result, "Unable to open '".$this->template_name."'");
        return($v_result);
      }

      $buffer = '';
      $v_start_token = array();
      $v_result = $this->_parse_recursive($v_start_token, $buffer, $handle);
      if ($v_result != 1) {
        //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
        return($v_result);
      }
      
      @fclose($handle);
      $this->tokens = $v_start_token['tokens'];
      
      $v_result=1;
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------
  
    // -------------------------------------------------------------------------
    // Function : parseString()
    // Description :
    // -------------------------------------------------------------------------
    function parseString($p_string)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::parseString', '');
      $v_result = 1;
      
      $buffer = '';          
      $v_start_token = array();
      $v_result = $this->_parse_recursive($v_start_token, $p_string, 0);
      if ($v_result != 1) {
        //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
        return($v_result);
      }
      
      $this->tokens = $v_start_token['tokens'];
      
      $v_result=1;
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------
  
    // -------------------------------------------------------------------------
    // Function : generate()
    // Description :
    // Arguments :
    //   $p_output : 'stdout', 'file', 'string'
    //   $p_filename : filename when 'file' is used in $p_output
    // -------------------------------------------------------------------------
    function generate($p_struct, $p_output='stdout', $p_filename='')
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::generate', 'filename="'.$p_filename.'"');
      $v_result = 1;
      
      $fd = 0;
      if ($p_output == 'file') {
        if (!($fd = @fopen($p_filename, "w"))) {
          $v_result = 0;
          //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result, 'unable to open file "'.$p_filename.'"');
          return($v_result);
        }
      }
      
      // TBC : look for file to open
      $v_result = $this->_generate($this->tokens, $p_struct, $p_output, $fd);

      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------
    
    // -------------------------------------------------------------------------
    // Function : _generate()
    // Description :
    // Arguments :
    //   $p_output : 'stdout', 'file', 'string'
    //   $p_fd : file descriptor when $p_output='file'
    // -------------------------------------------------------------------------
    function _generate($p_token_list, $p_struct, $p_output='stdout', $p_fd=0)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::_generate', '');
      $v_result = '';
      $v_global_result = '';
      
      foreach ($p_token_list as $v_token) {
        //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Look for token type '".$v_token['type']."'");
        $v_string = '';
        switch ($v_token['type']) {
          case 'line' :
            $v_string = $v_token['text'];
          break;
          case 'token' :
            // ----- Search for list with matching name
            $v_value = $this->_find_token($v_token['name'], $p_struct);
            
            // ----- Check that value is a string
            if (is_string($v_value)) {
              // ----- Add the value
              $v_string = $v_value;
            }
            else if ($v_value !== FALSE) {
              // ----- Add the value
              $v_string = (string)$v_value;
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid value for token '".$v_token['name']."'");
            }
          break;
          case 'list' :
            // ----- Search for list with matching name
            $v_value = $this->_find_token($v_token['name'], $p_struct);
            
            // ----- Check that value is an array
            if (is_array($v_value)) {
              $v_string = $this->_generate_list($v_token['tokens'], $v_value, $p_output, $p_fd);
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid value for token '".$v_token['name']."', or empty list");
              //$v_string = $this->_generate_list($v_token['tokens'], array(), $p_output, $p_fd);
            }
          break;
          case 'if' :
            // ----- Search for list with matching name
            $v_value = $this->_find_token($v_token['name'], $p_struct);
            
            // ----- Check that value is an array
            if ($v_value !== FALSE) {
              $v_string = $this->_generate($v_token['tokens'], $v_value, $p_output, $p_fd);
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "No value for token '".$v_token['name']."'");
            }
          break;
          case 'ifnot' :
            // ----- Search for list with matching name
            $v_value = $this->_find_token($v_token['name'], $p_struct);
            
            // ----- Check that value is an array
            if ($v_value === FALSE) {
              $v_string = $this->_generate($v_token['tokens'], $v_value, $p_output, $p_fd);
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Value for token '".$v_token['name']."'");
            }
          break;
          default :
            //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "No rule to manage '".$v_token['type']."'");
          break;
        }
      
        switch ($p_output) {
          case 'stdout' :
            echo $v_string;
          break;
          case 'file' :
            @fwrite($p_fd, $v_string);
          break;
          case 'string' :
            $v_global_result .= $v_string;
          break;
          default :
            // TBC : Invalid value
          break;
        }
      }

      $v_result = $v_global_result;
      
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------
    
    // -------------------------------------------------------------------------
    // Function : _generate_list()
    // Description :
    // Arguments :
    //   $p_outout : 'stdout', 'file', 'string'
    //   $p_fd : file descriptor when $p_output='file'
    // -------------------------------------------------------------------------
    function _generate_list($p_token_list, $p_struct, $p_output='stdout', $p_fd=0)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::_generate_list', '');
      $v_result = '';
      $v_global_result = '';
      
      foreach ($p_token_list as $v_token) {
        //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Look for token type '".$v_token['type']."'");
        $v_string = '';
        switch ($v_token['type']) {
          case 'line' :
            $v_string = $v_token['text'];
          break;
          case 'token' :
            // ----- Search for list with matching name
            $v_value = $this->_find_token($v_token['name'], $p_struct);
            
            // ----- Check that value is a string
            if (is_string($v_value)) {
              // ----- Add the value
              $v_string = $v_value;
            }
            else if ($v_value !== FALSE) {
              // ----- Add the value
              $v_string = (string)$v_value;
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Invalid value for token '".$v_token['name']."'");
            }
          break;
          case 'ifempty' :
            if (sizeof($p_struct) == 0) {
              $v_value = $this->_find_token($v_token['name'], $p_struct);
              if (is_array($v_value)) {
                $v_string = $this->_generate($v_token['tokens'], $v_value, $p_output, $p_fd);
              }
              else {
                $v_string = $this->_generate($v_token['tokens'], array(), $p_output, $p_fd);
              }
            }
          break;
          case 'ifnotempty' :
            if (sizeof($p_struct) > 0) {
              $v_value = $this->_find_token($v_token['name'], $p_struct);
              if (is_array($v_value)) {
                $v_string = $this->_generate($v_token['tokens'], $v_value, $p_output, $p_fd);
              }
              else {
                $v_string = $this->_generate($v_token['tokens'], array(), $p_output, $p_fd);
              }
            }
          break;
          case 'item' :
            foreach ($p_struct as $v_elt) {
                $v_string .= $this->_generate($v_token['tokens'], $v_elt, $p_output, $p_fd);              
            }
          break;
          case 'if' :
            // ----- Search for list with matching name
            $v_value = $this->_find_token($v_token['name'], $p_struct);
            
            // ----- Check that value is an array
            if ($v_value !== FALSE) {
              $v_string = $this->_generate($v_token['tokens'], $v_value, $p_output, $p_fd);
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "No value for token '".$v_token['name']."'");
            }
          break;
          case 'ifnot' :
            // ----- Search for list with matching name
            $v_value = $this->_find_token($v_token['name'], $p_struct);
            
            // ----- Check that value is an array
            if ($v_value === FALSE) {
              $v_string = $this->_generate($v_token['tokens'], $v_value, $p_output, $p_fd);
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Value for token '".$v_token['name']."'");
            }
          break;
          default :
          break;
        }
      
        switch ($p_output) {
          case 'stdout' :
            echo $v_string;
          break;
          case 'file' :
            @fwrite($p_fd, $v_string);
          break;
          case 'string' :
            $v_global_result .= $v_string;
          break;
          default :
            // TBC : Invalid value
          break;
        }
      }
      
      $v_result = $v_global_result;

      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------
    
    // -------------------------------------------------------------------------
    // Function : _find_token()
    // Description :
    // Arguments :
    // -------------------------------------------------------------------------
    function _find_token($p_token_name, $p_struct)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::_find_token', 'token="'.$p_token_name.'"');
      
      if (!is_array($p_struct)) {
        $v_result = FALSE;
        //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result, "argument is not an array");
        return($v_result);
      }
      
      if (isset($p_struct[$p_token_name])) {
          //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 1, "found by direct index");
          return($p_struct[$p_token_name]);
      }
      
      foreach ($p_struct as $v_key => $v_item) {
        //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Look for value with key '".$v_key."'");
        if (strtolower($v_key) == $p_token_name) {
          //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, 1, "found by strtolower");
          return($v_item);
        }
      }

      $v_result = FALSE;
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result, "not found");
      return($v_result);
    }
    // -------------------------------------------------------------------------
    
    // -------------------------------------------------------------------------
    // Function : _is_keyword()
    // Description :
    // Arguments :
    // -------------------------------------------------------------------------
    function _is_keyword($p_token)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::_is_keyword', 'token="'.$p_token.'"');
      $v_pcltemplate_keywords = array(
                                  'token',
                                  'list', 'endlist',
                                  'item', 'enditem',
                                  'ifnotempty', 'endifnotempty',
                                  'ifempty', 'endifempty',
                                  'if', 'endif',
                                  'ifnot', 'endifnot');
      $v_result = in_array($p_token, $v_pcltemplate_keywords);
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------
    
    // -------------------------------------------------------------------------
    // Function : _parse_recursive()
    // Description :
    // -------------------------------------------------------------------------
    function _parse_recursive(&$p_token, &$p_buffer, $p_fd=0)
    {
      //--(MAGIC-PclTrace)--//PclTraceFctStart(__FILE__, __LINE__, 'PclTemplate::_parse_recursive', '');
      $v_result = 1;
      
      $buffer = $p_buffer;
      $v_token_list = array();
      $v_current_index = 0;
      $v_token_list[$v_current_index]['type'] = 'line';
      $v_token_list[$v_current_index]['text'] = '';
      do {
           
        if (($v_pos = strpos($buffer,$this->token_start)) === FALSE) {
          //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Line has no token");
          $v_token_list[$v_current_index]['text']  .= $buffer; 
          $buffer = '';          
        }
        else {
          //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Token found at '".$v_pos."'");
          $v_token_list[$v_current_index]['text']  .= substr($buffer, 0, $v_pos);
          $v_pos2 = strpos($buffer, $this->token_stop);
          ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Line : '".htmlentities($buffer)."' end at ".$v_pos2);
          $v_pos += strlen($this->token_start);
          $v_token = strtolower(substr($buffer, $v_pos, $v_pos2-$v_pos));     
          $v_pos2 += strlen($this->token_stop);
          //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "token is '".htmlentities($v_token)."'");
          $buffer = substr($buffer, $v_pos2);
          
          // ----- Parse the token structure & Create the new token
          $v_current_index++;
          if (strpos($v_token, ":") === FALSE) {
            // ----- Look if $v_token is a reserved keyword
            // If not then by default the type is 'token',
            // If yes, then it is a token with no name
            if ($this->_is_keyword($v_token)) {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "token is reserved keyword");
              $v_token_list[$v_current_index]['type'] = $v_token;
              $v_token_list[$v_current_index]['name'] = '';
              $v_tok = $v_token;
            }
            else {
              //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "value is not a reserved keyword, type is set to 'token'");
              $v_token_list[$v_current_index]['type'] = 'token';
              $v_token_list[$v_current_index]['name'] = $v_token;
              $v_tok = 'token';
            }
          }
          else {
            // ----- Separate token type from token name
            list($v_tok,$v_name) = explode(":", $v_token);
            //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "short token is '".htmlentities($v_tok)."'");
            //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "short name is '".htmlentities($v_name)."'");
            $v_token_list[$v_current_index]['type'] = $v_tok;
            $v_token_list[$v_current_index]['name'] = $v_name;
          }
            
            switch ($v_tok) {
              case 'token' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");          
              break;

              case 'list.start' :
              case 'list' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");          
                $v_token_list[$v_current_index]['type'] = 'list';
                $v_result = $this->_parse_recursive($v_token_list[$v_current_index], $buffer, $p_fd);
                $p_buffer = $buffer;
                if ($v_result != 1) {
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
              break;

              case 'list.stop' :
              case 'endlist' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'list') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected list parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }

                // ----- Not a new token, but end of current list
                unset($v_token_list[$v_current_index]);
                $p_token['tokens'] = $v_token_list;                
                $p_buffer = $buffer;
                $v_result=1;
                //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                return($v_result);      
              break;

              case 'list.empty.start' :
              case 'ifempty' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");          
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'list') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected list parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
                $v_token_list[$v_current_index]['type'] = 'ifempty';
                $v_result = $this->_parse_recursive($v_token_list[$v_current_index], $buffer, $p_fd);
                $p_buffer = $buffer;
                if ($v_result != 1) {
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
              break;

              case 'list.empty.stop' :
              case 'endifempty' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'ifempty') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected empty parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }

                // ----- Not a new token, but end of current list
                unset($v_token_list[$v_current_index]);
                $p_token['tokens'] = $v_token_list;                
                $p_buffer = $buffer;
                $v_result=1;
                //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                return($v_result);      
              break;

              case 'list.notempty.start' :
              case 'ifnotempty' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");          
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'list') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected list parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
                $v_token_list[$v_current_index]['type'] = 'ifnotempty';
                $v_result = $this->_parse_recursive($v_token_list[$v_current_index], $buffer, $p_fd);
                $p_buffer = $buffer;
                if ($v_result != 1) {
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
              break;

              case 'list.notempty.stop' :
              case 'endifnotempty' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'ifnotempty') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected ifnotempty parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }

                // ----- Not a new token, but end of current list
                unset($v_token_list[$v_current_index]);
                $p_token['tokens'] = $v_token_list;                
                $p_buffer = $buffer;
                $v_result=1;
                //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                return($v_result);      
              break;

              case 'list.item.start' :
              case 'item' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");          
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'list') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected list parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
                $v_token_list[$v_current_index]['type'] = 'item';
                $v_result = $this->_parse_recursive($v_token_list[$v_current_index], $buffer, $p_fd);
                $p_buffer = $buffer;
                if ($v_result != 1) {
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
              break;

              case 'list.item.stop' :
              case 'enditem' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'item') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected item parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }

                // ----- Not a new token, but end of current list
                unset($v_token_list[$v_current_index]);
                $p_token['tokens'] = $v_token_list;                
                $p_buffer = $buffer;
                $v_result=1;
                //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                return($v_result);      
              break;

              case 'if.start' :
              case 'if' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");          
                $v_token_list[$v_current_index]['type'] = 'if';
                $v_result = $this->_parse_recursive($v_token_list[$v_current_index], $buffer, $p_fd);
                $p_buffer = $buffer;
                if ($v_result != 1) {
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
              break;

              case 'if.stop' :
              case 'endif' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'if') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected 'if' parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }

                // ----- Not a new token, but end of current if
                unset($v_token_list[$v_current_index]);
                $p_token['tokens'] = $v_token_list;                
                $p_buffer = $buffer;
                $v_result=1;
                //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                return($v_result);      
              break;

              case 'ifnot.start' :
              case 'ifnot' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");          
                $v_token_list[$v_current_index]['type'] = 'ifnot';
                $v_result = $this->_parse_recursive($v_token_list[$v_current_index], $buffer, $p_fd);
                $p_buffer = $buffer;
                if ($v_result != 1) {
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }
              break;

              case 'ifnot.stop' :
              case 'endifnot' :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Valid token type '".$v_tok."' found");
                // ----- Check that the parent token is a list with same name
                if ($p_token['type'] != 'ifnot') {
                  //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Template parse error : expected 'ifnot' parent");
                  $v_result=-1;
                  //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                  return($v_result);      
                }

                // ----- Not a new token, but end of current if
                unset($v_token_list[$v_current_index]);
                $p_token['tokens'] = $v_token_list;                
                $p_buffer = $buffer;
                $v_result=1;
                //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
                return($v_result);      
              break;

              default :
                //--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "Unknown token type '".$v_tok."', replacing by token");          
                $v_token_list[$v_current_index]['type'] = 'token';
            }
          
          // TBC : can be removed ... A token other than line may not have text
          $v_token_list[$v_current_index]['text'] = '';

          $v_current_index++;
          $v_token_list[$v_current_index]['type'] = 'line';
          $v_token_list[$v_current_index]['text'] = '';

          ////--(MAGIC-PclTrace)--//PclTraceFctMessage(__FILE__, __LINE__, 3, "current line : '".htmlentities($v_current_line)."'");
        }
        
        if (($buffer == '') && ($p_fd != 0)) {
          $buffer = fgets($p_fd, 4096);
        }
        
      } while (   ($buffer != '') && ($buffer !== FALSE)
               && (($p_fd == 0) || (!feof($p_fd))));
      
      $p_buffer = $buffer;
      $p_token['tokens'] = $v_token_list;
      
      $v_result=1;
      //--(MAGIC-PclTrace)--//PclTraceFctEnd(__FILE__, __LINE__, $v_result);
      return($v_result);
    }
    // -------------------------------------------------------------------------  

  }
  // ---------------------------------------------------------------------------
?>
Return current item: PclTemplate