| // +----------------------------------------------------------------------+ // // $Id$ // // This is the master Token file for The New Token driver Engine. // All the Token output, and building routines are in here. // // Note overriden methods are not documented unless they differ majorly from // The parent. // $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['base'] = 0; $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['state'] = 0; $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['statevars'] = array(); $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['activeForm'] = ''; $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['tokens'] = array(); $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['gettextStrings'] = array(); $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['activeFormId'] = 0; $GLOBALS['_HTML_TEMPLATE_FLEXY_TOKEN']['flexyIgnore'] = false; /** * Base Class for all Tokens. * * @abstract Provides the static Create Method, and default toString() methods * */ class HTML_Template_Flexy_Token { /** * the token type (Depreciated when we have classes for all tokens * * @var string * @access public */ var $token; /** * the default value (normally a string) * * @var string * @access public */ var $value; /** * the line the token is from * * @var int * @access public */ var $line; /** * the character Position * * @var int * @access public */ var $charPos; /** * factory a Token * * Standard factory method.. - with object vars. * ?? rename me to factory? * @param string Token type * @param mixed Initialization settings for token * @param int line that the token is defined. * * * @return object Created Object * @access public */ function factory($token,$value,$line,$charPos=0) { // try not to reload the same class to often static $loaded = array(); $c = 'HTML_Template_Flexy_Token_'.$token; if (!class_exists($c) && !isset($loaded[$token])) { // make sure parse errors are picked up - no @ here.. if (file_exists(dirname(__FILE__)."/Token/{$token}.php")) { require_once 'HTML/Template/Flexy/Token/'.$token.'.php'; } $loaded[$token] = true; } $t = new HTML_Template_Flexy_Token; if (class_exists($c)) { $t = new $c; } $t->token = $token; $t->charPos = $charPos; if ($t->setValue($value) === false) { // kick back error conditions.. return false; } $t->line = $line; return $t; } /** * Standard Value iterpretor * * @param mixed value recieved from factory method * @return none * @access public */ function setValue($value) { $this->value = $value; } /** * compile to String (vistor method) replaces toString * * @return string HTML * @access public */ function compile(&$compiler) { return $compiler->toString($this); } /** * compile children (visitor approach). * * @return string HTML * @access public */ function compileChildren( &$compiler) { if (!$this->children) { return ''; } if ($this->ignoreChildren) { return; } $ret = ''; //echo "output $this->id"; //new Gtk_VarDump($this); foreach ($this->children as $child) { if (!$child) { continue; } $add = $child->compile($compiler); if (is_a($add,'PEAR_Error')) { return $add; } $ret .= $add; } return $ret; } /* ======================================================= */ /* Token Managmenet = parse and store all the tokens in * an associative array and tree. */ /** * Run a Tokenizer and Store its results * It should build a DOM Tree of the HTML * * @param object Tokenizer to run.. - Theoretically other Tokenizers could be done for email,rtf etc. * * @access public * @return base token (really a dummy token, which contains the tree) * @static */ function buildTokens($tokenizer) { global $_HTML_TEMPLATE_FLEXY_TOKEN; // first record is a filler - to stick all the children on ! // reset my globals.. $_HTML_TEMPLATE_FLEXY_TOKEN['base'] = 0; $_HTML_TEMPLATE_FLEXY_TOKEN['statevars'] = array(); $_HTML_TEMPLATE_FLEXY_TOKEN['state'] = 0; $_HTML_TEMPLATE_FLEXY_TOKEN['flexyIgnore'] = false; if (@$GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['flexyIgnore']) { $_HTML_TEMPLATE_FLEXY_TOKEN['flexyIgnore'] = true; } $_HTML_TEMPLATE_FLEXY_TOKEN['activeFormId'] = 0; $_HTML_TEMPLATE_FLEXY_TOKEN['activeForm'] = ''; $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'] = array(new HTML_Template_Flexy_Token); $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][0]->id =0; $_HTML_TEMPLATE_FLEXY_TOKEN['gettextStrings'] = array(); $i=1; // initialize state - this trys to make sure that // you dont do to many elses etc. //echo "RUNNING TOKENIZER"; // step one just tokenize it. while ($t = $tokenizer->yylex()) { if ($t == HTML_TEMPLATE_FLEXY_TOKEN_ERROR) { //echo "ERROR"; //print_r($tokenizer); $err = "
" . $tokenizer->error . "\n" .
                    htmlspecialchars(substr($tokenizer->yy_buffer,0,$tokenizer->yy_buffer_end)) . 
                    "". htmlspecialchars(substr($tokenizer->yy_buffer,$tokenizer->yy_buffer_end,100)) . 
                    ".......
