* @license http://www.gnu.org/copyleft/gpl.html GNU GPL * @copyright (C) 2005 Nigel McNie * @version 1.1.0 * */ /** * The GeSHiStringContext class. This class extends GeSHiContext to handle * the concept of escape characters that strings often use. * * @package core * @author Nigel McNie * @since 1.1.0 * @version 1.1.0 * @see GeSHiContext */ class GeSHiStringContext extends GeSHiContext { /**#@- * @access private */ var $_escapeCharacters; // Characters that should be escaped var $_charsToEscape; /** * This is used by the 'DELIM' "character" in the _charsToEscape array. We * abuse the fact that _addParseData will be called right after _getContextEndData * if the context is to be passed */ var $_lastOpener; /**#@-*/ /** * GetContextEndData */ function _getContextEndData ($code, $context_open_key, $context_opener) { geshi_dbg('GeSHiStringContext::_getContextEndData(' . $this->_contextName . ', ' . $context_open_key . ', ' . $context_opener . ')', GESHI_DBG_API | GESHI_DBG_PARSE); $this->_lastOpener = $context_opener; foreach ($this->_contextDelimiters[$context_open_key][1] as $ender) { geshi_dbg(' Checking ender: ' . $ender, GESHI_DBG_PARSE); // Prepare ender regexes if needed $ender = $this->_substitutePlaceholders($ender); geshi_dbg(' ender after substitution: ' . $ender, GESHI_DBG_PARSE); $pos = 0; while (true) { $pos = geshi_get_position($code, $ender, $pos); if (false === $pos) { break; } $len = $pos['len']; $pos = $pos['pos']; $possible_string = substr($code, 0, $pos); geshi_dbg(' String might be: ' . $possible_string, GESHI_DBG_PARSE); foreach ($this->_escapeCharacters as $escape_char) { // remove escaped escape characters $possible_string = str_replace($escape_char . $escape_char, '', $possible_string); } geshi_dbg(' String with double escapes removed: ' . $possible_string, GESHI_DBG_PARSE); //@todo [blocking 1.1.1] possible bug: only last escape character checked here if (substr($possible_string, -1) != $escape_char) { // We may have found the correct ender. If we haven't, then this string // never ends and we will set the end position to the length of the code // substr($code, $pos, 1) == $ender $endpos = geshi_get_position($code, $ender, $pos); geshi_dbg(' position of ender: ' . $endpos['pos'], GESHI_DBG_PARSE); $pos = ($pos && $endpos['pos'] === $pos) ? $pos : strlen($code); return array('pos' => $pos, 'len' => $len, 'dlm' => $ender); } // else, start further up ++$pos; } } return false; } /** * Overrides addParseData to add escape characters also */ function _addParseData ($code, $first_char_of_next_context = '') { geshi_dbg('GeSHiStringContext::_addParseData(' . substr($code, 0, 15) . '...)', GESHI_DBG_PARSE); $length = strlen($code); $string = ''; for ($i = 0; $i < $length; $i++) { $char = substr($code, $i, 1); geshi_dbg('Char: ' . $char, GESHI_DBG_PARSE); $skip = false; foreach ($this->_escapeCharacters as $escape_char) { $len = 1; if ($char == $escape_char && (false !== ($len = $this->_shouldBeEscaped(substr($code, $i + 1))))) { geshi_dbg('Match: len = ' . $len, GESHI_DBG_PARSE); if ($string) { $this->_styler->addParseData($string, $this->_contextName); $string = ''; } // Needs a better name than /esc $this->_styler->addParseData($escape_char . substr($code, $i + 1, $len), $this->_contextName . '/esc'); // FastForward $i += $len; $skip = true; break; } } if (!$skip) { $string .= $char; } } if ($string) { $this->_styler->addParseData($string, $this->_contextName); } } /** * Checks whether the character(s) at the start of the parameter string are * characters that should be escaped. * * @param string The string to check the beginning of for escape characters * @return int|false The length of the escape character sequence, else false */ function _shouldBeEscaped ($code) { // Feature: If 'DELIM' is one of the "characters" in the _charsToEscape array, then it is // replaced by the context opener $chars_to_escape = str_replace('DELIM', $this->_lastOpener, $this->_charsToEscape); geshi_dbg('Checking: ' . substr($code, 0, 15), GESHI_DBG_PARSE); foreach ($chars_to_escape as $match) { if ('REGEX' != substr($match, 0, 5)) { geshi_dbg('Test: ' . $match, GESHI_DBG_PARSE); if (substr($code, 0, 1) == $match) { return 1; } } else { geshi_dbg(' Testing via regex: ' . $match . '... ', GESHI_DBG_PARSE, false); $data = geshi_get_position($code, $match, 0); if (0 === $data['pos']) { geshi_dbg('match, data = ' . print_r($data, true), GESHI_DBG_PARSE); return $data['len']; } geshi_dbg('no match', GESHI_DBG_PARSE); } } // No matches... return false; } } ?>