home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / HighlightParser.inc < prev    next >
Encoding:
Text File  |  2004-03-24  |  84.1 KB  |  2,233 lines

  1. <?php
  2. //
  3. // +------------------------------------------------------------------------+
  4. // | phpDocumentor                                                          |
  5. // +------------------------------------------------------------------------+
  6. // | Copyright (c) 2000-2003 Joshua Eichorn, Gregory Beaver                 |
  7. // | Email         jeichorn@phpdoc.org, cellog@phpdoc.org                   |
  8. // | Web           http://www.phpdoc.org                                    |
  9. // | Mirror        http://phpdocu.sourceforge.net/                          |
  10. // | PEAR          http://pear.php.net/package-info.php?pacid=137           |
  11. // +------------------------------------------------------------------------+
  12. // | This source file is subject to version 3.00 of the PHP License,        |
  13. // | that is available at http://www.php.net/license/3_0.txt.               |
  14. // | If you did not receive a copy of the PHP license and are unable to     |
  15. // | obtain it through the world-wide-web, please send a note to            |
  16. // | license@php.net so we can mail you a copy immediately.                 |
  17. // +------------------------------------------------------------------------+
  18. //
  19.  
  20. /**
  21.  * Source Code Highlighting
  22.  *
  23.  * The classes in this file are responsible for the dynamic @example, @filesource
  24.  * and {@}source} tags output.  Using the phpDocumentor_HighlightWordParser,
  25.  * the phpDocumentor_HighlightParser retrieves PHP tokens one by one from the
  26.  * array generated by {@link phpDocumentorTWordParser} source retrieval functions
  27.  * and then highlights them individually.
  28.  *
  29.  * It accomplishes this highlighting through the assistance of methods in
  30.  * the output Converter passed to its parse() method, and then returns the
  31.  * fully highlighted source as a string
  32.  * @tutorial tags.example.pkg, tags.filesource.pkg, tags.inlinesource.pkg
  33.  * @package phpDocumentor
  34.  * @subpackage Parsers
  35.  * @since 1.2.0beta3
  36.  */
  37. /**
  38.  * Retrieve tokens from an array of tokens organized by line numbers
  39.  * @package phpDocumentor
  40.  * @subpackage Parsers
  41.  * @since 1.2.0beta3
  42.  */
  43. class phpDocumentor_HighlightWordParser extends phpDocumentorTWordParser
  44. {
  45.     /**
  46.      * Hash used to keep track of line numbers that have already been initialized
  47.      * @var array
  48.      * @access private
  49.      */
  50.     var $_listLineNums = array();
  51.     /**
  52.      * @param array
  53.      * @param phpDocumentor_HighlightParser
  54.      */
  55.     function setup(&$input, &$parser)
  56.     {
  57.         $this->_parser = &$parser;
  58.         $this->data = &$input;
  59.         $this->_all = $input;
  60.         $this->_sourceline = 0;
  61.         $this->pos = 0;
  62.         $this->linenum = 0;
  63.     }
  64.     
  65.     /**
  66.      * debugging function
  67.      * @access private
  68.      */
  69.     function printState()
  70.     {
  71.         $linenum = $this->linenum;
  72.         $pos = $this->pos;
  73.         if (!isset($this->_all[$this->linenum][$this->pos]))
  74.         {
  75.             $linenum++;
  76.             $pos = 0;
  77.         }
  78.         $details = '';
  79.         $token = $this->_all[$linenum][$pos];
  80.         if (is_array($token))
  81.         {
  82.             $details = token_name($token[0]);
  83.             $token = htmlspecialchars($token[1]);
  84.         } else $token = htmlspecialchars($token);
  85.         debug('Next Token '.$this->linenum.'-'.$this->pos.':'.$details);
  86.         var_dump($token);
  87.     }
  88.     
  89.     /**
  90.      * Retrieve the position of the next token that will be parsed
  91.      * in the internal token array
  92.      * @return array format: array(line number, position)
  93.      */
  94.     function nextToken()
  95.     {
  96.         $linenum = $this->linenum;
  97.         $pos = $this->pos;
  98.         if (!isset($this->_all[$this->linenum][$this->pos]))
  99.         {
  100.             $linenum++;
  101.             $pos = 0;
  102.         }
  103.         if (!isset($this->_all[$linenum][$pos])) return false;
  104.         return array($linenum, $pos);
  105.     }
  106.     
  107.     /**
  108.      * Retrieve the next token
  109.      * @return array|string either array(PHP token constant, token) or string
  110.      *                      non-specific separator
  111.      */
  112.     function getWord()
  113.     {
  114.         if (!isset($this->_all[$this->linenum][$this->pos]))
  115.         {
  116.             $this->linenum++;
  117.             $this->pos = 0;
  118.             if (!isset($this->_all[$this->linenum])) return false;
  119.             $this->_parser->newLineNum();
  120.             return $this->getWord();
  121.         }
  122.         $word = $this->_all[$this->linenum][$this->pos++];
  123.         return $word;
  124.     }
  125.  
  126.     /**
  127.      * back the word parser to the previous token as defined by $last_token
  128.      * @param array|string token, or output from {@link nextToken()}
  129.      * @param boolean if true, backupPos interprets $last_token to be the
  130.      *                position in the internal token array of the last token
  131.      */
  132.     function backupPos($last_token, $is_pos = false)
  133.     {
  134.         if ($is_pos)
  135.         {
  136.             $this->linenum = $last_token[0];
  137.             $this->pos = $last_token[1];
  138.             return;
  139.         }
  140.         if ($last_token === false) return;
  141. //fancy_debug('before',$this->linenum,$this->pos,token_name($this->_all[$this->linenum][$this->pos][0]),htmlentities($this->_all[$this->linenum][$this->pos][1]),$this->_all[$this->linenum]);
  142.         do
  143.         {
  144.             $this->pos--;
  145.             if ($this->pos < 0)
  146.             {
  147.                 $this->linenum--;
  148.                 $this->pos = count($this->_all[$this->linenum]) - 1;
  149.             }
  150.         } while (!$this->tokenEquals($last_token,$this->_all[$this->linenum][$this->pos]));
  151.         //fancy_debug('after',$this->linenum,$this->pos,token_name($this->_all[$this->linenum][$this->pos][0]),htmlentities($this->_all[$this->linenum][$this->pos][1]));
  152.     }
  153. }
  154.  
  155. /**
  156.  * Highlights source code using {@link parse()}
  157.  * @package phpDocumentor
  158.  * @subpackage Parsers
  159.  */
  160. class phpDocumentor_HighlightParser extends phpDocumentorTParser
  161. {
  162.     /**#@+ @access private */
  163.     /**
  164.      * Highlighted source is built up in this string
  165.      * @var string
  166.      */
  167.     var $_output;
  168.     /**
  169.      * contents of the current source code line as it is parsed
  170.      * @var string
  171.      */
  172.     var $_line;
  173.     /**
  174.      * Used to retrieve highlighted tokens
  175.      * @var Converter a descendant of Converter
  176.      */
  177.     var $_converter;
  178.     /**
  179.      * Path to file being highlighted, if this is from a @filesource tag
  180.      * @var false|string full path
  181.      */
  182.     var $_filesourcepath;
  183.     /**
  184.      * @var array
  185.      */
  186.     var $eventHandlers = array(
  187.                                 PARSER_EVENT_ARRAY => 'defaultHandler',
  188.                                 PARSER_EVENT_CLASS => 'handleClass',
  189.                                 PARSER_EVENT_COMMENT => 'handleComment',
  190.                                 PARSER_EVENT_DOCBLOCK_TEMPLATE => 'handleDocBlockTemplate',
  191.                                 PARSER_EVENT_END_DOCBLOCK_TEMPLATE => 'handleEndDocBlockTemplate',
  192.                                 PARSER_EVENT_LOGICBLOCK => 'handleLogicBlock',
  193.                                 PARSER_EVENT_METHOD_LOGICBLOCK => 'handleMethodLogicBlock',
  194.                                 PARSER_EVENT_NOEVENTS => 'defaultHandler',
  195.                                 PARSER_EVENT_OUTPHP => 'defaultHandler',
  196.                                 PARSER_EVENT_CLASS_MEMBER => 'handleClassMember',
  197.                                 PARSER_EVENT_DEFINE => 'defaultHandler',
  198.                                 PARSER_EVENT_DEFINE_PARAMS => 'defaultHandler',
  199.                                 PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS => 'defaultHandler',
  200.                                 PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS => 'defaultHandler',
  201.                                 PARSER_EVENT_DOCBLOCK => 'handleDocBlock',
  202.                                 PARSER_EVENT_TAGS => 'handleTags',
  203.                                 PARSER_EVENT_DESC => 'handleDesc',
  204.                                 PARSER_EVENT_DOCKEYWORD => 'handleTag',
  205.                                 PARSER_EVENT_DOCKEYWORD_EMAIL => 'handleDockeywordEmail',
  206.                                 PARSER_EVENT_EOFQUOTE => 'handleEOFQuote',
  207.                                 PARSER_EVENT_FUNCTION => 'handleFunction',
  208.                                 PARSER_EVENT_METHOD => 'handleMethod',
  209.                                 PARSER_EVENT_FUNCTION_PARAMS => 'handleFunctionParams',
  210.                                 PARSER_EVENT_FUNC_GLOBAL => 'handleFuncGlobal',
  211.                                 PARSER_EVENT_INLINE_DOCKEYWORD => 'handleInlineDockeyword',
  212.                                 PARSER_EVENT_INCLUDE => 'defaultHandler',
  213.                                 PARSER_EVENT_INCLUDE_PARAMS => 'defaultHandler',
  214.                                 PARSER_EVENT_QUOTE => 'handleQuote',
  215.                                 PARSER_EVENT_QUOTE_VAR => 'handleQuoteVar',
  216.                                 PARSER_EVENT_PHPCODE => 'handlePhpCode',
  217.                                 PARSER_EVENT_SINGLEQUOTE => 'handleSingleQuote',
  218.                                 PARSER_EVENT_STATIC_VAR => 'defaultHandler',
  219.                                 PARSER_EVENT_STATIC_VAR_VALUE => 'defaultHandler',
  220.                                 PARSER_EVENT_VAR => 'handleVar',
  221.     );
  222.  
  223.     /**
  224.      * event handlers for @tags
  225.      * @tutorial tags.pkg
  226.      */
  227.     var $tagHandlers = array(
  228.                                 '*' => 'defaultTagHandler',
  229.                                 'abstract' => 'coreTagHandler',
  230.                                 'access' => 'coreTagHandler',
  231.                                 'author' => 'coreTagHandler',
  232.                                 'category' => 'coreTagHandler',
  233.                                 'copyright' => 'coreTagHandler',
  234.                                 'deprecated' => 'coreTagHandler',
  235.                                 'example' => 'coreTagHandler',
  236.                                 'filesource' => 'coreTagHandler',
  237.                                 'final' => 'coreTagHandler',
  238.                                 'global' => 'globalTagHandler',
  239.                                 'ignore' => 'coreTagHandler',
  240.                                 'license' => 'coreTagHandler',
  241.                                 'link' => 'coreTagHandler',
  242.                                 'name' => 'coreTagHandler',
  243.                                 'package' => 'coreTagHandler',
  244.                                 'param' => 'paramTagHandler',
  245.                                 'parameter' => 'paramTagHandler',
  246.                                 'see' => 'coreTagHandler',
  247.                                 'since' => 'coreTagHandler',
  248.                                 'subpackage' => 'coreTagHandler',
  249.                                 'internal' => 'coreTagHandler',
  250.                                 'return' => 'returnTagHandler',
  251.                                 'static' => 'coreTagHandler',
  252.                                 'staticvar' => 'staticvarTagHandler',
  253.                                 'throws' => 'coreTagHandler',
  254.                                 'todo' => 'coreTagHandler',
  255.                                 'tutorial' => 'coreTagHandler',
  256.                                 'uses' => 'coreTagHandler',
  257.                                 'var' => 'varTagHandler',
  258.                                 'version' => 'coreTagHandler',
  259.                             );
  260.     /**#@-*/
  261.     
  262.     /**
  263.      * @uses Converter::SourceLine() encloses {@link $_line} in a
  264.      *                               converter-specific format
  265.      */
  266.     function newLineNum()
  267.     {
  268.         if ($this->_pf_no_output_yet) return;
  269.         $this->_flush_save();
  270.         $this->_output .= $this->_converter->SourceLine($this->_wp->linenum, $this->_line, $this->_path);
  271.         $this->_line = '';
  272.     }
  273.     
  274.     /**
  275.      * Start the parsing at a certain line number
  276.      */
  277.     function setLineNum($num)
  278.     {
  279.         $this->_wp->linenum = $num;
  280.     }
  281.     
  282.     /**
  283.      * Parse a new file
  284.      *
  285.      * The parse() method is a do...while() loop that retrieves tokens one by
  286.      * one from the {@link $_event_stack}, and uses the token event array set up
  287.      * by the class constructor to call event handlers.
  288.      *
  289.      * The event handlers each process the tokens passed to them, and use the
  290.      * {@link _addoutput()} method to append the processed tokens to the
  291.      * {@link $_line} variable.  The word parser calls {@link newLineNum()}
  292.      * every time a line is reached.
  293.      *
  294.      * In addition, the event handlers use special linking functions
  295.      * {@link _link()} and its cousins (_classlink(), etc.) to create in-code
  296.      * hyperlinks to the documentation for source code elements that are in the
  297.      * source code.
  298.      *
  299.      * @uses setupStates() initialize parser state variables
  300.      * @uses configWordParser() pass $parse_data to prepare retrieval of tokens
  301.      * @param    array $parse_data
  302.      * @param    Converter $converter
  303.      * @param    boolean $inlinesourceparse whether this data is from an
  304.      *           inline {@}source} tag
  305.      * @param    string|false if a string, it is the name of the class whose
  306.      *           method we are parsing containing a {@}source} tag
  307.      * @param    false|integer starting line number from {@}source linenum}
  308.      * @param    false|string full path to file with @filesource tag, if this
  309.      *           is a @filesource parse
  310.      * @staticvar    integer    used for recursion limiting if a handler for
  311.      *                          an event is not found
  312.      * @return    bool
  313.      */
  314.     function parse (&$parse_data, &$converter, $inlinesourceparse = false, $class = false, $linenum = false, $filesourcepath = false)
  315.     {
  316.         if (!tokenizer_ext)
  317.         {
  318.             if (is_array($parse_data))
  319.             {
  320.                 $parse_data = join($parse_data,'');
  321.             }
  322.             $parse_data = explode("\n", $parse_data);
  323.             $this->_output = '';
  324.             foreach($parse_data as $linenum => $line)
  325.             {
  326.                 if ($linenum > 0)
  327.                 {
  328.                     $this->_output .= $converter->SourceLine($linenum, $line, $filesourcepath);
  329.                 }
  330.             }
  331.             return $converter->PreserveWhiteSpace($this->_output);
  332.         }
  333.         static $endrecur = 0;
  334.         $this->_converter = $converter;
  335.         $this->_path = $filesourcepath;
  336.         $this->setupStates($inlinesourceparse, $class);
  337.  
  338.         $this->configWordParser($parse_data);
  339.         if ($linenum !== false) $this->setLineNum($linenum);
  340.         // initialize variables so E_ALL error_reporting doesn't complain
  341.         $pevent = 0;
  342.         $word = 0;
  343.  
  344.         do
  345.         {
  346.             $lpevent = $pevent;
  347.             $pevent = $this->_event_stack->getEvent();
  348.             if ($lpevent != $pevent)
  349.             {
  350.                 $this->_last_pevent = $lpevent;
  351.             }
  352.  
  353.             if ($pevent == PARSER_EVENT_CLASS_MEMBER)
  354.             {
  355.                 $this->_wp->setWhitespace(true);
  356.             } else
  357.             {
  358.                 $this->_wp->setWhitespace(false);
  359.             }
  360.  
  361.             if (!is_array($word)) $lw = $word;
  362.             if (is_array($word) && $word[0] != T_WHITESPACE) $lw = $word;
  363.             $dbg_linenum = $this->_wp->linenum;
  364.             $dbg_pos = $this->_wp->getPos();
  365.             $word = $this->_wp->getWord();
  366.             // change tabs to spaces for consistency of output
  367.             if (is_array($word) && $word[0] == T_WHITESPACE) $word[1] = str_replace("\t",'    ',$word[1]);
  368.             if (is_array($word) && $word[0] == T_WHITESPACE  && $pevent != PARSER_EVENT_CLASS_MEMBER)
  369.             {
  370. //                debug("added ".$this->_wp->linenum.'-'.$this->_wp->pos);
  371.                 $this->_addoutput($word);
  372.                 continue;
  373.             } else $this->_pv_last_word = $lw;
  374.             if ($pevent != PARSER_EVENT_DOCBLOCK) $this->_pv_next_word = $this->_wp->nextToken();
  375.             // in wordparser, have to keep track of lines
  376. //            $this->publishEvent(PHPDOCUMENTOR_EVENT_NEWLINENUM, $this->_wp->linenum);
  377.             if (0)//PHPDOCUMENTOR_DEBUG == true)
  378.             {
  379.                 echo "LAST: ";
  380.                 if (is_array($this->_pv_last_word))
  381.                 {
  382.                     echo token_name($this->_pv_last_word[0]). ' => |'.htmlspecialchars($this->_pv_last_word[1]);
  383.                 } else echo "|" . $this->_pv_last_word;
  384.                 echo "|\n";
  385.                 echo "PEVENT: " . $this->getParserEventName($pevent) . "\n";
  386.                 echo "LASTPEVENT: " . $this->getParserEventName($this->_last_pevent) . "\n";
  387. //                echo "LINE: ".$this->_line."\n";
  388. //                echo "OUTPUT: ".$this->_output."\n";
  389.                 echo $dbg_linenum.'-'.$dbg_pos . ": ";
  390.                 if (is_array($word))
  391.                 {
  392.                     echo token_name($word[0]).' => |'.htmlspecialchars($word[1]);
  393.                 } else echo '|'.htmlspecialchars($word);
  394.                 echo "|\n";
  395.                 $this->_wp->printState();
  396.                 echo "NEXT TOKEN: ";
  397.                 $tok1 = $this->_pv_next_word;
  398.                 $tok = $this->_wp->_all[$tok1[0]][$tok1[1]];
  399.                 if (is_array($tok))
  400.                 {
  401.                     echo token_name($tok[0]). ' => '.$tok1[0].'-'.$tok1[1].'|'.htmlspecialchars($tok[1]);
  402.                 } else echo "|" . $tok;
  403.                 echo "|\n";
  404.                 echo "-------------------\n\n\n";
  405.                 flush();
  406.             }
  407.             if (isset($this->eventHandlers[$pevent]))
  408.             {
  409.                 $handle = $this->eventHandlers[$pevent];
  410.                 $this->$handle($word, $pevent);
  411.             } else
  412.             {
  413.                 debug('WARNING: possible error, no handler for event number '.$pevent);
  414.                 if ($endrecur++ == 25)
  415.                 {
  416.                     die("FATAL ERROR, recursion limit reached");
  417.                 }
  418.             }
  419.         } while (!($word === false));
  420.         if (strlen($this->_line)) $this->newLineNum();
  421.         return $this->_output;
  422.     }
  423.  
  424.     /**#@+
  425.      * Event Handlers
  426.      *
  427.      * All Event Handlers use {@link checkEventPush()} and
  428.      * {@link checkEventPop()} to set up the event stack and parser state.
  429.      * @access private
  430.      * @param string|array token value
  431.      * @param integer parser event from {@link Parser.inc}
  432.      */
  433.     /**
  434.      * Most tokens only need highlighting, and this method handles them
  435.      */
  436.     function defaultHandler($word, $pevent)
  437.     {
  438.         $this->_addoutput($word);
  439.         if ($this->checkEventPush($word, $pevent)) return;
  440.         $this->checkEventPop($word, $pevent);
  441.     }
  442.     
  443.     /**
  444.      * Handles global declarations in a function, like:
  445.      *
  446.      * <code>
  447.      * function foobar()
  448.      * {
  449.      *     global $_phpDocumentor_setting;
  450.      * }
  451.      * </code>
  452.      * @uses _globallink() instead of _addoutput(), to link to global variables
  453.      *       if they are used in a function
  454.      */
  455.     function handleFuncGlobal($word, $pevent)
  456.     {
  457.         if ($this->checkEventPush($word, $pevent)) return;
  458.         $this->_globallink($word);
  459.         $this->checkEventPop($word, $pevent);
  460.     }
  461.     
  462.     /**
  463.      * Handles strings in quotation marks
  464.      *
  465.      * Special handling is needed for strings that contain variables like:
  466.      *
  467.      * <code>$a = "$test string"</code>
  468.      *
  469.      * The tokenizer parses out tokens '"',array(T_VARIABLE,'$test'),' string',
  470.      * and '"'.  Since it is possible to have $this->classvar in a string,
  471.      * we save a variable name just in case the next token is -> to allow linking
  472.      * to class members.  Otherwise, the string is simply highlighted.
  473.      *
  474.      * constant strings (with no $variables in them) are passed as a single
  475.      * entity, and so will be saved in the last token parsed.  This means the
  476.      * event handler must tell the word parser to re-retrieve the current token
  477.      * so that the correct event handler can process it.
  478.      */
  479.     function handleQuote($word, $pevent)
  480.     {
  481.         if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word;
  482.         if ($this->checkEventPush($word, $pevent))
  483.         {
  484.             $this->_addoutput($word);
  485.             return;
  486.         }
  487.         if ($this->_pf_quote_active && $this->_pv_last_word == '"' && $this->_last_pevent != PARSER_EVENT_QUOTE)
  488.         {
  489.             $this->_pf_quote_active = false;
  490.             $this->_wp->backupPos($word);
  491.             $this->_event_stack->popEvent();
  492.             return;
  493.         }
  494.         if (!$this->_pf_quote_active && $this->_pv_last_word == '"' && $this->_last_pevent != PARSER_EVENT_QUOTE)
  495.         {
  496.             if (is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word;
  497.             $this->_pf_quote_active = true;
  498.             $this->_addoutput($word);
  499.             $this->checkEventPop($word, $pevent);
  500.             return;
  501.         } elseif (is_array($this->_pv_last_word) && $this->_pv_last_word[0] == T_CONSTANT_ENCAPSED_STRING)
  502.         {
  503. //            $this->_pv_quote_data = $this->_pv_last_word[1];
  504.             $this->_event_stack->popEvent();
  505.             $this->_wp->backupPos($word);
  506.             return;
  507.         }
  508.         if ($this->checkEventPop($word, $pevent))
  509.         {
  510.             $this->_pf_quote_active = false;
  511.         }
  512.         $this->_addoutput($word);
  513.     }
  514.     
  515.     /**
  516.      * Handles {$variable} within a "quote"
  517.      *
  518.      * This is a simple handler, for a very complex
  519.      * array of legal syntax.  It is legal to nest control structures
  520.      * inside the {}, and other weird stuff.
  521.      */
  522.     function handleQuoteVar($word, $pevent)
  523.     {
  524.         if ($this->checkEventPop($word, $pevent))
  525.         {
  526.             $this->_pf_quote_active = true;
  527.             $this->_addoutput($word);
  528.             return;
  529.         }
  530.         if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word;
  531.         if ($this->checkEventPush($word, $pevent))
  532.         {
  533.             $this->_pf_quote_active = false;
  534.             if (is_string($word) && ($word == '{' || $word == '"' || $word == "'"))
  535.             {
  536.                 $this->_pf_quote_active = true;
  537.                 $this->_pv_lastvar = false;
  538.             }
  539.         }
  540.         $this->_addoutput($word);
  541.     }
  542.     
  543.     /**
  544.      * Handles define() statements
  545.      *
  546.      * The only thing this handler cares about is retrieving the name of the
  547.      * define variable, and the end of the define statement, so after the name
  548.      * is found, it simply makes sure parentheses are matched as in this case:
  549.      *
  550.      * <code>
  551.      * define("test",array("hello",6 => 4, 5 => array('there')));
  552.      * </code>
  553.      *
  554.      * This handler and the DEFINE_PARAMS_PARENTHESIS handler (which is just
  555.      * {@link defaultHandler()} in this version, as nothing fancy is needed)
  556.      * work together to ensure proper parenthesis matching.
  557.      *
  558.      * If the define variable is documented, a link will be created to its
  559.      * documentation using the Converter passed.
  560.      */
  561.     function handleDefine($word, $pevent)
  562.     {
  563.         static $token_save;
  564.         if (!isset($token_save)) $token_save = array();
  565.         $e = $this->checkEventPush( $word, $pevent);
  566.         if ($e && $e != PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS) return;
  567.         
  568.         if(!isset($this->_pv_define_params_data)) $this->_pv_define_params_data = '';
  569.         
  570.         if ($this->checkEventPop($word,$pevent))
  571.         {
  572.             unset($token_save);
  573.             $this->_addoutput($word);
  574.         }
  575.         if ($this->_pf_definename_isset)
  576.         {
  577.             $this->_addoutput($word);
  578.         } else
  579.         {
  580.             if ($word != ",")
  581.             {
  582.                 $token_save[] = $word;
  583.                 if (is_array($word)) $word = $word[1];
  584.                 $this->_pv_define_params_data .= $word;
  585.             } else
  586.             {
  587.                 if (substr($this->_pv_define_params_data,0,1) ==
  588.                     substr($this->_pv_define_params_data,strlen($this->_pv_define_params_data) - 1) &&
  589.                     in_array(substr($this->_pv_define_params_data,0,1),array('"',"'")))
  590.                 { // remove leading and ending quotation marks if there are only two
  591.                     $a = substr($this->_pv_define_params_data,0,1);
  592.                     $b = substr($this->_pv_define_params_data,1,strlen($this->_pv_define_params_data) - 2);
  593.                     if (strpos($b,$a) === false)
  594.                     {
  595.                         $this->_pv_define_params_data = $b;
  596.                     }
  597.                 }
  598.                 $this->_pf_definename_isset = true;
  599.                 $link = $this->_converter->getLink($this->_pv_define_params_data);
  600.                 foreach ($token_save as $token)
  601.                 {
  602.                     if (is_object($link))
  603.                     {
  604.                         if (is_array($token)) $token = $token[1];
  605.                         $this->_addoutput($this->_converter->returnSee($link, $token));
  606.                     } else
  607.                     {
  608.                         $this->_addoutput($save, $token);
  609.                     }
  610.                 }
  611.                 $this->_pv_define_params_data = '';
  612.             }
  613.         }
  614.     }
  615.     
  616.     /**
  617.      * Handles normal global code.  Special consideration is taken for DocBlocks
  618.      * as they need to retrieve the whole DocBlock before doing any output, so
  619.      * the parser flag {@link $_pf_no_output_yet} is set to tell
  620.      * {@link _addoutput()} not to spit anything out yet.
  621.      * @uses _link() make any global code that is a documentable element link
  622.      *       to the php manual or its documentation
  623.      */
  624.     function handlePhpCode($word, $pevent)
  625.     {
  626.         if ($this->checkEventPush($word, $pevent) == PARSER_EVENT_DOCBLOCK)
  627.         {
  628.             $this->_pf_no_output_yet = true;
  629.             $this->_pv_saveline = $this->_wp->linenum + 1;
  630.             return;
  631.         }
  632.         if (is_array($word) && $word[0] == T_DOUBLE_COLON) $this->_pf_colon_colon = true;
  633.         if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) $this->_pv_last_string = $word;
  634.         $this->_link($word);
  635.         $this->checkEventPop($word, $pevent);
  636.     }
  637.     
  638.     /**
  639.      * Handle the function declaration header
  640.      *
  641.      * This handler only sees the "function name" portion of the function
  642.      * declaration.  Handling of the function parameters is by
  643.      * {@link handleFunctionParams()}, and the function body is handled by
  644.      * {@link handleLogicBlock()}
  645.      */
  646.     function handleFunction($word, $pevent)
  647.     {
  648.         if ($this->checkEventPush($word, $pevent))
  649.         {
  650.             $this->_addoutput($word);
  651.             return;
  652.         }
  653.         if ($this->checkEventPop($word, $pevent)) return;
  654.         $this->_link($word);
  655.     }
  656.     
  657.     /**
  658.      * Handle the method declaration header
  659.      *
  660.      * This handler only sees the "function name" portion of the method
  661.      * declaration.  Handling of the method parameters is by
  662.      * {@link handleFunctionParams()}, and the method body is handled by
  663.      * {@link handleMethodLogicBlock()}
  664.      */
  665.     function handleMethod($word, $pevent)
  666.     {
  667.         if ($this->checkEventPush($word, $pevent))
  668.         {
  669.             $this->_addoutput($word);
  670.             return;
  671.         }
  672.         if ($this->checkEventPop($word, $pevent)) return;
  673.         $this->_methodlink($word);
  674.     }
  675.     
  676.     /**
  677.      * Handler for the stuff between ( and ) in a function declaration
  678.      *
  679.      * <code>
  680.      * function handles($only,$these,$parameters){...}
  681.      * </code>
  682.      */
  683.     function handleFunctionParams($word, $pevent)
  684.     {
  685.         if ($this->checkEventPush($word, $pevent))
  686.         {
  687.             $this->_addoutput($word);
  688.             return;
  689.         }
  690.         $this->_addoutput($word);
  691.         $this->checkEventPop($word, $pevent);
  692.     }
  693.     
  694.     /**
  695.      * Handler for function body.
  696.      *
  697.      * The function body is checked for php functions, documented constants,
  698.      * functions, and indirectly for global statements.  It hyperlinks to the
  699.      * documentation for detected elements is created.  Everything else is
  700.      * highlighted normally.
  701.      */
  702.     function handleLogicBlock($word, $pevent)
  703.     {
  704.         if ($this->checkEventPush($word, $pevent))
  705.         {
  706.             $this->_addoutput($word);
  707.             return;
  708.         }
  709.         if (is_array($word) && $word[0] == T_DOUBLE_COLON) $this->_pf_colon_colon = true;
  710.         if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) $this->_pv_last_string = $word;
  711.         $this->_link($word);
  712.         if ($this->checkEventPop($word,$pevent))
  713.         {
  714.             $e = $this->_event_stack->popEvent();
  715.             $this->_event_stack->pushEvent($e);
  716.             if ($e == PARSER_EVENT_FUNCTION)
  717.             {
  718.                 $this->_wp->backupPos($word); 
  719.             }
  720.         }
  721.     }
  722.     
  723.     /**
  724.      * Handler for method body.
  725.      *
  726.      * Like functions, the method body is checked for php functions, documented
  727.      * constants, functions, and indirectly for global statements.  It also
  728.      * checks for "$this->XXXX" where XXXX is a class variable or method, and
  729.      * links to the documentation for detected elements is created.  Everything
  730.      * else is highlighted normally.
  731.      */
  732.     function handleMethodLogicBlock($word, $pevent)
  733.     {
  734.         if (isset($this->_pv_prev_var_type))
  735.         {
  736. //            debug('prevtype is set');
  737.             if (!is_array($word)) unset($this->_pv_prev_var_type);
  738.             else
  739.             {
  740.                 if ($word[0] != T_WHITESPACE && $word[0] != T_STRING && $word[0] != T_OBJECT_OPERATOR)
  741.                 {
  742. //                    fancy_debug('unset',$word);
  743.                     unset($this->_pv_prev_var_type);
  744.                 }
  745.             }
  746.         }
  747.         $this->_pf_inmethod = true;
  748.         if ($this->checkEventPush($word, $pevent))
  749.         {
  750.             $this->_addoutput($word);
  751.             return;
  752.         }
  753.         if (is_array($word) && $word[0] == T_DOUBLE_COLON) $this->_pf_colon_colon = true;
  754.         if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) $this->_pv_last_string = $word;
  755.         if (is_array($word) && $word[0] == T_VARIABLE) $this->_pv_lastvar = $word;
  756.         $this->_link($word);
  757.         if ($this->checkEventPop($word,$pevent))
  758.         {
  759.             $this->_pf_inmethod = false;
  760.             $e = $this->_event_stack->popEvent();
  761.             $this->_event_stack->pushEvent($e);
  762.             if ($e == PARSER_EVENT_METHOD)
  763.             {
  764.                 $this->_wp->backupPos($word); 
  765.             }
  766.         }
  767.     }
  768.     
  769.     /**
  770.      * Handles $obj->classmember in a method body
  771.      *
  772.      * This handler is responsible for linking to the documentation of a
  773.      * class member when it is used directly in a method body.
  774.      * 
  775.      * There are two methods of determining whether to link:
  776.      * - $this->member
  777.      * - $this->member->submember
  778.      *
  779.      * The first case is handled by the $_pv_lastvar variable, and the
  780.      * second case is handled by the $_pv_prev_var_type variable.  $_pv_lastvar
  781.      * is always set to the value of the last T_VARIABLE token, if and only if
  782.      * no text has occurred between the variable and a T_OBJECT_OPERATOR token
  783.      * "->".  handleClassMember will only link if the last variable encountered
  784.      * was $this.
  785.      *
  786.      * When $this->variable is encountered, the variable is looked up to see
  787.      * if it can be found, and if so, the contents of its @var tag are processed
  788.      * to see if the member variable is defined to have 1 and only 1 class.
  789.      * If so, the $_pv_prev_var_type variable is set to this classname.  When
  790.      * submember is processed, the HighlightParser checks to see if 
  791.      * $_pv_prev_var_type::submember() or $_pv_prev_var_type::$submember exists,
  792.      * and if it does, it is linked to.
  793.      */
  794.     function handleClassMember($word, $pevent)
  795.     {
  796.         if (!isset($this->_pv_lastvar) && !isset($this->_pv_prev_var_type))
  797.         {
  798. //            fancy_debug('returned from',$word,$this->_pv_prev_var_type);
  799.             $this->_event_stack->popEvent();
  800.             return $this->defaultHandler($word, $pevent);
  801.         }
  802.         if (isset($this->_pv_cm_name))
  803.         {
  804.             $this->_pf_obj_op = false;
  805.             $name = $this->_pv_cm_name;
  806.             unset($this->_pv_cm_name);
  807. //            debug('unset pvcmname');
  808.             $this->_event_stack->popEvent();
  809.             // control variable for _pv_prev_var_type
  810.             $setnow = false;
  811.             if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this')
  812.                 || isset($this->_pv_prev_var_type))
  813.             {
  814.                 if (is_array($word) && $word[0] == T_WHITESPACE)
  815.                 {
  816.                     // preserve value of _pv_prev_var_type
  817.                     $setnow = true;
  818.                     $save = $this->_wp->nextToken();
  819.                     $temp = $this->_wp->getWord();
  820.                     $this->_wp->backupPos($save, true);
  821.                 }
  822.                 if ((is_string($word) && $word == '(') ||
  823.                     (isset($temp) && is_string($temp) && $temp == '('))
  824.                 { // it's a function
  825.                     $this->_methodlink($name);
  826.                     unset($this->_pv_prev_var_type);
  827.                 } else
  828.                 { // it's a variable
  829. //                    fancy_debug('name is ',$name);
  830.                     $this->_varlink($name, true);
  831.                     $templink = $this->_converter->getLink('object '.$this->_pv_class);
  832.                     $class = $this->_converter->classes->getClass($templink->name, $templink->path);
  833.                     if ($class)
  834.                     {
  835.                         $varname = $name;
  836.                         if (is_array($varname)) $varname = $name[1];
  837.                         if ($varname{0} != '$') $varname = '$'.$varname;
  838.                         $var = $class->getVar($this->_converter, $varname);
  839.                         
  840.                         if ($var->docblock->var)
  841.                             $type = $var->docblock->var->returnType;
  842.                         if (isset($type))
  843.                         {
  844.                             if (strpos($type, 'object') === false)
  845.                                 $type = 'object '.$type;
  846.                             $type = $this->_converter->getLink($type);
  847.                             if (get_class($type) == 'classlink')
  848.                             { // the variable's type is a class, save it for future ->
  849. //                                fancy_debug('set prev_var_type!',$type->name);
  850.                                 $setnow = true;
  851.                                 $this->_pv_prev_var_type = $type->name;
  852.                             } else unset($this->_pv_prev_var_type);
  853.                         } else unset($this->_pv_prev_var_type);
  854.                     } else unset($this->_pv_prev_var_type);
  855.                 }
  856.             } else $this->_addoutput($name);
  857.             if (!$setnow)
  858.             {
  859. //                debug('unset prevtype, no setnow');
  860.                 unset($this->_pv_prev_var_type);
  861.             }
  862.             unset($this->_pv_lastvar);
  863.             if ($word[0] == T_OBJECT_OPERATOR)
  864.                 $this->_wp->backupPos($word);
  865.             else
  866.                 $this->_addoutput($word);
  867.             return;
  868.         }
  869.         if (!$this->_pf_obj_op && is_array($this->_pv_last_word) && $this->_pv_last_word[0] == T_OBJECT_OPERATOR)
  870.         {
  871.             if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') || isset($this->_pv_prev_var_type))
  872.             {
  873.                 $this->_pf_obj_op = true;
  874.             } else
  875.             {
  876.                 $this->_addoutput($word);
  877.                 $this->_event_stack->popEvent();
  878.             }
  879.         }
  880.         if (is_array($word) && $word == T_WHITESPACE)
  881.         {
  882.             $this->_addoutput($word);
  883.             return;
  884.         }
  885.         if ($this->_pf_obj_op)
  886.         {
  887.             if (!(is_array($word) && ($word[0] == T_STRING || $word[0] == T_WHITESPACE)))
  888.             {
  889.                 unset($this->_pv_lastvar);
  890. //                debug('unset lastvar');
  891.                 $this->_event_stack->popEvent();
  892.                 $this->_addoutput($word);
  893.                 return;
  894.             }
  895.             if ($word[0] == T_STRING)
  896.             {
  897. //                fancy_debug('set pvcmname to',$word);
  898.                 $this->_pv_cm_name = $word;
  899.             } else $this->_addoutput($word);
  900.         }
  901.     }
  902.     
  903.     /**
  904.      * Handles comments
  905.      *
  906.      * Comments are almost always single-line tokens, and so will be
  907.      * in the last word.  This handler checks to see if the current token
  908.      * is in fact a comment, and if it isn't, it backs up and returns control
  909.      * to the parent event handler with that word.
  910.      */
  911.     function handleComment($word, $pevent)
  912.     {
  913.         if (!is_array($word) || $word[0] != T_COMMENT ||
  914.             ($word[0] == T_COMMENT && strpos($word[1],'/**') === 0))
  915.         {
  916.             $this->_event_stack->popEvent();
  917.             if (strpos($this->_pv_last_word[1], "\n") !== false)
  918.             {
  919. //                $this->_wp->linenum++;
  920. //                $this->newLineNum();
  921.             }
  922.             $this->_wp->backupPos($word);
  923.             return;
  924.         }
  925.         $this->_addoutput($word);
  926.         $this->checkEventPop($word, $pevent);
  927.     }
  928.     
  929.     /**
  930.      * Handle class declarations
  931.      *
  932.      * Handles the initial declaration line:
  933.      *
  934.      * <code>class X [extends Y]</code>
  935.      *
  936.      * @uses _classlink() to link to documentation for X and for Y class in
  937.      *                    "class X extends Y"
  938.      */
  939.     function handleClass($word, $pevent)
  940.     {
  941.         $this->_pf_in_class = true;
  942.         $a = $this->checkEventPush( $word, $pevent);
  943.  
  944.         if (!isset($this->_pv_class) && is_array($word) && $word[0] == T_STRING)
  945.         {
  946.             $this->_pv_class = $this->_converter->class = $word[1];
  947.             $this->_classlink($word);
  948.             return;
  949.         }
  950.  
  951.         if ($this->_pf_extends_found && is_array($word) && $word[0] == T_STRING)
  952.         {
  953.             $this->_classlink($word);
  954.             return;
  955.         }
  956.         if (is_array($word) && $word[0] == T_EXTENDS) $this->_pf_extends_found = true;
  957.         if ($a == PARSER_EVENT_DOCBLOCK)
  958.         {
  959.             $this->_pf_no_output_yet = true;
  960.             $this->_pv_saveline = $this->_wp->linenum + 1;
  961.             return;
  962.         }
  963.         $this->_addoutput($word);
  964.         if ($this->checkEventPop($word,$pevent))
  965.         {
  966.             $this->_pf_in_class = false;
  967.             unset($this->_pv_class);
  968.         }
  969.     }
  970.     
  971.     /**
  972.      * Handles class variable declaration
  973.      *
  974.      * <code>
  975.      * class X
  976.      * {
  977.      *     var $Y;
  978.      * }
  979.      * </code>
  980.      * @uses _varlink() make a link to $Y documentation in class variable
  981.      *                  declaration "var $Y;"
  982.      */
  983.     function handleVar($word, $pevent)
  984.     {
  985.         if ($this->checkEventPush($word, $pevent))
  986.         {
  987.             $this->_addoutput($word);
  988.             return;
  989.         }
  990.         if (is_array($word) && $word[0] == T_VARIABLE)
  991.         {
  992.             return $this->_varlink($word);
  993.         }
  994.         $this->_addoutput($word);
  995.         $this->checkEventPop($word, $pevent);
  996.     }
  997.     
  998.     /**
  999.      * This handler is responsible for highlighting DocBlocks
  1000.      *
  1001.      * handleDocBlock determines whether the docblock is normal or a template,
  1002.      * and gathers all the lines of the docblock together before doing any
  1003.      * processing
  1004.      *
  1005.      * As it is not possible to distinguish any comment token from a docblock
  1006.      * token, this handler is also called for comments, and will pass control
  1007.      * to {@link handleComment()} if the comment is not a DocBlock
  1008.      * @uses commonDocBlock() once all lines of the DocBlock have been retrieved
  1009.      */
  1010.     function handleDocBlock($word, $pevent)
  1011.     {
  1012.         if (!($this->_pf_docblock || $this->_pf_docblock_template))
  1013.         {
  1014.             if (strpos($this->_pv_last_word[1],'/**') !== 0)
  1015.             { // not a docblock
  1016.                 $this->_wp->backupPos($this->_pv_last_word);
  1017.                 $this->_event_stack->popEvent();
  1018.                 $this->_event_stack->pushEvent(PARSER_EVENT_COMMENT);
  1019.                 $this->_pf_no_output_yet = false;
  1020.                 return;
  1021.             } else
  1022.             {
  1023.                 $this->_pf_no_output_yet = true;
  1024.                 $this->_pv_db_lines = array();
  1025.             }
  1026.         }
  1027.         $last_word = $this->_pv_last_word[1];
  1028.         $dtype = '_pv_docblock';
  1029.         if ($last_word == '/**#@-*/')
  1030.         { // stop using docblock template
  1031.             $this->_pf_no_output_yet = false;
  1032.             $this->_addDocBlockoutput('closetemplate', $last_word);
  1033.             $this->_wp->backupPos($this->_pv_next_word,true);
  1034.             $this->_event_stack->popEvent();
  1035.             return;
  1036.         }
  1037.         if (!($this->_pf_docblock || $this->_pf_docblock_template))
  1038.         {
  1039.             $this->_pv_db_lines = array();
  1040.             if (strpos($last_word,'/**#@+') === 0)
  1041.             { // docblock template definition
  1042.                 $this->_pf_docblock_template = true;
  1043.             } else
  1044.             {
  1045.                 $this->_pf_docblock = true;
  1046.             }
  1047.             $this->_pv_db_lines[] = $last_word;
  1048.             if (strpos($last_word,'*/') !== false)
  1049.             {
  1050.                 $this->commonDocBlock();
  1051.                 return;
  1052.             }
  1053.             $this->_pv_db_lines[] = $word[1];
  1054.             if (strpos($word[1],'*/') !== false)
  1055.             {
  1056.                 $this->commonDocBlock();
  1057.             }
  1058.         } else
  1059.         {
  1060.             $this->_pv_db_lines[] = $word[1];
  1061.         }
  1062.         if (($this->_pf_docblock || $this->_pf_docblock_template) && (strpos($word[1],'*/') !== false))
  1063.         {
  1064.             $this->commonDocBlock();
  1065.         }
  1066.     }
  1067.     /**#@-*/
  1068.     /**
  1069.      * This continuation of handleDocBlock splits DocBlock comments up into
  1070.      * phpDocumentor tokens.  It highlights DocBlock templates in a different
  1071.      * manner from regular DocBlocks, recognizes inline tags, regular tags,
  1072.      * and distinguishes between standard core tags and other tags, and
  1073.      * recognizes parameters to tags like @var.
  1074.      *
  1075.      * the type in "@var type description" will be highlighted as a php type,
  1076.      * and the var in "@param type $var description" will be highlighted as a
  1077.      * php variable.
  1078.      * @uses handleDesc() highlight inline tags in the description
  1079.      * @uses handleTags() highlight all tags
  1080.      * @access private
  1081.      */
  1082.     function commonDocBlock()
  1083.     {
  1084.         $this->_event_stack->popEvent();
  1085.         $lines = $this->_pv_db_lines;
  1086.         $go = count($this->_pv_db_lines);
  1087.         for($i=0;$i<$go;$i++)
  1088.         {
  1089.             if (substr(trim($lines[$i]),0,2) == '*/' || substr(trim($lines[$i]),0,1) != '*' && substr(trim($lines[$i]),0,3) != '/**')
  1090.             {
  1091.                 $lines[$i] = array($lines[$i],false);
  1092.             } elseif (substr(trim($lines[$i]),0,3) == '/**')
  1093.             {
  1094.                 $linesi = array();
  1095.                 $linesi[1] = substr(trim($lines[$i]),3); // remove leading "/**"
  1096.                 if (empty($linesi[1]))
  1097.                 $linesi[0] = $lines[$i];
  1098.                 else
  1099.                 $linesi[0] = substr($lines[$i],0,strpos($lines[$i],$linesi[1]));
  1100.                 $lines[$i] = $linesi;
  1101.             } else
  1102.             {
  1103.                 $linesi = array();
  1104.                 $linesi[1] = substr(trim($lines[$i]),1); // remove leading "* "
  1105.                 if (empty($linesi[1]))
  1106.                 $linesi[0] = $lines[$i];
  1107.                 else
  1108.                 $linesi[0] = substr($lines[$i],0,strpos($lines[$i],$linesi[1]));
  1109.                 $lines[$i] = $linesi;
  1110.             }
  1111.         }
  1112.         for($i = 0;$i<count($lines);$i++)
  1113.         {
  1114.             if ($lines[$i][1] === false) continue;
  1115.             if (substr(trim($lines[$i][1]),0,1) == '@' && substr(trim($lines[$i][1]),0,2) != '@ ')
  1116.             {
  1117.                 $tagindex = $i;
  1118.                 $i = count($lines);
  1119.             }
  1120.         }
  1121.         if (isset($tagindex))
  1122.         {
  1123.             $tags = array_slice($lines,$tagindex);
  1124.             $desc = array_slice($lines,0,$tagindex);
  1125.         } else
  1126.         {
  1127.             $tags = array();
  1128.             $desc = $lines;
  1129.         }
  1130. //        var_dump($desc,$tags);
  1131.         $this->_pf_no_output_yet = false;
  1132.         $save = $this->_wp->linenum;
  1133.         $this->_wp->linenum = $this->_pv_saveline;
  1134.         $this->handleDesc($desc);
  1135.         $this->handleTags($tags);
  1136.         $this->_pv_db_lines = array();
  1137.         $this->_wp->linenum = $save;
  1138.         if (strpos($this->_pv_last_word[1],'*/') !== false)
  1139.         {
  1140.             $this->_wp->backupPos($this->_pv_next_word,true);
  1141.         }
  1142.         $this->_pf_docblock = $this->_pf_docblock_template = false;
  1143.     }
  1144.     
  1145.     /**
  1146.      * Handle the description area of a DocBlock
  1147.      *
  1148.      * This method simply finds inline tags and highlights them
  1149.      * separately from the rest of the description.
  1150.      * @uses getInlineTags()
  1151.      * @access private
  1152.      */
  1153.     function handleDesc($desc)
  1154.     {
  1155.         $dbtype = 'docblock';
  1156.         $dbtype .= ($this->_pf_docblock ? '' : 'template');
  1157.         foreach($desc as $line)
  1158.         {
  1159.             $this->getInlineTags($line[0].$line[1]);
  1160.             if (strpos($line[0],'*/') === false)
  1161.             {
  1162.                 $this->newLineNum();
  1163.                 $this->_wp->linenum++;
  1164.             }
  1165.         }
  1166.         if ($this->_pf_internal)
  1167.         {
  1168.             $this->_pf_internal = false;
  1169.         }
  1170.     }
  1171.     
  1172.     /**
  1173.      * Handle phpDocumentor tags in a DocBlock
  1174.      *
  1175.      * This method uses the {@link $tagHandlers} array to determine which
  1176.      * method will handle tags found in the docblock, and passes the data to
  1177.      * the individual handlers one by one
  1178.      * @access private
  1179.      */
  1180.     function handleTags($tags)
  1181.     {
  1182.         $newtags = array();
  1183.         $curtag = array();
  1184.         for($i=0;$i < count($tags);$i++)
  1185.         {
  1186.             $tagsi = trim($tags[$i][1]);
  1187.             if (substr($tagsi,0,1) == '@' && substr($tagsi,0,2) != '@ ')
  1188.             { // start a new tag
  1189.                 $tags[$i][1] = array(substr($tags[$i][1],0,strpos($tags[$i][1],$tagsi)),$tagsi);
  1190.                 if (!empty($curtag))
  1191.                 {
  1192.                     $newtags[] = $curtag;
  1193.                     $curtag = array();
  1194.                 }
  1195.                 $curtag[] = $tags[$i];
  1196.             } else $curtag[] = $tags[$i];
  1197.         }
  1198.         if (!empty($curtag)) $newtags[] = $curtag;
  1199.         foreach($newtags as $tag)
  1200.         {
  1201.             foreach($tag as $i => $t)
  1202.             {
  1203.                 if ($t[1] === false) continue;
  1204.                 if (is_array($t[1]))
  1205.                 {
  1206.                     $tag[$i][1][1] = explode(" ",str_replace("\t",'    ',$t[1][1]));
  1207.                     $x = $tag[$i][1][1];
  1208.                 }
  1209.             }
  1210.             $tagname = substr(array_shift($x),1);
  1211.             $restoftag = $tag;
  1212.             if (isset($this->tagHandlers[$tagname]))
  1213.             $handle = $this->tagHandlers[$tagname];
  1214.             else
  1215.             $handle = $this->tagHandlers['*'];
  1216.             $this->$handle($tagname,$restoftag);
  1217.         }
  1218.     }
  1219.     
  1220.     /**
  1221.      * This handler recognizes all {@}inline} tags
  1222.      *
  1223.      * Normal inline tags are simply highlighted.  the {@}internal}} inline
  1224.      * tag {@tutorial tags.inlineinternal.pkg} is highlighted differently
  1225.      * to distinguish it from other inline tags.
  1226.      * @access private
  1227.      */
  1228.     function getInlineTags($value, $endinternal = false)
  1229.     {
  1230.         if (!$value) return;
  1231.         if ($this->_pf_internal && !$endinternal)
  1232.         {
  1233.             if (strpos($value,'}}') !== false)
  1234.             {
  1235.                 $x = strrpos($value,'}}');
  1236.                 // add the rest of internal
  1237.                 $this->getInlineTags(substr($value,0,$x + 3), true);
  1238.                 // strip internal from value
  1239.                 $value = substr($value,strrpos($value,'}}') + 1);
  1240.                 // turn off internal
  1241.                 $this->_pf_internal = false;
  1242.             }
  1243.         }
  1244.         if (!$value) return;
  1245.         $dbtype = 'docblock';
  1246.         $dbtype .= ($this->_pf_docblock ? '' : 'template');
  1247.         $save = $value;
  1248.         $value = explode('{@',$value);
  1249.         $newval = array();
  1250.         // everything before the first {@ is normal text
  1251.         $this->_addDocBlockoutput($dbtype, $value[0]);
  1252.         for($i=1;$i<count($value);$i++)
  1253.         {
  1254.             if (substr($value[$i],0,1) == '}')
  1255.             {
  1256.                 $this->_addDocBlockoutput($dbtype, '{@}'.substr($value[$i],1));
  1257.             } else
  1258.             {
  1259.                 $save = $value[$i];
  1260.                 $value[$i] = str_replace("\t","    ",$value[$i]);
  1261.                 $value[$i] = explode(" ",$value[$i]);
  1262.                 $word = array_shift($value[$i]);
  1263.                 $val = join(' ',$value[$i]);
  1264.                 if ($word == 'internal')
  1265.                 {
  1266.                     $this->_pf_internal = true;
  1267.                     $this->_addDocBlockoutput($dbtype, '{@internal ');
  1268.                     $value[$i] = substr($save,strlen('internal') + 1);
  1269.                     // strip internal and cycle as if it were normal text.
  1270.                     $this->_addDocBlockoutput($dbtype, $value[$i]);
  1271.                     continue;
  1272.                 }
  1273.                 if (in_array(str_replace('}','',$word),$this->allowableInlineTags))
  1274.                 {
  1275.                     if (strpos($word,'}'))
  1276.                     {
  1277.                         $word = str_replace('}','',$word);
  1278.                         $val = '} '.$val;
  1279.                     }
  1280.                     $val = explode('}',$val);
  1281.                     if (count($val) == 1)
  1282.                     {
  1283. //                         addError(PDERROR_UNTERMINATED_INLINE_TAG,$word,'',$save);
  1284.                     }
  1285.                     $rest = $val;
  1286.                     $val = array_shift($rest);
  1287.                     if ($endinternal)
  1288.                     $rest = join('}',$rest);
  1289.                     else
  1290.                     $rest = join(' ',$rest);
  1291.                     if (isset($this->inlineTagHandlers[$word]))
  1292.                     $handle = $this->inlineTagHandlers[$word];
  1293.                     else
  1294.                     $handle = $this->inlineTagHandlers['*'];
  1295.                     $this->$handle($word,$val);
  1296.                     $this->_addDocBlockoutput($dbtype, $rest);
  1297.                 } else
  1298.                 {
  1299.                     $val = $word.' '.$val;
  1300.                     $this->_addDocBlockoutput($dbtype, '{@'.$val);
  1301.                 }
  1302.             }
  1303.         }
  1304.     }
  1305.  
  1306.     
  1307.     /**
  1308.      * Handles all inline tags
  1309.      * @access private
  1310.      */
  1311.     function handleDefaultInlineTag($name, $value)
  1312.     {
  1313.         $this->_addDocBlockoutput('inlinetag','{@'.$name.' '.$value.'}');
  1314.     }
  1315.  
  1316.     /**#@+
  1317.      * phpDocumentor DocBlock tag handlers
  1318.      * @access private
  1319.      * @param string tag name
  1320.      * @param array array of lines contained in the tag description
  1321.      */
  1322.     /**
  1323.      * Handle normal tags
  1324.      *
  1325.      * This handler adds to outpu all comment information before the tag begins
  1326.      * as in " * " before "@todo" in " * @todo"
  1327.      *
  1328.      * Then, it highlights the tag as a regular or coretag based on $coretag.
  1329.      * Finally, it uses getInlineTags to highlight the description
  1330.      * @uses getInlineTags() highlight a tag description
  1331.      * @param boolean whether this tag is a core tag or not
  1332.      */
  1333.     function defaultTagHandler($name, $value, $coretag = false)
  1334.     {
  1335.         $dbtype = 'docblock';
  1336.         $dbtype .= ($this->_pf_docblock ? '' : 'template');
  1337.         foreach($value as $line)
  1338.         {
  1339.             $this->_addDocBlockoutput($dbtype, $line[0]);
  1340.             if ($line[1] === false)
  1341.             {
  1342.                 if (trim($line[0]) != '*/')
  1343.                 {
  1344.                     $this->newLineNum();
  1345.                     $this->_wp->linenum++;
  1346.                 }
  1347.                 continue;
  1348.             }
  1349.             $this->_addDocBlockoutput($dbtype, $line[1][0]);
  1350.             $stored = '';
  1351.             if (is_array($line[1][1]))
  1352.             {
  1353.                 foreach($line[1][1] as $i => $tpart)
  1354.                 {
  1355.                     if ($tpart == '@'.$name && $i == 0)
  1356.                     {
  1357.                         $tagname = 'tag';
  1358.                         if ($coretag) $tagname = 'coretag';
  1359.                         $this->_addDocBlockoutput($tagname,'@'.$name);
  1360.                         continue;
  1361.                     }
  1362.                     $stored .= ' '.$tpart;
  1363.                 }
  1364.             } else $stored = $line[1];
  1365.             $this->getInlineTags($stored);
  1366.             if (strpos($stored,'*/') === false)
  1367.             {
  1368.                 $this->newLineNum();
  1369.                 $this->_wp->linenum++;
  1370.             }
  1371.         }
  1372.     }
  1373.     
  1374.     /**
  1375.      * @see defaultTagHandler()
  1376.      */
  1377.     function coreTagHandler($name, $value)
  1378.     {
  1379.         return $this->defaultTagHandler($name, $value, true);
  1380.     }
  1381.     
  1382.     /**
  1383.      * Handles @global
  1384.      *
  1385.      * This handler works like {@link defaultTagHandler()} except it highlights
  1386.      * the type and variable (if present) in "@global type $variable" or
  1387.      * "@global type description"
  1388.      */
  1389.     function globalTagHandler($name, $value)
  1390.     {
  1391.         $this->paramTagHandler($name, $value);
  1392.     }
  1393.     
  1394.     /**
  1395.      * Handles @param
  1396.      *
  1397.      * This handler works like {@link defaultTagHandler()} except it highlights
  1398.      * the type and variable (if present) in "@param type $variable description"
  1399.      * or "@param type description"
  1400.      * @param boolean private parameter, checks for $var or not
  1401.      */
  1402.     function paramTagHandler($name, $value, $checkforvar = true)
  1403.     {
  1404.         $dbtype = 'docblock';
  1405.         $dbtype .= ($this->_pf_docblock ? '' : 'template');
  1406.         $ret = $this->retrieveType($value,0,$checkforvar);
  1407.         foreach($value as $num => $line)
  1408.         {
  1409.             $this->_addDocBlockoutput($dbtype, $line[0]);
  1410.             if ($line[1] === false)
  1411.             {
  1412.                 if (trim($line[0]) != '*/')
  1413.                 {
  1414.                     $this->newLineNum();
  1415.                     $this->_wp->linenum++;
  1416.                 }
  1417.                 continue;
  1418.             }
  1419.             $this->_addDocBlockoutput($dbtype, $line[1][0]);
  1420.             $stored = '';
  1421.             $typeloc = 1;
  1422.             $varloc = 2;
  1423.             if (is_array($line[1][1]))
  1424.             {
  1425.                 $this->_addDocBlockoutput('coretag','@'.$name.' ');
  1426.                 foreach($ret[0] as $text)
  1427.                 {
  1428.                     if (is_string($text)) $this->_addDocBlockoutput($dbtype,$text);
  1429.                     if (is_array($text))
  1430.                     {
  1431.                         if ($text[0] != 'desc') $this->_addDocBlockoutput($text[0],$text[1]);
  1432.                         else $stored .= $text[1];
  1433.                     }
  1434.                 }
  1435.             } else
  1436.             {
  1437.                 if (isset($ret[$num]))
  1438.                 {
  1439.                     foreach($ret[$num] as $text)
  1440.                     {
  1441.                         if (is_string($text)) $this->_addDocBlockoutput($dbtype,$text);
  1442.                         if (is_array($text))
  1443.                         {
  1444.                             if ($text[0] != 'desc') $this->_addDocBlockoutput($text[0],$text[1]);
  1445.                             else $stored .= $text[1];
  1446.                         }
  1447.                     }
  1448.                 } else $stored = $line[1];
  1449.             }
  1450.             $this->getInlineTags($stored);
  1451.             if (strpos($stored,'*/') === false)
  1452.             {
  1453.                 $this->newLineNum();
  1454.                 $this->_wp->linenum++;
  1455.             }
  1456.         }
  1457.     }
  1458.     
  1459.     /**
  1460.      * @see paramTagHandler()
  1461.      */
  1462.     function staticvarTagHandler($name, $value)
  1463.     {
  1464.         return $this->paramTagHandler($name, $value);
  1465.     }
  1466.     
  1467.     /**
  1468.      * @see paramTagHandler()
  1469.      */
  1470.     function varTagHandler($name, $value)
  1471.     {
  1472.         return $this->paramTagHandler($name, $value);
  1473.     }
  1474.     
  1475.     /**
  1476.      * Handles @return
  1477.      *
  1478.      * This handler works like {@link defaultTagHandler()} except it highlights
  1479.      * the type in "@return type description"
  1480.      */
  1481.     function returnTagHandler($name, $value)
  1482.     {
  1483.         $this->paramTagHandler($name, $value, false);
  1484.     }
  1485.     /**#@-*/
  1486.     
  1487.     /**
  1488.      * Retrieve the type portion of a @tag type description
  1489.      *
  1490.      * Tags like @param, @return and @var all have a PHP type portion in their
  1491.      * description.  Since the type may contain the expression "object blah"
  1492.      * where blah is a classname, it makes parsing out the type field complex.
  1493.      *
  1494.      * Even more complicated is the case where a tag variable can contain
  1495.      * multiple types, such as object blah|object blah2|false, and so this
  1496.      * method handles these cases.
  1497.      * @param array array of words that were separated by spaces
  1498.      * @param 0|1 0 = find the type, 1 = find the var, if present
  1499.      * @param boolean flag to determine whether to check for the end of a
  1500.      *        type is defined by a $varname
  1501.      * @return array Format: array(state (0 [find type], 1 [var], 2 [done]),
  1502.      *                             
  1503.      * @access private
  1504.      */
  1505.     function retrieveType($value, $state = 0, $checkforvar = false)
  1506.     {
  1507.         $index = 0;
  1508.         $result = array();
  1509.         do
  1510.         {
  1511.             if (!isset($value[$index][1])) return $result;
  1512.             $val = $value[$index][1];
  1513.             if (empty($val)) return $result;
  1514.             if ($index == 0)
  1515.             {
  1516.                 $val = $val[1];
  1517.                 array_shift($val);
  1518.             } else
  1519.             {
  1520.                 $val = explode(' ',$val);
  1521.             }
  1522.             $ret = $this->_retrieveType($val, $state, $checkforvar);
  1523.             $state = $ret[0];
  1524.             $result[$index++] = $ret[1];
  1525.         } while ((!$checkforvar && $state < 1) || ($state < 2 && $checkforvar));
  1526.         return $result;
  1527.     }
  1528.     
  1529.     function _retrieveType($value, $state, $checkforvar)
  1530.     {
  1531.         $result = array();
  1532.         $result[] = $this->_removeWhiteSpace($value, 0);
  1533.         if ($state == 0)
  1534.         {
  1535.             if (!count($value)) return array(2,$result);
  1536.             $types = '';
  1537.             $index = 0;
  1538.             if (trim($value[0]) == 'object')
  1539.             {
  1540.                 $result[] = array('tagphptype', $value[0].' ');
  1541.                 $types .= array_shift($value).' ';
  1542.                 $result[] = $this->_removeWhiteSpace($value, 0);
  1543.                 if (!count($value))
  1544.                 { // was just passed "object"
  1545.                     return array(2,$result);
  1546.                 }
  1547.                 if ($value[0]{0} == '$' || substr($value[0],0,2) == '&$')
  1548.                 { // was just passed "object" and the next thing is a variable name
  1549.                     if ($checkforvar)
  1550.                     {
  1551.                         $result[] = array('tagvarname' , $value[0].' ');
  1552.                         array_shift($value);
  1553.                     }
  1554.                     $result[] = array('desc', join(' ', $value));
  1555.                     return array(2,$result);
  1556.                 }
  1557.             }
  1558.             $done = false;
  1559.             $loop = -1;
  1560.             do
  1561.             { // this loop checks for type|type|type and for
  1562.               // type|object classname|type|object classname2
  1563.                 if (strpos($value[0], '|'))
  1564.                 {
  1565.                     $temptypes = explode('|', $value[0]);
  1566.                     while(count($temptypes))
  1567.                     {
  1568.                         $type = array_shift($temptypes);
  1569.                         $result[] = array('tagphptype',$type);
  1570.                         if (count($temptypes)) $result[] = '|';
  1571.                     }
  1572.                     if (trim($type) == 'object')
  1573.                     {
  1574.                         $result[] = array('tagphptype', $types . ' ');
  1575.                         $result[] = $this->_removeWhiteSpace($value,0);
  1576.                     } else $done = true;
  1577.                     array_shift($value);
  1578.                     if (count($value) && strlen($value[0]) && isset ($value[0]) && ($value[0]{0} == '$' || substr($value[0],0,2) == '&$'))
  1579.                     { // was just passed "object" and the next thing is a variable name
  1580.                         $result[] = array('tagvarname' , $value[0].' ');
  1581.                         array_shift($value);
  1582.                         $result[] = array('desc', join(' ', $value));
  1583.                         return array(2,$result);
  1584.                     }
  1585.                 } else
  1586.                 {
  1587.                     $result[] = array('tagphptype', $value[0].' ');
  1588.                     array_shift($value);
  1589.                     $done = true;
  1590.                 }
  1591.                 $loop++;
  1592.             } while (!$done && count($value));
  1593.             if ($loop) $result[] = ' ';
  1594.             // still searching for type
  1595.             if (!$done && !count($value)) return array(0,$result);
  1596.             // still searching for var
  1597.             if ($done && !count($value)) return array(1,$result);
  1598.         }
  1599.         $result[] = $this->_removeWhiteSpace($value,0);
  1600.         $state = 1;
  1601.         if ($checkforvar)
  1602.         {
  1603.             if (count($value))
  1604.             {
  1605.                 $state = 2;
  1606.                 if (substr($value[0],0,1) == '$' || substr($value[0],0,2) == '&$')
  1607.                 {
  1608.                     $result[] = array('tagvarname' , $value[0].' ');
  1609.                     array_shift($value);
  1610.                 }
  1611.             } else $state = 1;
  1612.         }
  1613.         $result[] = array('desc', join(' ',$value));
  1614.         return array($state,$result);
  1615.     }
  1616.     
  1617.     
  1618.     /**
  1619.      * @param array array of string
  1620.      * @param integer index to seek non-whitespace to
  1621.      * @access private
  1622.      * @return string whitespace
  1623.      */
  1624.     function _removeWhiteSpace(&$value, $index)
  1625.     {
  1626.         $result = '';
  1627.         if (count($value) > $index && empty($value[$index]))
  1628.         {
  1629.             $found = false;
  1630.             for($i=$index; $i<count($value) && !strlen($value[$i]); $i++) $result .= ' ';
  1631.             array_splice($value, $index, $i - $index);
  1632.         }
  1633.         return $result;
  1634.     }
  1635.  
  1636.     /**#@+
  1637.      * Link generation methods
  1638.      * @access private
  1639.      * @param string|array token to try to link
  1640.      */
  1641.     /**
  1642.      * Generate a link to documentation for an element
  1643.      *
  1644.      * This method tries to link to documentation for functions, methods,
  1645.      * PHP functions, class names, and if found, adds the links to output
  1646.      * instead of plain text
  1647.      */
  1648.     function _link($word)
  1649.     {
  1650.         if (is_array($word) && $word[0] == T_STRING)
  1651.         {
  1652.             if ($this->_pf_colon_colon)
  1653.             {
  1654.                 $this->_pf_colon_colon = false;
  1655.                 $combo = $this->_pv_last_string[1].'::'.$word[1].'()';
  1656. //                debug('testing '.$combo);
  1657.                 $link = $this->_converter->getLink($combo);
  1658.                 if (is_object($link))
  1659.                 {
  1660.                     $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1661.                     return;
  1662.                 }
  1663.                 $this->_addoutput($word);
  1664.                 return;
  1665.             }
  1666.             $link = $this->_converter->getLink($word[1].'()');
  1667.             if (is_object($link))
  1668.             {
  1669.                 $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1670.                 return;
  1671.             } elseif (is_string($link) && strpos($link,'ttp://'))
  1672.             {
  1673.                 $this->_addoutput($this->_converter->returnLink($link, $word[1]), true);
  1674.                 return;
  1675.             } else
  1676.             {
  1677.                 $link = $this->_converter->getLink($word[1]);
  1678.                 if (is_object($link)) $word[1] = $this->_converter->returnSee($link, $word[1]);
  1679.                 $this->_addoutput($word, true);
  1680.                 return;
  1681.             }
  1682.         }
  1683.         $this->_addoutput($word);
  1684.     }
  1685.     
  1686.     /**
  1687.      * Works like {@link _link()} except it only links to global variables
  1688.      */
  1689.     function _globallink($word)
  1690.     {
  1691.         if (!is_array($word)) return $word;
  1692.         if ($word[0] != T_VARIABLE) return $word;
  1693.         if (is_array($word) && $word[0] == T_VARIABLE)
  1694.         {
  1695.             $link = $this->_converter->getLink('global '.$word[1]);
  1696.             if (is_object($link))
  1697.             {
  1698.                 $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1699.                 return;
  1700.             }
  1701.         }
  1702.         $this->_addoutput($word);
  1703.     }
  1704.     
  1705.     /**
  1706.      * Works like {@link _link()} except it only links to classes
  1707.      */
  1708.     function _classlink($word)
  1709.     {
  1710. //            debug("checking class ".$word[1]);
  1711.         if (is_array($word) && $word[0] == T_STRING)
  1712.         {
  1713.             $link = $this->_converter->getLink($word[1]);
  1714.             if (is_object($link))
  1715.             {
  1716.                 $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1717.                 return;
  1718.             }
  1719.         }
  1720.         $this->_addoutput($word);
  1721.     }
  1722.     
  1723.     /**
  1724.      * Works like {@link _link()} except it only links to methods
  1725.      */
  1726.     function _methodlink($word)
  1727.     {
  1728.         if (is_array($word) && $word[0] == T_STRING)
  1729.         {
  1730. //            debug("checking method ".$this->_pv_class.'::'.$word[1].'()');
  1731.             if (isset($this->_pv_prev_var_type))
  1732.             {
  1733.                 $link = $this->_converter->getLink($this->_pv_prev_var_type.'::'.$word[1].'()');
  1734.             } else
  1735.                 $link = $this->_converter->getLink($this->_pv_class.'::'.$word[1].'()');
  1736.             if (is_object($link))
  1737.             {
  1738.                 $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1739.                 return;
  1740.             }
  1741.             if (isset($this->_pv_prev_var_type))
  1742.             {
  1743.                 $this->_addoutput($word);
  1744.                 return;
  1745.             }
  1746. //            debug("checking method ".$word[1].'()');
  1747.             $link = $this->_converter->getLink($word[1].'()');
  1748.             if (is_object($link))
  1749.             {
  1750.                 $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1751.                 return;
  1752.             }
  1753.         }
  1754.         $this->_addoutput($word);
  1755.     }
  1756.     
  1757.     /**
  1758.      * Works like {@link _link()} except it only links to class variables
  1759.      */
  1760.     function _varlink($word, $justastring=false)
  1761.     {
  1762.         if ($justastring)
  1763.         {
  1764.             $word[0] = T_VARIABLE;
  1765.         }
  1766.         if (is_array($word) && $word[0] == T_VARIABLE)
  1767.         {
  1768.             $x = ($justastring ? '$' : '');
  1769. //            debug("checking var ".$this->_pv_class.'::'.$x.$word[1]);
  1770.             if (isset($this->_pv_prev_var_type))
  1771.             {
  1772. //            debug("checking var ".$this->_pv_prev_var_type.'::'.$x.$word[1]);
  1773.                 $link = $this->_converter->getLink($this->_pv_prev_var_type.'::'.$x.$word[1]);
  1774.             }
  1775.             else
  1776.             $link = $this->_converter->getLink($this->_pv_class.'::'.$x.$word[1]);
  1777.             if (is_object($link))
  1778.             {
  1779.                 $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1780.                 return;
  1781.             }
  1782. //            debug("checking var ".$x.$word[1]);
  1783.             if (isset($this->_pv_prev_var_type))
  1784.             {
  1785.                 $this->_addoutput($word);
  1786.                 return;
  1787.             }
  1788.             $link = $this->_converter->getLink($x.$word[1]);
  1789.             if (is_object($link))
  1790.             {
  1791.                 $this->_addoutput($this->_converter->returnSee($link, $word[1]), true);
  1792.                 return;
  1793.             }
  1794.         }
  1795.         $this->_addoutput($word);
  1796.     }
  1797.     /**#@-*/
  1798.     
  1799.     /**#@+
  1800.      * Output Methods
  1801.      * @access private
  1802.      */
  1803.     /**
  1804.      * This method adds output to {@link $_line}
  1805.      *
  1806.      * If a string with variables like "$test this" is present, then special
  1807.      * handling is used to allow processing of the variable in context.
  1808.      * @see _flush_save()
  1809.      */
  1810.     function _addoutput($word, $preformatted = false)
  1811.     {
  1812.         if ($this->_pf_no_output_yet) return;
  1813.         if ($this->_pf_quote_active)
  1814.         {
  1815.             if (is_array($word)) $this->_save .= $this->_converter->highlightSource($word[0], $word[1]);
  1816.             else
  1817.             $this->_save .= $this->_converter->highlightSource(false, $word, true);
  1818.         } else
  1819.         {
  1820.             $this->_flush_save();
  1821.             if (is_string($word) && trim($word) == '')
  1822.             {
  1823.                 $this->_line .= $word;
  1824.                 return;
  1825.             }
  1826.             if (is_array($word) && trim($word[1]) == '')
  1827.             {
  1828.                 $this->_line .= $word[1];
  1829.                 return;
  1830.             }
  1831.             if (is_array($word)) 
  1832.             {
  1833.                 $this->_line .= $this->_converter->highlightSource($word[0], $word[1], $preformatted);
  1834.             } else
  1835.             {
  1836.                 $this->_line .= $this->_converter->highlightSource(false, $word, $preformatted);
  1837.             }
  1838.         }
  1839.     }
  1840.     
  1841.     /** 
  1842.      * Like {@link _output()}, but for DocBlock highlighting
  1843.      */
  1844.     function _addDocBlockoutput($dbtype, $word, $preformatted = false)
  1845.     {
  1846.         if ($this->_pf_internal)
  1847.         {
  1848.             $this->_line .= $this->_converter->highlightDocBlockSource('internal', $word, $preformatted);
  1849.         } else
  1850.         {
  1851.             $this->_line .= $this->_converter->highlightDocBlockSource($dbtype, $word, $preformatted);
  1852.         }
  1853.     }
  1854.     
  1855.     /**
  1856.      * Flush a saved string variable highlighting
  1857.      *
  1858.      * {@source}
  1859.      */
  1860.     function _flush_save()
  1861.     {
  1862.         if (!empty($this->_save))
  1863.         {
  1864.             $this->_line .= $this->_converter->highlightSource(T_CONSTANT_ENCAPSED_STRING, $this->_save, true);
  1865.             $this->_save = '';
  1866.         }
  1867.     }
  1868.     /**#@-*/
  1869.     
  1870.     /**
  1871.      * Give the word parser necessary data to begin a new parse
  1872.      * @param array all tokens separated by line number
  1873.      */
  1874.     function configWordParser(&$data)
  1875.     {
  1876.         $this->_wp->setup($data, $this);
  1877.         $this->_wp->setWhitespace(true);
  1878.     }
  1879.  
  1880.     /**
  1881.      * Initialize all parser state variables
  1882.      * @param boolean true if we are highlighting an inline {@}source} tag's
  1883.      *                output
  1884.      * @param false|string name of class we are going to start from
  1885.      * @uses $_wp sets to a new {@link phpDocumentor_HighlightWordParser}
  1886.      */
  1887.     function setupStates($inlinesourceparse, $class)
  1888.     {
  1889.         $this->_output = '';
  1890.         $this->_line = '';
  1891.         unset($this->_wp);
  1892.         $this->_wp = new phpDocumentor_HighlightWordParser;
  1893.         $this->_event_stack = new EventStack;
  1894.         if ($inlinesourceparse)
  1895.         {
  1896.             $this->_event_stack->pushEvent(PARSER_EVENT_PHPCODE);
  1897.             if ($class)
  1898.             {
  1899.                 $this->_event_stack->pushEvent(PARSER_EVENT_CLASS);
  1900.                 $this->_pv_class = $class;
  1901.             }
  1902.         } else $this->_pv_class = null;
  1903.         $this->_pv_define = null;
  1904.         $this->_pv_define_name = null;
  1905.         $this->_pv_define_value = null;
  1906.         $this->_pv_define_params_data = null;
  1907.         $this->_pv_dtype = null;
  1908.         $this->_pv_docblock = null;
  1909.         $this->_pv_dtemplate = null;
  1910.         $this->_pv_func = null;
  1911.         $this->_pv_global_name = null;
  1912.         $this->_pv_global_val = null;
  1913.         $this->_pv_globals = null;
  1914.         $this->_pv_global_count = null;
  1915.         $this->_pv_include_params_data = null;
  1916.         $this->_pv_include_name = null;
  1917.         $this->_pv_include_value = null;
  1918.         $this->_pv_linenum = null;
  1919.         $this->_pv_periodline = null;
  1920.         $this->_pv_paren_count = 0;
  1921.         $this->_pv_statics = null;
  1922.         $this->_pv_static_count = null;
  1923.         $this->_pv_static_val = null;
  1924.         $this->_pv_quote_data = null;
  1925.         $this->_pv_function_data = null;
  1926.         $this->_pv_var = null;
  1927.         $this->_pv_varname = null;
  1928.         $this->_pf_definename_isset = false;
  1929.         $this->_pf_extends_found = false;
  1930.         $this->_pf_includename_isset = false;
  1931.         $this->_pf_get_source = false;
  1932.         $this->_pf_getting_source = false;
  1933.         $this->_pf_in_class = false;
  1934.         $this->_pf_in_define = false;
  1935.         $this->_pf_in_global = false;
  1936.         $this->_pf_in_include = false;
  1937.         $this->_pf_in_var = false;
  1938.         $this->_pf_funcparam_val = false;
  1939.         $this->_pf_quote_active = false;
  1940.         $this->_pf_reset_quote_data = true;
  1941.         $this->_pf_useperiod = false;
  1942.         $this->_pf_var_equals = false;
  1943.         $this->_pf_obj_op = false;
  1944.         $this->_pf_docblock = false;
  1945.         $this->_pf_docblock_template = false;
  1946.         $this->_pf_colon_colon = false;
  1947.         $this->_pv_last_string = false;
  1948.         $this->_pf_inmethod = false;
  1949.         $this->_pf_no_output_yet = false;
  1950.         $this->_pv_saveline = 0;
  1951.         $this->_pv_next_word = false;
  1952.         $this->_save = '';
  1953.     }
  1954.  
  1955.     /**
  1956.      * Initialize the {@link $tokenpushEvent, $wordpushEvent} arrays
  1957.      */
  1958.     function phpDocumentor_HighlightParser()
  1959.     {
  1960.         $this->allowableTags = $GLOBALS['_phpDocumentor_tags_allowed'];
  1961.         $this->allowableInlineTags = $GLOBALS['_phpDocumentor_inline_doc_tags_allowed'];
  1962.         $this->inlineTagHandlers = array('*' => 'handleDefaultInlineTag');
  1963. /**************************************************************/
  1964.  
  1965.         $this->tokenpushEvent[PARSER_EVENT_NOEVENTS] = 
  1966.             array(
  1967.                 T_OPEN_TAG => PARSER_EVENT_PHPCODE,
  1968.             );
  1969.  
  1970. /**************************************************************/
  1971.  
  1972.         $this->tokenpushEvent[PARSER_EVENT_PHPCODE] = 
  1973.             array(
  1974.                 T_FUNCTION     => PARSER_EVENT_FUNCTION,
  1975.                 T_CLASS     => PARSER_EVENT_CLASS,
  1976.                 T_INCLUDE_ONCE => PARSER_EVENT_INCLUDE,
  1977.                 T_INCLUDE => PARSER_EVENT_INCLUDE,
  1978.                 T_REQUIRE    => PARSER_EVENT_INCLUDE,
  1979.                 T_REQUIRE_ONCE    => PARSER_EVENT_INCLUDE,
  1980.                 T_COMMENT   => PARSER_EVENT_DOCBLOCK,
  1981.             );
  1982.         $this->wordpushEvent[PARSER_EVENT_PHPCODE] =
  1983.             array(
  1984.                 "define"     => PARSER_EVENT_DEFINE,
  1985.             );
  1986. /**************************************************************/
  1987.  
  1988.         $this->wordpushEvent[PARSER_EVENT_FUNCTION] =
  1989.             array(
  1990.                 '{'     => PARSER_EVENT_LOGICBLOCK,
  1991.                 '('     => PARSER_EVENT_FUNCTION_PARAMS,
  1992.             );
  1993.         $this->tokenpushEvent[PARSER_EVENT_FUNCTION] =
  1994.             array(
  1995.                 T_COMMENT   => PARSER_EVENT_COMMENT,
  1996.                 T_ML_COMMENT => PARSER_EVENT_COMMENT,
  1997.             );
  1998.  
  1999.         $this->wordpopEvent[PARSER_EVENT_FUNCTION] = array("}");
  2000. /**************************************************************/
  2001.  
  2002.         $this->tokenpushEvent[PARSER_EVENT_FUNCTION_PARAMS] =
  2003.             array(
  2004.                 T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,
  2005.                 T_ARRAY => PARSER_EVENT_ARRAY,
  2006.                 T_COMMENT => PARSER_EVENT_COMMENT,
  2007.                 T_ML_COMMENT => PARSER_EVENT_COMMENT,
  2008.             );
  2009.         $this->wordpushEvent[PARSER_EVENT_FUNCTION_PARAMS] =
  2010.             array(
  2011.                 '"' => PARSER_EVENT_QUOTE,
  2012.                 "'" => PARSER_EVENT_QUOTE,
  2013.             );
  2014.         $this->wordpopEvent[PARSER_EVENT_FUNCTION_PARAMS] = array(")");
  2015. /**************************************************************/
  2016.  
  2017.         $this->wordpushEvent[PARSER_EVENT_LOGICBLOCK] = 
  2018.             array(
  2019.                 "{"    => PARSER_EVENT_LOGICBLOCK,
  2020.                 '"'    => PARSER_EVENT_QUOTE,
  2021.             );
  2022.         $this->tokenpushEvent[PARSER_EVENT_LOGICBLOCK] =
  2023.             array(
  2024.                 T_GLOBAL    => PARSER_EVENT_FUNC_GLOBAL,
  2025.                 T_STATIC    => PARSER_EVENT_STATIC_VAR,
  2026.                 T_CURLY_OPEN    => PARSER_EVENT_LOGICBLOCK,
  2027.                 T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK,
  2028.             );
  2029.  
  2030.         $this->wordpopEvent[PARSER_EVENT_LOGICBLOCK] = array("}");
  2031.         $this->tokenpopEvent[PARSER_EVENT_LOGICBLOCK] = array(T_CURLY_OPEN);
  2032.  
  2033. /**************************************************************/
  2034.  
  2035.         $this->tokenpushEvent[PARSER_EVENT_ARRAY] = 
  2036.             array(
  2037.                 T_COMMENT  => PARSER_EVENT_COMMENT,
  2038.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2039.             );
  2040.         $this->wordpopEvent[PARSER_EVENT_ARRAY] = array(")");
  2041. /**************************************************************/
  2042.  
  2043.         $this->tokenpushEvent[PARSER_EVENT_FUNC_GLOBAL] =
  2044.             array(
  2045.                 T_COMMENT   => PARSER_EVENT_COMMENT,
  2046.                 T_ML_COMMENT    => PARSER_EVENT_COMMENT,
  2047.             );
  2048.  
  2049.         $this->wordpopEvent[PARSER_EVENT_FUNC_GLOBAL] = array(";");
  2050. /**************************************************************/
  2051.  
  2052.         $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR] =
  2053.             array(
  2054.                 T_CONSTANT_ENCAPSED_STRING  => PARSER_EVENT_QUOTE,
  2055.                 T_COMMENT   => PARSER_EVENT_COMMENT,
  2056.                 T_ML_COMMENT    => PARSER_EVENT_COMMENT,
  2057.             );
  2058.         $this->wordpushEvent[PARSER_EVENT_STATIC_VAR] =
  2059.             array(
  2060.                 "="        => PARSER_EVENT_STATIC_VAR_VALUE,
  2061.             );
  2062.         $this->wordpopEvent[PARSER_EVENT_STATIC_VAR] = array(";");
  2063. /**************************************************************/
  2064.  
  2065.         $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] = 
  2066.             array(
  2067.                 T_CONSTANT_ENCAPSED_STRING  => PARSER_EVENT_QUOTE,
  2068.                 T_COMMENT   => PARSER_EVENT_COMMENT,
  2069.                 T_ML_COMMENT    => PARSER_EVENT_COMMENT,
  2070.                 T_ARRAY     => PARSER_EVENT_ARRAY,
  2071.             );
  2072.         $this->wordpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] =
  2073.             array(
  2074.                 '"' => PARSER_EVENT_QUOTE,
  2075.                 "'" => PARSER_EVENT_QUOTE,
  2076.             );
  2077.         $this->wordpopEvent[PARSER_EVENT_STATIC_VAR_VALUE] = array(";",",");
  2078. /**************************************************************/
  2079.         $this->tokenpushEvent[PARSER_EVENT_QUOTE] = 
  2080.             array(
  2081.                 T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
  2082.                 T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR,
  2083.             );
  2084.  
  2085.         $this->wordpopEvent[PARSER_EVENT_QUOTE] = array('"');
  2086. /**************************************************************/
  2087.         $this->tokenpushEvent[PARSER_EVENT_QUOTE_VAR] = 
  2088.             array(
  2089.                 T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
  2090.                 T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR,
  2091.             );
  2092.  
  2093.         $this->wordpushEvent[PARSER_EVENT_QUOTE_VAR] =
  2094.             array(
  2095.                 "{" => PARSER_EVENT_QUOTE_VAR,
  2096.                 '"' => PARSER_EVENT_QUOTE_VAR,
  2097.                 "'" => PARSER_EVENT_QUOTE_VAR,
  2098.             );
  2099.         $this->wordpopEvent[PARSER_EVENT_QUOTE_VAR] = array('}');
  2100. /**************************************************************/
  2101.  
  2102.         $this->tokenpushEvent[PARSER_EVENT_DEFINE] = 
  2103.             array(
  2104.                 T_COMMENT     => PARSER_EVENT_COMMENT,
  2105.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2106.                 T_CONSTANT_ENCAPSED_STRING        => PARSER_EVENT_QUOTE,
  2107.             );
  2108.         $this->wordpushEvent[PARSER_EVENT_DEFINE] = 
  2109.             array(
  2110.                 "("     => PARSER_EVENT_DEFINE_PARAMS,
  2111.             );
  2112.         $this->wordpopEvent[PARSER_EVENT_DEFINE] = array(";");
  2113. /**************************************************************/
  2114.  
  2115.         $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS] = 
  2116.             array(
  2117.                 T_COMMENT     => PARSER_EVENT_COMMENT,
  2118.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2119.             );
  2120.         $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS] = 
  2121.             array(
  2122.                 "("    =>    PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,
  2123.                 '"' => PARSER_EVENT_QUOTE,
  2124.                 "'" => PARSER_EVENT_QUOTE,
  2125.             );
  2126.         $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS] = array(")");
  2127. /**************************************************************/
  2128.  
  2129.         $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] =
  2130.             array(
  2131.                 T_COMMENT     => PARSER_EVENT_COMMENT,
  2132.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2133.             );
  2134.         $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] =
  2135.             array(
  2136.                 "("    =>    PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,
  2137.                 '"' => PARSER_EVENT_QUOTE,
  2138.                 "'" => PARSER_EVENT_QUOTE,
  2139.             );
  2140.         $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = array(")");
  2141. /**************************************************************/
  2142.  
  2143.         $this->tokenpushEvent[PARSER_EVENT_VAR] = 
  2144.             array(
  2145.                 T_COMMENT     => PARSER_EVENT_COMMENT,
  2146.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2147.                 T_ARRAY     => PARSER_EVENT_ARRAY,
  2148.             );
  2149.         $this->wordpopEvent[PARSER_EVENT_VAR] = array(";");
  2150. /**************************************************************/
  2151.  
  2152.         $this->tokenpushEvent[PARSER_EVENT_CLASS] = 
  2153.             array(
  2154.                 T_FUNCTION     => PARSER_EVENT_METHOD,
  2155.                 T_VAR         => PARSER_EVENT_VAR,
  2156.                 T_COMMENT         => PARSER_EVENT_DOCBLOCK,
  2157.                 T_ML_COMMENT         => PARSER_EVENT_DOCBLOCK,
  2158.                 T_CLOSE_TAG        => PARSER_EVENT_OUTPHP,
  2159.             );
  2160.         $this->wordpopEvent[PARSER_EVENT_CLASS] = array("}");
  2161.  
  2162. /**************************************************************/
  2163.  
  2164.         $this->wordpushEvent[PARSER_EVENT_METHOD] =
  2165.             array(
  2166.                 '{'     => PARSER_EVENT_METHOD_LOGICBLOCK,
  2167.                 '('     => PARSER_EVENT_FUNCTION_PARAMS,
  2168.             );
  2169.         $this->tokenpushEvent[PARSER_EVENT_METHOD] =
  2170.             array(
  2171.                 T_COMMENT   => PARSER_EVENT_COMMENT,
  2172.                 T_ML_COMMENT => PARSER_EVENT_COMMENT,
  2173.             );
  2174.  
  2175.         $this->wordpopEvent[PARSER_EVENT_METHOD] = array("}");
  2176. /**************************************************************/
  2177.  
  2178.         $this->wordpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = 
  2179.             array(
  2180.                 "{"    => PARSER_EVENT_METHOD_LOGICBLOCK,
  2181.                 '"'    => PARSER_EVENT_QUOTE,
  2182.             );
  2183.         $this->tokenpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] =
  2184.             array(
  2185.                 T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
  2186.                 T_GLOBAL    => PARSER_EVENT_FUNC_GLOBAL,
  2187.                 T_STATIC    => PARSER_EVENT_STATIC_VAR,
  2188.                 T_CURLY_OPEN    => PARSER_EVENT_LOGICBLOCK,
  2189.                 T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK,
  2190.             );
  2191.  
  2192.         $this->wordpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array("}");
  2193.         $this->tokenpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array(T_CURLY_OPEN);
  2194. /**************************************************************/
  2195.  
  2196.         $this->tokenpushEvent[PARSER_EVENT_INCLUDE] = 
  2197.             array(
  2198.                 T_COMMENT     => PARSER_EVENT_COMMENT,
  2199.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2200.             );
  2201.         $this->wordpushEvent[PARSER_EVENT_INCLUDE] = 
  2202.             array(
  2203.                 "("     => PARSER_EVENT_INCLUDE_PARAMS,
  2204.             );
  2205.         $this->wordpopEvent[PARSER_EVENT_INCLUDE] = array(";");
  2206. /**************************************************************/
  2207.  
  2208.         $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS] = 
  2209.             array(
  2210.                 T_COMMENT     => PARSER_EVENT_COMMENT,
  2211.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2212.             );
  2213.         $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS] = 
  2214.             array(
  2215.                 "("    =>    PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,
  2216.             );
  2217.         $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS] = array(")");
  2218. /**************************************************************/
  2219.  
  2220.         $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] =
  2221.             array(
  2222.                 T_COMMENT     => PARSER_EVENT_COMMENT,
  2223.                 T_ML_COMMENT     => PARSER_EVENT_COMMENT,
  2224.             );
  2225.         $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] =
  2226.             array(
  2227.                 "("    =>    PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,
  2228.             );
  2229.         $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = array(")");
  2230.     }
  2231. }
  2232. ?>
  2233.