"; return HTML_Template_Flexy::raiseError('HTML_Template_Flexy::Syntax error in ". "Template line:'. $tokenizer->yyline . $err , HTML_TEMPLATE_FLEXY_ERROR_SYNTAX ,HTML_TEMPLATE_FLEXY_ERROR_RETURN); } if ($t == HTML_TEMPLATE_FLEXY_TOKEN_NONE) { continue; } if ( $tokenizer->value->token == 'Php' ) { if (!$GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['allowPHP']) { return HTML_Template_Flexy::raiseError('PHP code found in script (Token)', HTML_TEMPLATE_FLEXY_ERROR_SYNTAX,HTML_TEMPLATE_FLEXY_ERROR_RETURN ); } if ($GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['allowPHP'] === 'delete') { continue; } } $i++; $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i] = $tokenizer->value; $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->id = $i; // this whole children thing needs rethinking // - I think the body of the page should be wrapped: .. // ?php if (!$this->bodyOnly) { .. .... ?php } ? // // old values alias to new ones.. if (isset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXYSTART'])) { unset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXYSTART']); $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXY:START'] = true; } if (isset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXYSTARTCHILDREN'])) { unset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXYSTARTCHILDREN']); $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXY:STARTCHILDREN'] = true; } if (isset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXY:START'])) { $_HTML_TEMPLATE_FLEXY_TOKEN['base'] = $i; unset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXY:START']); } if (isset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->ucAttributes['FLEXY:STARTCHILDREN'])) { $_HTML_TEMPLATE_FLEXY_TOKEN['base'] = $i; } //print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]); } //echo "BUILT TOKENS"; $res = &$_HTML_TEMPLATE_FLEXY_TOKEN['tokens']; // DEBUG DUMPTING : foreach($res as $k) { $k->dump(); } $stack = array(); $total = $i +1; // merge strings and entities - blanking out empty text. for($i=1;$i<$total;$i++) { if (!isset($res[$i]) || !is_a($res[$i],'HTML_Template_Flexy_Token_Text')) { continue; } $first = $i; $i++; while ($i<$total && is_a($res[$i],'HTML_Template_Flexy_Token_Text')) { if (isset($res[$i])) { $res[$first]->value .= $res[$i]->value; $res[$i]->value = ''; } $i++; } } // connect open and close tags. // this is done by having a stack for each of the tag types.. // then removing it when it finds the closing one // eg. // // ends up with a stack for 's and a stack for 's // // // //echo '
' . htmlspecialchars(print_R($res,true));//exit;
        //echo '
