s have margins that should be destroyed so all layout is
// controlled by the set_overall_style method, which works on the
// or container). Additionally, set default styles for lines
if (!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) {
//$stylesheet .= "$selector, {$selector}ol, {$selector}ol li {margin: 0;}\n";
$stylesheet .= "$selector.de1, $selector.de2 {{$this->code_style}}\n";
}
// Add overall styles
// note: neglect economy_mode, empty styles are meaningless
if ($this->overall_style != '') {
$stylesheet .= "$selector {{$this->overall_style}}\n";
}
// Add styles for links
// note: economy mode does not make _any_ sense here
// either the style is empty and thus no selector is needed
// or the appropriate key is given.
foreach ($this->link_styles as $key => $style) {
if ($style != '') {
switch ($key) {
case GESHI_LINK:
$stylesheet .= "{$selector}a:link {{$style}}\n";
break;
case GESHI_HOVER:
$stylesheet .= "{$selector}a:hover {{$style}}\n";
break;
case GESHI_ACTIVE:
$stylesheet .= "{$selector}a:active {{$style}}\n";
break;
case GESHI_VISITED:
$stylesheet .= "{$selector}a:visited {{$style}}\n";
break;
}
}
}
// Header and footer
// note: neglect economy_mode, empty styles are meaningless
if ($this->header_content_style != '') {
$stylesheet .= "$selector.head {{$this->header_content_style}}\n";
}
if ($this->footer_content_style != '') {
$stylesheet .= "$selector.foot {{$this->footer_content_style}}\n";
}
// Styles for important stuff
// note: neglect economy_mode, empty styles are meaningless
if ($this->important_styles != '') {
$stylesheet .= "$selector.imp {{$this->important_styles}}\n";
}
// Simple line number styles
if ((!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) && $this->line_style1 != '') {
$stylesheet .= "{$selector}li, {$selector}.li1 {{$this->line_style1}}\n";
}
if ((!$economy_mode || $this->line_numbers != GESHI_NO_LINE_NUMBERS) && $this->table_linenumber_style != '') {
$stylesheet .= "{$selector}.ln {{$this->table_linenumber_style}}\n";
}
// If there is a style set for fancy line numbers, echo it out
if ((!$economy_mode || $this->line_numbers == GESHI_FANCY_LINE_NUMBERS) && $this->line_style2 != '') {
$stylesheet .= "{$selector}.li2 {{$this->line_style2}}\n";
}
// note: empty styles are meaningless
foreach ($this->language_data['STYLES']['KEYWORDS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode ||
(isset($this->lexic_permissions['KEYWORDS'][$group]) &&
$this->lexic_permissions['KEYWORDS'][$group]))) {
$stylesheet .= "$selector.kw$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['COMMENTS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode ||
(isset($this->lexic_permissions['COMMENTS'][$group]) &&
$this->lexic_permissions['COMMENTS'][$group]) ||
(!empty($this->language_data['COMMENT_REGEXP']) &&
!empty($this->language_data['COMMENT_REGEXP'][$group])))) {
$stylesheet .= "$selector.co$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['ESCAPE_CHAR'] as $group => $styles) {
if ($styles != '' && (!$economy_mode || $this->lexic_permissions['ESCAPE_CHAR'])) {
// NEW: since 1.0.8 we have to handle hardescapes
if ($group === 'HARD') {
$group = '_h';
}
$stylesheet .= "$selector.es$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['BRACKETS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode || $this->lexic_permissions['BRACKETS'])) {
$stylesheet .= "$selector.br$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['SYMBOLS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode || $this->lexic_permissions['SYMBOLS'])) {
$stylesheet .= "$selector.sy$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['STRINGS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode || $this->lexic_permissions['STRINGS'])) {
// NEW: since 1.0.8 we have to handle hardquotes
if ($group === 'HARD') {
$group = '_h';
}
$stylesheet .= "$selector.st$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['NUMBERS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode || $this->lexic_permissions['NUMBERS'])) {
$stylesheet .= "$selector.nu$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['METHODS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode || $this->lexic_permissions['METHODS'])) {
$stylesheet .= "$selector.me$group {{$styles}}\n";
}
}
// note: neglect economy_mode, empty styles are meaningless
foreach ($this->language_data['STYLES']['SCRIPT'] as $group => $styles) {
if ($styles != '') {
$stylesheet .= "$selector.sc$group {{$styles}}\n";
}
}
foreach ($this->language_data['STYLES']['REGEXPS'] as $group => $styles) {
if ($styles != '' && (!$economy_mode ||
(isset($this->lexic_permissions['REGEXPS'][$group]) &&
$this->lexic_permissions['REGEXPS'][$group]))) {
if (is_array($this->language_data['REGEXPS'][$group]) &&
array_key_exists(GESHI_CLASS, $this->language_data['REGEXPS'][$group])) {
$stylesheet .= "$selector.";
$stylesheet .= $this->language_data['REGEXPS'][$group][GESHI_CLASS];
$stylesheet .= " {{$styles}}\n";
} else {
$stylesheet .= "$selector.re$group {{$styles}}\n";
}
}
}
// Styles for lines being highlighted extra
if (!$economy_mode || (count($this->highlight_extra_lines)!=count($this->highlight_extra_lines_styles))) {
$stylesheet .= "{$selector}.ln-xtra, {$selector}li.ln-xtra, {$selector}div.ln-xtra {{$this->highlight_extra_lines_style}}\n";
}
$stylesheet .= "{$selector}span.xtra { display:block; }\n";
foreach ($this->highlight_extra_lines_styles as $lineid => $linestyle) {
$stylesheet .= "{$selector}.lx$lineid, {$selector}li.lx$lineid, {$selector}div.lx$lineid {{$linestyle}}\n";
}
return $stylesheet;
}
/**
* Get's the style that is used for the specified line
*
* @param int The line number information is requested for
* @access private
* @since 1.0.7.21
*/
function get_line_style($line) {
//$style = null;
$style = null;
if (isset($this->highlight_extra_lines_styles[$line])) {
$style = $this->highlight_extra_lines_styles[$line];
} else { // if no "extra" style assigned
$style = $this->highlight_extra_lines_style;
}
return $style;
}
/**
* this functions creates an optimized regular expression list
* of an array of strings.
*
* Example:
* $list = array('faa', 'foo', 'foobar');
* => string 'f(aa|oo(bar)?)'
*
* @param $list array of (unquoted) strings
* @param $regexp_delimiter your regular expression delimiter, @see preg_quote()
* @return string for regular expression
* @author Milian Wolff
* @since 1.0.8
* @access private
*/
function optimize_regexp_list($list, $regexp_delimiter = '/') {
$regex_chars = array('.', '\\', '+', '-', '*', '?', '[', '^', ']', '$',
'(', ')', '{', '}', '=', '!', '<', '>', '|', ':', $regexp_delimiter);
sort($list);
$regexp_list = array('');
$num_subpatterns = 0;
$list_key = 0;
// the tokens which we will use to generate the regexp list
$tokens = array();
$prev_keys = array();
// go through all entries of the list and generate the token list
$cur_len = 0;
for ($i = 0, $i_max = count($list); $i < $i_max; ++$i) {
if ($cur_len > GESHI_MAX_PCRE_LENGTH) {
// seems like the length of this pcre is growing exorbitantly
$regexp_list[++$list_key] = $this->_optimize_regexp_list_tokens_to_string($tokens);
$num_subpatterns = substr_count($regexp_list[$list_key], '(?:');
$tokens = array();
$cur_len = 0;
}
$level = 0;
$entry = preg_quote((string) $list[$i], $regexp_delimiter);
$pointer = &$tokens;
// properly assign the new entry to the correct position in the token array
// possibly generate smaller common denominator keys
while (true) {
// get the common denominator
if (isset($prev_keys[$level])) {
if ($prev_keys[$level] == $entry) {
// this is a duplicate entry, skip it
continue 2;
}
$char = 0;
while (isset($entry[$char]) && isset($prev_keys[$level][$char])
&& $entry[$char] == $prev_keys[$level][$char]) {
++$char;
}
if ($char > 0) {
// this entry has at least some chars in common with the current key
if ($char == strlen($prev_keys[$level])) {
// current key is totally matched, i.e. this entry has just some bits appended
$pointer = &$pointer[$prev_keys[$level]];
} else {
// only part of the keys match
$new_key_part1 = substr($prev_keys[$level], 0, $char);
$new_key_part2 = substr($prev_keys[$level], $char);
if (in_array($new_key_part1[0], $regex_chars)
|| in_array($new_key_part2[0], $regex_chars)) {
// this is bad, a regex char as first character
$pointer[$entry] = array('' => true);
array_splice($prev_keys, $level, count($prev_keys), $entry);
$cur_len += strlen($entry);
continue;
} else {
// relocate previous tokens
$pointer[$new_key_part1] = array($new_key_part2 => $pointer[$prev_keys[$level]]);
unset($pointer[$prev_keys[$level]]);
$pointer = &$pointer[$new_key_part1];
// recreate key index
array_splice($prev_keys, $level, count($prev_keys), array($new_key_part1, $new_key_part2));
$cur_len += strlen($new_key_part2);
}
}
++$level;
$entry = substr($entry, $char);
continue;
}
// else: fall trough, i.e. no common denominator was found
}
if ($level == 0 && !empty($tokens)) {
// we can dump current tokens into the string and throw them away afterwards
$new_entry = $this->_optimize_regexp_list_tokens_to_string($tokens);
$new_subpatterns = substr_count($new_entry, '(?:');
if (GESHI_MAX_PCRE_SUBPATTERNS && $num_subpatterns + $new_subpatterns > GESHI_MAX_PCRE_SUBPATTERNS) {
$regexp_list[++$list_key] = $new_entry;
$num_subpatterns = $new_subpatterns;
} else {
if (!empty($regexp_list[$list_key])) {
$new_entry = '|' . $new_entry;
}
$regexp_list[$list_key] .= $new_entry;
$num_subpatterns += $new_subpatterns;
}
$tokens = array();
$cur_len = 0;
}
// no further common denominator found
$pointer[$entry] = array('' => true);
array_splice($prev_keys, $level, count($prev_keys), $entry);
$cur_len += strlen($entry);
break;
}
unset($list[$i]);
}
// make sure the last tokens get converted as well
$new_entry = $this->_optimize_regexp_list_tokens_to_string($tokens);
if (GESHI_MAX_PCRE_SUBPATTERNS && $num_subpatterns + substr_count($new_entry, '(?:') > GESHI_MAX_PCRE_SUBPATTERNS) {
if ( !empty($regexp_list[$list_key]) ) {
++$list_key;
}
$regexp_list[$list_key] = $new_entry;
} else {
if (!empty($regexp_list[$list_key])) {
$new_entry = '|' . $new_entry;
}
$regexp_list[$list_key] .= $new_entry;
}
return $regexp_list;
}
/**
* this function creates the appropriate regexp string of an token array
* you should not call this function directly, @see $this->optimize_regexp_list().
*
* @param &$tokens array of tokens
* @param $recursed bool to know wether we recursed or not
* @return string
* @author Milian Wolff
* @since 1.0.8
* @access private
*/
function _optimize_regexp_list_tokens_to_string(&$tokens, $recursed = false) {
$list = '';
foreach ($tokens as $token => $sub_tokens) {
$list .= $token;
$close_entry = isset($sub_tokens['']);
unset($sub_tokens['']);
if (!empty($sub_tokens)) {
$list .= '(?:' . $this->_optimize_regexp_list_tokens_to_string($sub_tokens, true) . ')';
if ($close_entry) {
// make sub_tokens optional
$list .= '?';
}
}
$list .= '|';
}
if (!$recursed) {
// do some optimizations
// common trailing strings
// BUGGY!
//$list = preg_replace_callback('#(?<=^|\:|\|)\w+?(\w+)(?:\|.+\1)+(?=\|)#', create_function(
// '$matches', 'return "(?:" . preg_replace("#" . preg_quote($matches[1], "#") . "(?=\||$)#", "", $matches[0]) . ")" . $matches[1];'), $list);
// (?:p)? => p?
$list = preg_replace('#\(\?\:(.)\)\?#', '\1?', $list);
// (?:a|b|c|d|...)? => [abcd...]?
// TODO: a|bb|c => [ac]|bb
static $callback_2;
if (!isset($callback_2)) {
$callback_2 = create_function('$matches', 'return "[" . str_replace("|", "", $matches[1]) . "]";');
}
$list = preg_replace_callback('#\(\?\:((?:.\|)+.)\)#', $callback_2, $list);
}
// return $list without trailing pipe
return substr($list, 0, -1);
}
} // End Class GeSHi
if (!function_exists('geshi_highlight')) {
/**
* Easy way to highlight stuff. Behaves just like highlight_string
*
* @param string The code to highlight
* @param string The language to highlight the code in
* @param string The path to the language files. You can leave this blank if you need
* as from version 1.0.7 the path should be automatically detected
* @param boolean Whether to return the result or to echo
* @return string The code highlighted (if $return is true)
* @since 1.0.2
*/
function geshi_highlight($string, $language, $path = null, $return = false) {
$geshi = new GeSHi($string, $language, $path);
$geshi->set_header_type(GESHI_HEADER_NONE);
if ($return) {
return '' . $geshi->parse_code() . '
';
}
echo '' . $geshi->parse_code() . '
';
if ($geshi->error()) {
return false;
}
return true;
}
}
?>