From 903ae8a581fac1e6917fc3e31d2ad8fb91df80c3 Mon Sep 17 00:00:00 2001 From: ctrlaltca <> Date: Thu, 12 Jul 2012 11:21:01 +0000 Subject: standardize the use of unix eol; use svn properties to enforce native eol --- .../TextHighlighter/Text/Highlighter/Generator.php | 2508 ++++++++++---------- 1 file changed, 1254 insertions(+), 1254 deletions(-) (limited to 'framework/3rdParty/TextHighlighter/Text/Highlighter/Generator.php') diff --git a/framework/3rdParty/TextHighlighter/Text/Highlighter/Generator.php b/framework/3rdParty/TextHighlighter/Text/Highlighter/Generator.php index 896af078..c9bca6aa 100644 --- a/framework/3rdParty/TextHighlighter/Text/Highlighter/Generator.php +++ b/framework/3rdParty/TextHighlighter/Text/Highlighter/Generator.php @@ -1,1254 +1,1254 @@ - -* @copyright 2004-2006 Andrey Demenev -* @license http://www.php.net/license/3_0.txt PHP License -* @version CVS: $Id: Generator.php,v 1.1 2007/06/03 02:36:35 ssttoo Exp $ -* @link http://pear.php.net/package/Text_Highlighter -*/ - -// {{{ error codes - -define ('TEXT_HIGHLIGHTER_EMPTY_RE', 1); -define ('TEXT_HIGHLIGHTER_INVALID_RE', 2); -define ('TEXT_HIGHLIGHTER_EMPTY_OR_MISSING', 3); -define ('TEXT_HIGHLIGHTER_EMPTY', 4); -define ('TEXT_HIGHLIGHTER_REGION_REGION', 5); -define ('TEXT_HIGHLIGHTER_REGION_BLOCK', 6); -define ('TEXT_HIGHLIGHTER_BLOCK_REGION', 7); -define ('TEXT_HIGHLIGHTER_KEYWORD_BLOCK', 8); -define ('TEXT_HIGHLIGHTER_KEYWORD_INHERITS', 9); -define ('TEXT_HIGHLIGHTER_PARSE', 10); -define ('TEXT_HIGHLIGHTER_FILE_WRITE', 11); -define ('TEXT_HIGHLIGHTER_FILE_READ', 12); -// }}} - -/** -* Syntax highliter class generator class -* -* This class is used to generate PHP classes -* from XML files with highlighting rules -* -* Usage example -* -*require_once 'Text/Highlighter/Generator.php'; -*$generator =& new Text_Highlighter_Generator('php.xml'); -*$generator->generate(); -*$generator->saveCode('PHP.php'); -* -* -* A command line script generate is provided for -* class generation (installs in scripts/Text/Highlighter). -* -* @author Andrey Demenev -* @copyright 2004-2006 Andrey Demenev -* @license http://www.php.net/license/3_0.txt PHP License -* @version Release: 0.7.0 -* @link http://pear.php.net/package/Text_Highlighter -*/ - -class Text_Highlighter_Generator extends XML_Parser -{ - // {{{ properties - /** - * Whether to do case folding. - * We have to declare it here, because XML_Parser - * sets case folding in constructor - * - * @var boolean - */ - var $folding = false; - - /** - * Holds name of file with highlighting rules - * - * @var string - * @access private - */ - var $_syntaxFile; - - /** - * Current element being processed - * - * @var array - * @access private - */ - var $_element; - - /** - * List of regions - * - * @var array - * @access private - */ - var $_regions = array(); - - /** - * List of blocks - * - * @var array - * @access private - */ - var $_blocks = array(); - - /** - * List of keyword groups - * - * @var array - * @access private - */ - var $_keywords = array(); - - /** - * List of authors - * - * @var array - * @access private - */ - var $_authors = array(); - - /** - * Name of language - * - * @var string - * @access public - */ - var $language = ''; - - /** - * Generated code - * - * @var string - * @access private - */ - var $_code = ''; - - /** - * Default class - * - * @var string - * @access private - */ - var $_defClass = 'default'; - - /** - * Comment - * - * @var string - * @access private - */ - var $_comment = ''; - - /** - * Flag for comment processing - * - * @var boolean - * @access private - */ - var $_inComment = false; - - /** - * Sorting order of current block/region - * - * @var integer - * @access private - */ - var $_blockOrder = 0; - - /** - * Generation errors - * - * @var array - * @access private - */ - var $_errors; - - // }}} - // {{{ constructor - - /** - * Constructor - * - * @param string $syntaxFile Name of XML file - * with syntax highlighting rules - * - * @access public - */ - - function __construct($syntaxFile = '') - { - XML_Parser::XML_Parser(null, 'func'); - $this->_errors = array(); - $this->_declareErrorMessages(); - if ($syntaxFile) { - $this->setInputFile($syntaxFile); - } - } - - // }}} - // {{{ _formatError - - /** - * Format error message - * - * @param int $code error code - * @param string $params parameters - * @param string $fileName file name - * @param int $lineNo line number - * @return array - * @access public - */ - function _formatError($code, $params, $fileName, $lineNo) - { - $template = $this->_templates[$code]; - $ret = call_user_func_array('sprintf', array_merge(array($template), $params)); - if ($fileName) { - $ret = '[' . $fileName . '] ' . $ret; - } - if ($lineNo) { - $ret .= ' (line ' . $lineNo . ')'; - } - return $ret; - } - - // }}} - // {{{ declareErrorMessages - - /** - * Set up error message templates - * - * @access private - */ - function _declareErrorMessages() - { - $this->_templates = array ( - TEXT_HIGHLIGHTER_EMPTY_RE => 'Empty regular expression', - TEXT_HIGHLIGHTER_INVALID_RE => 'Invalid regular expression : %s', - TEXT_HIGHLIGHTER_EMPTY_OR_MISSING => 'Empty or missing %s', - TEXT_HIGHLIGHTER_EMPTY => 'Empty %s', - TEXT_HIGHLIGHTER_REGION_REGION => 'Region %s refers undefined region %s', - TEXT_HIGHLIGHTER_REGION_BLOCK => 'Region %s refers undefined block %s', - TEXT_HIGHLIGHTER_BLOCK_REGION => 'Block %s refers undefined region %s', - TEXT_HIGHLIGHTER_KEYWORD_BLOCK => 'Keyword group %s refers undefined block %s', - TEXT_HIGHLIGHTER_KEYWORD_INHERITS => 'Keyword group %s inherits undefined block %s', - TEXT_HIGHLIGHTER_PARSE => '%s', - TEXT_HIGHLIGHTER_FILE_WRITE => 'Error writing file %s', - TEXT_HIGHLIGHTER_FILE_READ => '%s' - ); - } - - // }}} - // {{{ setInputFile - - /** - * Sets the input xml file to be parsed - * - * @param string Filename (full path) - * @return boolean - * @access public - */ - function setInputFile($file) - { - $this->_syntaxFile = $file; - $ret = parent::setInputFile($file); - if (PEAR::isError($ret)) { - $this->_error(TEXT_HIGHLIGHTER_FILE_READ, $ret->message); - return false; - } - return true; - } - - // }}} - // {{{ generate - - /** - * Generates class code - * - * @access public - */ - - function generate() - { - $this->_regions = array(); - $this->_blocks = array(); - $this->_keywords = array(); - $this->language = ''; - $this->_code = ''; - $this->_defClass = 'default'; - $this->_comment = ''; - $this->_inComment = false; - $this->_authors = array(); - $this->_blockOrder = 0; - $this->_errors = array(); - - $ret = $this->parse(); - if (PEAR::isError($ret)) { - $this->_error(TEXT_HIGHLIGHTER_PARSE, $ret->message); - return false; - } - return true; - } - - // }}} - // {{{ getCode - - /** - * Returns generated code as a string. - * - * @return string Generated code - * @access public - */ - - function getCode() - { - return $this->_code; - } - - // }}} - // {{{ saveCode - - /** - * Saves generated class to file. Note that {@link Text_Highlighter::factory()} - * assumes that filename is uppercase (SQL.php, DTD.php, etc), and file - * is located in Text/Highlighter - * - * @param string $filename Name of file to write the code to - * @return boolean true on success, false on failure - * @access public - */ - - function saveCode($filename) - { - $f = @fopen($filename, 'wb'); - if (!$f) { - $this->_error(TEXT_HIGHLIGHTER_FILE_WRITE, array('outfile'=>$filename)); - return false; - } - fwrite ($f, $this->_code); - fclose($f); - return true; - } - - // }}} - // {{{ hasErrors - - /** - * Reports if there were errors - * - * @return boolean - * @access public - */ - - function hasErrors() - { - return count($this->_errors) > 0; - } - - // }}} - // {{{ getErrors - - /** - * Returns errors - * - * @return array - * @access public - */ - - function getErrors() - { - return $this->_errors; - } - - // }}} - // {{{ _sortBlocks - - /** - * Sorts blocks - * - * @access private - */ - - function _sortBlocks($b1, $b2) { - return $b1['order'] - $b2['order']; - } - - // }}} - // {{{ _sortLookFor - /** - * Sort 'look for' list - * @return int - * @param string $b1 - * @param string $b2 - */ - function _sortLookFor($b1, $b2) { - $o1 = isset($this->_blocks[$b1]) ? $this->_blocks[$b1]['order'] : $this->_regions[$b1]['order']; - $o2 = isset($this->_blocks[$b2]) ? $this->_blocks[$b2]['order'] : $this->_regions[$b2]['order']; - return $o1 - $o2; - } - - // }}} - // {{{ _makeRE - - /** - * Adds delimiters and modifiers to regular expression if necessary - * - * @param string $text Original RE - * @return string Final RE - * @access private - */ - function _makeRE($text, $case = false) - { - if (!strlen($text)) { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_RE); - } - if (!strlen($text) || $text{0} != '/') { - $text = '/' . $text . '/'; - } - if (!$case) { - $text .= 'i'; - } - $php_errormsg = ''; - @preg_match($text, ''); - if ($php_errormsg) { - $this->_error(TEXT_HIGHLIGHTER_INVALID_RE, $php_errormsg); - } - preg_match ('#^/(.+)/(.*)$#', $text, $m); - if (@$m[2]) { - $text = '(?' . $m[2] . ')' . $m[1]; - } else { - $text = $m[1]; - } - return $text; - } - - // }}} - // {{{ _exportArray - - /** - * Exports array as PHP code - * - * @param array $array - * @return string Code - * @access private - */ - function _exportArray($array) - { - $array = var_export($array, true); - return trim(preg_replace('~^(\s*)~m',' \1\1',$array)); - } - - // }}} - // {{{ _countSubpatterns - /** - * Find number of capturing suppaterns in regular expression - * @return int - * @param string $re Regular expression (without delimiters) - */ - function _countSubpatterns($re) - { - preg_match_all('/' . $re . '/', '', $m); - return count($m)-1; - } - - // }}} - - /**#@+ - * @access private - * @param resource $xp XML parser resource - * @param string $elem XML element name - * @param array $attribs XML element attributes - */ - - // {{{ xmltag_Default - - /** - * start handler for element - */ - function xmltag_Default($xp, $elem, $attribs) - { - $this->_aliasAttributes($attribs); - if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); - } - $this->_defClass = @$attribs['innerGroup']; - } - - // }}} - // {{{ xmltag_Region - - /** - * start handler for element - */ - function xmltag_Region($xp, $elem, $attribs) - { - $this->_aliasAttributes($attribs); - if (!isset($attribs['name']) || $attribs['name'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region name'); - } - if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); - } - $this->_element = array('name' => $attribs['name']); - $this->_element['line'] = xml_get_current_line_number($this->parser); - if (isset($attribs['case'])) { - $this->_element['case'] = $attribs['case'] == 'yes'; - } else { - $this->_element['case'] = $this->_case; - } - $this->_element['innerGroup'] = $attribs['innerGroup']; - $this->_element['delimGroup'] = isset($attribs['delimGroup']) ? - $attribs['delimGroup'] : - $attribs['innerGroup']; - $this->_element['start'] = $this->_makeRE(@$attribs['start'], $this->_element['case']); - $this->_element['end'] = $this->_makeRE(@$attribs['end'], $this->_element['case']); - $this->_element['contained'] = @$attribs['contained'] == 'yes'; - $this->_element['never-contained'] = @$attribs['never-contained'] == 'yes'; - $this->_element['remember'] = @$attribs['remember'] == 'yes'; - if (isset($attribs['startBOL']) && $attribs['startBOL'] == 'yes') { - $this->_element['startBOL'] = true; - } - if (isset($attribs['endBOL']) && $attribs['endBOL'] == 'yes') { - $this->_element['endBOL'] = true; - } - if (isset($attribs['neverAfter'])) { - $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']); - } - } - - // }}} - // {{{ xmltag_Block - - /** - * start handler for element - */ - function xmltag_Block($xp, $elem, $attribs) - { - $this->_aliasAttributes($attribs); - if (!isset($attribs['name']) || $attribs['name'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'block name'); - } - if (isset($attribs['innerGroup']) && $attribs['innerGroup'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY, 'innerGroup'); - } - $this->_element = array('name' => $attribs['name']); - $this->_element['line'] = xml_get_current_line_number($this->parser); - if (isset($attribs['case'])) { - $this->_element['case'] = $attribs['case'] == 'yes'; - } else { - $this->_element['case'] = $this->_case; - } - if (isset($attribs['innerGroup'])) { - $this->_element['innerGroup'] = @$attribs['innerGroup']; - } - $this->_element['match'] = $this->_makeRE($attribs['match'], $this->_element['case']); - $this->_element['contained'] = @$attribs['contained'] == 'yes'; - $this->_element['multiline'] = @$attribs['multiline'] == 'yes'; - if (isset($attribs['BOL']) && $attribs['BOL'] == 'yes') { - $this->_element['BOL'] = true; - } - if (isset($attribs['neverAfter'])) { - $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']); - } - } - - // }}} - // {{{ cdataHandler - - /** - * Character data handler. Used for comment - */ - function cdataHandler($xp, $cdata) - { - if ($this->_inComment) { - $this->_comment .= $cdata; - } - } - - // }}} - // {{{ xmltag_Comment - - /** - * start handler for element - */ - function xmltag_Comment($xp, $elem, $attribs) - { - $this->_comment = ''; - $this->_inComment = true; - } - - // }}} - // {{{ xmltag_PartGroup - - /** - * start handler for element - */ - function xmltag_PartGroup($xp, $elem, $attribs) - { - $this->_aliasAttributes($attribs); - if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); - } - $this->_element['partClass'][$attribs['index']] = @$attribs['innerGroup']; - } - - // }}} - // {{{ xmltag_PartClass - - /** - * start handler for element - */ - function xmltag_PartClass($xp, $elem, $attribs) - { - $this->xmltag_PartGroup($xp, $elem, $attribs); - } - - // }}} - // {{{ xmltag_Keywords - - /** - * start handler for element - */ - function xmltag_Keywords($xp, $elem, $attribs) - { - $this->_aliasAttributes($attribs); - if (!isset($attribs['name']) || $attribs['name'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'keyword group name'); - } - if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); - } - if (!isset($attribs['inherits']) || $attribs['inherits'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'inherits'); - } - $this->_element = array('name'=>@$attribs['name']); - $this->_element['line'] = xml_get_current_line_number($this->parser); - $this->_element['innerGroup'] = @$attribs['innerGroup']; - if (isset($attribs['case'])) { - $this->_element['case'] = $attribs['case'] == 'yes'; - } else { - $this->_element['case'] = $this->_case; - } - $this->_element['inherits'] = @$attribs['inherits']; - if (isset($attribs['otherwise'])) { - $this->_element['otherwise'] = $attribs['otherwise']; - } - if (isset($attribs['ifdef'])) { - $this->_element['ifdef'] = $attribs['ifdef']; - } - if (isset($attribs['ifndef'])) { - $this->_element['ifndef'] = $attribs['ifndef']; - } - } - - // }}} - // {{{ xmltag_Keyword - - /** - * start handler for element - */ - function xmltag_Keyword($xp, $elem, $attribs) - { - if (!isset($attribs['match']) || $attribs['match'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'match'); - } - $keyword = @$attribs['match']; - if (!$this->_element['case']) { - $keyword = strtolower($keyword); - } - $this->_element['match'][$keyword] = true; - } - - // }}} - // {{{ xmltag_Contains - - /** - * start handler for element - */ - function xmltag_Contains($xp, $elem, $attribs) - { - $this->_element['contains-all'] = @$attribs['all'] == 'yes'; - if (isset($attribs['region'])) { - $this->_element['contains']['region'][$attribs['region']] = - xml_get_current_line_number($this->parser); - } - if (isset($attribs['block'])) { - $this->_element['contains']['block'][$attribs['block']] = - xml_get_current_line_number($this->parser); - } - } - - // }}} - // {{{ xmltag_But - - /** - * start handler for element - */ - function xmltag_But($xp, $elem, $attribs) - { - if (isset($attribs['region'])) { - $this->_element['not-contains']['region'][$attribs['region']] = true; - } - if (isset($attribs['block'])) { - $this->_element['not-contains']['block'][$attribs['block']] = true; - } - } - - // }}} - // {{{ xmltag_Onlyin - - /** - * start handler for element - */ - function xmltag_Onlyin($xp, $elem, $attribs) - { - if (!isset($attribs['region']) || $attribs['region'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region'); - } - $this->_element['onlyin'][$attribs['region']] = xml_get_current_line_number($this->parser); - } - - // }}} - // {{{ xmltag_Author - - /** - * start handler for element - */ - function xmltag_Author($xp, $elem, $attribs) - { - if (!isset($attribs['name']) || $attribs['name'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'author name'); - } - $this->_authors[] = array( - 'name' => @$attribs['name'], - 'email' => (string)@$attribs['email'] - ); - } - - // }}} - // {{{ xmltag_Highlight - - /** - * start handler for element - */ - function xmltag_Highlight($xp, $elem, $attribs) - { - if (!isset($attribs['lang']) || $attribs['lang'] === '') { - $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'language name'); - } - $this->_code = ''; - $this->language = strtoupper(@$attribs['lang']); - $this->_case = @$attribs['case'] == 'yes'; - } - - // }}} - - /**#@-*/ - - // {{{ _error - - /** - * Add an error message - * - * @param integer $code Error code - * @param mixed $message Error message or array with error message parameters - * @param integer $lineNo Source code line number - * @access private - */ - function _error($code, $params = array(), $lineNo = 0) - { - if (!$lineNo && !empty($this->parser)) { - $lineNo = xml_get_current_line_number($this->parser); - } - $this->_errors[] = $this->_formatError($code, $params, $this->_syntaxFile, $lineNo); - } - - // }}} - // {{{ _aliasAttributes - - /** - * BC trick - * - * @param array $attrs attributes - */ - function _aliasAttributes(&$attrs) - { - if (isset($attrs['innerClass']) && !isset($attrs['innerGroup'])) { - $attrs['innerGroup'] = $attrs['innerClass']; - } - if (isset($attrs['delimClass']) && !isset($attrs['delimGroup'])) { - $attrs['delimGroup'] = $attrs['delimClass']; - } - if (isset($attrs['partClass']) && !isset($attrs['partGroup'])) { - $attrs['partGroup'] = $attrs['partClass']; - } - } - - // }}} - - /**#@+ - * @access private - * @param resource $xp XML parser resource - * @param string $elem XML element name - */ - - // {{{ xmltag_Comment_ - - /** - * end handler for element - */ - function xmltag_Comment_($xp, $elem) - { - $this->_inComment = false; - } - - // }}} - // {{{ xmltag_Region_ - - /** - * end handler for element - */ - function xmltag_Region_($xp, $elem) - { - $this->_element['type'] = 'region'; - $this->_element['order'] = $this->_blockOrder ++; - $this->_regions[$this->_element['name']] = $this->_element; - } - - // }}} - // {{{ xmltag_Keywords_ - - /** - * end handler for element - */ - function xmltag_Keywords_($xp, $elem) - { - $this->_keywords[$this->_element['name']] = $this->_element; - } - - // }}} - // {{{ xmltag_Block_ - - /** - * end handler for element - */ - function xmltag_Block_($xp, $elem) - { - $this->_element['type'] = 'block'; - $this->_element['order'] = $this->_blockOrder ++; - $this->_blocks[$this->_element['name']] = $this->_element; - } - - // }}} - // {{{ xmltag_Highlight_ - - /** - * end handler for element - */ - function xmltag_Highlight_($xp, $elem) - { - $conditions = array(); - $toplevel = array(); - foreach ($this->_blocks as $i => $current) { - if (!$current['contained'] && !isset($current['onlyin'])) { - $toplevel[] = $i; - } - foreach ((array)@$current['onlyin'] as $region => $lineNo) { - if (!isset($this->_regions[$region])) { - $this->_error(TEXT_HIGHLIGHTER_BLOCK_REGION, - array( - 'block' => $current['name'], - 'region' => $region - )); - } - } - } - foreach ($this->_regions as $i=>$current) { - if (!$current['contained'] && !isset($current['onlyin'])) { - $toplevel[] = $i; - } - foreach ((array)@$current['contains']['region'] as $region => $lineNo) { - if (!isset($this->_regions[$region])) { - $this->_error(TEXT_HIGHLIGHTER_REGION_REGION, - array( - 'region1' => $current['name'], - 'region2' => $region - )); - } - } - foreach ((array)@$current['contains']['block'] as $region => $lineNo) { - if (!isset($this->_blocks[$region])) { - $this->_error(TEXT_HIGHLIGHTER_REGION_BLOCK, - array( - 'block' => $current['name'], - 'region' => $region - )); - } - } - foreach ((array)@$current['onlyin'] as $region => $lineNo) { - if (!isset($this->_regions[$region])) { - $this->_error(TEXT_HIGHLIGHTER_REGION_REGION, - array( - 'region1' => $current['name'], - 'region2' => $region - )); - } - } - foreach ($this->_regions as $j => $region) { - if (isset($region['onlyin'])) { - $suits = isset($region['onlyin'][$current['name']]); - } elseif (isset($current['not-contains']['region'][$region['name']])) { - $suits = false; - } elseif (isset($current['contains']['region'][$region['name']])) { - $suits = true; - } else { - $suits = @$current['contains-all'] && @!$region['never-contained']; - } - if ($suits) { - $this->_regions[$i]['lookfor'][] = $j; - } - } - foreach ($this->_blocks as $j=>$region) { - if (isset($region['onlyin'])) { - $suits = isset($region['onlyin'][$current['name']]); - } elseif (isset($current['not-contains']['block'][$region['name']])) { - $suits = false; - } elseif (isset($current['contains']['block'][$region['name']])) { - $suits = true; - } else { - $suits = @$current['contains-all'] && @!$region['never-contained']; - } - if ($suits) { - $this->_regions[$i]['lookfor'][] = $j; - } - } - } - foreach ($this->_blocks as $i=>$current) { - unset ($this->_blocks[$i]['never-contained']); - unset ($this->_blocks[$i]['contained']); - unset ($this->_blocks[$i]['contains-all']); - unset ($this->_blocks[$i]['contains']); - unset ($this->_blocks[$i]['onlyin']); - unset ($this->_blocks[$i]['line']); - } - - foreach ($this->_regions as $i=>$current) { - unset ($this->_regions[$i]['never-contained']); - unset ($this->_regions[$i]['contained']); - unset ($this->_regions[$i]['contains-all']); - unset ($this->_regions[$i]['contains']); - unset ($this->_regions[$i]['onlyin']); - unset ($this->_regions[$i]['line']); - } - - foreach ($this->_keywords as $name => $keyword) { - if (isset($keyword['ifdef'])) { - $conditions[$keyword['ifdef']][] = array($name, true); - } - if (isset($keyword['ifndef'])) { - $conditions[$keyword['ifndef']][] = array($name, false); - } - unset($this->_keywords[$name]['line']); - if (!isset($this->_blocks[$keyword['inherits']])) { - $this->_error(TEXT_HIGHLIGHTER_KEYWORD_INHERITS, - array( - 'keyword' => $keyword['name'], - 'block' => $keyword['inherits'] - )); - } - if (isset($keyword['otherwise']) && !isset($this->_blocks[$keyword['otherwise']]) ) { - $this->_error(TEXT_HIGHLIGHTER_KEYWORD_BLOCK, - array( - 'keyword' => $keyword['name'], - 'block' => $keyword['inherits'] - )); - } - } - - $syntax=array( - 'keywords' => $this->_keywords, - 'blocks' => array_merge($this->_blocks, $this->_regions), - 'toplevel' => $toplevel, - ); - uasort($syntax['blocks'], array(&$this, '_sortBlocks')); - foreach ($syntax['blocks'] as $name => $block) { - if ($block['type'] == 'block') { - continue; - } - if (is_array(@$syntax['blocks'][$name]['lookfor'])) { - usort($syntax['blocks'][$name]['lookfor'], array(&$this, '_sortLookFor')); - } - } - usort($syntax['toplevel'], array(&$this, '_sortLookFor')); - $syntax['case'] = $this->_case; - $this->_code = <<language} syntax highlighting -CODE; - - if ($this->_comment) { - $comment = preg_replace('~^~m',' * ',$this->_comment); - $this->_code .= "\n * \n" . $comment; - } - - $this->_code .= <<_syntaxFile - -CODE; - - foreach ($this->_authors as $author) { - $this->_code .= ' * @author ' . $author['name']; - if ($author['email']) { - $this->_code .= ' <' . $author['email'] . '>'; - } - $this->_code .= "\n"; - } - - $this->_code .= <<language} syntax highlighting - * - -CODE; - foreach ($this->_authors as $author) { - $this->_code .= ' * @author ' . $author['name']; - if ($author['email']) { - $this->_code .= ' <' . $author['email']. '>'; - } - $this->_code .= "\n"; - } - - - $this->_code .= <<language} extends Text_Highlighter -{ - -CODE; - $this->_code .= 'var $_language = \'' . strtolower($this->language) . "';\n\n"; - $array = var_export($syntax, true); - $array = trim(preg_replace('~^(\s*)~m',' \1\1',$array)); - // \$this->_syntax = $array; - $this->_code .= <<_code .= <<_options = \$options; -CODE; - $states = array(); - $i = 0; - foreach ($syntax['blocks'] as $name => $block) { - if ($block['type'] == 'region') { - $states[$name] = $i++; - } - } - $regs = array(); - $counts = array(); - $delim = array(); - $inner = array(); - $end = array(); - $stat = array(); - $keywords = array(); - $parts = array(); - $kwmap = array(); - $subst = array(); - $re = array(); - $ce = array(); - $rd = array(); - $in = array(); - $st = array(); - $kw = array(); - $sb = array(); - foreach ($syntax['toplevel'] as $name) { - $block = $syntax['blocks'][$name]; - if ($block['type'] == 'block') { - $kwm = array(); - $re[] = '(' . $block['match'] . ')'; - $ce[] = $this->_countSubpatterns($block['match']); - $rd[] = ''; - $sb[] = false;; - $st[] = -1; - foreach ($syntax['keywords'] as $kwname => $kwgroup) { - if ($kwgroup['inherits'] != $name) { - continue; - } - $gre = implode('|', array_keys($kwgroup['match'])); - if (!$kwgroup['case']) { - $gre = '(?i)' . $gre; - } - $kwm[$kwname][] = $gre; - $kwmap[$kwname] = $kwgroup['innerGroup']; - } - foreach ($kwm as $g => $ma) { - $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/'; - } - $kw[] = $kwm; - } else { - $kw[] = -1; - $re[] = '(' . $block['start'] . ')'; - $ce[] = $this->_countSubpatterns($block['start']); - $rd[] = $block['delimGroup']; - $st[] = $states[$name]; - $sb[] = $block['remember']; - } - $in[] = $block['innerGroup']; - } - $re = implode('|', $re); - $regs[-1] = '/' . $re . '/'; - $counts[-1] = $ce; - $delim[-1] = $rd; - $inner[-1] = $in; - $stat[-1] = $st; - $keywords[-1] = $kw; - $subst[-1] = $sb; - - foreach ($syntax['blocks'] as $ablock) { - if ($ablock['type'] != 'region') { - continue; - } - $end[] = '/' . $ablock['end'] . '/'; - $re = array(); - $ce = array(); - $rd = array(); - $in = array(); - $st = array(); - $kw = array(); - $pc = array(); - $sb = array(); - foreach ((array)@$ablock['lookfor'] as $name) { - $block = $syntax['blocks'][$name]; - if (isset($block['partClass'])) { - $pc[] = $block['partClass']; - } else { - $pc[] = null; - } - if ($block['type'] == 'block') { - $kwm = array();; - $re[] = '(' . $block['match'] . ')'; - $ce[] = $this->_countSubpatterns($block['match']); - $rd[] = ''; - $sb[] = false; - $st[] = -1; - foreach ($syntax['keywords'] as $kwname => $kwgroup) { - if ($kwgroup['inherits'] != $name) { - continue; - } - $gre = implode('|', array_keys($kwgroup['match'])); - if (!$kwgroup['case']) { - $gre = '(?i)' . $gre; - } - $kwm[$kwname][] = $gre; - $kwmap[$kwname] = $kwgroup['innerGroup']; - } - foreach ($kwm as $g => $ma) { - $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/'; - } - $kw[] = $kwm; - } else { - $sb[] = $block['remember']; - $kw[] = -1; - $re[] = '(' . $block['start'] . ')'; - $ce[] = $this->_countSubpatterns($block['start']); - $rd[] = $block['delimGroup']; - $st[] = $states[$name]; - } - $in[] = $block['innerGroup']; - } - $re = implode('|', $re); - $regs[] = '/' . $re . '/'; - $counts[] = $ce; - $delim[] = $rd; - $inner[] = $in; - $stat[] = $st; - $keywords[] = $kw; - $parts[] = $pc; - $subst[] = $sb; - } - - - $this->_code .= "\n \$this->_regs = " . $this->_exportArray($regs); - $this->_code .= ";\n \$this->_counts = " .$this->_exportArray($counts); - $this->_code .= ";\n \$this->_delim = " .$this->_exportArray($delim); - $this->_code .= ";\n \$this->_inner = " .$this->_exportArray($inner); - $this->_code .= ";\n \$this->_end = " .$this->_exportArray($end); - $this->_code .= ";\n \$this->_states = " .$this->_exportArray($stat); - $this->_code .= ";\n \$this->_keywords = " .$this->_exportArray($keywords); - $this->_code .= ";\n \$this->_parts = " .$this->_exportArray($parts); - $this->_code .= ";\n \$this->_subst = " .$this->_exportArray($subst); - $this->_code .= ";\n \$this->_conditions = " .$this->_exportArray($conditions); - $this->_code .= ";\n \$this->_kwmap = " .$this->_exportArray($kwmap); - $this->_code .= ";\n \$this->_defClass = '" .$this->_defClass . '\''; - $this->_code .= <<_checkDefines(); - } - -} -CODE; -} - -// }}} -} - - -/* -* Local variables: -* tab-width: 4 -* c-basic-offset: 4 -* c-hanging-comment-ender-p: nil -* End: -*/ - -?> + +* @copyright 2004-2006 Andrey Demenev +* @license http://www.php.net/license/3_0.txt PHP License +* @version CVS: $Id: Generator.php,v 1.1 2007/06/03 02:36:35 ssttoo Exp $ +* @link http://pear.php.net/package/Text_Highlighter +*/ + +// {{{ error codes + +define ('TEXT_HIGHLIGHTER_EMPTY_RE', 1); +define ('TEXT_HIGHLIGHTER_INVALID_RE', 2); +define ('TEXT_HIGHLIGHTER_EMPTY_OR_MISSING', 3); +define ('TEXT_HIGHLIGHTER_EMPTY', 4); +define ('TEXT_HIGHLIGHTER_REGION_REGION', 5); +define ('TEXT_HIGHLIGHTER_REGION_BLOCK', 6); +define ('TEXT_HIGHLIGHTER_BLOCK_REGION', 7); +define ('TEXT_HIGHLIGHTER_KEYWORD_BLOCK', 8); +define ('TEXT_HIGHLIGHTER_KEYWORD_INHERITS', 9); +define ('TEXT_HIGHLIGHTER_PARSE', 10); +define ('TEXT_HIGHLIGHTER_FILE_WRITE', 11); +define ('TEXT_HIGHLIGHTER_FILE_READ', 12); +// }}} + +/** +* Syntax highliter class generator class +* +* This class is used to generate PHP classes +* from XML files with highlighting rules +* +* Usage example +* +*require_once 'Text/Highlighter/Generator.php'; +*$generator =& new Text_Highlighter_Generator('php.xml'); +*$generator->generate(); +*$generator->saveCode('PHP.php'); +* +* +* A command line script generate is provided for +* class generation (installs in scripts/Text/Highlighter). +* +* @author Andrey Demenev +* @copyright 2004-2006 Andrey Demenev +* @license http://www.php.net/license/3_0.txt PHP License +* @version Release: 0.7.0 +* @link http://pear.php.net/package/Text_Highlighter +*/ + +class Text_Highlighter_Generator extends XML_Parser +{ + // {{{ properties + /** + * Whether to do case folding. + * We have to declare it here, because XML_Parser + * sets case folding in constructor + * + * @var boolean + */ + var $folding = false; + + /** + * Holds name of file with highlighting rules + * + * @var string + * @access private + */ + var $_syntaxFile; + + /** + * Current element being processed + * + * @var array + * @access private + */ + var $_element; + + /** + * List of regions + * + * @var array + * @access private + */ + var $_regions = array(); + + /** + * List of blocks + * + * @var array + * @access private + */ + var $_blocks = array(); + + /** + * List of keyword groups + * + * @var array + * @access private + */ + var $_keywords = array(); + + /** + * List of authors + * + * @var array + * @access private + */ + var $_authors = array(); + + /** + * Name of language + * + * @var string + * @access public + */ + var $language = ''; + + /** + * Generated code + * + * @var string + * @access private + */ + var $_code = ''; + + /** + * Default class + * + * @var string + * @access private + */ + var $_defClass = 'default'; + + /** + * Comment + * + * @var string + * @access private + */ + var $_comment = ''; + + /** + * Flag for comment processing + * + * @var boolean + * @access private + */ + var $_inComment = false; + + /** + * Sorting order of current block/region + * + * @var integer + * @access private + */ + var $_blockOrder = 0; + + /** + * Generation errors + * + * @var array + * @access private + */ + var $_errors; + + // }}} + // {{{ constructor + + /** + * Constructor + * + * @param string $syntaxFile Name of XML file + * with syntax highlighting rules + * + * @access public + */ + + function __construct($syntaxFile = '') + { + XML_Parser::XML_Parser(null, 'func'); + $this->_errors = array(); + $this->_declareErrorMessages(); + if ($syntaxFile) { + $this->setInputFile($syntaxFile); + } + } + + // }}} + // {{{ _formatError + + /** + * Format error message + * + * @param int $code error code + * @param string $params parameters + * @param string $fileName file name + * @param int $lineNo line number + * @return array + * @access public + */ + function _formatError($code, $params, $fileName, $lineNo) + { + $template = $this->_templates[$code]; + $ret = call_user_func_array('sprintf', array_merge(array($template), $params)); + if ($fileName) { + $ret = '[' . $fileName . '] ' . $ret; + } + if ($lineNo) { + $ret .= ' (line ' . $lineNo . ')'; + } + return $ret; + } + + // }}} + // {{{ declareErrorMessages + + /** + * Set up error message templates + * + * @access private + */ + function _declareErrorMessages() + { + $this->_templates = array ( + TEXT_HIGHLIGHTER_EMPTY_RE => 'Empty regular expression', + TEXT_HIGHLIGHTER_INVALID_RE => 'Invalid regular expression : %s', + TEXT_HIGHLIGHTER_EMPTY_OR_MISSING => 'Empty or missing %s', + TEXT_HIGHLIGHTER_EMPTY => 'Empty %s', + TEXT_HIGHLIGHTER_REGION_REGION => 'Region %s refers undefined region %s', + TEXT_HIGHLIGHTER_REGION_BLOCK => 'Region %s refers undefined block %s', + TEXT_HIGHLIGHTER_BLOCK_REGION => 'Block %s refers undefined region %s', + TEXT_HIGHLIGHTER_KEYWORD_BLOCK => 'Keyword group %s refers undefined block %s', + TEXT_HIGHLIGHTER_KEYWORD_INHERITS => 'Keyword group %s inherits undefined block %s', + TEXT_HIGHLIGHTER_PARSE => '%s', + TEXT_HIGHLIGHTER_FILE_WRITE => 'Error writing file %s', + TEXT_HIGHLIGHTER_FILE_READ => '%s' + ); + } + + // }}} + // {{{ setInputFile + + /** + * Sets the input xml file to be parsed + * + * @param string Filename (full path) + * @return boolean + * @access public + */ + function setInputFile($file) + { + $this->_syntaxFile = $file; + $ret = parent::setInputFile($file); + if (PEAR::isError($ret)) { + $this->_error(TEXT_HIGHLIGHTER_FILE_READ, $ret->message); + return false; + } + return true; + } + + // }}} + // {{{ generate + + /** + * Generates class code + * + * @access public + */ + + function generate() + { + $this->_regions = array(); + $this->_blocks = array(); + $this->_keywords = array(); + $this->language = ''; + $this->_code = ''; + $this->_defClass = 'default'; + $this->_comment = ''; + $this->_inComment = false; + $this->_authors = array(); + $this->_blockOrder = 0; + $this->_errors = array(); + + $ret = $this->parse(); + if (PEAR::isError($ret)) { + $this->_error(TEXT_HIGHLIGHTER_PARSE, $ret->message); + return false; + } + return true; + } + + // }}} + // {{{ getCode + + /** + * Returns generated code as a string. + * + * @return string Generated code + * @access public + */ + + function getCode() + { + return $this->_code; + } + + // }}} + // {{{ saveCode + + /** + * Saves generated class to file. Note that {@link Text_Highlighter::factory()} + * assumes that filename is uppercase (SQL.php, DTD.php, etc), and file + * is located in Text/Highlighter + * + * @param string $filename Name of file to write the code to + * @return boolean true on success, false on failure + * @access public + */ + + function saveCode($filename) + { + $f = @fopen($filename, 'wb'); + if (!$f) { + $this->_error(TEXT_HIGHLIGHTER_FILE_WRITE, array('outfile'=>$filename)); + return false; + } + fwrite ($f, $this->_code); + fclose($f); + return true; + } + + // }}} + // {{{ hasErrors + + /** + * Reports if there were errors + * + * @return boolean + * @access public + */ + + function hasErrors() + { + return count($this->_errors) > 0; + } + + // }}} + // {{{ getErrors + + /** + * Returns errors + * + * @return array + * @access public + */ + + function getErrors() + { + return $this->_errors; + } + + // }}} + // {{{ _sortBlocks + + /** + * Sorts blocks + * + * @access private + */ + + function _sortBlocks($b1, $b2) { + return $b1['order'] - $b2['order']; + } + + // }}} + // {{{ _sortLookFor + /** + * Sort 'look for' list + * @return int + * @param string $b1 + * @param string $b2 + */ + function _sortLookFor($b1, $b2) { + $o1 = isset($this->_blocks[$b1]) ? $this->_blocks[$b1]['order'] : $this->_regions[$b1]['order']; + $o2 = isset($this->_blocks[$b2]) ? $this->_blocks[$b2]['order'] : $this->_regions[$b2]['order']; + return $o1 - $o2; + } + + // }}} + // {{{ _makeRE + + /** + * Adds delimiters and modifiers to regular expression if necessary + * + * @param string $text Original RE + * @return string Final RE + * @access private + */ + function _makeRE($text, $case = false) + { + if (!strlen($text)) { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_RE); + } + if (!strlen($text) || $text{0} != '/') { + $text = '/' . $text . '/'; + } + if (!$case) { + $text .= 'i'; + } + $php_errormsg = ''; + @preg_match($text, ''); + if ($php_errormsg) { + $this->_error(TEXT_HIGHLIGHTER_INVALID_RE, $php_errormsg); + } + preg_match ('#^/(.+)/(.*)$#', $text, $m); + if (@$m[2]) { + $text = '(?' . $m[2] . ')' . $m[1]; + } else { + $text = $m[1]; + } + return $text; + } + + // }}} + // {{{ _exportArray + + /** + * Exports array as PHP code + * + * @param array $array + * @return string Code + * @access private + */ + function _exportArray($array) + { + $array = var_export($array, true); + return trim(preg_replace('~^(\s*)~m',' \1\1',$array)); + } + + // }}} + // {{{ _countSubpatterns + /** + * Find number of capturing suppaterns in regular expression + * @return int + * @param string $re Regular expression (without delimiters) + */ + function _countSubpatterns($re) + { + preg_match_all('/' . $re . '/', '', $m); + return count($m)-1; + } + + // }}} + + /**#@+ + * @access private + * @param resource $xp XML parser resource + * @param string $elem XML element name + * @param array $attribs XML element attributes + */ + + // {{{ xmltag_Default + + /** + * start handler for element + */ + function xmltag_Default($xp, $elem, $attribs) + { + $this->_aliasAttributes($attribs); + if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); + } + $this->_defClass = @$attribs['innerGroup']; + } + + // }}} + // {{{ xmltag_Region + + /** + * start handler for element + */ + function xmltag_Region($xp, $elem, $attribs) + { + $this->_aliasAttributes($attribs); + if (!isset($attribs['name']) || $attribs['name'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region name'); + } + if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); + } + $this->_element = array('name' => $attribs['name']); + $this->_element['line'] = xml_get_current_line_number($this->parser); + if (isset($attribs['case'])) { + $this->_element['case'] = $attribs['case'] == 'yes'; + } else { + $this->_element['case'] = $this->_case; + } + $this->_element['innerGroup'] = $attribs['innerGroup']; + $this->_element['delimGroup'] = isset($attribs['delimGroup']) ? + $attribs['delimGroup'] : + $attribs['innerGroup']; + $this->_element['start'] = $this->_makeRE(@$attribs['start'], $this->_element['case']); + $this->_element['end'] = $this->_makeRE(@$attribs['end'], $this->_element['case']); + $this->_element['contained'] = @$attribs['contained'] == 'yes'; + $this->_element['never-contained'] = @$attribs['never-contained'] == 'yes'; + $this->_element['remember'] = @$attribs['remember'] == 'yes'; + if (isset($attribs['startBOL']) && $attribs['startBOL'] == 'yes') { + $this->_element['startBOL'] = true; + } + if (isset($attribs['endBOL']) && $attribs['endBOL'] == 'yes') { + $this->_element['endBOL'] = true; + } + if (isset($attribs['neverAfter'])) { + $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']); + } + } + + // }}} + // {{{ xmltag_Block + + /** + * start handler for element + */ + function xmltag_Block($xp, $elem, $attribs) + { + $this->_aliasAttributes($attribs); + if (!isset($attribs['name']) || $attribs['name'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'block name'); + } + if (isset($attribs['innerGroup']) && $attribs['innerGroup'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY, 'innerGroup'); + } + $this->_element = array('name' => $attribs['name']); + $this->_element['line'] = xml_get_current_line_number($this->parser); + if (isset($attribs['case'])) { + $this->_element['case'] = $attribs['case'] == 'yes'; + } else { + $this->_element['case'] = $this->_case; + } + if (isset($attribs['innerGroup'])) { + $this->_element['innerGroup'] = @$attribs['innerGroup']; + } + $this->_element['match'] = $this->_makeRE($attribs['match'], $this->_element['case']); + $this->_element['contained'] = @$attribs['contained'] == 'yes'; + $this->_element['multiline'] = @$attribs['multiline'] == 'yes'; + if (isset($attribs['BOL']) && $attribs['BOL'] == 'yes') { + $this->_element['BOL'] = true; + } + if (isset($attribs['neverAfter'])) { + $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']); + } + } + + // }}} + // {{{ cdataHandler + + /** + * Character data handler. Used for comment + */ + function cdataHandler($xp, $cdata) + { + if ($this->_inComment) { + $this->_comment .= $cdata; + } + } + + // }}} + // {{{ xmltag_Comment + + /** + * start handler for element + */ + function xmltag_Comment($xp, $elem, $attribs) + { + $this->_comment = ''; + $this->_inComment = true; + } + + // }}} + // {{{ xmltag_PartGroup + + /** + * start handler for element + */ + function xmltag_PartGroup($xp, $elem, $attribs) + { + $this->_aliasAttributes($attribs); + if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); + } + $this->_element['partClass'][$attribs['index']] = @$attribs['innerGroup']; + } + + // }}} + // {{{ xmltag_PartClass + + /** + * start handler for element + */ + function xmltag_PartClass($xp, $elem, $attribs) + { + $this->xmltag_PartGroup($xp, $elem, $attribs); + } + + // }}} + // {{{ xmltag_Keywords + + /** + * start handler for element + */ + function xmltag_Keywords($xp, $elem, $attribs) + { + $this->_aliasAttributes($attribs); + if (!isset($attribs['name']) || $attribs['name'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'keyword group name'); + } + if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup'); + } + if (!isset($attribs['inherits']) || $attribs['inherits'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'inherits'); + } + $this->_element = array('name'=>@$attribs['name']); + $this->_element['line'] = xml_get_current_line_number($this->parser); + $this->_element['innerGroup'] = @$attribs['innerGroup']; + if (isset($attribs['case'])) { + $this->_element['case'] = $attribs['case'] == 'yes'; + } else { + $this->_element['case'] = $this->_case; + } + $this->_element['inherits'] = @$attribs['inherits']; + if (isset($attribs['otherwise'])) { + $this->_element['otherwise'] = $attribs['otherwise']; + } + if (isset($attribs['ifdef'])) { + $this->_element['ifdef'] = $attribs['ifdef']; + } + if (isset($attribs['ifndef'])) { + $this->_element['ifndef'] = $attribs['ifndef']; + } + } + + // }}} + // {{{ xmltag_Keyword + + /** + * start handler for element + */ + function xmltag_Keyword($xp, $elem, $attribs) + { + if (!isset($attribs['match']) || $attribs['match'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'match'); + } + $keyword = @$attribs['match']; + if (!$this->_element['case']) { + $keyword = strtolower($keyword); + } + $this->_element['match'][$keyword] = true; + } + + // }}} + // {{{ xmltag_Contains + + /** + * start handler for element + */ + function xmltag_Contains($xp, $elem, $attribs) + { + $this->_element['contains-all'] = @$attribs['all'] == 'yes'; + if (isset($attribs['region'])) { + $this->_element['contains']['region'][$attribs['region']] = + xml_get_current_line_number($this->parser); + } + if (isset($attribs['block'])) { + $this->_element['contains']['block'][$attribs['block']] = + xml_get_current_line_number($this->parser); + } + } + + // }}} + // {{{ xmltag_But + + /** + * start handler for element + */ + function xmltag_But($xp, $elem, $attribs) + { + if (isset($attribs['region'])) { + $this->_element['not-contains']['region'][$attribs['region']] = true; + } + if (isset($attribs['block'])) { + $this->_element['not-contains']['block'][$attribs['block']] = true; + } + } + + // }}} + // {{{ xmltag_Onlyin + + /** + * start handler for element + */ + function xmltag_Onlyin($xp, $elem, $attribs) + { + if (!isset($attribs['region']) || $attribs['region'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region'); + } + $this->_element['onlyin'][$attribs['region']] = xml_get_current_line_number($this->parser); + } + + // }}} + // {{{ xmltag_Author + + /** + * start handler for element + */ + function xmltag_Author($xp, $elem, $attribs) + { + if (!isset($attribs['name']) || $attribs['name'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'author name'); + } + $this->_authors[] = array( + 'name' => @$attribs['name'], + 'email' => (string)@$attribs['email'] + ); + } + + // }}} + // {{{ xmltag_Highlight + + /** + * start handler for element + */ + function xmltag_Highlight($xp, $elem, $attribs) + { + if (!isset($attribs['lang']) || $attribs['lang'] === '') { + $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'language name'); + } + $this->_code = ''; + $this->language = strtoupper(@$attribs['lang']); + $this->_case = @$attribs['case'] == 'yes'; + } + + // }}} + + /**#@-*/ + + // {{{ _error + + /** + * Add an error message + * + * @param integer $code Error code + * @param mixed $message Error message or array with error message parameters + * @param integer $lineNo Source code line number + * @access private + */ + function _error($code, $params = array(), $lineNo = 0) + { + if (!$lineNo && !empty($this->parser)) { + $lineNo = xml_get_current_line_number($this->parser); + } + $this->_errors[] = $this->_formatError($code, $params, $this->_syntaxFile, $lineNo); + } + + // }}} + // {{{ _aliasAttributes + + /** + * BC trick + * + * @param array $attrs attributes + */ + function _aliasAttributes(&$attrs) + { + if (isset($attrs['innerClass']) && !isset($attrs['innerGroup'])) { + $attrs['innerGroup'] = $attrs['innerClass']; + } + if (isset($attrs['delimClass']) && !isset($attrs['delimGroup'])) { + $attrs['delimGroup'] = $attrs['delimClass']; + } + if (isset($attrs['partClass']) && !isset($attrs['partGroup'])) { + $attrs['partGroup'] = $attrs['partClass']; + } + } + + // }}} + + /**#@+ + * @access private + * @param resource $xp XML parser resource + * @param string $elem XML element name + */ + + // {{{ xmltag_Comment_ + + /** + * end handler for element + */ + function xmltag_Comment_($xp, $elem) + { + $this->_inComment = false; + } + + // }}} + // {{{ xmltag_Region_ + + /** + * end handler for element + */ + function xmltag_Region_($xp, $elem) + { + $this->_element['type'] = 'region'; + $this->_element['order'] = $this->_blockOrder ++; + $this->_regions[$this->_element['name']] = $this->_element; + } + + // }}} + // {{{ xmltag_Keywords_ + + /** + * end handler for element + */ + function xmltag_Keywords_($xp, $elem) + { + $this->_keywords[$this->_element['name']] = $this->_element; + } + + // }}} + // {{{ xmltag_Block_ + + /** + * end handler for element + */ + function xmltag_Block_($xp, $elem) + { + $this->_element['type'] = 'block'; + $this->_element['order'] = $this->_blockOrder ++; + $this->_blocks[$this->_element['name']] = $this->_element; + } + + // }}} + // {{{ xmltag_Highlight_ + + /** + * end handler for element + */ + function xmltag_Highlight_($xp, $elem) + { + $conditions = array(); + $toplevel = array(); + foreach ($this->_blocks as $i => $current) { + if (!$current['contained'] && !isset($current['onlyin'])) { + $toplevel[] = $i; + } + foreach ((array)@$current['onlyin'] as $region => $lineNo) { + if (!isset($this->_regions[$region])) { + $this->_error(TEXT_HIGHLIGHTER_BLOCK_REGION, + array( + 'block' => $current['name'], + 'region' => $region + )); + } + } + } + foreach ($this->_regions as $i=>$current) { + if (!$current['contained'] && !isset($current['onlyin'])) { + $toplevel[] = $i; + } + foreach ((array)@$current['contains']['region'] as $region => $lineNo) { + if (!isset($this->_regions[$region])) { + $this->_error(TEXT_HIGHLIGHTER_REGION_REGION, + array( + 'region1' => $current['name'], + 'region2' => $region + )); + } + } + foreach ((array)@$current['contains']['block'] as $region => $lineNo) { + if (!isset($this->_blocks[$region])) { + $this->_error(TEXT_HIGHLIGHTER_REGION_BLOCK, + array( + 'block' => $current['name'], + 'region' => $region + )); + } + } + foreach ((array)@$current['onlyin'] as $region => $lineNo) { + if (!isset($this->_regions[$region])) { + $this->_error(TEXT_HIGHLIGHTER_REGION_REGION, + array( + 'region1' => $current['name'], + 'region2' => $region + )); + } + } + foreach ($this->_regions as $j => $region) { + if (isset($region['onlyin'])) { + $suits = isset($region['onlyin'][$current['name']]); + } elseif (isset($current['not-contains']['region'][$region['name']])) { + $suits = false; + } elseif (isset($current['contains']['region'][$region['name']])) { + $suits = true; + } else { + $suits = @$current['contains-all'] && @!$region['never-contained']; + } + if ($suits) { + $this->_regions[$i]['lookfor'][] = $j; + } + } + foreach ($this->_blocks as $j=>$region) { + if (isset($region['onlyin'])) { + $suits = isset($region['onlyin'][$current['name']]); + } elseif (isset($current['not-contains']['block'][$region['name']])) { + $suits = false; + } elseif (isset($current['contains']['block'][$region['name']])) { + $suits = true; + } else { + $suits = @$current['contains-all'] && @!$region['never-contained']; + } + if ($suits) { + $this->_regions[$i]['lookfor'][] = $j; + } + } + } + foreach ($this->_blocks as $i=>$current) { + unset ($this->_blocks[$i]['never-contained']); + unset ($this->_blocks[$i]['contained']); + unset ($this->_blocks[$i]['contains-all']); + unset ($this->_blocks[$i]['contains']); + unset ($this->_blocks[$i]['onlyin']); + unset ($this->_blocks[$i]['line']); + } + + foreach ($this->_regions as $i=>$current) { + unset ($this->_regions[$i]['never-contained']); + unset ($this->_regions[$i]['contained']); + unset ($this->_regions[$i]['contains-all']); + unset ($this->_regions[$i]['contains']); + unset ($this->_regions[$i]['onlyin']); + unset ($this->_regions[$i]['line']); + } + + foreach ($this->_keywords as $name => $keyword) { + if (isset($keyword['ifdef'])) { + $conditions[$keyword['ifdef']][] = array($name, true); + } + if (isset($keyword['ifndef'])) { + $conditions[$keyword['ifndef']][] = array($name, false); + } + unset($this->_keywords[$name]['line']); + if (!isset($this->_blocks[$keyword['inherits']])) { + $this->_error(TEXT_HIGHLIGHTER_KEYWORD_INHERITS, + array( + 'keyword' => $keyword['name'], + 'block' => $keyword['inherits'] + )); + } + if (isset($keyword['otherwise']) && !isset($this->_blocks[$keyword['otherwise']]) ) { + $this->_error(TEXT_HIGHLIGHTER_KEYWORD_BLOCK, + array( + 'keyword' => $keyword['name'], + 'block' => $keyword['inherits'] + )); + } + } + + $syntax=array( + 'keywords' => $this->_keywords, + 'blocks' => array_merge($this->_blocks, $this->_regions), + 'toplevel' => $toplevel, + ); + uasort($syntax['blocks'], array(&$this, '_sortBlocks')); + foreach ($syntax['blocks'] as $name => $block) { + if ($block['type'] == 'block') { + continue; + } + if (is_array(@$syntax['blocks'][$name]['lookfor'])) { + usort($syntax['blocks'][$name]['lookfor'], array(&$this, '_sortLookFor')); + } + } + usort($syntax['toplevel'], array(&$this, '_sortLookFor')); + $syntax['case'] = $this->_case; + $this->_code = <<language} syntax highlighting +CODE; + + if ($this->_comment) { + $comment = preg_replace('~^~m',' * ',$this->_comment); + $this->_code .= "\n * \n" . $comment; + } + + $this->_code .= <<_syntaxFile + +CODE; + + foreach ($this->_authors as $author) { + $this->_code .= ' * @author ' . $author['name']; + if ($author['email']) { + $this->_code .= ' <' . $author['email'] . '>'; + } + $this->_code .= "\n"; + } + + $this->_code .= <<language} syntax highlighting + * + +CODE; + foreach ($this->_authors as $author) { + $this->_code .= ' * @author ' . $author['name']; + if ($author['email']) { + $this->_code .= ' <' . $author['email']. '>'; + } + $this->_code .= "\n"; + } + + + $this->_code .= <<language} extends Text_Highlighter +{ + +CODE; + $this->_code .= 'var $_language = \'' . strtolower($this->language) . "';\n\n"; + $array = var_export($syntax, true); + $array = trim(preg_replace('~^(\s*)~m',' \1\1',$array)); + // \$this->_syntax = $array; + $this->_code .= <<_code .= <<_options = \$options; +CODE; + $states = array(); + $i = 0; + foreach ($syntax['blocks'] as $name => $block) { + if ($block['type'] == 'region') { + $states[$name] = $i++; + } + } + $regs = array(); + $counts = array(); + $delim = array(); + $inner = array(); + $end = array(); + $stat = array(); + $keywords = array(); + $parts = array(); + $kwmap = array(); + $subst = array(); + $re = array(); + $ce = array(); + $rd = array(); + $in = array(); + $st = array(); + $kw = array(); + $sb = array(); + foreach ($syntax['toplevel'] as $name) { + $block = $syntax['blocks'][$name]; + if ($block['type'] == 'block') { + $kwm = array(); + $re[] = '(' . $block['match'] . ')'; + $ce[] = $this->_countSubpatterns($block['match']); + $rd[] = ''; + $sb[] = false;; + $st[] = -1; + foreach ($syntax['keywords'] as $kwname => $kwgroup) { + if ($kwgroup['inherits'] != $name) { + continue; + } + $gre = implode('|', array_keys($kwgroup['match'])); + if (!$kwgroup['case']) { + $gre = '(?i)' . $gre; + } + $kwm[$kwname][] = $gre; + $kwmap[$kwname] = $kwgroup['innerGroup']; + } + foreach ($kwm as $g => $ma) { + $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/'; + } + $kw[] = $kwm; + } else { + $kw[] = -1; + $re[] = '(' . $block['start'] . ')'; + $ce[] = $this->_countSubpatterns($block['start']); + $rd[] = $block['delimGroup']; + $st[] = $states[$name]; + $sb[] = $block['remember']; + } + $in[] = $block['innerGroup']; + } + $re = implode('|', $re); + $regs[-1] = '/' . $re . '/'; + $counts[-1] = $ce; + $delim[-1] = $rd; + $inner[-1] = $in; + $stat[-1] = $st; + $keywords[-1] = $kw; + $subst[-1] = $sb; + + foreach ($syntax['blocks'] as $ablock) { + if ($ablock['type'] != 'region') { + continue; + } + $end[] = '/' . $ablock['end'] . '/'; + $re = array(); + $ce = array(); + $rd = array(); + $in = array(); + $st = array(); + $kw = array(); + $pc = array(); + $sb = array(); + foreach ((array)@$ablock['lookfor'] as $name) { + $block = $syntax['blocks'][$name]; + if (isset($block['partClass'])) { + $pc[] = $block['partClass']; + } else { + $pc[] = null; + } + if ($block['type'] == 'block') { + $kwm = array();; + $re[] = '(' . $block['match'] . ')'; + $ce[] = $this->_countSubpatterns($block['match']); + $rd[] = ''; + $sb[] = false; + $st[] = -1; + foreach ($syntax['keywords'] as $kwname => $kwgroup) { + if ($kwgroup['inherits'] != $name) { + continue; + } + $gre = implode('|', array_keys($kwgroup['match'])); + if (!$kwgroup['case']) { + $gre = '(?i)' . $gre; + } + $kwm[$kwname][] = $gre; + $kwmap[$kwname] = $kwgroup['innerGroup']; + } + foreach ($kwm as $g => $ma) { + $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/'; + } + $kw[] = $kwm; + } else { + $sb[] = $block['remember']; + $kw[] = -1; + $re[] = '(' . $block['start'] . ')'; + $ce[] = $this->_countSubpatterns($block['start']); + $rd[] = $block['delimGroup']; + $st[] = $states[$name]; + } + $in[] = $block['innerGroup']; + } + $re = implode('|', $re); + $regs[] = '/' . $re . '/'; + $counts[] = $ce; + $delim[] = $rd; + $inner[] = $in; + $stat[] = $st; + $keywords[] = $kw; + $parts[] = $pc; + $subst[] = $sb; + } + + + $this->_code .= "\n \$this->_regs = " . $this->_exportArray($regs); + $this->_code .= ";\n \$this->_counts = " .$this->_exportArray($counts); + $this->_code .= ";\n \$this->_delim = " .$this->_exportArray($delim); + $this->_code .= ";\n \$this->_inner = " .$this->_exportArray($inner); + $this->_code .= ";\n \$this->_end = " .$this->_exportArray($end); + $this->_code .= ";\n \$this->_states = " .$this->_exportArray($stat); + $this->_code .= ";\n \$this->_keywords = " .$this->_exportArray($keywords); + $this->_code .= ";\n \$this->_parts = " .$this->_exportArray($parts); + $this->_code .= ";\n \$this->_subst = " .$this->_exportArray($subst); + $this->_code .= ";\n \$this->_conditions = " .$this->_exportArray($conditions); + $this->_code .= ";\n \$this->_kwmap = " .$this->_exportArray($kwmap); + $this->_code .= ";\n \$this->_defClass = '" .$this->_defClass . '\''; + $this->_code .= <<_checkDefines(); + } + +} +CODE; +} + +// }}} +} + + +/* +* Local variables: +* tab-width: 4 +* c-basic-offset: 4 +* c-hanging-comment-ender-p: nil +* End: +*/ + +?> -- cgit v1.2.3