Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • Net
  • None
  • PHP
  • system
    • base
    • caching
      • dependencies
    • collections
    • console
    • db
      • ar
      • schema
        • cubrid
        • mssql
        • mysql
        • oci
        • pgsql
        • sqlite
    • i18n
      • gettext
    • logging
    • test
    • utils
    • validators
    • web
      • actions
      • auth
      • filters
      • form
      • helpers
      • renderers
      • services
      • widgets
        • captcha
        • pagers
  • Text
    • Highlighter
  • zii
    • behaviors
    • widgets
      • grid
      • jui

Classes

  • Text_Highlighter
  • Text_Highlighter_ABAP
  • Text_Highlighter_CPP
  • Text_Highlighter_CSS
  • Text_Highlighter_DIFF
  • Text_Highlighter_DTD
  • Text_Highlighter_Generator
  • Text_Highlighter_HTML
  • Text_Highlighter_JAVA
  • Text_Highlighter_JAVASCRIPT
  • Text_Highlighter_MYSQL
  • Text_Highlighter_PERL
  • Text_Highlighter_PHP
  • Text_Highlighter_PYTHON
  • Text_Highlighter_Renderer
  • Text_Highlighter_Renderer_Array
  • Text_Highlighter_Renderer_BB
  • Text_Highlighter_Renderer_Console
  • Text_Highlighter_Renderer_Html
  • Text_Highlighter_Renderer_HtmlTags
  • Text_Highlighter_Renderer_JSON
  • Text_Highlighter_Renderer_XML
  • Text_Highlighter_RUBY
  • Text_Highlighter_SH
  • Text_Highlighter_SQL
  • Text_Highlighter_VBSCRIPT
  • Text_Highlighter_XML
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   3: /**
   4: * Syntax highlighter class generator
   5: *
   6: * To simplify the process of creating new syntax highlighters
   7: * for different languages, {@link Text_Highlighter_Generator} class is
   8: * provided. It takes highlighting rules from XML file and generates
   9: * a code of a class inherited from {@link Text_Highlighter}.
  10: *
  11: * PHP versions 4 and 5
  12: *
  13: * LICENSE: This source file is subject to version 3.0 of the PHP license
  14: * that is available through the world-wide-web at the following URI:
  15: * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  16: * the PHP License and are unable to obtain it through the web, please
  17: * send a note to license@php.net so we can mail you a copy immediately.
  18: *
  19: * @category   Text
  20: * @package    Text_Highlighter
  21: * @author     Andrey Demenev <demenev@gmail.com>
  22: * @copyright  2004-2006 Andrey Demenev
  23: * @license    http://www.php.net/license/3_0.txt  PHP License
  24: * @version    CVS: $Id: Generator.php,v 1.1 2007/06/03 02:36:35 ssttoo Exp $
  25: * @link       http://pear.php.net/package/Text_Highlighter
  26: */
  27: 
  28: // {{{ error codes
  29: 
  30: define ('TEXT_HIGHLIGHTER_EMPTY_RE',          1);
  31: define ('TEXT_HIGHLIGHTER_INVALID_RE',        2);
  32: define ('TEXT_HIGHLIGHTER_EMPTY_OR_MISSING',  3);
  33: define ('TEXT_HIGHLIGHTER_EMPTY',             4);
  34: define ('TEXT_HIGHLIGHTER_REGION_REGION',     5);
  35: define ('TEXT_HIGHLIGHTER_REGION_BLOCK',      6);
  36: define ('TEXT_HIGHLIGHTER_BLOCK_REGION',      7);
  37: define ('TEXT_HIGHLIGHTER_KEYWORD_BLOCK',     8);
  38: define ('TEXT_HIGHLIGHTER_KEYWORD_INHERITS',  9);
  39: define ('TEXT_HIGHLIGHTER_PARSE',            10);
  40: define ('TEXT_HIGHLIGHTER_FILE_WRITE',       11);
  41: define ('TEXT_HIGHLIGHTER_FILE_READ',        12);
  42: // }}}
  43: 
  44: /**
  45: * Syntax highliter class generator class
  46: *
  47: * This class is used to generate PHP classes
  48: * from XML files with highlighting rules
  49: *
  50: * Usage example
  51: * <code>
  52: *require_once 'Text/Highlighter/Generator.php';
  53: *$generator =& new Text_Highlighter_Generator('php.xml');
  54: *$generator->generate();
  55: *$generator->saveCode('PHP.php');
  56: * </code>
  57: *
  58: * A command line script <b>generate</b> is provided for
  59: * class generation (installs in scripts/Text/Highlighter).
  60: *
  61: * @author     Andrey Demenev <demenev@gmail.com>
  62: * @copyright  2004-2006 Andrey Demenev
  63: * @license    http://www.php.net/license/3_0.txt  PHP License
  64: * @version    Release: 0.7.1
  65: * @link       http://pear.php.net/package/Text_Highlighter
  66: */
  67: 
  68: class Text_Highlighter_Generator extends  XML_Parser
  69: {
  70:     // {{{ properties
  71:     /**
  72:     * Whether to do case folding.
  73:     * We have to declare it here, because XML_Parser
  74:     * sets case folding in constructor
  75:     *
  76:     * @var  boolean
  77:     */
  78:     var $folding = false;
  79: 
  80:     /**
  81:     * Holds name of file with highlighting rules
  82:     *
  83:     * @var string
  84:     * @access private
  85:     */
  86:     var $_syntaxFile;
  87: 
  88:     /**
  89:     * Current element being processed
  90:     *
  91:     * @var array
  92:     * @access private
  93:     */
  94:     var $_element;
  95: 
  96:     /**
  97:     * List of regions
  98:     *
  99:     * @var array
 100:     * @access private
 101:     */
 102:     var $_regions = array();
 103: 
 104:     /**
 105:     * List of blocks
 106:     *
 107:     * @var array
 108:     * @access private
 109:     */
 110:     var $_blocks = array();
 111: 
 112:     /**
 113:     * List of keyword groups
 114:     *
 115:     * @var array
 116:     * @access private
 117:     */
 118:     var $_keywords = array();
 119: 
 120:     /**
 121:     * List of authors
 122:     *
 123:     * @var array
 124:     * @access private
 125:     */
 126:     var $_authors = array();
 127: 
 128:     /**
 129:     * Name of language
 130:     *
 131:     * @var string
 132:     * @access public
 133:     */
 134:     var $language = '';
 135: 
 136:     /**
 137:     * Generated code
 138:     *
 139:     * @var string
 140:     * @access private
 141:     */
 142:     var $_code = '';
 143: 
 144:     /**
 145:     * Default class
 146:     *
 147:     * @var string
 148:     * @access private
 149:     */
 150:     var $_defClass = 'default';
 151: 
 152:     /**
 153:     * Comment
 154:     *
 155:     * @var string
 156:     * @access private
 157:     */
 158:     var $_comment = '';
 159: 
 160:     /**
 161:     * Flag for comment processing
 162:     *
 163:     * @var boolean
 164:     * @access private
 165:     */
 166:     var $_inComment = false;
 167: 
 168:     /**
 169:     * Sorting order of current block/region
 170:     *
 171:     * @var integer
 172:     * @access private
 173:     */
 174:     var $_blockOrder = 0;
 175: 
 176:     /**
 177:     * Generation errors
 178:     *
 179:     * @var array
 180:     * @access private
 181:     */
 182:     var $_errors;
 183: 
 184:     // }}}
 185:     // {{{ constructor
 186: 
 187:     /**
 188:     * Constructor
 189:     *
 190:     * @param string $syntaxFile Name of XML file
 191:     * with syntax highlighting rules
 192:     *
 193:     * @access public
 194:     */
 195: 
 196:     function __construct($syntaxFile = '')
 197:     {
 198:         XML_Parser::XML_Parser(null, 'func');
 199:         $this->_errors = array();
 200:         $this->_declareErrorMessages();
 201:         if ($syntaxFile) {
 202:             $this->setInputFile($syntaxFile);
 203:         }
 204:     }
 205: 
 206:     // }}}
 207:     // {{{ _formatError
 208: 
 209:     /**
 210:     * Format error message
 211:     *
 212:     * @param integer $code error code
 213:     * @param string $params parameters
 214:     * @param string $fileName file name
 215:     * @param integer $lineNo line number
 216:     * @return  array
 217:     * @access  public
 218:     */
 219:     function _formatError($code, $params, $fileName, $lineNo)
 220:     {
 221:         $template = $this->_templates[$code];
 222:         $ret = call_user_func_array('sprintf', array_merge(array($template), $params));
 223:         if ($fileName) {
 224:             $ret = '[' . $fileName . '] ' . $ret;
 225:         }
 226:         if ($lineNo) {
 227:             $ret .= ' (line ' . $lineNo . ')';
 228:         }
 229:         return $ret;
 230:     }
 231: 
 232:     // }}}
 233:     // {{{ declareErrorMessages
 234: 
 235:     /**
 236:     * Set up error message templates
 237:     *
 238:     * @access  private
 239:     */
 240:     function _declareErrorMessages()
 241:     {
 242:         $this->_templates = array (
 243:         TEXT_HIGHLIGHTER_EMPTY_RE => 'Empty regular expression',
 244:         TEXT_HIGHLIGHTER_INVALID_RE => 'Invalid regular expression : %s',
 245:         TEXT_HIGHLIGHTER_EMPTY_OR_MISSING => 'Empty or missing %s',
 246:         TEXT_HIGHLIGHTER_EMPTY  => 'Empty %s',
 247:         TEXT_HIGHLIGHTER_REGION_REGION => 'Region %s refers undefined region %s',
 248:         TEXT_HIGHLIGHTER_REGION_BLOCK => 'Region %s refers undefined block %s',
 249:         TEXT_HIGHLIGHTER_BLOCK_REGION => 'Block %s refers undefined region %s',
 250:         TEXT_HIGHLIGHTER_KEYWORD_BLOCK => 'Keyword group %s refers undefined block %s',
 251:         TEXT_HIGHLIGHTER_KEYWORD_INHERITS => 'Keyword group %s inherits undefined block %s',
 252:         TEXT_HIGHLIGHTER_PARSE => '%s',
 253:         TEXT_HIGHLIGHTER_FILE_WRITE => 'Error writing file %s',
 254:         TEXT_HIGHLIGHTER_FILE_READ => '%s'
 255:         );
 256:     }
 257: 
 258:     // }}}
 259:     // {{{ setInputFile
 260: 
 261:     /**
 262:     * Sets the input xml file to be parsed
 263:     *
 264:     * @param    string      Filename (full path)
 265:     * @return   boolean
 266:     * @access   public
 267:     */
 268:     function setInputFile($file)
 269:     {
 270:         $this->_syntaxFile = $file;
 271:         $ret = parent::setInputFile($file);
 272:         if (PEAR::isError($ret)) {
 273:             $this->_error(TEXT_HIGHLIGHTER_FILE_READ, $ret->message);
 274:             return false;
 275:         }
 276:         return true;
 277:     }
 278: 
 279:     // }}}
 280:     // {{{ generate
 281: 
 282:     /**
 283:     * Generates class code
 284:     *
 285:     * @access public
 286:     */
 287: 
 288:     function generate()
 289:     {
 290:         $this->_regions    = array();
 291:         $this->_blocks     = array();
 292:         $this->_keywords   = array();
 293:         $this->language    = '';
 294:         $this->_code       = '';
 295:         $this->_defClass   = 'default';
 296:         $this->_comment    = '';
 297:         $this->_inComment  = false;
 298:         $this->_authors    = array();
 299:         $this->_blockOrder = 0;
 300:         $this->_errors   = array();
 301: 
 302:         $ret = $this->parse();
 303:         if (PEAR::isError($ret)) {
 304:             $this->_error(TEXT_HIGHLIGHTER_PARSE, $ret->message);
 305:             return false;
 306:         }
 307:         return true;
 308:     }
 309: 
 310:     // }}}
 311:     // {{{ getCode
 312: 
 313:     /**
 314:     * Returns generated code as a string.
 315:     *
 316:     * @return string Generated code
 317:     * @access public
 318:     */
 319: 
 320:     function getCode()
 321:     {
 322:         return $this->_code;
 323:     }
 324: 
 325:     // }}}
 326:     // {{{ saveCode
 327: 
 328:     /**
 329:     * Saves generated class to file. Note that {@link Text_Highlighter::factory()}
 330:     * assumes that filename is uppercase (SQL.php, DTD.php, etc), and file
 331:     * is located in Text/Highlighter
 332:     *
 333:     * @param string $filename Name of file to write the code to
 334:     * @return boolean true on success, false on failure
 335:     * @access public
 336:     */
 337: 
 338:     function saveCode($filename)
 339:     {
 340:         $f = @fopen($filename, 'wb');
 341:         if (!$f) {
 342:             $this->_error(TEXT_HIGHLIGHTER_FILE_WRITE, array('outfile'=>$filename));
 343:             return false;
 344:         }
 345:         fwrite ($f, $this->_code);
 346:         fclose($f);
 347:         return true;
 348:     }
 349: 
 350:     // }}}
 351:     // {{{ hasErrors
 352: 
 353:     /**
 354:     * Reports if there were errors
 355:     *
 356:     * @return boolean
 357:     * @access public
 358:     */
 359: 
 360:     function hasErrors()
 361:     {
 362:         return count($this->_errors) > 0;
 363:     }
 364: 
 365:     // }}}
 366:     // {{{ getErrors
 367: 
 368:     /**
 369:     * Returns errors
 370:     *
 371:     * @return array
 372:     * @access public
 373:     */
 374: 
 375:     function getErrors()
 376:     {
 377:         return $this->_errors;
 378:     }
 379: 
 380:     // }}}
 381:     // {{{ _sortBlocks
 382: 
 383:     /**
 384:     * Sorts blocks
 385:     *
 386:     * @access private
 387:     */
 388: 
 389:     function _sortBlocks($b1, $b2) {
 390:         return $b1['order'] - $b2['order'];
 391:     }
 392: 
 393:     // }}}
 394:     // {{{ _sortLookFor
 395:     /**
 396:     * Sort 'look for' list
 397:     * @return int
 398:     * @param string $b1
 399:     * @param string $b2
 400:     */
 401:     function _sortLookFor($b1, $b2) {
 402:         $o1 = isset($this->_blocks[$b1]) ? $this->_blocks[$b1]['order'] : $this->_regions[$b1]['order'];
 403:         $o2 = isset($this->_blocks[$b2]) ? $this->_blocks[$b2]['order'] : $this->_regions[$b2]['order'];
 404:         return $o1 - $o2;
 405:     }
 406: 
 407:     // }}}
 408:     // {{{ _makeRE
 409: 
 410:     /**
 411:     * Adds delimiters and modifiers to regular expression if necessary
 412:     *
 413:     * @param string $text Original RE
 414:     * @return string Final RE
 415:     * @access private
 416:     */
 417:     function _makeRE($text, $case = false)
 418:     {
 419:         if (!strlen($text)) {
 420:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_RE);
 421:         }
 422:         if (!strlen($text) || $text{0} != '/') {
 423:             $text = '/' . $text . '/';
 424:         }
 425:         if (!$case) {
 426:             $text .= 'i';
 427:         }
 428:         $php_errormsg = '';
 429:         @preg_match($text, '');
 430:         if ($php_errormsg) {
 431:             $this->_error(TEXT_HIGHLIGHTER_INVALID_RE, $php_errormsg);
 432:         }
 433:         preg_match ('#^/(.+)/(.*)$#', $text, $m);
 434:         if (@$m[2]) {
 435:             $text = '(?' . $m[2] . ')' . $m[1];
 436:         } else {
 437:             $text = $m[1];
 438:         }
 439:         return $text;
 440:     }
 441: 
 442:     // }}}
 443:     // {{{ _exportArray
 444: 
 445:     /**
 446:     * Exports array as PHP code
 447:     *
 448:     * @param array $array
 449:     * @return string Code
 450:     * @access private
 451:     */
 452:     function _exportArray($array)
 453:     {
 454:         $array = var_export($array, true);
 455:         return trim(preg_replace('~^(\s*)~m','        \1\1',$array));
 456:     }
 457: 
 458:     // }}}
 459:     // {{{ _countSubpatterns
 460:     /**
 461:     * Find number of capturing suppaterns in regular expression
 462:     * @return int
 463:     * @param string $re Regular expression (without delimiters)
 464:     */
 465:     function _countSubpatterns($re)
 466:     {
 467:         preg_match_all('/' . $re . '/', '', $m);
 468:         return count($m)-1;
 469:     }
 470: 
 471:     // }}}
 472: 
 473:     /**#@+
 474:     * @access private
 475:     * @param resource $xp      XML parser resource
 476:     * @param string   $elem    XML element name
 477:     * @param array    $attribs XML element attributes
 478:     */
 479: 
 480:     // {{{ xmltag_Default
 481: 
 482:     /**
 483:     * start handler for <default> element
 484:     */
 485:     function xmltag_Default($xp, $elem, $attribs)
 486:     {
 487:         $this->_aliasAttributes($attribs);
 488:         if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
 489:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
 490:         }
 491:         $this->_defClass = @$attribs['innerGroup'];
 492:     }
 493: 
 494:     // }}}
 495:     // {{{ xmltag_Region
 496: 
 497:     /**
 498:     * start handler for <region> element
 499:     */
 500:     function xmltag_Region($xp, $elem, $attribs)
 501:     {
 502:         $this->_aliasAttributes($attribs);
 503:         if (!isset($attribs['name']) || $attribs['name'] === '') {
 504:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region name');
 505:         }
 506:         if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
 507:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
 508:         }
 509:         $this->_element = array('name' => $attribs['name']);
 510:         $this->_element['line'] = xml_get_current_line_number($this->parser);
 511:         if (isset($attribs['case'])) {
 512:             $this->_element['case'] = $attribs['case'] == 'yes';
 513:         } else {
 514:             $this->_element['case'] = $this->_case;
 515:         }
 516:         $this->_element['innerGroup'] = $attribs['innerGroup'];
 517:         $this->_element['delimGroup'] = isset($attribs['delimGroup']) ?
 518:         $attribs['delimGroup'] :
 519:         $attribs['innerGroup'];
 520:         $this->_element['start'] = $this->_makeRE(@$attribs['start'], $this->_element['case']);
 521:         $this->_element['end'] = $this->_makeRE(@$attribs['end'], $this->_element['case']);
 522:         $this->_element['contained'] = @$attribs['contained'] == 'yes';
 523:         $this->_element['never-contained'] = @$attribs['never-contained'] == 'yes';
 524:         $this->_element['remember'] = @$attribs['remember'] == 'yes';
 525:         if (isset($attribs['startBOL']) && $attribs['startBOL'] == 'yes') {
 526:             $this->_element['startBOL'] = true;
 527:         }
 528:         if (isset($attribs['endBOL']) && $attribs['endBOL'] == 'yes') {
 529:             $this->_element['endBOL'] = true;
 530:         }
 531:         if (isset($attribs['neverAfter'])) {
 532:             $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']);
 533:         }
 534:     }
 535: 
 536:     // }}}
 537:     // {{{ xmltag_Block
 538: 
 539:     /**
 540:     * start handler for <block> element
 541:     */
 542:     function xmltag_Block($xp, $elem, $attribs)
 543:     {
 544:         $this->_aliasAttributes($attribs);
 545:         if (!isset($attribs['name']) || $attribs['name'] === '') {
 546:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'block name');
 547:         }
 548:         if (isset($attribs['innerGroup']) && $attribs['innerGroup'] === '') {
 549:             $this->_error(TEXT_HIGHLIGHTER_EMPTY, 'innerGroup');
 550:         }
 551:         $this->_element = array('name' => $attribs['name']);
 552:         $this->_element['line'] = xml_get_current_line_number($this->parser);
 553:         if (isset($attribs['case'])) {
 554:             $this->_element['case'] = $attribs['case'] == 'yes';
 555:         } else {
 556:             $this->_element['case'] = $this->_case;
 557:         }
 558:         if (isset($attribs['innerGroup'])) {
 559:             $this->_element['innerGroup'] = @$attribs['innerGroup'];
 560:         }
 561:         $this->_element['match'] = $this->_makeRE($attribs['match'], $this->_element['case']);
 562:         $this->_element['contained'] = @$attribs['contained'] == 'yes';
 563:         $this->_element['multiline'] = @$attribs['multiline'] == 'yes';
 564:         if (isset($attribs['BOL']) && $attribs['BOL'] == 'yes') {
 565:             $this->_element['BOL'] = true;
 566:         }
 567:         if (isset($attribs['neverAfter'])) {
 568:             $this->_element['neverafter'] = $this->_makeRE($attribs['neverAfter']);
 569:         }
 570:     }
 571: 
 572:     // }}}
 573:     // {{{ cdataHandler
 574: 
 575:     /**
 576:     * Character data handler. Used for comment
 577:     */
 578:     function cdataHandler($xp, $cdata)
 579:     {
 580:         if ($this->_inComment) {
 581:             $this->_comment .= $cdata;
 582:         }
 583:     }
 584: 
 585:     // }}}
 586:     // {{{ xmltag_Comment
 587: 
 588:     /**
 589:     * start handler for <comment> element
 590:     */
 591:     function xmltag_Comment($xp, $elem, $attribs)
 592:     {
 593:         $this->_comment = '';
 594:         $this->_inComment = true;
 595:     }
 596: 
 597:     // }}}
 598:     // {{{ xmltag_PartGroup
 599: 
 600:     /**
 601:     * start handler for <partgroup> element
 602:     */
 603:     function xmltag_PartGroup($xp, $elem, $attribs)
 604:     {
 605:         $this->_aliasAttributes($attribs);
 606:         if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
 607:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
 608:         }
 609:         $this->_element['partClass'][$attribs['index']] = @$attribs['innerGroup'];
 610:     }
 611: 
 612:     // }}}
 613:     // {{{ xmltag_PartClass
 614: 
 615:     /**
 616:     * start handler for <partclass> element
 617:     */
 618:     function xmltag_PartClass($xp, $elem, $attribs)
 619:     {
 620:         $this->xmltag_PartGroup($xp, $elem, $attribs);
 621:     }
 622: 
 623:     // }}}
 624:     // {{{ xmltag_Keywords
 625: 
 626:     /**
 627:     * start handler for <keywords> element
 628:     */
 629:     function xmltag_Keywords($xp, $elem, $attribs)
 630:     {
 631:         $this->_aliasAttributes($attribs);
 632:         if (!isset($attribs['name']) || $attribs['name'] === '') {
 633:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'keyword group name');
 634:         }
 635:         if (!isset($attribs['innerGroup']) || $attribs['innerGroup'] === '') {
 636:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'innerGroup');
 637:         }
 638:         if (!isset($attribs['inherits']) || $attribs['inherits'] === '') {
 639:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'inherits');
 640:         }
 641:         $this->_element = array('name'=>@$attribs['name']);
 642:         $this->_element['line'] = xml_get_current_line_number($this->parser);
 643:         $this->_element['innerGroup'] = @$attribs['innerGroup'];
 644:         if (isset($attribs['case'])) {
 645:             $this->_element['case'] = $attribs['case'] == 'yes';
 646:         } else {
 647:             $this->_element['case'] = $this->_case;
 648:         }
 649:         $this->_element['inherits'] = @$attribs['inherits'];
 650:         if (isset($attribs['otherwise'])) {
 651:             $this->_element['otherwise'] = $attribs['otherwise'];
 652:         }
 653:         if (isset($attribs['ifdef'])) {
 654:             $this->_element['ifdef'] = $attribs['ifdef'];
 655:         }
 656:         if (isset($attribs['ifndef'])) {
 657:             $this->_element['ifndef'] = $attribs['ifndef'];
 658:         }
 659:     }
 660: 
 661:     // }}}
 662:     // {{{ xmltag_Keyword
 663: 
 664:     /**
 665:     * start handler for <keyword> element
 666:     */
 667:     function xmltag_Keyword($xp, $elem, $attribs)
 668:     {
 669:         if (!isset($attribs['match']) || $attribs['match'] === '') {
 670:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'match');
 671:         }
 672:         $keyword = @$attribs['match'];
 673:         if (!$this->_element['case']) {
 674:             $keyword = strtolower($keyword);
 675:         }
 676:         $this->_element['match'][$keyword] = true;
 677:     }
 678: 
 679:     // }}}
 680:     // {{{ xmltag_Contains
 681: 
 682:     /**
 683:     * start handler for <contains> element
 684:     */
 685:     function xmltag_Contains($xp, $elem, $attribs)
 686:     {
 687:         $this->_element['contains-all'] = @$attribs['all'] == 'yes';
 688:         if (isset($attribs['region'])) {
 689:             $this->_element['contains']['region'][$attribs['region']] =
 690:             xml_get_current_line_number($this->parser);
 691:         }
 692:         if (isset($attribs['block'])) {
 693:             $this->_element['contains']['block'][$attribs['block']] =
 694:             xml_get_current_line_number($this->parser);
 695:         }
 696:     }
 697: 
 698:     // }}}
 699:     // {{{ xmltag_But
 700: 
 701:     /**
 702:     * start handler for <but> element
 703:     */
 704:     function xmltag_But($xp, $elem, $attribs)
 705:     {
 706:         if (isset($attribs['region'])) {
 707:             $this->_element['not-contains']['region'][$attribs['region']] = true;
 708:         }
 709:         if (isset($attribs['block'])) {
 710:             $this->_element['not-contains']['block'][$attribs['block']] = true;
 711:         }
 712:     }
 713: 
 714:     // }}}
 715:     // {{{ xmltag_Onlyin
 716: 
 717:     /**
 718:     * start handler for <onlyin> element
 719:     */
 720:     function xmltag_Onlyin($xp, $elem, $attribs)
 721:     {
 722:         if (!isset($attribs['region']) || $attribs['region'] === '') {
 723:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'region');
 724:         }
 725:         $this->_element['onlyin'][$attribs['region']] = xml_get_current_line_number($this->parser);
 726:     }
 727: 
 728:     // }}}
 729:     // {{{ xmltag_Author
 730: 
 731:     /**
 732:     * start handler for <author> element
 733:     */
 734:     function xmltag_Author($xp, $elem, $attribs)
 735:     {
 736:         if (!isset($attribs['name']) || $attribs['name'] === '') {
 737:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'author name');
 738:         }
 739:         $this->_authors[] = array(
 740:         'name'  => @$attribs['name'],
 741:         'email' => (string)@$attribs['email']
 742:         );
 743:     }
 744: 
 745:     // }}}
 746:     // {{{ xmltag_Highlight
 747: 
 748:     /**
 749:     * start handler for <highlight> element
 750:     */
 751:     function xmltag_Highlight($xp, $elem, $attribs)
 752:     {
 753:         if (!isset($attribs['lang']) || $attribs['lang'] === '') {
 754:             $this->_error(TEXT_HIGHLIGHTER_EMPTY_OR_MISSING, 'language name');
 755:         }
 756:         $this->_code = '';
 757:         $this->language = strtoupper(@$attribs['lang']);
 758:         $this->_case = @$attribs['case'] == 'yes';
 759:     }
 760: 
 761:     // }}}
 762: 
 763:     /**#@-*/
 764: 
 765:     // {{{ _error
 766: 
 767:     /**
 768:     * Add an error message
 769:     *
 770:     * @param integer $code Error code
 771:     * @param mixed   $message Error message or array with error message parameters
 772:     * @param integer $lineNo Source code line number
 773:     * @access private
 774:     */
 775:     function _error($code, $params = array(), $lineNo = 0)
 776:     {
 777:         if (!$lineNo && !empty($this->parser)) {
 778:             $lineNo = xml_get_current_line_number($this->parser);
 779:         }
 780:         $this->_errors[] = $this->_formatError($code, $params, $this->_syntaxFile, $lineNo);
 781:     }
 782: 
 783:     // }}}
 784:     // {{{ _aliasAttributes
 785: 
 786:     /**
 787:     * BC trick
 788:     *
 789:     * @param array $attrs attributes
 790:     */
 791:     function _aliasAttributes(&$attrs)
 792:     {
 793:         if (isset($attrs['innerClass']) && !isset($attrs['innerGroup'])) {
 794:             $attrs['innerGroup'] = $attrs['innerClass'];
 795:         }
 796:         if (isset($attrs['delimClass']) && !isset($attrs['delimGroup'])) {
 797:             $attrs['delimGroup'] = $attrs['delimClass'];
 798:         }
 799:         if (isset($attrs['partClass']) && !isset($attrs['partGroup'])) {
 800:             $attrs['partGroup'] = $attrs['partClass'];
 801:         }
 802:     }
 803: 
 804:     // }}}
 805: 
 806:     /**#@+
 807:     * @access private
 808:     * @param resource $xp      XML parser resource
 809:     * @param string   $elem    XML element name
 810:     */
 811: 
 812:     // {{{ xmltag_Comment_
 813: 
 814:     /**
 815:     * end handler for <comment> element
 816:     */
 817:     function xmltag_Comment_($xp, $elem)
 818:     {
 819:         $this->_inComment = false;
 820:     }
 821: 
 822:     // }}}
 823:     // {{{ xmltag_Region_
 824: 
 825:     /**
 826:     * end handler for <region> element
 827:     */
 828:     function xmltag_Region_($xp, $elem)
 829:     {
 830:         $this->_element['type'] = 'region';
 831:         $this->_element['order'] = $this->_blockOrder ++;
 832:         $this->_regions[$this->_element['name']] = $this->_element;
 833:     }
 834: 
 835:     // }}}
 836:     // {{{ xmltag_Keywords_
 837: 
 838:     /**
 839:     * end handler for <keywords> element
 840:     */
 841:     function xmltag_Keywords_($xp, $elem)
 842:     {
 843:         $this->_keywords[$this->_element['name']] = $this->_element;
 844:     }
 845: 
 846:     // }}}
 847:     // {{{ xmltag_Block_
 848: 
 849:     /**
 850:     * end handler for <block> element
 851:     */
 852:     function xmltag_Block_($xp, $elem)
 853:     {
 854:         $this->_element['type'] = 'block';
 855:         $this->_element['order'] = $this->_blockOrder ++;
 856:         $this->_blocks[$this->_element['name']] = $this->_element;
 857:     }
 858: 
 859:     // }}}
 860:     // {{{ xmltag_Highlight_
 861: 
 862:     /**
 863:     * end handler for <highlight> element
 864:     */
 865:     function xmltag_Highlight_($xp, $elem)
 866:     {
 867:         $conditions = array();
 868:         $toplevel = array();
 869:         foreach ($this->_blocks as $i => $current) {
 870:             if (!$current['contained'] && !isset($current['onlyin'])) {
 871:                 $toplevel[] = $i;
 872:             }
 873:             foreach ((array)@$current['onlyin'] as $region => $lineNo) {
 874:                 if (!isset($this->_regions[$region])) {
 875:                     $this->_error(TEXT_HIGHLIGHTER_BLOCK_REGION,
 876:                     array(
 877:                     'block' => $current['name'],
 878:                     'region' => $region
 879:                     ));
 880:                 }
 881:             }
 882:         }
 883:         foreach ($this->_regions as $i=>$current) {
 884:             if (!$current['contained'] && !isset($current['onlyin'])) {
 885:                 $toplevel[] = $i;
 886:             }
 887:             foreach ((array)@$current['contains']['region'] as $region => $lineNo) {
 888:                 if (!isset($this->_regions[$region])) {
 889:                     $this->_error(TEXT_HIGHLIGHTER_REGION_REGION,
 890:                     array(
 891:                     'region1' => $current['name'],
 892:                     'region2' => $region
 893:                     ));
 894:                 }
 895:             }
 896:             foreach ((array)@$current['contains']['block'] as $region => $lineNo) {
 897:                 if (!isset($this->_blocks[$region])) {
 898:                     $this->_error(TEXT_HIGHLIGHTER_REGION_BLOCK,
 899:                     array(
 900:                     'block' => $current['name'],
 901:                     'region' => $region
 902:                     ));
 903:                 }
 904:             }
 905:             foreach ((array)@$current['onlyin'] as $region => $lineNo) {
 906:                 if (!isset($this->_regions[$region])) {
 907:                     $this->_error(TEXT_HIGHLIGHTER_REGION_REGION,
 908:                     array(
 909:                     'region1' => $current['name'],
 910:                     'region2' => $region
 911:                     ));
 912:                 }
 913:             }
 914:             foreach ($this->_regions as $j => $region) {
 915:                 if (isset($region['onlyin'])) {
 916:                     $suits = isset($region['onlyin'][$current['name']]);
 917:                 } elseif (isset($current['not-contains']['region'][$region['name']])) {
 918:                     $suits = false;
 919:                 } elseif (isset($current['contains']['region'][$region['name']])) {
 920:                     $suits = true;
 921:                 } else {
 922:                     $suits = @$current['contains-all'] && @!$region['never-contained'];
 923:                 }
 924:                 if ($suits) {
 925:                     $this->_regions[$i]['lookfor'][] = $j;
 926:                 }
 927:             }
 928:             foreach ($this->_blocks as $j=>$region) {
 929:                 if (isset($region['onlyin'])) {
 930:                     $suits = isset($region['onlyin'][$current['name']]);
 931:                 } elseif (isset($current['not-contains']['block'][$region['name']])) {
 932:                     $suits = false;
 933:                 } elseif (isset($current['contains']['block'][$region['name']])) {
 934:                     $suits = true;
 935:                 } else {
 936:                     $suits = @$current['contains-all'] && @!$region['never-contained'];
 937:                 }
 938:                 if ($suits) {
 939:                     $this->_regions[$i]['lookfor'][] = $j;
 940:                 }
 941:             }
 942:         }
 943:         foreach ($this->_blocks as $i=>$current) {
 944:             unset ($this->_blocks[$i]['never-contained']);
 945:             unset ($this->_blocks[$i]['contained']);
 946:             unset ($this->_blocks[$i]['contains-all']);
 947:             unset ($this->_blocks[$i]['contains']);
 948:             unset ($this->_blocks[$i]['onlyin']);
 949:             unset ($this->_blocks[$i]['line']);
 950:         }
 951: 
 952:         foreach ($this->_regions as $i=>$current) {
 953:             unset ($this->_regions[$i]['never-contained']);
 954:             unset ($this->_regions[$i]['contained']);
 955:             unset ($this->_regions[$i]['contains-all']);
 956:             unset ($this->_regions[$i]['contains']);
 957:             unset ($this->_regions[$i]['onlyin']);
 958:             unset ($this->_regions[$i]['line']);
 959:         }
 960: 
 961:         foreach ($this->_keywords as $name => $keyword) {
 962:             if (isset($keyword['ifdef'])) {
 963:                 $conditions[$keyword['ifdef']][] = array($name, true);
 964:             }
 965:             if (isset($keyword['ifndef'])) {
 966:                 $conditions[$keyword['ifndef']][] = array($name, false);
 967:             }
 968:             unset($this->_keywords[$name]['line']);
 969:             if (!isset($this->_blocks[$keyword['inherits']])) {
 970:                 $this->_error(TEXT_HIGHLIGHTER_KEYWORD_INHERITS,
 971:                 array(
 972:                 'keyword' => $keyword['name'],
 973:                 'block' => $keyword['inherits']
 974:                 ));
 975:             }
 976:             if (isset($keyword['otherwise']) && !isset($this->_blocks[$keyword['otherwise']]) ) {
 977:                 $this->_error(TEXT_HIGHLIGHTER_KEYWORD_BLOCK,
 978:                 array(
 979:                 'keyword' => $keyword['name'],
 980:                 'block' => $keyword['inherits']
 981:                 ));
 982:             }
 983:         }
 984: 
 985:         $syntax=array(
 986:         'keywords'   => $this->_keywords,
 987:         'blocks'     => array_merge($this->_blocks, $this->_regions),
 988:         'toplevel'   => $toplevel,
 989:         );
 990:         uasort($syntax['blocks'], array(&$this, '_sortBlocks'));
 991:         foreach ($syntax['blocks'] as $name => $block) {
 992:             if ($block['type'] == 'block') {
 993:                 continue;
 994:             }
 995:             if (is_array(@$syntax['blocks'][$name]['lookfor'])) {
 996:                 usort($syntax['blocks'][$name]['lookfor'], array(&$this, '_sortLookFor'));
 997:             }
 998:         }
 999:         usort($syntax['toplevel'], array(&$this, '_sortLookFor'));
1000:         $syntax['case'] = $this->_case;
1001:         $this->_code = <<<CODE
1002: <?php
1003: /**
1004:  * Auto-generated class. {$this->language} syntax highlighting
1005: CODE;
1006: 
1007:         if ($this->_comment) {
1008:             $comment = preg_replace('~^~m',' * ',$this->_comment);
1009:             $this->_code .= "\n * \n" . $comment;
1010:         }
1011: 
1012:         $this->_code .= <<<CODE
1013:  
1014:  *
1015:  * PHP version 4 and 5
1016:  *
1017:  * LICENSE: This source file is subject to version 3.0 of the PHP license
1018:  * that is available through the world-wide-web at the following URI:
1019:  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
1020:  * the PHP License and are unable to obtain it through the web, please
1021:  * send a note to license@php.net so we can mail you a copy immediately.
1022:  *
1023:  * @copyright  2004-2006 Andrey Demenev
1024:  * @license    http://www.php.net/license/3_0.txt  PHP License
1025:  * @link       http://pear.php.net/package/Text_Highlighter
1026:  * @category   Text
1027:  * @package    Text_Highlighter
1028:  * @version    generated from: $this->_syntaxFile
1029: 
1030: CODE;
1031: 
1032:         foreach ($this->_authors as $author) {
1033:             $this->_code .= ' * @author ' . $author['name'];
1034:             if ($author['email']) {
1035:                 $this->_code .= ' <' . $author['email'] . '>';
1036:             }
1037:             $this->_code .= "\n";
1038:         }
1039: 
1040:         $this->_code .= <<<CODE
1041:  *
1042:  */
1043: 
1044: /**
1045:  * Auto-generated class. {$this->language} syntax highlighting
1046:  *
1047: 
1048: CODE;
1049:         foreach ($this->_authors as $author) {
1050:             $this->_code .= ' * @author ' . $author['name'];
1051:             if ($author['email']) {
1052:                 $this->_code .= ' <' . $author['email']. '>';
1053:             }
1054:             $this->_code .= "\n";
1055:         }
1056: 
1057: 
1058:         $this->_code .= <<<CODE
1059:  * @category   Text
1060:  * @package    Text_Highlighter
1061:  * @copyright  2004-2006 Andrey Demenev
1062:  * @license    http://www.php.net/license/3_0.txt  PHP License
1063:  * @version    Release: 0.7.1
1064:  * @link       http://pear.php.net/package/Text_Highlighter
1065:  */
1066: class  Text_Highlighter_{$this->language} extends Text_Highlighter
1067: {
1068:     
1069: CODE;
1070:         $this->_code .= 'var $_language = \'' . strtolower($this->language) . "';\n\n";
1071:         $array = var_export($syntax, true);
1072:         $array = trim(preg_replace('~^(\s*)~m','        \1\1',$array));
1073:         //        \$this->_syntax = $array;
1074:         $this->_code .= <<<CODE
1075: 
1076:     /**
1077:      *  Constructor
1078:      *
1079:      * @param array  \$options
1080:      * @access public
1081:      */
1082:     function __construct(\$options=array())
1083:     {
1084: 
1085: CODE;
1086:         $this->_code .= <<<CODE
1087: 
1088:         \$this->_options = \$options;
1089: CODE;
1090:         $states = array();
1091:         $i = 0;
1092:         foreach ($syntax['blocks'] as $name => $block) {
1093:             if ($block['type'] == 'region') {
1094:                 $states[$name] = $i++;
1095:             }
1096:         }
1097:         $regs = array();
1098:         $counts = array();
1099:         $delim = array();
1100:         $inner = array();
1101:         $end = array();
1102:         $stat = array();
1103:         $keywords = array();
1104:         $parts = array();
1105:         $kwmap = array();
1106:         $subst = array();
1107:         $re = array();
1108:         $ce = array();
1109:         $rd = array();
1110:         $in = array();
1111:         $st = array();
1112:         $kw = array();
1113:         $sb = array();
1114:         foreach ($syntax['toplevel'] as $name) {
1115:             $block = $syntax['blocks'][$name];
1116:             if ($block['type'] == 'block') {
1117:                 $kwm = array();
1118:                 $re[] = '(' . $block['match'] . ')';
1119:                 $ce[] = $this->_countSubpatterns($block['match']);
1120:                 $rd[] = '';
1121:                 $sb[] = false;;
1122:                 $st[] = -1;
1123:                 foreach ($syntax['keywords'] as $kwname => $kwgroup) {
1124:                     if ($kwgroup['inherits'] != $name) {
1125:                         continue;
1126:                     }
1127:                     $gre = implode('|', array_keys($kwgroup['match']));
1128:                     if (!$kwgroup['case']) {
1129:                         $gre = '(?i)' . $gre;
1130:                     }
1131:                     $kwm[$kwname][] =  $gre;
1132:                     $kwmap[$kwname] = $kwgroup['innerGroup'];
1133:                 }
1134:                 foreach ($kwm as $g => $ma) {
1135:                     $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/';
1136:                 }
1137:                 $kw[] = $kwm;
1138:             } else {
1139:                 $kw[] = -1;
1140:                 $re[] = '(' . $block['start'] . ')';
1141:                 $ce[] = $this->_countSubpatterns($block['start']);
1142:                 $rd[] = $block['delimGroup'];
1143:                 $st[] = $states[$name];
1144:                 $sb[] = $block['remember'];
1145:             }
1146:             $in[] = $block['innerGroup'];
1147:         }
1148:         $re = implode('|', $re);
1149:         $regs[-1] = '/' . $re . '/';
1150:         $counts[-1] = $ce;
1151:         $delim[-1] = $rd;
1152:         $inner[-1] = $in;
1153:         $stat[-1] = $st;
1154:         $keywords[-1] = $kw;
1155:         $subst[-1] = $sb;
1156: 
1157:         foreach ($syntax['blocks'] as $ablock) {
1158:             if ($ablock['type'] != 'region') {
1159:                 continue;
1160:             }
1161:             $end[] = '/' . $ablock['end'] . '/';
1162:             $re = array();
1163:             $ce = array();
1164:             $rd = array();
1165:             $in = array();
1166:             $st = array();
1167:             $kw = array();
1168:             $pc = array();
1169:             $sb = array();
1170:             foreach ((array)@$ablock['lookfor'] as $name) {
1171:                 $block = $syntax['blocks'][$name];
1172:                 if (isset($block['partClass'])) {
1173:                     $pc[] = $block['partClass'];
1174:                 } else {
1175:                     $pc[] = null;
1176:                 }
1177:                 if ($block['type'] == 'block') {
1178:                     $kwm = array();;
1179:                     $re[] = '(' . $block['match'] . ')';
1180:                     $ce[] = $this->_countSubpatterns($block['match']);
1181:                     $rd[] = '';
1182:                     $sb[] = false;
1183:                     $st[] = -1;
1184:                     foreach ($syntax['keywords'] as $kwname => $kwgroup) {
1185:                         if ($kwgroup['inherits'] != $name) {
1186:                             continue;
1187:                         }
1188:                         $gre = implode('|', array_keys($kwgroup['match']));
1189:                         if (!$kwgroup['case']) {
1190:                             $gre = '(?i)' . $gre;
1191:                         }
1192:                         $kwm[$kwname][] =  $gre;
1193:                         $kwmap[$kwname] = $kwgroup['innerGroup'];
1194:                     }
1195:                     foreach ($kwm as $g => $ma) {
1196:                         $kwm[$g] = '/^(' . implode(')|(', $ma) . ')$/';
1197:                     }
1198:                     $kw[] = $kwm;
1199:                 } else {
1200:                     $sb[] = $block['remember'];
1201:                     $kw[] = -1;
1202:                     $re[] = '(' . $block['start'] . ')';
1203:                     $ce[] = $this->_countSubpatterns($block['start']);
1204:                     $rd[] = $block['delimGroup'];
1205:                     $st[] = $states[$name];
1206:                 }
1207:                 $in[] = $block['innerGroup'];
1208:             }
1209:             $re = implode('|', $re);
1210:             $regs[] = '/' . $re . '/';
1211:             $counts[] = $ce;
1212:             $delim[] = $rd;
1213:             $inner[] = $in;
1214:             $stat[] = $st;
1215:             $keywords[] = $kw;
1216:             $parts[] = $pc;
1217:             $subst[] = $sb;
1218:         }
1219: 
1220: 
1221:         $this->_code .= "\n        \$this->_regs = " . $this->_exportArray($regs);
1222:         $this->_code .= ";\n        \$this->_counts = " .$this->_exportArray($counts);
1223:         $this->_code .= ";\n        \$this->_delim = " .$this->_exportArray($delim);
1224:         $this->_code .= ";\n        \$this->_inner = " .$this->_exportArray($inner);
1225:         $this->_code .= ";\n        \$this->_end = " .$this->_exportArray($end);
1226:         $this->_code .= ";\n        \$this->_states = " .$this->_exportArray($stat);
1227:         $this->_code .= ";\n        \$this->_keywords = " .$this->_exportArray($keywords);
1228:         $this->_code .= ";\n        \$this->_parts = " .$this->_exportArray($parts);
1229:         $this->_code .= ";\n        \$this->_subst = " .$this->_exportArray($subst);
1230:         $this->_code .= ";\n        \$this->_conditions = " .$this->_exportArray($conditions);
1231:         $this->_code .= ";\n        \$this->_kwmap = " .$this->_exportArray($kwmap);
1232:         $this->_code .= ";\n        \$this->_defClass = '" .$this->_defClass . '\'';
1233:         $this->_code .= <<<CODE
1234: ;
1235:         \$this->_checkDefines();
1236:     }
1237:     
1238: }
1239: CODE;
1240: }
1241: 
1242: // }}}
1243: }
1244: 
1245: 
1246: /*
1247: * Local variables:
1248: * tab-width: 4
1249: * c-basic-offset: 4
1250: * c-hanging-comment-ender-p: nil
1251: * End:
1252: */
1253: 
1254: ?>
1255: 
API documentation generated by ApiGen 2.8.0