summaryrefslogblamecommitdiffstats
path: root/paste/include/geshi/classes/class.geshistringcontext.php
blob: 1d712e556028f3944c3f9e2d513a8c3d3cf6217b (plain) (tree)





























































































































































































                                                                                                                                                                              
<?php
/**
 * GeSHi - Generic Syntax Highlighter
 * 
 * For information on how to use GeSHi, please consult the documentation
 * found in the docs/ directory, or online at http://geshi.org/docs/
 * 
 *  This file is part of GeSHi.
 *
 *  GeSHi is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  GeSHi 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GeSHi; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * You can view a copy of the GNU GPL in the COPYING file that comes
 * with GeSHi, in the docs/ directory.
 *
 * @package   core
 * @author    Nigel McNie <nigel@geshi.org>
 * @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 <nigel@geshi.org>
 * @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;
    }
}

?>