root/trunk/lib/geshi.php

Revision 2, 86.5 kB (checked in by fabien, 3 years ago)

initial import

  • Property svn:mime-type set to text/x-php
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2 /**
3  * GeSHi - Generic Syntax Highlighter
4  *
5  * The GeSHi class for Generic Syntax Highlighting. Please refer to the documentation
6  * at http://qbnz.com/highlighter/documentation.php for more information about how to
7  * use this class.
8  *
9  * For changes, release notes, TODOs etc, see the relevant files in the docs/ directory
10  *
11  *   This file is part of GeSHi.
12  *
13  *  GeSHi is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or
16  *  (at your option) any later version.
17  *
18  *  GeSHi is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with GeSHi; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * @package   core
28  * @author    Nigel McNie <nigel@geshi.org>
29  * @copyright Copyright &copy; 2004, 2005, Nigel McNie
30  * @license   http://gnu.org/copyleft/gpl.html GNU GPL
31  * @version   $Id$
32  *
33  */
34
35 //
36 // GeSHi Constants
37 // You should use these constant names in your programs instead of
38 // their values - you never know when a value may change in a future
39 // version
40 //
41
42 /** The version of this GeSHi file */
43 define('GESHI_VERSION', '1.0.7.5');
44
45 /** For the future (though this may never be realised) */
46 define('GESHI_OUTPUT_HTML', 0);
47
48 /** Set the correct directory separator */
49 define('GESHI_DIR_SEPARATOR', ('WIN' != substr(PHP_OS, 0, 3)) ? '/' : '\\');
50
51 // Define the root directory for the GeSHi code tree
52 if (!defined('GESHI_ROOT')) {
53     /** The root directory for GeSHi */
54     define('GESHI_ROOT', dirname(__FILE__) . GESHI_DIR_SEPARATOR);
55 }
56 /** The language file directory for GeSHi
57     @access private */
58 define('GESHI_LANG_ROOT', GESHI_ROOT . 'geshi' . GESHI_DIR_SEPARATOR);
59
60
61 // Line numbers - use with enable_line_numbers()
62 /** Use no line numbers when building the result */
63 define('GESHI_NO_LINE_NUMBERS', 0);
64 /** Use normal line numbers when building the result */
65 define('GESHI_NORMAL_LINE_NUMBERS', 1);
66 /** Use fancy line numbers when building the result */
67 define('GESHI_FANCY_LINE_NUMBERS', 2);
68
69 // Container HTML type
70 /** Use nothing to surround the source */
71 define('GESHI_HEADER_NONE', 0);
72 /** Use a "div" to surround the source */
73 define('GESHI_HEADER_DIV', 1);
74 /** Use a "pre" to surround the source */
75 define('GESHI_HEADER_PRE', 2);
76
77 // Capatalisation constants
78 /** Lowercase keywords found */
79 define('GESHI_CAPS_NO_CHANGE', 0);
80 /** Uppercase keywords found */
81 define('GESHI_CAPS_UPPER', 1);
82 /** Leave keywords found as the case that they are */
83 define('GESHI_CAPS_LOWER', 2);
84
85 // Link style constants
86 /** Links in the source in the :link state */
87 define('GESHI_LINK', 0);
88 /** Links in the source in the :hover state */
89 define('GESHI_HOVER', 1);
90 /** Links in the source in the :active state */
91 define('GESHI_ACTIVE', 2);
92 /** Links in the source in the :visited state */
93 define('GESHI_VISITED', 3);
94
95 // Important string starter/finisher
96 // Note that if you change these, they should be as-is: i.e., don't
97 // write them as if they had been run through htmlentities()
98 /** The starter for important parts of the source */
99 define('GESHI_START_IMPORTANT', '<BEGIN GeSHi>');
100 /** The ender for important parts of the source */
101 define('GESHI_END_IMPORTANT', '<END GeSHi>');
102
103 /**#@+
104  *  @access private
105  */
106 // When strict mode applies for a language
107 /** Strict mode never applies (this is the most common) */
108 define('GESHI_NEVER', 0);
109 /** Strict mode *might* apply, and can be enabled or
110     disabled by {@link GeSHi::enable_strict_mode()} */
111 define('GESHI_MAYBE', 1);
112 /** Strict mode always applies */
113 define('GESHI_ALWAYS', 2);
114
115 // Advanced regexp handling constants, used in language files
116 /** The key of the regex array defining what to search for */
117 define('GESHI_SEARCH', 0);
118 /** The key of the regex array defining what bracket group in a
119     matched search to use as a replacement */
120 define('GESHI_REPLACE', 1);
121 /** The key of the regex array defining any modifiers to the regular expression */
122 define('GESHI_MODIFIERS', 2);
123 /** The key of the regex array defining what bracket group in a
124     matched search to put before the replacement */
125 define('GESHI_BEFORE', 3);
126 /** The key of the regex array defining what bracket group in a
127     matched search to put after the replacement */
128 define('GESHI_AFTER', 4);
129
130 /** Used in language files to mark comments */
131 define('GESHI_COMMENTS', 0);
132
133 // Error detection - use these to analyse faults
134 /** No sourcecode to highlight was specified */
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   core
155  * @author    Nigel McNie <nigel@geshi.org>
156  * @copyright Copyright &copy; 2004, 2005 Nigel McNie
157  */
158 class GeSHi
159 {
160     /**#@+
161      * @access private
162      */
163     /**
164      * The source code to highlight
165      * @var string
166      */
167     var $source = '';
168     
169     /**
170      * The language to use when highlighting
171      * @var string
172      */
173     var $language = '';
174     
175     /**
176      * The data for the language used
177      * @var array
178      */
179     var $language_data = array();
180     
181     /**
182      * The path to the language files
183      * @var string
184      */
185     var $language_path = GESHI_LANG_ROOT;
186     
187     /**
188      * The error message associated with an error
189      * @var string
190      * @todo check err reporting works
191      */
192     var $error = false;
193     
194     /**
195      * Possible error messages
196      * @var array
197      */
198     var $error_messages = array(
199         GESHI_ERROR_NO_INPUT => 'No source code inputted',
200         GESHI_ERROR_NO_SUCH_LANG => 'GeSHi could not find the language {LANGUAGE} (using path {PATH})',
201         GESHI_ERROR_FILE_NOT_READABLE => 'The file specified for load_from_file was not readable',
202         GESHI_ERROR_INVALID_HEADER_TYPE => 'The header type specified is invalid',
203         GESHI_ERROR_INVALID_LINE_NUMBER_TYPE => 'The line number type specified is invalid'
204     );
205     
206     /**
207      * Whether highlighting is strict or not
208      * @var boolean
209      */
210     var $strict_mode = false;
211     
212     /**
213      * Whether to use CSS classes in output
214      * @var boolean
215      */
216     var $use_classes = false;
217     
218     /**
219      * The type of header to use. Can be one of the following
220      * values:
221      *
222      * <ul>
223      *   <li><b>GESHI_HEADER_PRE</b>: Source is outputted in
224      *   a &lt;pre&gt; HTML element.</li>
225      *   <li><b>GESHI_HEADER_DIV</b>: Source is outputted in
226      *   a &lt;div&gt; HTML element.</li>
227      * </ul>
228      *
229      * @var int
230      */
231     var $header_type = GESHI_HEADER_PRE;
232     
233     /**
234      * Array of permissions for which lexics should be highlighted
235      * @var array
236      */
237     var $lexic_permissions = array(
238         'KEYWORDS' =>    array(),
239         'COMMENTS' =>    array('MULTI' => true),
240         'REGEXPS' =>     array(),
241         'ESCAPE_CHAR' => true,
242         'BRACKETS' =>    true,
243         'SYMBOLS' =>     true,
244         'STRINGS' =>     true,
245         'NUMBERS' =>     true,
246         'METHODS' =>     true,
247         'SCRIPT' =>      true
248     );
249
250     /**
251      * The time it took to parse the code
252      * @var double
253      */
254     var $time = 0;
255     
256     /**
257      * The content of the header block
258      * @var string
259      */
260     var $header_content = '';
261     
262     /**
263      * The content of the footer block
264      * @var string
265      */
266     var $footer_content = '';
267     
268     /**
269      * The style of the header block
270      * @var string
271      */
272     var $header_content_style = '';
273     
274     /**
275      * The style of the footer block
276      * @var string
277      */
278     var $footer_content_style = '';
279     
280     /**
281      * The styles for hyperlinks in the code
282      * @var array
283      */
284     var $link_styles = array();
285     
286     /**
287      * Whether important blocks should be recognised or not
288      * @var boolean
289      * @deprecated
290      * @todo REMOVE THIS FUNCTIONALITY!
291      */
292     var $enable_important_blocks = false;
293     
294     /**
295      * Styles for important parts of the code
296      * @var string
297      * @deprecated
298      * @todo As above - rethink the whole idea of important blocks as it is buggy and
299      * will be hard to implement in 1.2
300      */
301     var $important_styles = 'font-weight: bold; color: red;'; // Styles for important parts of the code
302     
303     /**
304      * Whether CSS IDs should be added to the code
305      * @var boolean
306      */
307     var $add_ids = false;
308     
309     /**
310      * Lines that should be highlighted extra
311      * @var array
312      */
313     var $highlight_extra_lines = array();
314     
315     /**
316      * Styles of extra-highlighted lines
317      * @var string
318      */
319     var $highlight_extra_lines_style = 'color: #cc0; background-color: #ffc;';
320     
321     /**
322      * Number at which line numbers should start at
323      * @var int
324      * @todo Warning documentation about XHTML compliance
325      */
326     var $line_numbers_start = 1;
327
328     /**
329      * The overall style for this code block
330      * @var string
331      */
332     var $overall_style = '';
333     
334     /**
335      *  The style for the actual code
336      * @var string
337      */
338     var $code_style = 'font-family: \'Courier New\', Courier, monospace; font-weight: normal;';
339     
340     /**
341      * The overall class for this code block
342      * @var string
343      */
344     var $overall_class = '';
345     
346     /**
347      * The overall ID for this code block
348      * @var string
349      */
350     var $overall_id = '';
351     
352     /**
353      * Line number styles
354      * @var string
355      */
356     var $line_style1 = 'font-family: \'Courier New\', Courier, monospace; color: black; font-weight: normal; font-style: normal;';
357     
358     /**
359      * Line number styles for fancy lines
360      * @var string
361      */
362     var $line_style2 = 'font-weight: bold;';
363     
364     /**
365      * Flag for how line nubmers are displayed
366      * @var boolean
367      */
368     var $line_numbers = GESHI_NO_LINE_NUMBERS;
369     
370     /**
371      * The "nth" value for fancy line highlighting
372      * @var int
373      */
374     var $line_nth_row = 0;
375
376     /**
377      * The size of tab stops
378      * @var int
379      */
380     var $tab_width = 8;
381         
382     /**
383      * Default target for keyword links
384      * @var string
385      */
386     var $link_target = '';
387     
388     /**
389      * The encoding to use for entity encoding
390      * @var string
391      */
392     var $encoding = 'ISO-8859-1';
393
394     /**
395      * Unused (planned for future)
396      * @var int
397      */
398     var $output_format = GESHI_OUTPUT_HTML;
399
400     /**#@-*/
401
402     /**
403      * Creates a new GeSHi object, with source and language
404      *
405      * @param string The source code to highlight
406      * @param string The language to highlight the source with
407      * @param string The path to the language file directory. <b>This
408      *               is deprecated!</b> I've backported the auto path
409      *               detection from the 1.1.X dev branch, so now it
410      *               should be automatically set correctly. If you have
411      *               renamed the language directory however, you will
412      *               still need to set the path using this parameter or
413      *               {@link GeSHi::set_language_path()}
414      * @since 1.0.0
415      */
416     function GeSHi ($source, $language, $path = '')
417     {
418         $this->set_source($source);
419         $this->set_language_path($path);
420         $this->set_language($language);
421     }
422
423     /**
424      * Returns an error message associated with the last GeSHi operation,
425      * or false if no error has occured
426      *
427      * @return string|false An error message if there has been an error, else false
428      * @since  1.0.0
429      */
430     function error ()
431     {
432         if ($this->error) {
433             $msg = $this->error_messages[$this->error];
434             $debug_tpl_vars = array(
435                 '{LANGUAGE}' => $this->language,
436                 '{PATH}' => $this->language_path
437             );
438             foreach ($debug_tpl_vars as $tpl => $var) {
439                 $msg = str_replace($tpl, $var, $msg);
440             }
441             return "<br /><strong>GeSHi Error:</strong> $msg (code $this->error)<br />";
442         }
443         return false;
444     }
445
446     /**
447      * Gets a human-readable language name (thanks to Simon Patterson
448      * for the idea :))
449      *
450      * @return string The name for the current language
451      * @since  1.0.2
452      */
453     function get_language_name ()
454     {
455         if (GESHI_ERROR_NO_SUCH_LANG == $this->_error) {
456             return $this->language_data['LANG_NAME'] . ' (Unknown Language)';
457         }
458         return $this->language_data['LANG_NAME'];
459     }
460
461     /**
462      * Sets the source code for this object
463      *
464      * @param string The source code to highlight
465      * @since 1.0.0
466      */
467     function set_source ($source)
468     {
469         if ('' == trim($source)) {
470             $this->error = GESHI_ERROR_NO_INPUT;
471         }
472         $this->source = $source;
473     }
474
475     /**
476      * Sets the language for this object
477      *
478      * @param string The name of the language to use
479      * @since 1.0.0
480      */
481     function set_language ($language)
482     {
483         $this->error = false;
484         $this->strict_mode = GESHI_NEVER;
485         
486         $language = preg_replace('#[^a-zA-Z0-9\-_]#', '', $language);
487         $this->language = strtolower($language);
488         
489         $file_name = $this->language_path . $this->language . '.php';
490         if (!is_readable($file_name)) {
491             $this->error = GESHI_ERROR_NO_SUCH_LANG;
492             return;
493         }
494         // Load the language for parsing
495         $this->load_language($file_name);
496     }
497
498     /**
499      * Sets the path to the directory containing the language files. Note
500      * that this path is relative to the directory of the script that included
501      * geshi.php, NOT geshi.php itself.
502      *
503      * @param string The path to the language directory
504      * @since 1.0.0
505      * @deprecated The path to the language files should now be automatically
506      *             detected, so this method should no longer be needed. The
507      *             1.1.X branch handles manual setting of the path differently
508      *             so this method will disappear in 1.2.0.
509      */
510     function set_language_path ($path)
511     {
512         if ($path) {
513           $this->language_path = ('/' == substr($path, strlen($path) - 1, 1)) ? $path : $path . '/';
514         }
515     }
516
517     /**
518      * Sets the type of header to be used.
519      *
520      * If GESHI_HEADER_DIV is used, the code is surrounded in a "div".This
521      * means more source code but more control over tab width and line-wrapping.
522      * GESHI_HEADER_PRE means that a "pre" is used - less source, but less
523      * control. Default is GESHI_HEADER_PRE.
524      *
525      * From 1.0.7.2, you can use GESHI_HEADER_NONE to specify that no header code
526      * should be outputted.
527      *
528      * @param int The type of header to be used
529      * @since 1.0.0
530      */
531     function set_header_type ($type)
532     {
533         if (GESHI_HEADER_DIV != $type && GESHI_HEADER_PRE != $type && GESHI_HEADER_NONE != $type) {
534             $this->error = GESHI_ERROR_INVALID_HEADER_TYPE;
535             return;
536         }
537         $this->header_type = $type;
538     }
539
540     /**
541      * Sets the styles for the code that will be outputted
542      * when this object is parsed. The style should be a
543      * string of valid stylesheet declarations
544      *
545      * @param string  The overall style for the outputted code block
546      * @param boolean Whether to merge the styles with the current styles or not
547      * @since 1.0.0
548      */
549     function set_overall_style ($style, $preserve_defaults = false)
550     {
551         if (!$preserve_defaults) {
552             $this->overall_style = $style;
553         } else {
554             $this->overall_style .= $style;
555         }
556     }
557
558     /**
559      * Sets the overall classname for this block of code. This
560      * class can then be used in a stylesheet to style this object's
561      * output
562      *
563      * @param string The class name to use for this block of code
564      * @since 1.0.0
565      */
566     function set_overall_class ($class)
567     {
568         $this->overall_class = $class;
569     }
570
571     /**
572      * Sets the overall id for this block of code. This id can then
573      * be used in a stylesheet to style this object's output
574      *
575      * @param string The ID to use for this block of code
576      * @since 1.0.0
577      */
578     function set_overall_id ($id)
579     {
580         $this->overall_id = $id;
581     }
582
583     /**
584      * Sets whether CSS classes should be used to highlight the source. Default
585      * is off, calling this method with no arguments will turn it on
586      *
587      * @param boolean Whether to turn classes on or not
588      * @since 1.0.0
589      */
590     function enable_classes ($flag = true)
591     {
592         $this->use_classes = ($flag) ? true : false;
593     }
594
595     /**
596      * Sets the style for the actual code. This should be a string
597      * containing valid stylesheet declarations. If $preserve_defaults is
598      * true, then styles are merged with the default styles, with the
599      * user defined styles having priority
600      *
601      * Note: Use this method to override any style changes you made to
602      * the line numbers if you are using line numbers, else the line of
603      * code will have the same style as the line number! Consult the
604      * GeSHi documentation for more information about this.
605      *
606      * @param string  The style to use for actual code
607      * @param boolean Whether to merge the current styles with the new styles
608      */
609     function set_code_style ($style, $preserve_defaults = false)
610     {
611         if (!$preserve_defaults) {
612             $this->code_style = $style;
613         } else {
614             $this->code_style .= $style;
615         }
616     }
617
618     /**
619      * Sets the styles for the line numbers.
620      *
621      * @param string The style for the line numbers that are "normal"
622      * @param string|boolean If a string, this is the style of the line
623      *        numbers that are "fancy", otherwise if boolean then this
624      *        defines whether the normal styles should be merged with the
625      *        new normal styles or not
626      * @param boolean If set, is the flag for whether to merge the "fancy"
627      *        styles with the current styles or not
628      * @since 1.0.2
629      */
630     function set_line_style ($style1, $style2 = '', $preserve_defaults = false)
631     {
632         if (is_bool($style2)) {
633             $preserve_defaults = $style2;
634             $style2 = '';
635         }
636         if (!$preserve_defaults) {
637             $this->line_style1 = $style1;
638             $this->line_style2 = $style2;
639         } else {
640             $this->line_style1 .= $style1;
641             $this->line_style2 .= $style2;
642         }
643     }
644
645     /**
646      * Sets whether line numbers should be displayed.
647      *
648      * Valid values for the first parameter are:
649      *
650      * <ul>
651      *   <li><b>GESHI_NO_LINE_NUMBERS</b>: Line numbers will not be displayed</li>
652      *   <li><b>GESHI_NORMAL_LINE_NUMBERS</b>: Line numbers will be displayed</li>
653      *   <li><b>GESHI_FANCY_LINE_NUMBERS</b>: Fancy line numbers will be displayed</li>
654      * </ul>
655      *
656      * For fancy line numbers, the second parameter is used to signal which lines
657      * are to be fancy. For example, if the value of this parameter is 5 then every
658      * 5th line will be fancy.
659      *
660      * @param int How line numbers should be displayed
661      * @param int Defines which lines are fancy
662      * @since 1.0.0
663      */
664     function enable_line_numbers ($flag, $nth_row = 5)
665     {
666         if (GESHI_NO_LINE_NUMBERS != $flag && GESHI_NORMAL_LINE_NUMBERS != $flag
667             && GESHI_FANCY_LINE_NUMBERS != $flag) {
668             $this->error = GESHI_ERROR_INVALID_LINE_NUMBER_TYPE;
669         }
670         $this->line_numbers = $flag;
671         $this->line_nth_row = $nth_row;
672     }
673
674     /**
675      * Sets the style for a keyword group. If $preserve_defaults is
676      * true, then styles are merged with the default styles, with the
677      * user defined styles having priority
678      *
679      * @param int     The key of the keyword group to change the styles of
680      * @param string  The style to make the keywords
681      * @param boolean Whether to merge the new styles with the old or just
682      *                to overwrite them
683      * @since 1.0.0
684      */
685     function set_keyword_group_style ($key, $style, $preserve_defaults = false)
686     {
687         if (!$preserve_defaults) {
688             $this->language_data['STYLES']['KEYWORDS'][$key] = $style;
689         } else {
690             $this->language_data['STYLES']['KEYWORDS'][