From 08aa4418c30cfc18ccc69a0f0f9cb9e17be6c196 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Mon, 12 Aug 2013 09:28:15 +0200 Subject: Update to MediaWiki 1.21.1 --- .../__filesource/fsource_geshi_core_geshi.php.html | 4616 ++++++++++++++++++++ 1 file changed, 4616 insertions(+) create mode 100644 extensions/SyntaxHighlight_GeSHi/geshi/docs/api/__filesource/fsource_geshi_core_geshi.php.html (limited to 'extensions/SyntaxHighlight_GeSHi/geshi/docs/api/__filesource/fsource_geshi_core_geshi.php.html') diff --git a/extensions/SyntaxHighlight_GeSHi/geshi/docs/api/__filesource/fsource_geshi_core_geshi.php.html b/extensions/SyntaxHighlight_GeSHi/geshi/docs/api/__filesource/fsource_geshi_core_geshi.php.html new file mode 100644 index 00000000..3d799821 --- /dev/null +++ b/extensions/SyntaxHighlight_GeSHi/geshi/docs/api/__filesource/fsource_geshi_core_geshi.php.html @@ -0,0 +1,4616 @@ + + + + + + File Source for geshi.php + + + + +

Source for file geshi.php

+

Documentation is available at geshi.php

+
+
  1. <?php
  2. +
  3. /**
  4. +
  5.  * GeSHi - Generic Syntax Highlighter
  6. +
  7.  *
  8. +
  9.  * The GeSHi class for Generic Syntax Highlighting. Please refer to the
  10. +
  11.  * documentation at http://qbnz.com/highlighter/documentation.php for more
  12. +
  13.  * information about how to use this class.
  14. +
  15.  *
  16. +
  17.  * For changes, release notes, TODOs etc, see the relevant files in the docs/
  18. +
  19.  * directory.
  20. +
  21.  *
  22. +
  23.  *   This file is part of GeSHi.
  24. +
  25.  *
  26. +
  27.  *  GeSHi is free software; you can redistribute it and/or modify
  28. +
  29.  *  it under the terms of the GNU General Public License as published by
  30. +
  31.  *  the Free Software Foundation; either version 2 of the License, or
  32. +
  33.  *  (at your option) any later version.
  34. +
  35.  *
  36. +
  37.  *  GeSHi is distributed in the hope that it will be useful,
  38. +
  39.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  40. +
  41.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  42. +
  43.  *  GNU General Public License for more details.
  44. +
  45.  *
  46. +
  47.  *  You should have received a copy of the GNU General Public License
  48. +
  49.  *  along with GeSHi; if not, write to the Free Software
  50. +
  51.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  52. +
  53.  *
  54. +
  55.  * @package    geshi
  56. +
  57.  * @subpackage core
  58. +
  59.  * @author     Nigel McNie <nigel@geshi.org>, Benny Baumann <BenBE@omorphia.de>
  60. +
  61.  * @copyright  (C) 2004 - 2007 Nigel McNie, (C) 2007 - 2008 Benny Baumann
  62. +
  63.  * @license    http://gnu.org/copyleft/gpl.html GNU GPL
  64. +
  65.  *
  66. +
  67.  */
  68. +
  69.  
  70. +
  71. //
  72. +
  73. // GeSHi Constants
  74. +
  75. // You should use these constant names in your programs instead of
  76. +
  77. // their values - you never know when a value may change in a future
  78. +
  79. // version
  80. +
  81. //
  82. +
  83.  
  84. +
  85. /** The version of this GeSHi file */
  86. +
  87. define('GESHI_VERSION''1.0.8.2',);
  88. +
  89.  
  90. +
  91. // Define the root directory for the GeSHi code tree
  92. +
  93. if (!defined('GESHI_ROOT')) {
  94. +
  95.     /** The root directory for GeSHi */
  96. +
  97.     define('GESHI_ROOT'dirname(__FILE__DIRECTORY_SEPARATOR);
  98. +
  99. }
  100. +
  101. /** The language file directory for GeSHi
  102. +
  103.     @access private */
  104. +
  105. define('GESHI_LANG_ROOT'GESHI_ROOT 'geshi' DIRECTORY_SEPARATOR);
  106. +
  107.  
  108. +
  109. // Define if GeSHi should be paranoid about security
  110. +
  111. if (!defined('GESHI_SECURITY_PARANOID')) {
  112. +
  113.     /** Tells GeSHi to be paranoid about security settings */
  114. +
  115.     define('GESHI_SECURITY_PARANOID'false);
  116. +
  117. }
  118. +
  119.  
  120. +
  121. // Line numbers - use with enable_line_numbers()
  122. +
  123. /** Use no line numbers when building the result */
  124. +
  125. define('GESHI_NO_LINE_NUMBERS'0);
  126. +
  127. /** Use normal line numbers when building the result */
  128. +
  129. define('GESHI_NORMAL_LINE_NUMBERS'1);
  130. +
  131. /** Use fancy line numbers when building the result */
  132. +
  133. define('GESHI_FANCY_LINE_NUMBERS'2);
  134. +
  135.  
  136. +
  137. // Container HTML type
  138. +
  139. /** Use nothing to surround the source */
  140. +
  141. define('GESHI_HEADER_NONE'0);
  142. +
  143. /** Use a "div" to surround the source */
  144. +
  145. define('GESHI_HEADER_DIV'1);
  146. +
  147. /** Use a "pre" to surround the source */
  148. +
  149. define('GESHI_HEADER_PRE'2);
  150. +
  151. /** Use a pre to wrap lines when line numbers are enabled or to wrap the whole code. */
  152. +
  153. define('GESHI_HEADER_PRE_VALID'3);
  154. +
  155. /**
  156. +
  157.  * Use a "table" to surround the source:
  158. +
  159.  *
  160. +
  161.  *  <table>
  162. +
  163.  *    <thead><tr><td colspan="2">$header</td></tr></thead>
  164. +
  165.  *    <tbody><tr><td><pre>$linenumbers</pre></td><td><pre>$code></pre></td></tr></tbody>
  166. +
  167.  *    <tfooter><tr><td colspan="2">$footer</td></tr></tfoot>
  168. +
  169.  *  </table>
  170. +
  171.  *
  172. +
  173.  * this is essentially only a workaround for Firefox, see sf#1651996 or take a look at
  174. +
  175.  * https://bugzilla.mozilla.org/show_bug.cgi?id=365805
  176. +
  177.  * @note when linenumbers are disabled this is essentially the same as GESHI_HEADER_PRE
  178. +
  179.  */
  180. +
  181. define('GESHI_HEADER_PRE_TABLE'4);
  182. +
  183.  
  184. +
  185. // Capatalisation constants
  186. +
  187. /** Lowercase keywords found */
  188. +
  189. define('GESHI_CAPS_NO_CHANGE'0);
  190. +
  191. /** Uppercase keywords found */
  192. +
  193. define('GESHI_CAPS_UPPER'1);
  194. +
  195. /** Leave keywords found as the case that they are */
  196. +
  197. define('GESHI_CAPS_LOWER'2);
  198. +
  199.  
  200. +
  201. // Link style constants
  202. +
  203. /** Links in the source in the :link state */
  204. +
  205. define('GESHI_LINK'0);
  206. +
  207. /** Links in the source in the :hover state */
  208. +
  209. define('GESHI_HOVER'1);
  210. +
  211. /** Links in the source in the :active state */
  212. +
  213. define('GESHI_ACTIVE'2);
  214. +
  215. /** Links in the source in the :visited state */
  216. +
  217. define('GESHI_VISITED'3);
  218. +
  219.  
  220. +
  221. // Important string starter/finisher
  222. +
  223. // Note that if you change these, they should be as-is: i.e., don't
  224. +
  225. // write them as if they had been run through htmlentities()
  226. +
  227. /** The starter for important parts of the source */
  228. +
  229. define('GESHI_START_IMPORTANT''<BEGIN GeSHi>');
  230. +
  231. /** The ender for important parts of the source */
  232. +
  233. define('GESHI_END_IMPORTANT''<END GeSHi>');
  234. +
  235.  
  236. +
  237. /**#@+
  238. +
  239.  *  @access private
  240. +
  241.  */
  242. +
  243. // When strict mode applies for a language
  244. +
  245. /** Strict mode never applies (this is the most common) */
  246. +
  247. define('GESHI_NEVER'0);
  248. +
  249. /** Strict mode *might* apply, and can be enabled or
  250. +
  251.     disabled by {@link GeSHi->enable_strict_mode()} */
  252. +
  253. define('GESHI_MAYBE'1);
  254. +
  255. /** Strict mode always applies */
  256. +
  257. define('GESHI_ALWAYS'2);
  258. +
  259.  
  260. +
  261. // Advanced regexp handling constants, used in language files
  262. +
  263. /** The key of the regex array defining what to search for */
  264. +
  265. define('GESHI_SEARCH'0);
  266. +
  267. /** The key of the regex array defining what bracket group in a
  268. +
  269.     matched search to use as a replacement */
  270. +
  271. define('GESHI_REPLACE'1);
  272. +
  273. /** The key of the regex array defining any modifiers to the regular expression */
  274. +
  275. define('GESHI_MODIFIERS'2);
  276. +
  277. /** The key of the regex array defining what bracket group in a
  278. +
  279.     matched search to put before the replacement */
  280. +
  281. define('GESHI_BEFORE'3);
  282. +
  283. /** The key of the regex array defining what bracket group in a
  284. +
  285.     matched search to put after the replacement */
  286. +
  287. define('GESHI_AFTER'4);
  288. +
  289. /** The key of the regex array defining a custom keyword to use
  290. +
  291.     for this regexp's html tag class */
  292. +
  293. define('GESHI_CLASS'5);
  294. +
  295.  
  296. +
  297. /** Used in language files to mark comments */
  298. +
  299. define('GESHI_COMMENTS'0);
  300. +
  301.  
  302. +
  303. /** Used to work around missing PHP features **/
  304. +
  305. define('GESHI_PHP_PRE_433'!(version_compare(PHP_VERSION'4.3.3'=== 1));
  306. +
  307.  
  308. +
  309. /** make sure we can call stripos **/
  310. +
  311. if (!function_exists('stripos')) {
  312. +
  313.     // the offset param of preg_match is not supported below PHP 4.3.3
  314. +
  315.     if (GESHI_PHP_PRE_433{
  316. +
  317.         /**
  318. +
  319.          * @ignore
  320. +
  321.          */
  322. +
  323.         function stripos($haystack$needle$offset null{
  324. +
  325.             if (!is_null($offset)) {
  326. +
  327.                 $haystack substr($haystack$offset);
  328. +
  329.             }
  330. +
  331.             if (preg_match('/'preg_quote($needle'/''/'$haystack$matchPREG_OFFSET_CAPTURE)) {
  332. +
  333.                 return $match[0][1];
  334. +
  335.             }
  336. +
  337.             return false;
  338. +
  339.         }
  340. +
  341.     }
  342. +
  343.     else {
  344. +
  345.         /**
  346. +
  347.          * @ignore
  348. +
  349.          */
  350. +
  351.         function stripos($haystack$needle$offset null{
  352. +
  353.             if (preg_match('/'preg_quote($needle'/''/'$haystack$matchPREG_OFFSET_CAPTURE$offset)) {
  354. +
  355.                 return $match[0][1];
  356. +
  357.             }
  358. +
  359.             return false;
  360. +
  361.         }
  362. +
  363.     }
  364. +
  365. }
  366. +
  367.  
  368. +
  369. /** some old PHP / PCRE subpatterns only support up to xxx subpatterns in
  370. +
  371.     regular expressions. Set this to false if your PCRE lib is up to date
  372. +
  373.     @see GeSHi->optimize_regexp_list()
  374. +
  375.     **/
  376. +
  377.  
  378. +
  379. define('GESHI_MAX_PCRE_SUBPATTERNS'500);
  380. +
  381. /** it's also important not to generate too long regular expressions
  382. +
  383.     be generous here... but keep in mind, that when reaching this limit we
  384. +
  385.     still have to close open patterns. 12k should do just fine on a 16k limit.
  386. +
  387.     @see GeSHi->optimize_regexp_list()
  388. +
  389.     **/
  390. +
  391.  
  392. +
  393. define('GESHI_MAX_PCRE_LENGTH'12288);
  394. +
  395.  
  396. +
  397. //Number format specification
  398. +
  399. /** Basic number format for integers */
  400. +
  401. define('GESHI_NUMBER_INT_BASIC'1);        //Default integers \d+
  402. +
  403. /** Enhanced number format for integers like seen in C */
  404. +
  405. define('GESHI_NUMBER_INT_CSTYLE'2);       //Default C-Style \d+[lL]?
  406. +
  407. /** Number format to highlight binary numbers with a suffix "b" */
  408. +
  409. define('GESHI_NUMBER_BIN_SUFFIX'16);           //[01]+[bB]
  410. +
  411. /** Number format to highlight binary numbers with a prefix % */
  412. +
  413. define('GESHI_NUMBER_BIN_PREFIX_PERCENT'32);   //%[01]+
  414. +
  415. /** Number format to highlight binary numbers with a prefix 0b (C) */
  416. +
  417. define('GESHI_NUMBER_BIN_PREFIX_0B'64);        //0b[01]+
  418. +
  419. /** Number format to highlight octal numbers with a leading zero */
  420. +
  421. define('GESHI_NUMBER_OCT_PREFIX'256);           //0[0-7]+
  422. +
  423. /** Number format to highlight octal numbers with a suffix of o */
  424. +
  425. define('GESHI_NUMBER_OCT_SUFFIX'512);           //[0-7]+[oO]
  426. +
  427. /** Number format to highlight hex numbers with a prefix 0x */
  428. +
  429. define('GESHI_NUMBER_HEX_PREFIX'4096);           //0x[0-9a-fA-F]+
  430. +
  431. /** Number format to highlight hex numbers with a suffix of h */
  432. +
  433. define('GESHI_NUMBER_HEX_SUFFIX'8192);           //[0-9][0-9a-fA-F]*h
  434. +
  435. /** Number format to highlight floating-point numbers without support for scientific notation */
  436. +
  437. define('GESHI_NUMBER_FLT_NONSCI'65536);          //\d+\.\d+
  438. +
  439. /** Number format to highlight floating-point numbers without support for scientific notation */
  440. +
  441. define('GESHI_NUMBER_FLT_NONSCI_F'131072);       //\d+(\.\d+)?f
  442. +
  443. /** Number format to highlight floating-point numbers with support for scientific notation (E) and optional leading zero */
  444. +
  445. define('GESHI_NUMBER_FLT_SCI_SHORT'262144);      //\.\d+e\d+
  446. +
  447. /** Number format to highlight floating-point numbers with support for scientific notation (E) and required leading digit */
  448. +
  449. define('GESHI_NUMBER_FLT_SCI_ZERO'524288);       //\d+(\.\d+)?e\d+
  450. +
  451. //Custom formats are passed by RX array
  452. +
  453.  
  454. +
  455. // Error detection - use these to analyse faults
  456. +
  457. /** No sourcecode to highlight was specified
  458. +
  459.  * @deprecated
  460. +
  461.  */
  462. +
  463. define('GESHI_ERROR_NO_INPUT'1);
  464. +
  465. /** The language specified does not exist */
  466. +
  467. define('GESHI_ERROR_NO_SUCH_LANG'2);
  468. +
  469. /** GeSHi could not open a file for reading (generally a language file) */
  470. +
  471. define('GESHI_ERROR_FILE_NOT_READABLE'3);
  472. +
  473. /** The header type passed to {@link GeSHi->set_header_type()} was invalid */
  474. +
  475. define('GESHI_ERROR_INVALID_HEADER_TYPE'4);
  476. +
  477. /** The line number type passed to {@link GeSHi->enable_line_numbers()} was invalid */
  478. +
  479. define('GESHI_ERROR_INVALID_LINE_NUMBER_TYPE'5);
  480. +
  481. /**#@-*/
  482. +
  483.  
  484. +
  485.  
  486. +
  487. /**
  488. +
  489.  * The GeSHi Class.
  490. +
  491.  *
  492. +
  493.  * Please refer to the documentation for GeSHi 1.0.X that is available
  494. +
  495.  * at http://qbnz.com/highlighter/documentation.php for more information
  496. +
  497.  * about how to use this class.
  498. +
  499.  *
  500. +
  501.  * @package   geshi
  502. +
  503.  * @author    Nigel McNie <nigel@geshi.org>, Benny Baumann <BenBE@omorphia.de>
  504. +
  505.  * @copyright (C) 2004 - 2007 Nigel McNie, (C) 2007 - 2008 Benny Baumann
  506. +
  507.  */
  508. +
  509. class GeSHi {
  510. +
  511.     /**#@+
  512. +
  513.      * @access private
  514. +
  515.      */
  516. +
  517.     /**
  518. +
  519.      * The source code to highlight
  520. +
  521.      * @var string 
  522. +
  523.      */
  524. +
  525.     var $source '';
  526. +
  527.  
  528. +
  529.     /**
  530. +
  531.      * The language to use when highlighting
  532. +
  533.      * @var string 
  534. +
  535.      */
  536. +
  537.     var $language '';
  538. +
  539.  
  540. +
  541.     /**
  542. +
  543.      * The data for the language used
  544. +
  545.      * @var array 
  546. +
  547.      */
  548. +
  549.     var $language_data array();
  550. +
  551.  
  552. +
  553.     /**
  554. +
  555.      * The path to the language files
  556. +
  557.      * @var string 
  558. +
  559.      */
  560. +
  561.     var $language_path GESHI_LANG_ROOT;
  562. +
  563.  
  564. +
  565.     /**
  566. +
  567.      * The error message associated with an error
  568. +
  569.      * @var string 
  570. +
  571.      * @todo check err reporting works
  572. +
  573.      */
  574. +
  575.     var $error false;
  576. +
  577.  
  578. +
  579.     /**
  580. +
  581.      * Possible error messages
  582. +
  583.      * @var array 
  584. +
  585.      */
  586. +
  587.     var $error_messages array(
  588. +
  589.         GESHI_ERROR_NO_SUCH_LANG => 'GeSHi could not find the language {LANGUAGE} (using path {PATH})',
  590. +
  591.         GESHI_ERROR_FILE_NOT_READABLE => 'The file specified for load_from_file was not readable',
  592. +
  593.         GESHI_ERROR_INVALID_HEADER_TYPE => 'The header type specified is invalid',
  594. +
  595.         GESHI_ERROR_INVALID_LINE_NUMBER_TYPE => 'The line number type specified is invalid'
  596. +
  597.     );
  598. +
  599.  
  600. +
  601.     /**
  602. +
  603.      * Whether highlighting is strict or not
  604. +
  605.      * @var boolean 
  606. +
  607.      */
  608. +
  609.     var $strict_mode false;
  610. +
  611.  
  612. +
  613.     /**
  614. +
  615.      * Whether to use CSS classes in output
  616. +
  617.      * @var boolean 
  618. +
  619.      */
  620. +
  621.     var $use_classes false;
  622. +
  623.  
  624. +
  625.     /**
  626. +
  627.      * The type of header to use. Can be one of the following
  628. +
  629.      * values:
  630. +
  631.      *
  632. +
  633.      * - GESHI_HEADER_PRE: Source is outputted in a "pre" HTML element.
  634. +
  635.      * - GESHI_HEADER_DIV: Source is outputted in a "div" HTML element.
  636. +
  637.      * - GESHI_HEADER_NONE: No header is outputted.
  638. +
  639.      *
  640. +
  641.      * @var int 
  642. +
  643.      */
  644. +
  645.     var $header_type GESHI_HEADER_PRE;
  646. +
  647.  
  648. +
  649.     /**
  650. +
  651.      * Array of permissions for which lexics should be highlighted
  652. +
  653.      * @var array 
  654. +
  655.      */
  656. +
  657.     var $lexic_permissions array(
  658. +
  659.         'KEYWORDS' =>    array(),
  660. +
  661.         'COMMENTS' =>    array('MULTI' => true),
  662. +
  663.         'REGEXPS' =>     array(),
  664. +
  665.         'ESCAPE_CHAR' => true,
  666. +
  667.         'BRACKETS' =>    true,
  668. +
  669.         'SYMBOLS' =>     false,
  670. +
  671.         'STRINGS' =>     true,
  672. +
  673.         'NUMBERS' =>     true,
  674. +
  675.         'METHODS' =>     true,
  676. +
  677.         'SCRIPT' =>      true
  678. +
  679.     );
  680. +
  681.  
  682. +
  683.     /**
  684. +
  685.      * The time it took to parse the code
  686. +
  687.      * @var double 
  688. +
  689.      */
  690. +
  691.     var $time 0;
  692. +
  693.  
  694. +
  695.     /**
  696. +
  697.      * The content of the header block
  698. +
  699.      * @var string 
  700. +
  701.      */
  702. +
  703.     var $header_content '';
  704. +
  705.  
  706. +
  707.     /**
  708. +
  709.      * The content of the footer block
  710. +
  711.      * @var string 
  712. +
  713.      */
  714. +
  715.     var $footer_content '';
  716. +
  717.  
  718. +
  719.     /**
  720. +
  721.      * The style of the header block
  722. +
  723.      * @var string 
  724. +
  725.      */
  726. +
  727.     var $header_content_style '';
  728. +
  729.  
  730. +
  731.     /**
  732. +
  733.      * The style of the footer block
  734. +
  735.      * @var string 
  736. +
  737.      */
  738. +
  739.     var $footer_content_style '';
  740. +
  741.  
  742. +
  743.     /**
  744. +
  745.      * Tells if a block around the highlighted source should be forced
  746. +
  747.      * if not using line numbering
  748. +
  749.      * @var boolean 
  750. +
  751.      */
  752. +
  753.     var $force_code_block false;
  754. +
  755.  
  756. +
  757.     /**
  758. +
  759.      * The styles for hyperlinks in the code
  760. +
  761.      * @var array 
  762. +
  763.      */
  764. +
  765.     var $link_styles array();
  766. +
  767.  
  768. +
  769.     /**
  770. +
  771.      * Whether important blocks should be recognised or not
  772. +
  773.      * @var boolean 
  774. +
  775.      * @deprecated
  776. +
  777.      * @todo REMOVE THIS FUNCTIONALITY!
  778. +
  779.      */
  780. +
  781.     var $enable_important_blocks false;
  782. +
  783.  
  784. +
  785.     /**
  786. +
  787.      * Styles for important parts of the code
  788. +
  789.      * @var string 
  790. +
  791.      * @deprecated
  792. +
  793.      * @todo As above - rethink the whole idea of important blocks as it is buggy and
  794. +
  795.      *  will be hard to implement in 1.2
  796. +
  797.      */
  798. +
  799.     var $important_styles 'font-weight: bold; color: red;'// Styles for important parts of the code
  800. +
  801.  
  802. +
  803.     /**
  804. +
  805.      * Whether CSS IDs should be added to the code
  806. +
  807.      * @var boolean 
  808. +
  809.      */
  810. +
  811.     var $add_ids false;
  812. +
  813.  
  814. +
  815.     /**
  816. +
  817.      * Lines that should be highlighted extra
  818. +
  819.      * @var array 
  820. +
  821.      */
  822. +
  823.     var $highlight_extra_lines array();
  824. +
  825.  
  826. +
  827.     /**
  828. +
  829.      * Styles of lines that should be highlighted extra
  830. +
  831.      * @var array 
  832. +
  833.      */
  834. +
  835.     var $highlight_extra_lines_styles array();
  836. +
  837.  
  838. +
  839.     /**
  840. +
  841.      * Styles of extra-highlighted lines
  842. +
  843.      * @var string 
  844. +
  845.      */
  846. +
  847.     var $highlight_extra_lines_style 'background-color: #ffc;';
  848. +
  849.  
  850. +
  851.     /**
  852. +
  853.      * The line ending
  854. +
  855.      * If null, nl2br() will be used on the result string.
  856. +
  857.      * Otherwise, all instances of \n will be replaced with $line_ending
  858. +
  859.      * @var string 
  860. +
  861.      */
  862. +
  863.     var $line_ending null;
  864. +
  865.  
  866. +
  867.     /**
  868. +
  869.      * Number at which line numbers should start at
  870. +
  871.      * @var int 
  872. +
  873.      */
  874. +
  875.     var $line_numbers_start 1;
  876. +
  877.  
  878. +
  879.     /**
  880. +
  881.      * The overall style for this code block
  882. +
  883.      * @var string 
  884. +
  885.      */
  886. +
  887.     var $overall_style 'font-family:monospace;';
  888. +
  889.  
  890. +
  891.     /**
  892. +
  893.      *  The style for the actual code
  894. +
  895.      * @var string 
  896. +
  897.      */
  898. +
  899.     var $code_style 'font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;';
  900. +
  901.  
  902. +
  903.     /**
  904. +
  905.      * The overall class for this code block
  906. +
  907.      * @var string 
  908. +
  909.      */
  910. +
  911.     var $overall_class '';
  912. +
  913.  
  914. +
  915.     /**
  916. +
  917.      * The overall ID for this code block
  918. +
  919.      * @var string 
  920. +
  921.      */
  922. +
  923.     var $overall_id '';
  924. +
  925.  
  926. +
  927.     /**
  928. +
  929.      * Line number styles
  930. +
  931.      * @var string 
  932. +
  933.      */
  934. +
  935.     var $line_style1 'font-weight: normal; vertical-align:top;';
  936. +
  937.  
  938. +
  939.     /**
  940. +
  941.      * Line number styles for fancy lines
  942. +
  943.      * @var string 
  944. +
  945.      */
  946. +
  947.     var $line_style2 'font-weight: bold; vertical-align:top;';
  948. +
  949.  
  950. +
  951.     /**
  952. +
  953.      * Style for line numbers when GESHI_HEADER_PRE_TABLE is chosen
  954. +
  955.      * @var string 
  956. +
  957.      */
  958. +
  959.     var $table_linenumber_style 'width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;';
  960. +
  961.  
  962. +
  963.     /**
  964. +
  965.      * Flag for how line numbers are displayed
  966. +
  967.      * @var boolean 
  968. +
  969.      */
  970. +
  971.     var $line_numbers GESHI_NO_LINE_NUMBERS;
  972. +
  973.  
  974. +
  975.     /**
  976. +
  977.      * Flag to decide if multi line spans are allowed. Set it to false to make sure
  978. +
  979.      * each tag is closed before and reopened after each linefeed.
  980. +
  981.      * @var boolean 
  982. +
  983.      */
  984. +
  985.     var $allow_multiline_span true;
  986. +
  987.  
  988. +
  989.     /**
  990. +
  991.      * The "nth" value for fancy line highlighting
  992. +
  993.      * @var int 
  994. +
  995.      */
  996. +
  997.     var $line_nth_row 0;
  998. +
  999.  
  1000. +
  1001.     /**
  1002. +
  1003.      * The size of tab stops
  1004. +
  1005.      * @var int 
  1006. +
  1007.      */
  1008. +
  1009.     var $tab_width 8;
  1010. +
  1011.  
  1012. +
  1013.     /**
  1014. +
  1015.      * Should we use language-defined tab stop widths?
  1016. +
  1017.      * @var int 
  1018. +
  1019.      */
  1020. +
  1021.     var $use_language_tab_width false;
  1022. +
  1023.  
  1024. +
  1025.     /**
  1026. +
  1027.      * Default target for keyword links
  1028. +
  1029.      * @var string 
  1030. +
  1031.      */
  1032. +
  1033.     var $link_target '';
  1034. +
  1035.  
  1036. +
  1037.     /**
  1038. +
  1039.      * The encoding to use for entity encoding
  1040. +
  1041.      * NOTE: Used with Escape Char Sequences to fix UTF-8 handling (cf. SF#2037598)
  1042. +
  1043.      * @var string 
  1044. +
  1045.      */
  1046. +
  1047.     var $encoding 'utf-8';
  1048. +
  1049.  
  1050. +
  1051.     /**
  1052. +
  1053.      * Should keywords be linked?
  1054. +
  1055.      * @var boolean 
  1056. +
  1057.      */
  1058. +
  1059.     var $keyword_links true;
  1060. +
  1061.  
  1062. +
  1063.     /**
  1064. +
  1065.      * Currently loaded language file
  1066. +
  1067.      * @var string 
  1068. +
  1069.      * @since 1.0.7.22
  1070. +
  1071.      */
  1072. +
  1073.     var $loaded_language '';
  1074. +
  1075.  
  1076. +
  1077.     /**
  1078. +
  1079.      * Wether the caches needed for parsing are built or not
  1080. +
  1081.      *
  1082. +
  1083.      * @var bool 
  1084. +
  1085.      * @since 1.0.8
  1086. +
  1087.      */
  1088. +
  1089.     var $parse_cache_built false;
  1090. +
  1091.  
  1092. +
  1093.     /**
  1094. +
  1095.      * Work around for Suhosin Patch with disabled /e modifier
  1096. +
  1097.      *
  1098. +
  1099.      * Note from suhosins author in config file:
  1100. +
  1101.      * <blockquote>
  1102. +
  1103.      *   The /e modifier inside <code>preg_replace()</code> allows code execution.
  1104. +
  1105.      *   Often it is the cause for remote code execution exploits. It is wise to
  1106. +
  1107.      *   deactivate this feature and test where in the application it is used.
  1108. +
  1109.      *   The developer using the /e modifier should be made aware that he should
  1110. +
  1111.      *   use <code>preg_replace_callback()</code> instead
  1112. +
  1113.      * </blockquote>
  1114. +
  1115.      *
  1116. +
  1117.      * @var array 
  1118. +
  1119.      * @since 1.0.8
  1120. +
  1121.      */
  1122. +
  1123.     var $_kw_replace_group 0;
  1124. +
  1125.     var $_rx_key 0;
  1126. +
  1127.  
  1128. +
  1129.     /**
  1130. +
  1131.      * some "callback parameters" for handle_multiline_regexps
  1132. +
  1133.      *
  1134. +
  1135.      * @since 1.0.8
  1136. +
  1137.      * @access private
  1138. +
  1139.      * @var string 
  1140. +
  1141.      */
  1142. +
  1143.     var $_hmr_before '';
  1144. +
  1145.     var $_hmr_replace '';
  1146. +
  1147.     var $_hmr_after '';
  1148. +
  1149.     var $_hmr_key 0;
  1150. +
  1151.  
  1152. +
  1153.     /**#@-*/
  1154. +
  1155.  
  1156. +
  1157.     /**
  1158. +
  1159.      * Creates a new GeSHi object, with source and language
  1160. +
  1161.      *
  1162. +
  1163.      * @param string The source code to highlight
  1164. +
  1165.      * @param string The language to highlight the source with
  1166. +
  1167.      * @param string The path to the language file directory. <b>This
  1168. +
  1169.      *                is deprecated!</b> I've backported the auto path
  1170. +
  1171.      *                detection from the 1.1.X dev branch, so now it
  1172. +
  1173.      *                should be automatically set correctly. If you have
  1174. +
  1175.      *                renamed the language directory however, you will
  1176. +
  1177.      *                still need to set the path using this parameter or
  1178. +
  1179.      *                {@link GeSHi->set_language_path()}
  1180. +
  1181.      * @since 1.0.0
  1182. +
  1183.      */
  1184. +
  1185.     function GeSHi($source ''$language ''$path ''{
  1186. +
  1187.         if (!empty($source)) {
  1188. +
  1189.             $this->set_source($source);
  1190. +
  1191.         }
  1192. +
  1193.         if (!empty($language)) {
  1194. +
  1195.             $this->set_language($language);
  1196. +
  1197.         }
  1198. +
  1199.         $this->set_language_path($path);
  1200. +
  1201.     }
  1202. +
  1203.  
  1204. +
  1205.     /**
  1206. +
  1207.      * Returns an error message associated with the last GeSHi operation,
  1208. +
  1209.      * or false if no error has occured
  1210. +
  1211.      *
  1212. +
  1213.      * @return string|falseAn error message if there has been an error, else false
  1214. +
  1215.      * @since  1.0.0
  1216. +
  1217.      */
  1218. +
  1219.     function error({
  1220. +
  1221.         if ($this->error{
  1222. +
  1223.             //Put some template variables for debugging here ...
  1224. +
  1225.             $debug_tpl_vars array(
  1226. +
  1227.                 '{LANGUAGE}' => $this->language,
  1228. +
  1229.                 '{PATH}' => $this->language_path
  1230. +
  1231.             );
  1232. +
  1233.             $msg str_replace(
  1234. +
  1235.                 array_keys($debug_tpl_vars),
  1236. +
  1237.                 array_values($debug_tpl_vars),
  1238. +
  1239.                 $this->error_messages[$this->error]);
  1240. +
  1241.  
  1242. +
  1243.             return "<br /><strong>GeSHi Error:</strong> $msg (code {$this->error})<br />";
  1244. +
  1245.         }
  1246. +
  1247.         return false;
  1248. +
  1249.     }
  1250. +
  1251.  
  1252. +
  1253.     /**
  1254. +
  1255.      * Gets a human-readable language name (thanks to Simon Patterson
  1256. +
  1257.      * for the idea :))
  1258. +
  1259.      *
  1260. +
  1261.      * @return string The name for the current language
  1262. +
  1263.      * @since  1.0.2
  1264. +
  1265.      */
  1266. +
  1267.     function get_language_name() {
  1268. +
  1269.         if (GESHI_ERROR_NO_SUCH_LANG == $this->error) {
  1270. +
  1271.             return $this->language_data['LANG_NAME'] . ' (Unknown Language)';
  1272. +
  1273.         }
  1274. +
  1275.         return $this->language_data['LANG_NAME'];
  1276. +
  1277.     }
  1278. +
  1279.  
  1280. +
  1281. /**    
  1282. +
  1283.      * Sets the source code for this object
  1284. +
  1285.      *
  1286. +
  1287.      * @param string The source code to highlight
  1288. +
  1289.      * @since 1.0.0
  1290. +
  1291.      */
  1292. +
  1293.     function set_source($source) {
  1294. +
  1295.         $this->source = $source;
  1296. +
  1297.         $this->highlight_extra_lines = array();
  1298. +
  1299.     }
  1300. +
  1301.  
  1302. +
  1303. /**    
  1304. +
  1305.      * Sets the language for this object
  1306. +
  1307.      *
  1308. +
  1309.      * @note since 1.0.8 this function won't reset language-settings by default anymore!
  1310. +
  1311.      *        if you need this set $force_reset = true
  1312. +
  1313.      *
  1314. +
  1315.      * @param string The name of the language to use
  1316. +
  1317.      * @since 1.0.0
  1318. +
  1319.      */
  1320. +
  1321.     function set_language($language, $force_reset = false) {
  1322. +
  1323.         if ($force_reset) {
  1324. +
  1325.             $this->loaded_language = false;
  1326. +
  1327.         }
  1328. +
  1329.  
  1330. +
  1331.         //Clean up the language name to prevent malicious code injection
  1332. +
  1333.         $language = preg_replace('#[^a-zA-Z0-9\-_]#', '', $language);
  1334. +
  1335.  
  1336. +
  1337.         $language = strtolower($language);
  1338. +
  1339.  
  1340. +
  1341.         //Retreive the full filename
  1342. +
  1343.         $file_name = $this->language_path . $language . '.php';
  1344. +
  1345.         if ($file_name == $this->loaded_language) {
  1346. +
  1347.             // this language is already loaded!
  1348. +
  1349.             return;
  1350. +
  1351.         }
  1352. +
  1353.  
  1354. +
  1355.         $this->language = $language;
  1356. +
  1357.  
  1358. +
  1359.         $this->error = false;
  1360. +
  1361.         $this->strict_mode = GESHI_NEVER;
  1362. +
  1363.  
  1364. +
  1365.         //Check if we can read the desired file
  1366. +
  1367.         if (!is_readable($file_name)) {
  1368. +
  1369.             $this->error = GESHI_ERROR_NO_SUCH_LANG;
  1370. +
  1371.             return;
  1372. +
  1373.         }
  1374. +
  1375.  
  1376. +
  1377.         // Load the language for parsing
  1378. +
  1379.         $this->load_language($file_name);
  1380. +
  1381.     }
  1382. +
  1383.  
  1384. +
  1385. /**    
  1386. +
  1387.      * Sets the path to the directory containing the language files. Note
  1388. +
  1389.      * that this path is relative to the directory of the script that included
  1390. +
  1391.      * geshi.php, NOT geshi.php itself.
  1392. +
  1393.      *
  1394. +
  1395.      * @param string The path to the language directory
  1396. +
  1397.      * @since 1.0.0
  1398. +
  1399.      * @deprecated The path to the language files should now be automatically
  1400. +
  1401.      *              detected, so this method should no longer be needed. The
  1402. +
  1403.      *              1.1.X branch handles manual setting of the path differently
  1404. +
  1405.      *              so this method will disappear in 1.2.0.
  1406. +
  1407.      */
  1408. +
  1409.     function set_language_path($path) {
  1410. +
  1411.         if(strpos($path,':')) {
  1412. +
  1413.             //Security Fix to prevent external directories using fopen wrappers.
  1414. +
  1415.             if(DIRECTORY_SEPARATOR == "\\") {
  1416. +
  1417.                 if(!preg_match('#^[a-zA-Z]:#', $path) || false !== strpos($path, ':', 2)) {
  1418. +
  1419.                     return;
  1420. +
  1421.                 }
  1422. +
  1423.             } else {
  1424. +
  1425.                 return;
  1426. +
  1427.             }
  1428. +
  1429.         }
  1430. +
  1431.         if(preg_match('#[^/a-zA-Z0-9_\.\-\\\s:]#', $path)) {
  1432. +
  1433.             //Security Fix to prevent external directories using fopen wrappers.
  1434. +
  1435.             return;
  1436. +
  1437.         }
  1438. +
  1439.         if(<a href="../geshi/core/_geshi.php.html#defineGESHI_SECURITY_PARANOID">GESHI_SECURITY_PARANOID</a> && false !== strpos($path, '/.')) {
  1440. +
  1441.             //Security Fix to prevent external directories using fopen wrappers.
  1442. +
  1443.             return;
  1444. +
  1445.         }
  1446. +
  1447.         if(<a href="../geshi/core/_geshi.php.html#defineGESHI_SECURITY_PARANOID">GESHI_SECURITY_PARANOID</a> && false !== strpos($path, '..')) {
  1448. +
  1449.             //Security Fix to prevent external directories using fopen wrappers.
  1450. +
  1451.             return;
  1452. +
  1453.         }
  1454. +
  1455.         if ($path) {
  1456. +
  1457.             $this->language_path = ('/' == $path[strlen($path) - 1]) ? $path : $path . '/';
  1458. +
  1459.             $this->set_language($this->language); // otherwise set_language_path has no effect
  1460. +
  1461.         }
  1462. +
  1463.     }
  1464. +
  1465.  
  1466. +
  1467. /**    
  1468. +
  1469.      * Sets the type of header to be used.
  1470. +
  1471.      *
  1472. +
  1473.      * If GESHI_HEADER_DIV is used, the code is surrounded in a "div".This
  1474. +
  1475.      * means more source code but more control over tab width and line-wrapping.
  1476. +
  1477.      * GESHI_HEADER_PRE means that a "pre" is used - less source, but less
  1478. +
  1479.      * control. Default is GESHI_HEADER_PRE.
  1480. +
  1481.      *
  1482. +
  1483.      * From 1.0.7.2, you can use GESHI_HEADER_NONE to specify that no header code
  1484. +
  1485.      * should be outputted.
  1486. +
  1487.      *
  1488. +
  1489.      * @param int The type of header to be used
  1490. +
  1491.      * @since 1.0.0
  1492. +
  1493.      */
  1494. +
  1495.     function set_header_type($type) {
  1496. +
  1497.         //Check if we got a valid header type
  1498. +
  1499.         if (!in_array($type, array(<a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_NONE">GESHI_HEADER_NONE</a>, <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_DIV">GESHI_HEADER_DIV</a>,
  1500. +
  1501.             <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE">GESHI_HEADER_PRE</a>, <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a>, <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_TABLE">GESHI_HEADER_PRE_TABLE</a>))) {
  1502. +
  1503.             $this->error = GESHI_ERROR_INVALID_HEADER_TYPE;
  1504. +
  1505.             return;
  1506. +
  1507.         }
  1508. +
  1509.  
  1510. +
  1511.         //Set that new header type
  1512. +
  1513.         $this->header_type = $type;
  1514. +
  1515.     }
  1516. +
  1517.  
  1518. +
  1519. /**    
  1520. +
  1521.      * Sets the styles for the code that will be outputted
  1522. +
  1523.      * when this object is parsed. The style should be a
  1524. +
  1525.      * string of valid stylesheet declarations
  1526. +
  1527.      *
  1528. +
  1529.      * @param string  The overall style for the outputted code block
  1530. +
  1531.      * @param boolean Whether to merge the styles with the current styles or not
  1532. +
  1533.      * @since 1.0.0
  1534. +
  1535.      */
  1536. +
  1537.     function set_overall_style($style, $preserve_defaults = false) {
  1538. +
  1539.         if (!$preserve_defaults) {
  1540. +
  1541.             $this->overall_style = $style;
  1542. +
  1543.         } else {
  1544. +
  1545.             $this->overall_style .= $style;
  1546. +
  1547.         }
  1548. +
  1549.     }
  1550. +
  1551.  
  1552. +
  1553. /**    
  1554. +
  1555.      * Sets the overall classname for this block of code. This
  1556. +
  1557.      * class can then be used in a stylesheet to style this object's
  1558. +
  1559.      * output
  1560. +
  1561.      *
  1562. +
  1563.      * @param string The class name to use for this block of code
  1564. +
  1565.      * @since 1.0.0
  1566. +
  1567.      */
  1568. +
  1569.     function set_overall_class($class) {
  1570. +
  1571.         $this->overall_class = $class;
  1572. +
  1573.     }
  1574. +
  1575.  
  1576. +
  1577. /**    
  1578. +
  1579.      * Sets the overall id for this block of code. This id can then
  1580. +
  1581.      * be used in a stylesheet to style this object's output
  1582. +
  1583.      *
  1584. +
  1585.      * @param string The ID to use for this block of code
  1586. +
  1587.      * @since 1.0.0
  1588. +
  1589.      */
  1590. +
  1591.     function set_overall_id($id) {
  1592. +
  1593.         $this->overall_id = $id;
  1594. +
  1595.     }
  1596. +
  1597.  
  1598. +
  1599. /**    
  1600. +
  1601.      * Sets whether CSS classes should be used to highlight the source. Default
  1602. +
  1603.      * is off, calling this method with no arguments will turn it on
  1604. +
  1605.      *
  1606. +
  1607.      * @param boolean Whether to turn classes on or not
  1608. +
  1609.      * @since 1.0.0
  1610. +
  1611.      */
  1612. +
  1613.     function enable_classes($flag = true) {
  1614. +
  1615.         $this->use_classes = ($flag) ? true : false;
  1616. +
  1617.     }
  1618. +
  1619.  
  1620. +
  1621. /**    
  1622. +
  1623.      * Sets the style for the actual code. This should be a string
  1624. +
  1625.      * containing valid stylesheet declarations. If $preserve_defaults is
  1626. +
  1627.      * true, then styles are merged with the default styles, with the
  1628. +
  1629.      * user defined styles having priority
  1630. +
  1631.      *
  1632. +
  1633.      * Note: Use this method to override any style changes you made to
  1634. +
  1635.      * the line numbers if you are using line numbers, else the line of
  1636. +
  1637.      * code will have the same style as the line number! Consult the
  1638. +
  1639.      * GeSHi documentation for more information about this.
  1640. +
  1641.      *
  1642. +
  1643.      * @param string  The style to use for actual code
  1644. +
  1645.      * @param boolean Whether to merge the current styles with the new styles
  1646. +
  1647.      * @since 1.0.2
  1648. +
  1649.      */
  1650. +
  1651.     function set_code_style($style, $preserve_defaults = false) {
  1652. +
  1653.         if (!$preserve_defaults) {
  1654. +
  1655.             $this->code_style = $style;
  1656. +
  1657.         } else {
  1658. +
  1659.             $this->code_style .= $style;
  1660. +
  1661.         }
  1662. +
  1663.     }
  1664. +
  1665.  
  1666. +
  1667. /**    
  1668. +
  1669.      * Sets the styles for the line numbers.
  1670. +
  1671.      *
  1672. +
  1673.      * @param string The style for the line numbers that are "normal"
  1674. +
  1675.      * @param string|booleanIf a string, this is the style of the line
  1676. +
  1677.      *         numbers that are "fancy", otherwise if boolean then this
  1678. +
  1679.      *         defines whether the normal styles should be merged with the
  1680. +
  1681.      *         new normal styles or not
  1682. +
  1683.      * @param boolean If set, is the flag for whether to merge the "fancy"
  1684. +
  1685.      *         styles with the current styles or not
  1686. +
  1687.      * @since 1.0.2
  1688. +
  1689.      */
  1690. +
  1691.     function set_line_style($style1, $style2 = '', $preserve_defaults = false) {
  1692. +
  1693.         //Check if we got 2 or three parameters
  1694. +
  1695.         if (is_bool($style2)) {
  1696. +
  1697.             $preserve_defaults = $style2;
  1698. +
  1699.             $style2 = '';
  1700. +
  1701.         }
  1702. +
  1703.  
  1704. +
  1705.         //Actually set the new styles
  1706. +
  1707.         if (!$preserve_defaults) {
  1708. +
  1709.             $this->line_style1 = $style1;
  1710. +
  1711.             $this->line_style2 = $style2;
  1712. +
  1713.         } else {
  1714. +
  1715.             $this->line_style1 .= $style1;
  1716. +
  1717.             $this->line_style2 .= $style2;
  1718. +
  1719.         }
  1720. +
  1721.     }
  1722. +
  1723.  
  1724. +
  1725. /**    
  1726. +
  1727.      * Sets whether line numbers should be displayed.
  1728. +
  1729.      *
  1730. +
  1731.      * Valid values for the first parameter are:
  1732. +
  1733.      *
  1734. +
  1735.      *  - GESHI_NO_LINE_NUMBERS: Line numbers will not be displayed
  1736. +
  1737.      *  - GESHI_NORMAL_LINE_NUMBERS: Line numbers will be displayed
  1738. +
  1739.      *  - GESHI_FANCY_LINE_NUMBERS: Fancy line numbers will be displayed
  1740. +
  1741.      *
  1742. +
  1743.      * For fancy line numbers, the second parameter is used to signal which lines
  1744. +
  1745.      * are to be fancy. For example, if the value of this parameter is 5 then every
  1746. +
  1747.      * 5th line will be fancy.
  1748. +
  1749.      *
  1750. +
  1751.      * @param int How line numbers should be displayed
  1752. +
  1753.      * @param int Defines which lines are fancy
  1754. +
  1755.      * @since 1.0.0
  1756. +
  1757.      */
  1758. +
  1759.     function enable_line_numbers($flag, $nth_row = 5) {
  1760. +
  1761.         if (<a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a> != $flag && <a href="../geshi/core/_geshi.php.html#defineGESHI_NORMAL_LINE_NUMBERS">GESHI_NORMAL_LINE_NUMBERS</a> != $flag
  1762. +
  1763.             && <a href="../geshi/core/_geshi.php.html#defineGESHI_FANCY_LINE_NUMBERS">GESHI_FANCY_LINE_NUMBERS</a> != $flag) {
  1764. +
  1765.             $this->error = GESHI_ERROR_INVALID_LINE_NUMBER_TYPE;
  1766. +
  1767.         }
  1768. +
  1769.         $this->line_numbers = $flag;
  1770. +
  1771.         $this->line_nth_row = $nth_row;
  1772. +
  1773.     }
  1774. +
  1775.  
  1776. +
  1777. /**    
  1778. +
  1779.      * Sets wether spans and other HTML markup generated by GeSHi can
  1780. +
  1781.      * span over multiple lines or not. Defaults to true to reduce overhead.
  1782. +
  1783.      * Set it to false if you want to manipulate the output or manually display
  1784. +
  1785.      * the code in an ordered list.
  1786. +
  1787.      *
  1788. +
  1789.      * @param boolean Wether multiline spans are allowed or not
  1790. +
  1791.      * @since 1.0.7.22
  1792. +
  1793.      */
  1794. +
  1795.     function enable_multiline_span($flag) {
  1796. +
  1797.         $this->allow_multiline_span = (bool) $flag;
  1798. +
  1799.     }
  1800. +
  1801.  
  1802. +
  1803. /**    
  1804. +
  1805.      * Get current setting for multiline spans, see GeSHi->enable_multiline_span().
  1806. +
  1807.      *
  1808. +
  1809.      * @see enable_multiline_span
  1810. +
  1811.      * @return bool 
  1812. +
  1813.      */
  1814. +
  1815.     function get_multiline_span() {
  1816. +
  1817.         return $this->allow_multiline_span;
  1818. +
  1819.     }
  1820. +
  1821.  
  1822. +
  1823. /**    
  1824. +
  1825.      * Sets the style for a keyword group. If $preserve_defaults is
  1826. +
  1827.      * true, then styles are merged with the default styles, with the
  1828. +
  1829.      * user defined styles having priority
  1830. +
  1831.      *
  1832. +
  1833.      * @param int     The key of the keyword group to change the styles of
  1834. +
  1835.      * @param string  The style to make the keywords
  1836. +
  1837.      * @param boolean Whether to merge the new styles with the old or just
  1838. +
  1839.      *                 to overwrite them
  1840. +
  1841.      * @since 1.0.0
  1842. +
  1843.      */
  1844. +
  1845.     function set_keyword_group_style($key, $style, $preserve_defaults = false) {
  1846. +
  1847.         //Set the style for this keyword group
  1848. +
  1849.         if (!$preserve_defaults) {
  1850. +
  1851.             $this->language_data['STYLES']['KEYWORDS'][$key] = $style;
  1852. +
  1853.         } else {
  1854. +
  1855.             $this->language_data['STYLES']['KEYWORDS'][$key] .= $style;
  1856. +
  1857.         }
  1858. +
  1859.  
  1860. +
  1861.         //Update the lexic permissions
  1862. +
  1863.         if (!isset($this->lexic_permissions['KEYWORDS'][$key])) {
  1864. +
  1865.             $this->lexic_permissions['KEYWORDS'][$key] = true;
  1866. +
  1867.         }
  1868. +
  1869.     }
  1870. +
  1871.  
  1872. +
  1873. /**    
  1874. +
  1875.      * Turns highlighting on/off for a keyword group
  1876. +
  1877.      *
  1878. +
  1879.      * @param int     The key of the keyword group to turn on or off
  1880. +
  1881.      * @param boolean Whether to turn highlighting for that group on or off
  1882. +
  1883.      * @since 1.0.0
  1884. +
  1885.      */
  1886. +
  1887.     function set_keyword_group_highlighting($key, $flag = true) {
  1888. +
  1889.         $this->lexic_permissions['KEYWORDS'][$key] = ($flag) ? true : false;
  1890. +
  1891.     }
  1892. +
  1893.  
  1894. +
  1895. /**    
  1896. +
  1897.      * Sets the styles for comment groups.  If $preserve_defaults is
  1898. +
  1899.      * true, then styles are merged with the default styles, with the
  1900. +
  1901.      * user defined styles having priority
  1902. +
  1903.      *
  1904. +
  1905.      * @param int     The key of the comment group to change the styles of
  1906. +
  1907.      * @param string  The style to make the comments
  1908. +
  1909.      * @param boolean Whether to merge the new styles with the old or just
  1910. +
  1911.      *                 to overwrite them
  1912. +
  1913.      * @since 1.0.0
  1914. +
  1915.      */
  1916. +
  1917.     function set_comments_style($key, $style, $preserve_defaults = false) {
  1918. +
  1919.         if (!$preserve_defaults) {
  1920. +
  1921.             $this->language_data['STYLES']['COMMENTS'][$key] = $style;
  1922. +
  1923.         } else {
  1924. +
  1925.             $this->language_data['STYLES']['COMMENTS'][$key] .= $style;
  1926. +
  1927.         }
  1928. +
  1929.     }
  1930. +
  1931.  
  1932. +
  1933. /**    
  1934. +
  1935.      * Turns highlighting on/off for comment groups
  1936. +
  1937.      *
  1938. +
  1939.      * @param int     The key of the comment group to turn on or off
  1940. +
  1941.      * @param boolean Whether to turn highlighting for that group on or off
  1942. +
  1943.      * @since 1.0.0
  1944. +
  1945.      */
  1946. +
  1947.     function set_comments_highlighting($key, $flag = true) {
  1948. +
  1949.         $this->lexic_permissions['COMMENTS'][$key] = ($flag) ? true : false;
  1950. +
  1951.     }
  1952. +
  1953.  
  1954. +
  1955. /**    
  1956. +
  1957.      * Sets the styles for escaped characters. If $preserve_defaults is
  1958. +
  1959.      * true, then styles are merged with the default styles, with the
  1960. +
  1961.      * user defined styles having priority
  1962. +
  1963.      *
  1964. +
  1965.      * @param string  The style to make the escape characters
  1966. +
  1967.      * @param boolean Whether to merge the new styles with the old or just
  1968. +
  1969.      *                 to overwrite them
  1970. +
  1971.      * @since 1.0.0
  1972. +
  1973.      */
  1974. +
  1975.     function set_escape_characters_style($style, $preserve_defaults = false) {
  1976. +
  1977.         if (!$preserve_defaults) {
  1978. +
  1979.             $this->language_data['STYLES']['ESCAPE_CHAR'][0] = $style;
  1980. +
  1981.         } else {
  1982. +
  1983.             $this->language_data['STYLES']['ESCAPE_CHAR'][0] .= $style;
  1984. +
  1985.         }
  1986. +
  1987.     }
  1988. +
  1989.  
  1990. +
  1991. /**    
  1992. +
  1993.      * Turns highlighting on/off for escaped characters
  1994. +
  1995.      *
  1996. +
  1997.      * @param boolean Whether to turn highlighting for escape characters on or off
  1998. +
  1999.      * @since 1.0.0
  2000. +
  2001.      */
  2002. +
  2003.     function set_escape_characters_highlighting($flag = true) {
  2004. +
  2005.         $this->lexic_permissions['ESCAPE_CHAR'] = ($flag) ? true : false;
  2006. +
  2007.     }
  2008. +
  2009.  
  2010. +
  2011. /**    
  2012. +
  2013.      * Sets the styles for brackets. If $preserve_defaults is
  2014. +
  2015.      * true, then styles are merged with the default styles, with the
  2016. +
  2017.      * user defined styles having priority
  2018. +
  2019.      *
  2020. +
  2021.      * This method is DEPRECATED: use set_symbols_style instead.
  2022. +
  2023.      * This method will be removed in 1.2.X
  2024. +
  2025.      *
  2026. +
  2027.      * @param string  The style to make the brackets
  2028. +
  2029.      * @param boolean Whether to merge the new styles with the old or just
  2030. +
  2031.      *                 to overwrite them
  2032. +
  2033.      * @since 1.0.0
  2034. +
  2035.      * @deprecated In favour of set_symbols_style
  2036. +
  2037.      */
  2038. +
  2039.     function set_brackets_style($style, $preserve_defaults = false) {
  2040. +
  2041.         if (!$preserve_defaults) {
  2042. +
  2043.             $this->language_data['STYLES']['BRACKETS'][0] = $style;
  2044. +
  2045.         } else {
  2046. +
  2047.             $this->language_data['STYLES']['BRACKETS'][0] .= $style;
  2048. +
  2049.         }
  2050. +
  2051.     }
  2052. +
  2053.  
  2054. +
  2055. /**    
  2056. +
  2057.      * Turns highlighting on/off for brackets
  2058. +
  2059.      *
  2060. +
  2061.      * This method is DEPRECATED: use set_symbols_highlighting instead.
  2062. +
  2063.      * This method will be remove in 1.2.X
  2064. +
  2065.      *
  2066. +
  2067.      * @param boolean Whether to turn highlighting for brackets on or off
  2068. +
  2069.      * @since 1.0.0
  2070. +
  2071.      * @deprecated In favour of set_symbols_highlighting
  2072. +
  2073.      */
  2074. +
  2075.     function set_brackets_highlighting($flag) {
  2076. +
  2077.         $this->lexic_permissions['BRACKETS'] = ($flag) ? true : false;
  2078. +
  2079.     }
  2080. +
  2081.  
  2082. +
  2083. /**    
  2084. +
  2085.      * Sets the styles for symbols. If $preserve_defaults is
  2086. +
  2087.      * true, then styles are merged with the default styles, with the
  2088. +
  2089.      * user defined styles having priority
  2090. +
  2091.      *
  2092. +
  2093.      * @param string  The style to make the symbols
  2094. +
  2095.      * @param boolean Whether to merge the new styles with the old or just
  2096. +
  2097.      *                 to overwrite them
  2098. +
  2099.      * @param int     Tells the group of symbols for which style should be set.
  2100. +
  2101.      * @since 1.0.1
  2102. +
  2103.      */
  2104. +
  2105.     function set_symbols_style($style, $preserve_defaults = false, $group = 0) {
  2106. +
  2107.         // Update the style of symbols
  2108. +
  2109.         if (!$preserve_defaults) {
  2110. +
  2111.             $this->language_data['STYLES']['SYMBOLS'][$group] = $style;
  2112. +
  2113.         } else {
  2114. +
  2115.             $this->language_data['STYLES']['SYMBOLS'][$group] .= $style;
  2116. +
  2117.         }
  2118. +
  2119.  
  2120. +
  2121.         // For backward compatibility
  2122. +
  2123.         if (0 == $group) {
  2124. +
  2125.             $this->set_brackets_style ($style, $preserve_defaults);
  2126. +
  2127.         }
  2128. +
  2129.     }
  2130. +
  2131.  
  2132. +
  2133. /**    
  2134. +
  2135.      * Turns highlighting on/off for symbols
  2136. +
  2137.      *
  2138. +
  2139.      * @param boolean Whether to turn highlighting for symbols on or off
  2140. +
  2141.      * @since 1.0.0
  2142. +
  2143.      */
  2144. +
  2145.     function set_symbols_highlighting($flag) {
  2146. +
  2147.         // Update lexic permissions for this symbol group
  2148. +
  2149.         $this->lexic_permissions['SYMBOLS'] = ($flag) ? true : false;
  2150. +
  2151.  
  2152. +
  2153.         // For backward compatibility
  2154. +
  2155.         $this->set_brackets_highlighting ($flag);
  2156. +
  2157.     }
  2158. +
  2159.  
  2160. +
  2161. /**    
  2162. +
  2163.      * Sets the styles for strings. If $preserve_defaults is
  2164. +
  2165.      * true, then styles are merged with the default styles, with the
  2166. +
  2167.      * user defined styles having priority
  2168. +
  2169.      *
  2170. +
  2171.      * @param string  The style to make the escape characters
  2172. +
  2173.      * @param boolean Whether to merge the new styles with the old or just
  2174. +
  2175.      *                 to overwrite them
  2176. +
  2177.      * @since 1.0.0
  2178. +
  2179.      */
  2180. +
  2181.     function set_strings_style($style, $preserve_defaults = false) {
  2182. +
  2183.         if (!$preserve_defaults) {
  2184. +
  2185.             $this->language_data['STYLES']['STRINGS'][0] = $style;
  2186. +
  2187.         } else {
  2188. +
  2189.             $this->language_data['STYLES']['STRINGS'][0] .= $style;
  2190. +
  2191.         }
  2192. +
  2193.     }
  2194. +
  2195.  
  2196. +
  2197. /**    
  2198. +
  2199.      * Turns highlighting on/off for strings
  2200. +
  2201.      *
  2202. +
  2203.      * @param boolean Whether to turn highlighting for strings on or off
  2204. +
  2205.      * @since 1.0.0
  2206. +
  2207.      */
  2208. +
  2209.     function set_strings_highlighting($flag) {
  2210. +
  2211.         $this->lexic_permissions['STRINGS'] = ($flag) ? true : false;
  2212. +
  2213.     }
  2214. +
  2215.  
  2216. +
  2217. /**    
  2218. +
  2219.      * Sets the styles for numbers. If $preserve_defaults is
  2220. +
  2221.      * true, then styles are merged with the default styles, with the
  2222. +
  2223.      * user defined styles having priority
  2224. +
  2225.      *
  2226. +
  2227.      * @param string  The style to make the numbers
  2228. +
  2229.      * @param boolean Whether to merge the new styles with the old or just
  2230. +
  2231.      *                 to overwrite them
  2232. +
  2233.      * @since 1.0.0
  2234. +
  2235.      */
  2236. +
  2237.     function set_numbers_style($style, $preserve_defaults = false) {
  2238. +
  2239.         if (!$preserve_defaults) {
  2240. +
  2241.             $this->language_data['STYLES']['NUMBERS'][0] = $style;
  2242. +
  2243.         } else {
  2244. +
  2245.             $this->language_data['STYLES']['NUMBERS'][0] .= $style;
  2246. +
  2247.         }
  2248. +
  2249.     }
  2250. +
  2251.  
  2252. +
  2253. /**    
  2254. +
  2255.      * Turns highlighting on/off for numbers
  2256. +
  2257.      *
  2258. +
  2259.      * @param boolean Whether to turn highlighting for numbers on or off
  2260. +
  2261.      * @since 1.0.0
  2262. +
  2263.      */
  2264. +
  2265.     function set_numbers_highlighting($flag) {
  2266. +
  2267.         $this->lexic_permissions['NUMBERS'] = ($flag) ? true : false;
  2268. +
  2269.     }
  2270. +
  2271.  
  2272. +
  2273. /**    
  2274. +
  2275.      * Sets the styles for methods. $key is a number that references the
  2276. +
  2277.      * appropriate "object splitter" - see the language file for the language
  2278. +
  2279.      * you are highlighting to get this number. If $preserve_defaults is
  2280. +
  2281.      * true, then styles are merged with the default styles, with the
  2282. +
  2283.      * user defined styles having priority
  2284. +
  2285.      *
  2286. +
  2287.      * @param int     The key of the object splitter to change the styles of
  2288. +
  2289.      * @param string  The style to make the methods
  2290. +
  2291.      * @param boolean Whether to merge the new styles with the old or just
  2292. +
  2293.      *                 to overwrite them
  2294. +
  2295.      * @since 1.0.0
  2296. +
  2297.      */
  2298. +
  2299.     function set_methods_style($key, $style, $preserve_defaults = false) {
  2300. +
  2301.         if (!$preserve_defaults) {
  2302. +
  2303.             $this->language_data['STYLES']['METHODS'][$key] = $style;
  2304. +
  2305.         } else {
  2306. +
  2307.             $this->language_data['STYLES']['METHODS'][$key] .= $style;
  2308. +
  2309.         }
  2310. +
  2311.     }
  2312. +
  2313.  
  2314. +
  2315. /**    
  2316. +
  2317.      * Turns highlighting on/off for methods
  2318. +
  2319.      *
  2320. +
  2321.      * @param boolean Whether to turn highlighting for methods on or off
  2322. +
  2323.      * @since 1.0.0
  2324. +
  2325.      */
  2326. +
  2327.     function set_methods_highlighting($flag) {
  2328. +
  2329.         $this->lexic_permissions['METHODS'] = ($flag) ? true : false;
  2330. +
  2331.     }
  2332. +
  2333.  
  2334. +
  2335. /**    
  2336. +
  2337.      * Sets the styles for regexps. If $preserve_defaults is
  2338. +
  2339.      * true, then styles are merged with the default styles, with the
  2340. +
  2341.      * user defined styles having priority
  2342. +
  2343.      *
  2344. +
  2345.      * @param string  The style to make the regular expression matches
  2346. +
  2347.      * @param boolean Whether to merge the new styles with the old or just
  2348. +
  2349.      *                 to overwrite them
  2350. +
  2351.      * @since 1.0.0
  2352. +
  2353.      */
  2354. +
  2355.     function set_regexps_style($key, $style, $preserve_defaults = false) {
  2356. +
  2357.         if (!$preserve_defaults) {
  2358. +
  2359.             $this->language_data['STYLES']['REGEXPS'][$key] = $style;
  2360. +
  2361.         } else {
  2362. +
  2363.             $this->language_data['STYLES']['REGEXPS'][$key] .= $style;
  2364. +
  2365.         }
  2366. +
  2367.     }
  2368. +
  2369.  
  2370. +
  2371. /**    
  2372. +
  2373.      * Turns highlighting on/off for regexps
  2374. +
  2375.      *
  2376. +
  2377.      * @param int     The key of the regular expression group to turn on or off
  2378. +
  2379.      * @param boolean Whether to turn highlighting for the regular expression group on or off
  2380. +
  2381.      * @since 1.0.0
  2382. +
  2383.      */
  2384. +
  2385.     function set_regexps_highlighting($key, $flag) {
  2386. +
  2387.         $this->lexic_permissions['REGEXPS'][$key] = ($flag) ? true : false;
  2388. +
  2389.     }
  2390. +
  2391.  
  2392. +
  2393. /**    
  2394. +
  2395.      * Sets whether a set of keywords are checked for in a case sensitive manner
  2396. +
  2397.      *
  2398. +
  2399.      * @param int The key of the keyword group to change the case sensitivity of
  2400. +
  2401.      * @param boolean Whether to check in a case sensitive manner or not
  2402. +
  2403.      * @since 1.0.0
  2404. +
  2405.      */
  2406. +
  2407.     function set_case_sensitivity($key, $case) {
  2408. +
  2409.         $this->language_data['CASE_SENSITIVE'][$key] = ($case) ? true : false;
  2410. +
  2411.     }
  2412. +
  2413.  
  2414. +
  2415. /**    
  2416. +
  2417.      * Sets the case that keywords should use when found. Use the constants:
  2418. +
  2419.      *
  2420. +
  2421.      *  - GESHI_CAPS_NO_CHANGE: leave keywords as-is
  2422. +
  2423.      *  - GESHI_CAPS_UPPER: convert all keywords to uppercase where found
  2424. +
  2425.      *  - GESHI_CAPS_LOWER: convert all keywords to lowercase where found
  2426. +
  2427.      *
  2428. +
  2429.      * @param int A constant specifying what to do with matched keywords
  2430. +
  2431.      * @since 1.0.1
  2432. +
  2433.      */
  2434. +
  2435.     function set_case_keywords($case) {
  2436. +
  2437.         if (in_array($case, array(
  2438. +
  2439.             <a href="../geshi/core/_geshi.php.html#defineGESHI_CAPS_NO_CHANGE">GESHI_CAPS_NO_CHANGE</a>, <a href="../geshi/core/_geshi.php.html#defineGESHI_CAPS_UPPER">GESHI_CAPS_UPPER</a>, <a href="../geshi/core/_geshi.php.html#defineGESHI_CAPS_LOWER">GESHI_CAPS_LOWER</a>))) {
  2440. +
  2441.             $this->language_data['CASE_KEYWORDS'] = $case;
  2442. +
  2443.         }
  2444. +
  2445.     }
  2446. +
  2447.  
  2448. +
  2449. /**    
  2450. +
  2451.      * Sets how many spaces a tab is substituted for
  2452. +
  2453.      *
  2454. +
  2455.      * Widths below zero are ignored
  2456. +
  2457.      *
  2458. +
  2459.      * @param int The tab width
  2460. +
  2461.      * @since 1.0.0
  2462. +
  2463.      */
  2464. +
  2465.     function set_tab_width($width) {
  2466. +
  2467.         $this->tab_width = intval($width);
  2468. +
  2469.  
  2470. +
  2471.         //Check if it fit's the constraints:
  2472. +
  2473.         if ($this->tab_width < 1) {
  2474. +
  2475.             //Return it to the default
  2476. +
  2477.             $this->tab_width = 8;
  2478. +
  2479.         }
  2480. +
  2481.     }
  2482. +
  2483.  
  2484. +
  2485. /**    
  2486. +
  2487.      * Sets whether or not to use tab-stop width specifed by language
  2488. +
  2489.      *
  2490. +
  2491.      * @param boolean Whether to use language-specific tab-stop widths
  2492. +
  2493.      * @since 1.0.7.20
  2494. +
  2495.      */
  2496. +
  2497.     function set_use_language_tab_width($use) {
  2498. +
  2499.         $this->use_language_tab_width = (bool) $use;
  2500. +
  2501.     }
  2502. +
  2503.  
  2504. +
  2505. /**    
  2506. +
  2507.      * Returns the tab width to use, based on the current language and user
  2508. +
  2509.      * preference
  2510. +
  2511.      *
  2512. +
  2513.      * @return int Tab width
  2514. +
  2515.      * @since 1.0.7.20
  2516. +
  2517.      */
  2518. +
  2519.     function get_real_tab_width() {
  2520. +
  2521.         if (!$this->use_language_tab_width ||
  2522. +
  2523.             !isset($this->language_data['TAB_WIDTH'])) {
  2524. +
  2525.             return $this->tab_width;
  2526. +
  2527.         } else {
  2528. +
  2529.             return $this->language_data['TAB_WIDTH'];
  2530. +
  2531.         }
  2532. +
  2533.     }
  2534. +
  2535.  
  2536. +
  2537. /**    
  2538. +
  2539.      * Enables/disables strict highlighting. Default is off, calling this
  2540. +
  2541.      * method without parameters will turn it on. See documentation
  2542. +
  2543.      * for more details on strict mode and where to use it.
  2544. +
  2545.      *
  2546. +
  2547.      * @param boolean Whether to enable strict mode or not
  2548. +
  2549.      * @since 1.0.0
  2550. +
  2551.      */
  2552. +
  2553.     function enable_strict_mode($mode = true) {
  2554. +
  2555.         if (GESHI_MAYBE == $this->language_data['STRICT_MODE_APPLIES']) {
  2556. +
  2557.             $this->strict_mode = ($mode) ? GESHI_ALWAYS : GESHI_NEVER;
  2558. +
  2559.         }
  2560. +
  2561.     }
  2562. +
  2563.  
  2564. +
  2565. /**    
  2566. +
  2567.      * Disables all highlighting
  2568. +
  2569.      *
  2570. +
  2571.      * @since 1.0.0
  2572. +
  2573.      * @todo  Rewrite with array traversal
  2574. +
  2575.      * @deprecated In favour of enable_highlighting
  2576. +
  2577.      */
  2578. +
  2579.     function disable_highlighting() {
  2580. +
  2581.         $this->enable_highlighting(false);
  2582. +
  2583.     }
  2584. +
  2585.  
  2586. +
  2587. /**    
  2588. +
  2589.      * Enables all highlighting
  2590. +
  2591.      *
  2592. +
  2593.      * The optional flag parameter was added in version 1.0.7.21 and can be used
  2594. +
  2595.      * to enable (true) or disable (false) all highlighting.
  2596. +
  2597.      *
  2598. +
  2599.      * @since 1.0.0
  2600. +
  2601.      * @param boolean A flag specifying whether to enable or disable all highlighting
  2602. +
  2603.      * @todo  Rewrite with array traversal
  2604. +
  2605.      */
  2606. +
  2607.     function enable_highlighting($flag = true) {
  2608. +
  2609.         $flag = $flag ? true : false;
  2610. +
  2611.         foreach ($this->lexic_permissions as $key => $value) {
  2612. +
  2613.             if (is_array($value)) {
  2614. +
  2615.                 foreach ($value as $k => $v) {
  2616. +
  2617.                     $this->lexic_permissions[$key][$k] = $flag;
  2618. +
  2619.                 }
  2620. +
  2621.             } else {
  2622. +
  2623.                 $this->lexic_permissions[$key] = $flag;
  2624. +
  2625.             }
  2626. +
  2627.         }
  2628. +
  2629.  
  2630. +
  2631.         // Context blocks
  2632. +
  2633.         $this->enable_important_blocks = $flag;
  2634. +
  2635.     }
  2636. +
  2637.  
  2638. +
  2639. /**    
  2640. +
  2641.      * Given a file extension, this method returns either a valid geshi language
  2642. +
  2643.      * name, or the empty string if it couldn't be found
  2644. +
  2645.      *
  2646. +
  2647.      * @param string The extension to get a language name for
  2648. +
  2649.      * @param array  A lookup array to use instead of the default one
  2650. +
  2651.      * @since 1.0.5
  2652. +
  2653.      * @todo Re-think about how this method works (maybe make it private and/or make it
  2654. +
  2655.      *        a extension->lang lookup?)
  2656. +
  2657.      * @todo static?
  2658. +
  2659.      */
  2660. +
  2661.     function get_language_name_from_extension( $extension, $lookup = array() ) {
  2662. +
  2663.         if ( !is_array($lookup) || empty($lookup)) {
  2664. +
  2665.             $lookup = array(
  2666. +
  2667.                 'actionscript' => array('as'),
  2668. +
  2669.                 'ada' => array('a', 'ada', 'adb', 'ads'),
  2670. +
  2671.                 'apache' => array('conf'),
  2672. +
  2673.                 'asm' => array('ash', 'asm', 'inc'),
  2674. +
  2675.                 'asp' => array('asp'),
  2676. +
  2677.                 'bash' => array('sh'),
  2678. +
  2679.                 'bf' => array('bf'),
  2680. +
  2681.                 'c' => array('c', 'h'),
  2682. +
  2683.                 'c_mac' => array('c', 'h'),
  2684. +
  2685.                 'caddcl' => array(),
  2686. +
  2687.                 'cadlisp' => array(),
  2688. +
  2689.                 'cdfg' => array('cdfg'),
  2690. +
  2691.                 'cobol' => array('cbl'),
  2692. +
  2693.                 'cpp' => array('cpp', 'hpp', 'C', 'H', 'CPP', 'HPP'),
  2694. +
  2695.                 'csharp' => array('cs'),
  2696. +
  2697.                 'css' => array('css'),
  2698. +
  2699.                 'd' => array('d'),
  2700. +
  2701.                 'delphi' => array('dpk', 'dpr', 'pp', 'pas'),
  2702. +
  2703.                 'diff' => array('diff', 'patch'),
  2704. +
  2705.                 'dos' => array('bat', 'cmd'),
  2706. +
  2707.                 'gettext' => array('po', 'pot'),
  2708. +
  2709.                 'gml' => array('gml'),
  2710. +
  2711.                 'gnuplot' => array('plt'),
  2712. +
  2713.                 'groovy' => array('groovy'),
  2714. +
  2715.                 'haskell' => array('hs'),
  2716. +
  2717.                 'html4strict' => array('html', 'htm'),
  2718. +
  2719.                 'ini' => array('ini', 'desktop'),
  2720. +
  2721.                 'java' => array('java'),
  2722. +
  2723.                 'javascript' => array('js'),
  2724. +
  2725.                 'klonec' => array('kl1'),
  2726. +
  2727.                 'klonecpp' => array('klx'),
  2728. +
  2729.                 'latex' => array('tex'),
  2730. +
  2731.                 'lisp' => array('lisp'),
  2732. +
  2733.                 'lua' => array('lua'),
  2734. +
  2735.                 'matlab' => array('m'),
  2736. +
  2737.                 'mpasm' => array(),
  2738. +
  2739.                 'mysql' => array('sql'),
  2740. +
  2741.                 'nsis' => array(),
  2742. +
  2743.                 'objc' => array(),
  2744. +
  2745.                 'oobas' => array(),
  2746. +
  2747.                 'oracle8' => array(),
  2748. +
  2749.                 'oracle10' => array(),
  2750. +
  2751.                 'pascal' => array('pas'),
  2752. +
  2753.                 'perl' => array('pl', 'pm'),
  2754. +
  2755.                 'php' => array('php', 'php5', 'phtml', 'phps'),
  2756. +
  2757.                 'povray' => array('pov'),
  2758. +
  2759.                 'providex' => array('pvc', 'pvx'),
  2760. +
  2761.                 'prolog' => array('pl'),
  2762. +
  2763.                 'python' => array('py'),
  2764. +
  2765.                 'qbasic' => array('bi'),
  2766. +
  2767.                 'reg' => array('reg'),
  2768. +
  2769.                 'ruby' => array('rb'),
  2770. +
  2771.                 'sas' => array('sas'),
  2772. +
  2773.                 'scala' => array('scala'),
  2774. +
  2775.                 'scheme' => array('scm'),
  2776. +
  2777.                 'scilab' => array('sci'),
  2778. +
  2779.                 'smalltalk' => array('st'),
  2780. +
  2781.                 'smarty' => array(),
  2782. +
  2783.                 'tcl' => array('tcl'),
  2784. +
  2785.                 'vb' => array('bas'),
  2786. +
  2787.                 'vbnet' => array(),
  2788. +
  2789.                 'visualfoxpro' => array(),
  2790. +
  2791.                 'whitespace' => array('ws'),
  2792. +
  2793.                 'xml' => array('xml', 'svg'),
  2794. +
  2795.                 'z80' => array('z80', 'asm', 'inc')
  2796. +
  2797.             );
  2798. +
  2799.         }
  2800. +
  2801.  
  2802. +
  2803.         foreach ($lookup as $lang => $extensions) {
  2804. +
  2805.             if (in_array($extension, $extensions)) {
  2806. +
  2807.                 return $lang;
  2808. +
  2809.             }
  2810. +
  2811.         }
  2812. +
  2813.         return '';
  2814. +
  2815.     }
  2816. +
  2817.  
  2818. +
  2819. /**    
  2820. +
  2821.      * Given a file name, this method loads its contents in, and attempts
  2822. +
  2823.      * to set the language automatically. An optional lookup table can be
  2824. +
  2825.      * passed for looking up the language name. If not specified a default
  2826. +
  2827.      * table is used
  2828. +
  2829.      *
  2830. +
  2831.      * The language table is in the form
  2832. +
  2833.      * <pre>array(
  2834. +
  2835.      *   'lang_name' => array('extension', 'extension', ...),
  2836. +
  2837.      *   'lang_name' ...
  2838. +
  2839.      * );</pre>
  2840. +
  2841.      *
  2842. +
  2843.      * @param string The filename to load the source from
  2844. +
  2845.      * @param array  A lookup array to use instead of the default one
  2846. +
  2847.      * @todo Complete rethink of this and above method
  2848. +
  2849.      * @since 1.0.5
  2850. +
  2851.      */
  2852. +
  2853.     function load_from_file($file_name, $lookup = array()) {
  2854. +
  2855.         if (is_readable($file_name)) {
  2856. +
  2857.             $this->set_source(file_get_contents($file_name));
  2858. +
  2859.             $this->set_language($this->get_language_name_from_extension(substr(strrchr($file_name, '.'), 1), $lookup));
  2860. +
  2861.         } else {
  2862. +
  2863.             $this->error = GESHI_ERROR_FILE_NOT_READABLE;
  2864. +
  2865.         }
  2866. +
  2867.     }
  2868. +
  2869.  
  2870. +
  2871. /**    
  2872. +
  2873.      * Adds a keyword to a keyword group for highlighting
  2874. +
  2875.      *
  2876. +
  2877.      * @param int    The key of the keyword group to add the keyword to
  2878. +
  2879.      * @param string The word to add to the keyword group
  2880. +
  2881.      * @since 1.0.0
  2882. +
  2883.      */
  2884. +
  2885.     function add_keyword($key, $word) {
  2886. +
  2887.         if (!in_array($word, $this->language_data['KEYWORDS'][$key])) {
  2888. +
  2889.             $this->language_data['KEYWORDS'][$key][] = $word;
  2890. +
  2891.  
  2892. +
  2893.             //NEW in 1.0.8 don't recompile the whole optimized regexp, simply append it
  2894. +
  2895.             if ($this->parse_cache_built) {
  2896. +
  2897.                 $subkey = count($this->language_data['CACHED_KEYWORD_LISTS'][$key]) - 1;
  2898. +
  2899.                 $this->language_data['CACHED_KEYWORD_LISTS'][$key][$subkey] .= '|' . preg_quote($word, '/');
  2900. +
  2901.             }
  2902. +
  2903.         }
  2904. +
  2905.     }
  2906. +
  2907.  
  2908. +
  2909. /**    
  2910. +
  2911.      * Removes a keyword from a keyword group
  2912. +
  2913.      *
  2914. +
  2915.      * @param int    The key of the keyword group to remove the keyword from
  2916. +
  2917.      * @param string The word to remove from the keyword group
  2918. +
  2919.      * @param bool   Wether to automatically recompile the optimized regexp list or not.
  2920. +
  2921.      *                Note: if you set this to false and @see GeSHi->parse_code() was already called once,
  2922. +
  2923.      *                for the current language, you have to manually call @see GeSHi->optimize_keyword_group()
  2924. +
  2925.      *                or the removed keyword will stay in cache and still be highlighted! On the other hand
  2926. +
  2927.      *                it might be too expensive to recompile the regexp list for every removal if you want to
  2928. +
  2929.      *                remove a lot of keywords.
  2930. +
  2931.      * @since 1.0.0
  2932. +
  2933.      */
  2934. +
  2935.     function remove_keyword($key, $word, $recompile = true) {
  2936. +
  2937.         $key_to_remove = array_search($word, $this->language_data['KEYWORDS'][$key]);
  2938. +
  2939.         if ($key_to_remove !== false) {
  2940. +
  2941.             unset($this->language_data['KEYWORDS'][$key][$key_to_remove]);
  2942. +
  2943.  
  2944. +
  2945.             //NEW in 1.0.8, optionally recompile keyword group
  2946. +
  2947.             if ($recompile && $this->parse_cache_built) {
  2948. +
  2949.                 $this->optimize_keyword_group($key);
  2950. +
  2951.             }
  2952. +
  2953.         }
  2954. +
  2955.     }
  2956. +
  2957.  
  2958. +
  2959. /**    
  2960. +
  2961.      * Creates a new keyword group
  2962. +
  2963.      *
  2964. +
  2965.      * @param int    The key of the keyword group to create
  2966. +
  2967.      * @param string The styles for the keyword group
  2968. +
  2969.      * @param boolean Whether the keyword group is case sensitive ornot
  2970. +
  2971.      * @param array  The words to use for the keyword group
  2972. +
  2973.      * @since 1.0.0
  2974. +
  2975.      */
  2976. +
  2977.     function add_keyword_group($key, $styles, $case_sensitive = true, $words = array()) {
  2978. +
  2979.         $words = (array) $words;
  2980. +
  2981.         if  (empty($words)) {
  2982. +
  2983.             // empty word lists mess up highlighting
  2984. +
  2985.             return false;
  2986. +
  2987.         }
  2988. +
  2989.  
  2990. +
  2991.         //Add the new keyword group internally
  2992. +
  2993.         $this->language_data['KEYWORDS'][$key] = $words;
  2994. +
  2995.         $this->lexic_permissions['KEYWORDS'][$key] = true;
  2996. +
  2997.         $this->language_data['CASE_SENSITIVE'][$key] = $case_sensitive;
  2998. +
  2999.         $this->language_data['STYLES']['KEYWORDS'][$key] = $styles;
  3000. +
  3001.  
  3002. +
  3003.         //NEW in 1.0.8, cache keyword regexp
  3004. +
  3005.         if ($this->parse_cache_built) {
  3006. +
  3007.             $this->optimize_keyword_group($key);
  3008. +
  3009.         }
  3010. +
  3011.     }
  3012. +
  3013.  
  3014. +
  3015. /**    
  3016. +
  3017.      * Removes a keyword group
  3018. +
  3019.      *
  3020. +
  3021.      * @param int    The key of the keyword group to remove
  3022. +
  3023.      * @since 1.0.0
  3024. +
  3025.      */
  3026. +
  3027.     function remove_keyword_group ($key) {
  3028. +
  3029.         //Remove the keyword group internally
  3030. +
  3031.         unset($this->language_data['KEYWORDS'][$key]);
  3032. +
  3033.         unset($this->lexic_permissions['KEYWORDS'][$key]);
  3034. +
  3035.         unset($this->language_data['CASE_SENSITIVE'][$key]);
  3036. +
  3037.         unset($this->language_data['STYLES']['KEYWORDS'][$key]);
  3038. +
  3039.  
  3040. +
  3041.         //NEW in 1.0.8
  3042. +
  3043.         unset($this->language_data['CACHED_KEYWORD_LISTS'][$key]);
  3044. +
  3045.     }
  3046. +
  3047.  
  3048. +
  3049. /**    
  3050. +
  3051.      * compile optimized regexp list for keyword group
  3052. +
  3053.      *
  3054. +
  3055.      * @param int   The key of the keyword group to compile & optimize
  3056. +
  3057.      * @since 1.0.8
  3058. +
  3059.      */
  3060. +
  3061.     function optimize_keyword_group($key) {
  3062. +
  3063.         $this->language_data['CACHED_KEYWORD_LISTS'][$key] =
  3064. +
  3065.             $this->optimize_regexp_list($this->language_data['KEYWORDS'][$key]);
  3066. +
  3067.     }
  3068. +
  3069.  
  3070. +
  3071. /**    
  3072. +
  3073.      * Sets the content of the header block
  3074. +
  3075.      *
  3076. +
  3077.      * @param string The content of the header block
  3078. +
  3079.      * @since 1.0.2
  3080. +
  3081.      */
  3082. +
  3083.     function set_header_content($content) {
  3084. +
  3085.         $this->header_content = $content;
  3086. +
  3087.     }
  3088. +
  3089.  
  3090. +
  3091. /**    
  3092. +
  3093.      * Sets the content of the footer block
  3094. +
  3095.      *
  3096. +
  3097.      * @param string The content of the footer block
  3098. +
  3099.      * @since 1.0.2
  3100. +
  3101.      */
  3102. +
  3103.     function set_footer_content($content) {
  3104. +
  3105.         $this->footer_content = $content;
  3106. +
  3107.     }
  3108. +
  3109.  
  3110. +
  3111. /**    
  3112. +
  3113.      * Sets the style for the header content
  3114. +
  3115.      *
  3116. +
  3117.      * @param string The style for the header content
  3118. +
  3119.      * @since 1.0.2
  3120. +
  3121.      */
  3122. +
  3123.     function set_header_content_style($style) {
  3124. +
  3125.         $this->header_content_style = $style;
  3126. +
  3127.     }
  3128. +
  3129.  
  3130. +
  3131. /**    
  3132. +
  3133.      * Sets the style for the footer content
  3134. +
  3135.      *
  3136. +
  3137.      * @param string The style for the footer content
  3138. +
  3139.      * @since 1.0.2
  3140. +
  3141.      */
  3142. +
  3143.     function set_footer_content_style($style) {
  3144. +
  3145.         $this->footer_content_style = $style;
  3146. +
  3147.     }
  3148. +
  3149.  
  3150. +
  3151. /**    
  3152. +
  3153.      * Sets whether to force a surrounding block around
  3154. +
  3155.      * the highlighted code or not
  3156. +
  3157.      *
  3158. +
  3159.      * @param boolean Tells whether to enable or disable this feature
  3160. +
  3161.      * @since 1.0.7.20
  3162. +
  3163.      */
  3164. +
  3165.     function enable_inner_code_block($flag) {
  3166. +
  3167.         $this->force_code_block = (bool)$flag;
  3168. +
  3169.     }
  3170. +
  3171.  
  3172. +
  3173. /**    
  3174. +
  3175.      * Sets the base URL to be used for keywords
  3176. +
  3177.      *
  3178. +
  3179.      * @param int The key of the keyword group to set the URL for
  3180. +
  3181.      * @param string The URL to set for the group. If {FNAME} is in
  3182. +
  3183.      *                the url somewhere, it is replaced by the keyword
  3184. +
  3185.      *                that the URL is being made for
  3186. +
  3187.      * @since 1.0.2
  3188. +
  3189.      */
  3190. +
  3191.     function set_url_for_keyword_group($group, $url) {
  3192. +
  3193.         $this->language_data['URLS'][$group] = $url;
  3194. +
  3195.     }
  3196. +
  3197.  
  3198. +
  3199. /**    
  3200. +
  3201.      * Sets styles for links in code
  3202. +
  3203.      *
  3204. +
  3205.      * @param int A constant that specifies what state the style is being
  3206. +
  3207.      *             set for - e.g. :hover or :visited
  3208. +
  3209.      * @param string The styles to use for that state
  3210. +
  3211.      * @since 1.0.2
  3212. +
  3213.      */
  3214. +
  3215.     function set_link_styles($type, $styles) {
  3216. +
  3217.         $this->link_styles[$type] = $styles;
  3218. +
  3219.     }
  3220. +
  3221.  
  3222. +
  3223. /**    
  3224. +
  3225.      * Sets the target for links in code
  3226. +
  3227.      *
  3228. +
  3229.      * @param string The target for links in the code, e.g. _blank
  3230. +
  3231.      * @since 1.0.3
  3232. +
  3233.      */
  3234. +
  3235.     function set_link_target($target) {
  3236. +
  3237.         if (!$target) {
  3238. +
  3239.             $this->link_target = '';
  3240. +
  3241.         } else {
  3242. +
  3243.             $this->link_target = ' target="' . $target . '" ';
  3244. +
  3245.         }
  3246. +
  3247.     }
  3248. +
  3249.  
  3250. +
  3251. /**    
  3252. +
  3253.      * Sets styles for important parts of the code
  3254. +
  3255.      *
  3256. +
  3257.      * @param string The styles to use on important parts of the code
  3258. +
  3259.      * @since 1.0.2
  3260. +
  3261.      */
  3262. +
  3263.     function set_important_styles($styles) {
  3264. +
  3265.         $this->important_styles = $styles;
  3266. +
  3267.     }
  3268. +
  3269.  
  3270. +
  3271. /**    
  3272. +
  3273.      * Sets whether context-important blocks are highlighted
  3274. +
  3275.      *
  3276. +
  3277.      * @param boolean Tells whether to enable or disable highlighting of important blocks
  3278. +
  3279.      * @todo REMOVE THIS SHIZ FROM GESHI!
  3280. +
  3281.      * @deprecated
  3282. +
  3283.      * @since 1.0.2
  3284. +
  3285.      */
  3286. +
  3287.     function enable_important_blocks($flag) {
  3288. +
  3289.         $this->enable_important_blocks = ( $flag ) ? true : false;
  3290. +
  3291.     }
  3292. +
  3293.  
  3294. +
  3295. /**    
  3296. +
  3297.      * Whether CSS IDs should be added to each line
  3298. +
  3299.      *
  3300. +
  3301.      * @param boolean If true, IDs will be added to each line.
  3302. +
  3303.      * @since 1.0.2
  3304. +
  3305.      */
  3306. +
  3307.     function enable_ids($flag = true) {
  3308. +
  3309.         $this->add_ids = ($flag) ? true : false;
  3310. +
  3311.     }
  3312. +
  3313.  
  3314. +
  3315. /**    
  3316. +
  3317.      * Specifies which lines to highlight extra
  3318. +
  3319.      *
  3320. +
  3321.      * The extra style parameter was added in 1.0.7.21.
  3322. +
  3323.      *
  3324. +
  3325.      * @param mixed An array of line numbers to highlight, or just a line
  3326. +
  3327.      *               number on its own.
  3328. +
  3329.      * @param string A string specifying the style to use for this line.
  3330. +
  3331.      *               If null is specified, the default style is used.
  3332. +
  3333.      *               If false is specified, the line will be removed from
  3334. +
  3335.      *               special highlighting
  3336. +
  3337.      * @since 1.0.2
  3338. +
  3339.      * @todo  Some data replication here that could be cut down on
  3340. +
  3341.      */
  3342. +
  3343.     function highlight_lines_extra($lines, $style = null) {
  3344. +
  3345.         if (is_array($lines)) {
  3346. +
  3347.             //Split up the job using single lines at a time
  3348. +
  3349.             foreach ($lines as $line) {
  3350. +
  3351.                 $this->highlight_lines_extra($line, $style);
  3352. +
  3353.             }
  3354. +
  3355.         } else {
  3356. +
  3357.             //Mark the line as being highlighted specially
  3358. +
  3359.             $lines = intval($lines);
  3360. +
  3361.             $this->highlight_extra_lines[$lines] = $lines;
  3362. +
  3363.  
  3364. +
  3365.             //Decide on which style to use
  3366. +
  3367.             if ($style === null) { //Check if we should use default style
  3368. +
  3369.                 unset($this->highlight_extra_lines_styles[$lines]);
  3370. +
  3371.             } else if ($style === false) { //Check if to remove this line
  3372. +
  3373.                 unset($this->highlight_extra_lines[$lines]);
  3374. +
  3375.                 unset($this->highlight_extra_lines_styles[$lines]);
  3376. +
  3377.             } else {
  3378. +
  3379.                 $this->highlight_extra_lines_styles[$lines] = $style;
  3380. +
  3381.             }
  3382. +
  3383.         }
  3384. +
  3385.     }
  3386. +
  3387.  
  3388. +
  3389. /**    
  3390. +
  3391.      * Sets the style for extra-highlighted lines
  3392. +
  3393.      *
  3394. +
  3395.      * @param string The style for extra-highlighted lines
  3396. +
  3397.      * @since 1.0.2
  3398. +
  3399.      */
  3400. +
  3401.     function set_highlight_lines_extra_style($styles) {
  3402. +
  3403.         $this->highlight_extra_lines_style = $styles;
  3404. +
  3405.     }
  3406. +
  3407.  
  3408. +
  3409. /**    
  3410. +
  3411.      * Sets the line-ending
  3412. +
  3413.      *
  3414. +
  3415.      * @param string The new line-ending
  3416. +
  3417.      * @since 1.0.2
  3418. +
  3419.      */
  3420. +
  3421.     function set_line_ending($line_ending) {
  3422. +
  3423.         $this->line_ending = (string)$line_ending;
  3424. +
  3425.     }
  3426. +
  3427.  
  3428. +
  3429. /**    
  3430. +
  3431.      * Sets what number line numbers should start at. Should
  3432. +
  3433.      * be a positive integer, and will be converted to one.
  3434. +
  3435.      *
  3436. +
  3437.      * <b>Warning:</b> Using this method will add the "start"
  3438. +
  3439.      * attribute to the &lt;ol&gt; that is used for line numbering.
  3440. +
  3441.      * This is <b>not</b> valid XHTML strict, so if that's what you
  3442. +
  3443.      * care about then don't use this method. Firefox is getting
  3444. +
  3445.      * support for the CSS method of doing this in 1.1 and Opera
  3446. +
  3447.      * has support for the CSS method, but (of course) IE doesn't
  3448. +
  3449.      * so it's not worth doing it the CSS way yet.
  3450. +
  3451.      *
  3452. +
  3453.      * @param int The number to start line numbers at
  3454. +
  3455.      * @since 1.0.2
  3456. +
  3457.      */
  3458. +
  3459.     function start_line_numbers_at($number) {
  3460. +
  3461.         $this->line_numbers_start = abs(intval($number));
  3462. +
  3463.     }
  3464. +
  3465.  
  3466. +
  3467. /**    
  3468. +
  3469.      * Sets the encoding used for htmlspecialchars(), for international
  3470. +
  3471.      * support.
  3472. +
  3473.      *
  3474. +
  3475.      * NOTE: This is not needed for now because htmlspecialchars() is not
  3476. +
  3477.      * being used (it has a security hole in PHP4 that has not been patched).
  3478. +
  3479.      * Maybe in a future version it may make a return for speed reasons, but
  3480. +
  3481.      * I doubt it.
  3482. +
  3483.      *
  3484. +
  3485.      * @param string The encoding to use for the source
  3486. +
  3487.      * @since 1.0.3
  3488. +
  3489.      */
  3490. +
  3491.     function set_encoding($encoding) {
  3492. +
  3493.         if ($encoding) {
  3494. +
  3495.           $this->encoding = strtolower($encoding);
  3496. +
  3497.         }
  3498. +
  3499.     }
  3500. +
  3501.  
  3502. +
  3503. /**    
  3504. +
  3505.      * Turns linking of keywords on or off.
  3506. +
  3507.      *
  3508. +
  3509.      * @param boolean If true, links will be added to keywords
  3510. +
  3511.      * @since 1.0.2
  3512. +
  3513.      */
  3514. +
  3515.     function enable_keyword_links($enable = true) {
  3516. +
  3517.         $this->keyword_links = (bool) $enable;
  3518. +
  3519.     }
  3520. +
  3521.  
  3522. +
  3523. /**    
  3524. +
  3525.      * Setup caches needed for styling. This is automatically called in
  3526. +
  3527.      * parse_code() and get_stylesheet() when appropriate. This function helps
  3528. +
  3529.      * stylesheet generators as they rely on some style information being
  3530. +
  3531.      * preprocessed
  3532. +
  3533.      *
  3534. +
  3535.      * @since 1.0.8
  3536. +
  3537.      * @access private
  3538. +
  3539.      */
  3540. +
  3541.     function build_style_cache() {
  3542. +
  3543.         //Build the style cache needed to highlight numbers appropriate
  3544. +
  3545.         if($this->lexic_permissions['NUMBERS']) {
  3546. +
  3547.             //First check what way highlighting information for numbers are given
  3548. +
  3549.             if(!isset($this->language_data['NUMBERS'])) {
  3550. +
  3551.                 $this->language_data['NUMBERS'] = 0;
  3552. +
  3553.             }
  3554. +
  3555.  
  3556. +
  3557.             if(is_array($this->language_data['NUMBERS'])) {
  3558. +
  3559.                 $this->language_data['NUMBERS_CACHE'] = $this->language_data['NUMBERS'];
  3560. +
  3561.             } else {
  3562. +
  3563.                 $this->language_data['NUMBERS_CACHE'] = array();
  3564. +
  3565.                 if(!$this->language_data['NUMBERS']) {
  3566. +
  3567.                     $this->language_data['NUMBERS'] =
  3568. +
  3569.                         GESHI_NUMBER_INT_BASIC |
  3570. +
  3571.                         GESHI_NUMBER_FLT_NONSCI;
  3572. +
  3573.                 }
  3574. +
  3575.  
  3576. +
  3577.                 for($i = 0, $j = $this->language_data['NUMBERS']; $j > 0; ++$i, $j>>=1) {
  3578. +
  3579.                     //Rearrange style indices if required ...
  3580. +
  3581.                     if(isset($this->language_data['STYLES']['NUMBERS'][1<<$i])) {
  3582. +
  3583.                         $this->language_data['STYLES']['NUMBERS'][$i] =
  3584. +
  3585.                             $this->language_data['STYLES']['NUMBERS'][1<<$i];
  3586. +
  3587.                         unset($this->language_data['STYLES']['NUMBERS'][1<<$i]);
  3588. +
  3589.                     }
  3590. +
  3591.  
  3592. +
  3593.                     //Check if this bit is set for highlighting
  3594. +
  3595.                     if($j&1) {
  3596. +
  3597.                         //So this bit is set ...
  3598. +
  3599.                         //Check if it belongs to group 0 or the actual stylegroup
  3600. +
  3601.                         if(isset($this->language_data['STYLES']['NUMBERS'][$i])) {
  3602. +
  3603.                             $this->language_data['NUMBERS_CACHE'][$i] = 1 << $i;
  3604. +
  3605.                         } else {
  3606. +
  3607.                             if(!isset($this->language_data['NUMBERS_CACHE'][0])) {
  3608. +
  3609.                                 $this->language_data['NUMBERS_CACHE'][0] = 0;
  3610. +
  3611.                             }
  3612. +
  3613.                             $this->language_data['NUMBERS_CACHE'][0] |= 1 << $i;
  3614. +
  3615.                         }
  3616. +
  3617.                     }
  3618. +
  3619.                 }
  3620. +
  3621.             }
  3622. +
  3623.         }
  3624. +
  3625.     }
  3626. +
  3627.  
  3628. +
  3629. /**    
  3630. +
  3631.      * Setup caches needed for parsing. This is automatically called in parse_code() when appropriate.
  3632. +
  3633.      * This function makes stylesheet generators much faster as they do not need these caches.
  3634. +
  3635.      *
  3636. +
  3637.      * @since 1.0.8
  3638. +
  3639.      * @access private
  3640. +
  3641.      */
  3642. +
  3643.     function build_parse_cache() {
  3644. +
  3645.         // cache symbol regexp
  3646. +
  3647.         //As this is a costy operation, we avoid doing it for multiple groups ...
  3648. +
  3649.         //Instead we perform it for all symbols at once.
  3650. +
  3651.         //
  3652. +
  3653.         //For this to work, we need to reorganize the data arrays.
  3654. +
  3655.         if ($this->lexic_permissions['SYMBOLS'] && !empty($this->language_data['SYMBOLS'])) {
  3656. +
  3657.             $this->language_data['MULTIPLE_SYMBOL_GROUPS'] = count($this->language_data['STYLES']['SYMBOLS']) > 1;
  3658. +
  3659.  
  3660. +
  3661.             $this->language_data['SYMBOL_DATA'] = array();
  3662. +
  3663.             $symbol_preg_multi = array(); // multi char symbols
  3664. +
  3665.             $symbol_preg_single = array(); // single char symbols
  3666. +
  3667.             foreach ($this->language_data['SYMBOLS'] as $key => $symbols) {
  3668. +
  3669.                 if (is_array($symbols)) {
  3670. +
  3671.                     foreach ($symbols as $sym) {
  3672. +
  3673.                         $sym = $this->hsc($sym);
  3674. +
  3675.                         if (!isset($this->language_data['SYMBOL_DATA'][$sym])) {
  3676. +
  3677.                             $this->language_data['SYMBOL_DATA'][$sym] = $key;
  3678. +
  3679.                             if (isset($sym[1])) { // multiple chars
  3680. +
  3681.                                 $symbol_preg_multi[] = preg_quote($sym, '/');
  3682. +
  3683.                             } else { // single char
  3684. +
  3685.                                 if ($sym == '-') {
  3686. +
  3687.                                     // don't trigger range out of order error
  3688. +
  3689.                                     $symbol_preg_single[] = '\-';
  3690. +
  3691.                                 } else {
  3692. +
  3693.                                     $symbol_preg_single[] = preg_quote($sym, '/');
  3694. +
  3695.                                 }
  3696. +
  3697.                             }
  3698. +
  3699.                         }
  3700. +
  3701.                     }
  3702. +
  3703.                 } else {
  3704. +
  3705.                     $symbols = $this->hsc($symbols);
  3706. +
  3707.                     if (!isset($this->language_data['SYMBOL_DATA'][$symbols])) {
  3708. +
  3709.                         $this->language_data['SYMBOL_DATA'][$symbols] = 0;
  3710. +
  3711.                         if (isset($symbols[1])) { // multiple chars
  3712. +
  3713.                             $symbol_preg_multi[] = preg_quote($symbols, '/');
  3714. +
  3715.                         } else if ($symbols == '-') {
  3716. +
  3717.                             // don't trigger range out of order error
  3718. +
  3719.                             $symbol_preg_single[] = '\-';
  3720. +
  3721.                         } else { // single char
  3722. +
  3723.                             $symbol_preg_single[] = preg_quote($symbols, '/');
  3724. +
  3725.                         }
  3726. +
  3727.                     }
  3728. +
  3729.                 }
  3730. +
  3731.             }
  3732. +
  3733.  
  3734. +
  3735.             //Now we have an array with each possible symbol as the key and the style as the actual data.
  3736. +
  3737.             //This way we can set the correct style just the moment we highlight ...
  3738. +
  3739.             //
  3740. +
  3741.             //Now we need to rewrite our array to get a search string that
  3742. +
  3743.             $symbol_preg = array();
  3744. +
  3745.             if (!empty($symbol_preg_multi)) {
  3746. +
  3747.                 rsort($symbol_preg_multi);
  3748. +
  3749.                 $symbol_preg[] = implode('|', $symbol_preg_multi);
  3750. +
  3751.             }
  3752. +
  3753.             if (!empty($symbol_preg_single)) {
  3754. +
  3755.                 rsort($symbol_preg_single);
  3756. +
  3757.                 $symbol_preg[] = '[' . implode('', $symbol_preg_single) . ']';
  3758. +
  3759.             }
  3760. +
  3761.             $this->language_data['SYMBOL_SEARCH'] = implode("|", $symbol_preg);
  3762. +
  3763.         }
  3764. +
  3765.  
  3766. +
  3767.         // cache optimized regexp for keyword matching
  3768. +
  3769.         // remove old cache
  3770. +
  3771.         $this->language_data['CACHED_KEYWORD_LISTS'] = array();
  3772. +
  3773.         foreach (array_keys($this->language_data['KEYWORDS']) as $key) {
  3774. +
  3775.             if (!isset($this->lexic_permissions['KEYWORDS'][$key]) ||
  3776. +
  3777.                     $this->lexic_permissions['KEYWORDS'][$key]) {
  3778. +
  3779.                 $this->optimize_keyword_group($key);
  3780. +
  3781.             }
  3782. +
  3783.         }
  3784. +
  3785.  
  3786. +
  3787.         // brackets
  3788. +
  3789.         if ($this->lexic_permissions['BRACKETS']) {
  3790. +
  3791.             $this->language_data['CACHE_BRACKET_MATCH'] = array('[', ']', '(', ')', '{', '}');
  3792. +
  3793.             if (!$this->use_classes && isset($this->language_data['STYLES']['BRACKETS'][0])) {
  3794. +
  3795.                 $this->language_data['CACHE_BRACKET_REPLACE'] = array(
  3796. +
  3797.                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#91;|>',
  3798. +
  3799.                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#93;|>',
  3800. +
  3801.                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#40;|>',
  3802. +
  3803.                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#41;|>',
  3804. +
  3805.                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#123;|>',
  3806. +
  3807.                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#125;|>',
  3808. +
  3809.                 );
  3810. +
  3811.             }
  3812. +
  3813.             else {
  3814. +
  3815.                 $this->language_data['CACHE_BRACKET_REPLACE'] = array(
  3816. +
  3817.                     '<| class="br0">&#91;|>',
  3818. +
  3819.                     '<| class="br0">&#93;|>',
  3820. +
  3821.                     '<| class="br0">&#40;|>',
  3822. +
  3823.                     '<| class="br0">&#41;|>',
  3824. +
  3825.                     '<| class="br0">&#123;|>',
  3826. +
  3827.                     '<| class="br0">&#125;|>',
  3828. +
  3829.                 );
  3830. +
  3831.             }
  3832. +
  3833.         }
  3834. +
  3835.  
  3836. +
  3837.         //Build the parse cache needed to highlight numbers appropriate
  3838. +
  3839.         if($this->lexic_permissions['NUMBERS']) {
  3840. +
  3841.             //Check if the style rearrangements have been processed ...
  3842. +
  3843.             //This also does some preprocessing to check which style groups are useable ...
  3844. +
  3845.             if(!isset($this->language_data['NUMBERS_CACHE'])) {
  3846. +
  3847.                 $this->build_style_cache();
  3848. +
  3849.             }
  3850. +
  3851.  
  3852. +
  3853.             //Number format specification
  3854. +
  3855.             //All this formats are matched case-insensitively!
  3856. +
  3857.             static $numbers_format = array(
  3858. +
  3859.                 GESHI_NUMBER_INT_BASIC =>
  3860. +
  3861.                     '(?<![0-9a-z_\.%])(?<![\d\.]e[+\-])([1-9]\d*?|0)(?![0-9a-z\.])',
  3862. +
  3863.                 GESHI_NUMBER_INT_CSTYLE =>
  3864. +
  3865.                     '(?<![0-9a-z_\.%])(?<![\d\.]e[+\-])([1-9]\d*?|0)l(?![0-9a-z\.])',
  3866. +
  3867.                 GESHI_NUMBER_BIN_SUFFIX =>
  3868. +
  3869.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])[01]+?b(?![0-9a-z\.])',
  3870. +
  3871.                 GESHI_NUMBER_BIN_PREFIX_PERCENT =>
  3872. +
  3873.                     '(?<![0-9a-z_\.%])(?<![\d\.]e[+\-])%[01]+?(?![0-9a-z\.])',
  3874. +
  3875.                 GESHI_NUMBER_BIN_PREFIX_0B =>
  3876. +
  3877.                     '(?<![0-9a-z_\.%])(?<![\d\.]e[+\-])0b[01]+?(?![0-9a-z\.])',
  3878. +
  3879.                 GESHI_NUMBER_OCT_PREFIX =>
  3880. +
  3881.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])0[0-7]+?(?![0-9a-z\.])',
  3882. +
  3883.                 GESHI_NUMBER_OCT_SUFFIX =>
  3884. +
  3885.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])[0-7]+?o(?![0-9a-z\.])',
  3886. +
  3887.                 GESHI_NUMBER_HEX_PREFIX =>
  3888. +
  3889.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])0x[0-9a-f]+?(?![0-9a-z\.])',
  3890. +
  3891.                 GESHI_NUMBER_HEX_SUFFIX =>
  3892. +
  3893.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])\d[0-9a-f]*?h(?![0-9a-z\.])',
  3894. +
  3895.                 GESHI_NUMBER_FLT_NONSCI =>
  3896. +
  3897.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])\d+?\.\d+?(?![0-9a-z\.])',
  3898. +
  3899.                 GESHI_NUMBER_FLT_NONSCI_F =>
  3900. +
  3901.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])(?:\d+?(?:\.\d*?)?|\.\d+?)f(?![0-9a-z\.])',
  3902. +
  3903.                 GESHI_NUMBER_FLT_SCI_SHORT =>
  3904. +
  3905.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])\.\d+?(?:e[+\-]?\d+?)?(?![0-9a-z\.])',
  3906. +
  3907.                 GESHI_NUMBER_FLT_SCI_ZERO =>
  3908. +
  3909.                     '(?<![0-9a-z_\.])(?<![\d\.]e[+\-])(?:\d+?(?:\.\d*?)?|\.\d+?)(?:e[+\-]?\d+?)?(?![0-9a-z\.])'
  3910. +
  3911.                 );
  3912. +
  3913.  
  3914. +
  3915.             //At this step we have an associative array with flag groups for a
  3916. +
  3917.             //specific style or an string denoting a regexp given its index.
  3918. +
  3919.             $this->language_data['NUMBERS_RXCACHE'] = array();
  3920. +
  3921.             foreach($this->language_data['NUMBERS_CACHE'] as $key => $rxdata) {
  3922. +
  3923.                 if(is_string($rxdata)) {
  3924. +
  3925.                     $regexp = $rxdata;
  3926. +
  3927.                 } else {
  3928. +
  3929.                     //This is a bitfield of number flags to highlight:
  3930. +
  3931.                     //Build an array, implode them together and make this the actual RX
  3932. +
  3933.                     $rxuse = array();
  3934. +
  3935.                     for($i = 1; $i <= $rxdata; $i<<=1) {
  3936. +
  3937.                         if($rxdata & $i) {
  3938. +
  3939.                             $rxuse[] = $numbers_format[$i];
  3940. +
  3941.                         }
  3942. +
  3943.                     }
  3944. +
  3945.                     $regexp = implode("|", $rxuse);
  3946. +
  3947.                 }
  3948. +
  3949.  
  3950. +
  3951.                 $this->language_data['NUMBERS_RXCACHE'][$key] =
  3952. +
  3953.                     "/(?<!<\|\/NUM!)(?<!\d\/>)($regexp)(?!\|>)/i";
  3954. +
  3955.             }
  3956. +
  3957.         }
  3958. +
  3959.  
  3960. +
  3961.         $this->parse_cache_built = true;
  3962. +
  3963.     }
  3964. +
  3965.  
  3966. +
  3967.     /**
  3968. +
  3969.      * Returns the code in $this->source, highlighted and surrounded by the
  3970. +
  3971.      * nessecary HTML.
  3972. +
  3973.      *
  3974. +
  3975.      * This should only be called ONCE, cos it's SLOW! If you want to highlight
  3976. +
  3977.      * the same source multiple times, you're better off doing a whole lot of
  3978. +
  3979.      * str_replaces to replace the &lt;span&gt;s
  3980. +
  3981.      *
  3982. +
  3983.      * @since 1.0.0
  3984. +
  3985.      */
  3986. +
  3987.     function parse_code () {
  3988. +
  3989.         // Start the timer
  3990. +
  3991.         $start_time = microtime();
  3992. +
  3993.  
  3994. +
  3995.         // Firstly, if there is an error, we won't highlight
  3996. +
  3997.         if ($this->error) {
  3998. +
  3999.             //Escape the source for output
  4000. +
  4001.             $result = $this->hsc($this->source);
  4002. +
  4003.  
  4004. +
  4005.             //This fix is related to SF#1923020, but has to be applied regardless of
  4006. +
  4007.             //actually highlighting symbols.
  4008. +
  4009.             $result = str_replace(array('<SEMI>', '<PIPE>'), array(';', '|'), $result);
  4010. +
  4011.  
  4012. +
  4013.             // Timing is irrelevant
  4014. +
  4015.             $this->set_time($start_time, $start_time);
  4016. +
  4017.             $this->finalise($result);
  4018. +
  4019.             return $result;
  4020. +
  4021.         }
  4022. +
  4023.  
  4024. +
  4025.         // make sure the parse cache is up2date
  4026. +
  4027.         if (!$this->parse_cache_built) {
  4028. +
  4029.             $this->build_parse_cache();
  4030. +
  4031.         }
  4032. +
  4033.  
  4034. +
  4035.         // Replace all newlines to a common form.
  4036. +
  4037.         $code = str_replace("\r\n", "\n", $this->source);
  4038. +
  4039.         $code = str_replace("\r", "\n", $code);
  4040. +
  4041.  
  4042. +
  4043.         // Add spaces for regular expression matching and line numbers
  4044. +
  4045. //        $code = "\n" . $code . "\n";
  4046. +
  4047. +
  4048.         // Initialise various stuff
  4049. +
  4050.         $length           = strlen($code);
  4051. +
  4052.         $COMMENT_MATCHED  = false;
  4053. +
  4054.         $stuff_to_parse   = '';
  4055. +
  4056.         $endresult        = '';
  4057. +
  4058.  
  4059. +
  4060.         // "Important" selections are handled like multiline comments
  4061. +
  4062.         // @todo GET RID OF THIS SHIZ
  4063. +
  4064.         if ($this->enable_important_blocks) {
  4065. +
  4066.             $this->language_data['COMMENT_MULTI'][<a href="../geshi/core/_geshi.php.html#defineGESHI_START_IMPORTANT">GESHI_START_IMPORTANT</a>] = <a href="../geshi/core/_geshi.php.html#defineGESHI_END_IMPORTANT">GESHI_END_IMPORTANT</a>;
  4067. +
  4068.         }
  4069. +
  4070.  
  4071. +
  4072.         if ($this->strict_mode) {
  4073. +
  4074.             // Break the source into bits. Each bit will be a portion of the code
  4075. +
  4076.             // within script delimiters - for example, HTML between < and >
  4077. +
  4078.             $k = 0;
  4079. +
  4080.             $parts = array();
  4081. +
  4082.             $matches = array();
  4083. +
  4084.             $next_match_pointer = null;
  4085. +
  4086.             // we use a copy to unset delimiters on demand (when they are not found)
  4087. +
  4088.             $delim_copy = $this->language_data['SCRIPT_DELIMITERS'];
  4089. +
  4090.             $i = 0;
  4091. +
  4092.             while ($i < $length) {
  4093. +
  4094.                 $next_match_pos = $length + 1; // never true
  4095. +
  4096.                 foreach ($delim_copy as $dk => $delimiters) {
  4097. +
  4098.                     if(is_array($delimiters)) {
  4099. +
  4100.                         foreach ($delimiters as $open => $close) {
  4101. +
  4102.                             // make sure the cache is setup properly
  4103. +
  4104.                             if (!isset($matches[$dk][$open])) {
  4105. +
  4106.                                 $matches[$dk][$open] = array(
  4107. +
  4108.                                     'next_match' => -1,
  4109. +
  4110.                                     'dk' => $dk,
  4111. +
  4112.  
  4113. +
  4114.                                     'open' => $open, // needed for grouping of adjacent code blocks (see below)
  4115. +
  4116.                                     'open_strlen' => strlen($open),
  4117. +
  4118.  
  4119. +
  4120.                                     'close' => $close,
  4121. +
  4122.                                     'close_strlen' => strlen($close),
  4123. +
  4124.                                 );
  4125. +
  4126.                             }
  4127. +
  4128.                             // Get the next little bit for this opening string
  4129. +
  4130.                             if ($matches[$dk][$open]['next_match'] < $i) {
  4131. +
  4132.                                 // only find the next pos if it was not already cached
  4133. +
  4134.                                 $open_pos = strpos($code, $open, $i);
  4135. +
  4136.                                 if ($open_pos === false) {
  4137. +
  4138.                                     // no match for this delimiter ever
  4139. +
  4140.                                     unset($delim_copy[$dk][$open]);
  4141. +
  4142.                                     continue;
  4143. +
  4144.                                 }
  4145. +
  4146.                                 $matches[$dk][$open]['next_match'] = $open_pos;
  4147. +
  4148.                             }
  4149. +
  4150.                             if ($matches[$dk][$open]['next_match'] < $next_match_pos) {
  4151. +
  4152.                                 //So we got a new match, update the close_pos
  4153. +
  4154.                                 $matches[$dk][$open]['close_pos'] =
  4155. +
  4156.                                     strpos($code, $close, $matches[$dk][$open]['next_match']+1);
  4157. +
  4158.  
  4159. +
  4160.                                 $next_match_pointer =& $matches[$dk][$open];
  4161. +
  4162.                                 $next_match_pos = $matches[$dk][$open]['next_match'];
  4163. +
  4164.                             }
  4165. +
  4166.                         }
  4167. +
  4168.                     } else {
  4169. +
  4170.                         //So we should match an RegExp as Strict Block ...
  4171. +
  4172. /**                        
  4173. +
  4174.                          * The value in $delimiters is expected to be an RegExp
  4175. +
  4176.                          * containing exactly 2 matching groups:
  4177. +
  4178.                          *  - Group 1 is the opener
  4179. +
  4180.                          *  - Group 2 is the closer
  4181. +
  4182.                          */
  4183. +
  4184.                         if(!GESHI_PHP_PRE_433 && //Needs proper rewrite to work with PHP >=4.3.0; 4.3.3 is guaranteed to work.
  4185. +
  4186.                             preg_match($delimiters, $code, $matches_rx, PREG_OFFSET_CAPTURE, $i)) {
  4187. +
  4188.                             //We got a match ...
  4189. +
  4190.                             $matches[$dk] = array(
  4191. +
  4192.                                 'next_match' => $matches_rx[1][1],
  4193. +
  4194.                                 'dk' => $dk,
  4195. +
  4196.  
  4197. +
  4198.                                 'close_strlen' => strlen($matches_rx[2][0]),
  4199. +
  4200.                                 'close_pos' => $matches_rx[2][1],
  4201. +
  4202.                                 );
  4203. +
  4204.                         } else {
  4205. +
  4206.                             // no match for this delimiter ever
  4207. +
  4208.                             unset($delim_copy[$dk]);
  4209. +
  4210.                             continue;
  4211. +
  4212.                         }
  4213. +
  4214.  
  4215. +
  4216.                         if ($matches[$dk]['next_match'] <= $next_match_pos) {
  4217. +
  4218.                             $next_match_pointer =& $matches[$dk];
  4219. +
  4220.                             $next_match_pos = $matches[$dk]['next_match'];
  4221. +
  4222.                         }
  4223. +
  4224.                     }
  4225. +
  4226.                 }
  4227. +
  4228.                 // non-highlightable text
  4229. +
  4230.                 $parts[$k] = array(
  4231. +
  4232.                     1 => substr($code, $i, $next_match_pos - $i)
  4233. +
  4234.                 );
  4235. +
  4236.                 ++$k;
  4237. +
  4238.  
  4239. +
  4240.                 if ($next_match_pos > $length) {
  4241. +
  4242.                     // out of bounds means no next match was found
  4243. +
  4244.                     break;
  4245. +
  4246.                 }
  4247. +
  4248.  
  4249. +
  4250.                 // highlightable code
  4251. +
  4252.                 $parts[$k][0] = $next_match_pointer['dk'];
  4253. +
  4254.  
  4255. +
  4256.                 //Only combine for non-rx script blocks
  4257. +
  4258.                 if(is_array($delim_copy[$next_match_pointer['dk']])) {
  4259. +
  4260.                     // group adjacent script blocks, e.g. <foobar><asdf> should be one block, not three!
  4261. +
  4262.                     $i = $next_match_pos + $next_match_pointer['open_strlen'];
  4263. +
  4264.                     while (true) {
  4265. +
  4266.                         $close_pos = strpos($code, $next_match_pointer['close'], $i);
  4267. +
  4268.                         if ($close_pos == false) {
  4269. +
  4270.                             break;
  4271. +
  4272.                         }
  4273. +
  4274.                         $i = $close_pos + $next_match_pointer['close_strlen'];
  4275. +
  4276.                         if ($i == $length) {
  4277. +
  4278.                             break;
  4279. +
  4280.                         }
  4281. +
  4282.                         if ($code[$i] == $next_match_pointer['open'][0] && ($next_match_pointer['open_strlen'] == 1 ||
  4283. +
  4284.                             substr($code, $i, $next_match_pointer['open_strlen']) == $next_match_pointer['open'])) {
  4285. +
  4286.                             // merge adjacent but make sure we don't merge things like <tag><!-- comment -->
  4287. +
  4288.                             foreach ($matches as $submatches) {
  4289. +
  4290.                                 foreach ($submatches as $match) {
  4291. +
  4292.                                     if ($match['next_match'] == $i) {
  4293. +
  4294.                                         // a different block already matches here!
  4295. +
  4296.                                         break 3;
  4297. +
  4298.                                     }
  4299. +
  4300.                                 }
  4301. +
  4302.                             }
  4303. +
  4304.                         } else {
  4305. +
  4306.                             break;
  4307. +
  4308.                         }
  4309. +
  4310.                     }
  4311. +
  4312.                 } else {
  4313. +
  4314.                     $close_pos = $next_match_pointer['close_pos'] + $next_match_pointer['close_strlen'];
  4315. +
  4316.                     $i = $close_pos;
  4317. +
  4318.                 }
  4319. +
  4320.  
  4321. +
  4322.                 if ($close_pos === false) {
  4323. +
  4324.                     // no closing delimiter found!
  4325. +
  4326.                     $parts[$k][1] = substr($code, $next_match_pos);
  4327. +
  4328.                     ++$k;
  4329. +
  4330.                     break;
  4331. +
  4332.                 } else {
  4333. +
  4334.                     $parts[$k][1] = substr($code, $next_match_pos, $i - $next_match_pos);
  4335. +
  4336.                     ++$k;
  4337. +
  4338.                 }
  4339. +
  4340.             }
  4341. +
  4342.             unset($delim_copy, $next_match_pointer, $next_match_pos, $matches);
  4343. +
  4344.             $num_parts = $k;
  4345. +
  4346.  
  4347. +
  4348.             if ($num_parts == 1 && $this->strict_mode == GESHI_MAYBE) {
  4349. +
  4350.                 // when we have only one part, we don't have anything to highlight at all.
  4351. +
  4352.                 // if we have a "maybe" strict language, this should be handled as highlightable code
  4353. +
  4354.                 $parts = array(
  4355. +
  4356.                     0 => array(
  4357. +
  4358.                         0 => '',
  4359. +
  4360.                         1 => ''
  4361. +
  4362.                     ),
  4363. +
  4364.                     1 => array(
  4365. +
  4366.                         0 => null,
  4367. +
  4368.                         1 => $parts[0][1]
  4369. +
  4370.                     )
  4371. +
  4372.                 );
  4373. +
  4374.                 $num_parts = 2;
  4375. +
  4376.             }
  4377. +
  4378.  
  4379. +
  4380.         } else {
  4381. +
  4382.             // Not strict mode - simply dump the source into
  4383. +
  4384.             // the array at index 1 (the first highlightable block)
  4385. +
  4386.             $parts = array(
  4387. +
  4388.                 0 => array(
  4389. +
  4390.                     0 => '',
  4391. +
  4392.                     1 => ''
  4393. +
  4394.                 ),
  4395. +
  4396.                 1 => array(
  4397. +
  4398.                     0 => null,
  4399. +
  4400.                     1 => $code
  4401. +
  4402.                 )
  4403. +
  4404.             );
  4405. +
  4406.             $num_parts = 2;
  4407. +
  4408.         }
  4409. +
  4410.  
  4411. +
  4412.         //Unset variables we won't need any longer
  4413. +
  4414.         unset($code);
  4415. +
  4416.  
  4417. +
  4418.         //Preload some repeatedly used values regarding hardquotes ...
  4419. +
  4420.         $hq = isset($this->language_data['HARDQUOTE']) ? $this->language_data['HARDQUOTE'][0] : false;
  4421. +
  4422.         $hq_strlen = strlen($hq);
  4423. +
  4424.  
  4425. +
  4426.         //Preload if line numbers are to be generated afterwards
  4427. +
  4428.         //Added a check if line breaks should be forced even without line numbers, fixes SF#1727398
  4429. +
  4430.         $check_linenumbers = $this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a> ||
  4431. +
  4432.             !empty($this->highlight_extra_lines) || !$this->allow_multiline_span;
  4433. +
  4434.  
  4435. +
  4436.         //preload the escape char for faster checking ...
  4437. +
  4438.         $escaped_escape_char = $this->hsc($this->language_data['ESCAPE_CHAR']);
  4439. +
  4440.  
  4441. +
  4442.         // this is used for single-line comments
  4443. +
  4444.         $sc_disallowed_before = "";
  4445. +
  4446.         $sc_disallowed_after = "";
  4447. +
  4448.  
  4449. +
  4450.         if (isset($this->language_data['PARSER_CONTROL'])) {
  4451. +
  4452.             if (isset($this->language_data['PARSER_CONTROL']['COMMENTS'])) {
  4453. +
  4454.                 if (isset($this->language_data['PARSER_CONTROL']['COMMENTS']['DISALLOWED_BEFORE'])) {
  4455. +
  4456.                     $sc_disallowed_before = $this->language_data['PARSER_CONTROL']['COMMENTS']['DISALLOWED_BEFORE'];
  4457. +
  4458.                 }
  4459. +
  4460.                 if (isset($this->language_data['PARSER_CONTROL']['COMMENTS']['DISALLOWED_AFTER'])) {
  4461. +
  4462.                     $sc_disallowed_after = $this->language_data['PARSER_CONTROL']['COMMENTS']['DISALLOWED_AFTER'];
  4463. +
  4464.                 }
  4465. +
  4466.             }
  4467. +
  4468.         }
  4469. +
  4470.  
  4471. +
  4472.         //Fix for SF#1932083: Multichar Quotemarks unsupported
  4473. +
  4474.         $is_string_starter = array();
  4475. +
  4476.         if ($this->lexic_permissions['STRINGS']) {
  4477. +
  4478.             foreach ($this->language_data['QUOTEMARKS'] as $quotemark) {
  4479. +
  4480.                 if (!isset($is_string_starter[$quotemark[0]])) {
  4481. +
  4482.                     $is_string_starter[$quotemark[0]] = (string)$quotemark;
  4483. +
  4484.                 } else if (is_string($is_string_starter[$quotemark[0]])) {
  4485. +
  4486.                     $is_string_starter[$quotemark[0]] = array(
  4487. +
  4488.                         $is_string_starter[$quotemark[0]],
  4489. +
  4490.                         $quotemark);
  4491. +
  4492.                 } else {
  4493. +
  4494.                     $is_string_starter[$quotemark[0]][] = $quotemark;
  4495. +
  4496.                 }
  4497. +
  4498.             }
  4499. +
  4500.         }
  4501. +
  4502.  
  4503. +
  4504.         // Now we go through each part. We know that even-indexed parts are
  4505. +
  4506.         // code that shouldn't be highlighted, and odd-indexed parts should
  4507. +
  4508.         // be highlighted
  4509. +
  4510.         for ($key = 0; $key < $num_parts; ++$key) {
  4511. +
  4512.             $STRICTATTRS = '';
  4513. +
  4514.  
  4515. +
  4516.             // If this block should be highlighted...
  4517. +
  4518.             if (!($key & 1)) {
  4519. +
  4520.                 // Else not a block to highlight
  4521. +
  4522.                 $endresult .= $this->hsc($parts[$key][1]);
  4523. +
  4524.                 unset($parts[$key]);
  4525. +
  4526.                 continue;
  4527. +
  4528.             }
  4529. +
  4530.  
  4531. +
  4532.             $result = '';
  4533. +
  4534.             $part = $parts[$key][1];
  4535. +
  4536.  
  4537. +
  4538.             $highlight_part = true;
  4539. +
  4540.             if ($this->strict_mode && !is_null($parts[$key][0])) {
  4541. +
  4542.                 // get the class key for this block of code
  4543. +
  4544.                 $script_key = $parts[$key][0];
  4545. +
  4546.                 $highlight_part = $this->language_data['HIGHLIGHT_STRICT_BLOCK'][$script_key];
  4547. +
  4548.                 if ($this->language_data['STYLES']['SCRIPT'][$script_key] != '' &&
  4549. +
  4550.                     $this->lexic_permissions['SCRIPT']) {
  4551. +
  4552.                     // Add a span element around the source to
  4553. +
  4554.                     // highlight the overall source block
  4555. +
  4556.                     if (!$this->use_classes &&
  4557. +
  4558.                         $this->language_data['STYLES']['SCRIPT'][$script_key] != '') {
  4559. +
  4560.                         $attributes = ' style="' . $this->language_data['STYLES']['SCRIPT'][$script_key] . '"';
  4561. +
  4562.                     } else {
  4563. +
  4564.                         $attributes = ' class="sc' . $script_key . '"';
  4565. +
  4566.                     }
  4567. +
  4568.                     $result .= "<span$attributes>";
  4569. +
  4570.                     $STRICTATTRS = $attributes;
  4571. +
  4572.                 }
  4573. +
  4574.             }
  4575. +
  4576.  
  4577. +
  4578.             if ($highlight_part) {
  4579. +
  4580.                 // Now, highlight the code in this block. This code
  4581. +
  4582.                 // is really the engine of GeSHi (along with the method
  4583. +
  4584.                 // parse_non_string_part).
  4585. +
  4586. +
  4587.                 // cache comment regexps incrementally
  4588. +
  4589.                 $next_comment_regexp_key = '';
  4590. +
  4591.                 $next_comment_regexp_pos = -1;
  4592. +
  4593.                 $next_comment_multi_pos = -1;
  4594. +
  4595.                 $next_comment_single_pos = -1;
  4596. +
  4597.                 $comment_regexp_cache_per_key = array();
  4598. +
  4599.                 $comment_multi_cache_per_key = array();
  4600. +
  4601.                 $comment_single_cache_per_key = array();
  4602. +
  4603.                 $next_open_comment_multi = '';
  4604. +
  4605.                 $next_comment_single_key = '';
  4606. +
  4607.                 $escape_regexp_cache_per_key = array();
  4608. +
  4609.                 $next_escape_regexp_key = '';
  4610. +
  4611.                 $next_escape_regexp_pos = -1;
  4612. +
  4613.  
  4614. +
  4615.                 $length = strlen($part);
  4616. +
  4617.                 for ($i = 0; $i < $length; ++$i) {
  4618. +
  4619.                     // Get the next char
  4620. +
  4621.                     $char = $part[$i];
  4622. +
  4623.                     $char_len = 1;
  4624. +
  4625.  
  4626. +
  4627.                     // update regexp comment cache if needed
  4628. +
  4629.                     if (isset($this->language_data['COMMENT_REGEXP']) && $next_comment_regexp_pos < $i) {
  4630. +
  4631.                         $next_comment_regexp_pos = $length;
  4632. +
  4633.                         foreach ($this->language_data['COMMENT_REGEXP'] as $comment_key => $regexp) {
  4634. +
  4635.                             $match_i = false;
  4636. +
  4637.                             if (isset($comment_regexp_cache_per_key[$comment_key]) &&
  4638. +
  4639.                                 ($comment_regexp_cache_per_key[$comment_key]['pos'] >= $i ||
  4640. +
  4641.                                  $comment_regexp_cache_per_key[$comment_key]['pos'] === false)) {
  4642. +
  4643.                                 // we have already matched something
  4644. +
  4645.                                 if ($comment_regexp_cache_per_key[$comment_key]['pos'] === false) {
  4646. +
  4647.                                     // this comment is never matched
  4648. +
  4649.                                     continue;
  4650. +
  4651.                                 }
  4652. +
  4653.                                 $match_i = $comment_regexp_cache_per_key[$comment_key]['pos'];
  4654. +
  4655.                             } else if (
  4656. +
  4657.                                 //This is to allow use of the offset parameter in preg_match and stay as compatible with older PHP versions as possible
  4658. +
  4659.                                 (GESHI_PHP_PRE_433 && preg_match($regexp, substr($part, $i), $match, PREG_OFFSET_CAPTURE)) ||
  4660. +
  4661.                                 (!GESHI_PHP_PRE_433 && preg_match($regexp, $part, $match, PREG_OFFSET_CAPTURE, $i))
  4662. +
  4663.                                 ) {
  4664. +
  4665.                                 $match_i = $match[0][1];
  4666. +
  4667.                                 if (GESHI_PHP_PRE_433) {
  4668. +
  4669.                                     $match_i += $i;
  4670. +
  4671.                                 }
  4672. +
  4673.  
  4674. +
  4675.                                 $comment_regexp_cache_per_key[$comment_key] = array(
  4676. +
  4677.                                     'key' => $comment_key,
  4678. +
  4679.                                     'length' => strlen($match[0][0]),
  4680. +
  4681.                                     'pos' => $match_i
  4682. +
  4683.                                 );
  4684. +
  4685.                             } else {
  4686. +
  4687.                                 $comment_regexp_cache_per_key[$comment_key]['pos'] = false;
  4688. +
  4689.                                 continue;
  4690. +
  4691.                             }
  4692. +
  4693.  
  4694. +
  4695.                             if ($match_i !== false && $match_i < $next_comment_regexp_pos) {
  4696. +
  4697.                                 $next_comment_regexp_pos = $match_i;
  4698. +
  4699.                                 $next_comment_regexp_key = $comment_key;
  4700. +
  4701.                                 if ($match_i === $i) {
  4702. +
  4703.                                     break;
  4704. +
  4705.                                 }
  4706. +
  4707.                             }
  4708. +
  4709.                         }
  4710. +
  4711.                     }
  4712. +
  4713.  
  4714. +
  4715.                     $string_started = false;
  4716. +
  4717.  
  4718. +
  4719.                     if (isset($is_string_starter[$char])) {
  4720. +
  4721.                         // Possibly the start of a new string ...
  4722. +
  4723. +
  4724.                         //Check which starter it was ...
  4725. +
  4726.                         //Fix for SF#1932083: Multichar Quotemarks unsupported
  4727. +
  4728.                         if (is_array($is_string_starter[$char])) {
  4729. +
  4730.                             $char_new = '';
  4731. +
  4732.                             foreach ($is_string_starter[$char] as $testchar) {
  4733. +
  4734.                                 if ($testchar === substr($part, $i, strlen($testchar)) &&
  4735. +
  4736.                                     strlen($testchar) > strlen($char_new)) {
  4737. +
  4738.                                     $char_new = $testchar;
  4739. +
  4740.                                     $string_started = true;
  4741. +
  4742.                                 }
  4743. +
  4744.                             }
  4745. +
  4746.                             if ($string_started) {
  4747. +
  4748.                                 $char = $char_new;
  4749. +
  4750.                             }
  4751. +
  4752.                         } else {
  4753. +
  4754.                             $testchar = $is_string_starter[$char];
  4755. +
  4756.                             if ($testchar === substr($part, $i, strlen($testchar))) {
  4757. +
  4758.                                 $char = $testchar;
  4759. +
  4760.                                 $string_started = true;
  4761. +
  4762.                             }
  4763. +
  4764.                         }
  4765. +
  4766.                         $char_len = strlen($char);
  4767. +
  4768.                     }
  4769. +
  4770.  
  4771. +
  4772.                     if ($string_started && $i != $next_comment_regexp_pos) {
  4773. +
  4774.                         // Hand out the correct style information for this string
  4775. +
  4776.                         $string_key = array_search($char, $this->language_data['QUOTEMARKS']);
  4777. +
  4778.                         if (!isset($this->language_data['STYLES']['STRINGS'][$string_key]) ||
  4779. +
  4780.                             !isset($this->language_data['STYLES']['ESCAPE_CHAR'][$string_key])) {
  4781. +
  4782.                             $string_key = 0;
  4783. +
  4784.                         }
  4785. +
  4786.  
  4787. +
  4788.                         // parse the stuff before this
  4789. +
  4790.                         $result .= $this->parse_non_string_part($stuff_to_parse);
  4791. +
  4792.                         $stuff_to_parse = '';
  4793. +
  4794.  
  4795. +
  4796.                         if (!$this->use_classes) {
  4797. +
  4798.                             $string_attributes = ' style="' . $this->language_data['STYLES']['STRINGS'][$string_key] . '"';
  4799. +
  4800.                         } else {
  4801. +
  4802.                             $string_attributes = ' class="st'.$string_key.'"';
  4803. +
  4804.                         }
  4805. +
  4806.  
  4807. +
  4808.                         // now handle the string
  4809. +
  4810.                         $string = "<span$string_attributes>GeSHi::hsc($char);
  4811. +
  4812.                         $start = $i + $char_len;
  4813. +
  4814.                         $string_open = true;
  4815. +
  4816.  
  4817. +
  4818.                         if(empty($this->language_data['ESCAPE_REGEXP'])) {
  4819. +
  4820.                             $next_escape_regexp_pos = $length;
  4821. +
  4822.                         }
  4823. +
  4824.  
  4825. +
  4826.                         do {
  4827. +
  4828.                             //Get the regular ending pos ...
  4829. +
  4830.                             $close_pos = strpos($part, $char, $start);
  4831. +
  4832.                             if(false === $close_pos) {
  4833. +
  4834.                                 $close_pos = $length;
  4835. +
  4836.                             }
  4837. +
  4838.  
  4839. +
  4840.                             if($this->lexic_permissions['ESCAPE_CHAR']) {
  4841. +
  4842.                                 // update escape regexp cache if needed
  4843. +
  4844.                                 if (isset($this->language_data['ESCAPE_REGEXP']) && $next_escape_regexp_pos < $start) {
  4845. +
  4846.                                     $next_escape_regexp_pos = $length;
  4847. +
  4848.                                     foreach ($this->language_data['ESCAPE_REGEXP'] as $escape_key => $regexp) {
  4849. +
  4850.                                         $match_i = false;
  4851. +
  4852.                                         if (isset($escape_regexp_cache_per_key[$escape_key]) &&
  4853. +
  4854.                                             ($escape_regexp_cache_per_key[$escape_key]['pos'] >= $start ||
  4855. +
  4856.                                              $escape_regexp_cache_per_key[$escape_key]['pos'] === false)) {
  4857. +
  4858.                                             // we have already matched something
  4859. +
  4860.                                             if ($escape_regexp_cache_per_key[$escape_key]['pos'] === false) {
  4861. +
  4862.                                                 // this comment is never matched
  4863. +
  4864.                                                 continue;
  4865. +
  4866.                                             }
  4867. +
  4868.                                             $match_i = $escape_regexp_cache_per_key[$escape_key]['pos'];
  4869. +
  4870.                                         } else if (
  4871. +
  4872.                                             //This is to allow use of the offset parameter in preg_match and stay as compatible with older PHP versions as possible
  4873. +
  4874.                                             (GESHI_PHP_PRE_433 && preg_match($regexp, substr($part, $start), $match, PREG_OFFSET_CAPTURE)) ||
  4875. +
  4876.                                             (!GESHI_PHP_PRE_433 && preg_match($regexp, $part, $match, PREG_OFFSET_CAPTURE, $start))
  4877. +
  4878.                                             ) {
  4879. +
  4880.                                             $match_i = $match[0][1];
  4881. +
  4882.                                             if (GESHI_PHP_PRE_433) {
  4883. +
  4884.                                                 $match_i += $start;
  4885. +
  4886.                                             }
  4887. +
  4888.  
  4889. +
  4890.                                             $escape_regexp_cache_per_key[$escape_key] = array(
  4891. +
  4892.                                                 'key' => $escape_key,
  4893. +
  4894.                                                 'length' => strlen($match[0][0]),
  4895. +
  4896.                                                 'pos' => $match_i
  4897. +
  4898.                                             );
  4899. +
  4900.                                         } else {
  4901. +
  4902.                                             $escape_regexp_cache_per_key[$escape_key]['pos'] = false;
  4903. +
  4904.                                             continue;
  4905. +
  4906.                                         }
  4907. +
  4908.  
  4909. +
  4910.                                         if ($match_i !== false && $match_i < $next_escape_regexp_pos) {
  4911. +
  4912.                                             $next_escape_regexp_pos = $match_i;
  4913. +
  4914.                                             $next_escape_regexp_key = $escape_key;
  4915. +
  4916.                                             if ($match_i === $start) {
  4917. +
  4918.                                                 break;
  4919. +
  4920.                                             }
  4921. +
  4922.                                         }
  4923. +
  4924.                                     }
  4925. +
  4926.                                 }
  4927. +
  4928.  
  4929. +
  4930.                                 //Find the next simple escape position
  4931. +
  4932.                                 if('' != $this->language_data['ESCAPE_CHAR']) {
  4933. +
  4934.                                     $simple_escape = strpos($part, $this->language_data['ESCAPE_CHAR'], $start);
  4935. +
  4936.                                     if(false === $simple_escape) {
  4937. +
  4938.                                         $simple_escape = $length;
  4939. +
  4940.                                     }
  4941. +
  4942.                                 } else {
  4943. +
  4944.                                     $simple_escape = $length;
  4945. +
  4946.                                 }
  4947. +
  4948.                             } else {
  4949. +
  4950.                                 $next_escape_regexp_pos = $length;
  4951. +
  4952.                                 $simple_escape = $length;
  4953. +
  4954.                             }
  4955. +
  4956.  
  4957. +
  4958.                             if($simple_escape < $next_escape_regexp_pos &&
  4959. +
  4960.                                 $simple_escape < $length &&
  4961. +
  4962.                                 $simple_escape < $close_pos) {
  4963. +
  4964.                                 //The nexxt escape sequence is a simple one ...
  4965. +
  4966.                                 $es_pos = $simple_escape;
  4967. +
  4968.  
  4969. +
  4970.                                 //Add the stuff not in the string yet ...
  4971. +
  4972.                                 $string .= $this->hsc(substr($part, $start, $es_pos - $start));
  4973. +
  4974.  
  4975. +
  4976.                                 //Get the style for this escaped char ...
  4977. +
  4978.                                 if (!$this->use_classes) {
  4979. +
  4980.                                     $escape_char_attributes = ' style="' . $this->language_data['STYLES']['ESCAPE_CHAR'][0] . '"';
  4981. +
  4982.                                 } else {
  4983. +
  4984.                                     $escape_char_attributes = ' class="es0"';
  4985. +
  4986.                                 }
  4987. +
  4988.  
  4989. +
  4990.                                 //Add the style for the escape char ...
  4991. +
  4992.                                 $string .= "<span$escape_char_attributes>.
  4993. +
  4994.                                     GeSHi::hsc($this->language_data['ESCAPE_CHAR']);
  4995. +
  4996.  
  4997. +
  4998.                                 //Get the byte AFTER the ESCAPE_CHAR we just found
  4999. +
  5000.                                 $es_char = $part[$es_pos + 1];
  5001. +
  5002.                                 if ($es_char == "\n") {
  5003. +
  5004.                                     // don't put a newline around newlines
  5005. +
  5006.                                     $string .= "</span>\n";
  5007. +
  5008.                                     $start = $es_pos + 2;
  5009. +
  5010.                                 } else if (ord($es_char) >= 128) {
  5011. +
  5012.                                     //This is an non-ASCII char (UTF8 or single byte)
  5013. +
  5014.                                     //This code tries to work around SF#2037598 ...
  5015. +
  5016.                                     if(function_exists('mb_substr')) {
  5017. +
  5018.                                         $es_char_m = mb_substr(substr($part, $es_pos+1, 16), 0, 1, $this->encoding);
  5019. +
  5020.                                         $string .= $es_char_m . '</span>';
  5021. +
  5022.                                     } else if (!GESHI_PHP_PRE_433 && 'utf-8' == $this->encoding) {
  5023. +
  5024.                                         if(preg_match("/[\xC2-\xDF][\x80-\xBF]".
  5025. +
  5026.                                             "|\xE0[\xA0-\xBF][\x80-\xBF]".
  5027. +
  5028.                                             "|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}".
  5029. +
  5030.                                             "|\xED[\x80-\x9F][\x80-\xBF]".
  5031. +
  5032.                                             "|\xF0[\x90-\xBF][\x80-\xBF]{2}".
  5033. +
  5034.                                             "|[\xF1-\xF3][\x80-\xBF]{3}".
  5035. +
  5036.                                             "|\xF4[\x80-\x8F][\x80-\xBF]{2}/s",
  5037. +
  5038.                                             $part, $es_char_m, null, $es_pos + 1)) {
  5039. +
  5040.                                             $es_char_m = $es_char_m[0];
  5041. +
  5042.                                         } else {
  5043. +
  5044.                                             $es_char_m = $es_char;
  5045. +
  5046.                                         }
  5047. +
  5048.                                         $string .= $this->hsc($es_char_m) . '</span>';
  5049. +
  5050.                                     } else {
  5051. +
  5052.                                         $es_char_m = $this->hsc($es_char);
  5053. +
  5054.                                     }
  5055. +
  5056.                                     $start = $es_pos + strlen($es_char_m) + 1;
  5057. +
  5058.                                 } else {
  5059. +
  5060.                                     $string .= $this->hsc($es_char) . '</span>';
  5061. +
  5062.                                     $start = $es_pos + 2;
  5063. +
  5064.                                 }
  5065. +
  5066.                             } else if ($next_escape_regexp_pos < $length &&
  5067. +
  5068.                                 $next_escape_regexp_pos < $close_pos) {
  5069. +
  5070.                                 $es_pos = $next_escape_regexp_pos;
  5071. +
  5072.                                 //Add the stuff not in the string yet ...
  5073. +
  5074.                                 $string .= $this->hsc(substr($part, $start, $es_pos - $start));
  5075. +
  5076.  
  5077. +
  5078.                                 //Get the key and length of this match ...
  5079. +
  5080.                                 $escape = $escape_regexp_cache_per_key[$next_escape_regexp_key];
  5081. +
  5082.                                 $escape_str = substr($part, $es_pos, $escape['length']);
  5083. +
  5084.                                 $escape_key = $escape['key'];
  5085. +
  5086.  
  5087. +
  5088.                                 //Get the style for this escaped char ...
  5089. +
  5090.                                 if (!$this->use_classes) {
  5091. +
  5092.                                     $escape_char_attributes = ' style="' . $this->language_data['STYLES']['ESCAPE_CHAR'][$escape_key] . '"';
  5093. +
  5094.                                 } else {
  5095. +
  5096.                                     $escape_char_attributes = ' class="es' . $escape_key . '"';
  5097. +
  5098.                                 }
  5099. +
  5100.  
  5101. +
  5102.                                 //Add the style for the escape char ...
  5103. +
  5104.                                 $string .= "<span$escape_char_attributes>.
  5105. +
  5106.                                     $this->hsc($escape_str) . '</span>';
  5107. +
  5108.  
  5109. +
  5110.                                 $start = $es_pos + $escape['length'];
  5111. +
  5112.                             } else {
  5113. +
  5114.                                 //Copy the remainder of the string ...
  5115. +
  5116.                                 $string .= $this->hsc(substr($part, $start, $close_pos - $start + $char_len)) . '</span>';
  5117. +
  5118.                                 $start = $close_pos + $char_len;
  5119. +
  5120.                                 $string_open = false;
  5121. +
  5122.                             }
  5123. +
  5124.                         } while($string_open);
  5125. +
  5126.  
  5127. +
  5128.                         if ($check_linenumbers) {
  5129. +
  5130.                             // Are line numbers used? If, we should end the string before
  5131. +
  5132.                             // the newline and begin it again (so when <li>s are put in the source
  5133. +
  5134.                             // remains XHTML compliant)
  5135. +
  5136.                             // note to self: This opens up possibility of config files specifying
  5137. +
  5138.                             // that languages can/cannot have multiline strings???
  5139. +
  5140.                             $string = str_replace("\n", "</span>\n<span$string_attributes>", $string);
  5141. +
  5142.                         }
  5143. +
  5144.  
  5145. +
  5146.                         $result .= $string;
  5147. +
  5148.                         $string = '';
  5149. +
  5150.                         $i = $start - 1;
  5151. +
  5152.                         continue;
  5153. +
  5154.                     } else if ($this->lexic_permissions['STRINGS'] && $hq && $hq[0] == $char &&
  5155. +
  5156.                         substr($part, $i, $hq_strlen) == $hq) {
  5157. +
  5158.                         // The start of a hard quoted string
  5159. +
  5160.                         if (!$this->use_classes) {
  5161. +
  5162.                             $string_attributes = ' style="' . $this->language_data['STYLES']['STRINGS']['HARD'] . '"';
  5163. +
  5164.                             $escape_char_attributes = ' style="' . $this->language_data['STYLES']['ESCAPE_CHAR']['HARD'] . '"';
  5165. +
  5166.                         } else {
  5167. +
  5168.                             $string_attributes = ' class="st_h"';
  5169. +
  5170.                             $escape_char_attributes = ' class="es_h"';
  5171. +
  5172.                         }
  5173. +
  5174.                         // parse the stuff before this
  5175. +
  5176.                         $result .= $this->parse_non_string_part($stuff_to_parse);
  5177. +
  5178.                         $stuff_to_parse = '';
  5179. +
  5180.  
  5181. +
  5182.                         // now handle the string
  5183. +
  5184.                         $string = '';
  5185. +
  5186.  
  5187. +
  5188.                         // look for closing quote
  5189. +
  5190.                         $start = $i + $hq_strlen;
  5191. +
  5192.                         while ($close_pos = strpos($part, $this->language_data['HARDQUOTE'][1], $start)) {
  5193. +
  5194.                             $start = $close_pos + 1;
  5195. +
  5196.                             if ($this->lexic_permissions['ESCAPE_CHAR'] && $part[$close_pos - 1] == $this->language_data['ESCAPE_CHAR']) {
  5197. +
  5198.                                 // make sure this quote is not escaped
  5199. +
  5200.                                 foreach ($this->language_data['HARDESCAPE'] as $hardescape) {
  5201. +
  5202.                                     if (substr($part, $close_pos - 1, strlen($hardescape)) == $hardescape) {
  5203. +
  5204.                                         // check wether this quote is escaped or if it is something like '\\'
  5205. +
  5206.                                         $escape_char_pos = $close_pos - 1;
  5207. +
  5208.                                         while ($escape_char_pos > 0
  5209. +
  5210.                                                 && $part[$escape_char_pos - 1] == $this->language_data['ESCAPE_CHAR']) {
  5211. +
  5212.                                             --$escape_char_pos;
  5213. +
  5214.                                         }
  5215. +
  5216.                                         if (($close_pos - $escape_char_pos) & 1) {
  5217. +
  5218.                                             // uneven number of escape chars => this quote is escaped
  5219. +
  5220.                                             continue 2;
  5221. +
  5222.                                         }
  5223. +
  5224.                                     }
  5225. +
  5226.                                 }
  5227. +
  5228.                             }
  5229. +
  5230.  
  5231. +
  5232.                             // found closing quote
  5233. +
  5234.                             break;
  5235. +
  5236.                         }
  5237. +
  5238.  
  5239. +
  5240.                         //Found the closing delimiter?
  5241. +
  5242.                         if (!$close_pos) {
  5243. +
  5244.                             // span till the end of this $part when no closing delimiter is found
  5245. +
  5246.                             $close_pos = $length;
  5247. +
  5248.                         }
  5249. +
  5250.  
  5251. +
  5252.                         //Get the actual string
  5253. +
  5254.                         $string = substr($part, $i, $close_pos - $i + 1);
  5255. +
  5256.                         $i = $close_pos;
  5257. +
  5258.  
  5259. +
  5260.                         // handle escape chars and encode html chars
  5261. +
  5262.                         // (special because when we have escape chars within our string they may not be escaped)
  5263. +
  5264.                         if ($this->lexic_permissions['ESCAPE_CHAR'] && $this->language_data['ESCAPE_CHAR']) {
  5265. +
  5266.                             $start = 0;
  5267. +
  5268.                             $new_string = '';
  5269. +
  5270.                             while ($es_pos = strpos($string, $this->language_data['ESCAPE_CHAR'], $start)) {
  5271. +
  5272.                                 // hmtl escape stuff before
  5273. +
  5274.                                 $new_string .= $this->hsc(substr($string, $start, $es_pos - $start));
  5275. +
  5276.                                 // check if this is a hard escape
  5277. +
  5278.                                 foreach ($this->language_data['HARDESCAPE'] as $hardescape) {
  5279. +
  5280.                                     if (substr($string, $es_pos, strlen($hardescape)) == $hardescape) {
  5281. +
  5282.                                         // indeed, this is a hardescape
  5283. +
  5284.                                         $new_string .= "<span$escape_char_attributes>.
  5285. +
  5286.                                             $this->hsc($hardescape) . '</span>';
  5287. +
  5288.                                         $start = $es_pos + strlen($hardescape);
  5289. +
  5290.                                         continue 2;
  5291. +
  5292.                                     }
  5293. +
  5294.                                 }
  5295. +
  5296.                                 // not a hard escape, but a normal escape
  5297. +
  5298.                                 // they come in pairs of two
  5299. +
  5300.                                 $c = 0;
  5301. +
  5302.                                 while (isset($string[$es_pos + $c]) && isset($string[$es_pos + $c + 1])
  5303. +
  5304.                                     && $string[$es_pos + $c] == $this->language_data['ESCAPE_CHAR']
  5305. +
  5306.                                     && $string[$es_pos + $c + 1] == $this->language_data['ESCAPE_CHAR']) {
  5307. +
  5308.                                     $c += 2;
  5309. +
  5310.                                 }
  5311. +
  5312.                                 if ($c) {
  5313. +
  5314.                                     $new_string .= "<span$escape_char_attributes>.
  5315. +
  5316.                                         str_repeat($escaped_escape_char, $c) .
  5317. +
  5318.                                         '</span>';
  5319. +
  5320.                                     $start = $es_pos + $c;
  5321. +
  5322.                                 } else {
  5323. +
  5324.                                     // this is just a single lonely escape char...
  5325. +
  5326.                                     $new_string .= $escaped_escape_char;
  5327. +
  5328.                                     $start = $es_pos + 1;
  5329. +
  5330.                                 }
  5331. +
  5332.                             }
  5333. +
  5334.                             $string = $new_string . $this->hsc(substr($string, $start));
  5335. +
  5336.                         } else {
  5337. +
  5338.                             $string = $this->hsc($string);
  5339. +
  5340.                         }
  5341. +
  5342.  
  5343. +
  5344.                         if ($check_linenumbers) {
  5345. +
  5346.                             // Are line numbers used? If, we should end the string before
  5347. +
  5348.                             // the newline and begin it again (so when <li>s are put in the source
  5349. +
  5350.                             // remains XHTML compliant)
  5351. +
  5352.                             // note to self: This opens up possibility of config files specifying
  5353. +
  5354.                             // that languages can/cannot have multiline strings???
  5355. +
  5356.                             $string = str_replace("\n", "</span>\n<span$string_attributes>", $string);
  5357. +
  5358.                         }
  5359. +
  5360.  
  5361. +
  5362.                         $result .= "<span$string_attributes>$string . '</span>';
  5363. +
  5364.                         $string = '';
  5365. +
  5366.                         continue;
  5367. +
  5368.                     } else {
  5369. +
  5370.                         //Have a look for regexp comments
  5371. +
  5372.                         if ($i == $next_comment_regexp_pos) {
  5373. +
  5374.                             $COMMENT_MATCHED = true;
  5375. +
  5376.                             $comment = $comment_regexp_cache_per_key[$next_comment_regexp_key];
  5377. +
  5378.                             $test_str = $this->hsc(substr($part, $i, $comment['length']));
  5379. +
  5380.  
  5381. +
  5382.                             //@todo If remove important do remove here
  5383. +
  5384.                             if ($this->lexic_permissions['COMMENTS']['MULTI']) {
  5385. +
  5386.                                 if (!$this->use_classes) {
  5387. +
  5388.                                     $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS'][$comment['key']] . '"';
  5389. +
  5390.                                 } else {
  5391. +
  5392.                                     $attributes = ' class="co' . $comment['key'] . '"';
  5393. +
  5394.                                 }
  5395. +
  5396.  
  5397. +
  5398.                                 $test_str = "<span$attributes>$test_str . "</span>";
  5399. +
  5400.  
  5401. +
  5402.                                 // Short-cut through all the multiline code
  5403. +
  5404.                                 if ($check_linenumbers) {
  5405. +
  5406.                                     // strreplace to put close span and open span around multiline newlines
  5407. +
  5408.                                     $test_str = str_replace(
  5409. +
  5410.                                         "\n", "</span>\n<span$attributes>",
  5411. +
  5412.                                         str_replace("\n ", "\n&nbsp;", $test_str)
  5413. +
  5414.                                     );
  5415. +
  5416.                                 }
  5417. +
  5418.                             }
  5419. +
  5420.  
  5421. +
  5422.                             $i += $comment['length'] - 1;
  5423. +
  5424.  
  5425. +
  5426.                             // parse the rest
  5427. +
  5428.                             $result .= $this->parse_non_string_part($stuff_to_parse);
  5429. +
  5430.                             $stuff_to_parse = '';
  5431. +
  5432.                         }
  5433. +
  5434.  
  5435. +
  5436.                         // If we haven't matched a regexp comment, try multi-line comments
  5437. +
  5438.                         if (!$COMMENT_MATCHED) {
  5439. +
  5440.                             // Is this a multiline comment?
  5441. +
  5442.                             if (!empty($this->language_data['COMMENT_MULTI']) && $next_comment_multi_pos < $i) {
  5443. +
  5444.                                 $next_comment_multi_pos = $length;
  5445. +
  5446.                                 foreach ($this->language_data['COMMENT_MULTI'] as $open => $close) {
  5447. +
  5448.                                     $match_i = false;
  5449. +
  5450.                                     if (isset($comment_multi_cache_per_key[$open]) &&
  5451. +
  5452.                                         ($comment_multi_cache_per_key[$open] >= $i ||
  5453. +
  5454.                                          $comment_multi_cache_per_key[$open] === false)) {
  5455. +
  5456.                                         // we have already matched something
  5457. +
  5458.                                         if ($comment_multi_cache_per_key[$open] === false) {
  5459. +
  5460.                                             // this comment is never matched
  5461. +
  5462.                                             continue;
  5463. +
  5464.                                         }
  5465. +
  5466.                                         $match_i = $comment_multi_cache_per_key[$open];
  5467. +
  5468.                                     } else if (($match_i = stripos($part, $open, $i)) !== false) {
  5469. +
  5470.                                         $comment_multi_cache_per_key[$open] = $match_i;
  5471. +
  5472.                                     } else {
  5473. +
  5474.                                         $comment_multi_cache_per_key[$open] = false;
  5475. +
  5476.                                         continue;
  5477. +
  5478.                                     }
  5479. +
  5480.                                     if ($match_i !== false && $match_i < $next_comment_multi_pos) {
  5481. +
  5482.                                         $next_comment_multi_pos = $match_i;
  5483. +
  5484.                                         $next_open_comment_multi = $open;
  5485. +
  5486.                                         if ($match_i === $i) {
  5487. +
  5488.                                             break;
  5489. +
  5490.                                         }
  5491. +
  5492.                                     }
  5493. +
  5494.                                 }
  5495. +
  5496.                             }
  5497. +
  5498.                             if ($i == $next_comment_multi_pos) {
  5499. +
  5500.                                 $open = $next_open_comment_multi;
  5501. +
  5502.                                 $close = $this->language_data['COMMENT_MULTI'][$open];
  5503. +
  5504.                                 $open_strlen = strlen($open);
  5505. +
  5506.                                 $close_strlen = strlen($close);
  5507. +
  5508.                                 $COMMENT_MATCHED = true;
  5509. +
  5510.                                 $test_str_match = $open;
  5511. +
  5512.                                 //@todo If remove important do remove here
  5513. +
  5514.                                 if ($this->lexic_permissions['COMMENTS']['MULTI'] ||
  5515. +
  5516.                                     $open == <a href="../geshi/core/_geshi.php.html#defineGESHI_START_IMPORTANT">GESHI_START_IMPORTANT</a>) {
  5517. +
  5518.                                     if ($open != <a href="../geshi/core/_geshi.php.html#defineGESHI_START_IMPORTANT">GESHI_START_IMPORTANT</a>) {
  5519. +
  5520.                                         if (!$this->use_classes) {
  5521. +
  5522.                                             $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS']['MULTI'] . '"';
  5523. +
  5524.                                         } else {
  5525. +
  5526.                                             $attributes = ' class="coMULTI"';
  5527. +
  5528.                                         }
  5529. +
  5530.                                         $test_str = "<span$attributes>$this->hsc($open);
  5531. +
  5532.                                     } else {
  5533. +
  5534.                                         if (!$this->use_classes) {
  5535. +
  5536.                                             $attributes = ' style="' . $this->important_styles . '"';
  5537. +
  5538.                                         } else {
  5539. +
  5540.                                             $attributes = ' class="imp"';
  5541. +
  5542.                                         }
  5543. +
  5544.  
  5545. +
  5546.                                         // We don't include the start of the comment if it's an
  5547. +
  5548.                                         // "important" part
  5549. +
  5550.                                         $test_str = "<span$attributes>";
  5551. +
  5552.                                     }
  5553. +
  5554.                                 } else {
  5555. +
  5556.                                     $test_str = $this->hsc($open);
  5557. +
  5558.                                 }
  5559. +
  5560.  
  5561. +
  5562.                                 $close_pos = strpos( $part, $close, $i + $open_strlen );
  5563. +
  5564.  
  5565. +
  5566.                                 if ($close_pos === false) {
  5567. +
  5568.                                     $close_pos = $length;
  5569. +
  5570.                                 }
  5571. +
  5572.  
  5573. +
  5574.                                 // Short-cut through all the multiline code
  5575. +
  5576.                                 $rest_of_comment = $this->hsc(substr($part, $i + $open_strlen, $close_pos - $i - $open_strlen + $close_strlen));
  5577. +
  5578.                                 if (($this->lexic_permissions['COMMENTS']['MULTI'] ||
  5579. +
  5580.                                     $test_str_match == <a href="../geshi/core/_geshi.php.html#defineGESHI_START_IMPORTANT">GESHI_START_IMPORTANT</a>) &&
  5581. +
  5582.                                     $check_linenumbers) {
  5583. +
  5584.  
  5585. +
  5586.                                     // strreplace to put close span and open span around multiline newlines
  5587. +
  5588.                                     $test_str .= str_replace(
  5589. +
  5590.                                         "\n", "</span>\n<span$attributes>",
  5591. +
  5592.                                         str_replace("\n ", "\n&nbsp;", $rest_of_comment)
  5593. +
  5594.                                     );
  5595. +
  5596.                                 } else {
  5597. +
  5598.                                     $test_str .= $rest_of_comment;
  5599. +
  5600.                                 }
  5601. +
  5602.  
  5603. +
  5604.                                 if ($this->lexic_permissions['COMMENTS']['MULTI'] ||
  5605. +
  5606.                                     $test_str_match == <a href="../geshi/core/_geshi.php.html#defineGESHI_START_IMPORTANT">GESHI_START_IMPORTANT</a>) {
  5607. +
  5608.                                     $test_str .= '</span>';
  5609. +
  5610.                                 }
  5611. +
  5612.  
  5613. +
  5614.                                 $i = $close_pos + $close_strlen - 1;
  5615. +
  5616.  
  5617. +
  5618.                                 // parse the rest
  5619. +
  5620.                                 $result .= $this->parse_non_string_part($stuff_to_parse);
  5621. +
  5622.                                 $stuff_to_parse = '';
  5623. +
  5624.                             }
  5625. +
  5626.                         }
  5627. +
  5628.  
  5629. +
  5630.                         // If we haven't matched a multiline comment, try single-line comments
  5631. +
  5632.                         if (!$COMMENT_MATCHED) {
  5633. +
  5634.                             // cache potential single line comment occurances
  5635. +
  5636.                             if (!empty($this->language_data['COMMENT_SINGLE']) && $next_comment_single_pos < $i) {
  5637. +
  5638.                                 $next_comment_single_pos = $length;
  5639. +
  5640.                                 foreach ($this->language_data['COMMENT_SINGLE'] as $comment_key => $comment_mark) {
  5641. +
  5642.                                     $match_i = false;
  5643. +
  5644.                                     if (isset($comment_single_cache_per_key[$comment_key]) &&
  5645. +
  5646.                                         ($comment_single_cache_per_key[$comment_key] >= $i ||
  5647. +
  5648.                                          $comment_single_cache_per_key[$comment_key] === false)) {
  5649. +
  5650.                                         // we have already matched something
  5651. +
  5652.                                         if ($comment_single_cache_per_key[$comment_key] === false) {
  5653. +
  5654.                                             // this comment is never matched
  5655. +
  5656.                                             continue;
  5657. +
  5658.                                         }
  5659. +
  5660.                                         $match_i = $comment_single_cache_per_key[$comment_key];
  5661. +
  5662.                                     } else if (
  5663. +
  5664.                                         // case sensitive comments
  5665. +
  5666.                                         ($this->language_data['CASE_SENSITIVE'][GESHI_COMMENTS] &&
  5667. +
  5668.                                         ($match_i = stripos($part, $comment_mark, $i)) !== false) ||
  5669. +
  5670.                                         // non case sensitive
  5671. +
  5672.                                         (!$this->language_data['CASE_SENSITIVE'][GESHI_COMMENTS] &&
  5673. +
  5674.                                           (($match_i = strpos($part, $comment_mark, $i)) !== false))) {
  5675. +
  5676.                                         $comment_single_cache_per_key[$comment_key] = $match_i;
  5677. +
  5678.                                     } else {
  5679. +
  5680.                                         $comment_single_cache_per_key[$comment_key] = false;
  5681. +
  5682.                                         continue;
  5683. +
  5684.                                     }
  5685. +
  5686.                                     if ($match_i !== false && $match_i < $next_comment_single_pos) {
  5687. +
  5688.                                         $next_comment_single_pos = $match_i;
  5689. +
  5690.                                         $next_comment_single_key = $comment_key;
  5691. +
  5692.                                         if ($match_i === $i) {
  5693. +
  5694.                                             break;
  5695. +
  5696.                                         }
  5697. +
  5698.                                     }
  5699. +
  5700.                                 }
  5701. +
  5702.                             }
  5703. +
  5704.                             if ($next_comment_single_pos == $i) {
  5705. +
  5706.                                 $comment_key = $next_comment_single_key;
  5707. +
  5708.                                 $comment_mark = $this->language_data['COMMENT_SINGLE'][$comment_key];
  5709. +
  5710.                                 $com_len = strlen($comment_mark);
  5711. +
  5712.  
  5713. +
  5714.                                 // This check will find special variables like $# in bash
  5715. +
  5716.                                 // or compiler directives of Delphi beginning {$
  5717. +
  5718.                                 if ((empty($sc_disallowed_before) || ($i == 0) ||
  5719. +
  5720.                                     (false === strpos($sc_disallowed_before, $part[$i-1]))) &&
  5721. +
  5722.                                     (empty($sc_disallowed_after) || ($length <= $i + $com_len) ||
  5723. +
  5724.                                     (false === strpos($sc_disallowed_after, $part[$i + $com_len]))))
  5725. +
  5726.                                 {
  5727. +
  5728.                                     // this is a valid comment
  5729. +
  5730.                                     $COMMENT_MATCHED = true;
  5731. +
  5732.                                     if ($this->lexic_permissions['COMMENTS'][$comment_key]) {
  5733. +
  5734.                                         if (!$this->use_classes) {
  5735. +
  5736.                                             $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS'][$comment_key] . '"';
  5737. +
  5738.                                         } else {
  5739. +
  5740.                                             $attributes = ' class="co' . $comment_key . '"';
  5741. +
  5742.                                         }
  5743. +
  5744.                                         $test_str = "<span$attributes>$this->hsc($this->change_case($comment_mark));
  5745. +
  5746.                                     } else {
  5747. +
  5748.                                         $test_str = $this->hsc($comment_mark);
  5749. +
  5750.                                     }
  5751. +
  5752.  
  5753. +
  5754.                                     //Check if this comment is the last in the source
  5755. +
  5756.                                     $close_pos = strpos($part, "\n", $i);
  5757. +
  5758.                                     $oops = false;
  5759. +
  5760.                                     if ($close_pos === false) {
  5761. +
  5762.                                         $close_pos = $length;
  5763. +
  5764.                                         $oops = true;
  5765. +
  5766.                                     }
  5767. +
  5768.                                     $test_str .= $this->hsc(substr($part, $i + $com_len, $close_pos - $i - $com_len));
  5769. +
  5770.                                     if ($this->lexic_permissions['COMMENTS'][$comment_key]) {
  5771. +
  5772.                                         $test_str .= "</span>";
  5773. +
  5774.                                     }
  5775. +
  5776.  
  5777. +
  5778.                                     // Take into account that the comment might be the last in the source
  5779. +
  5780.                                     if (!$oops) {
  5781. +
  5782.                                       $test_str .= "\n";
  5783. +
  5784.                                     }
  5785. +
  5786.  
  5787. +
  5788.                                     $i = $close_pos;
  5789. +
  5790.  
  5791. +
  5792.                                     // parse the rest
  5793. +
  5794.                                     $result .= $this->parse_non_string_part($stuff_to_parse);
  5795. +
  5796.                                     $stuff_to_parse = '';
  5797. +
  5798.                                 }
  5799. +
  5800.                             }
  5801. +
  5802.                         }
  5803. +
  5804.                     }
  5805. +
  5806.  
  5807. +
  5808.                     // Where are we adding this char?
  5809. +
  5810.                     if (!$COMMENT_MATCHED) {
  5811. +
  5812.                         $stuff_to_parse .= $char;
  5813. +
  5814.                     } else {
  5815. +
  5816.                         $result .= $test_str;
  5817. +
  5818.                         unset($test_str);
  5819. +
  5820.                         $COMMENT_MATCHED = false;
  5821. +
  5822.                     }
  5823. +
  5824.                 }
  5825. +
  5826.                 // Parse the last bit
  5827. +
  5828.                 $result .= $this->parse_non_string_part($stuff_to_parse);
  5829. +
  5830.                 $stuff_to_parse = '';
  5831. +
  5832.             } else {
  5833. +
  5834.                 $result .= $this->hsc($part);
  5835. +
  5836.             }
  5837. +
  5838.             // Close the <span> that surrounds the block
  5839. +
  5840.             if ($STRICTATTRS != '') {
  5841. +
  5842.                 $result = str_replace("\n", "</span>\n<span$STRICTATTRS>", $result);
  5843. +
  5844.                 $result .= '</span>';
  5845. +
  5846.             }
  5847. +
  5848.  
  5849. +
  5850.             $endresult .= $result;
  5851. +
  5852.             unset($part, $parts[$key], $result);
  5853. +
  5854.         }
  5855. +
  5856.  
  5857. +
  5858.         //This fix is related to SF#1923020, but has to be applied regardless of
  5859. +
  5860.         //actually highlighting symbols.
  5861. +
  5862. /** NOTE: memorypeak #3 */        
  5863. +
  5864.         $endresult = str_replace(array('<SEMI>', '<PIPE>'), array(';', '|'), $endresult);
  5865. +
  5866.  
  5867. +
  5868. //        // Parse the last stuff (redundant?)
  5869. +
  5870. //        $result .= $this->parse_non_string_part($stuff_to_parse);
  5871. +
  5872. +
  5873.         // Lop off the very first and last spaces
  5874. +
  5875. //        $result = substr($result, 1, -1);
  5876. +
  5877. +
  5878.         // We're finished: stop timing
  5879. +
  5880.         $this->set_time($start_time, microtime());
  5881. +
  5882.  
  5883. +
  5884.         $this->finalise($endresult);
  5885. +
  5886.         return $endresult;
  5887. +
  5888.     }
  5889. +
  5890.  
  5891. +
  5892. /**    
  5893. +
  5894.      * Swaps out spaces and tabs for HTML indentation. Not needed if
  5895. +
  5896.      * the code is in a pre block...
  5897. +
  5898.      *
  5899. +
  5900.      * @param  string The source to indent (reference!)
  5901. +
  5902.      * @since  1.0.0
  5903. +
  5904.      * @access private
  5905. +
  5906.      */
  5907. +
  5908.     function indent(&$result) {
  5909. +
  5910.         /// Replace tabs with the correct number of spaces
  5911. +
  5912.         if (false !== strpos($result, "\t")) {
  5913. +
  5914.             $lines = explode("\n", $result);
  5915. +
  5916.             $result = null;//Save memory while we process the lines individually
  5917. +
  5918.             $tab_width = $this->get_real_tab_width();
  5919. +
  5920.             $tab_string = '&nbsp;' . str_repeat(' ', $tab_width);
  5921. +
  5922.  
  5923. +
  5924.             for ($key = 0, $n = count($lines); $key < $n; $key++) {
  5925. +
  5926.                 $line = $lines[$key];
  5927. +
  5928.                 if (false === strpos($line, "\t")) {
  5929. +
  5930.                     continue;
  5931. +
  5932.                 }
  5933. +
  5934.  
  5935. +
  5936.                 $pos = 0;
  5937. +
  5938.                 $length = strlen($line);
  5939. +
  5940.                 $lines[$key] = ''; // reduce memory
  5941. +
  5942. +
  5943.                 $IN_TAG = false;
  5944. +
  5945.                 for ($i = 0; $i < $length; ++$i) {
  5946. +
  5947.                     $char = $line[$i];
  5948. +
  5949.                     // Simple engine to work out whether we're in a tag.
  5950. +
  5951.                     // If we are we modify $pos. This is so we ignore HTML
  5952. +
  5953.                     // in the line and only workout the tab replacement
  5954. +
  5955.                     // via the actual content of the string
  5956. +
  5957.                     // This test could be improved to include strings in the
  5958. +
  5959.                     // html so that < or > would be allowed in user's styles
  5960. +
  5961.                     // (e.g. quotes: '<' '>'; or similar)
  5962. +
  5963.                     if ($IN_TAG) {
  5964. +
  5965.                         if ('>' == $char) {
  5966. +
  5967.                             $IN_TAG = false;
  5968. +
  5969.                         }
  5970. +
  5971.                         $lines[$key] .= $char;
  5972. +
  5973.                     } else if ('<' == $char) {
  5974. +
  5975.                         $IN_TAG = true;
  5976. +
  5977.                         $lines[$key] .= '<';
  5978. +
  5979.                     } else if ('&' == $char) {
  5980. +
  5981.                         $substr = substr($line, $i + 3, 5);
  5982. +
  5983.                         $posi = strpos($substr, ';');
  5984. +
  5985.                         if (false === $posi) {
  5986. +
  5987.                             ++$pos;
  5988. +
  5989.                         } else {
  5990. +
  5991.                             $pos -= $posi+2;
  5992. +
  5993.                         }
  5994. +
  5995.                         $lines[$key] .= $char;
  5996. +
  5997.                     } else if ("\t" == $char) {
  5998. +
  5999.                         $str = '';
  6000. +
  6001.                         // OPTIMISE - move $strs out. Make an array:
  6002. +
  6003.                         // $tabs = array(
  6004. +
  6005.                         //  1 => '&nbsp;',
  6006. +
  6007.                         //  2 => '&nbsp; ',
  6008. +
  6009.                         //  3 => '&nbsp; &nbsp;' etc etc
  6010. +
  6011.                         // to use instead of building a string every time
  6012. +
  6013.                         $tab_end_width = $tab_width - ($pos % $tab_width); //Moved out of the look as it doesn't change within the loop
  6014. +
  6015.                         if (($pos & 1) || 1 == $tab_end_width) {
  6016. +
  6017.                             $str .= substr($tab_string, 6, $tab_end_width);
  6018. +
  6019.                         } else {
  6020. +
  6021.                             $str .= substr($tab_string, 0, $tab_end_width+5);
  6022. +
  6023.                         }
  6024. +
  6025.                         $lines[$key] .= $str;
  6026. +
  6027.                         $pos += $tab_end_width;
  6028. +
  6029.  
  6030. +
  6031.                         if (false === strpos($line, "\t", $i + 1)) {
  6032. +
  6033.                             $lines[$key] .= substr($line, $i + 1);
  6034. +
  6035.                             break;
  6036. +
  6037.                         }
  6038. +
  6039.                     } else if (0 == $pos && ' ' == $char) {
  6040. +
  6041.                         $lines[$key] .= '&nbsp;';
  6042. +
  6043.                         ++$pos;
  6044. +
  6045.                     } else {
  6046. +
  6047.                         $lines[$key] .= $char;
  6048. +
  6049.                         ++$pos;
  6050. +
  6051.                     }
  6052. +
  6053.                 }
  6054. +
  6055.             }
  6056. +
  6057.             $result = implode("\n", $lines);
  6058. +
  6059.             unset($lines);//We don't need the lines separated beyond this --- free them!
  6060. +
  6061.         }
  6062. +
  6063.         // Other whitespace
  6064. +
  6065.         // BenBE: Fix to reduce the number of replacements to be done
  6066. +
  6067.         $result = preg_replace('/^ /m', '&nbsp;', $result);
  6068. +
  6069.         $result = str_replace('  ', ' &nbsp;', $result);
  6070. +
  6071.  
  6072. +
  6073.         if ($this->line_numbers == <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  6074. +
  6075.             if ($this->line_ending === null) {
  6076. +
  6077.                 $result = nl2br($result);
  6078. +
  6079.             } else {
  6080. +
  6081.                 $result = str_replace("\n", $this->line_ending, $result);
  6082. +
  6083.             }
  6084. +
  6085.         }
  6086. +
  6087.     }
  6088. +
  6089.  
  6090. +
  6091. /**    
  6092. +
  6093.      * Changes the case of a keyword for those languages where a change is asked for
  6094. +
  6095.      *
  6096. +
  6097.      * @param  string The keyword to change the case of
  6098. +
  6099.      * @return string The keyword with its case changed
  6100. +
  6101.      * @since  1.0.0
  6102. +
  6103.      * @access private
  6104. +
  6105.      */
  6106. +
  6107.     function change_case($instr) {
  6108. +
  6109.         switch ($this->language_data['CASE_KEYWORDS']) {
  6110. +
  6111.             case <a href="../geshi/core/_geshi.php.html#defineGESHI_CAPS_UPPER">GESHI_CAPS_UPPER</a>:
  6112. +
  6113.                 return strtoupper($instr);
  6114. +
  6115.             case <a href="../geshi/core/_geshi.php.html#defineGESHI_CAPS_LOWER">GESHI_CAPS_LOWER</a>:
  6116. +
  6117.                 return strtolower($instr);
  6118. +
  6119.             default:
  6120. +
  6121.                 return $instr;
  6122. +
  6123.         }
  6124. +
  6125.     }
  6126. +
  6127.  
  6128. +
  6129. /**    
  6130. +
  6131.      * Handles replacements of keywords to include markup and links if requested
  6132. +
  6133.      *
  6134. +
  6135.      * @param  string The keyword to add the Markup to
  6136. +
  6137.      * @return The HTML for the match found
  6138. +
  6139.      * @since  1.0.8
  6140. +
  6141.      * @access private
  6142. +
  6143.      *
  6144. +
  6145.      * @todo   Get rid of ender in keyword links
  6146. +
  6147.      */
  6148. +
  6149.     function handle_keyword_replace($match) {
  6150. +
  6151.         $k = $this->_kw_replace_group;
  6152. +
  6153.         $keyword = $match[0];
  6154. +
  6155.  
  6156. +
  6157.         $before = '';
  6158. +
  6159.         $after = '';
  6160. +
  6161.  
  6162. +
  6163.         if ($this->keyword_links) {
  6164. +
  6165.             // Keyword links have been ebabled
  6166. +
  6167. +
  6168.             if (isset($this->language_data['URLS'][$k]) &&
  6169. +
  6170.                 $this->language_data['URLS'][$k] != '') {
  6171. +
  6172.                 // There is a base group for this keyword
  6173. +
  6174. +
  6175.                 // Old system: strtolower
  6176. +
  6177.                 //$keyword = ( $this->language_data['CASE_SENSITIVE'][$group] ) ? $keyword : strtolower($keyword);
  6178. +
  6179.                 // New system: get keyword from language file to get correct case
  6180. +
  6181.                 if (!$this->language_data['CASE_SENSITIVE'][$k] &&
  6182. +
  6183.                     strpos($this->language_data['URLS'][$k], '{FNAME}') !== false) {
  6184. +
  6185.                     foreach ($this->language_data['KEYWORDS'][$k] as $word) {
  6186. +
  6187.                         if (strcasecmp($word, $keyword) == 0) {
  6188. +
  6189.                             break;
  6190. +
  6191.                         }
  6192. +
  6193.                     }
  6194. +
  6195.                 } else {
  6196. +
  6197.                     $word = $keyword;
  6198. +
  6199.                 }
  6200. +
  6201.  
  6202. +
  6203.                 $before = '<|UR1|"' .
  6204. +
  6205.                     str_replace(
  6206. +
  6207.                         array(
  6208. +
  6209.                             '{FNAME}',
  6210. +
  6211.                             '{FNAMEL}',
  6212. +
  6213.                             '{FNAMEU}',
  6214. +
  6215.                             '.'),
  6216. +
  6217.                         array(
  6218. +
  6219.                             str_replace('+', '%20', urlencode($this->hsc($word))),
  6220. +
  6221.                             str_replace('+', '%20', urlencode($this->hsc(strtolower($word)))),
  6222. +
  6223.                             str_replace('+', '%20', urlencode($this->hsc(strtoupper($word)))),
  6224. +
  6225.                             '<DOT>'),
  6226. +
  6227.                         $this->language_data['URLS'][$k]
  6228. +
  6229.                     ) . '">';
  6230. +
  6231.                 $after = '</a>';
  6232. +
  6233.             }
  6234. +
  6235.         }
  6236. +
  6237.  
  6238. +
  6239.         return $before . '<|/'$k .'/>' . $this->change_case($keyword) . '|>' . $after;
  6240. +
  6241.     }
  6242. +
  6243.  
  6244. +
  6245. /**    
  6246. +
  6247.      * handles regular expressions highlighting-definitions with callback functions
  6248. +
  6249.      *
  6250. +
  6251.      * @note this is a callback, don't use it directly
  6252. +
  6253.      *
  6254. +
  6255.      * @param array the matches array
  6256. +
  6257.      * @return The highlighted string
  6258. +
  6259.      * @since 1.0.8
  6260. +
  6261.      * @access private
  6262. +
  6263.      */
  6264. +
  6265.     function handle_regexps_callback($matches) {
  6266. +
  6267.         // before: "' style=\"' . call_user_func(\"$func\", '\\1') . '\"\\1|>'",
  6268. +
  6269.         return  ' style="' . call_user_func($this->language_data['STYLES']['REGEXPS'][$this->_rx_key], $matches[1]) . '"'$matches[1] . '|>';
  6270. +
  6271.     }
  6272. +
  6273.  
  6274. +
  6275. /**    
  6276. +
  6277.      * handles newlines in REGEXPS matches. Set the _hmr_* vars before calling this
  6278. +
  6279.      *
  6280. +
  6281.      * @note this is a callback, don't use it directly
  6282. +
  6283.      *
  6284. +
  6285.      * @param array the matches array
  6286. +
  6287.      * @return string 
  6288. +
  6289.      * @since 1.0.8
  6290. +
  6291.      * @access private
  6292. +
  6293.      */
  6294. +
  6295.     function handle_multiline_regexps($matches) {
  6296. +
  6297.         $before = $this->_hmr_before;
  6298. +
  6299.         $after = $this->_hmr_after;
  6300. +
  6301.         if ($this->_hmr_replace) {
  6302. +
  6303.             $replace = $this->_hmr_replace;
  6304. +
  6305.             $search = array();
  6306. +
  6307.  
  6308. +
  6309.             foreach (array_keys($matches) as $k) {
  6310. +
  6311.                 $search[] = '\\' . $k;
  6312. +
  6313.             }
  6314. +
  6315.  
  6316. +
  6317.             $before = str_replace($search, $matches, $before);
  6318. +
  6319.             $after = str_replace($search, $matches, $after);
  6320. +
  6321.             $replace = str_replace($search, $matches, $replace);
  6322. +
  6323.         } else {
  6324. +
  6325.             $replace = $matches[0];
  6326. +
  6327.         }
  6328. +
  6329.         return $before
  6330. +
  6331.                     . '<|!REG3XP' . $this->_hmr_key .'!>'
  6332. +
  6333.                         . str_replace("\n", "|>\n<|!REG3XP" . $this->_hmr_key . '!>', $replace)
  6334. +
  6335.                     . '|>'
  6336. +
  6337.               . $after;
  6338. +
  6339.     }
  6340. +
  6341.  
  6342. +
  6343. /**    
  6344. +
  6345.      * Takes a string that has no strings or comments in it, and highlights
  6346. +
  6347.      * stuff like keywords, numbers and methods.
  6348. +
  6349.      *
  6350. +
  6351.      * @param string The string to parse for keyword, numbers etc.
  6352. +
  6353.      * @since 1.0.0
  6354. +
  6355.      * @access private
  6356. +
  6357.      * @todo BUGGY! Why? Why not build string and return?
  6358. +
  6359.      */
  6360. +
  6361.     function parse_non_string_part($stuff_to_parse) {
  6362. +
  6363.         $stuff_to_parse = ' ' . $this->hsc($stuff_to_parse);
  6364. +
  6365.  
  6366. +
  6367.         // Regular expressions
  6368. +
  6369.         foreach ($this->language_data['REGEXPS'] as $key => $regexp) {
  6370. +
  6371.             if ($this->lexic_permissions['REGEXPS'][$key]) {
  6372. +
  6373.                 if (is_array($regexp)) {
  6374. +
  6375.                     if ($this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  6376. +
  6377.                         // produce valid HTML when we match multiple lines
  6378. +
  6379.                         $this->_hmr_replace = $regexp[GESHI_REPLACE];
  6380. +
  6381.                         $this->_hmr_before = $regexp[GESHI_BEFORE];
  6382. +
  6383.                         $this->_hmr_key = $key;
  6384. +
  6385.                         $this->_hmr_after = $regexp[GESHI_AFTER];
  6386. +
  6387.                         $stuff_to_parse = preg_replace_callback(
  6388. +
  6389.                             "/" . $regexp[GESHI_SEARCH] . "/{$regexp[GESHI_MODIFIERS]}",
  6390. +
  6391.                             array($this, 'handle_multiline_regexps'),
  6392. +
  6393.                             $stuff_to_parse);
  6394. +
  6395.                         $this->_hmr_replace = false;
  6396. +
  6397.                         $this->_hmr_before = '';
  6398. +
  6399.                         $this->_hmr_after = '';
  6400. +
  6401.                     } else {
  6402. +
  6403.                         $stuff_to_parse = preg_replace(
  6404. +
  6405.                             '/' . $regexp[GESHI_SEARCH] . '/' . $regexp[GESHI_MODIFIERS],
  6406. +
  6407.                             $regexp[GESHI_BEFORE] . '<|!REG3XP'$key .'!>' . $regexp[GESHI_REPLACE] . '|>' . $regexp[GESHI_AFTER],
  6408. +
  6409.                             $stuff_to_parse);
  6410. +
  6411.                     }
  6412. +
  6413.                 } else {
  6414. +
  6415.                     if ($this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  6416. +
  6417.                         // produce valid HTML when we match multiple lines
  6418. +
  6419.                         $this->_hmr_key = $key;
  6420. +
  6421.                         $stuff_to_parse = preg_replace_callback( "/(" . $regexp . ")/",
  6422. +
  6423.                                               array($this, 'handle_multiline_regexps'), $stuff_to_parse);
  6424. +
  6425.                         $this->_hmr_key = '';
  6426. +
  6427.                     } else {
  6428. +
  6429.                         $stuff_to_parse = preg_replace( "/(" . $regexp . ")/", "<|!REG3XP$key!>\\1|>", $stuff_to_parse);
  6430. +
  6431.                     }
  6432. +
  6433.                 }
  6434. +
  6435.             }
  6436. +
  6437.         }
  6438. +
  6439.  
  6440. +
  6441.         // Highlight numbers. As of 1.0.8 we support diffent types of numbers
  6442. +
  6443.         $numbers_found = false;
  6444. +
  6445.         if ($this->lexic_permissions['NUMBERS'] && preg_match('#\d#', $stuff_to_parse )) {
  6446. +
  6447.             $numbers_found = true;
  6448. +
  6449.  
  6450. +
  6451.             //For each of the formats ...
  6452. +
  6453.             foreach($this->language_data['NUMBERS_RXCACHE'] as $id => $regexp) {
  6454. +
  6455.                 //Check if it should be highlighted ...
  6456. +
  6457.                 $stuff_to_parse = preg_replace($regexp, "<|/NUM!$id/>\\1|>", $stuff_to_parse);
  6458. +
  6459.             }
  6460. +
  6461.         }
  6462. +
  6463.  
  6464. +
  6465.         // Highlight keywords
  6466. +
  6467.         $disallowed_before = "(?<![a-zA-Z0-9\$_\|\#;>|^&";
  6468. +
  6469.         $disallowed_after = "(?![a-zA-Z0-9_\|%\\-&;";
  6470. +
  6471.         if ($this->lexic_permissions['STRINGS']) {
  6472. +
  6473.             $quotemarks = preg_quote(implode($this->language_data['QUOTEMARKS']), '/');
  6474. +
  6475.             $disallowed_before .= $quotemarks;
  6476. +
  6477.             $disallowed_after .= $quotemarks;
  6478. +
  6479.         }
  6480. +
  6481.         $disallowed_before .= "])";
  6482. +
  6483.         $disallowed_after .= "])";
  6484. +
  6485.  
  6486. +
  6487.         $parser_control_pergroup = false;
  6488. +
  6489.         if (isset($this->language_data['PARSER_CONTROL'])) {
  6490. +
  6491.             if (isset($this->language_data['PARSER_CONTROL']['KEYWORDS'])) {
  6492. +
  6493.                 $x = 0; // check wether per-keyword-group parser_control is enabled
  6494. +
  6495.                 if (isset($this->language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE'])) {
  6496. +
  6497.                     $disallowed_before = $this->language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_BEFORE'];
  6498. +
  6499.                     ++$x;
  6500. +
  6501.                 }
  6502. +
  6503.                 if (isset($this->language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER'])) {
  6504. +
  6505.                     $disallowed_after = $this->language_data['PARSER_CONTROL']['KEYWORDS']['DISALLOWED_AFTER'];
  6506. +
  6507.                     ++$x;
  6508. +
  6509.                 }
  6510. +
  6511.                 $parser_control_pergroup = (count($this->language_data['PARSER_CONTROL']['KEYWORDS']) - $x) > 0;
  6512. +
  6513.             }
  6514. +
  6515.         }
  6516. +
  6517.  
  6518. +
  6519.         // if this is changed, don't forget to change it below
  6520. +
  6521. //        if (!empty($disallowed_before)) {
  6522. +
  6523. //            $disallowed_before = "(?<![$disallowed_before])";
  6524. +
  6525. //        }
  6526. +
  6527. //        if (!empty($disallowed_after)) {
  6528. +
  6529. //            $disallowed_after = "(?![$disallowed_after])";
  6530. +
  6531. //        }
  6532. +
  6533. +
  6534.         foreach (array_keys($this->language_data['KEYWORDS']) as $k) {
  6535. +
  6536.             if (!isset($this->lexic_permissions['KEYWORDS'][$k]) ||
  6537. +
  6538.                 $this->lexic_permissions['KEYWORDS'][$k]) {
  6539. +
  6540.  
  6541. +
  6542.                 $case_sensitive = $this->language_data['CASE_SENSITIVE'][$k];
  6543. +
  6544.                 $modifiers = $case_sensitive ? '' : 'i';
  6545. +
  6546.  
  6547. +
  6548.                 // NEW in 1.0.8 - per-keyword-group parser control
  6549. +
  6550.                 $disallowed_before_local = $disallowed_before;
  6551. +
  6552.                 $disallowed_after_local = $disallowed_after;
  6553. +
  6554.                 if ($parser_control_pergroup && isset($this->language_data['PARSER_CONTROL']['KEYWORDS'][$k])) {
  6555. +
  6556.                     if (isset($this->language_data['PARSER_CONTROL']['KEYWORDS'][$k]['DISALLOWED_BEFORE'])) {
  6557. +
  6558.                         $disallowed_before_local =
  6559. +
  6560.                             $this->language_data['PARSER_CONTROL']['KEYWORDS'][$k]['DISALLOWED_BEFORE'];
  6561. +
  6562.                     }
  6563. +
  6564.  
  6565. +
  6566.                     if (isset($this->language_data['PARSER_CONTROL']['KEYWORDS'][$k]['DISALLOWED_AFTER'])) {
  6567. +
  6568.                         $disallowed_after_local =
  6569. +
  6570.                             $this->language_data['PARSER_CONTROL']['KEYWORDS'][$k]['DISALLOWED_AFTER'];
  6571. +
  6572.                     }
  6573. +
  6574.                 }
  6575. +
  6576.  
  6577. +
  6578.                 $this->_kw_replace_group = $k;
  6579. +
  6580.  
  6581. +
  6582.                 //NEW in 1.0.8, the cached regexp list
  6583. +
  6584.                 // since we don't want PHP / PCRE to crash due to too large patterns we split them into smaller chunks
  6585. +
  6586.                 for ($set = 0, $set_length = count($this->language_data['CACHED_KEYWORD_LISTS'][$k]); $set <  $set_length; ++$set) {
  6587. +
  6588.                     $keywordset =& $this->language_data['CACHED_KEYWORD_LISTS'][$k][$set];
  6589. +
  6590.                     // Might make a more unique string for putting the number in soon
  6591. +
  6592.                     // Basically, we don't put the styles in yet because then the styles themselves will
  6593. +
  6594.                     // get highlighted if the language has a CSS keyword in it (like CSS, for example ;))
  6595. +
  6596.                     $stuff_to_parse = preg_replace_callback(
  6597. +
  6598.                         "/$disallowed_before_local({$keywordset})(?!\<DOT\>(?:htm|php))$disallowed_after_local/$modifiers",
  6599. +
  6600.                         array($this, 'handle_keyword_replace'),
  6601. +
  6602.                         $stuff_to_parse
  6603. +
  6604.                         );
  6605. +
  6606.                 }
  6607. +
  6608.             }
  6609. +
  6610.         }
  6611. +
  6612.  
  6613. +
  6614.         //
  6615. +
  6616.         // Now that's all done, replace /[number]/ with the correct styles
  6617. +
  6618.         //
  6619. +
  6620.         foreach (array_keys($this->language_data['KEYWORDS']) as $k) {
  6621. +
  6622.             if (!$this->use_classes) {
  6623. +
  6624.                 $attributes = ' style="' .
  6625. +
  6626.                     (isset($this->language_data['STYLES']['KEYWORDS'][$k]) ?
  6627. +
  6628.                     $this->language_data['STYLES']['KEYWORDS'][$k] : "") . '"';
  6629. +
  6630.             } else {
  6631. +
  6632.                 $attributes = ' class="kw' . $k . '"';
  6633. +
  6634.             }
  6635. +
  6636.             $stuff_to_parse = str_replace("<|/$k/>", "<|$attributes>", $stuff_to_parse);
  6637. +
  6638.         }
  6639. +
  6640.  
  6641. +
  6642.         if ($numbers_found) {
  6643. +
  6644.             // Put number styles in
  6645. +
  6646.             foreach($this->language_data['NUMBERS_RXCACHE'] as $id => $regexp) {
  6647. +
  6648. //Commented out for now, as this needs some review ...
  6649. +
  6650. //                if ($numbers_permissions & $id) {
  6651. +
  6652.                     //Get the appropriate style ...
  6653. +
  6654.                         //Checking for unset styles is done by the style cache builder ...
  6655. +
  6656.                     if (!$this->use_classes) {
  6657. +
  6658.                         $attributes = ' style="' . $this->language_data['STYLES']['NUMBERS'][$id] . '"';
  6659. +
  6660.                     } else {
  6661. +
  6662.                         $attributes = ' class="nu'.$id.'"';
  6663. +
  6664.                     }
  6665. +
  6666.  
  6667. +
  6668.                     //Set in the correct styles ...
  6669. +
  6670.                     $stuff_to_parse = str_replace("/NUM!$id/", $attributes, $stuff_to_parse);
  6671. +
  6672. //                }
  6673. +
  6674.             }
  6675. +
  6676.         }
  6677. +
  6678.  
  6679. +
  6680.         // Highlight methods and fields in objects
  6681. +
  6682.         if ($this->lexic_permissions['METHODS'] && $this->language_data['OOLANG']) {
  6683. +
  6684.             $oolang_spaces = "[\s]*";
  6685. +
  6686.             $oolang_before = "";
  6687. +
  6688.             $oolang_after = "[a-zA-Z][a-zA-Z0-9_]*";
  6689. +
  6690.             if (isset($this->language_data['PARSER_CONTROL'])) {
  6691. +
  6692.                 if (isset($this->language_data['PARSER_CONTROL']['OOLANG'])) {
  6693. +
  6694.                     if (isset($this->language_data['PARSER_CONTROL']['OOLANG']['MATCH_BEFORE'])) {
  6695. +
  6696.                         $oolang_before = $this->language_data['PARSER_CONTROL']['OOLANG']['MATCH_BEFORE'];
  6697. +
  6698.                     }
  6699. +
  6700.                     if (isset($this->language_data['PARSER_CONTROL']['OOLANG']['MATCH_AFTER'])) {
  6701. +
  6702.                         $oolang_after = $this->language_data['PARSER_CONTROL']['OOLANG']['MATCH_AFTER'];
  6703. +
  6704.                     }
  6705. +
  6706.                     if (isset($this->language_data['PARSER_CONTROL']['OOLANG']['MATCH_SPACES'])) {
  6707. +
  6708.                         $oolang_spaces = $this->language_data['PARSER_CONTROL']['OOLANG']['MATCH_SPACES'];
  6709. +
  6710.                     }
  6711. +
  6712.                 }
  6713. +
  6714.             }
  6715. +
  6716.  
  6717. +
  6718.             foreach ($this->language_data['OBJECT_SPLITTERS'] as $key => $splitter) {
  6719. +
  6720.                 if (false !== strpos($stuff_to_parse, $splitter)) {
  6721. +
  6722.                     if (!$this->use_classes) {
  6723. +
  6724.                         $attributes = ' style="' . $this->language_data['STYLES']['METHODS'][$key] . '"';
  6725. +
  6726.                     } else {
  6727. +
  6728.                         $attributes = ' class="me' . $key . '"';
  6729. +
  6730.                     }
  6731. +
  6732.                     $stuff_to_parse = preg_replace("/($oolang_before)(preg_quote($this->language_data['OBJECT_SPLITTERS'][$key], '/') . ")($oolang_spaces)($oolang_after)/", "\\1\\2\\3<|$attributes>\\4|>", $stuff_to_parse);
  6733. +
  6734.                 }
  6735. +
  6736.             }
  6737. +
  6738.         }
  6739. +
  6740.  
  6741. +
  6742.         //
  6743. +
  6744.         // Highlight brackets. Yes, I've tried adding a semi-colon to this list.
  6745. +
  6746.         // You try it, and see what happens ;)
  6747. +
  6748.         // TODO: Fix lexic permissions not converting entities if shouldn't
  6749. +
  6750.         // be highlighting regardless
  6751. +
  6752.         //
  6753. +
  6754.         if ($this->lexic_permissions['BRACKETS']) {
  6755. +
  6756.             $stuff_to_parse = str_replace( $this->language_data['CACHE_BRACKET_MATCH'],
  6757. +
  6758.                               $this->language_data['CACHE_BRACKET_REPLACE'], $stuff_to_parse );
  6759. +
  6760.         }
  6761. +
  6762.  
  6763. +
  6764.  
  6765. +
  6766.         //FIX for symbol highlighting ...
  6767. +
  6768.         if ($this->lexic_permissions['SYMBOLS'] && !empty($this->language_data['SYMBOLS'])) {
  6769. +
  6770.             //Get all matches and throw away those witin a block that is already highlighted... (i.e. matched by a regexp)
  6771. +
  6772.             $n_symbols = preg_match_all("/<\|(?:<DOT>|[^>])+>(?:(?!\|>).*?)\|>|<\/a>|(?:" . $this->language_data['SYMBOL_SEARCH'] . ")+/", $stuff_to_parse, $pot_symbols, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
  6773. +
  6774.             $global_offset = 0;
  6775. +
  6776.             for ($s_id = 0; $s_id < $n_symbols; ++$s_id) {
  6777. +
  6778.                 $symbol_match = $pot_symbols[$s_id][0][0];
  6779. +
  6780.                 if (strpos($symbol_match, '<') !== false || strpos($symbol_match, '>') !== false) {
  6781. +
  6782.                     // already highlighted blocks _must_ include either < or >
  6783. +
  6784.                     // so if this conditional applies, we have to skip this match
  6785. +
  6786.                     // BenBE: UNLESS the block contains <SEMI> or <PIPE>
  6787. +
  6788.                     if(strpos($symbol_match, '<SEMI>') === false &&
  6789. +
  6790.                         strpos($symbol_match, '<PIPE>') === false) {
  6791. +
  6792.                         continue;
  6793. +
  6794.                     }
  6795. +
  6796.                 }
  6797. +
  6798.  
  6799. +
  6800.                 // if we reach this point, we have a valid match which needs to be highlighted
  6801. +
  6802. +
  6803.                 $symbol_length = strlen($symbol_match);
  6804. +
  6805.                 $symbol_offset = $pot_symbols[$s_id][0][1];
  6806. +
  6807.                 unset($pot_symbols[$s_id]);
  6808. +
  6809.                 $symbol_end = $symbol_length + $symbol_offset;
  6810. +
  6811.                 $symbol_hl = "";
  6812. +
  6813.  
  6814. +
  6815.                 // if we have multiple styles, we have to handle them properly
  6816. +
  6817.                 if ($this->language_data['MULTIPLE_SYMBOL_GROUPS']) {
  6818. +
  6819.                     $old_sym = -1;
  6820. +
  6821.                     // Split the current stuff to replace into its atomic symbols ...
  6822. +
  6823.                     preg_match_all("/" . $this->language_data['SYMBOL_SEARCH'] . "/", $symbol_match, $sym_match_syms, PREG_PATTERN_ORDER);
  6824. +
  6825.                     foreach ($sym_match_syms[0] as $sym_ms) {
  6826. +
  6827.                         //Check if consequtive symbols belong to the same group to save output ...
  6828. +
  6829.                         if (isset($this->language_data['SYMBOL_DATA'][$sym_ms])
  6830. +
  6831.                             && ($this->language_data['SYMBOL_DATA'][$sym_ms] != $old_sym)) {
  6832. +
  6833.                             if (-1 != $old_sym) {
  6834. +
  6835.                                 $symbol_hl .= "|>";
  6836. +
  6837.                             }
  6838. +
  6839.                             $old_sym = $this->language_data['SYMBOL_DATA'][$sym_ms];
  6840. +
  6841.                             if (!$this->use_classes) {
  6842. +
  6843.                                 $symbol_hl .= '<| style="' . $this->language_data['STYLES']['SYMBOLS'][$old_sym] . '">';
  6844. +
  6845.                             } else {
  6846. +
  6847.                                 $symbol_hl .= '<| class="sy' . $old_sym . '">';
  6848. +
  6849.                             }
  6850. +
  6851.                         }
  6852. +
  6853.                         $symbol_hl .= $sym_ms;
  6854. +
  6855.                     }
  6856. +
  6857.                     unset($sym_match_syms);
  6858. +
  6859.  
  6860. +
  6861.                     //Close remaining tags and insert the replacement at the right position ...
  6862. +
  6863.                     //Take caution if symbol_hl is empty to avoid doubled closing spans.
  6864. +
  6865.                     if (-1 != $old_sym) {
  6866. +
  6867.                         $symbol_hl .= "|>";
  6868. +
  6869.                     }
  6870. +
  6871.                 } else {
  6872. +
  6873.                     if (!$this->use_classes) {
  6874. +
  6875.                         $symbol_hl = '<| style="' . $this->language_data['STYLES']['SYMBOLS'][0] . '">';
  6876. +
  6877.                     } else {
  6878. +
  6879.                         $symbol_hl = '<| class="sy0">';
  6880. +
  6881.                     }
  6882. +
  6883.                     $symbol_hl .= $symbol_match . '|>';
  6884. +
  6885.                 }
  6886. +
  6887.  
  6888. +
  6889.                 $stuff_to_parse = substr_replace($stuff_to_parse, $symbol_hl, $symbol_offset + $global_offset, $symbol_length);
  6890. +
  6891.  
  6892. +
  6893.                 // since we replace old text with something of different size,
  6894. +
  6895.                 // we'll have to keep track of the differences
  6896. +
  6897.                 $global_offset += strlen($symbol_hl) - $symbol_length;
  6898. +
  6899.             }
  6900. +
  6901.         }
  6902. +
  6903.         //FIX for symbol highlighting ...
  6904. +
  6905. +
  6906.         // Add class/style for regexps
  6907. +
  6908.         foreach (array_keys($this->language_data['REGEXPS']) as $key) {
  6909. +
  6910.             if ($this->lexic_permissions['REGEXPS'][$key]) {
  6911. +
  6912.                 if (is_callable($this->language_data['STYLES']['REGEXPS'][$key])) {
  6913. +
  6914.                     $this->_rx_key = $key;
  6915. +
  6916.                     $stuff_to_parse = preg_replace_callback("/!REG3XP$key!(.*)\|>/U",
  6917. +
  6918.                         array($this, 'handle_regexps_callback'),
  6919. +
  6920.                         $stuff_to_parse);
  6921. +
  6922.                 } else {
  6923. +
  6924.                     if (!$this->use_classes) {
  6925. +
  6926.                         $attributes = ' style="' . $this->language_data['STYLES']['REGEXPS'][$key] . '"';
  6927. +
  6928.                     } else {
  6929. +
  6930.                         if (is_array($this->language_data['REGEXPS'][$key]) &&
  6931. +
  6932.                             array_key_exists(GESHI_CLASS, $this->language_data['REGEXPS'][$key])) {
  6933. +
  6934.                             $attributes = ' class="' .
  6935. +
  6936.                                 $this->language_data['REGEXPS'][$key][GESHI_CLASS] . '"';
  6937. +
  6938.                         } else {
  6939. +
  6940.                            $attributes = ' class="re' . $key . '"';
  6941. +
  6942.                         }
  6943. +
  6944.                     }
  6945. +
  6946.                     $stuff_to_parse = str_replace("!REG3XP$key!", "$attributes", $stuff_to_parse);
  6947. +
  6948.                 }
  6949. +
  6950.             }
  6951. +
  6952.         }
  6953. +
  6954.  
  6955. +
  6956.         // Replace <DOT> with . for urls
  6957. +
  6958.         $stuff_to_parse = str_replace('<DOT>', '.', $stuff_to_parse);
  6959. +
  6960.         // Replace <|UR1| with <a href= for urls also
  6961. +
  6962.         if (isset($this->link_styles[<a href="../geshi/core/_geshi.php.html#defineGESHI_LINK">GESHI_LINK</a>])) {
  6963. +
  6964.             if ($this->use_classes) {
  6965. +
  6966.                 $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse);
  6967. +
  6968.             } else {
  6969. +
  6970.                 $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' style="' . $this->link_styles[<a href="../geshi/core/_geshi.php.html#defineGESHI_LINK">GESHI_LINK</a>] . '" href=', $stuff_to_parse);
  6971. +
  6972.             }
  6973. +
  6974.         } else {
  6975. +
  6976.             $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse);
  6977. +
  6978.         }
  6979. +
  6980.  
  6981. +
  6982.         //
  6983. +
  6984.         // NOW we add the span thingy ;)
  6985. +
  6986.         //
  6987. +
  6988. +
  6989.         $stuff_to_parse = str_replace('<|', '<span', $stuff_to_parse);
  6990. +
  6991.         $stuff_to_parse = str_replace ( '|>', '</span>', $stuff_to_parse );
  6992. +
  6993.         return substr($stuff_to_parse, 1);
  6994. +
  6995.     }
  6996. +
  6997.  
  6998. +
  6999.     /**
  7000. +
  7001.      * Sets the time taken to parse the code
  7002. +
  7003.      *
  7004. +
  7005.      * @param microtime The time when parsing started
  7006. +
  7007.      * @param microtime The time when parsing ended
  7008. +
  7009.      * @since 1.0.2
  7010. +
  7011.      * @access private
  7012. +
  7013.      */
  7014. +
  7015.     function set_time($start_time, $end_time) {
  7016. +
  7017.         $start = explode(' ', $start_time);
  7018. +
  7019.         $end = explode(' ', $end_time);
  7020. +
  7021.         $this->time = $end[0] + $end[1] - $start[0] - $start[1];
  7022. +
  7023.     }
  7024. +
  7025.  
  7026. +
  7027.     /**
  7028. +
  7029.      * Gets the time taken to parse the code
  7030. +
  7031.      *
  7032. +
  7033.      * @return double The time taken to parse the code
  7034. +
  7035.      * @since  1.0.2
  7036. +
  7037.      */
  7038. +
  7039.     function get_time() {
  7040. +
  7041.         return $this->time;
  7042. +
  7043.     }
  7044. +
  7045.  
  7046. +
  7047.     /**
  7048. +
  7049.      * Merges arrays recursively, overwriting values of the first array with values of later arrays
  7050. +
  7051.      *
  7052. +
  7053.      * @since 1.0.8
  7054. +
  7055.      * @access private
  7056. +
  7057.      */
  7058. +
  7059.     function merge_arrays() {
  7060. +
  7061.         $arrays = func_get_args();
  7062. +
  7063.         $narrays = count($arrays);
  7064. +
  7065.  
  7066. +
  7067.         // check arguments
  7068. +
  7069.         // comment out if more performance is necessary (in this case the foreach loop will trigger a warning if the argument is not an array)
  7070. +
  7071.         for ($i = 0; $i < $narrays; $i ++) {
  7072. +
  7073.             if (!is_array($arrays[$i])) {
  7074. +
  7075.                 // also array_merge_recursive returns nothing in this case
  7076. +
  7077.                 trigger_error('Argument #' . ($i+1) . ' is not an array - trying to merge array with scalar! Returning false!', E_USER_WARNING);
  7078. +
  7079.                 return false;
  7080. +
  7081.             }
  7082. +
  7083.         }
  7084. +
  7085.  
  7086. +
  7087.         // the first array is in the output set in every case
  7088. +
  7089.         $ret = $arrays[0];
  7090. +
  7091.  
  7092. +
  7093.         // merege $ret with the remaining arrays
  7094. +
  7095.         for ($i = 1; $i < $narrays; $i ++) {
  7096. +
  7097.             foreach ($arrays[$i] as $key => $value) {
  7098. +
  7099.                 if (is_array($value) && isset($ret[$key])) {
  7100. +
  7101.                     // if $ret[$key] is not an array you try to merge an scalar value with an array - the result is not defined (incompatible arrays)
  7102. +
  7103.                     // in this case the call will trigger an E_USER_WARNING and the $ret[$key] will be false.
  7104. +
  7105.                     $ret[$key] = $this->merge_arrays($ret[$key], $value);
  7106. +
  7107.                 } else {
  7108. +
  7109.                     $ret[$key] = $value;
  7110. +
  7111.                 }
  7112. +
  7113.             }
  7114. +
  7115.         }
  7116. +
  7117.  
  7118. +
  7119.         return $ret;
  7120. +
  7121.     }
  7122. +
  7123.  
  7124. +
  7125.     /**
  7126. +
  7127.      * Gets language information and stores it for later use
  7128. +
  7129.      *
  7130. +
  7131.      * @param string The filename of the language file you want to load
  7132. +
  7133.      * @since 1.0.0
  7134. +
  7135.      * @access private
  7136. +
  7137.      * @todo Needs to load keys for lexic permissions for keywords, regexps etc
  7138. +
  7139.      */
  7140. +
  7141.     function load_language($file_name) {
  7142. +
  7143.         if ($file_name == $this->loaded_language) {
  7144. +
  7145.             // this file is already loaded!
  7146. +
  7147.             return;
  7148. +
  7149.         }
  7150. +
  7151.  
  7152. +
  7153.         //Prepare some stuff before actually loading the language file
  7154. +
  7155.         $this->loaded_language = $file_name;
  7156. +
  7157.         $this->parse_cache_built = false;
  7158. +
  7159.         $this->enable_highlighting();
  7160. +
  7161.         $language_data = array();
  7162. +
  7163.  
  7164. +
  7165.         //Load the language file
  7166. +
  7167.         require $file_name;
  7168. +
  7169.  
  7170. +
  7171.         // Perhaps some checking might be added here later to check that
  7172. +
  7173.         // $language data is a valid thing but maybe not
  7174. +
  7175.         $this->language_data = $language_data;
  7176. +
  7177.  
  7178. +
  7179.         // Set strict mode if should be set
  7180. +
  7181.         $this->strict_mode = $this->language_data['STRICT_MODE_APPLIES'];
  7182. +
  7183.  
  7184. +
  7185.         // Set permissions for all lexics to true
  7186. +
  7187.         // so they'll be highlighted by default
  7188. +
  7189.         foreach (array_keys($this->language_data['KEYWORDS']) as $key) {
  7190. +
  7191.             if (!empty($this->language_data['KEYWORDS'][$key])) {
  7192. +
  7193.                 $this->lexic_permissions['KEYWORDS'][$key] = true;
  7194. +
  7195.             } else {
  7196. +
  7197.                 $this->lexic_permissions['KEYWORDS'][$key] = false;
  7198. +
  7199.             }
  7200. +
  7201.         }
  7202. +
  7203.  
  7204. +
  7205.         foreach (array_keys($this->language_data['COMMENT_SINGLE']) as $key) {
  7206. +
  7207.             $this->lexic_permissions['COMMENTS'][$key] = true;
  7208. +
  7209.         }
  7210. +
  7211.         foreach (array_keys($this->language_data['REGEXPS']) as $key) {
  7212. +
  7213.             $this->lexic_permissions['REGEXPS'][$key] = true;
  7214. +
  7215.         }
  7216. +
  7217.  
  7218. +
  7219.         // for BenBE and future code reviews:
  7220. +
  7221.         // we can use empty here since we only check for existance and emptiness of an array
  7222. +
  7223.         // if it is not an array at all but rather false or null this will work as intended as well
  7224. +
  7225.         // even if $this->language_data['PARSER_CONTROL'] is undefined this won't trigger a notice
  7226. +
  7227.         if (!empty($this->language_data['PARSER_CONTROL']['ENABLE_FLAGS'])) {
  7228. +
  7229.             foreach ($this->language_data['PARSER_CONTROL']['ENABLE_FLAGS'] as $flag => $value) {
  7230. +
  7231.                 // it's either true or false and maybe is true as well
  7232. +
  7233.                 $perm = $value !== GESHI_NEVER;
  7234. +
  7235.                 if ($flag == 'ALL') {
  7236. +
  7237.                     $this->enable_highlighting($perm);
  7238. +
  7239.                     continue;
  7240. +
  7241.                 }
  7242. +
  7243.                 if (!isset($this->lexic_permissions[$flag])) {
  7244. +
  7245.                     // unknown lexic permission
  7246. +
  7247.                     continue;
  7248. +
  7249.                 }
  7250. +
  7251.                 if (is_array($this->lexic_permissions[$flag])) {
  7252. +
  7253.                     foreach ($this->lexic_permissions[$flag] as $key => $val) {
  7254. +
  7255.                         $this->lexic_permissions[$flag][$key] = $perm;
  7256. +
  7257.                     }
  7258. +
  7259.                 } else {
  7260. +
  7261.                     $this->lexic_permissions[$flag] = $perm;
  7262. +
  7263.                 }
  7264. +
  7265.             }
  7266. +
  7267.             unset($this->language_data['PARSER_CONTROL']['ENABLE_FLAGS']);
  7268. +
  7269.         }
  7270. +
  7271.  
  7272. +
  7273.         //NEW in 1.0.8: Allow styles to be loaded from a separate file to override defaults
  7274. +
  7275.         $style_filename = substr($file_name, 0, -4) . '.style.php';
  7276. +
  7277.         if (is_readable($style_filename)) {
  7278. +
  7279.             //Clear any style_data that could have been set before ...
  7280. +
  7281.             if (isset($style_data)) {
  7282. +
  7283.                 unset($style_data);
  7284. +
  7285.             }
  7286. +
  7287.  
  7288. +
  7289.             //Read the Style Information from the style file
  7290. +
  7291.             include $style_filename;
  7292. +
  7293.  
  7294. +
  7295.             //Apply the new styles to our current language styles
  7296. +
  7297.             if (isset($style_data) && is_array($style_data)) {
  7298. +
  7299.                 $this->language_data['STYLES'] =
  7300. +
  7301.                     $this->merge_arrays($this->language_data['STYLES'], $style_data);
  7302. +
  7303.             }
  7304. +
  7305.         }
  7306. +
  7307.     }
  7308. +
  7309.  
  7310. +
  7311.     /**
  7312. +
  7313.      * Takes the parsed code and various options, and creates the HTML
  7314. +
  7315.      * surrounding it to make it look nice.
  7316. +
  7317.      *
  7318. +
  7319.      * @param  string The code already parsed (reference!)
  7320. +
  7321.      * @since  1.0.0
  7322. +
  7323.      * @access private
  7324. +
  7325.      */
  7326. +
  7327.     function finalise(&$parsed_code) {
  7328. +
  7329.         // Remove end parts of important declarations
  7330. +
  7331.         // This is BUGGY!! My fault for bad code: fix coming in 1.2
  7332. +
  7333.         // @todo Remove this crap
  7334. +
  7335.         if ($this->enable_important_blocks &&
  7336. +
  7337.             (strpos($parsed_code, $this->hsc(<a href="../geshi/core/_geshi.php.html#defineGESHI_START_IMPORTANT">GESHI_START_IMPORTANT</a>)) === false)) {
  7338. +
  7339.             $parsed_code = str_replace($this->hsc(<a href="../geshi/core/_geshi.php.html#defineGESHI_END_IMPORTANT">GESHI_END_IMPORTANT</a>), '', $parsed_code);
  7340. +
  7341.         }
  7342. +
  7343.  
  7344. +
  7345.         // Add HTML whitespace stuff if we're using the <div> header
  7346. +
  7347.         if ($this->header_type != <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE">GESHI_HEADER_PRE</a> && $this->header_type != <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a>) {
  7348. +
  7349.             $this->indent($parsed_code);
  7350. +
  7351.         }
  7352. +
  7353.  
  7354. +
  7355.         // purge some unnecessary stuff
  7356. +
  7357.         /** NOTE: memorypeak #1 */
  7358. +
  7359.         $parsed_code = preg_replace('#<span[^>]+>(\s*)</span>#', '\\1', $parsed_code);
  7360. +
  7361.  
  7362. +
  7363.         // If we are using IDs for line numbers, there needs to be an overall
  7364. +
  7365.         // ID set to prevent collisions.
  7366. +
  7367.         if ($this->add_ids && !$this->overall_id) {
  7368. +
  7369.             $this->overall_id = 'geshi-' . substr(md5(microtime()), 0, 4);
  7370. +
  7371.         }
  7372. +
  7373.  
  7374. +
  7375.         // Get code into lines
  7376. +
  7377.         /** NOTE: memorypeak #2 */
  7378. +
  7379.         $code = explode("\n", $parsed_code);
  7380. +
  7381.         $parsed_code = $this->header();
  7382. +
  7383.  
  7384. +
  7385.         // If we're using line numbers, we insert <li>s and appropriate
  7386. +
  7387.         // markup to style them (otherwise we don't need to do anything)
  7388. +
  7389.         if ($this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a> && $this->header_type != <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_TABLE">GESHI_HEADER_PRE_TABLE</a>) {
  7390. +
  7391.             // If we're using the <pre> header, we shouldn't add newlines because
  7392. +
  7393.             // the <pre> will line-break them (and the <li>s already do this for us)
  7394. +
  7395.             $ls = ($this->header_type != <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE">GESHI_HEADER_PRE</a> && $this->header_type != <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a>) ? "\n" : '';
  7396. +
  7397.  
  7398. +
  7399.             // Set vars to defaults for following loop
  7400. +
  7401.             $i = 0;
  7402. +
  7403.  
  7404. +
  7405.             // Foreach line...
  7406. +
  7407.             for ($i = 0, $n = count($code); $i < $n;) {
  7408. +
  7409.                 //Reset the attributes for a new line ...
  7410. +
  7411.                 $attrs = array();
  7412. +
  7413.  
  7414. +
  7415.                 // Make lines have at least one space in them if they're empty
  7416. +
  7417.                 // BenBE: Checking emptiness using trim instead of relying on blanks
  7418. +
  7419.                 if ('' == trim($code[$i])) {
  7420. +
  7421.                     $code[$i] = '&nbsp;';
  7422. +
  7423.                 }
  7424. +
  7425.  
  7426. +
  7427.                 // If this is a "special line"...
  7428. +
  7429.                 if ($this->line_numbers == <a href="../geshi/core/_geshi.php.html#defineGESHI_FANCY_LINE_NUMBERS">GESHI_FANCY_LINE_NUMBERS</a> &&
  7430. +
  7431.                     $i % $this->line_nth_row == ($this->line_nth_row - 1)) {
  7432. +
  7433.                     // Set the attributes to style the line
  7434. +
  7435.                     if ($this->use_classes) {
  7436. +
  7437.                         //$attr = ' class="li2"';
  7438. +
  7439.                         $attrs['class'][] = 'li2';
  7440. +
  7441.                         $def_attr = ' class="de2"';
  7442. +
  7443.                     } else {
  7444. +
  7445.                         //$attr = ' style="' . $this->line_style2 . '"';
  7446. +
  7447.                         $attrs['style'][] = $this->line_style2;
  7448. +
  7449.                         // This style "covers up" the special styles set for special lines
  7450. +
  7451.                         // so that styles applied to special lines don't apply to the actual
  7452. +
  7453.                         // code on that line
  7454. +
  7455.                         $def_attr = ' style="' . $this->code_style . '"';
  7456. +
  7457.                     }
  7458. +
  7459.                 } else {
  7460. +
  7461.                     if ($this->use_classes) {
  7462. +
  7463.                         //$attr = ' class="li1"';
  7464. +
  7465.                         $attrs['class'][] = 'li1';
  7466. +
  7467.                         $def_attr = ' class="de1"';
  7468. +
  7469.                     } else {
  7470. +
  7471.                         //$attr = ' style="' . $this->line_style1 . '"';
  7472. +
  7473.                         $attrs['style'][] = $this->line_style1;
  7474. +
  7475.                         $def_attr = ' style="' . $this->code_style . '"';
  7476. +
  7477.                     }
  7478. +
  7479.                 }
  7480. +
  7481.  
  7482. +
  7483.                 //Check which type of tag to insert for this line
  7484. +
  7485.                 if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a>) {
  7486. +
  7487.                     $start = "<pre$def_attr>";
  7488. +
  7489.                     $end = '</pre>';
  7490. +
  7491.                 } else {
  7492. +
  7493.                     // Span or div?
  7494. +
  7495.                     $start = "<div$def_attr>";
  7496. +
  7497.                     $end = '</div>';
  7498. +
  7499.                 }
  7500. +
  7501.  
  7502. +
  7503.                 ++$i;
  7504. +
  7505.  
  7506. +
  7507.                 // Are we supposed to use ids? If so, add them
  7508. +
  7509.                 if ($this->add_ids) {
  7510. +
  7511.                     $attrs['id'][] = "$this->overall_id-$i";
  7512. +
  7513.                 }
  7514. +
  7515.  
  7516. +
  7517.                 //Is this some line with extra styles???
  7518. +
  7519.                 if (in_array($i, $this->highlight_extra_lines)) {
  7520. +
  7521.                     if ($this->use_classes) {
  7522. +
  7523.                         if (isset($this->highlight_extra_lines_styles[$i])) {
  7524. +
  7525.                             $attrs['class'][] = "lx$i";
  7526. +
  7527.                         } else {
  7528. +
  7529.                             $attrs['class'][] = "ln-xtra";
  7530. +
  7531.                         }
  7532. +
  7533.                     } else {
  7534. +
  7535.                         array_push($attrs['style'], $this->get_line_style($i));
  7536. +
  7537.                     }
  7538. +
  7539.                 }
  7540. +
  7541.  
  7542. +
  7543.                 // Add in the line surrounded by appropriate list HTML
  7544. +
  7545.                 $attr_string = '';
  7546. +
  7547.                 foreach ($attrs as $key => $attr) {
  7548. +
  7549.                     $attr_string .= ' ' . $key . '="' . implode(' ', $attr) . '"';
  7550. +
  7551.                 }
  7552. +
  7553.  
  7554. +
  7555.                 $parsed_code .= "<li$attr_string>$start{$code[$i-1]}$end</li>$ls";
  7556. +
  7557.                 unset($code[$i - 1]);
  7558. +
  7559.             }
  7560. +
  7561.         } else {
  7562. +
  7563.             $n = count($code);
  7564. +
  7565.             if ($this->use_classes) {
  7566. +
  7567.                 $attributes = ' class="de1"';
  7568. +
  7569.             } else {
  7570. +
  7571.                 $attributes = ' style="'$this->code_style .'"';
  7572. +
  7573.             }
  7574. +
  7575.             if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a>) {
  7576. +
  7577.                 $parsed_code .= '<pre'$attributes .'>';
  7578. +
  7579.             } elseif ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_TABLE">GESHI_HEADER_PRE_TABLE</a>) {
  7580. +
  7581.                 if ($this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  7582. +
  7583.                     if ($this->use_classes) {
  7584. +
  7585.                         $attrs = ' class="ln"';
  7586. +
  7587.                     } else {
  7588. +
  7589.                         $attrs = ' style="'$this->table_linenumber_style .'"';
  7590. +
  7591.                     }
  7592. +
  7593.                     $parsed_code .= '<td'.$attrs.'><pre'.$attributes.'>';
  7594. +
  7595.                     // get linenumbers
  7596. +
  7597.                     // we don't merge it with the for below, since it should be better for
  7598. +
  7599.                     // memory consumption this way
  7600. +
  7601.                     // @todo: but... actually it would still be somewhat nice to merge the two loops
  7602. +
  7603.                     //        the mem peaks are at different positions
  7604. +
  7605.                     for ($i = 0; $i < $n; ++$i) {
  7606. +
  7607.                         $close = 0;
  7608. +
  7609.                         // fancy lines
  7610. +
  7611.                         if ($this->line_numbers == <a href="../geshi/core/_geshi.php.html#defineGESHI_FANCY_LINE_NUMBERS">GESHI_FANCY_LINE_NUMBERS</a> &&
  7612. +
  7613.                             $i % $this->line_nth_row == ($this->line_nth_row - 1)) {
  7614. +
  7615.                             // Set the attributes to style the line
  7616. +
  7617.                             if ($this->use_classes) {
  7618. +
  7619.                                 $parsed_code .= '<span class="xtra li2"><span class="de2">';
  7620. +
  7621.                             } else {
  7622. +
  7623.                                 // This style "covers up" the special styles set for special lines
  7624. +
  7625.                                 // so that styles applied to special lines don't apply to the actual
  7626. +
  7627.                                 // code on that line
  7628. +
  7629.                                 $parsed_code .= '<span style="display:block;' . $this->line_style2 . '">'
  7630. +
  7631.                                                   .'<span style="' . $this->code_style .'">';
  7632. +
  7633.                             }
  7634. +
  7635.                             $close += 2;
  7636. +
  7637.                         }
  7638. +
  7639.                         //Is this some line with extra styles???
  7640. +
  7641.                         if (in_array($i + 1, $this->highlight_extra_lines)) {
  7642. +
  7643.                             if ($this->use_classes) {
  7644. +
  7645.                                 if (isset($this->highlight_extra_lines_styles[$i])) {
  7646. +
  7647.                                     $parsed_code .= "<span class=\"xtra lx$i\">";
  7648. +
  7649.                                 } else {
  7650. +
  7651.                                     $parsed_code .= "<span class=\"xtra ln-xtra\">";
  7652. +
  7653.                                 }
  7654. +
  7655.                             } else {
  7656. +
  7657.                                 $parsed_code .= "<span style=\"display:block;" . $this->get_line_style($i) . "\">";
  7658. +
  7659.                             }
  7660. +
  7661.                             ++$close;
  7662. +
  7663.                         }
  7664. +
  7665.                         $parsed_code .= $this->line_numbers_start + $i;
  7666. +
  7667.                         if ($close) {
  7668. +
  7669.                             $parsed_code .= str_repeat('</span>', $close);
  7670. +
  7671.                         } else if ($i != $n) {
  7672. +
  7673.                             $parsed_code .= "\n";
  7674. +
  7675.                         }
  7676. +
  7677.                     }
  7678. +
  7679.                     $parsed_code .= '</pre></td><td'.$attributes.'>';
  7680. +
  7681.                 }
  7682. +
  7683.                 $parsed_code .= '<pre'$attributes .'>';
  7684. +
  7685.             }
  7686. +
  7687.             // No line numbers, but still need to handle highlighting lines extra.
  7688. +
  7689.             // Have to use divs so the full width of the code is highlighted
  7690. +
  7691.             $close = 0;
  7692. +
  7693.             for ($i = 0; $i < $n; ++$i) {
  7694. +
  7695.                 // Make lines have at least one space in them if they're empty
  7696. +
  7697.                 // BenBE: Checking emptiness using trim instead of relying on blanks
  7698. +
  7699.                 if ('' == trim($code[$i])) {
  7700. +
  7701.                     $code[$i] = '&nbsp;';
  7702. +
  7703.                 }
  7704. +
  7705.                 // fancy lines
  7706. +
  7707.                 if ($this->line_numbers == <a href="../geshi/core/_geshi.php.html#defineGESHI_FANCY_LINE_NUMBERS">GESHI_FANCY_LINE_NUMBERS</a> &&
  7708. +
  7709.                     $i % $this->line_nth_row == ($this->line_nth_row - 1)) {
  7710. +
  7711.                     // Set the attributes to style the line
  7712. +
  7713.                     if ($this->use_classes) {
  7714. +
  7715.                         $parsed_code .= '<span class="xtra li2"><span class="de2">';
  7716. +
  7717.                     } else {
  7718. +
  7719.                         // This style "covers up" the special styles set for special lines
  7720. +
  7721.                         // so that styles applied to special lines don't apply to the actual
  7722. +
  7723.                         // code on that line
  7724. +
  7725.                         $parsed_code .= '<span style="display:block;' . $this->line_style2 . '">'
  7726. +
  7727.                                           .'<span style="' . $this->code_style .'">';
  7728. +
  7729.                     }
  7730. +
  7731.                     $close += 2;
  7732. +
  7733.                 }
  7734. +
  7735.                 //Is this some line with extra styles???
  7736. +
  7737.                 if (in_array($i + 1, $this->highlight_extra_lines)) {
  7738. +
  7739.                     if ($this->use_classes) {
  7740. +
  7741.                         if (isset($this->highlight_extra_lines_styles[$i])) {
  7742. +
  7743.                             $parsed_code .= "<span class=\"xtra lx$i\">";
  7744. +
  7745.                         } else {
  7746. +
  7747.                             $parsed_code .= "<span class=\"xtra ln-xtra\">";
  7748. +
  7749.                         }
  7750. +
  7751.                     } else {
  7752. +
  7753.                         $parsed_code .= "<span style=\"display:block;" . $this->get_line_style($i) . "\">";
  7754. +
  7755.                     }
  7756. +
  7757.                     ++$close;
  7758. +
  7759.                 }
  7760. +
  7761.  
  7762. +
  7763.                 $parsed_code .= $code[$i];
  7764. +
  7765.  
  7766. +
  7767.                 if ($close) {
  7768. +
  7769.                   $parsed_code .= str_repeat('</span>', $close);
  7770. +
  7771.                   $close = 0;
  7772. +
  7773.                 }
  7774. +
  7775.                 elseif ($i + 1 < $n) {
  7776. +
  7777.                     $parsed_code .= "\n";
  7778. +
  7779.                 }
  7780. +
  7781.                 unset($code[$i]);
  7782. +
  7783.             }
  7784. +
  7785.  
  7786. +
  7787.             if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a> || $this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_TABLE">GESHI_HEADER_PRE_TABLE</a>) {
  7788. +
  7789.                 $parsed_code .= '</pre>';
  7790. +
  7791.             }
  7792. +
  7793.             if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_TABLE">GESHI_HEADER_PRE_TABLE</a> && $this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  7794. +
  7795.                 $parsed_code .= '</td>';
  7796. +
  7797.             }
  7798. +
  7799.         }
  7800. +
  7801.  
  7802. +
  7803.         $parsed_code .= $this->footer();
  7804. +
  7805.     }
  7806. +
  7807.  
  7808. +
  7809.     /**
  7810. +
  7811.      * Creates the header for the code block (with correct attributes)
  7812. +
  7813.      *
  7814. +
  7815.      * @return string The header for the code block
  7816. +
  7817.      * @since  1.0.0
  7818. +
  7819.      * @access private
  7820. +
  7821.      */
  7822. +
  7823.     function header() {
  7824. +
  7825.         // Get attributes needed
  7826. +
  7827.         /**
  7828. +
  7829.          * @todo   Document behaviour change - class is outputted regardless of whether
  7830. +
  7831.          *         we're using classes or not. Same with style
  7832. +
  7833.          */
  7834. +
  7835.         $attributes = ' class="' . $this->language;
  7836. +
  7837.         if ($this->overall_class != '') {
  7838. +
  7839.             $attributes .= " ".$this->overall_class;
  7840. +
  7841.         }
  7842. +
  7843.         $attributes .= '"';
  7844. +
  7845.  
  7846. +
  7847.         if ($this->overall_id != '') {
  7848. +
  7849.             $attributes .= " id=\"{$this->overall_id}\"";
  7850. +
  7851.         }
  7852. +
  7853.         if ($this->overall_style != '') {
  7854. +
  7855.             $attributes .= ' style="' . $this->overall_style . '"';
  7856. +
  7857.         }
  7858. +
  7859.  
  7860. +
  7861.         $ol_attributes = '';
  7862. +
  7863.  
  7864. +
  7865.         if ($this->line_numbers_start != 1) {
  7866. +
  7867.             $ol_attributes .= ' start="' . $this->line_numbers_start . '"';
  7868. +
  7869.         }
  7870. +
  7871.  
  7872. +
  7873.         // Get the header HTML
  7874. +
  7875.         $header = $this->header_content;
  7876. +
  7877.         if ($header) {
  7878. +
  7879.             if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE">GESHI_HEADER_PRE</a> || $this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a>) {
  7880. +
  7881.                 $header = str_replace("\n", '', $header);
  7882. +
  7883.             }
  7884. +
  7885.             $header = $this->replace_keywords($header);
  7886. +
  7887.  
  7888. +
  7889.             if ($this->use_classes) {
  7890. +
  7891.                 $attr = ' class="head"';
  7892. +
  7893.             } else {
  7894. +
  7895.                 $attr = " style=\"{$this->header_content_style}\"";
  7896. +
  7897.             }
  7898. +
  7899.             if ($this->header_type == GESHI_HEADER_PRE_TABLE && $this->line_numbers != GESHI_NO_LINE_NUMBERS) {
  7900. +
  7901.                 $header = "<thead><tr><td colspan=\"2\" $attr>$header</td></tr></thead>";
  7902. +
  7903.             } else {
  7904. +
  7905.                 $header = "<div$attr>$header</div>";
  7906. +
  7907.             }
  7908. +
  7909.         }
  7910. +
  7911.  
  7912. +
  7913.         if (GESHI_HEADER_NONE == $this->header_type) {
  7914. +
  7915.             if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
  7916. +
  7917.                 return "$header<ol$attributes$ol_attributes>";
  7918. +
  7919.             }
  7920. +
  7921.             return $header . ($this->force_code_block ? '<div>' : '');
  7922. +
  7923.         }
  7924. +
  7925.  
  7926. +
  7927.         // Work out what to return and do it
  7928. +
  7929.         if ($this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  7930. +
  7931.             if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE">GESHI_HEADER_PRE</a>) {
  7932. +
  7933.                 return "<pre$attributes>$header<ol$ol_attributes>";
  7934. +
  7935.             } else if ($this->header_type == GESHI_HEADER_DIV ||
  7936. +
  7937.                 $this->header_type == GESHI_HEADER_PRE_VALID) {
  7938. +
  7939.                 return "<div$attributes>$header<ol$ol_attributes>";
  7940. +
  7941.             } else if ($this->header_type == GESHI_HEADER_PRE_TABLE) {
  7942. +
  7943.                 return "<table$attributes>$header<tbody><tr class=\"li1\">";
  7944. +
  7945.             }
  7946. +
  7947.         } else {
  7948. +
  7949.             if ($this->header_type == GESHI_HEADER_PRE) {
  7950. +
  7951.                 return "<pre$attributes>$header"  .
  7952. +
  7953.                     ($this->force_code_block ? '<div>' : '');
  7954. +
  7955.             } else {
  7956. +
  7957.                 return "<div$attributes>$header.
  7958. +
  7959.                     ($this->force_code_block ? '<div>' : '');
  7960. +
  7961.             }
  7962. +
  7963.         }
  7964. +
  7965.     }
  7966. +
  7967.  
  7968. +
  7969.     /**
  7970. +
  7971.      * Returns the footer for the code block.
  7972. +
  7973.      *
  7974. +
  7975.      * @return string The footer for the code block
  7976. +
  7977.      * @since  1.0.0
  7978. +
  7979.      * @access private
  7980. +
  7981.      */
  7982. +
  7983.     function footer() {
  7984. +
  7985.         $footer = $this->footer_content;
  7986. +
  7987.         if ($footer) {
  7988. +
  7989.             if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE">GESHI_HEADER_PRE</a>) {
  7990. +
  7991.                 $footer = str_replace("\n", '', $footer);;
  7992. +
  7993.             }
  7994. +
  7995.             $footer = $this->replace_keywords($footer);
  7996. +
  7997.  
  7998. +
  7999.             if ($this->use_classes) {
  8000. +
  8001.                 $attr = ' class="foot"';
  8002. +
  8003.             } else {
  8004. +
  8005.                 $attr = " style=\"{$this->footer_content_style}\"";
  8006. +
  8007.             }
  8008. +
  8009.             if ($this->header_type == GESHI_HEADER_PRE_TABLE && $this->linenumbers != GESHI_NO_LINE_NUMBERS) {
  8010. +
  8011.                 $footer = "<tfoot><tr><td colspan=\"2\">$footer</td></tr></tfoot>";
  8012. +
  8013.             } else {
  8014. +
  8015.                 $footer = "<div$attr>$footer</div>";
  8016. +
  8017.             }
  8018. +
  8019.         }
  8020. +
  8021.  
  8022. +
  8023.         if (GESHI_HEADER_NONE == $this->header_type) {
  8024. +
  8025.             return ($this->line_numbers != GESHI_NO_LINE_NUMBERS) ? '</ol>' . $footer : $footer;
  8026. +
  8027.         }
  8028. +
  8029.  
  8030. +
  8031.         if ($this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_DIV">GESHI_HEADER_DIV</a> || $this->header_type == <a href="../geshi/core/_geshi.php.html#defineGESHI_HEADER_PRE_VALID">GESHI_HEADER_PRE_VALID</a>) {
  8032. +
  8033.             if ($this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  8034. +
  8035.                 return "</ol>$footer</div>";
  8036. +
  8037.             }
  8038. +
  8039.             return ($this->force_code_block ? '</div>' : '') .
  8040. +
  8041.                 "$footer</div>";
  8042. +
  8043.         }
  8044. +
  8045.         elseif ($this->header_type == GESHI_HEADER_PRE_TABLE) {
  8046. +
  8047.             if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
  8048. +
  8049.                 return "</tr></tbody>$footer</table>";
  8050. +
  8051.             }
  8052. +
  8053.             return ($this->force_code_block ? '</div>' : '') .
  8054. +
  8055.                 "$footer</div>";
  8056. +
  8057.         }
  8058. +
  8059.         else {
  8060. +
  8061.             if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
  8062. +
  8063.                 return "</ol>$footer</pre>";
  8064. +
  8065.             }
  8066. +
  8067.             return ($this->force_code_block ? '</div>' : '') .
  8068. +
  8069.                 "$footer</pre>";
  8070. +
  8071.         }
  8072. +
  8073.     }
  8074. +
  8075.  
  8076. +
  8077.     /**
  8078. +
  8079.      * Replaces certain keywords in the header and footer with
  8080. +
  8081.      * certain configuration values
  8082. +
  8083.      *
  8084. +
  8085.      * @param  string The header or footer content to do replacement on
  8086. +
  8087.      * @return string The header or footer with replaced keywords
  8088. +
  8089.      * @since  1.0.2
  8090. +
  8091.      * @access private
  8092. +
  8093.      */
  8094. +
  8095.     function replace_keywords($instr) {
  8096. +
  8097.         $keywords = $replacements = array();
  8098. +
  8099.  
  8100. +
  8101.         $keywords[] = '<TIME>';
  8102. +
  8103.         $keywords[] = '{TIME}';
  8104. +
  8105.         $replacements[] = $replacements[] = number_format($time = $this->get_time(), 3);
  8106. +
  8107.  
  8108. +
  8109.         $keywords[] = '<LANGUAGE>';
  8110. +
  8111.         $keywords[] = '{LANGUAGE}';
  8112. +
  8113.         $replacements[] = $replacements[] = $this->language_data['LANG_NAME'];
  8114. +
  8115.  
  8116. +
  8117.         $keywords[] = '<VERSION>';
  8118. +
  8119.         $keywords[] = '{VERSION}';
  8120. +
  8121.         $replacements[] = $replacements[] = <a href="../geshi/core/_geshi.php.html#defineGESHI_VERSION">GESHI_VERSION</a>;
  8122. +
  8123.  
  8124. +
  8125.         $keywords[] = '<SPEED>';
  8126. +
  8127.         $keywords[] = '{SPEED}';
  8128. +
  8129.         if ($time <= 0) {
  8130. +
  8131.             $speed = 'N/A';
  8132. +
  8133.         } else {
  8134. +
  8135.             $speed = strlen($this->source) / $time;
  8136. +
  8137.             if ($speed >= 1024) {
  8138. +
  8139.                 $speed = sprintf("%.2f KB/s", $speed / 1024.0);
  8140. +
  8141.             } else {
  8142. +
  8143.                 $speed = sprintf("%.0f B/s", $speed);
  8144. +
  8145.             }
  8146. +
  8147.         }
  8148. +
  8149.         $replacements[] = $replacements[] = $speed;
  8150. +
  8151.  
  8152. +
  8153.         return str_replace($keywords, $replacements, $instr);
  8154. +
  8155.     }
  8156. +
  8157.  
  8158. +
  8159.     /**
  8160. +
  8161.      * Secure replacement for PHP built-in function htmlspecialchars().
  8162. +
  8163.      *
  8164. +
  8165.      * See ticket #427 (http://wush.net/trac/wikka/ticket/427) for the rationale
  8166. +
  8167.      * for this replacement function.
  8168. +
  8169.      *
  8170. +
  8171.      * The INTERFACE for this function is almost the same as that for
  8172. +
  8173.      * htmlspecialchars(), with the same default for quote style; however, there
  8174. +
  8175.      * is no 'charset' parameter. The reason for this is as follows:
  8176. +
  8177.      *
  8178. +
  8179.      * The PHP docs say:
  8180. +
  8181.      *      "The third argument charset defines character set used in conversion."
  8182. +
  8183.      *
  8184. +
  8185.      * I suspect PHP's htmlspecialchars() is working at the byte-value level and
  8186. +
  8187.      * thus _needs_ to know (or asssume) a character set because the special
  8188. +
  8189.      * characters to be replaced could exist at different code points in
  8190. +
  8191.      * different character sets. (If indeed htmlspecialchars() works at
  8192. +
  8193.      * byte-value level that goes some  way towards explaining why the
  8194. +
  8195.      * vulnerability would exist in this function, too, and not only in
  8196. +
  8197.      * htmlentities() which certainly is working at byte-value level.)
  8198. +
  8199.      *
  8200. +
  8201.      * This replacement function however works at character level and should
  8202. +
  8203.      * therefore be "immune" to character set differences - so no charset
  8204. +
  8205.      * parameter is needed or provided. If a third parameter is passed, it will
  8206. +
  8207.      * be silently ignored.
  8208. +
  8209.      *
  8210. +
  8211.      * In the OUTPUT there is a minor difference in that we use '&#39;' instead
  8212. +
  8213.      * of PHP's '&#039;' for a single quote: this provides compatibility with
  8214. +
  8215.      *      get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES)
  8216. +
  8217.      * (see comment by mikiwoz at yahoo dot co dot uk on
  8218. +
  8219.      * http://php.net/htmlspecialchars); it also matches the entity definition
  8220. +
  8221.      * for XML 1.0
  8222. +
  8223.      * (http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters).
  8224. +
  8225.      * Like PHP we use a numeric character reference instead of '&apos;' for the
  8226. +
  8227.      * single quote. For the other special characters we use the named entity
  8228. +
  8229.      * references, as PHP is doing.
  8230. +
  8231.      *
  8232. +
  8233.      * @author      {@link http://wikkawiki.org/JavaWoman Marjolein Katsma}
  8234. +
  8235.      *
  8236. +
  8237.      * @license     http://www.gnu.org/copyleft/lgpl.html
  8238. +
  8239.      *              GNU Lesser General Public License
  8240. +
  8241.      * @copyright   Copyright 2007, {@link http://wikkawiki.org/CreditsPage
  8242. +
  8243.      *              Wikka Development Team}
  8244. +
  8245.      *
  8246. +
  8247.      * @access      private
  8248. +
  8249.      * @param       string  $string string to be converted
  8250. +
  8251.      * @param       integer $quote_style
  8252. +
  8253.      *                      - ENT_COMPAT:   escapes &, <, > and double quote (default)
  8254. +
  8255.      *                      - ENT_NOQUOTES: escapes only &, < and >
  8256. +
  8257.      *                      - ENT_QUOTES:   escapes &, <, >, double and single quotes
  8258. +
  8259.      * @return      string  converted string
  8260. +
  8261.      * @since       1.0.7.18
  8262. +
  8263.      */
  8264. +
  8265.     function hsc($string, $quote_style = ENT_COMPAT) {
  8266. +
  8267.         // init
  8268. +
  8269.         static $aTransSpecchar = array(
  8270. +
  8271.             '&' => '&amp;',
  8272. +
  8273.             '"' => '&quot;',
  8274. +
  8275.             '<' => '&lt;',
  8276. +
  8277.             '>' => '&gt;',
  8278. +
  8279.  
  8280. +
  8281.             //This fix is related to SF#1923020, but has to be applied
  8282. +
  8283.             //regardless of actually highlighting symbols.
  8284. +
  8285. +
  8286.             //Circumvent a bug with symbol highlighting
  8287. +
  8288.             //This is required as ; would produce undesirable side-effects if it
  8289. +
  8290.             //was not to be processed as an entity.
  8291. +
  8292.             ';' => '<SEMI>', // Force ; to be processed as entity
  8293. +
  8294.             '|' => '<PIPE>' // Force | to be processed as entity
  8295. +
  8296.             );                      // ENT_COMPAT set
  8297. +
  8298. +
  8299.         switch ($quote_style) {
  8300. +
  8301.             case ENT_NOQUOTES// don't convert double quotes
  8302. +
  8303.                 unset($aTransSpecchar['"']);
  8304. +
  8305.                 break;
  8306. +
  8307.             case ENT_QUOTES// convert single quotes as well
  8308. +
  8309.                 $aTransSpecchar["'"] = '&#39;'; // (apos) htmlspecialchars() uses '&#039;'
  8310. +
  8311.                 break;
  8312. +
  8313.         }
  8314. +
  8315.  
  8316. +
  8317.         // return translated string
  8318. +
  8319.         return strtr($string, $aTransSpecchar);
  8320. +
  8321.     }
  8322. +
  8323.  
  8324. +
  8325.     /**
  8326. +
  8327.      * Returns a stylesheet for the highlighted code. If $economy mode
  8328. +
  8329.      * is true, we only return the stylesheet declarations that matter for
  8330. +
  8331.      * this code block instead of the whole thing
  8332. +
  8333.      *
  8334. +
  8335.      * @param  boolean Whether to use economy mode or not
  8336. +
  8337.      * @return string A stylesheet built on the data for the current language
  8338. +
  8339.      * @since  1.0.0
  8340. +
  8341.      */
  8342. +
  8343.     function get_stylesheet($economy_mode = true) {
  8344. +
  8345.         // If there's an error, chances are that the language file
  8346. +
  8347.         // won't have populated the language data file, so we can't
  8348. +
  8349.         // risk getting a stylesheet...
  8350. +
  8351.         if ($this->error) {
  8352. +
  8353.             return '';
  8354. +
  8355.         }
  8356. +
  8357.  
  8358. +
  8359.         //Check if the style rearrangements have been processed ...
  8360. +
  8361.         //This also does some preprocessing to check which style groups are useable ...
  8362. +
  8363.         if(!isset($this->language_data['NUMBERS_CACHE'])) {
  8364. +
  8365.             $this->build_style_cache();
  8366. +
  8367.         }
  8368. +
  8369.  
  8370. +
  8371.         // First, work out what the selector should be. If there's an ID,
  8372. +
  8373.         // that should be used, the same for a class. Otherwise, a selector
  8374. +
  8375.         // of '' means that these styles will be applied anywhere
  8376. +
  8377.         if ($this->overall_id) {
  8378. +
  8379.             $selector = '#' . $this->overall_id;
  8380. +
  8381.         } else {
  8382. +
  8383.             $selector = '.' . $this->language;
  8384. +
  8385.             if ($this->overall_class) {
  8386. +
  8387.                 $selector .= '.' . $this->overall_class;
  8388. +
  8389.             }
  8390. +
  8391.         }
  8392. +
  8393.         $selector .= ' ';
  8394. +
  8395.  
  8396. +
  8397.         // Header of the stylesheet
  8398. +
  8399.         if (!$economy_mode) {
  8400. +
  8401.             $stylesheet = "/**\n".
  8402. +
  8403.                 " * GeSHi Dynamically Generated Stylesheet\n".
  8404. +
  8405.                 " * --------------------------------------\n".
  8406. +
  8407.                 " * Dynamically generated stylesheet for {$this->language}\n".
  8408. +
  8409.                 " * CSS class: {$this->overall_class}, CSS id: {$this->overall_id}\n".
  8410. +
  8411.                 " * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann\n" .
  8412. +
  8413.                 " * (http://qbnz.com/highlighter/ and http://geshi.org/)\n".
  8414. +
  8415.                 " * --------------------------------------\n".
  8416. +
  8417.                 " */\n";
  8418. +
  8419.         } else {
  8420. +
  8421.             $stylesheet = "/**\n".
  8422. +
  8423.                 " * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann\n" .
  8424. +
  8425.                 " * (http://qbnz.com/highlighter/ and http://geshi.org/)\n".
  8426. +
  8427.                 " */\n";
  8428. +
  8429.         }
  8430. +
  8431.  
  8432. +
  8433.         // Set the <ol> to have no effect at all if there are line numbers
  8434. +
  8435.         // (<ol>s have margins that should be destroyed so all layout is
  8436. +
  8437.         // controlled by the set_overall_style method, which works on the
  8438. +
  8439.         // <pre> or <div> container). Additionally, set default styles for lines
  8440. +
  8441.         if (!$economy_mode || $this->line_numbers != <a href="../geshi/core/_geshi.php.html#defineGESHI_NO_LINE_NUMBERS">GESHI_NO_LINE_NUMBERS</a>) {
  8442. +
  8443.             //$stylesheet .= "$selector, {$selector}ol, {$selector}ol li {margin: 0;}\n";
  8444. +
  8445.             $stylesheet .= "$selector.de1, $selector.de2 {{$this->code_style}}\n";
  8446. +
  8447.         }
  8448. +
  8449.  
  8450. +
  8451.         // Add overall styles
  8452. +
  8453.         // note: neglect economy_mode, empty styles are meaningless
  8454. +
  8455.         if ($this->overall_style != '') {
  8456. +
  8457.             $stylesheet .= "$selector {{$this->overall_style}}\n";
  8458. +
  8459.         }
  8460. +
  8461.  
  8462. +
  8463.         // Add styles for links
  8464. +
  8465.         // note: economy mode does not make _any_ sense here
  8466. +
  8467.         //       either the style is empty and thus no selector is needed
  8468. +
  8469.         //       or the appropriate key is given.
  8470. +
  8471.         foreach ($this->link_styles as $key => $style) {
  8472. +
  8473.             if ($style != '') {
  8474. +
  8475.                 switch ($key) {
  8476. +
  8477.                     case <a href="../geshi/core/_geshi.php.html#defineGESHI_LINK">GESHI_LINK</a>:
  8478. +
  8479.                         $stylesheet .= "{$selector}a:link {{$style}}\n";
  8480. +
  8481.                         break;
  8482. +
  8483.                     case GESHI_HOVER:
  8484. +
  8485.                         $stylesheet .= "{$selector}a:hover {{$style}}\n";
  8486. +
  8487.                         break;
  8488. +
  8489.                     case GESHI_ACTIVE:
  8490. +
  8491.                         $stylesheet .= "{$selector}a:active {{$style}}\n";
  8492. +
  8493.                         break;
  8494. +
  8495.                     case GESHI_VISITED:
  8496. +
  8497.                         $stylesheet .= "{$selector}a:visited {{$style}}\n";
  8498. +
  8499.                         break;
  8500. +
  8501.                 }
  8502. +
  8503.             }
  8504. +
  8505.         }
  8506. +
  8507.  
  8508. +
  8509.         // Header and footer
  8510. +
  8511.         // note: neglect economy_mode, empty styles are meaningless
  8512. +
  8513.         if ($this->header_content_style != ''{
  8514. +
  8515.             $stylesheet .= "$selector.head {{$this->header_content_style}}\n";
  8516. +
  8517.         }
  8518. +
  8519.         if ($this->footer_content_style != ''{
  8520. +
  8521.             $stylesheet .= "$selector.foot {{$this->footer_content_style}}\n";
  8522. +
  8523.         }
  8524. +
  8525.  
  8526. +
  8527.         // Styles for important stuff
  8528. +
  8529.         // note: neglect economy_mode, empty styles are meaningless
  8530. +
  8531.         if ($this->important_styles != ''{
  8532. +
  8533.             $stylesheet .= "$selector.imp {{$this->important_styles}}\n";
  8534. +
  8535.         }
  8536. +
  8537.  
  8538. +
  8539.         // Simple line number styles
  8540. +
  8541.         if ((!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS&& $this->line_style1 != ''{
  8542. +
  8543.             $stylesheet .= "{$selector}li, {$selector}.li1 {{$this->line_style1}}\n";
  8544. +
  8545.         }
  8546. +
  8547.         if ((!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS&& $this->table_linenumber_style != ''{
  8548. +
  8549.             $stylesheet .= "{$selector}.ln {{$this->table_linenumber_style}}\n";
  8550. +
  8551.         }
  8552. +
  8553.         // If there is a style set for fancy line numbers, echo it out
  8554. +
  8555.         if ((!$economy_mode || $this->line_numbers == GESHI_FANCY_LINE_NUMBERS&& $this->line_style2 != ''{
  8556. +
  8557.             $stylesheet .= "{$selector}.li2 {{$this->line_style2}}\n";
  8558. +
  8559.         }
  8560. +
  8561.  
  8562. +
  8563.         // note: empty styles are meaningless
  8564. +
  8565.         foreach ($this->language_data['STYLES']['KEYWORDS'as $group => $styles{
  8566. +
  8567.             if ($styles != '' && (!$economy_mode ||
  8568. +
  8569.                 (isset($this->lexic_permissions['KEYWORDS'][$group]&&
  8570. +
  8571.                 $this->lexic_permissions['KEYWORDS'][$group]))) {
  8572. +
  8573.                 $stylesheet .= "$selector.kw$group {{$styles}}\n";
  8574. +
  8575.             }
  8576. +
  8577.         }
  8578. +
  8579.         foreach ($this->language_data['STYLES']['COMMENTS'as $group => $styles{
  8580. +
  8581.             if ($styles != '' && (!$economy_mode ||
  8582. +
  8583.                 (isset($this->lexic_permissions['COMMENTS'][$group]&&
  8584. +
  8585.                 $this->lexic_permissions['COMMENTS'][$group]||
  8586. +
  8587.                 (!empty($this->language_data['COMMENT_REGEXP']&&
  8588. +
  8589.                 !empty($this->language_data['COMMENT_REGEXP'][$group])))) {
  8590. +
  8591.                 $stylesheet .= "$selector.co$group {{$styles}}\n";
  8592. +
  8593.             }
  8594. +
  8595.         }
  8596. +
  8597.         foreach ($this->language_data['STYLES']['ESCAPE_CHAR'as $group => $styles{
  8598. +
  8599.             if ($styles != '' && (!$economy_mode || $this->lexic_permissions['ESCAPE_CHAR'])) {
  8600. +
  8601.                 // NEW: since 1.0.8 we have to handle hardescapes
  8602. +
  8603.                 if ($group === 'HARD'{
  8604. +
  8605.                     $group '_h';
  8606. +
  8607.                 }
  8608. +
  8609.                 $stylesheet .= "$selector.es$group {{$styles}}\n";
  8610. +
  8611.             }
  8612. +
  8613.         }
  8614. +
  8615.         foreach ($this->language_data['STYLES']['BRACKETS'as $group => $styles{
  8616. +
  8617.             if ($styles != '' && (!$economy_mode || $this->lexic_permissions['BRACKETS'])) {
  8618. +
  8619.                 $stylesheet .= "$selector.br$group {{$styles}}\n";
  8620. +
  8621.             }
  8622. +
  8623.         }
  8624. +
  8625.         foreach ($this->language_data['STYLES']['SYMBOLS'as $group => $styles{
  8626. +
  8627.             if ($styles != '' && (!$economy_mode || $this->lexic_permissions['SYMBOLS'])) {
  8628. +
  8629.                 $stylesheet .= "$selector.sy$group {{$styles}}\n";
  8630. +
  8631.             }
  8632. +
  8633.         }
  8634. +
  8635.         foreach ($this->language_data['STYLES']['STRINGS'as $group => $styles{
  8636. +
  8637.             if ($styles != '' && (!$economy_mode || $this->lexic_permissions['STRINGS'])) {
  8638. +
  8639.                 // NEW: since 1.0.8 we have to handle hardquotes
  8640. +
  8641.                 if ($group === 'HARD'{
  8642. +
  8643.                     $group '_h';
  8644. +
  8645.                 }
  8646. +
  8647.                 $stylesheet .= "$selector.st$group {{$styles}}\n";
  8648. +
  8649.             }
  8650. +
  8651.         }
  8652. +
  8653.         foreach ($this->language_data['STYLES']['NUMBERS'as $group => $styles{
  8654. +
  8655.             if ($styles != '' && (!$economy_mode || $this->lexic_permissions['NUMBERS'])) {
  8656. +
  8657.                 $stylesheet .= "$selector.nu$group {{$styles}}\n";
  8658. +
  8659.             }
  8660. +
  8661.         }
  8662. +
  8663.         foreach ($this->language_data['STYLES']['METHODS'as $group => $styles{
  8664. +
  8665.             if ($styles != '' && (!$economy_mode || $this->lexic_permissions['METHODS'])) {
  8666. +
  8667.                 $stylesheet .= "$selector.me$group {{$styles}}\n";
  8668. +
  8669.             }
  8670. +
  8671.         }
  8672. +
  8673.         // note: neglect economy_mode, empty styles are meaningless
  8674. +
  8675.         foreach ($this->language_data['STYLES']['SCRIPT'as $group => $styles{
  8676. +
  8677.             if ($styles != ''{
  8678. +
  8679.                 $stylesheet .= "$selector.sc$group {{$styles}}\n";
  8680. +
  8681.             }
  8682. +
  8683.         }
  8684. +
  8685.         foreach ($this->language_data['STYLES']['REGEXPS'as $group => $styles{
  8686. +
  8687.             if ($styles != '' && (!$economy_mode ||
  8688. +
  8689.                 (isset($this->lexic_permissions['REGEXPS'][$group]&&
  8690. +
  8691.                 $this->lexic_permissions['REGEXPS'][$group]))) {
  8692. +
  8693.                 if (is_array($this->language_data['REGEXPS'][$group]&&
  8694. +
  8695.                     array_key_exists(GESHI_CLASS$this->language_data['REGEXPS'][$group])) {
  8696. +
  8697.                     $stylesheet .= "$selector.";
  8698. +
  8699.                     $stylesheet .= $this->language_data['REGEXPS'][$group][GESHI_CLASS];
  8700. +
  8701.                     $stylesheet .= " {{$styles}}\n";
  8702. +
  8703.                 else {
  8704. +
  8705.                     $stylesheet .= "$selector.re$group {{$styles}}\n";
  8706. +
  8707.                 }
  8708. +
  8709.             }
  8710. +
  8711.         }
  8712. +
  8713.         // Styles for lines being highlighted extra
  8714. +
  8715.         if (!$economy_mode || (count($this->highlight_extra_lines)!=count($this->highlight_extra_lines_styles))) {
  8716. +
  8717.             $stylesheet .= "{$selector}.ln-xtra, {$selector}li.ln-xtra, {$selector}div.ln-xtra {{$this->highlight_extra_lines_style}}\n";
  8718. +
  8719.         }
  8720. +
  8721.         $stylesheet .= "{$selector}span.xtra { display:block; }\n";
  8722. +
  8723.         foreach ($this->highlight_extra_lines_styles as $lineid => $linestyle{
  8724. +
  8725.             $stylesheet .= "{$selector}.lx$lineid, {$selector}li.lx$lineid, {$selector}div.lx$lineid {{$linestyle}}\n";
  8726. +
  8727.         }
  8728. +
  8729.  
  8730. +
  8731.         return $stylesheet;
  8732. +
  8733.     }
  8734. +
  8735.  
  8736. +
  8737.     /**
  8738. +
  8739.      * Get's the style that is used for the specified line
  8740. +
  8741.      *
  8742. +
  8743.      * @param int The line number information is requested for
  8744. +
  8745.      * @access private
  8746. +
  8747.      * @since 1.0.7.21
  8748. +
  8749.      */
  8750. +
  8751.     function get_line_style($line{
  8752. +
  8753.         //$style = null;
  8754. +
  8755.         $style null;
  8756. +
  8757.         if (isset($this->highlight_extra_lines_styles[$line])) {
  8758. +
  8759.             $style $this->highlight_extra_lines_styles[$line];
  8760. +
  8761.         else // if no "extra" style assigned
  8762. +
  8763.             $style $this->highlight_extra_lines_style;
  8764. +
  8765.         }
  8766. +
  8767.  
  8768. +
  8769.         return $style;
  8770. +
  8771.     }
  8772. +
  8773.  
  8774. +
  8775.     /**
  8776. +
  8777.     * this functions creates an optimized regular expression list
  8778. +
  8779.     * of an array of strings.
  8780. +
  8781.     *
  8782. +
  8783.     * Example:
  8784. +
  8785.     * <code>$list = array('faa', 'foo', 'foobar');
  8786. +
  8787.     *          => string 'f(aa|oo(bar)?)'</code>
  8788. +
  8789.     *
  8790. +
  8791.     * @param $list array of (unquoted) strings
  8792. +
  8793.     * @param $regexp_delimiter your regular expression delimiter, @see preg_quote()
  8794. +
  8795.     * @return string for regular expression
  8796. +
  8797.     * @author Milian Wolff <mail@milianw.de>
  8798. +
  8799.     * @since 1.0.8
  8800. +
  8801.     * @access private
  8802. +
  8803.     */
  8804. +
  8805.     function optimize_regexp_list($list$regexp_delimiter '/'{
  8806. +
  8807.         $regex_chars array('.''\\''+''*''?''[''^'']''$',
  8808. +
  8809.             '('')''{''}''=''!''<''>''|'':'$regexp_delimiter);
  8810. +
  8811.         sort($list);
  8812. +
  8813.         $regexp_list array('');
  8814. +
  8815.         $num_subpatterns 0;
  8816. +
  8817.         $list_key 0;
  8818. +
  8819.  
  8820. +
  8821.         // the tokens which we will use to generate the regexp list
  8822. +
  8823.         $tokens array();
  8824. +
  8825.         $prev_keys array();
  8826. +
  8827.         // go through all entries of the list and generate the token list
  8828. +
  8829.         $cur_len 0;
  8830. +
  8831.         for ($i 0$i_max count($list)$i $i_max++$i{
  8832. +
  8833.             if ($cur_len GESHI_MAX_PCRE_LENGTH{
  8834. +
  8835.                 // seems like the length of this pcre is growing exorbitantly
  8836. +
  8837.                 $regexp_list[++$list_key$this->_optimize_regexp_list_tokens_to_string($tokens);
  8838. +
  8839.                 $num_subpatterns substr_count($regexp_list[$list_key]'(?:');
  8840. +
  8841.                 $tokens array();
  8842. +
  8843.                 $cur_len 0;
  8844. +
  8845.             }
  8846. +
  8847.             $level 0;
  8848. +
  8849.             $entry preg_quote((string) $list[$i]$regexp_delimiter);
  8850. +
  8851.             $pointer &$tokens;
  8852. +
  8853.             // properly assign the new entry to the correct position in the token array
  8854. +
  8855.             // possibly generate smaller common denominator keys
  8856. +
  8857.             while (true{
  8858. +
  8859.                 // get the common denominator
  8860. +
  8861.                 if (isset($prev_keys[$level])) {
  8862. +
  8863.                     if ($prev_keys[$level== $entry{
  8864. +
  8865.                         // this is a duplicate entry, skip it
  8866. +
  8867.                         continue 2;
  8868. +
  8869.                     }
  8870. +
  8871.                     $char 0;
  8872. +
  8873.                     while (isset($entry[$char]&& isset($prev_keys[$level][$char])
  8874. +
  8875.                             && $entry[$char== $prev_keys[$level][$char]{
  8876. +
  8877.                         ++$char;
  8878. +
  8879.                     }
  8880. +
  8881.                     if ($char 0{
  8882. +
  8883.                         // this entry has at least some chars in common with the current key
  8884. +
  8885.                         if ($char == strlen($prev_keys[$level])) {
  8886. +
  8887.                             // current key is totally matched, i.e. this entry has just some bits appended
  8888. +
  8889.                             $pointer &$pointer[$prev_keys[$level]];
  8890. +
  8891.                         else {
  8892. +
  8893.                             // only part of the keys match
  8894. +
  8895.                             $new_key_part1 substr($prev_keys[$level]0$char);
  8896. +
  8897.                             $new_key_part2 substr($prev_keys[$level]$char);
  8898. +
  8899.  
  8900. +
  8901.                             if (in_array($new_key_part1[0]$regex_chars)
  8902. +
  8903.                                 || in_array($new_key_part2[0]$regex_chars)) {
  8904. +
  8905.                                 // this is bad, a regex char as first character
  8906. +
  8907.                                 $pointer[$entryarray('' => true);
  8908. +
  8909.                                 array_splice($prev_keys$levelcount($prev_keys)$entry);
  8910. +
  8911.                                 $cur_len += strlen($entry);
  8912. +
  8913.                                 continue;
  8914. +
  8915.                             else {
  8916. +
  8917.                                 // relocate previous tokens
  8918. +
  8919.                                 $pointer[$new_key_part1array($new_key_part2 => $pointer[$prev_keys[$level]]);
  8920. +
  8921.                                 unset($pointer[$prev_keys[$level]]);
  8922. +
  8923.                                 $pointer &$pointer[$new_key_part1];
  8924. +
  8925.                                 // recreate key index
  8926. +
  8927.                                 array_splice($prev_keys$levelcount($prev_keys)array($new_key_part1$new_key_part2));
  8928. +
  8929.                                 $cur_len += strlen($new_key_part2);
  8930. +
  8931.                             }
  8932. +
  8933.                         }
  8934. +
  8935.                         ++$level;
  8936. +
  8937.                         $entry substr($entry$char);
  8938. +
  8939.                         continue;
  8940. +
  8941.                     }
  8942. +
  8943.                     // else: fall trough, i.e. no common denominator was found
  8944. +
  8945.                 }
  8946. +
  8947.                 if ($level == && !empty($tokens)) {
  8948. +
  8949.                     // we can dump current tokens into the string and throw them away afterwards
  8950. +
  8951.                     $new_entry $this->_optimize_regexp_list_tokens_to_string($tokens);
  8952. +
  8953.                     $new_subpatterns substr_count($new_entry'(?:');
  8954. +
  8955.                     if (GESHI_MAX_PCRE_SUBPATTERNS && $num_subpatterns $new_subpatterns GESHI_MAX_PCRE_SUBPATTERNS{
  8956. +
  8957.                         $regexp_list[++$list_key$new_entry;
  8958. +
  8959.                         $num_subpatterns $new_subpatterns;
  8960. +
  8961.                     else {
  8962. +
  8963.                         if (!empty($regexp_list[$list_key])) {
  8964. +
  8965.                             $new_entry '|' $new_entry;
  8966. +
  8967.                         }
  8968. +
  8969.                         $regexp_list[$list_key.= $new_entry;
  8970. +
  8971.                         $num_subpatterns += $new_subpatterns;
  8972. +
  8973.                     }
  8974. +
  8975.                     $tokens array();
  8976. +
  8977.                     $cur_len 0;
  8978. +
  8979.                 }
  8980. +
  8981.                 // no further common denominator found
  8982. +
  8983.                 $pointer[$entryarray('' => true);
  8984. +
  8985.                 array_splice($prev_keys$levelcount($prev_keys)$entry);
  8986. +
  8987.  
  8988. +
  8989.                 $cur_len += strlen($entry);
  8990. +
  8991.                 break;
  8992. +
  8993.             }
  8994. +
  8995.             unset($list[$i]);
  8996. +
  8997.         }
  8998. +
  8999.         // make sure the last tokens get converted as well
  9000. +
  9001.         $new_entry $this->_optimize_regexp_list_tokens_to_string($tokens);
  9002. +
  9003.         if (GESHI_MAX_PCRE_SUBPATTERNS && $num_subpatterns substr_count($new_entry'(?:'GESHI_MAX_PCRE_SUBPATTERNS{
  9004. +
  9005.             $regexp_list[++$list_key$new_entry;
  9006. +
  9007.         else {
  9008. +
  9009.             if (!empty($regexp_list[$list_key])) {
  9010. +
  9011.                 $new_entry '|' $new_entry;
  9012. +
  9013.             }
  9014. +
  9015.             $regexp_list[$list_key.= $new_entry;
  9016. +
  9017.         }
  9018. +
  9019.         return $regexp_list;
  9020. +
  9021.     }
  9022. +
  9023.     /**
  9024. +
  9025.     * this function creates the appropriate regexp string of an token array
  9026. +
  9027.     * you should not call this function directly, @see $this->optimize_regexp_list().
  9028. +
  9029.     *
  9030. +
  9031.     * @param &$tokens array of tokens
  9032. +
  9033.     * @param $recursed bool to know wether we recursed or not
  9034. +
  9035.     * @return string
  9036. +
  9037.     * @author Milian Wolff <mail@milianw.de>
  9038. +
  9039.     * @since 1.0.8
  9040. +
  9041.     * @access private
  9042. +
  9043.     */
  9044. +
  9045.     function _optimize_regexp_list_tokens_to_string(&$tokens$recursed false{
  9046. +
  9047.         $list '';
  9048. +
  9049.         foreach ($tokens as $token => $sub_tokens{
  9050. +
  9051.             $list .= $token;
  9052. +
  9053.             $close_entry = isset($sub_tokens['']);
  9054. +
  9055.             unset($sub_tokens['']);
  9056. +
  9057.             if (!empty($sub_tokens)) {
  9058. +
  9059.                 $list .= '(?:' $this->_optimize_regexp_list_tokens_to_string($sub_tokenstrue')';
  9060. +
  9061.                 if ($close_entry{
  9062. +
  9063.                     // make sub_tokens optional
  9064. +
  9065.                     $list .= '?';
  9066. +
  9067.                 }
  9068. +
  9069.             }
  9070. +
  9071.             $list .= '|';
  9072. +
  9073.         }
  9074. +
  9075.         if (!$recursed{
  9076. +
  9077.             // do some optimizations
  9078. +
  9079.             // common trailing strings
  9080. +
  9081.             // BUGGY!
  9082. +
  9083.             //$list = preg_replace_callback('#(?<=^|\:|\|)\w+?(\w+)(?:\|.+\1)+(?=\|)#', create_function(
  9084. +
  9085.             //    '$matches', 'return "(?:" . preg_replace("#" . preg_quote($matches[1], "#") . "(?=\||$)#", "", $matches[0]) . ")" . $matches[1];'), $list);
  9086. +
  9087.             // (?:p)? => p?
  9088. +
  9089.             $list preg_replace('#\(\?\:(.)\)\?#''\1?'$list);
  9090. +
  9091.             // (?:a|b|c|d|...)? => [abcd...]?
  9092. +
  9093.             // TODO: a|bb|c => [ac]|bb
  9094. +
  9095.             static $callback_2;
  9096. +
  9097.             if (!isset($callback_2)) {
  9098. +
  9099.                 $callback_2 create_function('$matches''return "[" . str_replace("|", "", $matches[1]) . "]";');
  9100. +
  9101.             }
  9102. +
  9103.             $list preg_replace_callback('#\(\?\:((?:.\|)+.)\)#'$callback_2$list);
  9104. +
  9105.         }
  9106. +
  9107.         // return $list without trailing pipe
  9108. +
  9109.         return substr($list0-1);
  9110. +
  9111.     }
  9112. +
  9113. // End Class GeSHi
  9114. +
  9115.  
  9116. +
  9117.  
  9118. +
  9119. if (!function_exists('geshi_highlight')) {
  9120. +
  9121.     /**
  9122. +
  9123.      * Easy way to highlight stuff. Behaves just like highlight_string
  9124. +
  9125.      *
  9126. +
  9127.      * @param string The code to highlight
  9128. +
  9129.      * @param string The language to highlight the code in
  9130. +
  9131.      * @param string The path to the language files. You can leave this blank if you need
  9132. +
  9133.      *               as from version 1.0.7 the path should be automatically detected
  9134. +
  9135.      * @param boolean Whether to return the result or to echo
  9136. +
  9137.      * @return string The code highlighted (if $return is true)
  9138. +
  9139.      * @since 1.0.2
  9140. +
  9141.      */
  9142. +
  9143.     function geshi_highlight($string$language$path null$return false{
  9144. +
  9145.         $geshi new GeSHi($string$language$path);
  9146. +
  9147.         $geshi->set_header_type(GESHI_HEADER_NONE);
  9148. +
  9149.  
  9150. +
  9151.         if ($return{
  9152. +
  9153.             return '<code>' $geshi->parse_code('</code>';
  9154. +
  9155.         }
  9156. +
  9157.  
  9158. +
  9159.         echo '<code>' $geshi->parse_code('</code>';
  9160. +
  9161.  
  9162. +
  9163.         if ($geshi->error()) {
  9164. +
  9165.             return false;
  9166. +
  9167.         }
  9168. +
  9169.         return true;
  9170. +
  9171.     }
  9172. +
  9173. }
  9174. +
  9175.  
  9176. +
  9177. ?>
  9178. +
+
+

+ Documentation generated on Thu, 25 Dec 2008 14:34:52 +0100 by phpDocumentor 1.4.2 +

+ + \ No newline at end of file -- cgit v1.2.2