summaryrefslogtreecommitdiff
path: root/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc
diff options
context:
space:
mode:
authorctrlaltca@gmail.com <>2011-11-19 11:33:31 +0000
committerctrlaltca@gmail.com <>2011-11-19 11:33:31 +0000
commit98dbe6f0d2edfff3a1f5785504504b4a6e5dd4eb (patch)
tree89f19120abb170cb37bb512c8c9535eb2b451da8 /buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc
parent1f09b786730956d01c48a82272617a0f8b2597f0 (diff)
updating phpDocumentor, part 2: add new version
Diffstat (limited to 'buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc')
-rwxr-xr-xbuildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc2603
1 files changed, 2603 insertions, 0 deletions
diff --git a/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc b/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc
new file mode 100755
index 00000000..a474f73c
--- /dev/null
+++ b/buildscripts/PhpDocumentor/phpDocumentor/HighlightParser.inc
@@ -0,0 +1,2603 @@
+<?php
+/**
+ * Source Code Highlighting
+ *
+ * The classes in this file are responsible for the dynamic @example, @filesource
+ * and {@}source} tags output. Using the phpDocumentor_HighlightWordParser,
+ * the phpDocumentor_HighlightParser retrieves PHP tokens one by one from the
+ * array generated by {@link phpDocumentorTWordParser} source retrieval functions
+ * and then highlights them individually.
+ *
+ * It accomplishes this highlighting through the assistance of methods in
+ * the output Converter passed to its parse() method, and then returns the
+ * fully highlighted source as a string
+ *
+ * phpDocumentor :: automatic documentation generator
+ *
+ * PHP versions 4 and 5
+ *
+ * Copyright (c) 2002-2008 Gregory Beaver
+ *
+ * LICENSE:
+ *
+ * This library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation;
+ * either version 2.1 of the License, or (at your option) any
+ * later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * @category ToolsAndUtilities
+ * @package phpDocumentor
+ * @subpackage Parsers
+ * @author Gregory Beaver <cellog@php.net>
+ * @copyright 2002-2008 Gregory Beaver
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @version CVS: $Id: HighlightParser.inc 253641 2008-02-24 02:35:44Z ashnazg $
+ * @filesource
+ * @link http://www.phpdoc.org
+ * @link http://pear.php.net/PhpDocumentor
+ * @tutorial tags.example.pkg, tags.filesource.pkg, tags.inlinesource.pkg
+ * @since 1.2.0beta3
+ * @todo CS cleanup - change package to PhpDocumentor
+ */
+
+/**
+ * Retrieve tokens from an array of tokens organized by line numbers
+ *
+ * @category ToolsAndUtilities
+ * @package phpDocumentor
+ * @subpackage Parsers
+ * @author Gregory Beaver <cellog@php.net>
+ * @copyright 2002-2008 Gregory Beaver
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @version Release: 1.4.3
+ * @link http://www.phpdoc.org
+ * @link http://pear.php.net/PhpDocumentor
+ * @since 1.2.0beta3
+ * @todo CS cleanup - change package to PhpDocumentor
+ * @todo CS cleanup - change class name to PhpDocumentor_*
+ */
+class phpDocumentor_HighlightWordParser extends phpDocumentorTWordParser
+{
+ /**
+ * Hash used to keep track of line numbers that have already been initialized
+ * @var array
+ * @access private
+ */
+ var $_listLineNums = array();
+ /**
+ * Initialize the parser object
+ *
+ * @param array &$input the input
+ * @param phpDocumentor_HighlightParser &$parser the parser
+ *
+ * @return void
+ */
+ function setup(&$input, &$parser)
+ {
+ $this->_parser = &$parser;
+ $this->data = &$input;
+ $this->_all = $input;
+ $this->_sourceline = 0;
+ $this->pos = 0;
+ $this->linenum = 0;
+ }
+
+ /**
+ * debugging function
+ *
+ * @return void
+ * @access private
+ */
+ function printState()
+ {
+ $linenum = $this->linenum;
+ $pos = $this->pos;
+ if (!isset($this->_all[$this->linenum][$this->pos])) {
+ $linenum++;
+ $pos = 0;
+ }
+ $details = '';
+ $token = $this->_all[$linenum][$pos];
+ if (is_array($token)) {
+ $details = token_name($token[0]);
+ $token = htmlspecialchars($token[1]);
+ } else {
+ $token = htmlspecialchars($token);
+ }
+ debug('Next Token ' . $this->linenum . '-' . $this->pos . ':' . $details);
+ var_dump($token);
+ }
+
+ /**
+ * Retrieve the position of the next token that will be parsed
+ * in the internal token array
+ *
+ * @return array format: array(line number, position)
+ */
+ function nextToken()
+ {
+ $linenum = $this->linenum;
+ $pos = $this->pos;
+ if (!isset($this->_all[$this->linenum][$this->pos])) {
+ $linenum++;
+ $pos = 0;
+ }
+ if (!isset($this->_all[$linenum][$pos])) {
+ return false;
+ }
+ return array($linenum, $pos);
+ }
+
+ /**
+ * Retrieve the next token
+ *
+ * @return array|string either array(PHP token constant, token) or string
+ * non-specific separator
+ */
+ function getWord()
+ {
+ if (!isset($this->_all[$this->linenum][$this->pos])) {
+ $this->linenum++;
+ $this->pos = 0;
+ if (!isset($this->_all[$this->linenum])) {
+ return false;
+ }
+ $this->_parser->newLineNum();
+ return $this->getWord();
+ }
+ $word = $this->_all[$this->linenum][$this->pos++];
+ return str_replace("\t", ' ', $word);
+ }
+
+ /**
+ * back the word parser to the previous token as defined by $last_token
+ *
+ * @param array|string $last_token token, or output from {@link nextToken()}
+ * @param bool $is_pos if true, backupPos interprets $last_token
+ * to be the position in the internal token
+ * array of the last token
+ *
+ * @return void
+ */
+ function backupPos($last_token, $is_pos = false)
+ {
+ if (!$last_token) {
+ return;
+ }
+ if ($is_pos) {
+ $this->linenum = $last_token[0];
+ $this->pos = $last_token[1];
+ return;
+ }
+ if ($last_token === false) {
+ return;
+ }
+
+ //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]);
+
+ do {
+ $this->pos--;
+ if ($this->pos < 0) {
+ $this->linenum--;
+ if ($this->linenum < 0) {
+ var_dump($last_token);
+ break;
+ }
+ $this->pos = count($this->_all[$this->linenum]) - 1;
+ }
+ } while (!$this->tokenEquals($last_token, str_replace("\t", ' ',
+ $this->_all[$this->linenum][$this->pos])));
+
+ //fancy_debug('after', $this->linenum, $this->pos,
+ // token_name($this->_all[$this->linenum][$this->pos][0]),
+ // htmlentities($this->_all[$this->linenum][$this->pos][1]));
+ }
+}
+
+/**
+ * Highlights source code using {@link parse()}
+ *
+ * @category ToolsAndUtilities
+ * @package phpDocumentor
+ * @subpackage Parsers
+ * @author Gregory Beaver <cellog@php.net>
+ * @copyright 2002-2008 Gregory Beaver
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @version Release: 1.4.3
+ * @link http://www.phpdoc.org
+ * @link http://pear.php.net/PhpDocumentor
+ * @since 1.2.0beta3
+ * @todo CS cleanup - change package to PhpDocumentor
+ * @todo CS cleanup - change class name to PhpDocumentor_*
+ */
+class phpDocumentor_HighlightParser extends phpDocumentorTParser
+{
+ /**#@+
+ * @access private
+ */
+
+ /**
+ * Highlighted source is built up in this string
+ * @var string
+ */
+ var $_output;
+
+ /**
+ * contents of the current source code line as it is parsed
+ * @var string
+ */
+ var $_line;
+
+ /**
+ * Used to retrieve highlighted tokens
+ * @var Converter a descendant of Converter
+ */
+ var $_converter;
+
+ /**
+ * Path to file being highlighted, if this is from a @filesource tag
+ * @var false|string full path
+ */
+ var $_filesourcepath;
+
+ /**
+ * @var array
+ */
+ var $eventHandlers = array(
+ PARSER_EVENT_ARRAY => 'defaultHandler',
+ PARSER_EVENT_CLASS => 'handleClass',
+ PARSER_EVENT_COMMENT => 'handleComment',
+ PARSER_EVENT_DOCBLOCK_TEMPLATE => 'handleDocBlockTemplate',
+ PARSER_EVENT_END_DOCBLOCK_TEMPLATE => 'handleEndDocBlockTemplate',
+ PARSER_EVENT_LOGICBLOCK => 'handleLogicBlock',
+ PARSER_EVENT_METHOD_LOGICBLOCK => 'handleMethodLogicBlock',
+ PARSER_EVENT_NOEVENTS => 'defaultHandler',
+ PARSER_EVENT_OUTPHP => 'defaultHandler',
+ PARSER_EVENT_CLASS_MEMBER => 'handleClassMember',
+ PARSER_EVENT_DEFINE => 'defaultHandler',
+ PARSER_EVENT_DEFINE_PARAMS => 'defaultHandler',
+ PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS => 'defaultHandler',
+ PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS => 'defaultHandler',
+ PARSER_EVENT_DOCBLOCK => 'handleDocBlock',
+ PARSER_EVENT_TAGS => 'handleTags',
+ PARSER_EVENT_DESC => 'handleDesc',
+ PARSER_EVENT_DOCKEYWORD => 'handleTag',
+ PARSER_EVENT_DOCKEYWORD_EMAIL => 'handleDockeywordEmail',
+ PARSER_EVENT_EOFQUOTE => 'handleQuote',
+ PARSER_EVENT_FUNCTION => 'handleFunction',
+ PARSER_EVENT_METHOD => 'handleMethod',
+ PARSER_EVENT_FUNCTION_PARAMS => 'handleFunctionParams',
+ PARSER_EVENT_FUNC_GLOBAL => 'handleFuncGlobal',
+ PARSER_EVENT_INLINE_DOCKEYWORD => 'handleInlineDockeyword',
+ PARSER_EVENT_INCLUDE => 'defaultHandler',
+ PARSER_EVENT_INCLUDE_PARAMS => 'defaultHandler',
+ PARSER_EVENT_QUOTE => 'handleQuote',
+ PARSER_EVENT_QUOTE_VAR => 'handleQuoteVar',
+ PARSER_EVENT_PHPCODE => 'handlePhpCode',
+ PARSER_EVENT_SINGLEQUOTE => 'handleSingleQuote',
+ PARSER_EVENT_STATIC_VAR => 'defaultHandler',
+ PARSER_EVENT_STATIC_VAR_VALUE => 'defaultHandler',
+ PARSER_EVENT_VAR => 'handleVar',
+ );
+
+ /**
+ * event handlers for @tags
+ * @tutorial tags.pkg
+ */
+ var $tagHandlers = array(
+ '*' => 'defaultTagHandler',
+ 'abstract' => 'coreTagHandler',
+ 'access' => 'coreTagHandler',
+ 'author' => 'coreTagHandler',
+ 'category' => 'coreTagHandler',
+ 'copyright' => 'coreTagHandler',
+ 'deprecated' => 'coreTagHandler',
+ 'example' => 'coreTagHandler',
+ 'filesource' => 'coreTagHandler',
+ 'final' => 'coreTagHandler',
+ 'global' => 'globalTagHandler',
+ 'ignore' => 'coreTagHandler',
+ 'license' => 'coreTagHandler',
+ 'link' => 'coreTagHandler',
+ 'name' => 'coreTagHandler',
+ 'package' => 'coreTagHandler',
+ 'param' => 'paramTagHandler',
+ 'parameter' => 'paramTagHandler',
+ 'see' => 'coreTagHandler',
+ 'since' => 'coreTagHandler',
+ 'subpackage' => 'coreTagHandler',
+ 'internal' => 'coreTagHandler',
+ 'return' => 'returnTagHandler',
+ 'static' => 'coreTagHandler',
+ 'staticvar' => 'staticvarTagHandler',
+ 'throws' => 'coreTagHandler',
+ 'todo' => 'coreTagHandler',
+ 'tutorial' => 'coreTagHandler',
+ 'uses' => 'coreTagHandler',
+ 'var' => 'varTagHandler',
+ 'version' => 'coreTagHandler',
+ 'property' => 'propertyTagHandler',
+ 'property-read' => 'propertyTagHandler',
+ 'property-write' => 'propertyTagHandler',
+ 'method' => 'propertyTagHandler'
+ );
+ /**#@-*/
+
+ /**
+ * wraps the current line (via the converter) and resets it to empty
+ *
+ * @return void
+ * @uses Converter::SourceLine() encloses {@link $_line} in a
+ * converter-specific format
+ */
+ function newLineNum()
+ {
+ if ($this->_pf_no_output_yet) {
+ return;
+ }
+ $this->_flush_save();
+ $this->_line .= $this->_converter->flushHighlightCache();
+ $this->_output .= $this->_converter->SourceLine($this->_wp->linenum,
+ $this->_line, $this->_path);
+ $this->_line = '';
+ }
+
+ /**
+ * Start the parsing at a certain line number
+ *
+ * @param int $num line number
+ *
+ * @return void
+ */
+ function setLineNum($num)
+ {
+ $this->_wp->linenum = $num;
+ }
+
+ /**
+ * Parse a new file
+ *
+ * The parse() method is a do...while() loop that retrieves tokens one by
+ * one from the {@link $_event_stack}, and uses the token event array set up
+ * by the class constructor to call event handlers.
+ *
+ * The event handlers each process the tokens passed to them, and use the
+ * {@link _addoutput()} method to append the processed tokens to the
+ * {@link $_line} variable. The word parser calls {@link newLineNum()}
+ * every time a line is reached.
+ *
+ * In addition, the event handlers use special linking functions
+ * {@link _link()} and its cousins (_classlink(), etc.) to create in-code
+ * hyperlinks to the documentation for source code elements that are in the
+ * source code.
+ *
+ * @param array &$parse_data the parse data
+ * @param Converter &$converter the converter object
+ * @param bool $inlinesourceparse whether this data is from an
+ * inline {@}source} tag
+ * @param string|false $class if a string, it is the name of the
+ * class whose method we are parsing
+ * containing a {@}source} tag
+ * @param false|integer $linenum starting line number from
+ * {@}source linenum}
+ * @param false|string $filesourcepath full path to file with @filesource
+ * tag, if this is a @filesource parse
+ *
+ * @staticvar int used for recursion limiting if a handler for
+ * an event is not found
+ * @return bool
+ * @uses setupStates() initialize parser state variables
+ * @uses configWordParser() pass $parse_data to prepare retrieval of tokens
+ * @todo CS cleanup - rename tokenizer_ext constant to uppercase
+ */
+ function parse (&$parse_data, &$converter, $inlinesourceparse = false,
+ $class = false, $linenum = false, $filesourcepath = false)
+ {
+ if (!tokenizer_ext) {
+ if (is_array($parse_data)) {
+ $parse_data = join($parse_data, '');
+ }
+ $parse_data = explode("\n", $parse_data);
+ $this->_output = '';
+ foreach ($parse_data as $linenum => $line) {
+ if ($linenum > 0) {
+ $this->_output .= $converter->SourceLine($linenum,
+ $line, $filesourcepath);
+ }
+ }
+ return $converter->PreserveWhiteSpace($this->_output);
+ }
+ static $endrecur = 0;
+ $this->_converter = &$converter;
+ $converter->startHighlight();
+ $this->_path = $filesourcepath;
+ $this->setupStates($inlinesourceparse, $class);
+
+ $this->configWordParser($parse_data);
+ if ($linenum !== false) {
+ $this->setLineNum($linenum);
+ }
+ // initialize variables so E_ALL error_reporting doesn't complain
+ $pevent = 0;
+ $word = 0;
+
+ do {
+ $lpevent = $pevent;
+ $pevent = $this->_event_stack->getEvent();
+ if ($lpevent != $pevent) {
+ $this->_last_pevent = $lpevent;
+ }
+
+ if ($pevent == PARSER_EVENT_CLASS_MEMBER) {
+ $this->_wp->setWhitespace(true);
+ } else {
+ $this->_wp->setWhitespace(false);
+ }
+
+ if (!is_array($word)) {
+ $lw = $word;
+ }
+ if (is_array($word) && $word[0] != T_WHITESPACE) {
+ $lw = $word;
+ }
+ $dbg_linenum = $this->_wp->linenum;
+ $dbg_pos = $this->_wp->getPos();
+ $word = $this->_wp->getWord();
+ if (is_array($word) && ($word[0] == T_WHITESPACE ||
+ $word[0] == T_COMMENT) &&
+ $pevent != PARSER_EVENT_CLASS_MEMBER
+ ) {
+ //debug("added " . $this->_wp->linenum . '-' . $this->_wp->pos);
+ $this->_addoutput($word);
+ continue;
+ } else {
+ $this->_pv_last_word = $lw;
+ }
+ if ($pevent != PARSER_EVENT_DOCBLOCK) {
+ $this->_pv_last_next_word = $this->_pv_next_word;
+ $this->_pv_next_word = $this->_wp->nextToken();
+ }
+ // in wordparser, have to keep track of lines
+ //$this->publishEvent(PHPDOCUMENTOR_EVENT_NEWLINENUM,
+ // $this->_wp->linenum);
+ if (PHPDOCUMENTOR_DEBUG == true) {
+ echo "LAST: ";
+ if (is_array($this->_pv_last_word)) {
+ echo token_name($this->_pv_last_word[0]) .
+ ' => |' .
+ htmlspecialchars($this->_pv_last_word[1]);
+ } else {
+ echo "|" . $this->_pv_last_word;
+ }
+ echo "|\n";
+ echo "PEVENT: " . $this->getParserEventName($pevent) . "\n";
+ echo "LASTPEVENT: " .
+ $this->getParserEventName($this->_last_pevent) . "\n";
+ //echo "LINE: " . $this->_line . "\n";
+ //echo "OUTPUT: " . $this->_output . "\n";
+ echo $dbg_linenum . '-' . $dbg_pos . ": ";
+ if (is_array($word)) {
+ echo token_name($word[0]) . ' => |' . htmlspecialchars($word[1]);
+ } else {
+ echo '|'.htmlspecialchars($word);
+ }
+ echo "|\n";
+ $this->_wp->printState();
+ echo "NEXT TOKEN: ";
+ $tok1 = $this->_pv_next_word;
+ $tok = $this->_wp->_all[$tok1[0]][$tok1[1]];
+ if (is_array($tok)) {
+ echo token_name($tok[0]) . ' => ' . $tok1[0] . '-' . $tok1[1] .
+ '|' . htmlspecialchars($tok[1]);
+ } else {
+ echo "|" . $tok;
+ }
+ echo "|\n";
+ echo "-------------------\n\n\n";
+ flush();
+ }
+ if ($word !== false && isset($this->eventHandlers[$pevent])) {
+ $handle = $this->eventHandlers[$pevent];
+ $this->$handle($word, $pevent);
+ } elseif ($word !== false) {
+ debug('WARNING: possible error, no handler for event number '
+ . $pevent);
+ if ($endrecur++ == 25) {
+ die("FATAL ERROR, recursion limit reached");
+ }
+ }
+ } while (!($word === false));
+ if (strlen($this->_line)) {
+ $this->newLineNum();
+ }
+ return $this->_output;
+ }
+
+ /**#@+
+ * Event Handlers
+ *
+ * All Event Handlers use {@link checkEventPush()} and
+ * {@link checkEventPop()} to set up the event stack and parser state.
+ *
+ * @param string|array $word token value
+ * @param int $pevent parser event from {@link Parser.inc}
+ *
+ * @return void
+ * @access private
+ */
+ /**
+ * Most tokens only need highlighting, and this method handles them
+ */
+ function defaultHandler($word, $pevent)
+ {
+ $this->_addoutput($word);
+ if ($this->checkEventPush($word, $pevent)) {
+ return;
+ }
+ $this->checkEventPop($word, $pevent);
+ }
+
+ /**
+ * Handles global declarations in a function, like:
+ *
+ * <code>
+ * function foobar()
+ * {
+ * global $_phpDocumentor_setting;
+ * }
+ * </code>
+ *
+ * @uses _globallink() instead of _addoutput(), to link to global variables
+ * if they are used in a function
+ */
+ function handleFuncGlobal($word, $pevent)
+ {
+ if ($this->checkEventPush($word, $pevent)) {
+ return;
+ }
+ $this->_globallink($word);
+ $this->checkEventPop($word, $pevent);
+ }
+
+ /**
+ * Handles strings in quotation marks and heredoc
+ *
+ * Special handling is needed for strings that contain variables like:
+ *
+ * <code>$a = "$test string"</code>
+ *
+ * The tokenizer parses out tokens '"',array(T_VARIABLE,'$test'),' string',
+ * and '"'. Since it is possible to have $this->classvar in a string,
+ * we save a variable name just in case the next token is -> to allow linking
+ * to class members. Otherwise, the string is simply highlighted.
+ *
+ * constant strings (with no $variables in them) are passed as a single
+ * entity, and so will be saved in the last token parsed. This means the
+ * event handler must tell the word parser to re-retrieve the current token
+ * so that the correct event handler can process it.
+ */
+ function handleQuote($word, $pevent)
+ {
+ if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) {
+ $this->_pv_lastvar = $word;
+ }
+ if ($this->checkEventPush($word, $pevent)) {
+ $this->_addoutput($word);
+ return;
+ }
+ if ($this->_pf_quote_active &&
+ (($this->_pv_last_word == '"' &&
+ $this->_last_pevent != PARSER_EVENT_QUOTE) ||
+ (is_array($this->_pv_last_word) &&
+ $this->_pv_last_word[0] == T_END_HEREDOC &&
+ $this->_last_pevent != PARSER_EVENT_EOFQUOTE))
+ ) {
+ $this->_pf_quote_active = false;
+ $this->_wp->backupPos($word);
+ $this->_event_stack->popEvent();
+ return;
+ }
+ if (!$this->_pf_quote_active &&
+ (($this->_pv_last_word == '"' &&
+ $this->_last_pevent != PARSER_EVENT_QUOTE) ||
+ (is_array($this->_pv_last_word) &&
+ $this->_pv_last_word[0] == T_END_HEREDOC &&
+ $this->_last_pevent != PARSER_EVENT_EOFQUOTE))
+ ) {
+ if (is_array($word) && $word[0] == T_VARIABLE) {
+ $this->_pv_lastvar = $word;
+ }
+ $this->_pf_quote_active = true;
+ $this->_save_highlight_state = $this->_converter->getHighlightState();
+ $this->_converter->startHighlight();
+ $this->_addoutput($word);
+ $this->checkEventPop($word, $pevent);
+ return;
+ } elseif (is_array($this->_pv_last_word) &&
+ $this->_pv_last_word[0] == T_CONSTANT_ENCAPSED_STRING
+ ) {
+ //$this->_pv_quote_data = $this->_pv_last_word[1];
+ $this->_event_stack->popEvent();
+ $this->_wp->backupPos($word);
+ return;
+ }
+ if ($this->checkEventPop($word, $pevent)) {
+ $this->_pf_quote_active = false;
+ }
+ $this->_addoutput($word);
+ }
+
+ /**
+ * Handles {$variable} within a "quote"
+ *
+ * This is a simple handler, for a very complex
+ * array of legal syntax. It is legal to nest control structures
+ * inside the {}, and other weird stuff.
+ */
+ function handleQuoteVar($word, $pevent)
+ {
+ if ($this->checkEventPop($word, $pevent)) {
+ $this->_pf_quote_active = true;
+ $this->_addoutput($word);
+ return;
+ }
+ if ($this->_pf_inmethod && is_array($word) && $word[0] == T_VARIABLE) {
+ $this->_pv_lastvar = $word;
+ }
+ if ($this->checkEventPush($word, $pevent)) {
+ $this->_pf_quote_active = false;
+ if (is_string($word) && ($word == '{' || $word == '"' || $word == "'")
+ ) {
+ $this->_pf_quote_active = true;
+ $this->_pv_lastvar = false;
+ }
+ }
+ $this->_addoutput($word);
+ }
+
+ /**
+ * Handles define() statements
+ *
+ * The only thing this handler cares about is retrieving the name of the
+ * define variable, and the end of the define statement, so after the name
+ * is found, it simply makes sure parentheses are matched as in this case:
+ *
+ * <code>
+ * define("test",array("hello",6 => 4, 5 => array('there')));
+ * </code>
+ *
+ * This handler and the DEFINE_PARAMS_PARENTHESIS handler (which is just
+ * {@link defaultHandler()} in this version, as nothing fancy is needed)
+ * work together to ensure proper parenthesis matching.
+ *
+ * If the define variable is documented, a link will be created to its
+ * documentation using the Converter passed.
+ */
+ function handleDefine($word, $pevent)
+ {
+ static $token_save;
+ if (!isset($token_save)) {
+ $token_save = array();
+ }
+ $e = $this->checkEventPush($word, $pevent);
+ if ($e && $e != PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS) {
+ return;
+ }
+
+ if (!isset($this->_pv_define_params_data)) {
+ $this->_pv_define_params_data = '';
+ }
+
+ if ($this->checkEventPop($word, $pevent)) {
+ unset($token_save);
+ $this->_addoutput($word);
+ }
+ if ($this->_pf_definename_isset) {
+ $this->_addoutput($word);
+ } else {
+ if ($word != ",") {
+ $token_save[] = $word;
+ if (is_array($word)) {
+ $word = $word[1];
+ }
+ $this->_pv_define_params_data .= $word;
+ } else {
+ if (substr($this->_pv_define_params_data, 0, 1) ==
+ substr($this->_pv_define_params_data,
+ strlen($this->_pv_define_params_data) - 1) &&
+ in_array(substr($this->_pv_define_params_data, 0, 1),
+ array('"', "'"))
+ ) {
+ // remove leading and ending quotation marks
+ // if there are only two
+ $a = substr($this->_pv_define_params_data, 0, 1);
+ $b = substr($this->_pv_define_params_data, 1,
+ strlen($this->_pv_define_params_data) - 2);
+ if (strpos($b, $a) === false) {
+ $this->_pv_define_params_data = $b;
+ }
+ }
+ $this->_pf_definename_isset = true;
+
+ $link = $this->_converter->getLink($this->_pv_define_params_data);
+ foreach ($token_save as $token) {
+ if (is_object($link)) {
+ if (is_array($token)) {
+ $token = $token[1];
+ }
+ $this->_addoutput($this->_converter->returnSee($link,
+ $token));
+ } else {
+ $this->_addoutput($save, $token);
+ }
+ }
+ $this->_pv_define_params_data = '';
+ }
+ }
+ }
+
+ /**
+ * Handles normal global code. Special consideration is taken for DocBlocks
+ * as they need to retrieve the whole DocBlock before doing any output, so
+ * the parser flag {@link $_pf_no_output_yet} is set to tell
+ * {@link _addoutput()} not to spit anything out yet.
+ *
+ * @uses _link() make any global code that is a documentable element link
+ * to the php manual or its documentation
+ */
+ function handlePhpCode($word, $pevent)
+ {
+ $test = $this->checkEventPush($word, $pevent);
+ if ($test == PARSER_EVENT_DOCBLOCK || $test == PARSER_EVENT_COMMENT) {
+ if (substr($word[1], 0, 2) == '/*' && strpos($word[1], '*/')) {
+ $this->_pv_last_word = $word;
+ if ($word[1] == '/**#@-*/') {
+ $this->_pf_docblock_template = true;
+ } else {
+ $this->_pf_docblock = true;
+ }
+ return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK);
+ }
+ $this->_pf_no_output_yet = true;
+ $this->_pv_saveline = $this->_wp->linenum + 1;
+ return;
+ }
+ if (is_array($word) && $word[0] == T_DOUBLE_COLON) {
+ $this->_pf_colon_colon = true;
+ }
+ if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {
+ $this->_pv_last_string = $word;
+ }
+ $this->_link($word);
+ $this->checkEventPop($word, $pevent);
+ }
+
+ /**
+ * Handle the function declaration header
+ *
+ * This handler only sees the "function name" portion of the function
+ * declaration. Handling of the function parameters is by
+ * {@link handleFunctionParams()}, and the function body is handled by
+ * {@link handleLogicBlock()}
+ */
+ function handleFunction($word, $pevent)
+ {
+ if ($this->checkEventPush($word, $pevent)) {
+ $this->_addoutput($word);
+ return;
+ }
+ if ($this->checkEventPop($word, $pevent)) {
+ return;
+ }
+ $this->_link($word);
+ }
+
+ /**
+ * Handle the method declaration header
+ *
+ * This handler only sees the "function name" portion of the method
+ * declaration. Handling of the method parameters is by
+ * {@link handleFunctionParams()}, and the method body is handled by
+ * {@link handleMethodLogicBlock()}
+ */
+ function handleMethod($word, $pevent)
+ {
+ if ($this->checkEventPush($word, $pevent)) {
+ $this->_addoutput($word);
+ return;
+ }
+ if ($this->checkEventPop($word, $pevent)) {
+ if ($word == ';') {
+ $this->_addoutput($word);
+ }
+ return;
+ }
+ $this->_methodlink($word);
+ }
+
+ /**
+ * Handler for the stuff between ( and ) in a function declaration
+ *
+ * <code>
+ * function handles($only,$these,$parameters){...}
+ * </code>
+ */
+ function handleFunctionParams($word, $pevent)
+ {
+ if ($this->checkEventPush($word, $pevent)) {
+ $this->_addoutput($word);
+ return;
+ }
+ $this->_addoutput($word);
+ $this->checkEventPop($word, $pevent);
+ }
+
+ /**
+ * Handler for function body.
+ *
+ * The function body is checked for php functions, documented constants,
+ * functions, and indirectly for global statements. It hyperlinks to the
+ * documentation for detected elements is created. Everything else is
+ * highlighted normally.
+ */
+ function handleLogicBlock($word, $pevent)
+ {
+ if ($this->checkEventPush($word, $pevent)) {
+ $this->_addoutput($word);
+ return;
+ }
+ if (is_array($word) && $word[0] == T_DOUBLE_COLON) {
+ $this->_pf_colon_colon = true;
+ }
+ if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {
+ $this->_pv_last_string = $word;
+ }
+ $this->_link($word);
+ if ($this->checkEventPop($word, $pevent)) {
+ $e = $this->_event_stack->popEvent();
+ $this->_event_stack->pushEvent($e);
+ if ($e == PARSER_EVENT_FUNCTION) {
+ $this->_wp->backupPos($word);
+ }
+ }
+ }
+
+ /**
+ * Handler for method body.
+ *
+ * Like functions, the method body is checked for php functions, documented
+ * constants, functions, and indirectly for global statements. It also
+ * checks for "$this->XXXX" where XXXX is a class variable or method, and
+ * links to the documentation for detected elements is created. Everything
+ * else is highlighted normally.
+ */
+ function handleMethodLogicBlock($word, $pevent)
+ {
+ if (isset($this->_pv_prev_var_type)) {
+ //debug('prevtype is set');
+ if (!is_array($word)) {
+ unset($this->_pv_prev_var_type);
+ } else {
+ if ($word[0] != T_WHITESPACE &&
+ $word[0] != T_STRING && $word[0] != T_OBJECT_OPERATOR
+ ) {
+ //fancy_debug('unset', $word);
+ unset($this->_pv_prev_var_type);
+ }
+ }
+ }
+ $this->_pf_inmethod = true;
+ if ($e = $this->checkEventPush($word, $pevent)) {
+ $this->_addoutput($word);
+ if ($e == PARSER_EVENT_CLASS_MEMBER) {
+ $this->_pf_no_output_yet = true;
+ }
+ return;
+ }
+ if (is_array($word) && $word[0] == T_DOUBLE_COLON) {
+ $this->_pf_colon_colon = true;
+ }
+ if (!$this->_pf_colon_colon && is_array($word) && $word[0] == T_STRING) {
+ $this->_pv_last_string = $word;
+ }
+ if (is_array($word) && $word[0] == T_VARIABLE) {
+ $this->_pv_lastvar = $word;
+ }
+ $this->_link($word);
+ if ($this->checkEventPop($word, $pevent)) {
+ $this->_pf_inmethod = false;
+ $e = $this->_event_stack->popEvent();
+ $this->_event_stack->pushEvent($e);
+ if ($e == PARSER_EVENT_METHOD) {
+ $this->_wp->backupPos($word);
+ }
+ }
+ }
+
+ /**
+ * Handles $obj->classmember in a method body
+ *
+ * This handler is responsible for linking to the documentation of a
+ * class member when it is used directly in a method body.
+ *
+ * There are two methods of determining whether to link:
+ * - $this->member
+ * - $this->member->submember
+ *
+ * The first case is handled by the $_pv_lastvar variable, and the
+ * second case is handled by the $_pv_prev_var_type variable. $_pv_lastvar
+ * is always set to the value of the last T_VARIABLE token, if and only if
+ * no text has occurred between the variable and a T_OBJECT_OPERATOR token
+ * "->". handleClassMember will only link if the last variable encountered
+ * was $this.
+ *
+ * When $this->variable is encountered, the variable is looked up to see
+ * if it can be found, and if so, the contents of its @var tag are processed
+ * to see if the member variable is defined to have 1 and only 1 class.
+ * If so, the $_pv_prev_var_type variable is set to this classname. When
+ * submember is processed, the HighlightParser checks to see if
+ * $_pv_prev_var_type::submember() or $_pv_prev_var_type::$submember exists,
+ * and if it does, it is linked to.
+ */
+ function handleClassMember($word, $pevent)
+ {
+ if (!isset($this->_pv_lastvar) && !isset($this->_pv_prev_var_type)) {
+ //fancy_debug('returned from', $word, $this->_pv_prev_var_type);
+ $this->_pf_no_output_yet = false;
+ $this->_event_stack->popEvent();
+ return $this->defaultHandler($word, $pevent);
+ }
+ if (isset($this->_pv_cm_name)) {
+ $this->_pf_obj_op = false;
+ $name = $this->_pv_cm_name;
+ unset($this->_pv_cm_name);
+ //debug('unset pvcmname');
+ $this->_event_stack->popEvent();
+ // control variable for _pv_prev_var_type
+ $setnow = false;
+ if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') ||
+ isset($this->_pv_prev_var_type)
+ ) {
+ if (is_array($word) && $word[0] == T_WHITESPACE) {
+ // preserve value of _pv_prev_var_type
+ $setnow = true;
+ $save = $this->_wp->nextToken();
+ $temp = $this->_wp->getWord();
+ $this->_wp->backupPos($save, true);
+ }
+ if ((is_string($word) && $word == '(') || (isset($temp) &&
+ is_string($temp) && $temp == '(')
+ ) {
+ // it's a function
+ $this->_pf_no_output_yet = false;
+ $this->_methodlink($name);
+ unset($this->_pv_prev_var_type);
+ } else {
+ // it's a variable
+ //fancy_debug('name is ', $name);
+ $this->_pf_no_output_yet = false;
+ $this->_varlink($name, true);
+ $templink =
+ $this->_converter->getLink('object ' . $this->_pv_class);
+ $class = false;
+ if (is_object($templink)) {
+ $class = $this->_converter->classes
+ ->getClass($templink->name, $templink->path);
+ }
+ if ($class) {
+ $varname = $name;
+ if (is_array($varname)) {
+ $varname = $name[1];
+ }
+ if ($varname{0} != '$') {
+ $varname = '$'.$varname;
+ }
+ $var = $class->getVar($this->_converter, $varname);
+
+ if (is_object($var) && $var->docblock->var) {
+ $type = $var->docblock->var->returnType;
+ }
+ if (isset($type)) {
+ if (strpos($type, 'object') === false) {
+ $type = 'object '.$type;
+ }
+ $type = $this->_converter->getLink($type);
+ if (phpDocumentor_get_class($type) == 'classlink') {
+ // the variable's type is a class,
+ // save it for future ->
+ //fancy_debug('set prev_var_type!', $type->name);
+ $setnow = true;
+ $this->_pv_prev_var_type = $type->name;
+ } else {
+ unset($this->_pv_prev_var_type);
+ }
+ } else {
+ unset($this->_pv_prev_var_type);
+ }
+ } else {
+ unset($this->_pv_prev_var_type);
+ }
+ }
+ } else {
+ $this->_pf_no_output_yet = false;
+ // this does NewLinenum if necessary
+ $this->_wp->backupPos($word);
+ $this->_wp->getWord();
+ $this->_addoutput($name);
+ }
+ if (!$setnow) {
+ //debug('unset prevtype, no setnow');
+ unset($this->_pv_prev_var_type);
+ }
+ unset($this->_pv_lastvar);
+ $this->_pf_no_output_yet = false;
+ // this does NewLinenum if necessary
+ $this->_wp->backupPos($word);
+ $this->_wp->getWord();
+ if ($word[0] == T_OBJECT_OPERATOR) {
+ $this->_wp->backupPos($word);
+ } else {
+ $this->_addoutput($word);
+ }
+ return;
+ }
+ if (!$this->_pf_obj_op && is_array($this->_pv_last_word) &&
+ $this->_pv_last_word[0] == T_OBJECT_OPERATOR
+ ) {
+ if ((isset($this->_pv_lastvar) && $this->_pv_lastvar[1] == '$this') ||
+ isset($this->_pv_prev_var_type)
+ ) {
+ $this->_pf_obj_op = true;
+ } else {
+ $this->_pf_no_output_yet = false;
+ // this does NewLinenum if necessary
+ $this->_wp->backupPos($word);
+ $this->_wp->getWord();
+ $this->_addoutput($word);
+ $this->_event_stack->popEvent();
+ }
+ }
+ if (is_array($word) && $word == T_WHITESPACE) {
+ $this->_pf_no_output_yet = false;
+ // this does NewLinenum if necessary
+ $this->_wp->backupPos($word);
+ $this->_wp->getWord();
+ $this->_addoutput($word);
+ return;
+ }
+ if ($this->_pf_obj_op) {
+ if (!(is_array($word) && ($word[0] == T_STRING ||
+ $word[0] == T_WHITESPACE))
+ ) {
+ unset($this->_pv_lastvar);
+ //debug('unset lastvar');
+ $this->_event_stack->popEvent();
+ $this->_pf_no_output_yet = false;
+ // this does NewLinenum if necessary
+ $this->_wp->backupPos($word);
+ $this->_wp->getWord();
+ $this->_addoutput($word);
+ return;
+ }
+ if ($word[0] == T_STRING) {
+ //fancy_debug('set pvcmname to', $word);
+ $this->_pv_cm_name = $word;
+ } else {
+ $this->_pf_no_output_yet = false;
+ // this does NewLinenum if necessary
+ $this->_wp->backupPos($word);
+ $this->_wp->getWord();
+ $this->_addoutput($word);
+ }
+ }
+ }
+
+ /**
+ * Handles comments
+ *
+ * Comments are almost always single-line tokens, and so will be
+ * in the last word. This handler checks to see if the current token
+ * is in fact a comment, and if it isn't, it backs up and returns control
+ * to the parent event handler with that word.
+ */
+ function handleComment($word, $pevent)
+ {
+ $w = $this->_pv_last_word;
+ // don't perform this check if this is a normal comment. Docblocks
+ // have the _pf_no_output_yet variable set to true
+ if ($this->_pf_no_output_yet && is_array($w) &&
+ (in_array($w[0], array(T_COMMENT, T_DOC_COMMENT)) &&
+ strpos($w[1], '/**') === 0)
+ ) {
+ $this->_event_stack->popEvent();
+ $this->_event_stack->pushEvent(PARSER_EVENT_DOCBLOCK);
+ return $this->handleDocBlock($word, PARSER_EVENT_DOCBLOCK);
+ }
+ if ($this->_pf_no_output_yet) {
+ $flag = 1;
+ $this->_pf_no_output_yet = false;
+ $this->_addoutput($this->_pv_last_word);
+ }
+ if (!is_array($word) ||
+ !in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) ||
+ (in_array($word[0], array(T_COMMENT, T_DOC_COMMENT)) &&
+ strpos($word[1], '/**') === 0)
+ ) {
+ $this->_event_stack->popEvent();
+ if (strpos($this->_pv_last_word[1], "\n") !== false) {
+ //$this->_wp->linenum++;
+ //$this->newLineNum();
+ }
+ $this->_wp->backupPos($this->_pv_last_word);
+ $this->_wp->getWord();
+ //var_dump($this->_wp->nextToken());
+ return;
+ } elseif (isset($flag)) {
+ $this->newLineNum();
+ }
+ $this->_addoutput($word);
+ $this->checkEventPop($word, $pevent);
+ if (strpos($word[1], '*/') === strlen($word[1]) - 2) {
+ $this->_event_stack->popEvent();
+ }
+ }
+
+ /**
+ * Handle class declarations
+ *
+ * Handles the initial declaration line:
+ *
+ * <code>class X</code>
+ *
+ * or
+ *
+ * <code>class X extends Y implements I</code>
+ *
+ * @uses _classlink() to link to documentation for X and for Y class in
+ * "class X extends Y"
+ */
+ function handleClass($word, $pevent)
+ {
+ $this->_pf_in_class = true;
+ $a = $this->checkEventPush($word, $pevent);
+
+ if (!isset($this->_pv_class) && is_array($word) && $word[0] == T_STRING) {
+ $this->_pv_class = $this->_converter->class = $word[1];
+ $this->_classlink($word);
+ return;
+ }
+
+ if (is_array($word) &&
+ in_array($word[0], array(T_PRIVATE, T_PROTECTED, T_PUBLIC))
+ ) {
+ $starttok = $this->_wp->nextToken();
+ $test = array(T_WHITESPACE);
+ while ($test && $test[0] == T_WHITESPACE) {
+ $tok = $this->_wp->nextToken();
+ $test = $this->_wp->getWord();
+ } // while
+
+ if (is_array($test) && $test[0] == T_VARIABLE) {
+ $this->_wp->backupPos($tok, true);
+ return;
+ }
+ $this->_wp->backupPos($starttok, true);
+ }
+
+ if (@in_array($this->_pv_last_word[0],
+ array(T_PRIVATE, T_PROTECTED, T_PUBLIC))
+ ) {
+ if (is_array($word) && $word[0] == T_VARIABLE) {
+ $this->_wp->backupPos($this->_pv_last_word);
+ $this->_event_stack->pushEvent(PARSER_EVENT_VAR);
+ return;
+ }
+ }
+
+ if ($this->_pf_extends_found && is_array($word) && $word[0] == T_STRING) {
+ $this->_classlink($word);
+ return;
+ }
+ if (is_array($word) && $word[0] == T_EXTENDS) {
+ $this->_pf_extends_found = true;
+ }
+ if ($a == PARSER_EVENT_DOCBLOCK) {
+ $this->_pf_no_output_yet = true;
+ $this->_pv_saveline = $this->_wp->linenum + 1;
+ return;
+ }
+ $this->_addoutput($word);
+ if ($this->checkEventPop($word, $pevent)) {
+ $this->_pf_in_class = false;
+ unset($this->_pv_class);
+ }
+ }
+
+ /**
+ * Handles class variable declaration
+ *
+ * <code>
+ * class X
+ * {
+ * var $Y;
+ * }
+ * </code>
+ *
+ * @uses _varlink() make a link to $Y documentation in class variable
+ * declaration "var $Y;"
+ */
+ function handleVar($word, $pevent)
+ {
+ if ($this->checkEventPush($word, $pevent)) {
+ $this->_addoutput($word);
+ return;
+ }
+ if (is_array($word) && $word[0] == T_VARIABLE) {
+ return $this->_varlink($word);
+ }
+ $this->_addoutput($word);
+ $this->checkEventPop($word, $pevent);
+ }
+
+ /**
+ * This handler is responsible for highlighting DocBlocks
+ *
+ * handleDocBlock determines whether the docblock is normal or a template,
+ * and gathers all the lines of the docblock together before doing any
+ * processing
+ *
+ * As it is not possible to distinguish any comment token from a docblock
+ * token, this handler is also called for comments, and will pass control
+ * to {@link handleComment()} if the comment is not a DocBlock
+ *
+ * @uses commonDocBlock() once all lines of the DocBlock have been retrieved
+ */
+ function handleDocBlock($word, $pevent)
+ {
+ if (!($this->_pf_docblock || $this->_pf_docblock_template)) {
+ if (strpos($this->_pv_last_word[1], '/**') !== 0) {
+ // not a docblock
+ $this->_wp->backupPos($this->_pv_last_word);
+ $this->_event_stack->popEvent();
+ $this->_event_stack->pushEvent(PARSER_EVENT_COMMENT);
+ $this->_pf_no_output_yet = false;
+ return;
+ } else {
+ $this->_pf_no_output_yet = true;
+ $this->_pv_db_lines = array();
+ }
+ }
+ $last_word = $this->_pv_last_word[1];
+ $dtype = '_pv_docblock';
+ if ($last_word == '/**#@-*/') {
+ // stop using docblock template
+ $this->_pf_no_output_yet = false;
+ $this->_addDocBlockoutput('closetemplate', $last_word);
+ if ($this->_pv_next_word !== false) {
+ $this->_wp->backupPos($this->_pv_next_word, true);
+ }
+ $this->_event_stack->popEvent();
+ return;
+ }
+ if (!($this->_pf_docblock || $this->_pf_docblock_template)) {
+ $this->_pv_db_lines = array();
+ if (strpos($last_word, '/**#@+') === 0) {
+ // docblock template definition
+ $this->_pf_docblock_template = true;
+ } else {
+ $this->_pf_docblock = true;
+ }
+ $this->_pv_db_lines[] = $last_word;
+ if (strpos($last_word, '*/') !== false) {
+ $this->commonDocBlock();
+ return;
+ }
+ $this->_pv_db_lines[] = $word[1];
+ if (strpos($word[1], '*/') !== false) {
+ $this->commonDocBlock();
+ }
+ } else {
+ $this->_pv_db_lines[] = $word[1];
+ }
+ if (($this->_pf_docblock || $this->_pf_docblock_template) &&
+ (strpos($word[1], '*/') !== false)
+ ) {
+ $this->commonDocBlock();
+ }
+ }
+ /**#@-*/
+
+ /**
+ * This continuation of handleDocBlock splits DocBlock comments up into
+ * phpDocumentor tokens. It highlights DocBlock templates in a different
+ * manner from regular DocBlocks, recognizes inline tags, regular tags,
+ * and distinguishes between standard core tags and other tags, and
+ * recognizes parameters to tags like @var.
+ *
+ * the type in "@var type description" will be highlighted as a php type,
+ * and the var in "@param type $var description" will be highlighted as a
+ * php variable.
+ *
+ * @return void
+ * @uses handleDesc() highlight inline tags in the description
+ * @uses handleTags() highlight all tags
+ * @access private
+ */
+ function commonDocBlock()
+ {
+ $this->_event_stack->popEvent();
+ $lines = $this->_pv_db_lines;
+ $go = count($this->_pv_db_lines);
+ for ($i=0; $i < $go; $i++) {
+ if (substr(trim($lines[$i]), 0, 2) == '*/' ||
+ substr(trim($lines[$i]), 0, 1) != '*' &&
+ substr(trim($lines[$i]), 0, 3) != '/**'
+ ) {
+ $lines[$i] = array($lines[$i], false);
+ } elseif (substr(trim($lines[$i]), 0, 3) == '/**') {
+ $linesi = array();
+ // remove leading "/**"
+ $linesi[1] = substr(trim($lines[$i]), 3);
+ if (empty($linesi[1])) {
+ $linesi[0] = $lines[$i];
+ } else {
+ $linesi[0] =
+ substr($lines[$i], 0, strpos($lines[$i], $linesi[1]));
+ }
+ $lines[$i] = $linesi;
+ } else {
+ $linesi = array();
+ // remove leading "* "
+ $linesi[1] = substr(trim($lines[$i]), 1);
+ if (empty($linesi[1])) {
+ $linesi[0] = $lines[$i];
+ } else {
+ $linesi[0] =
+ substr($lines[$i], 0, strpos($lines[$i], $linesi[1]));
+ }
+ $lines[$i] = $linesi;
+ }
+ }
+ for ($i = 0; $i < count($lines); $i++) {
+ if ($lines[$i][1] === false) {
+ continue;
+ }
+ if (substr(trim($lines[$i][1]), 0, 1) == '@' &&
+ substr(trim($lines[$i][1]), 0, 2) != '@ '
+ ) {
+ $tagindex = $i;
+ $i = count($lines);
+ }
+ }
+ if (isset($tagindex)) {
+ $tags = array_slice($lines, $tagindex);
+ $desc = array_slice($lines, 0, $tagindex);
+ } else {
+ $tags = array();
+ $desc = $lines;
+ }
+ //var_dump($desc, $tags);
+ $this->_pf_no_output_yet = false;
+ $save = $this->_wp->linenum;
+ $this->_wp->linenum = $this->_pv_saveline;
+ $this->handleDesc($desc);
+ $this->handleTags($tags);
+ $this->_pv_db_lines = array();
+ $this->_wp->linenum = $save;
+ if (strpos($this->_pv_last_word[1], '*/') !== false) {
+ $this->_wp->backupPos($this->_pv_next_word, true);
+ }
+ $this->_pf_docblock = $this->_pf_docblock_template = false;
+ }
+
+ /**
+ * Handle the description area of a DocBlock
+ *
+ * This method simply finds inline tags and highlights them
+ * separately from the rest of the description.
+ *
+ * @param mixed $desc the description piece(s)
+ *
+ * @return void
+ * @uses getInlineTags()
+ * @access private
+ */
+ function handleDesc($desc)
+ {
+ $dbtype = 'docblock';
+ $dbtype .= ($this->_pf_docblock ? '' : 'template');
+ foreach ($desc as $line) {
+ $this->getInlineTags($line[0] . $line[1]);
+ if (strpos($line[0], '*/') === false &&
+ !(substr($line[0], 0, 2) == '/*' &&
+ strpos($line[1], '*/') !== false)
+ ) {
+ $this->newLineNum();
+ $this->_wp->linenum++;
+ }
+ }
+ if ($this->_pf_internal) {
+ $this->_pf_internal = false;
+ }
+ }
+
+ /**
+ * Handle phpDocumentor tags in a DocBlock
+ *
+ * This method uses the {@link $tagHandlers} array to determine which
+ * method will handle tags found in the docblock, and passes the data to
+ * the individual handlers one by one
+ *
+ * @param array $tags array of tags to handle
+ *
+ * @return void
+ * @access private
+ */
+ function handleTags($tags)
+ {
+ $newtags = array();
+ $curtag = array();
+ for ($i=0; $i < count($tags); $i++) {
+ $tagsi = trim($tags[$i][1]);
+ if (substr($tagsi, 0, 1) == '@' && substr($tagsi, 0, 2) != '@ ') {
+ // start a new tag
+ $tags[$i][1] = array(substr($tags[$i][1], 0,
+ strpos($tags[$i][1], $tagsi)), $tagsi);
+ if (!empty($curtag)) {
+ $newtags[] = $curtag;
+ $curtag = array();
+ }
+ $curtag[] = $tags[$i];
+ } else {
+ $curtag[] = $tags[$i];
+ }
+ }
+ if (!empty($curtag)) {
+ $newtags[] = $curtag;
+ }
+ foreach ($newtags as $tag) {
+ foreach ($tag as $i => $t) {
+ if ($t[1] === false) {
+ continue;
+ }
+ if (is_array($t[1])) {
+ $tag[$i][1][1]
+ = explode(" ", str_replace("\t", ' ', $t[1][1]));
+ $x = $tag[$i][1][1];
+ }
+ }
+ $tagname = substr(array_shift($x), 1);
+ $restoftag = $tag;
+ if (isset($this->tagHandlers[$tagname])) {
+ $handle = $this->tagHandlers[$tagname];
+ } else {
+ $handle = $this->tagHandlers['*'];
+ }
+ $this->$handle($tagname, $restoftag);
+ }
+ }
+
+ /**
+ * This handler recognizes all {@}inline} tags
+ *
+ * Normal inline tags are simply highlighted. the {@}internal}} inline
+ * tag {@tutorial tags.inlineinternal.pkg} is highlighted differently
+ * to distinguish it from other inline tags.
+ *
+ * @param mixed $value the tag value
+ * @param bool $endinternal indicates the end of an @internal tag
+ *
+ * @return void
+ * @access private
+ */
+ function getInlineTags($value, $endinternal = false)
+ {
+ if (!$value) {
+ return;
+ }
+ if ($this->_pf_internal && !$endinternal) {
+ if (strpos($value, '}}') !== false) {
+ $x = strrpos($value, '}}');
+ // add the rest of internal
+ $this->getInlineTags(substr($value, 0, $x + 3), true);
+ // strip internal from value
+ $value = substr($value, strrpos($value, '}}') + 1);
+ // turn off internal
+ $this->_pf_internal = false;
+ }
+ }
+ if (!$value) {
+ return;
+ }
+ $dbtype = 'docblock';
+ $dbtype .= ($this->_pf_docblock ? '' : 'template');
+ $save = $value;
+ $value = explode('{@', $value);
+ $newval = array();
+ // everything before the first {@ is normal text
+ $this->_addDocBlockoutput($dbtype, $value[0]);
+ for ($i=1; $i < count($value); $i++) {
+ if (substr($value[$i], 0, 1) == '}') {
+ $this->_addDocBlockoutput($dbtype, '{@}' . substr($value[$i], 1));
+ } else {
+ $save = $value[$i];
+ $value[$i] = str_replace("\t", " ", $value[$i]);
+ $value[$i] = explode(" ", $value[$i]);
+ $word = array_shift($value[$i]);
+ $val = join(' ', $value[$i]);
+ if ($word == 'internal') {
+ $this->_pf_internal = true;
+ $this->_addDocBlockoutput($dbtype, '{@internal ');
+ $value[$i] = substr($save, strlen('internal') + 1);
+ // strip internal and cycle as if it were normal text.
+ $this->_addDocBlockoutput($dbtype, $value[$i]);
+ continue;
+ }
+ if (in_array(str_replace('}', '', $word), $this->allowableInlineTags)
+ ) {
+ if (strpos($word, '}')) {
+ $word = str_replace('}', '', $word);
+ $val = '} ' . $val;
+ }
+ $val = explode('}', $val);
+ if (count($val) == 1) {
+ //addError(PDERROR_UNTERMINATED_INLINE_TAG,
+ // $word, '', $save);
+ }
+ $rest = $val;
+ $val = array_shift($rest);
+ if ($endinternal) {
+ $rest = join('}', $rest);
+ } else {
+ $rest = join(' ', $rest);
+ }
+ if (isset($this->inlineTagHandlers[$word])) {
+ $handle = $this->inlineTagHandlers[$word];
+ } else {
+ $handle = $this->inlineTagHandlers['*'];
+ }
+ $this->$handle($word, $val);
+ $this->_addDocBlockoutput($dbtype, $rest);
+ } else {
+ $val = $word . ' ' . $val;
+ $this->_addDocBlockoutput($dbtype, '{@' . $val);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Handles all inline tags
+ *
+ * @param string $name the tag name
+ * @param mixed $value the tag value
+ *
+ * @return void
+ * @access private
+ */
+ function handleDefaultInlineTag($name, $value)
+ {
+ $this->_addDocBlockoutput('inlinetag', '{@' . $name . ' ' . $value . '}');
+ }
+
+ /**#@+
+ * phpDocumentor DocBlock tag handlers
+ *
+ * @param string $name tag name
+ * @param array $value array of lines contained in the tag description
+ *
+ * @return void
+ * @access private
+ */
+ /**
+ * Handle normal tags
+ *
+ * This handler adds to outpu all comment information before the tag begins
+ * as in " * " before "@todo" in " * @todo"
+ *
+ * Then, it highlights the tag as a regular or coretag based on $coretag.
+ * Finally, it uses getInlineTags to highlight the description
+ *
+ * @param bool $coretag whether this tag is a core tag or not
+ *
+ * @uses getInlineTags() highlight a tag description
+ */
+ function defaultTagHandler($name, $value, $coretag = false)
+ {
+ $dbtype = 'docblock';
+ $dbtype .= ($this->_pf_docblock ? '' : 'template');
+ foreach ($value as $line) {
+ $this->_addDocBlockoutput($dbtype, $line[0]);
+ if ($line[1] === false) {
+ if (trim($line[0]) != '*/') {
+ $this->newLineNum();
+ $this->_wp->linenum++;
+ }
+ continue;
+ }
+ $this->_addDocBlockoutput($dbtype, $line[1][0]);
+ $stored = '';
+ if (is_array($line[1][1])) {
+ foreach ($line[1][1] as $i => $tpart) {
+ if ($tpart == '@' . $name && $i == 0) {
+ $tagname = 'tag';
+ if ($coretag) {
+ $tagname = 'coretag';
+ }
+ $this->_addDocBlockoutput($tagname, '@' . $name);
+ continue;
+ }
+ $stored .= ' ' . $tpart;
+ }
+ } else {
+ $stored = $line[1];
+ }
+ $this->getInlineTags($stored);
+ if (strpos($stored, '*/') === false) {
+ $this->newLineNum();
+ $this->_wp->linenum++;
+ }
+ }
+ }
+
+ /**
+ * main handler for "core" tags
+ *
+ * @see defaultTagHandler()
+ */
+ function coreTagHandler($name, $value)
+ {
+ return $this->defaultTagHandler($name, $value, true);
+ }
+
+ /**
+ * Handles @global
+ *
+ * This handler works like {@link defaultTagHandler()} except it highlights
+ * the type and variable (if present) in "@global type $variable" or
+ * "@global type description"
+ */
+ function globalTagHandler($name, $value)
+ {
+ $this->paramTagHandler($name, $value);
+ }
+
+ /**
+ * Handles @param
+ *
+ * This handler works like {@link defaultTagHandler()} except it highlights
+ * the type and variable (if present) in "@param type $variable description"
+ * or "@param type description"
+ *
+ * @param bool $checkforvar private parameter, checks for $var or not
+ */
+ function paramTagHandler($name, $value, $checkforvar = true)
+ {
+ $dbtype = 'docblock';
+ $dbtype .= ($this->_pf_docblock ? '' : 'template');
+ $ret = $this->retrieveType($value, 0, $checkforvar);
+ foreach ($value as $num => $line) {
+ $this->_addDocBlockoutput($dbtype, $line[0]);
+ if ($line[1] === false) {
+ if (trim($line[0]) != '*/') {
+ $this->newLineNum();
+ $this->_wp->linenum++;
+ }
+ continue;
+ }
+ $this->_addDocBlockoutput($dbtype, $line[1][0]);
+ $stored = '';
+ $typeloc = 1;
+ $varloc = 2;
+ if (is_array($line[1][1])) {
+ $this->_addDocBlockoutput('coretag', '@' . $name . ' ');
+ foreach ($ret[0] as $text) {
+ if (is_string($text)) {
+ $this->_addDocBlockoutput($dbtype, $text);
+ }
+ if (is_array($text)) {
+ if ($text[0] != 'desc') {
+ $this->_addDocBlockoutput($text[0], $text[1]);
+ } else {
+ $stored .= $text[1];
+ }
+ }
+ }
+ } else {
+ if (isset($ret[$num])) {
+ foreach ($ret[$num] as $text) {
+ if (is_string($text)) {
+ $this->_addDocBlockoutput($dbtype, $text);
+ }
+ if (is_array($text)) {
+ if ($text[0] != 'desc') {
+ $this->_addDocBlockoutput($text[0], $text[1]);
+ } else {
+ $stored .= $text[1];
+ }
+ }
+ }
+ } else {
+ $stored = $line[1];
+ }
+ }
+ $this->getInlineTags($stored);
+ if (strpos($stored, '*/') === false) {
+ $this->newLineNum();
+ $this->_wp->linenum++;
+ }
+ }
+ }
+
+ /**
+ * handles the @staticvar tag
+ *
+ * @see paramTagHandler()
+ */
+ function staticvarTagHandler($name, $value)
+ {
+ return $this->paramTagHandler($name, $value);
+ }
+
+ /**
+ * handles the @var tag
+ *
+ * @see paramTagHandler()
+ */
+ function varTagHandler($name, $value)
+ {
+ return $this->paramTagHandler($name, $value);
+ }
+
+ /**
+ * Handles @return
+ *
+ * This handler works like {@link defaultTagHandler()} except it highlights
+ * the type in "@return type description"
+ */
+ function returnTagHandler($name, $value)
+ {
+ $this->paramTagHandler($name, $value, false);
+ }
+
+ /**
+ * Handles @property(-read or -write) and @method magic tags
+ */
+ function propertyTagHandler($name, $value)
+ {
+ return $this->paramTagHandler($name, $value, true);
+ }
+
+ /**#@-*/
+
+ /**
+ * Retrieve the type portion of a @tag type description
+ *
+ * Tags like @param, @return and @var all have a PHP type portion in their
+ * description. Since the type may contain the expression "object blah"
+ * where blah is a classname, it makes parsing out the type field complex.
+ *
+ * Even more complicated is the case where a tag variable can contain
+ * multiple types, such as object blah|object blah2|false, and so this
+ * method handles these cases.
+ *
+ * @param array $value array of words that were separated by spaces
+ * @param 0|1 $state 0 = find the type, 1 = find the var, if present
+ * @param bool $checkforvar flag to determine whether to check for the end of a
+ * type is defined by a $varname
+ *
+ * @return array Format: array(state (0 [find type], 1 [var], 2 [done]),
+ * @access private
+ */
+ function retrieveType($value, $state = 0, $checkforvar = false)
+ {
+ $index = 0;
+ $result = array();
+ do {
+ if (!isset($value[$index][1])) {
+ return $result;
+ }
+ $val = $value[$index][1];
+ if (empty($val)) {
+ return $result;
+ }
+ if ($index == 0) {
+ $val = $val[1];
+ array_shift($val);
+ } else {
+ $val = explode(' ', $val);
+ }
+ $ret = $this->_retrieveType($val, $state, $checkforvar);
+ $state = $ret[0];
+ $result[$index++] = $ret[1];
+ } while ((!$checkforvar && $state < 1) || ($state < 2 && $checkforvar));
+ return $result;
+ }
+
+ /**
+ * used by {@link retrieveType()} in its work
+ *
+ * @param array $value array of words that were separated by spaces
+ * @param 0|1 $state 0 = find the type, 1 = find the var, if present
+ * @param bool $checkforvar flag to determine whether to check for the end of a
+ * type is defined by a $varname
+ *
+ * @return array
+ * @access private
+ */
+ function _retrieveType($value, $state, $checkforvar)
+ {
+ $result = array();
+ $result[] = $this->_removeWhiteSpace($value, 0);
+ if ($state == 0) {
+ if (!count($value)) {
+ return array(2, $result);
+ }
+ $types = '';
+ $index = 0;
+ if (trim($value[0]) == 'object') {
+ $result[] = array('tagphptype', $value[0] . ' ');
+ $types .= array_shift($value).' ';
+ $result[] = $this->_removeWhiteSpace($value, 0);
+ if (!count($value)) {
+ // was just passed "object"
+ return array(2, $result);
+ }
+ if ($value[0]{0} == '$' || substr($value[0], 0, 2) == '&$') {
+ // was just passed "object"
+ // and the next thing is a variable name
+ if ($checkforvar) {
+ $result[] = array('tagvarname' , $value[0] . ' ');
+ array_shift($value);
+ }
+ $result[] = array('desc', join(' ', $value));
+ return array(2, $result);
+ }
+ }
+ $done = false;
+ $loop = -1;
+ do {
+ // this loop checks for type|type|type and for
+ // type|object classname|type|object classname2
+ if (strpos($value[0], '|')) {
+ $temptypes = explode('|', $value[0]);
+ while (count($temptypes)) {
+ $type = array_shift($temptypes);
+ $result[] = array('tagphptype', $type);
+ if (count($temptypes)) {
+ $result[] = '|';
+ }
+ }
+ if (trim($type) == 'object') {
+ $result[] = array('tagphptype', $types . ' ');
+ $result[] = $this->_removeWhiteSpace($value, 0);
+ } else {
+ $done = true;
+ }
+ array_shift($value);
+ if (count($value) && strlen($value[0]) && isset ($value[0]) &&
+ ($value[0]{0} == '$' || substr($value[0], 0, 2) == '&$')
+ ) {
+ // was just passed "object"
+ // and the next thing is a variable name
+ $result[] = array('tagvarname' , $value[0] . ' ');
+ array_shift($value);
+ $result[] = array('desc', join(' ', $value));
+ return array(2, $result);
+ }
+ } else {
+ $result[] = array('tagphptype', $value[0] . ' ');
+ array_shift($value);
+ $done = true;
+ }
+ $loop++;
+ } while (!$done && count($value));
+ if ($loop) {
+ $result[] = ' ';
+ }
+ // still searching for type
+ if (!$done && !count($value)) {
+ return array(0, $result);
+ }
+ // still searching for var
+ if ($done && !count($value)) {
+ return array(1, $result);
+ }
+ }
+ $result[] = $this->_removeWhiteSpace($value, 0);
+ $state = 1;
+ if ($checkforvar) {
+ if (count($value)) {
+ $state = 2;
+ if (substr($value[0], 0, 1) == '$' ||
+ substr($value[0], 0, 2) == '&$'
+ ) {
+ $result[] = array('tagvarname' , $value[0] . ' ');
+ array_shift($value);
+ }
+ } else {
+ $state = 1;
+ }
+ }
+ $result[] = array('desc', join(' ', $value));
+ return array($state, $result);
+ }
+
+ /**
+ * captures trailing whitespace
+ *
+ * @param array &$value array of string
+ * @param int $index index to seek non-whitespace to
+ *
+ * @return string whitespace
+ * @access private
+ */
+ function _removeWhiteSpace(&$value, $index)
+ {
+ $result = '';
+ if (count($value) > $index && empty($value[$index])) {
+ $found = false;
+ for ($i = $index; $i < count($value) && !strlen($value[$i]); $i++) {
+ $result .= ' ';
+ }
+ array_splice($value, $index, $i - $index);
+ }
+ return $result;
+ }
+
+ /**#@+
+ * Link generation methods
+ *
+ * @param string|array $word token to try to link
+ *
+ * @access private
+ */
+ /**
+ * Generate a link to documentation for an element
+ *
+ * This method tries to link to documentation for functions, methods,
+ * PHP functions, class names, and if found, adds the links to output
+ * instead of plain text
+ */
+ function _link($word)
+ {
+ if (is_array($word) && $word[0] == T_STRING) {
+ if ($this->_pf_colon_colon) {
+ $this->_pf_colon_colon = false;
+
+ $combo = $this->_pv_last_string[1] . '::' . $word[1] . '()';
+ //debug('testing ' . $combo);
+ $link = $this->_converter->getLink($combo);
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ }
+ $this->_addoutput($word);
+ return;
+ }
+ $link = $this->_converter->getLink($word[1] . '()');
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ } elseif (is_string($link) && strpos($link, 'ttp://')) {
+ $this->_addoutput($this->_converter->returnLink($link,
+ $word[1]), true);
+ return;
+ } else {
+ $link = $this->_converter->getLink($word[1]);
+ if (is_object($link)) {
+ $word[1] = $this->_converter->returnSee($link, $word[1]);
+ }
+ $this->_addoutput($word, true);
+ return;
+ }
+ }
+ $this->_addoutput($word);
+ }
+
+ /**
+ * Works like {@link _link()} except it only links to global variables
+ */
+ function _globallink($word)
+ {
+ if (!is_array($word)) {
+ return $this->_addoutput($word);
+ }
+ if ($word[0] != T_VARIABLE) {
+ return $this->_addoutput($word);
+ }
+ if (is_array($word) && $word[0] == T_VARIABLE) {
+ $link = $this->_converter->getLink('global ' . $word[1]);
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ }
+ }
+ $this->_addoutput($word);
+ }
+
+ /**
+ * Works like {@link _link()} except it only links to classes
+ */
+ function _classlink($word)
+ {
+ //debug("checking class " . $word[1]);
+ if (is_array($word) && $word[0] == T_STRING) {
+ $link = $this->_converter->getLink($word[1]);
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ }
+ }
+ $this->_addoutput($word);
+ }
+
+ /**
+ * Works like {@link _link()} except it only links to methods
+ */
+ function _methodlink($word)
+ {
+ if (is_array($word) && $word[0] == T_STRING) {
+ //debug("checking method " . $this->_pv_class . '::' . $word[1] . '()');
+ if (isset($this->_pv_prev_var_type)) {
+ $link = $this->_converter->getLink($this->_pv_prev_var_type . '::' .
+ $word[1] . '()');
+ } else {
+ $link = $this->_converter->getLink($this->_pv_class . '::' .
+ $word[1] . '()');
+ }
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ }
+ if (isset($this->_pv_prev_var_type)) {
+ $this->_addoutput($word);
+ return;
+ }
+ //debug("checking method " . $word[1] . '()');
+ $link = $this->_converter->getLink($word[1] . '()');
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ }
+ }
+ $this->_addoutput($word);
+ }
+
+ /**
+ * Works like {@link _link()} except it only links to class variables
+ *
+ * @param bool $justastring true if the $word is only a string
+ */
+ function _varlink($word, $justastring=false)
+ {
+ if ($justastring) {
+ $word[0] = T_VARIABLE;
+ }
+ if (is_array($word) && $word[0] == T_VARIABLE) {
+ $x = ($justastring ? '$' : '');
+ //debug("checking var " . $this->_pv_class . '::' . $x . $word[1]);
+ if (isset($this->_pv_prev_var_type)) {
+ //debug("checking var " . $this->_pv_prev_var_type . '::' .
+ // $x . $word[1]);
+ $link = $this->_converter->getLink($this->_pv_prev_var_type . '::' .
+ $x . $word[1]);
+ } else {
+ $link = $this->_converter->getLink($this->_pv_class . '::' .
+ $x . $word[1]);
+ }
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ }
+ //debug("checking var " . $x . $word[1]);
+ if (isset($this->_pv_prev_var_type)) {
+ $this->_addoutput($word);
+ return;
+ }
+ $link = $this->_converter->getLink($x . $word[1]);
+ if (is_object($link)) {
+ $this->_addoutput($this->_converter->returnSee($link,
+ $word[1]), true);
+ return;
+ }
+ }
+ $this->_addoutput($word);
+ }
+ /**#@-*/
+
+ /**#@+
+ * Output Methods
+ * @access private
+ */
+ /**
+ * This method adds output to {@link $_line}
+ *
+ * If a string with variables like "$test this" is present, then special
+ * handling is used to allow processing of the variable in context.
+ *
+ * @param mixed $word the string|array tag token and value
+ * @param bool $preformatted whether or not the $word is already formatted
+ *
+ * @return void
+ * @see _flush_save()
+ */
+ function _addoutput($word, $preformatted = false)
+ {
+ if ($this->_pf_no_output_yet) {
+ return;
+ }
+ if ($this->_pf_quote_active) {
+ if (is_array($word)) {
+ $this->_save .= $this->_converter->highlightSource($word[0],
+ $word[1]);
+ } else {
+ $this->_save .= $this->_converter->highlightSource(false,
+ $word, true);
+ }
+ } else {
+ $this->_flush_save();
+ if (is_string($word) && trim($word) == '') {
+ $this->_line .= $this->_converter->postProcess($word);
+ return;
+ }
+ if (is_array($word) && trim($word[1]) == '') {
+ $this->_line .= $this->_converter->postProcess($word[1]);
+ return;
+ }
+ if (is_array($word)) {
+ $this->_line .= $this->_converter->highlightSource($word[0],
+ $word[1], $preformatted);
+ } else {
+ $this->_line .= $this->_converter->highlightSource(false,
+ $word, $preformatted);
+ }
+ }
+ }
+
+ /**
+ * Like {@link _output()}, but for DocBlock highlighting
+ *
+ * @param mixed $dbtype the docblock type
+ * @param mixed $word the string|array tag token and value
+ * @param bool $preformatted whether or not the $word is already formatted
+ *
+ * @return void
+ */
+ function _addDocBlockoutput($dbtype, $word, $preformatted = false)
+ {
+ if ($this->_pf_internal) {
+ $this->_line .= $this->_converter->highlightDocBlockSource('internal',
+ $word, $preformatted);
+ } else {
+ $this->_line .= $this->_converter->highlightDocBlockSource($dbtype,
+ $word, $preformatted);
+ }
+ }
+
+ /**
+ * Flush a saved string variable highlighting
+ *
+ * {@source}
+ *
+ * @return void
+ * @todo CS cleanup - rename to _flushSave() for camelCase rule
+ */
+ function _flush_save()
+ {
+ if (!empty($this->_save)) {
+ $this->_save .= $this->_converter->flushHighlightCache();
+ // clear the existing cache, reset it to the old value
+ if (isset($this->_save_highlight_state)) {
+ $this->_converter->
+ _setHighlightCache($this->_save_highlight_state[0],
+ $this->_save_highlight_state[1]);
+ }
+ $this->_line .= $this->_converter->
+ highlightSource(T_CONSTANT_ENCAPSED_STRING, $this->_save, true);
+ $this->_save = '';
+ }
+ }
+ /**#@-*/
+
+ /**
+ * Give the word parser necessary data to begin a new parse
+ *
+ * @param array &$data all tokens separated by line number
+ *
+ * @return void
+ */
+ function configWordParser(&$data)
+ {
+ $this->_wp->setup($data, $this);
+ $this->_wp->setWhitespace(true);
+ }
+
+ /**
+ * Initialize all parser state variables
+ *
+ * @param bool $inlinesourceparse true if we are highlighting an inline
+ * {@}source} tag's output
+ * @param false|string $class name of class we are going
+ * to start from
+ *
+ * @return void
+ * @uses $_wp sets to a new {@link phpDocumentor_HighlightWordParser}
+ */
+ function setupStates($inlinesourceparse, $class)
+ {
+ $this->_output = '';
+ $this->_line = '';
+ unset($this->_wp);
+ $this->_wp = new phpDocumentor_HighlightWordParser;
+ $this->_event_stack = new EventStack;
+ if ($inlinesourceparse) {
+ $this->_event_stack->pushEvent(PARSER_EVENT_PHPCODE);
+ if ($class) {
+ $this->_event_stack->pushEvent(PARSER_EVENT_CLASS);
+ $this->_pv_class = $class;
+ }
+ } else {
+ $this->_pv_class = null;
+ }
+
+ $this->_pv_define = null;
+ $this->_pv_define_name = null;
+ $this->_pv_define_value = null;
+ $this->_pv_define_params_data = null;
+ $this->_pv_dtype = null;
+ $this->_pv_docblock = null;
+ $this->_pv_dtemplate = null;
+ $this->_pv_func = null;
+ $this->_pv_global_name = null;
+ $this->_pv_global_val = null;
+ $this->_pv_globals = null;
+ $this->_pv_global_count = null;
+ $this->_pv_include_params_data = null;
+ $this->_pv_include_name = null;
+ $this->_pv_include_value = null;
+ $this->_pv_linenum = null;
+ $this->_pv_periodline = null;
+ $this->_pv_paren_count = 0;
+ $this->_pv_statics = null;
+ $this->_pv_static_count = null;
+ $this->_pv_static_val = null;
+ $this->_pv_quote_data = null;
+ $this->_pv_function_data = null;
+ $this->_pv_var = null;
+ $this->_pv_varname = null;
+ $this->_pf_definename_isset = false;
+ $this->_pf_extends_found = false;
+ $this->_pf_includename_isset = false;
+ $this->_pf_get_source = false;
+ $this->_pf_getting_source = false;
+ $this->_pf_in_class = false;
+ $this->_pf_in_define = false;
+ $this->_pf_in_global = false;
+ $this->_pf_in_include = false;
+ $this->_pf_in_var = false;
+ $this->_pf_funcparam_val = false;
+ $this->_pf_quote_active = false;
+ $this->_pf_reset_quote_data = true;
+ $this->_pf_useperiod = false;
+ $this->_pf_var_equals = false;
+ $this->_pf_obj_op = false;
+ $this->_pf_docblock = false;
+ $this->_pf_docblock_template = false;
+ $this->_pf_colon_colon = false;
+ $this->_pv_last_string = false;
+ $this->_pf_inmethod = false;
+ $this->_pf_no_output_yet = false;
+ $this->_pv_saveline = 0;
+ $this->_pv_next_word = false;
+ $this->_save = '';
+ }
+
+ /**
+ * Initialize the {@link $tokenpushEvent, $wordpushEvent} arrays
+ *
+ * @return void
+ */
+ function phpDocumentor_HighlightParser()
+ {
+ if (!defined('T_INTERFACE')) {
+ define('T_INTERFACE', -1);
+ }
+ $this->allowableTags
+ = $GLOBALS['_phpDocumentor_tags_allowed'];
+ $this->allowableInlineTags
+ = $GLOBALS['_phpDocumentor_inline_doc_tags_allowed'];
+ $this->inlineTagHandlers
+ = array('*' => 'handleDefaultInlineTag');
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_NOEVENTS] =
+ array(
+ T_OPEN_TAG => PARSER_EVENT_PHPCODE,
+ );
+
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_PHPCODE] =
+ array(
+ T_FUNCTION => PARSER_EVENT_FUNCTION,
+ T_CLASS => PARSER_EVENT_CLASS,
+ T_INTERFACE => PARSER_EVENT_CLASS,
+ T_INCLUDE_ONCE => PARSER_EVENT_INCLUDE,
+ T_INCLUDE => PARSER_EVENT_INCLUDE,
+ T_START_HEREDOC => PARSER_EVENT_EOFQUOTE,
+ T_REQUIRE => PARSER_EVENT_INCLUDE,
+ T_REQUIRE_ONCE => PARSER_EVENT_INCLUDE,
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_PHPCODE] =
+ array(
+ "define" => PARSER_EVENT_DEFINE,
+ '"' => PARSER_EVENT_QUOTE,
+ '\'' => PARSER_EVENT_QUOTE,
+ );
+ /**************************************************************/
+
+ $this->wordpushEvent[PARSER_EVENT_FUNCTION] =
+ array(
+ '{' => PARSER_EVENT_LOGICBLOCK,
+ '(' => PARSER_EVENT_FUNCTION_PARAMS,
+ );
+ $this->tokenpushEvent[PARSER_EVENT_FUNCTION] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpopEvent[PARSER_EVENT_FUNCTION] = array("}");
+ /**************************************************************/
+
+ $this->tokenpopEvent[PARSER_EVENT_EOFQUOTE] = array(T_END_HEREDOC);
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_FUNCTION_PARAMS] =
+ array(
+ T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,
+ T_ARRAY => PARSER_EVENT_ARRAY,
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_FUNCTION_PARAMS] =
+ array(
+ '"' => PARSER_EVENT_QUOTE,
+ "'" => PARSER_EVENT_QUOTE,
+ );
+ $this->wordpopEvent[PARSER_EVENT_FUNCTION_PARAMS] = array(")");
+ /**************************************************************/
+
+ $this->wordpushEvent[PARSER_EVENT_LOGICBLOCK] =
+ array(
+ "{" => PARSER_EVENT_LOGICBLOCK,
+ '"' => PARSER_EVENT_QUOTE,
+ );
+ $this->tokenpushEvent[PARSER_EVENT_LOGICBLOCK] =
+ array(
+ T_GLOBAL => PARSER_EVENT_FUNC_GLOBAL,
+ T_STATIC => PARSER_EVENT_STATIC_VAR,
+ T_START_HEREDOC => PARSER_EVENT_EOFQUOTE,
+ T_CURLY_OPEN => PARSER_EVENT_LOGICBLOCK,
+ T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK,
+ );
+ $this->wordpopEvent[PARSER_EVENT_LOGICBLOCK] = array("}");
+ $this->tokenpopEvent[PARSER_EVENT_LOGICBLOCK] = array(T_CURLY_OPEN);
+
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_ARRAY] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpopEvent[PARSER_EVENT_ARRAY] = array(")");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_FUNC_GLOBAL] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpopEvent[PARSER_EVENT_FUNC_GLOBAL] = array(";");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR] =
+ array(
+ T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_STATIC_VAR] =
+ array(
+ "=" => PARSER_EVENT_STATIC_VAR_VALUE,
+ );
+ $this->wordpopEvent[PARSER_EVENT_STATIC_VAR] = array(";");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] =
+ array(
+ T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ T_ARRAY => PARSER_EVENT_ARRAY,
+ );
+ $this->wordpushEvent[PARSER_EVENT_STATIC_VAR_VALUE] =
+ array(
+ '"' => PARSER_EVENT_QUOTE,
+ "'" => PARSER_EVENT_QUOTE,
+ );
+ $this->wordpopEvent[PARSER_EVENT_STATIC_VAR_VALUE] = array(";", ",");
+ /**************************************************************/
+ $this->tokenpushEvent[PARSER_EVENT_QUOTE] =
+ array(
+ T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
+ T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR,
+ );
+ $this->wordpopEvent[PARSER_EVENT_QUOTE] = array('"');
+ /**************************************************************/
+ $this->tokenpushEvent[PARSER_EVENT_QUOTE_VAR] =
+ array(
+ T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
+ T_CURLY_OPEN => PARSER_EVENT_QUOTE_VAR,
+ );
+ $this->wordpushEvent[PARSER_EVENT_QUOTE_VAR] =
+ array(
+ "{" => PARSER_EVENT_QUOTE_VAR,
+ '"' => PARSER_EVENT_QUOTE_VAR,
+ "'" => PARSER_EVENT_QUOTE_VAR,
+ );
+ $this->wordpopEvent[PARSER_EVENT_QUOTE_VAR] = array('}');
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_DEFINE] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ T_CONSTANT_ENCAPSED_STRING => PARSER_EVENT_QUOTE,
+ );
+ $this->wordpushEvent[PARSER_EVENT_DEFINE] =
+ array(
+ "(" => PARSER_EVENT_DEFINE_PARAMS,
+ );
+ $this->wordpopEvent[PARSER_EVENT_DEFINE] = array(";");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS] =
+ array(
+ "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,
+ '"' => PARSER_EVENT_QUOTE,
+ "'" => PARSER_EVENT_QUOTE,
+ );
+ $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS] = array(")");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] =
+ array(
+ "(" => PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS,
+ '"' => PARSER_EVENT_QUOTE,
+ "'" => PARSER_EVENT_QUOTE,
+ );
+ $this->wordpopEvent[PARSER_EVENT_DEFINE_PARAMS_PARENTHESIS] = array(")");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_VAR] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ T_ARRAY => PARSER_EVENT_ARRAY,
+ );
+ $this->wordpopEvent[PARSER_EVENT_VAR] = array(";");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_CLASS] =
+ array(
+ T_FUNCTION => PARSER_EVENT_METHOD,
+ T_VAR => PARSER_EVENT_VAR,
+ T_COMMENT => PARSER_EVENT_DOCBLOCK,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ T_CLOSE_TAG => PARSER_EVENT_OUTPHP,
+ );
+ $this->wordpopEvent[PARSER_EVENT_CLASS] = array("}");
+ /**************************************************************/
+
+ $this->wordpushEvent[PARSER_EVENT_METHOD] =
+ array(
+ '{' => PARSER_EVENT_METHOD_LOGICBLOCK,
+ '(' => PARSER_EVENT_FUNCTION_PARAMS,
+ );
+ $this->tokenpushEvent[PARSER_EVENT_METHOD] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpopEvent[PARSER_EVENT_METHOD] = array("}", ";");
+ /**************************************************************/
+
+ $this->wordpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] =
+ array(
+ "{" => PARSER_EVENT_METHOD_LOGICBLOCK,
+ '"' => PARSER_EVENT_QUOTE,
+ );
+ $this->tokenpushEvent[PARSER_EVENT_METHOD_LOGICBLOCK] =
+ array(
+ T_OBJECT_OPERATOR => PARSER_EVENT_CLASS_MEMBER,
+ T_GLOBAL => PARSER_EVENT_FUNC_GLOBAL,
+ T_STATIC => PARSER_EVENT_STATIC_VAR,
+ T_CURLY_OPEN => PARSER_EVENT_LOGICBLOCK,
+ T_DOLLAR_OPEN_CURLY_BRACES => PARSER_EVENT_LOGICBLOCK,
+ );
+ $this->wordpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array("}");
+ $this->tokenpopEvent[PARSER_EVENT_METHOD_LOGICBLOCK] = array(T_CURLY_OPEN);
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_INCLUDE] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_INCLUDE] =
+ array(
+ "(" => PARSER_EVENT_INCLUDE_PARAMS,
+ );
+ $this->wordpopEvent[PARSER_EVENT_INCLUDE] = array(";");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS] =
+ array(
+ "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,
+ );
+ $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS] = array(")");
+ /**************************************************************/
+
+ $this->tokenpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] =
+ array(
+ T_COMMENT => PARSER_EVENT_COMMENT,
+ T_DOC_COMMENT => PARSER_EVENT_DOCBLOCK,
+ );
+ $this->wordpushEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] =
+ array(
+ "(" => PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS,
+ );
+ $this->wordpopEvent[PARSER_EVENT_INCLUDE_PARAMS_PARENTHESIS] = array(")");
+ }
+}
+?>