geshi.php

gehe zur Dokumentation dieser Datei
00001 <?php
00036 //
00037 // GeSHi Constants
00038 // You should use these constant names in your programs instead of
00039 // their values - you never know when a value may change in a future
00040 // version
00041 //
00042 
00044 define('GESHI_VERSION', '1.0.7.20');
00045 
00046 // Define the root directory for the GeSHi code tree
00047 if (!defined('GESHI_ROOT')) {
00049     define('GESHI_ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR);
00050 }
00053 define('GESHI_LANG_ROOT', GESHI_ROOT . 'geshi' . DIRECTORY_SEPARATOR);
00054 
00055 
00056 // Line numbers - use with enable_line_numbers()
00058 define('GESHI_NO_LINE_NUMBERS', 0);
00060 define('GESHI_NORMAL_LINE_NUMBERS', 1);
00062 define('GESHI_FANCY_LINE_NUMBERS', 2);
00063 
00064 // Container HTML type
00066 define('GESHI_HEADER_NONE', 0);
00068 define('GESHI_HEADER_DIV', 1);
00070 define('GESHI_HEADER_PRE', 2);
00071 
00072 // Capatalisation constants
00074 define('GESHI_CAPS_NO_CHANGE', 0);
00076 define('GESHI_CAPS_UPPER', 1);
00078 define('GESHI_CAPS_LOWER', 2);
00079 
00080 // Link style constants
00082 define('GESHI_LINK', 0);
00084 define('GESHI_HOVER', 1);
00086 define('GESHI_ACTIVE', 2);
00088 define('GESHI_VISITED', 3);
00089 
00090 // Important string starter/finisher
00091 // Note that if you change these, they should be as-is: i.e., don't
00092 // write them as if they had been run through htmlentities()
00094 define('GESHI_START_IMPORTANT', '<BEGIN GeSHi>');
00096 define('GESHI_END_IMPORTANT', '<END GeSHi>');
00097 
00101 // When strict mode applies for a language
00103 define('GESHI_NEVER', 0);
00106 define('GESHI_MAYBE', 1);
00108 define('GESHI_ALWAYS', 2);
00109 
00110 // Advanced regexp handling constants, used in language files
00112 define('GESHI_SEARCH', 0);
00115 define('GESHI_REPLACE', 1);
00117 define('GESHI_MODIFIERS', 2);
00120 define('GESHI_BEFORE', 3);
00123 define('GESHI_AFTER', 4);
00126 define('GESHI_CLASS', 5);
00127 
00129 define('GESHI_COMMENTS', 0);
00130 
00131 // Error detection - use these to analyse faults
00135 define('GESHI_ERROR_NO_INPUT', 1);
00137 define('GESHI_ERROR_NO_SUCH_LANG', 2);
00139 define('GESHI_ERROR_FILE_NOT_READABLE', 3);
00141 define('GESHI_ERROR_INVALID_HEADER_TYPE', 4);
00143 define('GESHI_ERROR_INVALID_LINE_NUMBER_TYPE', 5);
00158 class GeSHi {
00166     var $source = '';
00167 
00172     var $language = '';
00173 
00178     var $language_data = array();
00179 
00184     var $language_path = GESHI_LANG_ROOT;
00185 
00191     var $error = false;
00192 
00197     var $error_messages = array(
00198         GESHI_ERROR_NO_SUCH_LANG => 'GeSHi could not find the language {LANGUAGE} (using path {PATH})',
00199         GESHI_ERROR_FILE_NOT_READABLE => 'The file specified for load_from_file was not readable',
00200         GESHI_ERROR_INVALID_HEADER_TYPE => 'The header type specified is invalid',
00201         GESHI_ERROR_INVALID_LINE_NUMBER_TYPE => 'The line number type specified is invalid'
00202     );
00203 
00208     var $strict_mode = false;
00209 
00214     var $use_classes = false;
00215 
00226     var $header_type = GESHI_HEADER_PRE;
00227 
00232     var $lexic_permissions = array(
00233         'KEYWORDS' =>    array(),
00234         'COMMENTS' =>    array('MULTI' => true),
00235         'REGEXPS' =>     array(),
00236         'ESCAPE_CHAR' => true,
00237         'BRACKETS' =>    true,
00238         'SYMBOLS' =>     true,
00239         'STRINGS' =>     true,
00240         'NUMBERS' =>     true,
00241         'METHODS' =>     true,
00242         'SCRIPT' =>      true
00243     );
00244 
00249     var $time = 0;
00250 
00255     var $header_content = '';
00256 
00261     var $footer_content = '';
00262 
00267     var $header_content_style = '';
00268 
00273     var $footer_content_style = '';
00274 
00280     var $force_code_block = false;
00281 
00286     var $link_styles = array();
00287 
00294     var $enable_important_blocks = false;
00295 
00303     var $important_styles = 'font-weight: bold; color: red;'; // Styles for important parts of the code
00304 
00309     var $add_ids = false;
00310 
00315     var $highlight_extra_lines = array();
00316 
00321     var $highlight_extra_lines_style = 'color: #cc0; background-color: #ffc;';
00322 
00329      var $line_ending = null;
00330 
00335     var $line_numbers_start = 1;
00336 
00341     var $overall_style = '';
00342 
00347     var $code_style = 'font-family: \'Courier New\', Courier, monospace; font-weight: normal;';
00348 
00353     var $overall_class = '';
00354 
00359     var $overall_id = '';
00360 
00365     var $line_style1 = 'font-family: \'Courier New\', Courier, monospace; color: black; font-weight: normal; font-style: normal;';
00366 
00371     var $line_style2 = 'font-weight: bold;';
00372 
00377     var $line_numbers = GESHI_NO_LINE_NUMBERS;
00378 
00383     var $line_nth_row = 0;
00384 
00389     var $tab_width = 8;
00390 
00395      var $use_language_tab_width = false;
00396 
00401     var $link_target = '';
00402 
00408     var $encoding = 'ISO-8859-1';
00409 
00414     var $keyword_links = true;
00415 
00432     function GeSHi($source, $language, $path = '') {
00433         $this->set_source($source);
00434         $this->set_language_path($path);
00435         $this->set_language($language);
00436     }
00437 
00445     function error() {
00446         if ($this->error) {
00447             $msg = $this->error_messages[$this->error];
00448             $debug_tpl_vars = array(
00449                 '{LANGUAGE}' => $this->language,
00450                 '{PATH}' => $this->language_path
00451             );
00452             foreach ($debug_tpl_vars as $tpl => $var) {
00453                 $msg = str_replace($tpl, $var, $msg);
00454             }
00455             return "<br /><strong>GeSHi Error:</strong> $msg (code $this->error)<br />";
00456         }
00457         return false;
00458     }
00459 
00467     function get_language_name() {
00468         if (GESHI_ERROR_NO_SUCH_LANG == $this->error) {
00469             return $this->language_data['LANG_NAME'] . ' (Unknown Language)';
00470         }
00471         return $this->language_data['LANG_NAME'];
00472     }
00473 
00480     function set_source($source) {
00481         $this->source = $source;
00482         $this->highlight_extra_lines = array();
00483     }
00484 
00491     function set_language($language) {
00492         $this->error = false;
00493         $this->strict_mode = GESHI_NEVER;
00494 
00495         $language = preg_replace('#[^a-zA-Z0-9\-_]#', '', $language);
00496         $this->language = strtolower($language);
00497 
00498         $file_name = $this->language_path . $this->language . '.php';
00499         if (!is_readable($file_name)) {
00500             $this->error = GESHI_ERROR_NO_SUCH_LANG;
00501             return;
00502         }
00503         // Load the language for parsing
00504         $this->load_language($file_name);
00505     }
00506 
00519     function set_language_path($path) {
00520         if ($path) {
00521             $this->language_path = ('/' == substr($path, strlen($path) - 1, 1)) ? $path : $path . '/';
00522             $this->set_language($this->language);        // otherwise set_language_path has no effect
00523         }
00524     }
00525 
00540     function set_header_type($type) {
00541         if (GESHI_HEADER_DIV != $type && GESHI_HEADER_PRE != $type && GESHI_HEADER_NONE != $type) {
00542             $this->error = GESHI_ERROR_INVALID_HEADER_TYPE;
00543             return;
00544         }
00545         $this->header_type = $type;
00546         // Set a default overall style if the header is a <div>
00547         if (GESHI_HEADER_DIV == $type && !$this->overall_style) {
00548             $this->overall_style = 'font-family: monospace;';
00549         }
00550     }
00551 
00561     function set_overall_style($style, $preserve_defaults = false) {
00562         if (!$preserve_defaults) {
00563             $this->overall_style = $style;
00564         }
00565         else {
00566             $this->overall_style .= $style;
00567         }
00568     }
00569 
00578     function set_overall_class($class) {
00579         $this->overall_class = $class;
00580     }
00581 
00589     function set_overall_id($id) {
00590         $this->overall_id = $id;
00591     }
00592 
00600     function enable_classes($flag = true) {
00601         $this->use_classes = ($flag) ? true : false;
00602     }
00603 
00618     function set_code_style($style, $preserve_defaults = false) {
00619         if (!$preserve_defaults) {
00620             $this->code_style = $style;
00621         }
00622         else {
00623             $this->code_style .= $style;
00624         }
00625     }
00626 
00639     function set_line_style($style1, $style2 = '', $preserve_defaults = false) {
00640         if (is_bool($style2)) {
00641             $preserve_defaults = $style2;
00642             $style2 = '';
00643         }
00644         if (!$preserve_defaults) {
00645             $this->line_style1 = $style1;
00646             $this->line_style2 = $style2;
00647         }
00648         else {
00649             $this->line_style1 .= $style1;
00650             $this->line_style2 .= $style2;
00651         }
00652     }
00653 
00671     function enable_line_numbers($flag, $nth_row = 5) {
00672         if (GESHI_NO_LINE_NUMBERS != $flag && GESHI_NORMAL_LINE_NUMBERS != $flag
00673             && GESHI_FANCY_LINE_NUMBERS != $flag) {
00674             $this->error = GESHI_ERROR_INVALID_LINE_NUMBER_TYPE;
00675         }
00676         $this->line_numbers = $flag;
00677         $this->line_nth_row = $nth_row;
00678     }
00679 
00691     function set_keyword_group_style($key, $style, $preserve_defaults = false) {
00692         if (!$preserve_defaults) {
00693             $this->language_data['STYLES']['KEYWORDS'][$key] = $style;
00694         }
00695         else {
00696             $this->language_data['STYLES']['KEYWORDS'][$key] .= $style;
00697         }
00698     }
00699 
00707     function set_keyword_group_highlighting($key, $flag = true) {
00708         $this->lexic_permissions['KEYWORDS'][$key] = ($flag) ? true : false;
00709     }
00710 
00722     function set_comments_style($key, $style, $preserve_defaults = false) {
00723         if (!$preserve_defaults) {
00724             $this->language_data['STYLES']['COMMENTS'][$key] = $style;
00725         }
00726         else {
00727             $this->language_data['STYLES']['COMMENTS'][$key] .= $style;
00728         }
00729     }
00730 
00738     function set_comments_highlighting($key, $flag = true) {
00739         $this->lexic_permissions['COMMENTS'][$key] = ($flag) ? true : false;
00740     }
00741 
00752     function set_escape_characters_style($style, $preserve_defaults = false) {
00753         if (!$preserve_defaults) {
00754             $this->language_data['STYLES']['ESCAPE_CHAR'][0] = $style;
00755         }
00756         else {
00757             $this->language_data['STYLES']['ESCAPE_CHAR'][0] .= $style;
00758         }
00759     }
00760 
00767     function set_escape_characters_highlighting($flag = true) {
00768         $this->lexic_permissions['ESCAPE_CHAR'] = ($flag) ? true : false;
00769     }
00770 
00785     function set_brackets_style($style, $preserve_defaults = false) {
00786         if (!$preserve_defaults) {
00787             $this->language_data['STYLES']['BRACKETS'][0] = $style;
00788         }
00789         else {
00790             $this->language_data['STYLES']['BRACKETS'][0] .= $style;
00791         }
00792     }
00793 
00804     function set_brackets_highlighting($flag) {
00805         $this->lexic_permissions['BRACKETS'] = ($flag) ? true : false;
00806     }
00807 
00818     function set_symbols_style($style, $preserve_defaults = false) {
00819         if (!$preserve_defaults) {
00820             $this->language_data['STYLES']['SYMBOLS'][0] = $style;
00821         }
00822         else {
00823             $this->language_data['STYLES']['SYMBOLS'][0] .= $style;
00824         }
00825         // For backward compatibility
00826         $this->set_brackets_style ($style, $preserve_defaults);
00827     }
00828 
00835     function set_symbols_highlighting($flag) {
00836         $this->lexic_permissions['SYMBOLS'] = ($flag) ? true : false;
00837         // For backward compatibility
00838         $this->set_brackets_highlighting ($flag);
00839     }
00840 
00851     function set_strings_style($style, $preserve_defaults = false) {
00852         if (!$preserve_defaults) {
00853             $this->language_data['STYLES']['STRINGS'][0] = $style;
00854         }
00855         else {
00856             $this->language_data['STYLES']['STRINGS'][0] .= $style;
00857         }
00858     }
00859 
00866     function set_strings_highlighting($flag) {
00867         $this->lexic_permissions['STRINGS'] = ($flag) ? true : false;
00868     }
00869 
00880     function set_numbers_style($style, $preserve_defaults = false) {
00881         if (!$preserve_defaults) {
00882             $this->language_data['STYLES']['NUMBERS'][0] = $style;
00883         }
00884         else {
00885             $this->language_data['STYLES']['NUMBERS'][0] .= $style;
00886         }
00887     }
00888 
00895     function set_numbers_highlighting($flag) {
00896         $this->lexic_permissions['NUMBERS'] = ($flag) ? true : false;
00897     }
00898 
00912     function set_methods_style($key, $style, $preserve_defaults = false) {
00913         if (!$preserve_defaults) {
00914             $this->language_data['STYLES']['METHODS'][$key] = $style;
00915         }
00916         else {
00917             $this->language_data['STYLES']['METHODS'][$key] .= $style;
00918         }
00919     }
00920 
00927     function set_methods_highlighting($flag) {
00928         $this->lexic_permissions['METHODS'] = ($flag) ? true : false;
00929     }
00930 
00941     function set_regexps_style($key, $style, $preserve_defaults = false) {
00942         if (!$preserve_defaults) {
00943             $this->language_data['STYLES']['REGEXPS'][$key] = $style;
00944         }
00945         else {
00946             $this->language_data['STYLES']['REGEXPS'][$key] .= $style;
00947         }
00948     }
00949 
00957     function set_regexps_highlighting($key, $flag) {
00958         $this->lexic_permissions['REGEXPS'][$key] = ($flag) ? true : false;
00959     }
00960 
00968     function set_case_sensitivity($key, $case) {
00969         $this->language_data['CASE_SENSITIVE'][$key] = ($case) ? true : false;
00970     }
00971 
00983     function set_case_keywords($case) {
00984         $this->language_data['CASE_KEYWORDS'] = $case;
00985     }
00986 
00995     function set_tab_width($width) {
00996         $this->tab_width = intval($width);
00997         //Check if it fit's the constraints:
00998         if($this->tab_width < 1) {
00999             //Return it to the default
01000             $this->tab_width = 8;
01001         }
01002     }
01003 
01009      function set_use_language_tab_width($use) {
01010           $this->use_language_tab_width = (bool) $use;
01011      }
01012 
01019      function get_real_tab_width() {
01020           if (!$this->use_language_tab_width || !isset($this->language_data['TAB_WIDTH'])) {
01021                return $this->tab_width;
01022           } else {
01023                return $this->language_data['TAB_WIDTH'];
01024           }
01025      }
01026 
01035     function enable_strict_mode($mode = true) {
01036         if (GESHI_MAYBE == $this->language_data['STRICT_MODE_APPLIES']) {
01037           $this->strict_mode = ($mode) ? true : false;
01038         }
01039     }
01040 
01047     function disable_highlighting() {
01048         foreach ($this->lexic_permissions as $key => $value) {
01049             if (is_array($value)) {
01050                 foreach ($value as $k => $v) {
01051                     $this->lexic_permissions[$key][$k] = false;
01052                 }
01053             }
01054             else {
01055                 $this->lexic_permissions[$key] = false;
01056             }
01057         }
01058         // Context blocks
01059         $this->enable_important_blocks = false;
01060     }
01061 
01068     function enable_highlighting() {
01069         foreach ($this->lexic_permissions as $key => $value) {
01070             if (is_array($value)) {
01071                 foreach ($value as $k => $v) {
01072                     $this->lexic_permissions[$key][$k] = true;
01073                 }
01074             }
01075             else {
01076                 $this->lexic_permissions[$key] = true;
01077             }
01078         }
01079         // Context blocks
01080         $this->enable_important_blocks = true;
01081     }
01082 
01094     function get_language_name_from_extension( $extension, $lookup = array() ) {
01095         if ( !$lookup ) {
01096             $lookup = array(
01097                 'actionscript' => array('as'),
01098                 'ada' => array('a', 'ada', 'adb', 'ads'),
01099                 'apache' => array('conf'),
01100                 'asm' => array('ash', 'asm'),
01101                 'asp' => array('asp'),
01102                 'bash' => array('sh'),
01103                 'c' => array('c', 'h'),
01104                 'c_mac' => array('c', 'h'),
01105                 'caddcl' => array(),
01106                 'cadlisp' => array(),
01107                 'cdfg' => array('cdfg'),
01108                 'cpp' => array('cpp', 'h', 'hpp'),
01109                 'csharp' => array(),
01110                 'css' => array('css'),
01111                 'delphi' => array('dpk', 'dpr'),
01112                 'html4strict' => array('html', 'htm'),
01113                 'java' => array('java'),
01114                 'javascript' => array('js'),
01115                 'lisp' => array('lisp'),
01116                 'lua' => array('lua'),
01117                 'mpasm' => array(),
01118                 'nsis' => array(),
01119                 'objc' => array(),
01120                 'oobas' => array(),
01121                 'oracle8' => array(),
01122                 'pascal' => array('pas'),
01123                 'perl' => array('pl', 'pm'),
01124                 'php' => array('php', 'php5', 'phtml', 'phps'),
01125                 'python' => array('py'),
01126                 'qbasic' => array('bi'),
01127                 'sas' => array('sas'),
01128                 'smarty' => array(),
01129                 'vb' => array('bas'),
01130                 'vbnet' => array(),
01131                 'visualfoxpro' => array(),
01132                 'xml' => array('xml')
01133             );
01134         }
01135 
01136         foreach ($lookup as $lang => $extensions) {
01137             foreach ($extensions as $ext) {
01138                 if ($ext == $extension) {
01139                     return $lang;
01140                 }
01141             }
01142         }
01143         return '';
01144     }
01145 
01161     function load_from_file($file_name, $lookup = array()) {
01162         if (is_readable($file_name)) {
01163             $this->set_source(implode('', file($file_name)));
01164             $this->set_language($this->get_language_name_from_extension(substr(strrchr($file_name, '.'), 1), $lookup));
01165         }
01166         else {
01167             $this->error = GESHI_ERROR_FILE_NOT_READABLE;
01168         }
01169     }
01170 
01178     function add_keyword($key, $word) {
01179         $this->language_data['KEYWORDS'][$key][] = $word;
01180     }
01181 
01189     function remove_keyword($key, $word) {
01190         $this->language_data['KEYWORDS'][$key] =
01191             array_diff($this->language_data['KEYWORDS'][$key], array($word));
01192     }
01193 
01203     function add_keyword_group($key, $styles, $case_sensitive = true, $words = array()) {
01204         $words = (array) $words;
01205         $this->language_data['KEYWORDS'][$key] = $words;
01206         $this->lexic_permissions['KEYWORDS'][$key] = true;
01207         $this->language_data['CASE_SENSITIVE'][$key] = $case_sensitive;
01208         $this->language_data['STYLES']['KEYWORDS'][$key] = $styles;
01209     }
01210 
01217     function remove_keyword_group ($key) {
01218         unset($this->language_data['KEYWORDS'][$key]);
01219         unset($this->lexic_permissions['KEYWORDS'][$key]);
01220         unset($this->language_data['CASE_SENSITIVE'][$key]);
01221         unset($this->language_data['STYLES']['KEYWORDS'][$key]);
01222     }
01223 
01230     function set_header_content($content) {
01231         $this->header_content = $content;
01232     }
01233 
01240     function set_footer_content($content) {
01241         $this->footer_content = $content;
01242     }
01243 
01250     function set_header_content_style($style) {
01251         $this->header_content_style = $style;
01252     }
01253 
01260     function set_footer_content_style($style) {
01261         $this->footer_content_style = $style;
01262     }
01263 
01271     function enable_inner_code_block($flag) {
01272         $this->force_code_block = (bool)$flag;
01273     }
01274 
01284     function set_url_for_keyword_group($group, $url) {
01285         $this->language_data['URLS'][$group] = $url;
01286     }
01287 
01296     function set_link_styles($type, $styles) {
01297         $this->link_styles[$type] = $styles;
01298     }
01299 
01306     function set_link_target($target) {
01307         if (!$target) {
01308             $this->link_target = '';
01309         }
01310         else {
01311             $this->link_target = ' target="' . $target . '" ';
01312         }
01313     }
01314 
01321     function set_important_styles($styles) {
01322         $this->important_styles = $styles;
01323     }
01324 
01331     function enable_important_blocks($flag) {
01332         $this->enable_important_blocks = ( $flag ) ? true : false;
01333     }
01334 
01341     function enable_ids($flag = true) {
01342         $this->add_ids = ($flag) ? true : false;
01343     }
01344 
01353     function highlight_lines_extra($lines) {
01354         if (is_array($lines)) {
01355             foreach ($lines as $line) {
01356                 $this->highlight_extra_lines[intval($line)] = intval($line);
01357             }
01358         }
01359         else {
01360             $this->highlight_extra_lines[intval($lines)] = intval($lines);
01361         }
01362     }
01363 
01370     function set_highlight_lines_extra_style($styles) {
01371         $this->highlight_extra_lines_style = $styles;
01372     }
01373 
01379      function set_line_ending($line_ending) {
01380           $this->line_ending = (string)$line_ending;
01381      }
01382 
01398     function start_line_numbers_at($number) {
01399         $this->line_numbers_start = abs(intval($number));
01400     }
01401 
01414     function set_encoding($encoding) {
01415         if ($encoding) {
01416           $this->encoding = $encoding;
01417         }
01418     }
01419 
01425     function enable_keyword_links($enable = true) {
01426         $this->keyword_links = ($enable) ? true : false;
01427     }
01428 
01439     function parse_code () {
01440         // Start the timer
01441         $start_time = microtime();
01442 
01443         // Firstly, if there is an error, we won't highlight
01444         if ($this->error) {
01445             $result = GeSHi::hsc($this->source);
01446             // Timing is irrelevant
01447             $this->set_time($start_time, $start_time);
01448             return $this->finalise($result);
01449         }
01450 
01451         // Replace all newlines to a common form.
01452         $code = str_replace("\r\n", "\n", $this->source);
01453         $code = str_replace("\r", "\n", $code);
01454         // Add spaces for regular expression matching and line numbers
01455         $code = "\n" . $code . "\n";
01456 
01457         // Initialise various stuff
01458         $length           = strlen($code);
01459         $STRING_OPEN      = '';
01460         $CLOSE_STRING     = false;
01461         $ESCAPE_CHAR_OPEN = false;
01462         $COMMENT_MATCHED  = false;
01463         // Turn highlighting on if strict mode doesn't apply to this language
01464         $HIGHLIGHTING_ON  = ( !$this->strict_mode ) ? true : '';
01465         // Whether to highlight inside a block of code
01466         $HIGHLIGHT_INSIDE_STRICT = false;
01467         $HARDQUOTE_OPEN = false;
01468         $STRICTATTRS = '';
01469         $stuff_to_parse   = '';
01470         $result           = '';
01471 
01472         // "Important" selections are handled like multiline comments
01473         // @todo GET RID OF THIS SHIZ
01474         if ($this->enable_important_blocks) {
01475             $this->language_data['COMMENT_MULTI'][GESHI_START_IMPORTANT] = GESHI_END_IMPORTANT;
01476         }
01477 
01478         if ($this->strict_mode) {
01479             // Break the source into bits. Each bit will be a portion of the code
01480             // within script delimiters - for example, HTML between < and >
01481             $parts = array(0 => array(0 => ''));
01482             $k = 0;
01483             for ($i = 0; $i < $length; $i++) {
01484                 $char = substr($code, $i, 1);
01485                 if (!$HIGHLIGHTING_ON) {
01486                     foreach ($this->language_data['SCRIPT_DELIMITERS'] as $key => $delimiters) {
01487                         foreach ($delimiters as $open => $close) {
01488                             // Get the next little bit for this opening string
01489                             $check = substr($code, $i, strlen($open));
01490                             // If it matches...
01491                             if ($check == $open) {
01492                                 // We start a new block with the highlightable
01493                                 // code in it
01494                                 $HIGHLIGHTING_ON = $open;
01495                                 $i += strlen($open) - 1;
01496                                 $char = $open;
01497                                 $parts[++$k][0] = $char;
01498 
01499                                 // No point going around again...
01500                                 break(2);
01501                             }
01502                         }
01503                     }
01504                 }
01505                 else {
01506                     foreach ($this->language_data['SCRIPT_DELIMITERS'] as $key => $delimiters) {
01507                         foreach ($delimiters as $open => $close) {
01508                             if ($open == $HIGHLIGHTING_ON) {
01509                                 // Found the closing tag
01510                                 break(2);
01511                             }
01512                         }
01513                     }
01514                     // We check code from our current position BACKWARDS. This is so
01515                     // the ending string for highlighting can be included in the block
01516                     $check = substr($code, $i - strlen($close) + 1, strlen($close));
01517                     if ($check == $close) {
01518                         $HIGHLIGHTING_ON = '';
01519                         // Add the string to the rest of the string for this part
01520                         $parts[$k][1] = ( isset($parts[$k][1]) ) ? $parts[$k][1] . $char : $char;
01521                         $parts[++$k][0] = '';
01522                         $char = '';
01523                     }
01524                 }
01525                 $parts[$k][1] = ( isset($parts[$k][1]) ) ? $parts[$k][1] . $char : $char;
01526             }
01527             $HIGHLIGHTING_ON = '';
01528         }
01529         else {
01530             // Not strict mode - simply dump the source into
01531             // the array at index 1 (the first highlightable block)
01532             $parts = array(
01533                 1 => array(
01534                     0 => '',
01535                     1 => $code
01536                 )
01537             );
01538         }
01539 
01540         // Now we go through each part. We know that even-indexed parts are
01541         // code that shouldn't be highlighted, and odd-indexed parts should
01542         // be highlighted
01543         foreach ($parts as $key => $data) {
01544             $part = $data[1];
01545             // If this block should be highlighted...
01546             if ($key % 2) {
01547                 if ($this->strict_mode) {
01548                     // Find the class key for this block of code
01549                     foreach ($this->language_data['SCRIPT_DELIMITERS'] as $script_key => $script_data) {
01550                         foreach ($script_data as $open => $close) {
01551                             if ($data[0] == $open) {
01552                                 break(2);
01553                             }
01554                         }
01555                     }
01556 
01557                     if ($this->language_data['STYLES']['SCRIPT'][$script_key] != '' &&
01558                         $this->lexic_permissions['SCRIPT']) {
01559                         // Add a span element around the source to
01560                         // highlight the overall source block
01561                         if (!$this->use_classes &&
01562                             $this->language_data['STYLES']['SCRIPT'][$script_key] != '') {
01563                             $attributes = ' style="' . $this->language_data['STYLES']['SCRIPT'][$script_key] . '"';
01564                         }
01565                         else {
01566                             $attributes = ' class="sc' . $script_key . '"';
01567                         }
01568                         $result .= "<span$attributes>";
01569                         $STRICTATTRS = $attributes;
01570                     }
01571                 }
01572 
01573                 if (!$this->strict_mode || $this->language_data['HIGHLIGHT_STRICT_BLOCK'][$script_key]) {
01574                     // Now, highlight the code in this block. This code
01575                     // is really the engine of GeSHi (along with the method
01576                     // parse_non_string_part).
01577                     $length = strlen($part);
01578                     for ($i = 0; $i < $length; $i++) {
01579                         // Get the next char
01580                         $char = substr($part, $i, 1);
01581                         $hq = isset($this->language_data['HARDQUOTE']) ? $this->language_data['HARDQUOTE'][0] : false;
01582                         // Is this char the newline and line numbers being used?
01583                         if (($this->line_numbers != GESHI_NO_LINE_NUMBERS
01584                             || count($this->highlight_extra_lines) > 0)
01585                             && $char == "\n") {
01586                             // If so, is there a string open? If there is, we should end it before
01587                             // the newline and begin it again (so when <li>s are put in the source
01588                             // remains XHTML compliant)
01589                             // note to self: This opens up possibility of config files specifying
01590                             // that languages can/cannot have multiline strings???
01591                             if ($STRING_OPEN) {
01592                                 if (!$this->use_classes) {
01593                                     $attributes = ' style="' . $this->language_data['STYLES']['STRINGS'][0] . '"';
01594                                 }
01595                                 else {
01596                                     $attributes = ' class="st0"';
01597                                 }
01598                                 $char = '</span>' . $char . "<span$attributes>";
01599                             }
01600                         }
01601                         else if ($char == $STRING_OPEN) {
01602                             // A match of a string delimiter
01603                             if (($this->lexic_permissions['ESCAPE_CHAR'] && $ESCAPE_CHAR_OPEN) ||
01604                                 ($this->lexic_permissions['STRINGS'] && !$ESCAPE_CHAR_OPEN)) {
01605                                 $char = GeSHi::hsc($char) . '</span>';
01606                             }
01607                             $escape_me = false;
01608                             if ($HARDQUOTE_OPEN) {
01609                                 if ($ESCAPE_CHAR_OPEN) {
01610                                     $escape_me = true;
01611                                 }
01612                                 else {
01613                                     foreach ($this->language_data['HARDESCAPE'] as $hardesc) {
01614                                         if (substr($part, $i, strlen($hardesc)) == $hardesc) {
01615                                             $escape_me = true;
01616                                             break;
01617                                         }
01618                                     }
01619                                 }
01620                             }
01621 
01622                             if (!$ESCAPE_CHAR_OPEN) {
01623                                 $STRING_OPEN = '';
01624                                 $CLOSE_STRING = true;
01625                             }
01626                             if (!$escape_me) {
01627                                 $HARDQUOTE_OPEN = false;
01628                             }
01629                             $ESCAPE_CHAR_OPEN = false;
01630                         }
01631                         else if (in_array($char, $this->language_data['QUOTEMARKS']) &&
01632                             ($STRING_OPEN == '') && $this->lexic_permissions['STRINGS']) {
01633                             // The start of a new string
01634                             $STRING_OPEN = $char;
01635                             if (!$this->use_classes) {
01636                                 $attributes = ' style="' . $this->language_data['STYLES']['STRINGS'][0] . '"';
01637                             }
01638                             else {
01639                                 $attributes = ' class="st0"';
01640                             }
01641                             $char = "<span$attributes>" . GeSHi::hsc($char);
01642 
01643                             $result .= $this->parse_non_string_part( $stuff_to_parse );
01644                             $stuff_to_parse = '';
01645                         }
01646                         else if ($hq && substr($part, $i, strlen($hq)) == $hq &&
01647                             ($STRING_OPEN == '') && $this->lexic_permissions['STRINGS']) {
01648                             // The start of a hard quoted string
01649                             $STRING_OPEN = $this->language_data['HARDQUOTE'][1];
01650                             if (!$this->use_classes) {
01651                                 $attributes = ' style="' . $this->language_data['STYLES']['STRINGS'][0] . '"';
01652                             }
01653                             else {
01654                                 $attributes = ' class="st0"';
01655                             }
01656                             $char = "<span$attributes>" . $hq;
01657                             $i += strlen($hq) - 1;
01658                             $HARDQUOTE_OPEN = true;
01659                             $result .= $this->parse_non_string_part($stuff_to_parse);
01660                             $stuff_to_parse = '';
01661                         }
01662                         else if ($char == $this->language_data['ESCAPE_CHAR'] && $STRING_OPEN != '') {
01663                             // An escape character
01664                             if (!$ESCAPE_CHAR_OPEN) {
01665                                 $ESCAPE_CHAR_OPEN = !$HARDQUOTE_OPEN;  // true unless $HARDQUOTE_OPEN
01666                                 if ($HARDQUOTE_OPEN) {
01667                                     foreach ($this->language_data['HARDESCAPE'] as $hard) {
01668                                         if (substr($part, $i, strlen($hard)) == $hard) {
01669                                             $ESCAPE_CHAR_OPEN = true;
01670                                             break;
01671                                         }
01672                                     }
01673                                 }
01674                                 if ($ESCAPE_CHAR_OPEN && $this->lexic_permissions['ESCAPE_CHAR']) {
01675                                     if (!$this->use_classes) {
01676                                         $attributes = ' style="' . $this->language_data['STYLES']['ESCAPE_CHAR'][0] . '"';
01677                                     }
01678                                     else {
01679                                         $attributes = ' class="es0"';
01680                                     }
01681                                     $char = "<span$attributes>" . $char;
01682                                     if (substr($code, $i + 1, 1) == "\n") {
01683                                         // escaping a newline, what's the point in putting the span around
01684                                         // the newline? It only causes hassles when inserting line numbers
01685                                         $char .= '</span>';
01686                                         $ESCAPE_CHAR_OPEN = false;
01687                                     }
01688                                 }
01689                             }
01690                             else {
01691                                 $ESCAPE_CHAR_OPEN = false;
01692                                 if ($this->lexic_permissions['ESCAPE_CHAR']) {
01693                                     $char .= '</span>';
01694                                 }
01695                             }
01696                         }
01697                         else if ($ESCAPE_CHAR_OPEN) {
01698                             if ($this->lexic_permissions['ESCAPE_CHAR']) {
01699                                 $char .= '</span>';
01700                             }
01701                             $ESCAPE_CHAR_OPEN = false;
01702                             $test_str = $char;
01703                         }
01704                         else if ($STRING_OPEN == '') {
01705                             // Is this a multiline comment?
01706                             foreach ($this->language_data['COMMENT_MULTI'] as $open => $close) {
01707                                 $com_len = strlen($open);
01708                                 $test_str = substr( $part, $i, $com_len );
01709                                 $test_str_match = $test_str;
01710                                 if ($open == $test_str) {
01711                                     $COMMENT_MATCHED = true;
01712                                     //@todo If remove important do remove here
01713                                     if ($this->lexic_permissions['COMMENTS']['MULTI'] ||
01714                                         $test_str == GESHI_START_IMPORTANT) {
01715                                         if ($test_str != GESHI_START_IMPORTANT) {
01716                                             if (!$this->use_classes) {
01717                                                 $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS']['MULTI'] . '"';
01718                                             }
01719                                             else {
01720                                                 $attributes = ' class="coMULTI"';
01721                                             }
01722                                             $test_str = "<span$attributes>" . GeSHi::hsc($test_str);
01723                                         }
01724                                         else {
01725                                             if (!$this->use_classes) {
01726                                                 $attributes = ' style="' . $this->important_styles . '"';
01727                                             }
01728                                             else {
01729                                                 $attributes = ' class="imp"';
01730                                             }
01731                                             // We don't include the start of the comment if it's an
01732                                             // "important" part
01733                                             $test_str = "<span$attributes>";
01734                                         }
01735                                     }
01736                                     else {
01737                                         $test_str = GeSHi::hsc($test_str);
01738                                     }
01739 
01740                                     $close_pos = strpos( $part, $close, $i + strlen($close) );
01741 
01742                                     $oops = false;
01743                                     if ($close_pos === false) {
01744                                         $close_pos = strlen($part);
01745                                         $oops = true;
01746                                     }
01747                                     else {
01748                                         $close_pos -= ($com_len - strlen($close));
01749                                     }
01750 
01751                                     // Short-cut through all the multiline code
01752                                     $rest_of_comment = GeSHi::hsc(substr($part, $i + $com_len, $close_pos - $i));
01753                                     if (($this->lexic_permissions['COMMENTS']['MULTI'] ||
01754                                         $test_str_match == GESHI_START_IMPORTANT) &&
01755                                         ($this->line_numbers != GESHI_NO_LINE_NUMBERS ||
01756                                         count($this->highlight_extra_lines) > 0)) {
01757                                         // strreplace to put close span and open span around multiline newlines
01758                                         $test_str .= str_replace(
01759                                             "\n", "</span>\n<span$attributes>", 
01760                                             str_replace("\n ", "\n&nbsp;", $rest_of_comment)
01761                                         );
01762                                     }
01763                                     else {
01764                                         $test_str .= $rest_of_comment;
01765                                     }
01766 
01767                                     if ($this->lexic_permissions['COMMENTS']['MULTI'] ||
01768                                         $test_str_match == GESHI_START_IMPORTANT) {
01769                                         $test_str .= '</span>';
01770                                         if ($oops) {
01771                                             $test_str .= "\n";
01772                                         }
01773                                     }
01774                                              $i = $close_pos + $com_len - 1;
01775                                     // parse the rest
01776                                     $result .= $this->parse_non_string_part($stuff_to_parse);
01777                                     $stuff_to_parse = '';
01778                                     break;
01779                                 }
01780                             }
01781                             // If we haven't matched a multiline comment, try single-line comments
01782                             if (!$COMMENT_MATCHED) {
01783                                 foreach ($this->language_data['COMMENT_SINGLE'] as $comment_key => $comment_mark) {
01784                                     $com_len = strlen($comment_mark);
01785                                     $test_str = substr($part, $i, $com_len);
01786                                     if ($this->language_data['CASE_SENSITIVE'][GESHI_COMMENTS]) {
01787                                         $match = ($comment_mark == $test_str);
01788                                     }
01789                                     else {
01790                                         $match = (strtolower($comment_mark) == strtolower($test_str));
01791                                     }
01792                                     if ($match) {
01793                                         $COMMENT_MATCHED = true;
01794                                         if ($this->lexic_permissions['COMMENTS'][$comment_key]) {
01795                                             if (!$this->use_classes) {
01796                                                 $attributes = ' style="' . $this->language_data['STYLES']['COMMENTS'][$comment_key] . '"';
01797                                             }
01798                                             else {
01799                                                 $attributes = ' class="co' . $comment_key . '"';
01800                                             }
01801                                             $test_str = "<span$attributes>" . GeSHi::hsc($this->change_case($test_str));
01802                                         }
01803                                         else {
01804                                             $test_str = GeSHi::hsc($test_str);
01805                                         }
01806                                         $close_pos = strpos($part, "\n", $i);
01807                                         $oops = false;
01808                                         if ($close_pos === false) {
01809                                             $close_pos = strlen($part);
01810                                             $oops = true;
01811                                         }
01812                                         $test_str .= GeSHi::hsc(substr($part, $i + $com_len, $close_pos - $i - $com_len));
01813                                         if ($this->lexic_permissions['COMMENTS'][$comment_key]) {
01814                                             $test_str .= "</span>";
01815                                         }
01816                                         // Take into account that the comment might be the last in the source
01817                                         if (!$oops) {
01818                                           $test_str .= "\n";
01819                                         }
01820                                         $i = $close_pos;
01821                                         // parse the rest
01822                                         $result .= $this->parse_non_string_part($stuff_to_parse);
01823                                         $stuff_to_parse = '';
01824                                         break;
01825                                     }
01826                                 }
01827                             }
01828                         }
01829                         else if ($STRING_OPEN != '') {
01830                             // Otherwise, convert it to HTML form
01831                             if (strtolower($this->encoding) == 'utf-8') {
01832                                 //only escape <128 (we don't want to break multibyte chars)
01833                                 if (ord($char) < 128) {
01834                                     $char = GeSHi::hsc($char);
01835                                 }
01836                             }
01837                             else {
01838                                 //encode everthing
01839                                 $char = GeSHi::hsc($char);
01840                             }
01841                         }
01842                         // Where are we adding this char?
01843                         if (!$COMMENT_MATCHED) {
01844                             if (($STRING_OPEN == '') && !$CLOSE_STRING) {
01845                                 $stuff_to_parse .= $char;
01846                             }
01847                             else {
01848                                 $result .= $char;
01849                                 $CLOSE_STRING = false;
01850                             }
01851                         }
01852                         else {
01853                             $result .= $test_str;
01854                             $COMMENT_MATCHED = false;
01855                         }
01856                     }
01857                     // Parse the last bit
01858                     $result .= $this->parse_non_string_part($stuff_to_parse);
01859                     $stuff_to_parse = '';
01860                 }
01861                 else {
01862                     if ($STRICTATTRS != '') {
01863                         $part = str_replace("\n", "</span>\n<span$STRICTATTRS>", GeSHi::hsc($part));
01864                         $STRICTATTRS = '';
01865                     }
01866                     $result .= $part;
01867                 }
01868                 // Close the <span> that surrounds the block
01869                 if ($this->strict_mode && $this->language_data['STYLES']['SCRIPT'][$script_key] != '' &&
01870                     $this->lexic_permissions['SCRIPT']) {
01871                     $result .= '</span>';
01872                 }
01873             }
01874             else {
01875                 // Else not a block to highlight
01876                 $result .= GeSHi::hsc($part);
01877             }
01878         }
01879 
01880         // Parse the last stuff (redundant?)
01881         $result .= $this->parse_non_string_part($stuff_to_parse);
01882 
01883         // Lop off the very first and last spaces
01884         $result = substr($result, 1, -1);
01885 
01886         // Are we still in a string?
01887         if ($STRING_OPEN) {
01888             $result .= '</span>';
01889         }
01890 
01891         // We're finished: stop timing
01892         $this->set_time($start_time, microtime());
01893 
01894         return $this->finalise($result);
01895     }
01896 
01906     function indent($result) {
01908         if (false !== strpos($result, "\t")) {
01909             $lines = explode("\n", $result);
01910                $tab_width = $this->get_real_tab_width();
01911             foreach ($lines as $key => $line) {
01912                 if (false === strpos($line, "\t")) {
01913                     $lines[$key] = $line;
01914                     continue;
01915                 }
01916 
01917                 $pos = 0;
01918                 $length = strlen($line);
01919                 $result_line = '';
01920 
01921                 $IN_TAG = false;
01922                 for ($i = 0; $i < $length; $i++) {
01923                     $char = substr($line, $i, 1);
01924                     // Simple engine to work out whether we're in a tag.
01925                     // If we are we modify $pos. This is so we ignore HTML
01926                     // in the line and only workout the tab replacement
01927                     // via the actual content of the string
01928                     // This test could be improved to include strings in the
01929                     // html so that < or > would be allowed in user's styles
01930                     // (e.g. quotes: '<' '>'; or similar)
01931                     if ($IN_TAG && '>' == $char) {
01932                         $IN_TAG = false;
01933                         $result_line .= '>';
01934                         ++$pos;
01935                     }
01936                     else if (!$IN_TAG && '<' == $char) {
01937                         $IN_TAG = true;
01938                         $result_line .= '<';
01939                         ++$pos;
01940                     }
01941                     else if (!$IN_TAG && '&' == $char) {
01942                         $substr = substr($line, $i + 3, 4);
01943                         //$substr_5 = substr($line, 5, 1);
01944                         $posi = strpos($substr, ';');
01945                         if (false !== $posi) {
01946                             $pos += $posi + 3;
01947                         }
01948                         $result_line .= '&';
01949                     }
01950                     else if (!$IN_TAG && "\t" == $char) {
01951                         $str = '';
01952                         // OPTIMISE - move $strs out. Make an array:
01953                         // $tabs = array(
01954                         //  1 => '&nbsp;',
01955                         //  2 => '&nbsp; ',
01956                         //  3 => '&nbsp; &nbsp;' etc etc
01957                         // to use instead of building a string every time
01958                         $strs = array(0 => '&nbsp;', 1 => ' ');
01959                         for ($k = 0; $k < ($tab_width - (($i - $pos) % $tab_width)); $k++) $str .= $strs[$k % 2];
01960                         $result_line .= $str;
01961                         $pos += ($i - $pos) % $tab_width + 1;
01962 
01963                         if (false === strpos($line, "\t", $i + 1)) {
01964                             $result_line .= substr($line, $i + 1);
01965                             break;
01966                         }
01967                     }
01968                     else if ($IN_TAG) {
01969                         ++$pos;
01970                         $result_line .= $char;
01971                     }
01972                     else {
01973                         $result_line .= $char;
01974                         //++$pos;
01975                     }
01976                 }
01977                 $lines[$key] = $result_line;
01978             }
01979             $result = implode("\n", $lines);
01980         }
01981         // Other whitespace
01982         // BenBE: Fix to reduce the number of replacements to be done
01983         $result = str_replace("\n ", "\n&nbsp;", $result);
01984         $result = str_replace('  ', ' &nbsp;', $result);
01985 
01986         if ($this->line_numbers == GESHI_NO_LINE_NUMBERS) {
01987                if ($this->line_ending === null) {
01988                     $result = nl2br($result);
01989                } else {
01990                     $result = str_replace("\n", $this->line_ending, $result);
01991                }
01992           }
01993         return $result;
01994     }
01995 
02004     function change_case($instr) {
02005         if ($this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_UPPER) {
02006             return strtoupper($instr);
02007         }
02008         else if ($this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_LOWER) {
02009             return strtolower($instr);
02010         }
02011         return $instr;
02012     }
02013 
02025     function add_url_to_keyword($keyword, $group, $start_or_end) {
02026         if (!$this->keyword_links) {
02027             // Keyword links have been disabled
02028             return;
02029         }
02030 
02031         if (isset($this->language_data['URLS'][$group]) &&
02032             $this->language_data['URLS'][$group] != '' &&
02033             substr($keyword, 0, 5) != '&lt;/') {
02034             // There is a base group for this keyword
02035             if ($start_or_end == 'BEGIN') {
02036                 // HTML workaround... not good form (tm) but should work for 1.0.X
02037                 if ($keyword != '') {
02038                     // Old system: strtolower
02039                     //$keyword = ( $this->language_data['CASE_SENSITIVE'][$group] ) ? $keyword : strtolower($keyword);
02040                     // New system: get keyword from language file to get correct case
02041                     foreach ($this->language_data['KEYWORDS'][$group] as $word) {
02042                         if (strtolower($word) == strtolower($keyword)) {
02043                             break;
02044                         }
02045                     }
02046                     $word = ( substr($word, 0, 4) == '&lt;' ) ? substr($word, 4) : $word;
02047                     $word = ( substr($word, -4) == '&gt;' ) ? substr($word, 0, strlen($word) - 4) : $word;
02048                     if (!$word) return '';
02049 
02050                     return '<|UR1|"' .
02051                         str_replace(
02052                             array('{FNAME}', '.'),
02053                             array(GeSHi::hsc($word), '<DOT>'),
02054                             $this->language_data['URLS'][$group]
02055                         ) . '">';
02056                 }
02057                 return '';
02058             // HTML fix. Again, dirty hackage...
02059             }
02060             else if (!($this->language == 'html4strict' && ('&gt;' == $keyword || '&lt;' == $keyword))) {
02061                 return '</a>';
02062             }
02063         }
02064     }
02065 
02075     function parse_non_string_part(&$stuff_to_parse) {
02076         $stuff_to_parse = ' ' . GeSHi::hsc($stuff_to_parse);
02077         $stuff_to_parse_pregquote = preg_quote($stuff_to_parse, '/');
02078         $func = '$this->change_case';
02079         $func2 = '$this->add_url_to_keyword';
02080 
02081         //
02082         // Regular expressions
02083         //
02084         foreach ($this->language_data['REGEXPS'] as $key => $regexp) {
02085             if ($this->lexic_permissions['REGEXPS'][$key]) {
02086                 if (is_array($regexp)) {
02087                     $stuff_to_parse = preg_replace(
02088                         "/" .
02089                         str_replace('/', '\/', $regexp[GESHI_SEARCH]) .
02090                         "/{$regexp[GESHI_MODIFIERS]}",
02091                         "{$regexp[GESHI_BEFORE]}<|!REG3XP$key!>{$regexp[GESHI_REPLACE]}|>{$regexp[GESHI_AFTER]}",
02092                         $stuff_to_parse
02093                     );
02094                 }
02095                 else {
02096                     $stuff_to_parse = preg_replace( "/(" . str_replace('/', '\/', $regexp) . ")/", "<|!REG3XP$key!>\\1|>", $stuff_to_parse);
02097                 }
02098             }
02099         }
02100 
02101         //
02102         // Highlight numbers. This regexp sucks... anyone with a regexp that WORKS
02103         // here wins a cookie if they send it to me. At the moment there's two doing
02104         // almost exactly the same thing, except the second one prevents a number
02105         // being highlighted twice (eg <span...><span...>5</span></span>)
02106         // Put /NUM!/ in for the styles, which gets replaced at the end.
02107         //
02108         // NEW ONE: Brice Bernard
02109         //
02110         if ($this->lexic_permissions['NUMBERS'] && preg_match('#[0-9]#', $stuff_to_parse )) {
02111             $stuff_to_parse = preg_replace('/([-+]?\\b(?:[0-9]*\\.)?[0-9]+\\b)/', '<|/NUM!/>\\1|>', $stuff_to_parse);
02112         }
02113 
02114         // Highlight keywords
02115         // if there is a couple of alpha symbols there *might* be a keyword
02116         if (preg_match('#[a-zA-Z]{2,}#', $stuff_to_parse)) {
02117             foreach ($this->language_data['KEYWORDS'] as $k => $keywordset) {
02118                 if ($this->lexic_permissions['KEYWORDS'][$k]) {
02119                     foreach ($keywordset as $keyword) {
02120                         $keyword = preg_quote($keyword, '/');
02121                         //
02122                         // This replacement checks the word is on it's own (except if brackets etc
02123                         // are next to it), then highlights it. We don't put the color=" for the span
02124                         // in just yet - otherwise languages with the keywords "color" or "or" have
02125                         // a fit.
02126                         //
02127                         if (false !== stristr($stuff_to_parse_pregquote, $keyword )) {
02128                             $stuff_to_parse .= ' ';
02129                             // Might make a more unique string for putting the number in soon
02130                             // Basically, we don't put the styles in yet because then the styles themselves will
02131                             // get highlighted if the language has a CSS keyword in it (like CSS, for example ;))
02132                             $styles = "/$k/";
02133                             if ($this->language_data['CASE_SENSITIVE'][$k]) {
02134                                 $stuff_to_parse = preg_replace(
02135                                     "/([^a-zA-Z0-9\$_\|\#;>|^])($keyword)(?=[^a-zA-Z0-9_<\|%\-&])/e",
02136                                     "'\\1' . $func2('\\2', '$k', 'BEGIN') . '<|$styles>' . $func('\\2') . '|>' . $func2('\\2', '$k', 'END')",
02137                                     $stuff_to_parse
02138                                 );
02139                             }
02140                             else {
02141                                 // Change the case of the word.
02142                                 // hackage again... must... release... 1.2...
02143                                 if ('smarty' == $this->language) { $hackage = '\/'; } else { $hackage = ''; }
02144                                 $stuff_to_parse = preg_replace(
02145                                     "/([^a-zA-Z0-9\$_\|\#;>$hackage|^])($keyword)(?=[^a-zA-Z0-9_<\|%\-&])/ie",
02146                                     "'\\1' . $func2('\\2', '$k', 'BEGIN') . '<|$styles>' . $func('\\2') . '|>' . $func2('\\2', '$k', 'END')",
02147                                     $stuff_to_parse
02148                                 );
02149                             }
02150                             $stuff_to_parse = substr($stuff_to_parse, 0, strlen($stuff_to_parse) - 1);
02151                         }
02152                     }
02153                 }
02154             }
02155         }
02156 
02157         //
02158         // Now that's all done, replace /[number]/ with the correct styles
02159         //
02160         foreach ($this->language_data['KEYWORDS'] as $k => $kws) {
02161             if (!$this->use_classes) {
02162                 $attributes = ' style="' . $this->language_data['STYLES']['KEYWORDS'][$k] . '"';
02163             }
02164             else {
02165                 $attributes = ' class="kw' . $k . '"';
02166             }
02167             $stuff_to_parse = str_replace("/$k/", $attributes, $stuff_to_parse);
02168         }
02169 
02170         // Put number styles in
02171         if (!$this->use_classes && $this->lexic_permissions['NUMBERS']) {
02172             $attributes = ' style="' . $this->language_data['STYLES']['NUMBERS'][0] . '"';
02173         }
02174         else {
02175             $attributes = ' class="nu0"';
02176         }
02177         $stuff_to_parse = str_replace('/NUM!/', $attributes, $stuff_to_parse);
02178 
02179         //
02180         // Highlight methods and fields in objects
02181         //
02182         if ($this->lexic_permissions['METHODS'] && $this->language_data['OOLANG']) {
02183             foreach ($this->language_data['OBJECT_SPLITTERS'] as $key => $splitter) {
02184                 if (false !== stristr($stuff_to_parse, $splitter)) {
02185                     if (!$this->use_classes) {
02186                         $attributes = ' style="' . $this->language_data['STYLES']['METHODS'][$key] . '"';
02187                     }
02188                     else {
02189                         $attributes = ' class="me' . $key . '"';
02190                     }
02191                     $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);
02192                 }
02193             }
02194         }
02195 
02196         //
02197         // Highlight brackets. Yes, I've tried adding a semi-colon to this list.
02198         // You try it, and see what happens ;)
02199         // TODO: Fix lexic permissions not converting entities if shouldn't
02200         // be highlighting regardless
02201         //
02202         if ($this->lexic_permissions['BRACKETS']) {
02203             $code_entities_match = array('[', ']', '(', ')', '{', '}');
02204             if (!$this->use_classes) {
02205                 $code_entities_replace = array(
02206                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#91;|>',
02207                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#93;|>',
02208                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#40;|>',
02209                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#41;|>',
02210                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#123;|>',
02211                     '<| style="' . $this->language_data['STYLES']['BRACKETS'][0] . '">&#125;|>',
02212                 );
02213             }
02214             else {
02215                 $code_entities_replace = array(
02216                     '<| class="br0">&#91;|>',
02217                     '<| class="br0">&#93;|>',
02218                     '<| class="br0">&#40;|>',
02219                     '<| class="br0">&#41;|>',
02220                     '<| class="br0">&#123;|>',
02221                     '<| class="br0">&#125;|>',
02222                 );
02223             }
02224             $stuff_to_parse = str_replace( $code_entities_match,  $code_entities_replace, $stuff_to_parse );
02225         }
02226 
02227         //
02228         // Add class/style for regexps
02229         //
02230         foreach ($this->language_data['REGEXPS'] as $key => $regexp) {
02231             if ($this->lexic_permissions['REGEXPS'][$key]) {
02232                 if (!$this->use_classes) {
02233                     $attributes = ' style="' . $this->language_data['STYLES']['REGEXPS'][$key] . '"';
02234                 }
02235                 else {
02236                    if(is_array($this->language_data['REGEXPS'][$key]) &&
02237                             array_key_exists(GESHI_CLASS, $this->language_data['REGEXPS'][$key])) {
02238                         $attributes = ' class="'
02239                             . $this->language_data['REGEXPS'][$key][GESHI_CLASS] . '"';
02240                     }
02241                    else {
02242                        $attributes = ' class="re' . $key . '"';
02243                     }
02244                 }
02245                 $stuff_to_parse = str_replace("!REG3XP$key!", "$attributes", $stuff_to_parse);
02246             }
02247         }
02248 
02249         // Replace <DOT> with . for urls
02250         $stuff_to_parse = str_replace('<DOT>', '.', $stuff_to_parse);
02251         // Replace <|UR1| with <a href= for urls also
02252         if (isset($this->link_styles[GESHI_LINK])) {
02253             if ($this->use_classes) {
02254                 $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse);
02255             }
02256             else {
02257                 $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' style="' . $this->link_styles[GESHI_LINK] . '" href=', $stuff_to_parse);
02258             }
02259         }
02260         else {
02261             $stuff_to_parse = str_replace('<|UR1|', '<a' . $this->link_target . ' href=', $stuff_to_parse);
02262         }
02263 
02264         //
02265         // NOW we add the span thingy ;)
02266         //
02267 
02268         $stuff_to_parse = str_replace('<|', '<span', $stuff_to_parse);
02269         $stuff_to_parse = str_replace ( '|>', '</span>', $stuff_to_parse );
02270 
02271         return substr($stuff_to_parse, 1);
02272     }
02273 
02282     function set_time($start_time, $end_time) {
02283         $start = explode(' ', $start_time);
02284         $end = explode(' ', $end_time);
02285         $this->time = $end[0] + $end[1] - $start[0] - $start[1];
02286     }
02287 
02294     function get_time() {
02295         return $this->time;
02296     }
02297 
02304     function load_language($file_name) {
02305         $this->enable_highlighting();
02306         $language_data = array();
02307         require $file_name;
02308         // Perhaps some checking might be added here later to check that
02309         // $language data is a valid thing but maybe not
02310         $this->language_data = $language_data;
02311         // Set strict mode if should be set
02312         if ($this->language_data['STRICT_MODE_APPLIES'] == GESHI_ALWAYS) {
02313             $this->strict_mode = true;
02314         }
02315         // Set permissions for all lexics to true
02316         // so they'll be highlighted by default
02317         foreach ($this->language_data['KEYWORDS'] as $key => $words) {
02318             $this->lexic_permissions['KEYWORDS'][$key] = true;
02319         }
02320         foreach ($this->language_data['COMMENT_SINGLE'] as $key => $comment) {
02321             $this->lexic_permissions['COMMENTS'][$key] = true;
02322         }
02323         foreach ($this->language_data['REGEXPS'] as $key => $regexp) {
02324             $this->lexic_permissions['REGEXPS'][$key] = true;
02325         }
02326         // Set default class for CSS
02327         $this->overall_class = $this->language;
02328     }
02329 
02339     function finalise($parsed_code) {
02340         // Remove end parts of important declarations
02341         // This is BUGGY!! My fault for bad code: fix coming in 1.2
02342         // @todo Remove this crap
02343         if ($this->enable_important_blocks &&
02344             (strstr($parsed_code, GeSHi::hsc(GESHI_START_IMPORTANT)) === false)) {
02345             $parsed_code = str_replace(GeSHi::hsc(GESHI_END_IMPORTANT), '', $parsed_code);
02346         }
02347 
02348         // Add HTML whitespace stuff if we're using the <div> header
02349         if ($this->header_type != GESHI_HEADER_PRE) {
02350             $parsed_code = $this->indent($parsed_code);
02351         }
02352 
02353         // purge some unnecessary stuff
02354         $parsed_code = preg_replace('#<span[^>]+>(\s*)</span>#', '\\1', $parsed_code);
02355         $parsed_code = preg_replace('#<div[^>]+>(\s*)</div>#', '\\1', $parsed_code);
02356 
02357         // If we are using IDs for line numbers, there needs to be an overall
02358         // ID set to prevent collisions.
02359         if ($this->add_ids && !$this->overall_id) {
02360             $this->overall_id = 'geshi-' . substr(md5(microtime()), 0, 4);
02361         }
02362 
02363         // If we're using line numbers, we insert <li>s and appropriate
02364         // markup to style them (otherwise we don't need to do anything)
02365         if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
02366             // If we're using the <pre> header, we shouldn't add newlines because
02367             // the <pre> will line-break them (and the <li>s already do this for us)
02368             $ls = ($this->header_type != GESHI_HEADER_PRE) ? "\n" : '';
02369             // Get code into lines
02370             $code = explode("\n", $parsed_code);
02371             // Set vars to defaults for following loop
02372             $parsed_code = '';
02373             $i = 0;
02374             $attrs = array();
02375 
02376             // Foreach line...
02377             foreach ($code as $line) {
02378                 // Make lines have at least one space in them if they're empty
02379                 // BenBE: Checking emptiness using trim instead of relying on blanks
02380                 if ('' == trim($line)) {
02381                     $line = '&nbsp;';
02382                 }
02383                 // If this is a "special line"...
02384                 if ($this->line_numbers == GESHI_FANCY_LINE_NUMBERS &&
02385                     $i % $this->line_nth_row == ($this->line_nth_row - 1)) {
02386                     // Set the attributes to style the line
02387                     if ($this->use_classes) {
02388                         //$attr = ' class="li2"';
02389                         $attrs['class'][] = 'li2';
02390                         $def_attr = ' class="de2"';
02391                     }
02392                     else {
02393                         //$attr = ' style="' . $this->line_style2 . '"';
02394                         $attrs['style'][] = $this->line_style2;
02395                         // This style "covers up" the special styles set for special lines
02396                         // so that styles applied to special lines don't apply to the actual
02397                         // code on that line
02398                         $def_attr = ' style="' . $this->code_style . '"';
02399                     }
02400                     // Span or div?
02401                     $start = "<div$def_attr>";
02402                     $end = '</div>';
02403                 }
02404                 else {
02405                     if ($this->use_classes) {
02406                         //$attr = ' class="li1"';
02407                         $attrs['class'][] = 'li1';
02408                         $def_attr = ' class="de1"';
02409                     }
02410                     else {
02411                         //$attr = ' style="' . $this->line_style1 . '"';
02412                         $attrs['style'][] = $this->line_style1;
02413                         $def_attr = ' style="' . $this->code_style . '"';
02414                     }
02415                     $start = "<div$def_attr>";
02416                     $end = '</div>';
02417                 }
02418 
02419                 ++$i;
02420                 // Are we supposed to use ids? If so, add them
02421                 if ($this->add_ids) {
02422                     $attrs['id'][] = "$this->overall_id-$i";
02423                 }
02424                 if ($this->use_classes && in_array($i, $this->highlight_extra_lines)) {
02425                     $attrs['class'][] = 'ln-xtra';
02426                 }
02427                 if (!$this->use_classes && in_array($i, $this->highlight_extra_lines)) {
02428                     $attrs['style'][] = $this->highlight_extra_lines_style;
02429                 }
02430 
02431                 // Add in the line surrounded by appropriate list HTML
02432                 $attr_string = ' ';
02433                 foreach ($attrs as $key => $attr) {
02434                     $attr_string .= $key . '="' . implode(' ', $attr) . '" ';
02435                 }
02436                 $attr_string = substr($attr_string, 0, -1);
02437                 $parsed_code .= "<li$attr_string>$start$line$end</li>$ls";
02438                 $attrs = array();
02439             }
02440         }
02441         else {
02442             // No line numbers, but still need to handle highlighting lines extra.
02443             // Have to use divs so the full width of the code is highlighted
02444             $code = explode("\n", $parsed_code);
02445             $parsed_code = '';
02446             $i = 0;
02447             foreach ($code as $line) {
02448                 // Make lines have at least one space in them if they're empty
02449                 // BenBE: Checking emptiness using trim instead of relying on blanks
02450                 if ('' == trim($line)) {
02451                     $line = '&nbsp;';
02452                 }
02453                 if (in_array(++$i, $this->highlight_extra_lines)) {
02454                     if ($this->use_classes) {
02455                         $parsed_code .= '<div class="ln-xtra">';
02456                     }
02457                     else {
02458                         $parsed_code .= "<div style=\"{$this->highlight_extra_lines_style}\">";
02459                     }
02460                     // Remove \n because it stuffs up <pre> header
02461                     $parsed_code .= $line . "</div>";
02462                 }
02463                 else {
02464                     $parsed_code .= $line . "\n";
02465                 }
02466             }
02467         }
02468 
02469         if ($this->header_type == GESHI_HEADER_PRE) {
02470             // enforce line numbers when using pre
02471             $parsed_code = str_replace('<li></li>', '<li>&nbsp;</li>', $parsed_code);
02472         }
02473 
02474         return $this->header() . chop($parsed_code) . $this->footer();
02475     }
02476 
02484     function header() {
02485         // Get attributes needed
02486         $attributes = $this->get_attributes();
02487 
02488         $ol_attributes = '';
02489 
02490         if ($this->line_numbers_start != 1) {
02491             $ol_attributes .= ' start="' . $this->line_numbers_start . '"';
02492         }
02493 
02494         // Get the header HTML
02495         $header = $this->format_header_content();
02496 
02497         if (GESHI_HEADER_NONE == $this->header_type) {
02498             if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
02499                 return "$header<ol$ol_attributes>";
02500             }
02501             return $header .
02502                 ($this->force_code_block ? '<div>' : '');
02503         }
02504 
02505         // Work out what to return and do it
02506         if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
02507             if ($this->header_type == GESHI_HEADER_PRE) {
02508                 return "<pre$attributes>$header<ol$ol_attributes>";
02509             }
02510             else if ($this->header_type == GESHI_HEADER_DIV) {
02511                 return "<div$attributes>$header<ol$ol_attributes>";
02512             }
02513         }
02514         else {
02515             if ($this->header_type == GESHI_HEADER_PRE) {
02516                 return "<pre$attributes>$header"  .
02517                     ($this->force_code_block ? '<div>' : '');
02518             }
02519             else if ($this->header_type == GESHI_HEADER_DIV) {
02520                 return "<div$attributes>$header" .
02521                     ($this->force_code_block ? '<div>' : '');
02522             }
02523         }
02524     }
02525 
02533     function format_header_content() {
02534         $header = $this->header_content;
02535         if ($header) {
02536             if ($this->header_type == GESHI_HEADER_PRE) {
02537                 $header = str_replace("\n", '', $header);
02538             }
02539             $header = $this->replace_keywords($header);
02540 
02541             if ($this->use_classes) {
02542                 $attr = ' class="head"';
02543             }
02544             else {
02545                 $attr = " style=\"{$this->header_content_style}\"";
02546             }
02547             return "<div$attr>$header</div>";
02548         }
02549     }
02550 
02558     function footer() {
02559         $footer_content = $this->format_footer_content();
02560 
02561         if (GESHI_HEADER_NONE == $this->header_type) {
02562             return ($this->line_numbers != GESHI_NO_LINE_NUMBERS) ? '</ol>' . $footer_content
02563                 : $footer_content;
02564         }
02565 
02566         if ($this->header_type == GESHI_HEADER_DIV) {
02567             if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
02568                 return "</ol>$footer_content</div>";
02569             }
02570             return ($this->force_code_block ? '</div>' : '') .
02571                 "$footer_content</div>";
02572         }
02573         else {
02574             if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
02575                 return "</ol>$footer_content</pre>";
02576             }
02577             return ($this->force_code_block ? '</div>' : '') .
02578                 "$footer_content</pre>";
02579         }
02580     }
02581 
02589     function format_footer_content() {
02590         $footer = $this->footer_content;
02591         if ($footer) {
02592             if ($this->header_type == GESHI_HEADER_PRE) {
02593                 $footer = str_replace("\n", '', $footer);;
02594             }
02595             $footer = $this->replace_keywords($footer);
02596 
02597             if ($this->use_classes) {
02598                 $attr = ' class="foot"';
02599             }
02600             else {
02601                 $attr = " style=\"{$this->footer_content_style}\"";
02602             }
02603             return "<div$attr>$footer</div>";
02604         }
02605     }
02606 
02616     function replace_keywords($instr) {
02617         $keywords = $replacements = array();
02618 
02619         $keywords[] = '<TIME>';
02620         $keywords[] = '{TIME}';
02621         $replacements[] = $replacements[] = number_format($this->get_time(), 3);
02622 
02623         $keywords[] = '<LANGUAGE>';
02624         $keywords[] = '{LANGUAGE}';
02625         $replacements[] = $replacements[] = $this->language;
02626 
02627         $keywords[] = '<VERSION>';
02628         $keywords[] = '{VERSION}';
02629         $replacements[] = $replacements[] = GESHI_VERSION;
02630 
02631         return str_replace($keywords, $replacements, $instr);
02632     }
02633 
02643     function get_attributes() {
02644         $attributes = '';
02645 
02646         if ($this->overall_class != '') {
02647             $attributes .= " class=\"{$this->overall_class}\"";
02648         }
02649         if ($this->overall_id != '') {
02650             $attributes .= " id=\"{$this->overall_id}\"";
02651         }
02652         if ($this->overall_style != '') {
02653             $attributes .= ' style="' . $this->overall_style . '"';
02654         }
02655         return $attributes;
02656     }
02657 
02710     function hsc($string, $quote_style=ENT_COMPAT) {
02711         // init
02712         $aTransSpecchar = array(
02713             '&' => '&amp;',
02714             '"' => '&quot;',
02715             '<' => '&lt;',
02716             '>' => '&gt;'
02717             );                      // ENT_COMPAT set
02718 
02719         if (ENT_NOQUOTES == $quote_style)       // don't convert double quotes
02720         {
02721             unset($aTransSpecchar['"']);
02722         }
02723         elseif (ENT_QUOTES == $quote_style)     // convert single quotes as well
02724         {
02725             $aTransSpecchar["'"] = '&#39;'; // (apos) htmlspecialchars() uses '&#039;'
02726         }
02727 
02728         // return translated string
02729         return strtr($string,$aTransSpecchar);
02730     }
02731 
02741     function get_stylesheet($economy_mode = true) {
02742         // If there's an error, chances are that the language file
02743         // won't have populated the language data file, so we can't
02744         // risk getting a stylesheet...
02745         if ($this->error) {
02746             return '';
02747         }
02748         // First, work out what the selector should be. If there's an ID,
02749         // that should be used, the same for a class. Otherwise, a selector
02750         // of '' means that these styles will be applied anywhere
02751         $selector = ($this->overall_id != '') ? "#{$this->overall_id} " : '';
02752         $selector = ($selector == '' && $this->overall_class != '') ? ".{$this->overall_class} " : $selector;
02753 
02754         // Header of the stylesheet
02755         if (!$economy_mode) {
02756             $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";
02757          } else {
02758             $stylesheet = '/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */' . "\n";
02759         }
02760 
02761         // Set the <ol> to have no effect at all if there are line numbers
02762         // (<ol>s have margins that should be destroyed so all layout is
02763         // controlled by the set_overall_style method, which works on the
02764         // <pre> or <div> container). Additionally, set default styles for lines
02765         if (!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) {
02766             //$stylesheet .= "$selector, {$selector}ol, {$selector}ol li {margin: 0;}\n";
02767             $stylesheet .= "$selector.de1, $selector.de2 {{$this->code_style}}\n";
02768         }
02769 
02770         // Add overall styles
02771         if (!$economy_mode || $this->overall_style != '') {
02772             $stylesheet .= "$selector {{$this->overall_style}}\n";
02773         }
02774 
02775         // Add styles for links
02776         foreach ($this->link_styles as $key => $style) {
02777             if (!$economy_mode || $key == GESHI_LINK && $style != '') {
02778                 $stylesheet .= "{$selector}a:link {{$style}}\n";
02779             }
02780             if (!$economy_mode || $key == GESHI_HOVER && $style != '') {
02781                 $stylesheet .= "{$selector}a:hover {{$style}}\n";
02782             }
02783             if (!$economy_mode || $key == GESHI_ACTIVE && $style != '') {
02784                 $stylesheet .= "{$selector}a:active {{$style}}\n";
02785             }
02786             if (!$economy_mode || $key == GESHI_VISITED && $style != '') {
02787                 $stylesheet .= "{$selector}a:visited {{$style}}\n";
02788             }
02789         }
02790 
02791         // Header and footer
02792         if (!$economy_mode || $this->header_content_style != '') {
02793             $stylesheet .= "$selector.head {{$this->header_content_style}}\n";
02794         }
02795         if (!$economy_mode || $this->footer_content_style != '') {
02796             $stylesheet .= "$selector.foot {{$this->footer_content_style}}\n";
02797         }
02798 
02799         // Styles for important stuff
02800         if (!$economy_mode || $this->important_styles != '') {
02801             $stylesheet .= "$selector.imp {{$this->important_styles}}\n";
02802         }
02803 
02804         // Styles for lines being highlighted extra
02805         if (!$economy_mode || count($this->highlight_extra_lines)) {
02806             $stylesheet .= "$selector.ln-xtra {{$this->highlight_extra_lines_style}}\n";
02807         }
02808 
02809         // Simple line number styles
02810         if (!$economy_mode || ($this->line_numbers != GESHI_NO_LINE_NUMBERS && $this->line_style1 != '')) {
02811             $stylesheet .= "{$selector}li {{$this->line_style1}}\n";
02812         }
02813 
02814         // If there is a style set for fancy line numbers, echo it out
02815         if (!$economy_mode || ($this->line_numbers == GESHI_FANCY_LINE_NUMBERS && $this->line_style2 != '')) {
02816             $stylesheet .= "{$selector}li.li2 {{$this->line_style2}}\n";
02817         }
02818 
02819         foreach ($this->language_data['STYLES']['KEYWORDS'] as $group => $styles) {
02820             if (!$economy_mode || !($economy_mode && (!$this->lexic_permissions['KEYWORDS'][$group] || $styles == ''))) {
02821                 $stylesheet .= "$selector.kw$group {{$styles}}\n";
02822             }
02823         }
02824         foreach ($this->language_data['STYLES']['COMMENTS'] as $group => $styles) {
02825             if (!$economy_mode || !($economy_mode && $styles == '') &&
02826                 !($economy_mode && !$this->lexic_permissions['COMMENTS'][$group])) {
02827                 $stylesheet .= "$selector.co$group {{$styles}}\n";
02828             }
02829         }
02830         foreach ($this->language_data['STYLES']['ESCAPE_CHAR'] as $group => $styles) {
02831             if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode &&
02832                 !$this->lexic_permissions['ESCAPE_CHAR'])) {
02833                 $stylesheet .= "$selector.es$group {{$styles}}\n";
02834             }
02835         }
02836         foreach ($this->language_data['STYLES']['SYMBOLS'] as $group => $styles) {
02837             if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode &&
02838                 !$this->lexic_permissions['BRACKETS'])) {
02839                 $stylesheet .= "$selector.br$group {{$styles}}\n";
02840             }
02841         }
02842         foreach ($this->language_data['STYLES']['STRINGS'] as $group => $styles) {
02843             if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode &&
02844                 !$this->lexic_permissions['STRINGS'])) {
02845                 $stylesheet .= "$selector.st$group {{$styles}}\n";
02846             }
02847         }
02848         foreach ($this->language_data['STYLES']['NUMBERS'] as $group => $styles) {
02849             if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode &&
02850                 !$this->lexic_permissions['NUMBERS'])) {
02851                 $stylesheet .= "$selector.nu$group {{$styles}}\n";
02852             }
02853         }
02854         foreach ($this->language_data['STYLES']['METHODS'] as $group => $styles) {
02855             if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode &&
02856                 !$this->lexic_permissions['METHODS'])) {
02857                 $stylesheet .= "$selector.me$group {{$styles}}\n";
02858             }
02859         }
02860         foreach ($this->language_data['STYLES']['SCRIPT'] as $group => $styles) {
02861             if (!$economy_mode || !($economy_mode && $styles == '')) {
02862                 $stylesheet .= "$selector.sc$group {{$styles}}\n";
02863             }
02864         }
02865         foreach ($this->language_data['STYLES']['REGEXPS'] as $group => $styles) {
02866             if (!$economy_mode || !($economy_mode && $styles == '') && !($economy_mode &&
02867                 !$this->lexic_permissions['REGEXPS'][$group])) {
02868                 if (is_array($this->language_data['REGEXPS'][$group]) &&
02869                          array_key_exists(GESHI_CLASS,
02870                                     $this->language_data['REGEXPS'][$group])) {
02871                     $stylesheet .= "$selector.";
02872                     $stylesheet .= $this->language_data['REGEXPS'][$group][GESHI_CLASS];
02873                     $stylesheet .= " {{$styles}}\n";
02874                 }
02875                 else {
02876                     $stylesheet .= "$selector.re$group {{$styles}}\n";
02877                 }
02878             }
02879         }
02880 
02881         return $stylesheet;
02882     }
02883 
02884 } // End Class GeSHi
02885 
02886 
02887 if (!function_exists('geshi_highlight')) {
02899     function geshi_highlight($string, $language, $path = null, $return = false) {
02900         $geshi = new GeSHi($string, $language, $path);
02901         $geshi->set_header_type(GESHI_HEADER_NONE);
02902         if ($return) {
02903             return '<code>' . $geshi->parse_code() . '</code>';
02904         }
02905         echo '<code>' . $geshi->parse_code() . '</code>';
02906         if ($geshi->error()) {
02907             return false;
02908         }
02909         return true;
02910     }
02911 }
02912 
02913 ?>

Erzeugt am Thu May 14 00:55:48 2009 für OpenRat von  doxygen 1.5.8