';
        for($i=1;$i<$total;$i++) {
            
            if (empty($res[$i]->tag)) {
                continue;
            }
            //echo "Checking TAG $i {$res[$i]->tag}\n";
            if ($res[$i]->tag{0} == '/') { // it's a close tag..
                //echo "GOT END TAG: {$res[$i]->tag}\n";
                $tag = strtoupper(substr($res[$i]->tag,1));
                if (!count($stack)) {
                    continue;
                }
                $ssc = count($stack) - 1;
                /* go up the stack trying to find a match */
                for($s = $ssc; $s > -1; $s--) {
                    if (!isset($stack[$s])) {
                        echo "MISSED STACK? $s
";print_r($stack);exit;
                    }
                    if (!isset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$stack[$s]])) {
                        echo "STACKED BAD OFFSET : {$stack[$s]}
";print_r($stack);exit;
                    }
                    $tok =  &$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$stack[$s]];
                    if (strtoupper($tok->tag) == $tag) {
                        // got the matching closer..
                        // echo "MATCH: {$i}:{$tok->tag}({$tok->line}) to  {$stack[$s]}:$tag
"; $tok->close = &$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]; array_splice($stack,$s); //print_R($stack); break; } } continue; } $stack[] = $i; // tag with no closer (or unmatched in stack..) } // create a dummy close for the end $i = $total; $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i] = new HTML_Template_Flexy_Token; $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->id = $total; $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][0]->close = &$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$total]; // now is it possible to connect children... // now we need to GLOBALIZE!! - $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'] = $res; HTML_Template_Flexy_Token::buildChildren(0); //new Gtk_VarDump($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][0]); //echo '
';print_R($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$_HTML_TEMPLATE_FLEXY_TOKEN['base']]  ); 
        return $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$_HTML_TEMPLATE_FLEXY_TOKEN['base']];
    }
    /**
    * Matching closing tag for a Token
    *
    * @var object|none  optional closing tag
    * @access public 
    */
    
  
    var $close;
           
    /**
    * array of children to each object. 
    *
    * @var array
    * @access public|private
    */
    
  
    var $children = array();
    
    /**
    * Build the child array for each element.
    * RECURSIVE FUNCTION!!!!
    * @param   int  id of node to add children to.
    *
    * @access   public
    * @static
    */
    function buildChildren($id) 
    {
        global $_HTML_TEMPLATE_FLEXY_TOKEN;
        
        $base = &$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$id];
        $base->children = array();
        $start = $base->id +1;
        $end = $base->close->id;
        
        for ($i=$start; $i<$end; $i++) {
            //echo "{$base->id}:{$base->tag} ADDING {$i}{$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->tag}
"; //if ($base->id == 1176) { // echo "
";print_r($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]);
            // }
         
            $base->children[] = &$_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i];
            
            if (isset($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]) && 
                is_object($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->close)) {
            
                // if the close id is greater than my id - ignore it! - 
                if ($_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->close->id > $end) {
                    continue;
                }
                HTML_Template_Flexy_Token::buildChildren($i);
                $i = $_HTML_TEMPLATE_FLEXY_TOKEN['tokens'][$i]->close->id;
            }
        }
    }
            
            
            
    /**
    * Flag to ignore children - Used to block output for select/text area etc.
    * may not be required as I moved the Tag parsing into the toString ph
    *
    * @var boolean ingore children
    * @access public
    */
    
  
    var $ignoreChildren = false;
    
    
    
     
    /* ======================================================== */
    /* variable STATE management 
    *
    * raw variables are assumed to be $this->, unless defined by foreach..
    * it also monitors syntax - eg. end without an if/foreach etc.
    */
 
    
    /**
    * tell the generator you are entering a block
    *
    * @access   public
    */
    function pushState() 
    {
        global $_HTML_TEMPLATE_FLEXY_TOKEN;
        
        $_HTML_TEMPLATE_FLEXY_TOKEN['state']++;
        $s = $_HTML_TEMPLATE_FLEXY_TOKEN['state'];
        
        $_HTML_TEMPLATE_FLEXY_TOKEN['statevars'][$s] = array(); // initialize statevars
    }
    /**
    * tell the generator you are entering a block
    *
    * @return  boolean  parse error - out of bounds
    * @access   public
    */
    function pullState() 
    {
        global $_HTML_TEMPLATE_FLEXY_TOKEN;
        
        $s = $_HTML_TEMPLATE_FLEXY_TOKEN['state'];
        $_HTML_TEMPLATE_FLEXY_TOKEN['statevars'][$s] = array(); // initialize statevars
        $_HTML_TEMPLATE_FLEXY_TOKEN['state']--;
        if ($s<0) {
            return false;
        }
        return true;
    }
     /**
    * get the real variable name formated x.y.z => $this->x->y->z
    * if  a variable is in the stack it return $x->y->z
    *
    * @return  string PHP variable 
    * @access   public
    */
    
    function toVar($s) {
        // wrap [] with quotes.
        $s = str_replace('[',"['",$s);
        $s = str_replace('%5b',"['",$s);
        $s = str_replace('%5B',"['",$s);
        $s = str_replace(']',"']",$s);
        $s = str_replace('%5d',"']",$s);
        $s = str_replace('%5D',"']",$s);
        // strip the quotes if it's only numbers..
        $s = preg_replace("/'([-]?[0-9]+)'/", "\\1",$s);
        
        $parts = explode(".",$s);
        
        
        $ret =  $this->findVar($parts[0]);
        if (is_a($ret,'PEAR_Error')) {
            return $ret;
        }
        
        array_shift($parts);
        
        if (!count($parts)) {
            return $ret;
        }
        foreach($parts as $p) {
            $ret .= "->{$p}";
        }
        return $ret;
    }
    /**
    * do the stack lookup on the variable
    * this relates to flexy
    * t relates to the object being parsed.
    *
    * @return  string PHP variable 
    * @access   public
    */
    
    function findVar($string) 
    {
        global $_HTML_TEMPLATE_FLEXY_TOKEN;
    
        if (!$string || $string == 't') {
            return '$t';
        }
        if ($string == 'this') {
            return '$this';
        }
        // accept global access on some string
        if (@$GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['globals'] &&
            preg_match('/^(_POST|_GET|_REQUEST|_SESSION|_COOKIE|GLOBALS)\[/',$string)) {
            return '$'.$string;
        } 
        if (!@$GLOBALS['_HTML_TEMPLATE_FLEXY']['currentOptions']['privates'] &&
                ($string{0} == '_')) {
                return HTML_Template_Flexy::raiseError('HTML_Template_Flexy::Attempt to access private variable:'.
                    " on line {$this->line} of {$GLOBALS['_HTML_TEMPLATE_FLEXY']['filename']}".
                    ", Use options[privates] to allow this."
                   , HTML_TEMPLATE_FLEXY_ERROR_SYNTAX ,HTML_TEMPLATE_FLEXY_ERROR_RETURN);
        }
        
        $lookup = $string;
        if ($p = strpos($string,'[')) {
            $lookup = substr($string,0,$p);
        }
        
        
        for ($s = $_HTML_TEMPLATE_FLEXY_TOKEN['state']; $s > 0; $s--) {
            if (in_array($lookup , $_HTML_TEMPLATE_FLEXY_TOKEN['statevars'][$s])) {
                return '$'.$string;
            }
        }
        return '$t->'.$string;
    }
    /**
    * add a variable to the stack.
    *
    * @param  string PHP variable 
    * @access   public
    */
    
    function pushVar($string) 
    {
        global $_HTML_TEMPLATE_FLEXY_TOKEN;
        $s = $_HTML_TEMPLATE_FLEXY_TOKEN['state'];
        $_HTML_TEMPLATE_FLEXY_TOKEN['statevars'][$s][] = $string;
    }
    
     /**
    * dump to text ATM
    *
    * 
    * @access   public
    */
    
    function dump() {
        echo "{$this->token}/" . (isset($this->tag) ? "<{$this->tag}>" : '') . ": {$this->value}\n";
    }
    
    
    
    
}