home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / Text / Highlighter.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  12.1 KB  |  399 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4.  * Highlighter base class
  5.  *
  6.  * PHP versions 4 and 5
  7.  *
  8.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  9.  * that is available through the world-wide-web at the following URI:
  10.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  11.  * the PHP License and are unable to obtain it through the web, please
  12.  * send a note to license@php.net so we can mail you a copy immediately.
  13.  *
  14.  * @category   Text
  15.  * @package    Text_Highlighter
  16.  * @author     Andrey Demenev <demenev@gmail.com>
  17.  * @copyright  2004-2006 Andrey Demenev
  18.  * @license    http://www.php.net/license/3_0.txt  PHP License
  19.  * @version    CVS: $Id: Highlighter.php,v 1.1 2007/06/03 02:35:28 ssttoo Exp $
  20.  * @link       http://pear.php.net/package/Text_Highlighter
  21.  */
  22.  
  23. require_once 'PEAR.php';
  24.  
  25. // {{{ BC constants
  26.  
  27. // BC trick : define constants related to default
  28. // renderer if needed
  29. if (!defined('HL_NUMBERS_LI')) {
  30.     /**#@+
  31.      * Constant for use with $options['numbers']
  32.      * @see Text_Highlighter_Renderer_Html::_init()
  33.      */
  34.     /**
  35.      * use numbered list
  36.      */
  37.     define ('HL_NUMBERS_LI'    ,    1);
  38.     /**
  39.      * Use 2-column table with line numbers in left column and code in  right column.
  40.      * Forces $options['tag'] = HL_TAG_PRE
  41.      */
  42.     define ('HL_NUMBERS_TABLE'    , 2);
  43.     /**#@-*/
  44. }
  45.  
  46. // }}}
  47. // {{{ constants
  48. /**
  49.  * for our purpose, it is infinity
  50.  */
  51. define ('HL_INFINITY',      1000000000);
  52.  
  53. // }}}
  54.  
  55. /**
  56.  * Text highlighter base class
  57.  *
  58.  * @author     Andrey Demenev <demenev@gmail.com>
  59.  * @copyright  2004-2006 Andrey Demenev
  60.  * @license    http://www.php.net/license/3_0.txt  PHP License
  61.  * @version    Release: 0.7.1
  62.  * @link       http://pear.php.net/package/Text_Highlighter
  63.  */
  64.  
  65. // {{{ Text_Highlighter
  66.  
  67. /**
  68.  * Text highlighter base class
  69.  *
  70.  * This class implements all functions necessary for highlighting,
  71.  * but it does not contain highlighting rules. Actual highlighting is
  72.  * done using a descendent of this class.
  73.  *
  74.  * One is not supposed to manually create descendent classes.
  75.  * Instead, describe highlighting  rules in XML format and
  76.  * use {@link Text_Highlighter_Generator} to create descendent class.
  77.  * Alternatively, an instance of a descendent class can be created
  78.  * directly.
  79.  *
  80.  * Use {@link Text_Highlighter::factory()} to create an
  81.  * object for particular language highlighter
  82.  *
  83.  * Usage example
  84.  * <code>
  85.  *require_once 'Text/Highlighter.php';
  86.  *$hlSQL =& Text_Highlighter::factory('SQL',array('numbers'=>true));
  87.  *echo $hlSQL->highlight('SELECT * FROM table a WHERE id = 12');
  88.  * </code>
  89.  *
  90.  * @author Andrey Demenev <demenev@gmail.com>
  91.  * @package Text_Highlighter
  92.  * @access public
  93.  */
  94.  
  95. class Text_Highlighter
  96. {
  97.     // {{{ members
  98.     
  99.     /**
  100.      * Syntax highlighting rules.
  101.      * Auto-generated classes set this var
  102.      *
  103.      * @access protected
  104.      * @see _init
  105.      * @var array
  106.      */
  107.     var $_syntax;
  108.  
  109.     /**
  110.      * Renderer object.
  111.      *
  112.      * @access private
  113.      * @var array
  114.      */
  115.     var $_renderer;
  116.  
  117.     /**
  118.      * Options. Keeped for BC
  119.      *
  120.      * @access protected
  121.      * @var array
  122.      */
  123.     var $_options = array();
  124.  
  125.     /**
  126.      * Conditionds
  127.      *
  128.      * @access protected
  129.      * @var array
  130.      */
  131.     var $_conditions = array();
  132.  
  133.     /**
  134.      * Disabled keywords
  135.      *
  136.      * @access protected
  137.      * @var array
  138.      */
  139.     var $_disabled = array();
  140.  
  141.     /**
  142.      * Language
  143.      *
  144.      * @access protected
  145.      * @var string
  146.      */
  147.     var $_language = '';
  148.  
  149.     // }}}
  150.     // {{{ _checkDefines
  151.     
  152.     /**
  153.      * Called by subclssses' constructors to enable/disable
  154.      * optional highlighter rules
  155.      *
  156.      * @param array $defines  Conditional defines
  157.      *
  158.      * @access protected
  159.      */
  160.     function _checkDefines()
  161.     {
  162.         if (isset($this->_options['defines'])) {
  163.             $defines = $this->_options['defines'];
  164.         } else {
  165.             $defines = array();
  166.         }
  167.         foreach ($this->_conditions as $name => $actions) {
  168.             foreach($actions as $action) {
  169.                 $present = in_array($name, $defines);
  170.                 if (!$action[1]) {
  171.                     $present = !$present;
  172.                 }
  173.                 if ($present) {
  174.                     unset($this->_disabled[$action[0]]);
  175.                 } else {
  176.                     $this->_disabled[$action[0]] = true;
  177.                 }
  178.             }
  179.         }
  180.     }
  181.  
  182.     // }}}
  183.     // {{{ factory
  184.     
  185.     /**
  186.      * Create a new Highlighter object for specified language
  187.      *
  188.      * @param string $lang    language, for example "SQL"
  189.      * @param array  $options Rendering options. This
  190.      * parameter is only keeped for BC reasons, use 
  191.      * {@link Text_Highlighter::setRenderer()} instead
  192.      *
  193.      * @return mixed a newly created Highlighter object, or 
  194.      * a PEAR error object on error
  195.      *
  196.      * @static
  197.      * @access public
  198.      */
  199.     function &factory($lang, $options = array())
  200.     {
  201.         $lang = strtoupper($lang);
  202.         @include_once 'Text/Highlighter/' . $lang . '.php';
  203.  
  204.         $classname = 'Text_Highlighter_' . $lang;
  205.  
  206.         if (!class_exists($classname)) {
  207.             return PEAR::raiseError('Highlighter for ' . $lang . ' not found');
  208.         }
  209.  
  210.         $obj =& new $classname($options);
  211.  
  212.         return $obj;
  213.     }
  214.  
  215.     // }}}
  216.     // {{{ setRenderer
  217.     
  218.     /**
  219.      * Set renderer object
  220.      *
  221.      * @param object $renderer  Text_Highlighter_Renderer
  222.      *
  223.      * @access public
  224.      */
  225.     function setRenderer(&$renderer)
  226.     {
  227.         $this->_renderer =& $renderer;
  228.     }
  229.  
  230.     // }}}
  231.  
  232.     /**
  233.      * Helper function to find matching brackets
  234.      *
  235.      * @access private
  236.      */
  237.     function _matchingBrackets($str)
  238.     {
  239.         return strtr($str, '()<>[]{}', ')(><][}{');
  240.     }
  241.  
  242.  
  243.     
  244.     
  245.     function _getToken()
  246.     {
  247.         if (!empty($this->_tokenStack)) {
  248.             return array_pop($this->_tokenStack);
  249.         }
  250.         if ($this->_pos >= $this->_len) {
  251.             return NULL;
  252.         }
  253.  
  254.         if ($this->_state != -1 && preg_match($this->_endpattern, $this->_str, $m, PREG_OFFSET_CAPTURE, $this->_pos)) {
  255.             $endpos = $m[0][1];
  256.             $endmatch = $m[0][0];
  257.         } else {
  258.             $endpos = -1;
  259.         }
  260.         preg_match ($this->_regs[$this->_state], $this->_str, $m, PREG_OFFSET_CAPTURE, $this->_pos);
  261.         $n = 1;
  262.  
  263.  
  264.          foreach ($this->_counts[$this->_state] as $i=>$count) {
  265.             if (!isset($m[$n])) {
  266.                 break;
  267.             }
  268.             if ($m[$n][1]>-1 && ($endpos == -1 || $m[$n][1] < $endpos)) {
  269.                 if ($this->_states[$this->_state][$i] != -1) {
  270.                     $this->_tokenStack[] = array($this->_delim[$this->_state][$i], $m[$n][0]);
  271.                 } else {
  272.                     $inner = $this->_inner[$this->_state][$i];
  273.                     if (isset($this->_parts[$this->_state][$i])) {
  274.                         $parts = array();
  275.                         $partpos = $m[$n][1];
  276.                         for ($j=1; $j<=$count; $j++) {
  277.                             if ($m[$j+$n][1] < 0) {
  278.                                 continue;
  279.                             }
  280.                             if (isset($this->_parts[$this->_state][$i][$j])) {
  281.                                 if ($m[$j+$n][1] > $partpos) {
  282.                                     array_unshift($parts, array($inner, substr($this->_str, $partpos, $m[$j+$n][1]-$partpos)));
  283.                                 }
  284.                                 array_unshift($parts, array($this->_parts[$this->_state][$i][$j], $m[$j+$n][0]));
  285.                             }
  286.                             $partpos = $m[$j+$n][1] + strlen($m[$j+$n][0]);
  287.                         }
  288.                         if ($partpos < $m[$n][1] + strlen($m[$n][0])) {
  289.                             array_unshift($parts, array($inner, substr($this->_str, $partpos, $m[$n][1] - $partpos + strlen($m[$n][0]))));
  290.                         }
  291.                         $this->_tokenStack = array_merge($this->_tokenStack, $parts);
  292.                     } else {
  293.                         foreach ($this->_keywords[$this->_state][$i] as $g => $re) {
  294.                             if (isset($this->_disabled[$g])) {
  295.                                 continue;
  296.                             }
  297.                             if (preg_match($re, $m[$n][0])) {
  298.                                 $inner = $this->_kwmap[$g];
  299.                                 break;
  300.                             }
  301.                         }
  302.                         $this->_tokenStack[] = array($inner, $m[$n][0]);
  303.                     }
  304.                 }
  305.                 if ($m[$n][1] > $this->_pos) {
  306.                     $this->_tokenStack[] = array($this->_lastinner, substr($this->_str, $this->_pos, $m[$n][1]-$this->_pos));
  307.                 }
  308.                 $this->_pos = $m[$n][1] + strlen($m[$n][0]);
  309.                 if ($this->_states[$this->_state][$i] != -1) {
  310.                     $this->_stack[] = array($this->_state, $this->_lastdelim, $this->_lastinner, $this->_endpattern);
  311.                     $this->_lastinner = $this->_inner[$this->_state][$i];
  312.                     $this->_lastdelim = $this->_delim[$this->_state][$i];
  313.                     $l = $this->_state;
  314.                     $this->_state = $this->_states[$this->_state][$i];
  315.                     $this->_endpattern = $this->_end[$this->_state];
  316.                     if ($this->_subst[$l][$i]) {
  317.                         for ($k=0; $k<=$this->_counts[$l][$i]; $k++) {
  318.                             if (!isset($m[$i+$k])) {
  319.                                 break;
  320.                             }
  321.                             $quoted = preg_quote($m[$n+$k][0], '/');
  322.                             $this->_endpattern = str_replace('%'.$k.'%', $quoted, $this->_endpattern);
  323.                             $this->_endpattern = str_replace('%b'.$k.'%', $this->_matchingBrackets($quoted), $this->_endpattern);
  324.                         }
  325.                     }
  326.                 }
  327.                 return array_pop($this->_tokenStack);
  328.             }
  329.             $n += $count + 1;
  330.         }
  331.  
  332.         if ($endpos > -1) {
  333.             $this->_tokenStack[] = array($this->_lastdelim, $endmatch);
  334.             if ($endpos > $this->_pos) {
  335.                 $this->_tokenStack[] = array($this->_lastinner, substr($this->_str, $this->_pos, $endpos-$this->_pos));
  336.             }
  337.             list($this->_state, $this->_lastdelim, $this->_lastinner, $this->_endpattern) = array_pop($this->_stack);
  338.             $this->_pos = $endpos + strlen($endmatch);
  339.             return array_pop($this->_tokenStack);
  340.         }
  341.         $p = $this->_pos;
  342.         $this->_pos = HL_INFINITY;
  343.         return array($this->_lastinner, substr($this->_str, $p));
  344.     }
  345.     
  346.     
  347.     
  348.     
  349.     // {{{ highlight
  350.  
  351.     /**
  352.      * Highlights code
  353.      *
  354.      * @param  string $str      Code to highlight
  355.      * @access public
  356.      * @return string Highlighted text
  357.      *
  358.      */
  359.  
  360.     function highlight($str)
  361.     {
  362.         if (!($this->_renderer)) {
  363.             include_once('Text/Highlighter/Renderer/Html.php');
  364.             $this->_renderer =& new Text_Highlighter_Renderer_Html($this->_options);
  365.         }
  366.         $this->_state = -1;
  367.         $this->_pos = 0;
  368.         $this->_stack = array();
  369.         $this->_tokenStack = array();
  370.         $this->_lastinner = $this->_defClass;
  371.         $this->_lastdelim = $this->_defClass;
  372.         $this->_endpattern = '';
  373.         $this->_renderer->reset();
  374.         $this->_renderer->setCurrentLanguage($this->_language);
  375.         $this->_str = $this->_renderer->preprocess($str);
  376.         $this->_len = strlen($this->_str);
  377.         while ($token = $this->_getToken()) {
  378.             $this->_renderer->acceptToken($token[0], $token[1]);
  379.         }
  380.         $this->_renderer->finalize();
  381.         return $this->_renderer->getOutput();
  382.     }
  383.     
  384.     // }}}
  385.     
  386. }
  387.  
  388. // }}}
  389.  
  390. /*
  391.  * Local variables:
  392.  * tab-width: 4
  393.  * c-basic-offset: 4
  394.  * c-hanging-comment-ender-p: nil
  395.  * End:
  396.  */
  397.  
  398. ?>
  399.