|
1 <?php |
|
2 /** |
|
3 * GeSHi - Generic Syntax Highlighter |
|
4 * |
|
5 * The GeSHi class for Generic Syntax Highlighting. Please refer to the |
|
6 * documentation at http://qbnz.com/highlighter/documentation.php for more |
|
7 * information about how to use this class. |
|
8 * |
|
9 * For changes, release notes, TODOs etc, see the relevant files in the docs/ |
|
10 * directory. |
|
11 * |
|
12 * This file is part of GeSHi. |
|
13 * |
|
14 * GeSHi is free software; you can redistribute it and/or modify |
|
15 * it under the terms of the GNU General Public License as published by |
|
16 * the Free Software Foundation; either version 2 of the License, or |
|
17 * (at your option) any later version. |
|
18 * |
|
19 * GeSHi is distributed in the hope that it will be useful, |
|
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
22 * GNU General Public License for more details. |
|
23 * |
|
24 * You should have received a copy of the GNU General Public License |
|
25 * along with GeSHi; if not, write to the Free Software |
|
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
27 * |
|
28 * @package geshi |
|
29 * @subpackage core |
|
30 * @author Nigel McNie <nigel@geshi.org> |
|
31 * @copyright (C) 2004 - 2007 Nigel McNie |
|
32 * @license http://gnu.org/copyleft/gpl.html GNU GPL |
|
33 * |
|
34 */ |
|
35 |
|
36 // |
|
37 // GeSHi Constants |
|
38 // You should use these constant names in your programs instead of |
|
39 // their values - you never know when a value may change in a future |
|
40 // version |
|
41 // |
|
42 |
|
43 /** The version of this GeSHi file */ |
|
44 define('GESHI_VERSION', '1.0.7.20'); |
|
45 |
|
46 // Define the root directory for the GeSHi code tree |
|
47 if (!defined('GESHI_ROOT')) { |
|
48 /** The root directory for GeSHi */ |
|
49 define('GESHI_ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR); |
|
50 } |
|
51 /** The language file directory for GeSHi |
|
52 @access private */ |
|
53 define('GESHI_LANG_ROOT', GESHI_ROOT . 'geshi' . DIRECTORY_SEPARATOR); |
|
54 |
|
55 |
|
56 // Line numbers - use with enable_line_numbers() |
|
57 /** Use no line numbers when building the result */ |
|
58 define('GESHI_NO_LINE_NUMBERS', 0); |
|
59 /** Use normal line numbers when building the result */ |
|
60 define('GESHI_NORMAL_LINE_NUMBERS', 1); |
|
61 /** Use fancy line numbers when building the result */ |
|
62 define('GESHI_FANCY_LINE_NUMBERS', 2); |
|
63 |
|
64 // Container HTML type |
|
65 /** Use nothing to surround the source */ |
|
66 define('GESHI_HEADER_NONE', 0); |
|
67 /** Use a "div" to surround the source */ |
|
68 define('GESHI_HEADER_DIV', 1); |
|
69 /** Use a "pre" to surround the source */ |
|
70 define('GESHI_HEADER_PRE', 2); |
|
71 |
|
72 // Capatalisation constants |
|
73 /** Lowercase keywords found */ |
|
74 define('GESHI_CAPS_NO_CHANGE', 0); |
|
75 /** Uppercase keywords found */ |
|
76 define('GESHI_CAPS_UPPER', 1); |
|
77 /** Leave keywords found as the case that they are */ |
|
78 define('GESHI_CAPS_LOWER', 2); |
|
79 |
|
80 // Link style constants |
|
81 /** Links in the source in the :link state */ |
|
82 define('GESHI_LINK', 0); |
|
83 /** Links in the source in the :hover state */ |
|
84 define('GESHI_HOVER', 1); |
|
85 /** Links in the source in the :active state */ |
|
86 define('GESHI_ACTIVE', 2); |
|
87 /** Links in the source in the :visited state */ |
|
88 define('GESHI_VISITED', 3); |
|
89 |
|
90 // Important string starter/finisher |
|
91 // Note that if you change these, they should be as-is: i.e., don't |
|
92 // write them as if they had been run through htmlentities() |
|
93 /** The starter for important parts of the source */ |
|
94 define('GESHI_START_IMPORTANT', '<BEGIN GeSHi>'); |
|
95 /** The ender for important parts of the source */ |
|
96 define('GESHI_END_IMPORTANT', '<END GeSHi>'); |
|
97 |
|
98 /**#@+ |
|
99 * @access private |
|
100 */ |
|
101 // When strict mode applies for a language |
|
102 /** Strict mode never applies (this is the most common) */ |
|
103 define('GESHI_NEVER', 0); |
|
104 /** Strict mode *might* apply, and can be enabled or |
|
105 disabled by {@link GeSHi::enable_strict_mode()} */ |
|
106 define('GESHI_MAYBE', 1); |
|
107 /** Strict mode always applies */ |
|
108 define('GESHI_ALWAYS', 2); |
|
109 |
|
110 // Advanced regexp handling constants, used in language files |
|
111 /** The key of the regex array defining what to search for */ |
|
112 define('GESHI_SEARCH', 0); |
|
113 /** The key of the regex array defining what bracket group in a |
|
114 matched search to use as a replacement */ |
|
115 define('GESHI_REPLACE', 1); |
|
116 /** The key of the regex array defining any modifiers to the regular expression */ |
|
117 define('GESHI_MODIFIERS', 2); |
|
118 /** The key of the regex array defining what bracket group in a |
|
119 matched search to put before the replacement */ |
|
120 define('GESHI_BEFORE', 3); |
|
121 /** The key of the regex array defining what bracket group in a |
|
122 matched search to put after the replacement */ |
|
123 define('GESHI_AFTER', 4); |
|
124 /** The key of the regex array defining a custom keyword to use |
|
125 for this regexp's html tag class */ |
|
126 define('GESHI_CLASS', 5); |
|
127 |
|
128 /** Used in language files to mark comments */ |
|
129 define('GESHI_COMMENTS', 0); |
|
130 |
|
131 // Error detection - use these to analyse faults |
|
132 /** No sourcecode to highlight was specified |
|
133 * @deprecated |
|
134 */ |
|
135 define('GESHI_ERROR_NO_INPUT', 1); |
|
136 /** The language specified does not exist */ |
|
137 define('GESHI_ERROR_NO_SUCH_LANG', 2); |
|
138 /** GeSHi could not open a file for reading (generally a language file) */ |
|
139 define('GESHI_ERROR_FILE_NOT_READABLE', 3); |
|
140 /** The header type passed to {@link GeSHi::set_header_type()} was invalid */ |
|
141 define('GESHI_ERROR_INVALID_HEADER_TYPE', 4); |
|
142 /** The line number type passed to {@link GeSHi::enable_line_numbers()} was invalid */ |
|
143 define('GESHI_ERROR_INVALID_LINE_NUMBER_TYPE', 5); |
|
144 /**#@-*/ |
|
145 |
|
146 |
|
147 /** |
|
148 * The GeSHi Class. |
|
149 * |
|
150 * Please refer to the documentation for GeSHi 1.0.X that is available |
|
151 * at http://qbnz.com/highlighter/documentation.php for more information |
|
152 * about how to use this class. |
|
153 * |
|
154 * @package geshi |
|
155 * @author Nigel McNie <nigel@geshi.org> |
|
156 * @copyright (C) 2004 - 2007 Nigel McNie |
|
157 */ |
|
158 class GeSHi { |
|
159 /**#@+ |
|
160 * @access private |
|
161 */ |
|
162 /** |
|
163 * The source code to highlight |
|
164 * @var string |
|
165 */ |
|
166 var $source = ''; |
|
167 |
|
168 /** |
|
169 * The language to use when highlighting |
|
170 * @var string |
|
171 */ |
|
172 var $language = ''; |
|
173 |
|
174 /** |
|
175 * The data for the language used |
|
176 * @var array |
|
177 */ |
|
178 var $language_data = array(); |
|
179 |
|
180 /** |
|
181 * The path to the language files |
|
182 * @var string |
|
183 */ |
|
184 var $language_path = GESHI_LANG_ROOT; |
|
185 |
|
186 /** |
|
187 * The error message associated with an error |
|
188 * @var string |
|
189 * @todo check err reporting works |
|
190 */ |
|
191 var $error = false; |
|
192 |
|
193 /** |
|
194 * Possible error messages |
|
195 * @var array |
|
196 */ |
|
197 var $error_messages = array( |
|
198 GESHI_ERROR_NO_SUCH_LANG => 'GeSHi could not find the language {LANGUAGE} (using path {PATH})', |
|
199 GESHI_ERROR_FILE_NOT_READABLE => 'The file specified for load_from_file was not readable', |
|
200 GESHI_ERROR_INVALID_HEADER_TYPE => 'The header type specified is invalid', |
|
201 GESHI_ERROR_INVALID_LINE_NUMBER_TYPE => 'The line number type specified is invalid' |
|
202 ); |
|
203 |
|
204 /** |
|
205 * Whether highlighting is strict or not |
|
206 * @var boolean |
|
207 */ |
|
208 var $strict_mode = false; |
|
209 |
|
210 /** |
|
211 * Whether to use CSS classes in output |
|
212 * @var boolean |
|
213 */ |
|
214 var $use_classes = false; |
|
215 |
|
216 /** |
|
217 * The type of header to use. Can be one of the following |
|
218 * values: |
|
219 * |
|
220 * - GESHI_HEADER_PRE: Source is outputted in a "pre" HTML element. |
|
221 * - GESHI_HEADER_DIV: Source is outputted in a "div" HTML element. |
|
222 * - GESHI_HEADER_NONE: No header is outputted. |
|
223 * |
|
224 * @var int |
|
225 */ |
|
226 var $header_type = GESHI_HEADER_PRE; |
|
227 |
|
228 /** |
|
229 * Array of permissions for which lexics should be highlighted |
|
230 * @var array |
|
231 */ |
|
232 var $lexic_permissions = array( |
|
233 'KEYWORDS' => array(), |
|
234 'COMMENTS' => array('MULTI' => true), |
|
235 'REGEXPS' => array(), |
|
236 'ESCAPE_CHAR' => true, |
|
237 'BRACKETS' => true, |
|
238 'SYMBOLS' => true, |
|
239 'STRINGS' => true, |
|
240 'NUMBERS' => true, |
|
241 'METHODS' => true, |
|
242 'SCRIPT' => true |
|
243 ); |
|
244 |
|
245 /** |
|
246 * The time it took to parse the code |
|
247 * @var double |
|
248 */ |
|
249 var $time = 0; |
|
250 |
|
251 /** |
|
252 * The content of the header block |
|
253 * @var string |
|
254 */ |
|
255 var $header_content = ''; |
|
256 |
|
257 /** |
|
258 * The content of the footer block |
|
259 * @var string |
|
260 */ |
|
261 var $footer_content = ''; |
|
262 |
|
263 /** |
|
264 * The style of the header block |
|
265 * @var string |
|
266 */ |
|
267 var $header_content_style = ''; |
|
268 |
|
269 /** |
|
270 * The style of the footer block |
|
271 * @var string |
|
272 */ |
|
273 var $footer_content_style = ''; |
|
274 |
|
275 /** |
|
276 * Tells if a block around the highlighted source should be forced |
|
277 * if not using line numbering |
|
278 * @var boolean |
|
279 */ |
|
280 var $force_code_block = false; |
|
281 |
|
282 /** |
|
283 * The styles for hyperlinks in the code |
|
284 * @var array |
|
285 */ |
|
286 var $link_styles = array(); |
|
287 |
|
288 /** |
|
289 * Whether important blocks should be recognised or not |
|
290 * @var boolean |
|
291 * @deprecated |
|
292 * @todo REMOVE THIS FUNCTIONALITY! |
|
293 */ |
|
294 var $enable_important_blocks = false; |
|
295 |
|
296 /** |
|
297 * Styles for important parts of the code |
|
298 * @var string |
|
299 * @deprecated |
|
300 * @todo As above - rethink the whole idea of important blocks as it is buggy and |
|
301 * will be hard to implement in 1.2 |
|
302 */ |
|
303 var $important_styles = 'font-weight: bold; color: red;'; // Styles for important parts of the code |
|
304 |
|
305 /** |
|
306 * Whether CSS IDs should be added to the code |
|
307 * @var boolean |
|
308 */ |
|
309 var $add_ids = false; |
|
310 |
|
311 /** |
|
312 * Lines that should be highlighted extra |
|
313 * @var array |
|
314 */ |
|
315 var $highlight_extra_lines = array(); |
|
316 |
|
317 /** |
|
318 * Styles of extra-highlighted lines |
|
319 * @var string |
|
320 */ |
|
321 var $highlight_extra_lines_style = 'color: #cc0; background-color: #ffc;'; |
|
322 |
|
323 /** |
|
324 * The line ending |
|
325 * If null, nl2br() will be used on the result string. |
|
326 * Otherwise, all instances of \n will be replaced with $line_ending |
|
327 * @var string |
|
328 */ |
|
329 var $line_ending = null; |
|
330 |
|
331 /** |
|
332 * Number at which line numbers should start at |
|
333 * @var int |
|
334 */ |
|
335 var $line_numbers_start = 1; |
|
336 |
|
337 /** |
|
338 * The overall style for this code block |
|
339 * @var string |
|
340 */ |
|
341 var $overall_style = ''; |
|
342 |
|
343 /** |
|
344 * The style for the actual code |
|
345 * @var string |
|
346 */ |
|
347 var $code_style = 'font-family: \'Courier New\', Courier, monospace; font-weight: normal;'; |
|
348 |
|
349 /** |
|
350 * The overall class for this code block |
|
351 * @var string |
|
352 */ |
|
353 var $overall_class = ''; |
|
354 |
|
355 /** |
|
356 * The overall ID for this code block |
|
357 * @var string |
|
358 */ |
|
359 var $overall_id = ''; |
|
360 |
|
361 /** |
|
362 * Line number styles |
|
363 * @var string |
|
364 */ |
|
365 var $line_style1 = 'font-family: \'Courier New\', Courier, monospace; color: black; font-weight: normal; font-style: normal;'; |
|
366 |
|
367 /** |
|
368 * Line number styles for fancy lines |
|
369 * @var string |
|
370 */ |
|
371 var $line_style2 = 'font-weight: bold;'; |
|
372 |
|
373 /** |
|
374 * Flag for how line nubmers are displayed |
|
375 * @var boolean |
|
376 */ |
|
377 var $line_numbers = GESHI_NO_LINE_NUMBERS; |
|
378 |
|
379 /** |
|
380 * The "nth" value for fancy line highlighting |
|
381 * @var int |
|
382 */ |
|
383 var $line_nth_row = 0; |
|
384 |
|
385 /** |
|
386 * The size of tab stops |
|
387 * @var int |
|
388 */ |
|
389 var $tab_width = 8; |
|
390 |
|
391 /** |
|
392 * Should we use language-defined tab stop widths? |
|
393 * @var int |
|
394 */ |
|
395 var $use_language_tab_width = false; |
|
396 |
|
397 /** |
|
398 * Default target for keyword links |
|
399 * @var string |
|
400 */ |
|
401 var $link_target = ''; |
|
402 |
|
403 /** |
|
404 * The encoding to use for entity encoding |
|
405 * NOTE: no longer used |
|
406 * @var string |
|
407 */ |
|
408 var $encoding = 'ISO-8859-1'; |
|
409 |
|
410 /** |
|
411 * Should keywords be linked? |
|
412 * @var boolean |
|
413 */ |
|
414 var $keyword_links = true; |
|
415 |
|
416 /**#@-*/ |
|
417 |
|
418 /** |
|
419 * Creates a new GeSHi object, with source and language |
|
420 * |
|
421 * @param string The source code to highlight |
|
422 * @param string The language to highlight the source with |
|
423 * @param string The path to the language file directory. <b>This |
|
424 * is deprecated!</b> I've backported the auto path |
|
425 * detection from the 1.1.X dev branch, so now it |
|
426 * should be automatically set correctly. If you have |
|
427 * renamed the language directory however, you will |
|
428 * still need to set the path using this parameter or |
|
429 * {@link GeSHi::set_language_path()} |
|
430 * @since 1.0.0 |
|
431 */ |
|
432 function GeSHi($source, $language, $path = '') { |
|
433 $this->set_source($source); |
|
434 $this->set_language_path($path); |
|
435 $this->set_language($language); |
|
436 } |
|
437 |
|
438 /** |
|
439 * Returns an error message associated with the last GeSHi operation, |
|
440 * or false if no error has occured |
|
441 * |
|
442 * @return string|false An error message if there has been an error, else false |
|
443 * @since 1.0.0 |
|
444 */ |
|
445 function error() { |
|
446 if ($this->error) { |
|
447 $msg = $this->error_messages[$this->error]; |
|
448 $debug_tpl_vars = array( |
|
449 '{LANGUAGE}' => $this->language, |
|
450 '{PATH}' => $this->language_path |
|
451 ); |
|
452 foreach ($debug_tpl_vars as $tpl => $var) { |
|
453 $msg = str_replace($tpl, $var, $msg); |
|
454 } |
|
455 return "<br /><strong>GeSHi Error:</strong> $msg (code $this->error)<br />"; |
|
456 } |
|
457 return false; |
|
458 } |
|
459 |
|
460 /** |
|
461 * Gets a human-readable language name (thanks to Simon Patterson |
|
462 * for the idea :)) |
|
463 * |
|
464 * @return string The name for the current language |
|
465 * @since 1.0.2 |
|
466 */ |
|
467 function get_language_name() { |
|
468 if (GESHI_ERROR_NO_SUCH_LANG == $this->error) { |
|
469 return $this->language_data['LANG_NAME'] . ' (Unknown Language)'; |
|
470 } |
|
471 return $this->language_data['LANG_NAME']; |
|
472 } |
|
473 |
|
474 /** |
|
475 * Sets the source code for this object |
|
476 * |
|
477 * @param string The source code to highlight |
|
478 * @since 1.0.0 |
|
479 */ |
|
480 function set_source($source) { |
|
481 $this->source = $source; |
|
482 $this->highlight_extra_lines = array(); |
|
483 } |
|
484 |
|
485 /** |
|
486 * Sets the language for this object |
|
487 * |
|
488 * @param string The name of the language to use |
|
489 * @since 1.0.0 |
|
490 */ |
|
491 function set_language($language) { |
|
492 $this->error = false; |
|
493 $this->strict_mode = GESHI_NEVER; |
|
494 |
|
495 $language = preg_replace('#[^a-zA-Z0-9\-_]#', '', $language); |
|
496 $this->language = strtolower($language); |
|
497 |
|
498 $file_name = $this->language_path . $this->language . '.php'; |
|
499 if (!is_readable($file_name)) { |
|
500 $this->error = GESHI_ERROR_NO_SUCH_LANG; |
|
501 return; |
|
502 } |
|
503 // Load the language for parsing |
|
504 $this->load_language($file_name); |
|
505 } |
|
506 |
|
507 /** |
|
508 * Sets the path to the directory containing the language files. Note |
|
509 * that this path is relative to the directory of the script that included |
|
510 * geshi.php, NOT geshi.php itself. |
|
511 * |
|
512 * @param string The path to the language directory |
|
513 * @since 1.0.0 |
|
514 * @deprecated The path to the language files should now be automatically |
|
515 * detected, so this method should no longer be needed. The |
|
516 * 1.1.X branch handles manual setting of the path differently |
|
517 * so this method will disappear in 1.2.0. |
|
518 */ |
|
519 function set_language_path($path) { |
|
520 if ($path) { |
|
521 $this->language_path = ('/' == substr($path, strlen($path) - 1, 1)) ? $path : $path . '/'; |
|
522 $this->set_language($this->language); // otherwise set_language_path has no effect |
|
523 } |
|
524 } |
|
525 |
|
526 /** |
|
527 * Sets the type of header to be used. |
|
528 * |
|
529 * If GESHI_HEADER_DIV is used, the code is surrounded in a "div".This |
|
530 * means more source code but more control over tab width and line-wrapping. |
|
531 * GESHI_HEADER_PRE means that a "pre" is used - less source, but less |
|
532 * control. Default is GESHI_HEADER_PRE. |
|
533 * |
|
534 * From 1.0.7.2, you can use GESHI_HEADER_NONE to specify that no header code |
|
535 * should be outputted. |
|
536 * |
|
537 * @param int The type of header to be used |
|
538 * @since 1.0.0 |
|
539 */ |
|
540 function set_header_type($type) { |
|
541 if (GESHI_HEADER_DIV != $type && GESHI_HEADER_PRE != $type && GESHI_HEADER_NONE != $type) { |
|
542 $this->error = GESHI_ERROR_INVALID_HEADER_TYPE; |
|
543 return; |
|
544 } |
|
545 $this->header_type = $type; |
|
546 // Set a default overall style if the header is a <div> |
|
547 if (GESHI_HEADER_DIV == $type && !$this->overall_style) { |
|
548 $this->overall_style = 'font-family: monospace;'; |
|
549 } |
|
550 } |
|
551 |
|
552 /** |
|
553 * Sets the styles for the code that will be outputted |
|
554 * when this object is parsed. The style should be a |
|
555 * string of valid stylesheet declarations |
|
556 * |
|
557 * @param string The overall style for the outputted code block |
|
558 * @param boolean Whether to merge the styles with the current styles or not |
|
559 * @since 1.0.0 |
|
560 */ |
|
561 function set_overall_style($style, $preserve_defaults = false) { |
|
562 if (!$preserve_defaults) { |
|
563 $this->overall_style = $style; |
|
564 } |
|
565 else { |
|
566 $this->overall_style .= $style; |
|
567 } |
|
568 } |
|
569 |
|
570 /** |
|
571 * Sets the overall classname for this block of code. This |
|
572 * class can then be used in a stylesheet to style this object's |
|
573 * output |
|
574 * |
|
575 * @param string The class name to use for this block of code |
|
576 * @since 1.0.0 |
|
577 */ |
|
578 function set_overall_class($class) { |
|
579 $this->overall_class = $class; |
|
580 } |
|
581 |
|
582 /** |
|
583 * Sets the overall id for this block of code. This id can then |
|
584 * be used in a stylesheet to style this object's output |
|
585 * |
|
586 * @param string The ID to use for this block of code |
|
587 * @since 1.0.0 |
|
588 */ |
|
589 function set_overall_id($id) { |
|
590 $this->overall_id = $id; |
|
591 } |
|
592 |
|
593 /** |
|
594 * Sets whether CSS classes should be used to highlight the source. Default |
|
595 * is off, calling this method with no arguments will turn it on |
|
596 * |
|
597 * @param boolean Whether to turn classes on or not |
|
598 * @since 1.0.0 |
|
599 */ |
|
600 function enable_classes($flag = true) { |
|
601 $this->use_classes = ($flag) ? true : false; |
|
602 } |
|
603 |
|
604 /** |
|
605 * Sets the style for the actual code. This should be a string |
|
606 * containing valid stylesheet declarations. If $preserve_defaults is |
|
607 * true, then styles are merged with the default styles, with the |
|
608 * user defined styles having priority |
|
609 * |
|
610 * Note: Use this method to override any style changes you made to |
|
611 * the line numbers if you are using line numbers, else the line of |
|
612 * code will have the same style as the line number! Consult the |
|
613 * GeSHi documentation for more information about this. |
|
614 * |
|
615 * @param string The style to use for actual code |
|
616 * @param boolean Whether to merge the current styles with the new styles |
|
617 */ |
|
618 function set_code_style($style, $preserve_defaults = false) { |
|
619 if (!$preserve_defaults) { |
|
620 $this->code_style = $style; |
|
621 } |
|
622 else { |
|
623 $this->code_style .= $style; |
|
624 } |
|
625 } |
|
626 |
|
627 /** |
|
628 * Sets the styles for the line numbers. |
|
629 * |
|
630 * @param string The style for the line numbers that are "normal" |
|
631 * @param string|boolean If a string, this is the style of the line |
|
632 * numbers that are "fancy", otherwise if boolean then this |
|
633 * defines whether the normal styles should be merged with the |
|
634 * new normal styles or not |
|
635 * @param boolean If set, is the flag for whether to merge the "fancy" |
|
636 * styles with the current styles or not |
|
637 * @since 1.0.2 |
|
638 */ |
|
639 function set_line_style($style1, $style2 = '', $preserve_defaults = false) { |
|
640 if (is_bool($style2)) { |
|
641 $preserve_defaults = $style2; |
|
642 $style2 = ''; |
|
643 } |
|
644 if (!$preserve_defaults) { |
|
645 $this->line_style1 = $style1; |
|
646 $this->line_style2 = $style2; |
|
647 } |
|
648 else { |
|
649 $this->line_style1 .= $style1; |
|
650 $this->line_style2 .= $style2; |
|
651 } |
|
652 } |
|
653 |
|
654 /** |
|
655 * Sets whether line numbers should be displayed. |
|
656 * |
|
657 * Valid values for the first parameter are: |
|
658 * |
|
659 * - GESHI_NO_LINE_NUMBERS: Line numbers will not be displayed |
|
660 * - GESHI_NORMAL_LINE_NUMBERS: Line numbers will be displayed |
|
661 * - GESHI_FANCY_LINE_NUMBERS: Fancy line numbers will be displayed |
|
662 * |
|
663 * For fancy line numbers, the second parameter is used to signal which lines |
|
664 * are to be fancy. For example, if the value of this parameter is 5 then every |
|
665 * 5th line will be fancy. |
|
666 * |
|
667 * @param int How line numbers should be displayed |
|
668 * @param int Defines which lines are fancy |
|
669 * @since 1.0.0 |
|
670 */ |
|
671 function enable_line_numbers($flag, $nth_row = 5) { |
|
672 if (GESHI_NO_LINE_NUMBERS != $flag && GESHI_NORMAL_LINE_NUMBERS != $flag |
|
673 && GESHI_FANCY_LINE_NUMBERS != $flag) { |
|
674 $this->error = GESHI_ERROR_INVALID_LINE_NUMBER_TYPE; |
|
675 } |
|
676 $this->line_numbers = $flag; |
|
677 $this->line_nth_row = $nth_row; |
|
678 } |
|
679 |
|
680 /** |
|
681 * Sets the style for a keyword group. If $preserve_defaults is |
|
682 * true, then styles are merged with the default styles, with the |
|
683 * user defined styles having priority |
|
684 * |
|
685 * @param int The key of the keyword group to change the styles of |
|
686 * @param string The style to make the keywords |
|
687 * @param boolean Whether to merge the new styles with the old or just |
|
688 * to overwrite them |
|
689 * @since 1.0.0 |
|
690 */ |
|
691 function set_keyword_group_style($key, $style, $preserve_defaults = false) { |
|
692 if (!$preserve_defaults) { |
|
693 $this->language_data['STYLES']['KEYWORDS'][$key] = $style; |
|
694 } |
|
695 else { |
|
696 $this->language_data['STYLES']['KEYWORDS'][$key] .= $style; |
|
697 } |
|
698 } |
|
699 |
|
700 /** |
|
701 * Turns highlighting on/off for a keyword group |
|
702 * |
|
703 * @param int The key of the keyword group to turn on or off |
|
704 * @param boolean Whether to turn highlighting for that group on or off |
|
705 * @since 1.0.0 |
|
706 */ |
|
707 function set_keyword_group_highlighting($key, $flag = true) { |
|
708 $this->lexic_permissions['KEYWORDS'][$key] = ($flag) ? true : false; |
|
709 } |
|
710 |
|
711 /** |
|
712 * Sets the styles for comment groups. If $preserve_defaults is |
|
713 * true, then styles are merged with the default styles, with the |
|
714 * user defined styles having priority |
|
715 * |
|
716 * @param int The key of the comment group to change the styles of |
|
717 * @param string The style to make the comments |
|
718 * @param boolean Whether to merge the new styles with the old or just |
|
719 * to overwrite them |
|
720 * @since 1.0.0 |
|
721 */ |
|
722 function set_comments_style($key, $style, $preserve_defaults = false) { |
|
723 if (!$preserve_defaults) { |
|
724 $this->language_data['STYLES']['COMMENTS'][$key] = $style; |
|
725 } |
|
726 else { |
|
727 $this->language_data['STYLES']['COMMENTS'][$key] .= $style; |
|
728 } |
|
729 } |
|
730 |
|
731 /** |
|
732 * Turns highlighting on/off for comment groups |
|
733 * |
|
734 * @param int The key of the comment group to turn on or off |
|
735 * @param boolean Whether to turn highlighting for that group on or off |
|
736 * @since 1.0.0 |
|
737 */ |
|
738 function set_comments_highlighting($key, $flag = true) { |
|
739 $this->lexic_permissions['COMMENTS'][$key] = ($flag) ? true : false; |
|
740 } |
|
741 |
|
742 /** |
|
743 * Sets the styles for escaped characters. If $preserve_defaults is |
|
744 * true, then styles are merged with the default styles, with the |
|
745 * user defined styles having priority |
|
746 * |
|
747 * @param string The style to make the escape characters |
|
748 * @param boolean Whether to merge the new styles with the old or just |
|
749 * to overwrite them |
|
750 * @since 1.0.0 |
|
751 */ |
|
752 function set_escape_characters_style($style, $preserve_defaults = false) { |
|
753 if (!$preserve_defaults) { |
|
754 $this->language_data['STYLES']['ESCAPE_CHAR'][0] = $style; |
|
755 } |
|
756 else { |
|
757 $this->language_data['STYLES']['ESCAPE_CHAR'][0] .= $style; |
|
758 } |
|
759 } |
|
760 |
|
761 /** |
|
762 * Turns highlighting on/off for escaped characters |
|
763 * |
|
764 * @param boolean Whether to turn highlighting for escape characters on or off |
|
765 * @since 1.0.0 |
|
766 */ |
|
767 function set_escape_characters_highlighting($flag = true) { |
|
768 $this->lexic_permissions['ESCAPE_CHAR'] = ($flag) ? true : false; |
|
769 } |
|
770 |
|
771 /** |
|
772 * Sets the styles for brackets. If $preserve_defaults is |
|
773 * true, then styles are merged with the default styles, with the |
|
774 * user defined styles having priority |
|
775 * |
|
776 * This method is DEPRECATED: use set_symbols_style instead. |
|
777 * This method will be removed in 1.2.X |
|
778 * |
|
779 * @param string The style to make the brackets |
|
780 * @param boolean Whether to merge the new styles with the old or just |
|
781 * to overwrite them |
|
782 * @since 1.0.0 |
|
783 * @deprecated In favour of set_symbols_style |
|
784 */ |
|
785 function set_brackets_style($style, $preserve_defaults = false) { |
|
786 if (!$preserve_defaults) { |
|
787 $this->language_data['STYLES']['BRACKETS'][0] = $style; |
|
788 } |
|
789 else { |
|
790 $this->language_data['STYLES']['BRACKETS'][0] .= $style; |
|
791 } |
|
792 } |
|
793 |
|
794 /** |
|
795 * Turns highlighting on/off for brackets |
|
796 * |
|
797 * This method is DEPRECATED: use set_symbols_highlighting instead. |
|
798 * This method will be remove in 1.2.X |
|
799 * |
|
800 * @param boolean Whether to turn highlighting for brackets on or off |
|
801 * @since 1.0.0 |
|
802 * @deprecated In favour of set_symbols_highlighting |
|
803 */ |
|
804 function set_brackets_highlighting($flag) { |
|
805 $this->lexic_permissions['BRACKETS'] = ($flag) ? true : false; |
|
806 } |
|
807 |
|
808 /** |
|
809 * Sets the styles for symbols. If $preserve_defaults is |
|
810 * true, then styles are merged with the default styles, with the |
|
811 * user defined styles having priority |
|
812 * |
|
813 * @param string The style to make the symbols |
|
814 * @param boolean Whether to merge the new styles with the old or just |
|
815 * to overwrite them |
|
816 * @since 1.0.1 |
|
817 */ |
|
818 function set_symbols_style($style, $preserve_defaults = false) { |
|
819 if (!$preserve_defaults) { |
|
820 $this->language_data['STYLES']['SYMBOLS'][0] = $style; |
|
821 } |
|
822 else { |
|
823 $this->language_data['STYLES']['SYMBOLS'][0] .= $style; |
|
824 } |
|
825 // For backward compatibility |
|
826 $this->set_brackets_style ($style, $preserve_defaults); |
|
827 } |
|
828 |
|
829 /** |
|
830 * Turns highlighting on/off for symbols |
|
831 * |
|
832 * @param boolean Whether to turn highlighting for symbols on or off |
|
833 * @since 1.0.0 |
|
834 */ |
|
835 function set_symbols_highlighting($flag) { |
|
836 $this->lexic_permissions['SYMBOLS'] = ($flag) ? true : false; |
|
837 // For backward compatibility |
|
838 $this->set_brackets_highlighting ($flag); |
|
839 } |
|
840 |
|
841 /** |
|
842 * Sets the styles for strings. If $preserve_defaults is |
|
843 * true, then styles are merged with the default styles, with the |
|
844 * user defined styles having priority |
|
845 * |
|
846 * @param string The style to make the escape characters |
|
847 * @param boolean Whether to merge the new styles with the old or just |
|
848 * to overwrite them |
|
849 * @since 1.0.0 |
|
850 */ |
|
851 function set_strings_style($style, $preserve_defaults = false) { |
|
852 if (!$preserve_defaults) { |
|
853 $this->language_data['STYLES']['STRINGS'][0] = $style; |
|
854 } |
|
855 else { |
|
856 $this->language_data['STYLES']['STRINGS'][0] .= $style; |
|
857 } |
|
858 } |
|
859 |
|
860 /** |
|
861 * Turns highlighting on/off for strings |
|
862 * |
|
863 * @param boolean Whether to turn highlighting for strings on or off |
|
864 * @since 1.0.0 |
|
865 */ |
|
866 function set_strings_highlighting($flag) { |
|
867 $this->lexic_permissions['STRINGS'] = ($flag) ? true : false; |
|
868 } |
|
869 |
|
870 /** |
|
871 * Sets the styles for numbers. If $preserve_defaults is |
|
872 * true, then styles are merged with the default styles, with the |
|
873 * user defined styles having priority |
|
874 * |
|
875 * @param string The style to make the numbers |
|
876 * @param boolean Whether to merge the new styles with the old or just |
|
877 * to overwrite them |
|
878 * @since 1.0.0 |
|
879 */ |
|
880 function set_numbers_style($style, $preserve_defaults = false) { |
|
881 if (!$preserve_defaults) { |
|
882 $this->language_data['STYLES']['NUMBERS'][0] = $style; |
|
883 } |
|
884 else { |
|
885 $this->language_data['STYLES']['NUMBERS'][0] .= $style; |
|
886 } |
|
887 } |
|
888 |
|
889 /** |
|
890 * Turns highlighting on/off for numbers |
|
891 * |
|
892 * @param boolean Whether to turn highlighting for numbers on or off |
|
893 * @since 1.0.0 |
|
894 */ |
|
895 function set_numbers_highlighting($flag) { |
|
896 $this->lexic_permissions['NUMBERS'] = ($flag) ? true : false; |
|
897 } |
|
898 |
|
899 /** |
|
900 * Sets the styles for methods. $key is a number that references the |
|
901 * appropriate "object splitter" - see the language file for the language |
|
902 * you are highlighting to get this number. If $preserve_defaults is |
|
903 * true, then styles are merged with the default styles, with the |
|
904 * user defined styles having priority |
|
905 * |
|
906 * @param int The key of the object splitter to change the styles of |
|
907 * @param string The style to make the methods |
|
908 * @param boolean Whether to merge the new styles with the old or just |
|
909 * to overwrite them |
|
910 * @since 1.0.0 |
|
911 */ |
|
912 function set_methods_style($key, $style, $preserve_defaults = false) { |
|
913 if (!$preserve_defaults) { |
|
914 $this->language_data['STYLES']['METHODS'][$key] = $style; |
|
915 } |
|
916 else { |
|
917 $this->language_data['STYLES']['METHODS'][$key] .= $style; |
|
918 } |
|
919 } |
|
920 |
|
921 /** |
|
922 * Turns highlighting on/off for methods |
|
923 * |
|
924 * @param boolean Whether to turn highlighting for methods on or off |
|
925 * @since 1.0.0 |
|
926 */ |
|
927 function set_methods_highlighting($flag) { |
|
928 $this->lexic_permissions['METHODS'] = ($flag) ? true : false; |
|
929 } |
|
930 |
|
931 /** |
|
932 * Sets the styles for regexps. If $preserve_defaults is |
|
933 * true, then styles are merged with the default styles, with the |
|
934 * user defined styles having priority |
|
935 * |
|
936 * @param string The style to make the regular expression matches |
|
937 * @param boolean Whether to merge the new styles with the old or just |
|
938 * to overwrite them |
|
939 * @since 1.0.0 |
|
940 */ |
|
941 function set_regexps_style($key, $style, $preserve_defaults = false) { |
|
942 if (!$preserve_defaults) { |
|
943 $this->language_data['STYLES']['REGEXPS'][$key] = $style; |
|
944 } |
|
945 else { |
|
946 $this->language_data['STYLES']['REGEXPS'][$key] .= $style; |
|
947 } |
|
948 } |
|
949 |
|
950 /** |
|
951 * Turns highlighting on/off for regexps |
|
952 * |
|
953 * @param int The key of the regular expression group to turn on or off |
|
954 * @param boolean Whether to turn highlighting for the regular expression group on or off |
|
955 * @since 1.0.0 |
|
956 */ |
|
957 function set_regexps_highlighting($key, $flag) { |
|
958 $this->lexic_permissions['REGEXPS'][$key] = ($flag) ? true : false; |
|
959 } |
|
960 |
|
961 /** |
|
962 * Sets whether a set of keywords are checked for in a case sensitive manner |
|
963 * |
|
964 * @param int The key of the keyword group to change the case sensitivity of |
|
965 * @param boolean Whether to check in a case sensitive manner or not |
|
966 * @since 1.0.0 |
|
967 */ |
|
968 function set_case_sensitivity($key, $case) { |
|
969 $this->language_data['CASE_SENSITIVE'][$key] = ($case) ? true : false; |
|
970 } |
|
971 |
|
972 /** |
|
973 * Sets the case that keywords should use when found. Use the constants: |
|
974 * |
|
975 * - GESHI_CAPS_NO_CHANGE: leave keywords as-is |
|
976 * - GESHI_CAPS_UPPER: convert all keywords to uppercase where found |
|
977 * - GESHI_CAPS_LOWER: convert all keywords to lowercase where found |
|
978 * |
|
979 * @param int A constant specifying what to do with matched keywords |
|
980 * @since 1.0.1 |
|
981 * @todo Error check the passed value |
|
982 */ |
|
983 function set_case_keywords($case) { |
|
984 $this->language_data['CASE_KEYWORDS'] = $case; |
|
985 } |
|
986 |
|
987 /** |
|
988 * Sets how many spaces a tab is substituted for |
|
989 * |
|
990 * Widths below zero are ignored |
|
991 * |
|
992 * @param int The tab width |
|
993 * @since 1.0.0 |
|
994 */ |
|
995 function set_tab_width($width) { |
|
996 $this->tab_width = intval($width); |
|
997 //Check if it fit's the constraints: |
|
998 if($this->tab_width < 1) { |
|
999 //Return it to the default |
|
1000 $this->tab_width = 8; |
|
1001 } |
|
1002 } |
|
1003 |
|
1004 /** |
|
1005 * Sets whether or not to use tab-stop width specifed by language |
|
1006 * |
|
1007 * @param boolean Whether to use language-specific tab-stop widths |
|
1008 */ |
|
1009 function set_use_language_tab_width($use) { |
|
1010 $this->use_language_tab_width = (bool) $use; |
|
1011 } |
|
1012 |
|
1013 /** |
|
1014 * Returns the tab width to use, based on the current language and user |
|
1015 * preference |
|
1016 * |
|
1017 * @return int Tab width |
|
1018 */ |
|
1019 function get_real_tab_width() { |
|
1020 if (!$this->use_language_tab_width || !isset($this->language_data['TAB_WIDTH'])) { |
|
1021 return $this->tab_width; |
|
1022 } else { |
|
1023 return $this->language_data['TAB_WIDTH']; |
|
1024 } |
|
1025 } |
|
1026 |
|
1027 /** |
|
1028 * Enables/disables strict highlighting. Default is off, calling this |
|
1029 * method without parameters will turn it on. See documentation |
|
1030 * for more details on strict mode and where to use it. |
|
1031 * |
|
1032 * @param boolean Whether to enable strict mode or not |
|
1033 * @since 1.0.0 |
|
1034 */ |
|
1035 function enable_strict_mode($mode = true) { |
|
1036 if (GESHI_MAYBE == $this->language_data['STRICT_MODE_APPLIES']) { |
|
1037 $this->strict_mode = ($mode) ? true : false; |
|
1038 } |
|
1039 } |
|
1040 |
|
1041 /** |
|
1042 * Disables all highlighting |
|
1043 * |
|
1044 * @since 1.0.0 |
|
1045 * @todo Rewrite with an array traversal |
|
1046 */ |
|
1047 function disable_highlighting() { |
|
1048 foreach ($this->lexic_permissions as $key => $value) { |
|
1049 if (is_array($value)) { |
|
1050 foreach ($value as $k => $v) { |
|
1051 $this->lexic_permissions[$key][$k] = false; |
|
1052 } |
|
1053 } |
|
1054 else { |
|
1055 $this->lexic_permissions[$key] = false; |
|
1056 } |
|
1057 } |
|
1058 // Context blocks |
|
1059 $this->enable_important_blocks = false; |
|
1060 } |
|
1061 |
|
1062 /** |
|
1063 * Enables all highlighting |
|
1064 * |
|
1065 * @since 1.0.0 |
|
1066 * @todo Rewrite with array traversal |
|
1067 */ |
|
1068 function enable_highlighting() { |
|
1069 foreach ($this->lexic_permissions as $key => $value) { |
|
1070 if (is_array($value)) { |
|
1071 foreach ($value as $k => $v) { |
|
1072 $this->lexic_permissions[$key][$k] = true; |
|
1073 } |
|
1074 } |
|
1075 else { |
|
1076 $this->lexic_permissions[$key] = true; |
|
1077 } |
|
1078 } |
|
1079 // Context blocks |
|
1080 $this->enable_important_blocks = true; |
|
1081 } |
|
1082 |
|
1083 /** |
|
1084 * Given a file extension, this method returns either a valid geshi language |
|
1085 * name, or the empty string if it couldn't be found |
|
1086 * |
|
1087 * @param string The extension to get a language name for |
|
1088 * @param array A lookup array to use instead of the default |
|
1089 * @since 1.0.5 |
|
1090 * @todo Re-think about how this method works (maybe make it private and/or make it |
|
1091 * a extension->lang lookup?) |
|
1092 * @todo static? |
|
1093 */ |
|
1094 function get_language_name_from_extension( $extension, $lookup = array() ) { |
|
1095 if ( !$lookup ) { |
|
1096 $lookup = array( |
|
1097 'actionscript' => array('as'), |
|
1098 'ada' => array('a', 'ada', 'adb', 'ads'), |
|
1099 'apache' => array('conf'), |
|
1100 'asm' => array('ash', 'asm'), |
|
1101 'asp' => array('asp'), |
|
1102 'bash' => array('sh'), |
|
1103 'c' => array('c', 'h'), |
|
1104 'c_mac' => array('c', 'h'), |
|
1105 'caddcl' => array(), |
|
1106 'cadlisp' => array(), |
|
1107 'cdfg' => array('cdfg'), |
|
1108 'cpp' => array('cpp', 'h', 'hpp'), |
|
1109 'csharp' => array(), |
|
1110 'css' => array('css'), |
|
1111 'delphi' => array('dpk', 'dpr'), |
|
1112 'html4strict' => array('html', 'htm'), |
|
1113 'java' => array('java'), |
|
1114 'javascript' => array('js'), |
|
1115 'lisp' => array('lisp'), |
|
1116 'lua' => array('lua'), |
|
1117 'mpasm' => array(), |
|
1118 'nsis' => array(), |
|
1119 'objc' => array(), |
|
1120 'oobas' => array(), |
|
1121 'oracle8' => array(), |
|
1122 'pascal' => array('pas'), |
|
1123 'perl' => array('pl', 'pm'), |
|
1124 'php' => array('php', 'php5', 'phtml', 'phps'), |
|
1125 'python' => array('py'), |
|
1126 'qbasic' => array('bi'), |
|
1127 'sas' => array('sas'), |
|
1128 'smarty' => array(), |
|
1129 'vb' => array('bas'), |
|
1130 'vbnet' => array(), |
|
1131 'visualfoxpro' => array(), |
|
1132 'xml' => array('xml') |
|
1133 ); |
|
1134 } |
|
1135 |
|
1136 foreach ($lookup as $lang => $extensions) { |
|
1137 foreach ($extensions as $ext) { |
|
1138 if ($ext == $extension) { |
|
1139 return $lang; |
|
1140 } |
|
1141 } |
|
1142 } |
|
1143 return ''; |
|
1144 } |
|
1145 |
|
1146 /** |
|
1147 * Given a file name, this method loads its contents in, and attempts |
|
1148 * to set the language automatically. An optional lookup table can be |
|
1149 * passed for looking up the language name. If not specified a default |
|
1150 * table is used |
|
1151 * |
|
1152 * The language table is in the form |
|
1153 * <pre>array( |
|
1154 * 'lang_name' => array('extension', 'extension', ...), |
|
1155 * 'lang_name' ... |
|
1156 * );</pre> |
|
1157 * |
|
1158 * @todo Complete rethink of this and above method |
|
1159 * @since 1.0.5 |
|
1160 */ |
|
1161 function load_from_file($file_name, $lookup = array()) { |
|
1162 if (is_readable($file_name)) { |
|
1163 $this->set_source(implode('', file($file_name))); |
|
1164 $this->set_language($this->get_language_name_from_extension(substr(strrchr($file_name, '.'), 1), $lookup)); |
|
1165 } |
|
1166 else { |
|
1167 $this->error = GESHI_ERROR_FILE_NOT_READABLE; |
|
1168 } |
|
1169 } |
|
1170 |
|
1171 /** |
|
1172 * Adds a keyword to a keyword group for highlighting |
|
1173 * |
|
1174 * @param int The key of the keyword group to add the keyword to |
|
1175 * @param string The word to add to the keyword group |
|
1176 * @since 1.0.0 |
|
1177 */ |
|
1178 function add_keyword($key, $word) { |
|
1179 $this->language_data['KEYWORDS'][$key][] = $word; |
|
1180 } |
|
1181 |
|
1182 /** |
|
1183 * Removes a keyword from a keyword group |
|
1184 * |
|
1185 * @param int The key of the keyword group to remove the keyword from |
|
1186 * @param string The word to remove from the keyword group |
|
1187 * @since 1.0.0 |
|
1188 */ |
|
1189 function remove_keyword($key, $word) { |
|
1190 $this->language_data['KEYWORDS'][$key] = |
|
1191 array_diff($this->language_data['KEYWORDS'][$key], array($word)); |
|
1192 } |
|
1193 |
|
1194 /** |
|
1195 * Creates a new keyword group |
|
1196 * |
|
1197 * @param int The key of the keyword group to create |
|
1198 * @param string The styles for the keyword group |
|
1199 * @param boolean Whether the keyword group is case sensitive ornot |
|
1200 * @param array The words to use for the keyword group |
|
1201 * @since 1.0.0 |
|
1202 */ |
|
1203 function add_keyword_group($key, $styles, $case_sensitive = true, $words = array()) { |
|
1204 $words = (array) $words; |
|
1205 $this->language_data['KEYWORDS'][$key] = $words; |
|
1206 $this->lexic_permissions['KEYWORDS'][$key] = true; |
|
1207 $this->language_data['CASE_SENSITIVE'][$key] = $case_sensitive; |
|
1208 $this->language_data['STYLES']['KEYWORDS'][$key] = $styles; |
|
1209 } |
|
1210 |
|
1211 /** |
|
1212 * Removes a keyword group |
|
1213 * |
|
1214 * @param int The key of the keyword group to remove |
|
1215 * @since 1.0.0 |
|
1216 */ |
|
1217 function remove_keyword_group ($key) { |
|
1218 unset($this->language_data['KEYWORDS'][$key]); |
|
1219 unset($this->lexic_permissions['KEYWORDS'][$key]); |
|
1220 unset($this->language_data['CASE_SENSITIVE'][$key]); |
|
1221 unset($this->language_data['STYLES']['KEYWORDS'][$key]); |
|
1222 } |
|
1223 |
|
1224 /** |
|
1225 * Sets the content of the header block |
|
1226 * |
|
1227 * @param string The content of the header block |
|
1228 * @since 1.0.2 |
|
1229 */ |
|
1230 function set_header_content($content) { |
|
1231 $this->header_content = $content; |
|
1232 } |
|
1233 |
|
1234 /** |
|
1235 * Sets the content of the footer block |
|
1236 * |
|
1237 * @param string The content of the footer block |
|
1238 * @since 1.0.2 |
|
1239 */ |
|
1240 function set_footer_content($content) { |
|
1241 $this->footer_content = $content; |
|
1242 } |
|
1243 |
|
1244 /** |
|
1245 * Sets the style for the header content |
|
1246 * |
|
1247 * @param string The style for the header content |
|
1248 * @since 1.0.2 |
|
1249 */ |
|
1250 function set_header_content_style($style) { |
|
1251 $this->header_content_style = $style; |
|
1252 } |
|
1253 |
|
1254 /** |
|
1255 * Sets the style for the footer content |
|
1256 * |
|
1257 * @param string The style for the footer content |
|
1258 * @since 1.0.2 |
|
1259 */ |
|
1260 function set_footer_content_style($style) { |
|
1261 $this->footer_content_style = $style; |
|
1262 } |
|
1263 |
|
1264 /** |
|
1265 * Sets whether to force a surrounding block around |
|
1266 * the highlighted code or not |
|
1267 * |
|
1268 * @param boolean Tells whether to enable or disable this feature |
|
1269 * @since 1.0.7.20 |
|
1270 */ |
|
1271 function enable_inner_code_block($flag) { |
|
1272 $this->force_code_block = (bool)$flag; |
|
1273 } |
|
1274 |
|
1275 /** |
|
1276 * Sets the base URL to be used for keywords |
|
1277 * |
|
1278 * @param int The key of the keyword group to set the URL for |
|
1279 * @param string The URL to set for the group. If {FNAME} is in |
|
1280 * the url somewhere, it is replaced by the keyword |
|
1281 * that the URL is being made for |
|
1282 * @since 1.0.2 |
|
1283 */ |
|
1284 function set_url_for_keyword_group($group, $url) { |
|
1285 $this->language_data['URLS'][$group] = $url; |
|
1286 } |
|
1287 |
|
1288 /** |
|
1289 * Sets styles for links in code |
|
1290 * |
|
1291 * @param int A constant that specifies what state the style is being |
|
1292 * set for - e.g. :hover or :visited |
|
1293 * @param string The styles to use for that state |
|
1294 * @since 1.0.2 |
|
1295 */ |
|
1296 function set_link_styles($type, $styles) { |
|
1297 $this->link_styles[$type] = $styles; |
|
1298 } |
|
1299 |
|
1300 /** |
|
1301 * Sets the target for links in code |
|
1302 * |
|
1303 * @param string The target for links in the code, e.g. _blank |
|
1304 * @since 1.0.3 |
|
1305 */ |
|
1306 function set_link_target($target) { |
|
1307 if (!$target) { |
|
1308 $this->link_target = ''; |
|
1309 } |
|
1310 else { |
|
1311 $this->link_target = ' target="' . $target . '" '; |
|
1312 } |
|
1313 } |
|
1314 |
|
1315 /** |
|
1316 * Sets styles for important parts of the code |
|
1317 * |
|
1318 * @param string The styles to use on important parts of the code |
|
1319 * @since 1.0.2 |
|
1320 */ |
|
1321 function set_important_styles($styles) { |
|
1322 $this->important_styles = $styles; |
|
1323 } |
|
1324 |
|
1325 /** |
|
1326 * Sets whether context-important blocks are highlighted |
|
1327 * |
|
1328 * @todo REMOVE THIS SHIZ FROM GESHI! |
|
1329 * @deprecated |
|
1330 */ |
|
1331 function enable_important_blocks($flag) { |
|
1332 $this->enable_important_blocks = ( $flag ) ? true : false; |
|
1333 } |
|
1334 |
|
1335 /** |
|
1336 * Whether CSS IDs should be added to each line |
|
1337 * |
|
1338 * @param boolean If true, IDs will be added to each line. |
|
1339 * @since 1.0.2 |
|
1340 */ |
|
1341 function enable_ids($flag = true) { |
|
1342 $this->add_ids = ($flag) ? true : false; |
|
1343 } |
|
1344 |
|
1345 /** |
|
1346 * Specifies which lines to highlight extra |
|
1347 * |
|
1348 * @param mixed An array of line numbers to highlight, or just a line |
|
1349 * number on its own. |
|
1350 * @since 1.0.2 |
|
1351 * @todo Some data replication here that could be cut down on |
|
1352 */ |
|
1353 function highlight_lines_extra($lines) { |
|
1354 if (is_array($lines)) { |
|
1355 foreach ($lines as $line) { |
|
1356 $this->highlight_extra_lines[intval($line)] = intval($line); |
|
1357 } |
|
1358 } |
|
1359 else { |
|
1360 $this->highlight_extra_lines[intval($lines)] = intval($lines); |
|
1361 } |
|
1362 } |
|
1363 |
|
1364 /** |
|
1365 * Sets the style for extra-highlighted lines |
|
1366 * |
|
1367 * @param string The style for extra-highlighted lines |
|
1368 * @since 1.0.2 |
|
1369 */ |
|
1370 function set_highlight_lines_extra_style($styles) { |
|
1371 $this->highlight_extra_lines_style = $styles; |
|
1372 } |
|
1373 |
|
1374 /** |
|
1375 * Sets the line-ending |
|
1376 * |
|
1377 * @param string The new line-ending |
|
1378 */ |
|
1379 function set_line_ending($line_ending) { |
|
1380 $this->line_ending = (string)$line_ending; |
|
1381 } |
|
1382 |
|
1383 /** |
|
1384 * Sets what number line numbers should start at. Should |
|
1385 * be a positive integer, and will be converted to one. |
|
1386 * |
|
1387 * <b>Warning:</b> Using this method will add the "start" |
|
1388 * attribute to the <ol> that is used for line numbering. |
|
1389 * This is <b>not</b> valid XHTML strict, so if that's what you |
|
1390 * care about then don't use this method. Firefox is getting |
|
1391 * support for the CSS method of doing this in 1.1 and Opera |
|
1392 * has support for the CSS method, but (of course) IE doesn't |
|
1393 * so it's not worth doing it the CSS way yet. |
|
1394 * |
|
1395 * @param int The number to start line numbers at |
|
1396 * @since 1.0.2 |
|
1397 */ |
|
1398 function start_line_numbers_at($number) { |
|
1399 $this->line_numbers_start = abs(intval($number)); |
|
1400 } |
|
1401 |
|
1402 /** |
|
1403 * Sets the encoding used for htmlspecialchars(), for international |
|
1404 * support. |
|
1405 * |
|
1406 * NOTE: This is not needed for now because htmlspecialchars() is not |
|
1407 * being used (it has a security hole in PHP4 that has not been patched). |
|
1408 * Maybe in a future version it may make a return for speed reasons, but |
|
1409 * I doubt it. |
|
1410 * |
|
1411 * @param string The encoding to use for the source |
|
1412 * @since 1.0.3 |
|
1413 */ |
|
1414 function set_encoding($encoding) { |
|
1415 if ($encoding) { |
|
1416 $this->encoding = $encoding; |
|
1417 } |
|
1418 } |
|
1419 |
|
1420 /** |
|
1421 * Turns linking of keywords on or off. |
|
1422 * |
|
1423 * @param boolean If true, links will be added to keywords |
|
1424 */ |
|
1425 function enable_keyword_links($enable = true) { |
|
1426 $this->keyword_links = ($enable) ? true : false; |
|
1427 } |
|
1428 |
|
1429 /** |
|
1430 * Returns the code in $this->source, highlighted and surrounded by the |
|
1431 * nessecary HTML. |
|
1432 * |
|
1433 * This should only be called ONCE, cos it's SLOW! If you want to highlight |
|
1434 * the same source multiple times, you're better off doing a whole lot of |
|
1435 * str_replaces to replace the <span>s |
|
1436 * |
|
1437 * @since 1.0.0 |
|
1438 */ |
|
1439 function parse_code () { |
|
1440 // Start the timer |
|
1441 $start_time = microtime(); |
|
1442 |
|
1443 // Firstly, if there is an error, we won't highlight |
|
1444 if ($this->error) { |
|
1445 $result = GeSHi::hsc($this->source); |
|
1446 // Timing is irrelevant |
|
1447 $this->set_time($start_time, $start_time); |
|
1448 return $this->finalise($result); |
|
1449 } |
|
1450 |
|
1451 // Replace all newlines to a common form. |
|
1452 $code = str_replace("\r\n", "\n", $this->source); |
|
1453 $code = str_replace("\r", "\n", $code); |
|
1454 // Add spaces for regular expression matching and line numbers |
|
1455 $code = "\n" . $code . "\n"; |
|
1456 |
|
1457 // Initialise various stuff |
|
1458 $length = strlen($code); |
|
1459 $STRING_OPEN = ''; |
|
1460 $CLOSE_STRING = false; |
|
1461 $ESCAPE_CHAR_OPEN = false; |
|
1462 $COMMENT_MATCHED = false; |
|
1463 // Turn highlighting on if strict mode doesn't apply to this language |
|
1464 $HIGHLIGHTING_ON = ( !$this->strict_mode ) ? true : ''; |
|
1465 // Whether to highlight inside a block of code |
|
1466 $HIGHLIGHT_INSIDE_STRICT = false; |
|
1467 $HARDQUOTE_OPEN = false; |
|
1468 $STRICTATTRS = ''; |
|
1469 $stuff_to_parse = ''; |
|
1470 $result = ''; |
|
1471 |
|
1472 // "Important" selections are handled like multiline comments |
|
1473 // @todo GET RID OF THIS SHIZ |
|
1474 if ($this->enable_important_blocks) { |
|
1475 $this->language_data['COMMENT_MULTI'][GESHI_START_IMPORTANT] = GESHI_END_IMPORTANT; |
|
1476 } |
|
1477 |
|
1478 if ($this->strict_mode) { |
|
1479 // Break the source into bits. Each bit will be a portion of the code |
|
1480 // within script delimiters - for example, HTML between < and > |
|
1481 $parts = array(0 => array(0 => '')); |
|
1482 $k = 0; |
|
1483 for ($i = 0; $i < $length; $i++) { |
|
1484 $char = substr($code, $i, 1); |
|
1485 if (!$HIGHLIGHTING_ON) { |
|
1486 foreach ($this->language_data['SCRIPT_DELIMITERS'] as $key => $delimiters) { |
|
1487 foreach ($delimiters as $open => $close) { |
|
1488 // Get the next little bit for this opening string |
|
1489 $check = substr($code, $i, strlen($open)); |
|
1490 // If it matches... |
|
1491 if ($check == $open) { |
|
1492 // We start a new block with the highlightable |
|
1493 // code in it |
|
1494 $HIGHLIGHTING_ON = $open; |
|
1495 $i += strlen($open) - 1; |
|
1496 $char = $open; |
|
1497 $parts[++$k][0] = $char; |
|
1498 |
|
1499 // No point going around again... |
|
1500 break(2); |
|
1501 } |
|
1502 } |
|
1503 } |
|
1504 } |
|
1505 else { |
|
1506 foreach ($this->language_data['SCRIPT_DELIMITERS'] as $key => $delimiters) { |
|
1507 foreach ($delimiters as $open => $close) { |
|
1508 if ($open == $HIGHLIGHTING_ON) { |
|
1509 // Found the closing tag |
|
1510 break(2); |
|
1511 } |
|
1512 } |
|
1513 } |
|
1514 // We check code from our current position BACKWARDS. This is so |
|
1515 // the ending string for highlighting can be included in the block |
|
1516 $check = substr($code, $i - strlen($close) + 1, strlen($close)); |
|
1517 if ($check == $close) { |
|
1518 $HIGHLIGHTING_ON = ''; |
|
1519 // Add the string to the rest of the string for this part |
|
1520 $parts[$k][1] = ( isset($parts[$k][1]) ) ? $parts[$k][1] . $char : $char; |
|
1521 $parts[++$k][0] = ''; |
|
1522 $char = ''; |
|
1523 } |
|
1524 } |
|
1525 $parts[$k][1] = ( isset($parts[$k][1]) ) ? $parts[$k][1] . $char : $char; |
|
1526 } |
|
1527 $HIGHLIGHTING_ON = ''; |
|
1528 } |
|
1529 else { |
|
1530 // Not strict mode - simply dump the source into |
|
1531 // the array at index 1 (the first highlightable block) |
|
1532 $parts = array( |
|
1533 1 => array( |
|
1534 0 => '', |
|
1535 1 => $code |
|
1536 ) |
|
1537 ); |
|
1538 } |
|
1539 |
|
1540 // Now we go through each part. We know that even-indexed parts are |
|
1541 // code that shouldn't be highlighted, and odd-indexed parts should |
|
1542 // be highlighted |
|
1543 foreach ($parts as $key => $data) { |
|
1544 $part = $data[1]; |
|
1545 // If this block should be highlighted... |
|
1546 if ($key % 2) { |
|
1547 if ($this->strict_mode) { |
|
1548 // Find the class key for this block of code |
|
1549 foreach ($this->language_data['SCRIPT_DELIMITERS'] as $script_key => $script_data) { |
|
1550 foreach ($script_data as $open => $close) { |
|
1551 if ($data[0] == $open) { |
|
1552 break(2); |
|
1553 } |
|
1554 } |
|
1555 } |
|
1556 |
|
1557 if ($this->language_data['STYLES']['SCRIPT'][$script_key] != '' && |
|
1558 $this->lexic_permissions['SCRIPT']) { |
|
1559 // Add a span element around the source to |
|
1560 // highlight the overall source block |
|
1561 if (!$this->use_classes && |
|
1562 $this->language_data['STYLES']['SCRIPT'][$script_key] != '') { |
|
1563 $attributes = ' style="' . $this->language_data['STYLES']['SCRIPT'][$script_key] . '"'; |
|
1564 } |
|
1565 else { |
|
1566 $attributes = ' class="sc' . $script_key . '"'; |
|
1567 } |
|
1568 $result .= "<span$attributes>"; |
|
1569 $STRICTATTRS = $attributes; |
|
1570 } |
|
1571 } |
|
1572 |
|
1573 if (!$this->strict_mode || $this->language_data['HIGHLIGHT_STRICT_BLOCK'][$script_key]) { |
|
1574 // Now, highlight the code in this block. This code |
|
1575 // is really the engine of GeSHi (along with the method |
|
1576 // parse_non_string_part). |
|
1577 $length = strlen($part); |
|
1578 for ($i = 0; $i < $length; $i++) { |
|
1579 // Get the next char |
|
1580 $char = substr($part, $i, 1); |
|
1581 $hq = isset($this->language_data['HARDQUOTE']) ? $this->language_data['HARDQUOTE'][0] : false; |
|
1582 // Is this char the newline and line numbers being used? |
|
1583 if (($this->line_numbers != GESHI_NO_LINE_NUMBERS |
|
1584 || count($this->highlight_extra_lines) > 0) |
|
1585 && $char == "\n") { |
|
1586 // If so, is there a string open? If there is, we should end it before |
|
1587 // the newline and begin it again (so when <li>s are put in the source |
|
1588 // remains XHTML compliant) |
|
1589 // note to self: This opens up possibility of config files specifying |
|
1590 // that languages can/cannot have multiline strings??? |
|
1591 if ($STRING_OPEN) { |
|
1592 if (!$this->use_classes) { |
|
1593 $attributes = ' style="' . $this->language_data['STYLES']['STRINGS'][0] . '"'; |
|
1594 } |
|
1595 else { |
|
1596 $attributes = ' class="st0"'; |
|
1597 } |
|
1598 $char = '</span>' . $char . "<span$attributes>"; |
|
1599 } |
|
1600 } |
|
1601 else if ($char == $STRING_OPEN) { |
|
1602 // A match of a string delimiter |
|
1603 if (($this->lexic_permissions['ESCAPE_CHAR'] && $ESCAPE_CHAR_OPEN) || |
|
1604 ($this->lexic_permissions['STRINGS'] && !$ESCAPE_CHAR_OPEN)) { |
|
1605 $char = GeSHi::hsc($char) . '</span>'; |
|
1606 } |
|
1607 $escape_me = false; |
|
1608 if ($HARDQUOTE_OPEN) { |
|
1609 if ($ESCAPE_CHAR_OPEN) { |
|
1610 $escape_me = true; |
|
1611 } |
|
1612 else { |
|
1613 foreach ($this->language_data['HARDESCAPE'] as $hardesc) { |
|
1614 if (substr($part, $i, strlen($hardesc)) == $hardesc) { |
|
1615 $escape_me = true; |
|
1616 break; |
|
1617 } |
|
1618 } |
|
1619 } |
|
1620 } |
|
1621 |
|
1622 if (!$ESCAPE_CHAR_OPEN) { |
|
1623 $STRING_OPEN = ''; |
|
1624 $CLOSE_STRING = true; |
|
1625 } |
|
1626 if (!$escape_me) { |
|
1627 $HARDQUOTE_OPEN = false; |
|
1628 } |
|
1629 $ESCAPE_CHAR_OPEN = false; |
|
1630 } |
|
1631 else if (in_array($char, $this->language_data['QUOTEMARKS']) && |
|
1632 ($STRING_OPEN == '') && $this->lexic_permissions['STRINGS']) { |
|
1633 // The start of a new string |
|
1634 $STRING_OPEN = $char; |
|
1635 if (!$this->use_classes) { |
|
1636 $attributes = ' style="' . $this->language_data['STYLES']['STRINGS'][0] . '"'; |
|
1637 } |
|
1638 else { |
|
1639 $attributes = ' class="st0"'; |
|
1640 } |
|
1641 $char = "<span$attributes>" . GeSHi::hsc($char); |
|
1642 |
|
1643 $result .= $this->parse_non_string_part( $stuff_to_parse ); |
|
1644 $stuff_to_parse = ''; |
|
1645 } |
|
1646 else if ($hq && substr($part, $i, strlen($hq)) == $hq && |
|
1647 ($STRING_OPEN == '') && $this->lexic_permissions['STRINGS']) { |
|
1648 // The start of a hard quoted string |
|
1649 $STRING_OPEN = $this->language_data['HARDQUOTE'][1]; |
|
1650 if (!$this->use_classes) { |
|
1651 $attributes = ' style="' . $this->language_data['STYLES']['STRINGS'][0] . '"'; |
|
1652 } |
|
1653 else { |
|
1654 $attributes = ' class="st0"'; |
|
1655 } |
|
1656 $char = "<span$attributes>" . $hq; |
|
1657 $i += strlen($hq) - 1; |
|
1658 $HARDQUOTE_OPEN = true; |
|
1659 $result .= $this->parse_non_string_part($stuff_to_parse); |
|
1660 $stuff_to_parse = ''; |
|
1661 } |
|
1662 else if ($char == $this->language_data['ESCAPE_CHAR'] && $STRING_OPEN != '') { |
|
1663 // An escape character |
|
1664 if (!$ESCAPE_CHAR_OPEN) { |
|
1665 $ESCAPE_CHAR_OPEN = !$HARDQUOTE_OPEN; // true unless $HARDQUOTE_OPEN |
|
1666 if ($HARDQUOTE_OPEN) { |
|
1667 foreach ($this->language_data['HARDESCAPE'] as $hard) { |
|
1668 if (substr($part, $i, strlen($hard)) == $hard) { |
|
1669 $ESCAPE_CHAR_OPEN = true; |
|
1670 break; |
|
1671 } |
|
1672 } |
|
1673 } |
|
1674 if ($ESCAPE_CHAR_OPEN && $this->lexic_permissions['ESCAPE_CHAR']) { |
|
1675 if (!$this->use_classes) { |
|
1676 $attributes = ' style="' . $this->language_data['STYLES']['ESCAPE_CHAR'][0] . '"'; |
|
1677 } |
|
1678 else { |
|
1679 $attributes = ' class="es0"'; |
|
1680 } |
|
1681 $char = "<span$attributes>" . $char; |
|
1682 if (substr($code, $i + 1, 1) == "\n") { |
|
1683 // escaping a newline, what's the point in putting the span around |
|
1684 // the newline? It only causes hassles when inserting line numbers |
|
1685 $char .= '</span>'; |
|
1686 $ESCAPE_CHAR_OPEN = false; |
|
1687 } |
|
1688 } |
|
1689 } |
|
1690 else { |
|
1691 $ESCAPE_CHAR_OPEN = false; |
|
1692 if ($this->lexic_permissions['ESCAPE_CHAR']) { |
|
1693 $char .= '</span>'; |
|
1694 } |
|
1695 } |
|
1696 } |
|
1697 else if ($ESCAPE_CHAR_OPEN) { |
|
1698 if ($this->lexic_permissions['ESCAPE_CHAR']) { |
|
1699 $char .= '</span>'; |
|
1700 } |
|
1701 $ESCAPE_CHAR_OPEN = false; |
|
1702 $test_str = $char; |
|
1703 } |
|
1704 else if ($STRING_OPEN == '') { |
|
1705 // Is this a multiline comment? |
|
1706 foreach ($this->language_data['COMMENT_MULTI'] as $open => $close) { |
|
1707 $com_len = strlen($open); |
|
1708 $test_str = substr( $part, $i, $com_len ); |
|
1709 $test_str_match = $test_str; |
|
1710 if ($open == $test_str) { |
|
1711 $COMMENT_MATCHED = true; |
|
1712 //@todo If remove important do remove here |
|
1713 if ($this->lexic_permissions['COMMENTS']['MULTI'] || |
|
1714 $test_str == GESHI_START_IMPORTANT) { |
|
1715 if ($test_str != GESHI_START_IMPORTANT) { |
|
1716 if (!$this->use_classes) { |
|
1717 $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS']['MULTI'] . '"'; |
|
1718 } |
|
1719 else { |
|
1720 $attributes = ' class="coMULTI"'; |
|
1721 } |
|
1722 $test_str = "<span$attributes>" . GeSHi::hsc($test_str); |
|
1723 } |
|
1724 else { |
|
1725 if (!$this->use_classes) { |
|
1726 $attributes = ' style="' . $this->important_styles . '"'; |
|
1727 } |
|
1728 else { |
|
1729 $attributes = ' class="imp"'; |
|
1730 } |
|
1731 // We don't include the start of the comment if it's an |
|
1732 // "important" part |
|
1733 $test_str = "<span$attributes>"; |
|
1734 } |
|
1735 } |
|
1736 else { |
|
1737 $test_str = GeSHi::hsc($test_str); |
|
1738 } |
|
1739 |
|
1740 $close_pos = strpos( $part, $close, $i + strlen($close) ); |
|
1741 |
|
1742 $oops = false; |
|
1743 if ($close_pos === false) { |
|
1744 $close_pos = strlen($part); |
|
1745 $oops = true; |
|
1746 } |
|
1747 else { |
|
1748 $close_pos -= ($com_len - strlen($close)); |
|
1749 } |
|
1750 |
|
1751 // Short-cut through all the multiline code |
|
1752 $rest_of_comment = GeSHi::hsc(substr($part, $i + $com_len, $close_pos - $i)); |
|
1753 if (($this->lexic_permissions['COMMENTS']['MULTI'] || |
|
1754 $test_str_match == GESHI_START_IMPORTANT) && |
|
1755 ($this->line_numbers != GESHI_NO_LINE_NUMBERS || |
|
1756 count($this->highlight_extra_lines) > 0)) { |
|
1757 // strreplace to put close span and open span around multiline newlines |
|
1758 $test_str .= str_replace( |
|
1759 "\n", "</span>\n<span$attributes>", |
|
1760 str_replace("\n ", "\n ", $rest_of_comment) |
|
1761 ); |
|
1762 } |
|
1763 else { |
|
1764 $test_str .= $rest_of_comment; |
|
1765 } |
|
1766 |
|
1767 if ($this->lexic_permissions['COMMENTS']['MULTI'] || |
|
1768 $test_str_match == GESHI_START_IMPORTANT) { |
|
1769 $test_str .= '</span>'; |
|
1770 if ($oops) { |
|
1771 $test_str .= "\n"; |
|
1772 } |
|
1773 } |
|
1774 $i = $close_pos + $com_len - 1; |
|
1775 // parse the rest |
|
1776 $result .= $this->parse_non_string_part($stuff_to_parse); |
|
1777 $stuff_to_parse = ''; |
|
1778 break; |
|
1779 } |
|
1780 } |
|
1781 // If we haven't matched a multiline comment, try single-line comments |
|
1782 if (!$COMMENT_MATCHED) { |
|
1783 foreach ($this->language_data['COMMENT_SINGLE'] as $comment_key => $comment_mark) { |
|
1784 $com_len = strlen($comment_mark); |
|
1785 $test_str = substr($part, $i, $com_len); |
|
1786 if ($this->language_data['CASE_SENSITIVE'][GESHI_COMMENTS]) { |
|
1787 $match = ($comment_mark == $test_str); |
|
1788 } |
|
1789 else { |
|
1790 $match = (strtolower($comment_mark) == strtolower($test_str)); |
|
1791 } |
|
1792 if ($match) { |
|
1793 $COMMENT_MATCHED = true; |
|
1794 if ($this->lexic_permissions['COMMENTS'][$comment_key]) { |
|
1795 if (!$this->use_classes) { |
|
1796 $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS'][$comment_key] . '"'; |
|
1797 } |
|
1798 else { |
|
1799 $attributes = ' class="co' . $comment_key . '"'; |
|
1800 } |
|
1801 $test_str = "<span$attributes>" . GeSHi::hsc($this->change_case($test_str)); |
|
1802 } |
|
1803 else { |
|
1804 $test_str = GeSHi::hsc($test_str); |
|
1805 } |
|
1806 $close_pos = strpos($part, "\n", $i); |
|
1807 $oops = false; |
|
1808 if ($close_pos === false) { |
|
1809 $close_pos = strlen($part); |
|
1810 $oops = true; |
|
1811 } |
|
1812 $test_str .= GeSHi::hsc(substr($part, $i + $com_len, $close_pos - $i - $com_len)); |
|
1813 if ($this->lexic_permissions['COMMENTS'][$comment_key]) { |
|
1814 $test_str .= "</span>"; |
|
1815 } |
|
1816 // Take into account that the comment might be the last in the source |
|
1817 if (!$oops) { |
|
1818 $test_str .= "\n"; |
|
1819 } |
|
1820 $i = $close_pos; |
|
1821 // parse the rest |
|
1822 $result .= $this->parse_non_string_part($stuff_to_parse); |
|
1823 $stuff_to_parse = ''; |
|
1824 break; |
|
1825 } |
|
1826 } |
|
1827 } |
|
1828 } |
|
1829 else if ($STRING_OPEN != '') { |
|
1830 // Otherwise, convert it to HTML form |
|
1831 if (strtolower($this->encoding) == 'utf-8') { |
|
1832 //only escape <128 (we don't want to break multibyte chars) |
|
1833 if (ord($char) < 128) { |
|
1834 $char = GeSHi::hsc($char); |
|
1835 } |
|
1836 } |
|
1837 else { |
|
1838 //encode everthing |
|
1839 $char = GeSHi::hsc($char); |
|
1840 } |
|
1841 } |
|
1842 // Where are we adding this char? |
|
1843 if (!$COMMENT_MATCHED) { |
|
1844 if (($STRING_OPEN == '') && !$CLOSE_STRING) { |
|
1845 $stuff_to_parse .= $char; |
|
1846 } |
|
1847 else { |
|
1848 $result .= $char; |
|
1849 $CLOSE_STRING = false; |
|
1850 } |
|
1851 } |
|
1852 else { |
|
1853 $result .= $test_str; |
|
1854 $COMMENT_MATCHED = false; |
|
1855 } |
|
1856 } |
|
1857 // Parse the last bit |
|
1858 $result .= $this->parse_non_string_part($stuff_to_parse); |
|
1859 $stuff_to_parse = ''; |
|
1860 } |
|
1861 else { |
|
1862 if ($STRICTATTRS != '') { |
|
1863 $part = str_replace("\n", "</span>\n<span$STRICTATTRS>", GeSHi::hsc($part)); |
|
1864 $STRICTATTRS = ''; |
|
1865 } |
|
1866 $result .= $part; |
|
1867 } |
|
1868 // Close the <span> that surrounds the block |
|
1869 if ($this->strict_mode && $this->language_data['STYLES']['SCRIPT'][$script_key] != '' && |
|
1870 $this->lexic_permissions['SCRIPT']) { |
|
1871 $result .= '</span>'; |
|
1872 } |
|
1873 } |
|
1874 else { |
|
1875 // Else not a block to highlight |
|
1876 $result .= GeSHi::hsc($part); |
|
1877 } |
|
1878 } |
|
1879 |
|
1880 // Parse the last stuff (redundant?) |
|
1881 $result .= $this->parse_non_string_part($stuff_to_parse); |
|
1882 |
|
1883 // Lop off the very first and last spaces |
|
1884 $result = substr($result, 1, -1); |
|
1885 |
|
1886 // Are we still in a string? |
|
1887 if ($STRING_OPEN) { |
|
1888 $result .= '</span>'; |
|
1889 } |
|
1890 |
|
1891 // We're finished: stop timing |
|
1892 $this->set_time($start_time, microtime()); |
|
1893 |
|
1894 return $this->finalise($result); |
|
1895 } |
|
1896 |
|
1897 /** |
|
1898 * Swaps out spaces and tabs for HTML indentation. Not needed if |
|
1899 * the code is in a pre block... |
|
1900 * |
|
1901 * @param string The source to indent |
|
1902 * @return string The source with HTML indenting applied |
|
1903 * @since 1.0.0 |
|
1904 * @access private |
|
1905 */ |
|
1906 function indent($result) { |
|
1907 /// Replace tabs with the correct number of spaces |
|
1908 if (false !== strpos($result, "\t")) { |
|
1909 $lines = explode("\n", $result); |
|
1910 $tab_width = $this->get_real_tab_width(); |
|
1911 foreach ($lines as $key => $line) { |
|
1912 if (false === strpos($line, "\t")) { |
|
1913 $lines[$key] = $line; |
|
1914 continue; |
|
1915 } |
|
1916 |
|
1917 $pos = 0; |
|
1918 $length = strlen($line); |
|
1919 $result_line = ''; |
|
1920 |
|
1921 $IN_TAG = false; |
|
1922 for ($i = 0; $i < $length; $i++) { |
|
1923 $char = substr($line, $i, 1); |
|
1924 // Simple engine to work out whether we're in a tag. |
|
1925 // If we are we modify $pos. This is so we ignore HTML |
|
1926 // in the line and only workout the tab replacement |
|
1927 // via the actual content of the string |
|
1928 // This test could be improved to include strings in the |
|
1929 // html so that < or > would be allowed in user's styles |
|
1930 // (e.g. quotes: '<' '>'; or similar) |
|
1931 if ($IN_TAG && '>' == $char) { |
|
1932 $IN_TAG = false; |
|
1933 $result_line .= '>'; |
|
1934 ++$pos; |
|
1935 } |
|
1936 else if (!$IN_TAG && '<' == $char) { |
|
1937 $IN_TAG = true; |
|
1938 $result_line .= '<'; |
|
1939 ++$pos; |
|
1940 } |
|
1941 else if (!$IN_TAG && '&' == $char) { |
|
1942 $substr = substr($line, $i + 3, 4); |
|
1943 //$substr_5 = substr($line, 5, 1); |
|
1944 $posi = strpos($substr, ';'); |
|
1945 if (false !== $posi) { |
|
1946 $pos += $posi + 3; |
|
1947 } |
|
1948 $result_line .= '&'; |
|
1949 } |
|
1950 else if (!$IN_TAG && "\t" == $char) { |
|
1951 $str = ''; |
|
1952 // OPTIMISE - move $strs out. Make an array: |
|
1953 // $tabs = array( |
|
1954 // 1 => ' ', |
|
1955 // 2 => ' ', |
|
1956 // 3 => ' ' etc etc |
|
1957 // to use instead of building a string every time |
|
1958 $strs = array(0 => ' ', 1 => ' '); |
|
1959 for ($k = 0; $k < ($tab_width - (($i - $pos) % $tab_width)); $k++) $str .= $strs[$k % 2]; |
|
1960 $result_line .= $str; |
|
1961 $pos += ($i - $pos) % $tab_width + 1; |
|
1962 |
|
1963 if (false === strpos($line, "\t", $i + 1)) { |
|
1964 $result_line .= substr($line, $i + 1); |
|
1965 break; |
|
1966 } |
|
1967 } |
|
1968 else if ($IN_TAG) { |
|
1969 ++$pos; |
|
1970 $result_line .= $char; |
|
1971 } |
|
1972 else { |
|
1973 $result_line .= $char; |
|
1974 //++$pos; |
|
1975 } |
|
1976 } |
|
1977 $lines[$key] = $result_line; |
|
1978 } |
|
1979 $result = implode("\n", $lines); |
|
1980 } |
|
1981 // Other whitespace |
|
1982 // BenBE: Fix to reduce the number of replacements to be done |
|
1983 $result = str_replace("\n ", "\n ", $result); |
|
1984 $result = str_replace(' ', ' ', $result); |
|
1985 |
|
1986 if ($this->line_numbers == GESHI_NO_LINE_NUMBERS) { |
|
1987 if ($this->line_ending === null) { |
|
1988 $result = nl2br($result); |
|
1989 } else { |
|
1990 $result = str_replace("\n", $this->line_ending, $result); |
|
1991 } |
|
1992 } |
|
1993 return $result; |
|
1994 } |
|
1995 |
|
1996 /** |
|
1997 * Changes the case of a keyword for those languages where a change is asked for |
|
1998 * |
|
1999 * @param string The keyword to change the case of |
|
2000 * @return string The keyword with its case changed |
|
2001 * @since 1.0.0 |
|
2002 * @access private |
|
2003 */ |
|
2004 function change_case($instr) { |
|
2005 if ($this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_UPPER) { |
|
2006 return strtoupper($instr); |
|
2007 } |
|
2008 else if ($this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_LOWER) { |
|
2009 return strtolower($instr); |
|
2010 } |
|
2011 return $instr; |
|
2012 } |
|
2013 |
|
2014 /** |
|
2015 * Adds a url to a keyword where needed. |
|
2016 * |
|
2017 * @param string The keyword to add the URL HTML to |
|
2018 * @param int What group the keyword is from |
|
2019 * @param boolean Whether to get the HTML for the start or end |
|
2020 * @return The HTML for either the start or end of the HTML <a> tag |
|
2021 * @since 1.0.2 |
|
2022 * @access private |
|
2023 * @todo Get rid of ender |
|
2024 */ |
|
2025 function add_url_to_keyword($keyword, $group, $start_or_end) { |
|
2026 if (!$this->keyword_links) { |
|
2027 // Keyword links have been disabled |
|
2028 return; |
|
2029 } |
|
2030 |
|
2031 if (isset($this->language_data['URLS'][$group]) && |
|
2032 $this->language_data['URLS'][$group] != '' && |
|
2033 substr($keyword, 0, 5) != '</') { |
|
2034 // There is a base group for this keyword |
|
2035 if ($start_or_end == 'BEGIN') { |
|
2036 // HTML workaround... not good form (tm) but should work for 1.0.X |
|
2037 if ($keyword != '') { |
|
2038 // Old system: strtolower |
|
2039 //$keyword = ( $this->language_data['CASE_SENSITIVE'][$group] ) ? $keyword : strtolower($keyword); |
|
2040 // New system: get keyword from language file to get correct case |
|
2041 foreach ($this->language_data['KEYWORDS'][$group] as $word) { |
|
2042 if (strtolower($word) == strtolower($keyword)) { |
|
2043 break; |
|
2044 } |
|
2045 } |
|
2046 $word = ( substr($word, 0, 4) == '<' ) ? substr($word, 4) : $word; |
|
2047 $word = ( substr($word, -4) == '>' ) ? substr($word, 0, strlen($word) - 4) : $word; |
|
2048 if (!$word) return ''; |
|
2049 |
|
2050 return '<|UR1|"' . |
|
2051 str_replace( |
|
2052 array('{FNAME}', '.'), |
|
2053 array(GeSHi::hsc($word), '<DOT>'), |
|
2054 $this->language_data['URLS'][$group] |
|
2055 ) . '">'; |
|
2056 } |
|
2057 return ''; |
|
2058 // HTML fix. Again, dirty hackage... |
|
2059 } |
|
2060 else if (!($this->language == 'html4strict' && ('>' == $keyword || '<' == $keyword))) { |
|
2061 return '</a>'; |
|
2062 } |
|
2063 } |
|
2064 } |
|
2065 |
|
2066 /** |
|
2067 * Takes a string that has no strings or comments in it, and highlights |
|
2068 * stuff like keywords, numbers and methods. |
|
2069 * |
|
2070 * @param string The string to parse for keyword, numbers etc. |
|
2071 * @since 1.0.0 |
|
2072 * @access private |
|
2073 * @todo BUGGY! Why? Why not build string and return? |
|
2074 */ |
|
2075 function parse_non_string_part(&$stuff_to_parse) { |
|
2076 $stuff_to_parse = ' ' . GeSHi::hsc($stuff_to_parse); |
|
2077 $stuff_to_parse_pregquote = preg_quote($stuff_to_parse, '/'); |
|
2078 $func = '$this->change_case'; |
|
2079 $func2 = '$this->add_url_to_keyword'; |
|
2080 |
|
2081 // |
|
2082 // Regular expressions |
|
2083 // |
|
2084 foreach ($this->language_data['REGEXPS'] as $key => $regexp) { |
|
2085 if ($this->lexic_permissions['REGEXPS'][$key]) { |
|
2086 if (is_array($regexp)) { |
|
2087 $stuff_to_parse = preg_replace( |
|
2088 "/" . |
|
2089 str_replace('/', '\/', $regexp[GESHI_SEARCH]) . |
|
2090 "/{$regexp[GESHI_MODIFIERS]}", |
|
2091 "{$regexp[GESHI_BEFORE]}<|!REG3XP$key!>{$regexp[GESHI_REPLACE]}|>{$regexp[GESHI_AFTER]}", |
|
2092 $stuff_to_parse |
|
2093 ); |
|
2094 } |
|
2095 else { |
|
2096 $stuff_to_parse = preg_replace( "/(" . str_replace('/', '\/', $regexp) . ")/", "<|!REG3XP$key!>\\1|>", $stuff_to_parse); |
|
2097 } |
|
2098 } |
|
2099 } |
|
2100 |
|
2101 // |
|
2102 // Highlight numbers. This regexp sucks... anyone with a regexp that WORKS |
|
2103 // here wins a cookie if they send it to me. At the moment there's two doing |
|
2104 // almost exactly the same thing, except the second one prevents a number |
|
2105 // being highlighted twice (eg <span...><span...>5</span></span>) |
|
2106 // Put /NUM!/ in for the styles, which gets replaced at the end. |
|
2107 // |
|
2108 // NEW ONE: Brice Bernard |
|
2109 // |
|
2110 if ($this->lexic_permissions['NUMBERS'] && preg_match('#[0-9]#', $stuff_to_parse )) { |
|
2111 $stuff_to_parse = preg_replace('/([-+]?\\b(?:[0-9]*\\.)?[0-9]+\\b)/', '<|/NUM!/>\\1|>', $stuff_to_parse); |
|
2112 } |
|
2113 |
|
2114 // Highlight keywords |
|
2115 // if there is a couple of alpha symbols there *might* be a keyword |
|
2116 if (preg_match('#[a-zA-Z]{2,}#', $stuff_to_parse)) { |
|
2117 foreach ($this->language_data['KEYWORDS'] as $k => $keywordset) { |
|
2118 if ($this->lexic_permissions['KEYWORDS'][$k]) { |
|
2119 foreach ($keywordset as $keyword) { |
|
2120 $keyword = preg_quote($keyword, '/'); |
|
2121 // |
|
2122 // This replacement checks the word is on it's own (except if brackets etc |
|
2123 // are next to it), then highlights it. We don't put the color=" for the span |
|
2124 // in just yet - otherwise languages with the keywords "color" or "or" have |
|
2125 // a fit. |
|
2126 // |
|
2127 if (false !== stristr($stuff_to_parse_pregquote, $keyword )) { |
|
2128 $stuff_to_parse .= ' '; |
|
2129 // Might make a more unique string for putting the number in soon |
|
2130 // Basically, we don't put the styles in yet because then the styles themselves will |
|
2131 // get highlighted if the language has a CSS keyword in it (like CSS, for example ;)) |
|
2132 $styles = "/$k/"; |
|
2133 if ($this->language_data['CASE_SENSITIVE'][$k]) { |
|
2134 $stuff_to_parse = preg_replace( |
|
2135 "/([^a-zA-Z0-9\$_\|\#;>|^])($keyword)(?=[^a-zA-Z0-9_<\|%\-&])/e", |
|
2136 "'\\1' . $func2('\\2', '$k', 'BEGIN') . '<|$styles>' . $func('\\2') . '|>' . $func2('\\2', '$k', 'END')", |
|
2137 $stuff_to_parse |
|
2138 ); |
|
2139 } |
|
2140 else { |
|
2141 // Change the case of the word. |
|
2142 // hackage again... must... release... 1.2... |
|
2143 if ('smarty' == $this->language) { $hackage = '\/'; } else { $hackage = ''; } |
|
2144 $stuff_to_parse = preg_replace( |
|
2145 "/([^a-zA-Z0-9\$_\|\#;>$hackage|^])($keyword)(?=[^a-zA-Z0-9_<\|%\-&])/ie", |
|
2146 "'\\1' . $func2('\\2', '$k', 'BEGIN') . '<|$styles>' . $func('\\2') . '|>' . $func2('\\2', '$k', 'END')", |
|
2147 $stuff_to_parse |
|
2148 ); |
|
2149 } |
|
2150 $stuff_to_parse = substr($stuff_to_parse, 0, strlen($stuff_to_parse) - 1); |
|
2151 } |
|
2152 } |
|
2153 } |
|
2154 } |
|
2155 } |
|
2156 |
|
2157 // |
|
2158 // Now that's all done, replace /[number]/ with the correct styles |
|
2159 // |
|
2160 foreach ($this->language_data['KEYWORDS'] as $k => $kws) { |
|
2161 if (!$this->use_classes) { |
|
2162 $attributes = ' style="' . $this->language_data['STYLES']['KEYWORDS'][$k] . '"'; |
|
2163 } |
|
2164 else { |
|
2165 $attributes = ' class="kw' . $k . '"'; |
|
2166 } |
|
2167 $stuff_to_parse = str_replace("/$k/", $attributes, $stuff_to_parse); |
|
2168 } |
|
2169 |
|
2170 // Put number styles in |
|
2171 if (!$this->use_classes && $this->lexic_permissions['NUMBERS']) { |
|
2172 $attributes = ' style="' . $this->language_data['STYLES']['NUMBERS'][0] . '"'; |
|
2173 } |
|
2174 else { |
|
2175 $attributes = ' class="nu0"'; |
|
2176 } |
|
2177 $stuff_to_parse = str_replace('/NUM!/', $attributes, $stuff_to_parse); |
|
2178 |
|
2179 // |
|
2180 // Highlight methods and fields in objects |
|
2181 // |
|
2182 if ($this->lexic_permissions['METHODS'] && $this->language_data['OOLANG']) { |
|
2183 foreach ($this->language_data['OBJECT_SPLITTERS'] as $key => $splitter) { |
|
2184 if (false !== stristr($stuff_to_parse, $splitter)) { |
|
2185 if (!$this->use_classes) { |
|
2186 $attributes = ' style="' . $this->language_data['STYLES']['METHODS'][$key] . '"'; |
|
2187 } |
|
2188 else { |
|
2189 $attributes = ' class="me' . $key . '"'; |
|
2190 } |
|
2191 $stuff_to_parse = preg_replace("/(" . preg_quote($this->language_data['OBJECT_SPLITTERS'][$key], 1) . "[\s]*)([a-zA-Z\*\(][a-zA-Z0-9_\*]*)/", "\\1<|$attributes>\\2|>", $stuff_to_parse); |
|
2192 } |
|
2193 } |
|
2194 } |
|
2195 |
|
2196 // |
|
2197 // Highlight brackets. Yes, I've tried adding a semi-colon to this list. |
|
2198 // You try it, and see what happens ;) |
|
2199 // TODO: Fix lexic permissions not converting entities if shouldn't |
|
2200 // be highlighting regardless |
|
2201 // |
|
2202 if ($this->lexic_permissions['BRACKETS']) { |
|
2203 $code_entities_match = array('[', ']', '(', ')', '{', '}'); |
|
2204 if (!$this->use_classes) { |
|
2205 $code_entities_replace = array( |
|
2206 '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">[|>', |
|
2207 '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">]|>', |
|
2208 '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">(|>', |
|
2209 '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">)|>', |
|
2210 '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">{|>', |
|
2211 '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">}|>', |
|
2212 ); |
|
2213 } |
|
2214 else { |
|
2215 $code_entities_replace = array( |
|
2216 '<| class="br0">[|>', |
|
2217 '<| class="br0">]|>', |
|
2218 '<| class="br0">(|>', |
|
2219 '<| class="br0">)|>', |
|
2220 '<| class="br0">{|>', |
|
2221 '<| class="br0">}|>', |
|
2222 ); |
|
2223 } |
|
2224 $stuff_to_parse = str_replace( $code_entities_match, $code_entities_replace, $stuff_to_parse ); |
|
2225 } |
|
2226 |
|
2227 // |
|
2228 // Add class/style for regexps |
|
2229 // |
|
2230 foreach ($this->language_data['REGEXPS'] as $key => $regexp) { |
|
2231 if ($this->lexic_permissions['REGEXPS'][$key]) { |
|
2232 if (!$this->use_classes) { |
|
2233 $attributes = ' style="' . $this->language_data['STYLES']['REGEXPS'][$key] . '"'; |
|
2234 } |
|
2235 else { |
|
2236 if(is_array($this->language_data['REGEXPS'][$key]) && |
|
2237 array_key_exists(GESHI_CLASS, $this->language_data['REGEXPS'][$key])) { |
|
2238 $attributes = ' class="' |
|
2239 . $this->language_data['REGEXPS'][$key][GESHI_CLASS] . '"'; |
|
2240 } |
|
2241 else { |
|
2242 $attributes = ' class="re' . $key . '"'; |
|
2243 } |
|
2244 } |
|
2245 $stuff_to_parse = str_replace("!REG3XP$key!", "$attributes", $stuff_to_parse); |
|
2246 } |
|
2247 } |
|
2248 |
|
2249 // Replace <DOT> with . for urls |
|
2250 $stuff_to_parse = str_replace('<DOT>', '.', $stuff_to_parse); |
|
2251 // Replace <|UR1| with <a href= for urls also |
|
2252 if (isset($this->link_styles[GESHI_LINK])) { |
|
2253 if ($this->use_classes) { |
|
2254 $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse); |
|
2255 } |
|
2256 else { |
|
2257 $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' style="' . $this->link_styles[GESHI_LINK] . '" href=', $stuff_to_parse); |
|
2258 } |
|
2259 } |
|
2260 else { |
|
2261 $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse); |
|
2262 } |
|
2263 |
|
2264 // |
|
2265 // NOW we add the span thingy ;) |
|
2266 // |
|
2267 |
|
2268 $stuff_to_parse = str_replace('<|', '<span', $stuff_to_parse); |
|
2269 $stuff_to_parse = str_replace ( '|>', '</span>', $stuff_to_parse ); |
|
2270 |
|
2271 return substr($stuff_to_parse, 1); |
|
2272 } |
|
2273 |
|
2274 /** |
|
2275 * Sets the time taken to parse the code |
|
2276 * |
|
2277 * @param microtime The time when parsing started |
|
2278 * @param microtime The time when parsing ended |
|
2279 * @since 1.0.2 |
|
2280 * @access private |
|
2281 */ |
|
2282 function set_time($start_time, $end_time) { |
|
2283 $start = explode(' ', $start_time); |
|
2284 $end = explode(' ', $end_time); |
|
2285 $this->time = $end[0] + $end[1] - $start[0] - $start[1]; |
|
2286 } |
|
2287 |
|
2288 /** |
|
2289 * Gets the time taken to parse the code |
|
2290 * |
|
2291 * @return double The time taken to parse the code |
|
2292 * @since 1.0.2 |
|
2293 */ |
|
2294 function get_time() { |
|
2295 return $this->time; |
|
2296 } |
|
2297 |
|
2298 /** |
|
2299 * Gets language information and stores it for later use |
|
2300 * |
|
2301 * @access private |
|
2302 * @todo Needs to load keys for lexic permissions for keywords, regexps etc |
|
2303 */ |
|
2304 function load_language($file_name) { |
|
2305 $this->enable_highlighting(); |
|
2306 $language_data = array(); |
|
2307 require $file_name; |
|
2308 // Perhaps some checking might be added here later to check that |
|
2309 // $language data is a valid thing but maybe not |
|
2310 $this->language_data = $language_data; |
|
2311 // Set strict mode if should be set |
|
2312 if ($this->language_data['STRICT_MODE_APPLIES'] == GESHI_ALWAYS) { |
|
2313 $this->strict_mode = true; |
|
2314 } |
|
2315 // Set permissions for all lexics to true |
|
2316 // so they'll be highlighted by default |
|
2317 foreach ($this->language_data['KEYWORDS'] as $key => $words) { |
|
2318 $this->lexic_permissions['KEYWORDS'][$key] = true; |
|
2319 } |
|
2320 foreach ($this->language_data['COMMENT_SINGLE'] as $key => $comment) { |
|
2321 $this->lexic_permissions['COMMENTS'][$key] = true; |
|
2322 } |
|
2323 foreach ($this->language_data['REGEXPS'] as $key => $regexp) { |
|
2324 $this->lexic_permissions['REGEXPS'][$key] = true; |
|
2325 } |
|
2326 // Set default class for CSS |
|
2327 $this->overall_class = $this->language; |
|
2328 } |
|
2329 |
|
2330 /** |
|
2331 * Takes the parsed code and various options, and creates the HTML |
|
2332 * surrounding it to make it look nice. |
|
2333 * |
|
2334 * @param string The code already parsed |
|
2335 * @return string The code nicely finalised |
|
2336 * @since 1.0.0 |
|
2337 * @access private |
|
2338 */ |
|
2339 function finalise($parsed_code) { |
|
2340 // Remove end parts of important declarations |
|
2341 // This is BUGGY!! My fault for bad code: fix coming in 1.2 |
|
2342 // @todo Remove this crap |
|
2343 if ($this->enable_important_blocks && |
|
2344 (strstr($parsed_code, GeSHi::hsc(GESHI_START_IMPORTANT)) === false)) { |
|
2345 $parsed_code = str_replace(GeSHi::hsc(GESHI_END_IMPORTANT), '', $parsed_code); |
|
2346 } |
|
2347 |
|
2348 // Add HTML whitespace stuff if we're using the <div> header |
|
2349 if ($this->header_type != GESHI_HEADER_PRE) { |
|
2350 $parsed_code = $this->indent($parsed_code); |
|
2351 } |
|
2352 |
|
2353 // purge some unnecessary stuff |
|
2354 $parsed_code = preg_replace('#<span[^>]+>(\s*)</span>#', '\\1', $parsed_code); |
|
2355 $parsed_code = preg_replace('#<div[^>]+>(\s*)</div>#', '\\1', $parsed_code); |
|
2356 |
|
2357 // If we are using IDs for line numbers, there needs to be an overall |
|
2358 // ID set to prevent collisions. |
|
2359 if ($this->add_ids && !$this->overall_id) { |
|
2360 $this->overall_id = 'geshi-' . substr(md5(microtime()), 0, 4); |
|
2361 } |
|
2362 |
|
2363 // If we're using line numbers, we insert <li>s and appropriate |
|
2364 // markup to style them (otherwise we don't need to do anything) |
|
2365 if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { |
|
2366 // If we're using the <pre> header, we shouldn't add newlines because |
|
2367 // the <pre> will line-break them (and the <li>s already do this for us) |
|
2368 $ls = ($this->header_type != GESHI_HEADER_PRE) ? "\n" : ''; |
|
2369 // Get code into lines |
|
2370 $code = explode("\n", $parsed_code); |
|
2371 // Set vars to defaults for following loop |
|
2372 $parsed_code = ''; |
|
2373 $i = 0; |
|
2374 $attrs = array(); |
|
2375 |
|
2376 // Foreach line... |
|
2377 foreach ($code as $line) { |
|
2378 // Make lines have at least one space in them if they're empty |
|
2379 // BenBE: Checking emptiness using trim instead of relying on blanks |
|
2380 if ('' == trim($line)) { |
|
2381 $line = ' '; |
|
2382 } |
|
2383 // If this is a "special line"... |
|
2384 if ($this->line_numbers == GESHI_FANCY_LINE_NUMBERS && |
|
2385 $i % $this->line_nth_row == ($this->line_nth_row - 1)) { |
|
2386 // Set the attributes to style the line |
|
2387 if ($this->use_classes) { |
|
2388 //$attr = ' class="li2"'; |
|
2389 $attrs['class'][] = 'li2'; |
|
2390 $def_attr = ' class="de2"'; |
|
2391 } |
|
2392 else { |
|
2393 //$attr = ' style="' . $this->line_style2 . '"'; |
|
2394 $attrs['style'][] = $this->line_style2; |
|
2395 // This style "covers up" the special styles set for special lines |
|
2396 // so that styles applied to special lines don't apply to the actual |
|
2397 // code on that line |
|
2398 $def_attr = ' style="' . $this->code_style . '"'; |
|
2399 } |
|
2400 // Span or div? |
|
2401 $start = "<div$def_attr>"; |
|
2402 $end = '</div>'; |
|
2403 } |
|
2404 else { |
|
2405 if ($this->use_classes) { |
|
2406 //$attr = ' class="li1"'; |
|
2407 $attrs['class'][] = 'li1'; |
|
2408 $def_attr = ' class="de1"'; |
|
2409 } |
|
2410 else { |
|
2411 //$attr = ' style="' . $this->line_style1 . '"'; |
|
2412 $attrs['style'][] = $this->line_style1; |
|
2413 $def_attr = ' style="' . $this->code_style . '"'; |
|
2414 } |
|
2415 $start = "<div$def_attr>"; |
|
2416 $end = '</div>'; |
|
2417 } |
|
2418 |
|
2419 ++$i; |
|
2420 // Are we supposed to use ids? If so, add them |
|
2421 if ($this->add_ids) { |
|
2422 $attrs['id'][] = "$this->overall_id-$i"; |
|
2423 } |
|
2424 if ($this->use_classes && in_array($i, $this->highlight_extra_lines)) { |
|
2425 $attrs['class'][] = 'ln-xtra'; |
|
2426 } |
|
2427 if (!$this->use_classes && in_array($i, $this->highlight_extra_lines)) { |
|
2428 $attrs['style'][] = $this->highlight_extra_lines_style; |
|
2429 } |
|
2430 |
|
2431 // Add in the line surrounded by appropriate list HTML |
|
2432 $attr_string = ' '; |
|
2433 foreach ($attrs as $key => $attr) { |
|
2434 $attr_string .= $key . '="' . implode(' ', $attr) . '" '; |
|
2435 } |
|
2436 $attr_string = substr($attr_string, 0, -1); |
|
2437 $parsed_code .= "<li$attr_string>$start$line$end</li>$ls"; |
|
2438 $attrs = array(); |
|
2439 } |
|
2440 } |
|
2441 else { |
|
2442 // No line numbers, but still need to handle highlighting lines extra. |
|
2443 // Have to use divs so the full width of the code is highlighted |
|
2444 $code = explode("\n", $parsed_code); |
|
2445 $parsed_code = ''; |
|
2446 $i = 0; |
|
2447 foreach ($code as $line) { |
|
2448 // Make lines have at least one space in them if they're empty |
|
2449 // BenBE: Checking emptiness using trim instead of relying on blanks |
|
2450 if ('' == trim($line)) { |
|
2451 $line = ' '; |
|
2452 } |
|
2453 if (in_array(++$i, $this->highlight_extra_lines)) { |
|
2454 if ($this->use_classes) { |
|
2455 $parsed_code .= '<div class="ln-xtra">'; |
|
2456 } |
|
2457 else { |
|
2458 $parsed_code .= "<div style=\"{$this->highlight_extra_lines_style}\">"; |
|
2459 } |
|
2460 // Remove \n because it stuffs up <pre> header |
|
2461 $parsed_code .= $line . "</div>"; |
|
2462 } |
|
2463 else { |
|
2464 $parsed_code .= $line . "\n"; |
|
2465 } |
|
2466 } |
|
2467 } |
|
2468 |
|
2469 if ($this->header_type == GESHI_HEADER_PRE) { |
|
2470 // enforce line numbers when using pre |
|
2471 $parsed_code = str_replace('<li></li>', '<li> </li>', $parsed_code); |
|
2472 } |
|
2473 |
|
2474 return $this->header() . chop($parsed_code) . $this->footer(); |
|
2475 } |
|
2476 |
|
2477 /** |
|
2478 * Creates the header for the code block (with correct attributes) |
|
2479 * |
|
2480 * @return string The header for the code block |
|
2481 * @since 1.0.0 |
|
2482 * @access private |
|
2483 */ |
|
2484 function header() { |
|
2485 // Get attributes needed |
|
2486 $attributes = $this->get_attributes(); |
|
2487 |
|
2488 $ol_attributes = ''; |
|
2489 |
|
2490 if ($this->line_numbers_start != 1) { |
|
2491 $ol_attributes .= ' start="' . $this->line_numbers_start . '"'; |
|
2492 } |
|
2493 |
|
2494 // Get the header HTML |
|
2495 $header = $this->format_header_content(); |
|
2496 |
|
2497 if (GESHI_HEADER_NONE == $this->header_type) { |
|
2498 if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { |
|
2499 return "$header<ol$ol_attributes>"; |
|
2500 } |
|
2501 return $header . |
|
2502 ($this->force_code_block ? '<div>' : ''); |
|
2503 } |
|
2504 |
|
2505 // Work out what to return and do it |
|
2506 if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { |
|
2507 if ($this->header_type == GESHI_HEADER_PRE) { |
|
2508 return "<pre$attributes>$header<ol$ol_attributes>"; |
|
2509 } |
|
2510 else if ($this->header_type == GESHI_HEADER_DIV) { |
|
2511 return "<div$attributes>$header<ol$ol_attributes>"; |
|
2512 } |
|
2513 } |
|
2514 else { |
|
2515 if ($this->header_type == GESHI_HEADER_PRE) { |
|
2516 return "<pre$attributes>$header" . |
|
2517 ($this->force_code_block ? '<div>' : ''); |
|
2518 } |
|
2519 else if ($this->header_type == GESHI_HEADER_DIV) { |
|
2520 return "<div$attributes>$header" . |
|
2521 ($this->force_code_block ? '<div>' : ''); |
|
2522 } |
|
2523 } |
|
2524 } |
|
2525 |
|
2526 /** |
|
2527 * Returns the header content, formatted for output |
|
2528 * |
|
2529 * @return string The header content, formatted for output |
|
2530 * @since 1.0.2 |
|
2531 * @access private |
|
2532 */ |
|
2533 function format_header_content() { |
|
2534 $header = $this->header_content; |
|
2535 if ($header) { |
|
2536 if ($this->header_type == GESHI_HEADER_PRE) { |
|
2537 $header = str_replace("\n", '', $header); |
|
2538 } |
|
2539 $header = $this->replace_keywords($header); |
|
2540 |
|
2541 if ($this->use_classes) { |
|
2542 $attr = ' class="head"'; |
|
2543 } |
|
2544 else { |
|
2545 $attr = " style=\"{$this->header_content_style}\""; |
|
2546 } |
|
2547 return "<div$attr>$header</div>"; |
|
2548 } |
|
2549 } |
|
2550 |
|
2551 /** |
|
2552 * Returns the footer for the code block. |
|
2553 * |
|
2554 * @return string The footer for the code block |
|
2555 * @since 1.0.0 |
|
2556 * @access private |
|
2557 */ |
|
2558 function footer() { |
|
2559 $footer_content = $this->format_footer_content(); |
|
2560 |
|
2561 if (GESHI_HEADER_NONE == $this->header_type) { |
|
2562 return ($this->line_numbers != GESHI_NO_LINE_NUMBERS) ? '</ol>' . $footer_content |
|
2563 : $footer_content; |
|
2564 } |
|
2565 |
|
2566 if ($this->header_type == GESHI_HEADER_DIV) { |
|
2567 if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { |
|
2568 return "</ol>$footer_content</div>"; |
|
2569 } |
|
2570 return ($this->force_code_block ? '</div>' : '') . |
|
2571 "$footer_content</div>"; |
|
2572 } |
|
2573 else { |
|
2574 if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) { |
|
2575 return "</ol>$footer_content</pre>"; |
|
2576 } |
|
2577 return ($this->force_code_block ? '</div>' : '') . |
|
2578 "$footer_content</pre>"; |
|
2579 } |
|
2580 } |
|
2581 |
|
2582 /** |
|
2583 * Returns the footer content, formatted for output |
|
2584 * |
|
2585 * @return string The footer content, formatted for output |
|
2586 * @since 1.0.2 |
|
2587 * @access private |
|
2588 */ |
|
2589 function format_footer_content() { |
|
2590 $footer = $this->footer_content; |
|
2591 if ($footer) { |
|
2592 if ($this->header_type == GESHI_HEADER_PRE) { |
|
2593 $footer = str_replace("\n", '', $footer);; |
|
2594 } |
|
2595 $footer = $this->replace_keywords($footer); |
|
2596 |
|
2597 if ($this->use_classes) { |
|
2598 $attr = ' class="foot"'; |
|
2599 } |
|
2600 else { |
|
2601 $attr = " style=\"{$this->footer_content_style}\""; |
|
2602 } |
|
2603 return "<div$attr>$footer</div>"; |
|
2604 } |
|
2605 } |
|
2606 |
|
2607 /** |
|
2608 * Replaces certain keywords in the header and footer with |
|
2609 * certain configuration values |
|
2610 * |
|
2611 * @param string The header or footer content to do replacement on |
|
2612 * @return string The header or footer with replaced keywords |
|
2613 * @since 1.0.2 |
|
2614 * @access private |
|
2615 */ |
|
2616 function replace_keywords($instr) { |
|
2617 $keywords = $replacements = array(); |
|
2618 |
|
2619 $keywords[] = '<TIME>'; |
|
2620 $keywords[] = '{TIME}'; |
|
2621 $replacements[] = $replacements[] = number_format($this->get_time(), 3); |
|
2622 |
|
2623 $keywords[] = '<LANGUAGE>'; |
|
2624 $keywords[] = '{LANGUAGE}'; |
|
2625 $replacements[] = $replacements[] = $this->language; |
|
2626 |
|
2627 $keywords[] = '<VERSION>'; |
|
2628 $keywords[] = '{VERSION}'; |
|
2629 $replacements[] = $replacements[] = GESHI_VERSION; |
|
2630 |
|
2631 return str_replace($keywords, $replacements, $instr); |
|
2632 } |
|
2633 |
|
2634 /** |
|
2635 * Gets the CSS attributes for this code |
|
2636 * |
|
2637 * @return The CSS attributes for this code |
|
2638 * @since 1.0.0 |
|
2639 * @access private |
|
2640 * @todo Document behaviour change - class is outputted regardless of whether we're using classes or not. |
|
2641 * Same with style |
|
2642 */ |
|
2643 function get_attributes() { |
|
2644 $attributes = ''; |
|
2645 |
|
2646 if ($this->overall_class != '') { |
|
2647 $attributes .= " class=\"{$this->overall_class}\""; |
|
2648 } |
|
2649 if ($this->overall_id != '') { |
|
2650 $attributes .= " id=\"{$this->overall_id}\""; |
|
2651 } |
|
2652 if ($this->overall_style != '') { |
|
2653 $attributes .= ' style="' . $this->overall_style . '"'; |
|
2654 } |
|
2655 return $attributes; |
|
2656 } |
|
2657 |
|
2658 /** |
|
2659 * Secure replacement for PHP built-in function htmlspecialchars(). |
|
2660 * |
|
2661 * See ticket #427 (http://wush.net/trac/wikka/ticket/427) for the rationale |
|
2662 * for this replacement function. |
|
2663 * |
|
2664 * The INTERFACE for this function is almost the same as that for |
|
2665 * htmlspecialchars(), with the same default for quote style; however, there |
|
2666 * is no 'charset' parameter. The reason for this is as follows: |
|
2667 * |
|
2668 * The PHP docs say: |
|
2669 * "The third argument charset defines character set used in conversion." |
|
2670 * |
|
2671 * I suspect PHP's htmlspecialchars() is working at the byte-value level and |
|
2672 * thus _needs_ to know (or asssume) a character set because the special |
|
2673 * characters to be replaced could exist at different code points in |
|
2674 * different character sets. (If indeed htmlspecialchars() works at |
|
2675 * byte-value level that goes some way towards explaining why the |
|
2676 * vulnerability would exist in this function, too, and not only in |
|
2677 * htmlentities() which certainly is working at byte-value level.) |
|
2678 * |
|
2679 * This replacement function however works at character level and should |
|
2680 * therefore be "immune" to character set differences - so no charset |
|
2681 * parameter is needed or provided. If a third parameter is passed, it will |
|
2682 * be silently ignored. |
|
2683 * |
|
2684 * In the OUTPUT there is a minor difference in that we use ''' instead |
|
2685 * of PHP's ''' for a single quote: this provides compatibility with |
|
2686 * get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES) |
|
2687 * (see comment by mikiwoz at yahoo dot co dot uk on |
|
2688 * http://php.net/htmlspecialchars); it also matches the entity definition |
|
2689 * for XML 1.0 |
|
2690 * (http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters). |
|
2691 * Like PHP we use a numeric character reference instead of ''' for the |
|
2692 * single quote. For the other special characters we use the named entity |
|
2693 * references, as PHP is doing. |
|
2694 * |
|
2695 * @author {@link http://wikkawiki.org/JavaWoman Marjolein Katsma} |
|
2696 * |
|
2697 * @license http://www.gnu.org/copyleft/lgpl.html |
|
2698 * GNU Lesser General Public License |
|
2699 * @copyright Copyright 2007, {@link http://wikkawiki.org/CreditsPage |
|
2700 * Wikka Development Team} |
|
2701 * |
|
2702 * @access public |
|
2703 * @param string $string string to be converted |
|
2704 * @param integer $quote_style |
|
2705 * - ENT_COMPAT: escapes &, <, > and double quote (default) |
|
2706 * - ENT_NOQUOTES: escapes only &, < and > |
|
2707 * - ENT_QUOTES: escapes &, <, >, double and single quotes |
|
2708 * @return string converted string |
|
2709 */ |
|
2710 function hsc($string, $quote_style=ENT_COMPAT) { |
|
2711 // init |
|
2712 $aTransSpecchar = array( |
|
2713 '&' => '&', |
|
2714 '"' => '"', |
|
2715 '<' => '<', |
|
2716 '>' => '>' |
|
2717 ); // ENT_COMPAT set |
|
2718 |
|
2719 if (ENT_NOQUOTES == $quote_style) // don't convert double quotes |
|
2720 { |
|
2721 unset($aTransSpecchar['"']); |
|
2722 } |
|
2723 elseif (ENT_QUOTES == $quote_style) // convert single quotes as well |
|
2724 { |
|
2725 $aTransSpecchar["'"] = '''; // (apos) htmlspecialchars() uses ''' |
|
2726 } |
|
2727 |
|
2728 // return translated string |
|
2729 return strtr($string,$aTransSpecchar); |
|
2730 } |
|
2731 |
|
2732 /** |
|
2733 * Returns a stylesheet for the highlighted code. If $economy mode |
|
2734 * is true, we only return the stylesheet declarations that matter for |
|
2735 * this code block instead of the whole thing |
|
2736 * |
|
2737 * @param boolean Whether to use economy mode or not |
|
2738 * @return string A stylesheet built on the data for the current language |
|
2739 * @since 1.0.0 |
|
2740 */ |
|
2741 function get_stylesheet($economy_mode = true) { |
|
2742 // If there's an error, chances are that the language file |
|
2743 // won't have populated the language data file, so we can't |
|
2744 // risk getting a stylesheet... |
|
2745 if ($this->error) { |
|
2746 return ''; |
|
2747 } |
|
2748 // First, work out what the selector should be. If there's an ID, |
|
2749 // that should be used, the same for a class. Otherwise, a selector |
|
2750 // of '' means that these styles will be applied anywhere |
|
2751 $selector = ($this->overall_id != '') ? "#{$this->overall_id} " : ''; |
|
2752 $selector = ($selector == '' && $this->overall_class != '') ? ".{$this->overall_class} " : $selector; |
|
2753 |
|
2754 // Header of the stylesheet |
|
2755 if (!$economy_mode) { |
|
2756 $stylesheet = "/**\n * GeSHi Dynamically Generated Stylesheet\n * --------------------------------------\n * Dynamically generated stylesheet for {$this->language}\n * CSS class: {$this->overall_class}, CSS id: {$this->overall_id}\n * GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter)\n */\n"; |
|
2757 } else { |
|
2758 $stylesheet = '/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */' . "\n"; |
|
2759 } |
|
2760 |
|
2761 // Set the <ol> to have no effect at all if there are line numbers |
|
2762 // (<ol>s have margins that should be destroyed so all layout is |
|
2763 // controlled by the set_overall_style method, which works on the |
|
2764 // <pre> or <div> container). Additionally, set default styles for lines |
|
2765 if (!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) { |
|
2766 //$stylesheet .= "$selector, {$selector}ol, {$selector}ol li {margin: 0;}\n"; |
|
2767 $stylesheet .= "$selector.de1, $selector.de2 {{$this->code_style}}\n"; |
|
2768 } |
|
2769 |
|
2770 // Add overall styles |
|
2771 if (!$economy_mode || $this->overall_style != '') { |
|
2772 $stylesheet .= "$selector {{$this->overall_style}}\n"; |
|
2773 } |
|
2774 |
|
2775 // Add styles for links |
|
2776 foreach ($this->link_styles as $key => $style) { |
|
2777 if (!$economy_mode || $key == GESHI_LINK && $style != '') { |
|
2778 $stylesheet .= "{$selector}a:link {{$style}}\n"; |
|
2779 } |
|
2780 if (!$economy_mode || $key == GESHI_HOVER && $style != '') { |
|
2781 $stylesheet .= "{$selector}a:hover {{$style}}\n"; |
|
2782 } |
|
2783 if (!$economy_mode || $key == GESHI_ACTIVE && $style != '') { |
|
2784 $stylesheet .= "{$selector}a:active {{$style}}\n"; |
|
2785 } |
|
2786 if (!$economy_mode || $key == GESHI_VISITED && $style != '') { |
|
2787 $stylesheet .= "{$selector}a:visited {{$style}}\n"; |
|
2788 } |
|
2789 } |
|
2790 |
|
2791 // Header and footer |
|
2792 if (!$economy_mode || $this->header_content_style != '') { |
|
2793 $stylesheet .= "$selector.head {{$this->header_content_style}}\n"; |
|
2794 } |
|
2795 if (!$economy_mode || $this->footer_content_style != '') { |
|
2796 $stylesheet .= "$selector.foot {{$this->footer_content_style}}\n"; |
|
2797 } |
|
2798 |
|
2799 // Styles for important stuff |
|
2800 if (!$economy_mode || $this->important_styles != '') { |
|
2801 $stylesheet .= "$selector.imp {{$this->important_styles}}\n"; |
|
2802 } |
|
2803 |
|
2804 // Styles for lines being highlighted extra |
|
2805 if (!$economy_mode || count($this->highlight_extra_lines)) { |
|
2806 $stylesheet .= "$selector.ln-xtra {{$this->highlight_extra_lines_style}}\n"; |
|
2807 } |
|
2808 |
|
2809 // Simple line number styles |
|
2810 if (!$economy_mode || ($this->line_numbers != GESHI_NO_LINE_NUMBERS && $this->line_style1 != '')) { |
|
2811 $stylesheet .= "{$selector}li {{$this->line_style1}}\n"; |
|
2812 } |
|
2813 |
|
2814 // If there is a style set for fancy line numbers, echo it out |
|
2815 if (!$economy_mode || ($this->line_numbers == GESHI_FANCY_LINE_NUMBERS && $this->line_style2 != '')) { |
|
2816 $stylesheet .= "{$selector}li.li2 {{$this->line_style2}}\n"; |
|
2817 } |
|
2818 |
|
2819 foreach ($this->language_data['STYLES']['KEYWORDS'] as $group => $styles) { |
|
2820 if (!$economy_mode || !($economy_mode && (!$this->lexic_permissions['KEYWORDS'][$group] || $styles == ''))) { |
|
2821 $stylesheet .= "$selector.kw$group {{$styles}}\n"; |
|
2822 } |
|
2823 } |
|
2824 foreach ($this->language_data['STYLES']['COMMENTS'] as $group => $styles) { |
|
2825 if (!$economy_mode || !($economy_mode && $styles == '') && |
|
2826 !($economy_mode && !$this->lexic_permissions['COMMENTS'][$group])) { |
|
2827 $stylesheet .= "$selector.co$group {{$styles}}\n"; |
|
2828 } |
|
2829 } |
|
2830 foreach ($this->language_data['STYLES']['ESCAPE_CHAR'] as $group => $styles) { |
|
2831 if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode && |
|
2832 !$this->lexic_permissions['ESCAPE_CHAR'])) { |
|
2833 $stylesheet .= "$selector.es$group {{$styles}}\n"; |
|
2834 } |
|
2835 } |
|
2836 foreach ($this->language_data['STYLES']['SYMBOLS'] as $group => $styles) { |
|
2837 if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode && |
|
2838 !$this->lexic_permissions['BRACKETS'])) { |
|
2839 $stylesheet .= "$selector.br$group {{$styles}}\n"; |
|
2840 } |
|
2841 } |
|
2842 foreach ($this->language_data['STYLES']['STRINGS'] as $group => $styles) { |
|
2843 if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode && |
|
2844 !$this->lexic_permissions['STRINGS'])) { |
|
2845 $stylesheet .= "$selector.st$group {{$styles}}\n"; |
|
2846 } |
|
2847 } |
|
2848 foreach ($this->language_data['STYLES']['NUMBERS'] as $group => $styles) { |
|
2849 if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode && |
|
2850 !$this->lexic_permissions['NUMBERS'])) { |
|
2851 $stylesheet .= "$selector.nu$group {{$styles}}\n"; |
|
2852 } |
|
2853 } |
|
2854 foreach ($this->language_data['STYLES']['METHODS'] as $group => $styles) { |
|
2855 if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode && |
|
2856 !$this->lexic_permissions['METHODS'])) { |
|
2857 $stylesheet .= "$selector.me$group {{$styles}}\n"; |
|
2858 } |
|
2859 } |
|
2860 foreach ($this->language_data['STYLES']['SCRIPT'] as $group => $styles) { |
|
2861 if (!$economy_mode || !($economy_mode && $styles == '')) { |
|
2862 $stylesheet .= "$selector.sc$group {{$styles}}\n"; |
|
2863 } |
|
2864 } |
|
2865 foreach ($this->language_data['STYLES']['REGEXPS'] as $group => $styles) { |
|
2866 if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode && |
|
2867 !$this->lexic_permissions['REGEXPS'][$group])) { |
|
2868 if (is_array($this->language_data['REGEXPS'][$group]) && |
|
2869 array_key_exists(GESHI_CLASS, |
|
2870 $this->language_data['REGEXPS'][$group])) { |
|
2871 $stylesheet .= "$selector."; |
|
2872 $stylesheet .= $this->language_data['REGEXPS'][$group][GESHI_CLASS]; |
|
2873 $stylesheet .= " {{$styles}}\n"; |
|
2874 } |
|
2875 else { |
|
2876 $stylesheet .= "$selector.re$group {{$styles}}\n"; |
|
2877 } |
|
2878 } |
|
2879 } |
|
2880 |
|
2881 return $stylesheet; |
|
2882 } |
|
2883 |
|
2884 } // End Class GeSHi |
|
2885 |
|
2886 |
|
2887 if (!function_exists('geshi_highlight')) { |
|
2888 /** |
|
2889 * Easy way to highlight stuff. Behaves just like highlight_string |
|
2890 * |
|
2891 * @param string The code to highlight |
|
2892 * @param string The language to highlight the code in |
|
2893 * @param string The path to the language files. You can leave this blank if you need |
|
2894 * as from version 1.0.7 the path should be automatically detected |
|
2895 * @param boolean Whether to return the result or to echo |
|
2896 * @return string The code highlighted (if $return is true) |
|
2897 * @since 1.0.2 |
|
2898 */ |
|
2899 function geshi_highlight($string, $language, $path = null, $return = false) { |
|
2900 $geshi = new GeSHi($string, $language, $path); |
|
2901 $geshi->set_header_type(GESHI_HEADER_NONE); |
|
2902 if ($return) { |
|
2903 return '<code>' . $geshi->parse_code() . '</code>'; |
|
2904 } |
|
2905 echo '<code>' . $geshi->parse_code() . '</code>'; |
|
2906 if ($geshi->error()) { |
|
2907 return false; |
|
2908 } |
|
2909 return true; |
|
2910 } |
|
2911 } |
|
2912 |
|
2913 ?> |