00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00030 class Textile {
00037 var
$options = array();
00038
00046 var
$urlre;
00047
00055 var
$punct;
00056
00064 var
$valignre;
00065
00073 var
$tblalignre;
00074
00082 var
$halignre;
00083
00091 var
$alignre;
00092
00100 var
$imgalignre;
00101
00109 var
$clstypadre;
00110
00118 var
$clstyre;
00119
00127 var
$clstyfiltre;
00128
00136 var
$codere;
00137
00145 var
$blocktags;
00146
00152 var
$links = array();
00153
00165 var
$repl = array();
00166
00173 var
$tmp = array();
00174
00186 function
Textile($options = array()) {
00187 $this->options =
$options;
00188 $this->options['
filters'] = ($this->options['
filters'] ? $this->options['
filters'] : array());
00189 $this->options['
charset'] = ($this->options['
charset'] ? $this->options['
charset'] : 'iso-8859-1');
00190 $this->options['
char_encoding'] = (isset($this->options['
char_encoding']) ? $this->options['
char_encoding'] : 1);
00191 $this->options['do_quotes'] = (isset($this->options['do_quotes']) ? $this->options['do_quotes'] : 1);
00192 $this->options['
trim_spaces'] = (isset($this->options['
trim_spaces']) ? $this->options['
trim_spaces'] : 0);
00193 $this->options['smarty_mode'] = (isset($this->options['smarty_mode']) ? $this->options['smarty_mode'] : 1);
00194 $this->options['
preserve_spaces'] = (iset($this->options['
preserve_spaces']) ? $this->options['preserve_spaaces'] : 0);
00195 $this->options['
head_offset'] = (isset($this->options['
head_offset']) ? $this->options['
head_offset'] : 0);
00196
00197
if (is_array($this->options['
css'])) {
00198 $this->
css($this->options['
css']);
00199 }
00200 $this->options['macros'] = ($this->options['macros'] ? $this->options['macros'] : $this->
default_macros());
00201
if (isset($this->options['
flavor'])) {
00202 $this->
flavor($this->options['
flavor']);
00203 }
else {
00204 $this->
flavor('xhtml1/
css');
00205 }
00206 $this->
_create_re();
00207 }
00208
00209
00210
00221 function
set($opt, $value = NULL) {
00222
if (is_array($opt)) {
00223 foreach ($opt as $opt => $value) {
00224 $this->set($opt, $value);
00225 }
00226 }
else {
00227
00228
00229
if ($opt == '
charset') {
00230 $this->
charset($value);
00231 } elseif ($opt == '
css') {
00232 $this->css($value);
00233 } elseif ($opt == '
flavor') {
00234 $this->flavor($value);
00235 }
else {
00236 $this->options[$opt] = $value;
00237 }
00238 }
00239 }
00240
00251 function
get($opt) {
00252
return $this->options[$opt];
00253 }
00254
00269 function
disable_html($disable_html = NULL) {
00270
if ($disable_html != NULL) {
00271 $this->options['disable_html'] = $disable_html;
00272 }
00273
return ($this->options['disable_html'] ? $this->options['disable_html'] : 0);
00274 }
00275
00290 function
head_offset($head_offset = NULL) {
00291
if ($head_offset != NULL) {
00292 $this->options['head_offset'] = $head_offset;
00293 }
00294
return ($this->options['head_offset'] ? $this->options['head_offset'] : 0);
00295 }
00296
00313 function
flavor($flavor = NULL) {
00314
if ($flavor != NULL) {
00315 $this->options['flavor'] = $flavor;
00316
if (preg_match('/^xhtml(\d)?(\D|$)/', $flavor, $matches)) {
00317
if ($matches[1] ==
'2') {
00318 $this->options['_line_open'] = '<l>';
00319 $this->options['_line_close'] = '</l>';
00320 $this->options['_blockcode_open'] = '<blockcode>';
00321 $this->options['_blockcode_close'] = '</blockcode>';
00322 $this->options['css_mode'] = 1;
00323 }
else {
00324
00325 $this->options['_line_open'] = '';
00326 $this->options['_line_close'] = '<br />';
00327 $this->options['_blockcode_open'] = '<pre><code>';
00328 $this->options['_blockcode_close'] = '</code></pre>';
00329 $this->options['css_mode'] = 1;
00330 }
00331 } elseif (preg_match('/^html/', $flavor)) {
00332 $this->options['_line_open'] = '';
00333 $this->options['_line_close'] = '<br>';
00334 $this->options['_blockcode_open'] = '<pre><code>';
00335 $this->options['_blockcode_close'] = '</code></pre>';
00336 $this->options['css_mode'] = preg_match('/\/
css/', $flavor);
00337 }
00338
if ($this->options['css_mode'] && !isset($this->options['
css'])) { $this->
_css_defaults(); }
00339 }
00340
return $this->options['flavor'];
00341 }
00342
00404 function
css($css = NULL) {
00405
if ($css != NULL) {
00406
if (is_array($css)) {
00407 $this->options['css'] = $css;
00408 $this->options['css_mode'] = 1;
00409 }
else {
00410 $this->options['css_mode'] = $css;
00411
if ($this->options['css_mode'] && !isset($this->options['css'])) { $this->
_css_defaults(); }
00412 }
00413 }
00414
return ($this->options['css_mode'] ? $this->options['css'] : 0);
00415 }
00416
00433 function
charset($charset = NULL) {
00434
if ($charset != NULL) {
00435 $this->options['charset'] = $charset;
00436
if (preg_match('/^utf-?8$/i', $this->options['charset'])) {
00437 $this->
char_encoding(0);
00438 }
else {
00439 $this->
char_encoding(1);
00440 }
00441 }
00442
return $this->options['charset'];
00443 }
00444
00458 function
docroot($docroot = NULL) {
00459
if ($docroot != NULL) {
00460 $this->options['docroot'] = $docroot;
00461 }
00462
return $this->options['docroot'];
00463 }
00464
00478 function
trim_spaces($trim_spaces = NULL) {
00479
if ($trim_spaces != NULL) {
00480 $this->options['trim_spaces'] = $trim_spaces;
00481 }
00482
return $this->options['trim_spaces'];
00483 }
00484
00495 function
filter_param($filter_param = NULL) {
00496
if ($filter_param != NULL) {
00497 $this->options['filter_param'] = $filter_param;
00498 }
00499
return $this->options['filter_param'];
00500 }
00501
00518 function
preserve_spaces($preserve_spaces = NULL) {
00519
if ($preserve_spaces != NULL) {
00520 $this->options['preserve_spaces'] = $preserve_spaces;
00521 }
00522
return $this->options['preserve_spaces'];
00523 }
00524
00537 function
filters($filters = NULL) {
00538
if ($filters != NULL) {
00539 $this->options['filters'] = $filters;
00540 }
00541
return $this->options['filters'];
00542 }
00543
00558 function
char_encoding($char_encoding = NULL) {
00559
if ($char_encoding != NULL) {
00560 $this->options['char_encoding'] = $char_encoding;
00561 }
00562
return $this->options['char_encoding'];
00563 }
00564
00577 function
handle_quotes($do_quotes = NULL) {
00578
if ($do_quotes != NULL) {
00579 $this->options['do_quotes'] = $do_quotes;
00580 }
00581
return $this->options['do_quotes'];
00582 }
00583
00584
00585
00599 function
_create_re() {
00600
00601
00602 $this->urlre = '(?:
00603
# Must start out right...
00604
(?=[a-zA-Z0-9./#])
00605
# Match the leading part (proto://hostname, or just hostname)
00606
(?:
00607
# ftp://, http://, or https:// leading part
00608
(?:ftp|https?|telnet|nntp):
00609 |
00610 (?:mailto:)?[-\+\w]+@[-\w]+(?:\.\w[-\w]*)+
00611 |
00612
# or, try to find a hostname with our more specific sub-expression
00613
(?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \. )+ # sub domains
00614
# Now ending .com, etc. For these, require lowercase
00615
(?-i: com\b
00616 | edu\b
00617 | biz\b
00618 | gov\b
00619 | in(?:t|fo)\b # .int or .info
00620 | mil\b
00621 | net\b
00622 | org\b
00623 | museum\b
00624 | aero\b
00625 | coop\b
00626 | name\b
00627 | pro\b
00628 | [a-z][a-z]\b # two-letter country codes
00629 )
00630 )?
00631
00632
# Allow an optional port number
00633
(?: : \d+ )?
00634
00635
# The rest of the URL is optional, and begins with / . . .
00636
(?:
00637 /?
00638
# The rest are heuristics for what seems to work well
00639
[^.!,?;:
"\'<>()\[\]{}\s\x7F-\xFF]*
00640
(?:
00641
[.!,?;:]+ [^.!,?;:"\'<>()\[\]{}\s\x7F-\xFF]+ #\'
"
00642
)*
00643
)?
00644
)';
00645
00646
$this->punct = '[\!"\#\$%&\'()\*\+,\-\./:;<=>\?@\[\\\\\]\^_`{\|}\~]';
00647 $this->valignre = '[\-^~]';
00648 $this->tblalignre = '[<>=]';
00649 $this->halignre = '(?:<>|[<>=])';
00650 $this->alignre = '(?:(?:' . $this->valignre . '|<>' . $this->valignre . '?|' . $this->valignre . '?<>|' . $this->valignre .
'?' . $this->halignre . '?|' . $this->halignre .
'?' . $this->valignre . '?)(?!\w))';
00651 $this->imgalignre = '(?:(?:[<>]|' . $this->valignre . '){1,2})';
00652
00653 $this->clstypadre = '(?:
00654 (?:\([A-Za-z0-9_\- \#]+\))
00655 |
00656 (?:{
00657 (?: \( [^)]+ \) | [^\}] )+
00658 })
00659 |
00660 (?:\(+? (?![A-Za-z0-9_\-\#]) )
00661 |
00662 (?:\)+?)
00663 |
00664 (?: \[ [a-zA-Z\-]+? \] )
00665 )';
00666
00667 $this->clstyre = '(?:
00668 (?:\([A-Za-z0-9_\- \#]+\))
00669 |
00670 (?:{
00671 [A-Za-z0-9_\-](?: \( [^)]+ \) | [^\}] )+
00672 })
00673 |
00674 (?: \[ [a-zA-Z\-]+? \] )
00675 )';
00676
00677 $this->clstyfiltre = '(?:
00678 (?:\([A-Za-z0-9_\- \#]+\))
00679 |
00680 (?:{
00681 [A-Za-z0-9_\-](?: \( [^)]+ \) | [^\}] )+
00682 })
00683 |
00684 (?:\|[^\|]+\|)
00685 |
00686 (?:\(+?(?![A-Za-z0-9_\-\#]))
00687 |
00688 (?:\)+)
00689 |
00690 (?: \[ [a-zA-Z]+? \] )
00691 )';
00692
00693 $this->codere = '(?:
00694 (?:
00695 [\[{]
00696 @ # opening
00697 (?:\[([A-Za-z0-9]+)\])? # $1: language
id
00698 (.+?) # $2: code
00699 @ # closing
00700 [\]}]
00701 )
00702 |
00703 (?:
00704 (?:^|(?<=[\s\(]))
00705 @ # opening
00706 (?:\[([A-Za-z0-9]+)\])? # $3: language
id
00707 ([^\s].+?[^\s]) # $4: code itself
00708 @ # closing
00709 (?:$|(?=' . $this->punct . '{1,2}|\s))
00710 )
00711 )';
00712
00713 $this->blocktags = '
00714 <
00715 (( /? ( h[1-6]
00716 | p
00717 | pre
00718 | div
00719 | table
00720 | t[rdh]
00721 | [ou]l
00722 | li
00723 | block(?:quote|code)
00724 | form
00725 | input
00726 | select
00727 | option
00728 | textarea
00729 )
00730 [ >]
00731 )
00732 | !--
00733 )
00734 ';
00735 }
00736
00746 function process($str) {
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760 $macros = array('bq' => 'blockquote');
00761
00762
00763
00764 array_unshift($this->repl, array());
00765
00766
00767
00768 $str = preg_replace('!(?:\015?\012|\015)!',
"\n", $str);
00769
00770
00771
if ($this->options['trim_spaces']) { $str = preg_replace('/ +$/m', '', $str); }
00772
00773
00774 $str = preg_replace_callback('{(^|\n\n)==(.+?)==($|\n\n)}s',
00775 $this->_cb('
"$m[1]\n\n" . $me->_repl($me->repl[0], $me->format_block(array(
"text" => $m[2]))) .
"\n\n$m[3]"'), $str);
00776
00777
if (!$this->disable_html()) {
00778
00779 $str = preg_replace_callback('!(<(style|script)(?:>| .+?>).*?</\2>)!s', $this->_cb('$me->_repl($me->repl[0], $m[1])'), $str);
00780
00781
00782 $str = preg_replace_callback('|(<!--.+?-->)|s', $this->_cb('$me->_repl($me->repl[0], $m[1])'), $str);
00783
00784
00785 $pre_start = count($this->repl[0]);
00786 $str = preg_replace_callback('{(<pre(?: [^>]*)?>)(.+?)(</pre>)}s',
00787 $this->_cb('
"\n\n" . $me->_repl($me->repl[0], $m[1] . $me->encode_html($m[2], 1) . $m[3]) .
"\n\n"'), $str);
00788
00789
for ($i = $pre_start; $i < count($this->repl[0]); $i++) {
00790 $this->repl[0][$i] = preg_replace('|<(/?)code(.*?)>|s', '<$1code$2>', $this->repl[0][$i]);
00791 }
00792
00793
00794 $str = preg_replace_callback('{(<code(?: [^>]+)?>)(.+?)(</code>)}s',
00795 $this->_cb('$me->_repl($me->repl[0], $m[1] . $me->encode_html($m[2], 1) . $m[3])'), $str);
00796
00797
00798
00799 $str = preg_replace_callback('{(<blockcode(?: [^>]+)?>)(.+?)(</blockcode>)}s',
00800 $this->_cb('
"\n\n" . $me->_repl($me->repl[0], $m[1] . $me->encode_html($m[2], 1) . $m[3]) .
"\n\n"'), $str);
00801
00802
00803 $str = preg_replace_callback('!(<([\?%]).*?(\2)>)!s', $this->_cb('$me->_repl($me->repl[0], $m[1])'), $str);
00804 }
00805
00806
00807
00808
00809
00810
00811 $str = preg_replace_callback('{(?:\n|^) [ ]* \[ ([^ ]+?) [ ]*? (?:\( (.+?) \) )? \] ((?:(?:ftp|https?|telnet|nntp):
00812 $this->_cb('($me->links[$m[1]] = array(
"url" => $m[3],
"title" => $m[2])) ? $m[4] : $m[4]'), $str);
00813
00814
00815
00816 $str = preg_replace('/^\n+/s', '', $str, 1);
00817 $str = preg_replace('/\n+$/s', '', $str, 1);
00818
00819
00820 $para = preg_split('/(\n{2,})/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
00821 unset($block, $bqlang, $filter, $
class, $sticky, $lines,
00822 $style, $stickybuff, $lang, $clear);
00823
00824 $out = '';
00825
00826 foreach ($para as $para) {
00827
if (preg_match('/^\n+$/s', $para)) {
00828
if ($sticky && $stickybuff) {
00829 $stickybuff .= $para;
00830 }
else {
00831 $out .= $para;
00832 }
00833
continue;
00834 }
00835
00836
if ($sticky) {
00837 $sticky++;
00838 }
else {
00839 unset($block);
00840 unset($
class);
00841 $style = '';
00842 unset($lang);
00843 }
00844
00845 unset($
id, $cite, $align, $padleft, $padright, $lines, $buffer);
00846
if (preg_match('{^(h[1-6]|p|bq|bc|fn\d+)
00847 ((?:' . $this->clstyfiltre . '*|' . $this->halignre . ')*)
00848 (\.\.?)
00849 (?::(\d+|' . $this->urlre . '))?\ (.*)$}sx', $para, $matches)) {
00850
if ($sticky) {
00851
if ($block == 'bc') {
00852
00853 $out = preg_replace('/\n\n$/', '', $out, 1);
00854 $out .= $this->options['_blockcode_close'] .
"\n\n";
00855 } elseif ($block == 'bq') {
00856 $out = preg_replace('/\n\n$/', '', $out, 1);
00857 $out .= '</blockquote>' .
"\n\n";
00858 } elseif ($block == 'table') {
00859 $table_out = $this->format_table(array('text' => $stickybuff));
00860
if (!$table_out) { $table_out = ''; }
00861 $out .= $table_out;
00862 unset($stickybuff);
00863 } elseif ($block == 'dl') {
00864 $dl_out = $this->format_deflist(array('text' => $stickybuff));
00865
if (!$dl_out) { $dl_out = ''; }
00866 $out .= $dl_out;
00867 unset($stickybuff);
00868 }
00869 $sticky = 0;
00870 }
00871
00872
00873 $block = $matches[1];
00874 $params = $matches[2];
00875 $cite = $matches[4];
00876
if ($matches[3] == '..') {
00877 $sticky = 1;
00878 }
else {
00879 $sticky = 0;
00880 unset($
class);
00881 unset($bqlang);
00882 unset($lang);
00883 $style = '';
00884 unset($filter);
00885 }
00886
if (preg_match('/^h([1-6])$/', $block, $matches2)) {
00887
if ($this->options['head_offset']) {
00888 $block =
'h' . ($matches2[1] + $this->options['head_offset']);
00889 }
00890 }
00891
if (preg_match('{(' . $this->halignre . '+)}', $params, $matches2)) {
00892 $align = $matches2[1];
00893 $params = preg_replace(
'{' . $this->halignre . '+}', '', $params, 1);
00894 }
00895
if ($params) {
00896
if (preg_match('/\|(.+)\|/', $params, $matches2)) {
00897 $filter = $matches2[1];
00898 $params = preg_replace('/\|.+?\|/', '', $params, 1);
00899 }
00900
if (preg_match('/{([^}]+)}/', $params, $matches2)) {
00901 $style = $matches2[1];
00902 $style = preg_replace('/\n/',
' ', $style);
00903 $params = preg_replace('/{[^}]+}/', '', $params);
00904 }
00905
if (preg_match('/\(([A-Za-z0-9_\-\ ]+?)(?:\#(.+?))?\)/', $params, $matches2) ||
00906 preg_match('/\(([A-Za-z0-9_\-\ ]+?)?(?:\#(.+?))\)/', $params, $matches2)) {
00907
if ($matches2[1] || $matches2[2]) {
00908 $class = $matches2[1];
00909 $id = $matches2[2];
00910
if ($class) {
00911 $params = preg_replace('/\([A-Za-z0-9_\-\ ]+?(#.*?)?\)/', '', $params);
00912 } elseif ($
id) {
00913 $params = preg_replace('/\(#.+?\)/', '', $params);
00914 }
00915 }
00916 }
00917
if (preg_match('/(\(+)/', $params, $matches2)) {
00918 $padleft = strlen($matches2[1]);
00919 $params = preg_replace('/\(+/', '', $params, 1);
00920 }
00921
if (preg_match('/(\)+)/', $params, $matches2)) {
00922 $padright = strlen($matches2[1]);
00923 $params = preg_replace('/\)+/', '', $params, 1);
00924 }
00925
if (preg_match('/\[(.+?)\]/', $params, $matches2)) {
00926 $lang = $matches2[1];
00927
if ($block == 'bc') {
00928 $bqlang = $lang;
00929 unset($lang);
00930 }
00931 $params = preg_replace('/\[.+?\]/', '', $params, 1);
00932 }
00933 }
00934
00935 $para = $matches[5];
00936 } elseif (preg_match('|^<textile#(\d+)>$|', $para, $matches)) {
00937 $buffer = $this->repl[0][$matches[1] - 1];
00938 } elseif (preg_match('/^clear([<>]+)?\.$/', $para, $matches)) {
00939
if ($matches[1] ==
'<') {
00940 $clear = 'left';
00941 } elseif ($matches[1] ==
'>') {
00942 $clear = 'right';
00943 }
else {
00944 $clear = 'both';
00945 }
00946
continue;
00947 } elseif ($sticky && $stickybuff &&
00948 ($block == 'table' || $block == 'dl')) {
00949 $stickybuff .= $para;
00950
continue;
00951 } elseif (preg_match('{^(?:' . $this->halignre .
'|' . $this->clstypadre . '*)*
00952 [\*\#]
00953 (?:' . $this->halignre .
'|' . $this->clstypadre . '*)*
00954 \ }x', $para)) {
00955
00956 $buffer = $this->format_list(array('text' => $para));
00957 } elseif (preg_match('{^(?:table(?:' . $this->tblalignre .
'|' . $this->clstypadre . '*)*
00958 (\.\.?)\s+)?
00959 (?:_|' . $this->alignre .
'|' . $this->clstypadre . '*)*\|}x', $para, $matches)) {
00960
00961
if ($matches[1] && ($matches[1] == '..')) {
00962 $block = 'table';
00963 $stickybuff = $para;
00964 $sticky = 1;
00965
continue;
00966 }
else {
00967 $buffer = $this->format_table(array('text' => $para));
00968 }
00969 } elseif (preg_match('{^(?:dl(?:' . $this->clstyre . ')*(\.\.?)\s+)}x', $para, $matches)) {
00970
00971
if ($matches[1] && ($matches[1] == '..')) {
00972 $block = 'dl';
00973 $stickybuff = $para;
00974 $sticky = 1;
00975
continue;
00976 }
else {
00977 $buffer = $this->format_deflist(array('text' => $para));
00978 }
00979 }
00980
if ($buffer) {
00981 $out .= $buffer;
00982
continue;
00983 }
00984 $lines = preg_split('/\n/', $para);
00985
if ((count($lines) == 1) && ($lines[0] == '')) {
00986
continue;
00987 }
00988
00989 $block = ($block ? $block :
'p');
00990
00991 $buffer = '';
00992 $pre = '';
00993 $post = '';
00994
00995
if ($block == 'bc') {
00996
if ($sticky <= 1) {
00997 $pre .= $this->options['_blockcode_open'];
00998 $pre = preg_replace('/>$/s', '', $pre, 1);
00999
if ($bqlang) { $pre .=
" language=\"$bqlang\""; }
01000
if ($align) {
01001 $alignment = $this->_halign($align);
01002
if ($this->options['css_mode']) {
01003
if (($padleft || $padright) &&
01004 (($alignment == 'left') || ($alignment == 'right'))) {
01005 $style .= ';
float:' . $alignment;
01006 }
else {
01007 $style .= ';text-align:' . $alignment;
01008 }
01009 $class .=
' ' . ($this->options['css'][
"class_align_$alignment"] ? $this->options['css'][
"class_align_$alignment"] : $alignment);
01010 }
else {
01011
if ($alignment) { $pre .=
" align=\"$alignment\""; }
01012 }
01013 }
01014
if ($padleft) { $style .=
";padding-left:${padleft}em"; }
01015
if ($padright) { $style .=
";padding-right:${padright}em"; }
01016
if ($clear) { $style .=
";clear:${clear}"; }
01017
if ($class) { $class = preg_replace('/^ /', '', $
class, 1); }
01018
if ($class) { $pre .=
" class=\"$class\""; }
01019
if ($id) { $pre .=
" id=\"$id\""; }
01020
if ($style) { $style = preg_replace('/^;/', '', $style, 1); }
01021
if ($style) { $pre .=
" style=\"$style\""; }
01022
if ($lang) { $pre .=
" lang=\"$lang\""; }
01023 $pre .=
'>';
01024 unset($lang);
01025 unset($bqlang);
01026 unset($clear);
01027 }
01028 $para = preg_replace_callback('{(?:^|(?<=[\s>])|([{[]))
01029 ==(.+?)==
01030 (?:$|([\]}])|(?=' . $this->punct . '{1,2}|\s))}sx',
01031 $this->_cb('$me->_repl($me->repl[0], $me->format_block(array(
"text" => $m[2],
"inline" => 1,
"pre" => $m[1],
"post" => $m[3])))'), $para);
01032 $buffer .= $this->encode_html_basic($para, 1);
01033 $buffer = preg_replace('/<textile#(\d+)>/', '<textile#$1>', $buffer);
01034
if ($sticky == 0) {
01035 $post .= $this->options['_blockcode_close'];
01036 }
01037 $out .= $pre . $buffer . $post;
01038
continue;
01039 } elseif ($block == 'bq') {
01040
if ($sticky <= 1) {
01041 $pre .= '<blockquote';
01042
if ($align) {
01043 $alignment = $this->_halign($align);
01044
if ($this->options['css_mode']) {
01045
if (($padleft || $padright) &&
01046 (($alignment == 'left') || ($alignment == 'right'))) {
01047 $style .= ';
float:' . $alignment;
01048 }
else {
01049 $style .= ';text-align:' . $alignment;
01050 }
01051 $class .=
' ' . ($this->options['css'][
"class_align_$alignment"] ? $this->options['css'][
"class_align_$alignment"] : $alignment);
01052 }
else {
01053
if ($alignment) { $pre .=
" align=\"$alignment\""; }
01054 }
01055 }
01056
if ($padleft) { $style .=
";padding-left:${padleft}em"; }
01057
if ($padright) { $style .=
";padding-right:${padright}em"; }
01058
if ($clear) { $style .=
";clear:${clear}"; }
01059
if ($class) { $class = preg_replace('/^ /', '', $
class, 1); }
01060
if ($class) { $pre .=
" class=\"$class\""; }
01061
if ($id) { $pre .=
" id=\"$id\""; }
01062
if ($style) { $style = preg_replace('/^;/', '', $style, 1); }
01063
if ($style) { $pre .=
" style=\"$style\""; }
01064
if ($lang) { $pre .=
" lang=\"$lang\""; }
01065
if ($cite) { $pre .= ' cite=
"' . $this->format_url(array('url' => $cite)) . '"'; }
01066 $pre .=
'>';
01067 unset($clear);
01068 }
01069 $pre .= '<p>';
01070 } elseif (preg_match('/fn(\d+)/', $block, $matches)) {
01071 $fnum = $matches[1];
01072 $pre .= '<p';
01073
if ($this->options['css']['class_footnote']) { $class .=
' ' . $this->options['css']['class_footnote']; }
01074
if ($align) {
01075 $alignment = $this->_halign($align);
01076
if ($this->options['css_mode']) {
01077
if (($padleft || $padright) &&
01078 (($alignment == 'left') || ($alignment == 'right'))) {
01079 $style .= ';
float:' . $alignment;
01080 }
else {
01081 $style .= ';text-align:' . $alignment;
01082 }
01083 $class .= ($this->options['css'][
"class_align_$alignment"] ? $this->options['css'][
"class_align_$alignment"] : $alignment);
01084 }
else {
01085 $pre .=
" align=\"$alignment\"";
01086 }
01087 }
01088
if ($padleft) { $style .=
";padding-left:${padleft}em"; }
01089
if ($padright) { $style .=
";padding-right:${padright}em"; }
01090
if ($clear) { $style .=
";clear:${clear}"; }
01091
if ($class) { $class = preg_replace('/^ /', '', $
class, 1); }
01092
if ($class) { $pre .=
" class=\"$class\""; }
01093 $pre .= '
id=
"' . ($this->options['css']['id_footnote_prefix'] ? $this->options['css']['id_footnote_prefix'] : 'fn') . $fnum . '"';
01094
if ($style) { $style = preg_replace('/^;/', '', $style, 1); }
01095
if ($style) { $pre .=
" style=\"$style\""; }
01096
if ($lang) { $pre .=
" lang=\"$lang\""; }
01097 $pre .=
'>';
01098 $pre .= '<sup>' . $fnum . '</sup> ';
01099
01100 $block =
'p';
01101 unset($clear);
01102 }
else {
01103 $pre .=
'<' . ($macros[$block] ? $macros[$block] : $block);
01104
if ($align) {
01105 $alignment = $this->_halign($align);
01106
if ($this->options['css_mode']) {
01107
if (($padleft || $padright) &&
01108 (($alignment == 'left') || ($alignment == 'right'))) {
01109 $style .= ';
float:' . $alignment;
01110 }
else {
01111 $style .= ';text-align:' . $alignment;
01112 }
01113 $class .=
' ' . ($this->options['css'][
"class_align_$alignment"] ? $this->options['css'][
"class_align_$alignment"] : $alignment);
01114 }
else {
01115 $pre .=
" align=\"$alignment\"";
01116 }
01117 }
01118
if ($padleft) { $style .=
";padding-left:${padleft}em"; }
01119
if ($padright) { $style .=
";padding-right:${padright}em"; }
01120
if ($clear) { $style .=
";clear:${clear}"; }
01121
if ($class) { $class = preg_replace('/^ /', '', $
class, 1); }
01122
if ($class) { $pre .=
" class=\"$class\""; }
01123
if ($id) { $pre .=
" id=\"$id\""; }
01124
if ($style) { $style = preg_replace('/^;/', '', $style, 1); }
01125
if ($style) { $pre .=
" style=\"$style\""; }
01126
if ($lang) { $pre .=
" lang=\"$lang\""; }
01127
if ($cite && ($block == 'bq')) { $pre .= ' cite=
"' . $this->format_url(array('url' => $cite)) . '"'; }
01128 $pre .=
'>';
01129 unset($clear);
01130 }
01131
01132 $buffer = $this->format_paragraph(array('text' => $para));
01133
01134
if ($block == 'bq') {
01135
if (!preg_match('/<p[ >]/', $buffer)) { $post .= '</p>'; }
01136
if ($sticky == 0) {
01137 $post .= '</blockquote>';
01138 }
01139 }
else {
01140 $post .= '</' . $block .
'>';
01141 }
01142
01143
if (preg_match(
'{' . $this->blocktags . '}x', $buffer)) {
01144 $buffer = preg_replace('/^\n\n/s', '', $buffer, 1);
01145 $out .= $buffer;
01146 }
else {
01147
if ($filter) { $buffer = $this->format_block(array('text' =>
"|$filter|" . $buffer, '
inline' => 1)); }
01148 $out .= $pre . $buffer . $post;
01149 }
01150 }
01151
01152
if ($sticky) {
01153
if ($block == 'bc') {
01154
01155 $out .= $this->options['_blockcode_close'];
01156 } elseif ($block == 'bq') {
01157 $out .= '</blockquote>';
01158 } elseif (($block == 'table') && $stickybuff) {
01159 $table_out = $this->format_table(array('text' => $stickybuff));
01160
if ($table_out) { $out .= $table_out; }
01161 } elseif (($block == 'dl') && $stickybuff) {
01162 $dl_out = $this->format_deflist(array('text' => $stickybuff));
01163
if ($dl_out) { $out .= $dl_out; }
01164 }
01165 }
01166
01167
01168
for ($i = count($this->repl[0]); $i > 0; $i--) {
01169 $out = preg_replace('!(?:<|<)textile#' . $i . '(?:>|>)!', str_replace(
'$', '\\$', $this->repl[0][$i - 1]), $out, 1);
01170 }
01171 array_shift($this->repl);
01172
01173
01174
01175
01176
if (preg_match('/^xhtml/i', $this->flavor())) {
01177 $out = preg_replace('/(<(?:img|br|hr)[^>]*?(?<!\/))>/', '$1 />', $out);
01178 }
01179
01180
return $out;
01181 }
01182
01202 function format_paragraph($args) {
01203 $buffer = (isset($args['text']) ? $args['text'] : '');
01204
01205 array_unshift($this->repl, array());
01206 $buffer = preg_replace_callback('{(?:^|(?<=[\s>])|([{[]))
01207 ==(.+?)==
01208 (?:$|([\]}])|(?=' . $this->punct . '{1,2}|\s))}sx',
01209 $this->_cb('$me->_repl($me->repl[0], $me->format_block(array(
"text" => $m[2],
"inline" => 1,
"pre" => $m[1],
"post" => $m[3])))'), $buffer);
01210
01211 unset($tokens);
01212
if (preg_match('/</', $buffer) && (!$this->disable_html())) {
01213
01214 $tokens = $this->_tokenize($buffer);
01215 }
else {
01216 $tokens = array(array('text', $buffer));
01217 }
01218 $result = '';
01219 foreach ($tokens as $token) {
01220 $text = $token[1];
01221
if ($token[0] == 'tag') {
01222 $text = preg_replace('/&(?!amp;)/', '&', $text);
01223 $result .= $text;
01224 }
else {
01225 $text = $this->format_inline(array('text' => $text));
01226 $result .= $text;
01227 }
01228 }
01229
01230
01231 $lines = preg_split('/\n/', $result);
01232 $result = '';
01233 $needs_closing = 0;
01234 foreach ($lines as $line) {
01235
if (!preg_match('{(' . $this->blocktags . ')}x', $line)
01236 && ((preg_match('/^[^<]/', $line) || preg_match('/>[^<]/', $line))
01237 || !preg_match('/<img /', $line))) {
01238
if ($this->options['_line_open']) {
01239
if ($result != '') { $result .=
"\n"; }
01240 $result .= $this->options['_line_open'] . $line . $this->options['_line_close'];
01241 }
else {
01242
if ($needs_closing) {
01243 $result .= $this->options['_line_close'] .
"\n";
01244 }
else {
01245 $needs_closing = 1;
01246
if ($result != '') { $result .=
"\n"; }
01247 }
01248 $result .= $line;
01249 }
01250 }
else {
01251
if ($needs_closing) {
01252 $result .= $this->options['_line_close'] .
"\n";
01253 }
else {
01254
if ($result != '') { $result .=
"\n"; }
01255 }
01256 $result .= $line;
01257 $needs_closing = 0;
01258 }
01259 }
01260
01261
01262
01263
01264 $result = preg_replace('/\001/',
"\n", $result);
01265
01266
for ($i = count($this->repl[0]); $i > 0; $i--) {
01267 $result = preg_replace(
"|<textile#$i>|", str_replace(
'$', '\\$', $this->repl[0][$i - 1]), $result, 1);
01268 }
01269 array_shift($this->repl);
01270
01271
01272
if ($this->options['do_quotes']) {
01273 $result = $this->process_quotes($result);
01274 }
01275
01276
return $result;
01277 }
01278
01298 function format_inline($args) {
01299 $qtags = array(array('**',
'b', '(?<!\*)\*\*(?!\*)',
'\*'),
01300 array('__',
'i', '(?<!_)__(?!_)',
'_'),
01301 array('??', 'cite', '\?\?(?!\?)',
'\?'),
01302 array(
'*', 'strong', '(?<!\*)\*(?!\*)',
'\*'),
01303 array(
'_', 'em', '(?<!_)_(?!_)',
'_'),
01304 array(
'-', 'del', '(?<!\-)\-(?!\-)',
'-'),
01305 array(
'+', 'ins', '(?<!\+)\+(?!\+)',
'\+'),
01306 array('++', 'big', '(?<!\+)\+\+(?!\+)', '\+\+'),
01307 array('--', 'small', '(?<!\-)\-\-(?!\-)', '\-\-'),
01308 array(
'~', 'sub', '(?<!\~)\~(?![\\\\/~])',
'\~'));
01309 $text = (isset($args['text']) ? $args['text'] : '');
01310
01311 array_unshift($this->repl, array());
01312
01313 $text = preg_replace_callback(
'{' . $this->codere . '}mx', $this->_cb('$me->_repl($me->repl[0], $me->format_code(array(
"text" => $m[2] . $m[4],
"lang" => $m[1] . $m[3])))'), $text);
01314
01315
01316
01317
01318
01319 $text = preg_replace_callback('{(?:^|(?<=[\s>])|([{[])) # $1: open brace/bracket
01320 ! # opening
01321 (' . $this->imgalignre . '?) # $2: optional alignment
01322 (' . $this->clstypadre . '*) # $3: optional CSS
class/id
01323 (' . $this->imgalignre . '?) # $4: optional alignment
01324 (?:\s*) # space between alignment/css stuff
01325 ([^\s\(!]+) # $5: filename
01326 (\s*[^\(!]*(?:\([^\)]+\))?[^!]*) # $6: extras (alt text)
01327 ! # closing
01328 (?::(\d+|' . $this->urlre . '))? # $7: optional URL
01329 (?:$|([\]}])|(?=' . $this->punct . '{1,2}|\s)) # $8: closing brace/bracket
01330 }mx', $this->_cb('$me->_repl($me->repl[0], $me->format_image(array(
"pre" => $m[1],
"src" => $m[5],
"align" => ($m[2] ? $m[2] : $m[4]),
"extra" => $m[6],
"url" => $m[7],
"clsty" => $m[3],
"post" => $m[8])))'), $text);
01331
01332 $text = preg_replace_callback('{(?:^|(?<=[\s>])|([{[])) # $1: open brace/bracket
01333 % # opening
01334 (' . $this->halignre . '?) # $2: optional alignment
01335 (' . $this->clstyre . '*) # $3: optional CSS
class/id
01336 (' . $this->halignre . '?) # $4: optional alignment
01337 (?:\s*) # spacing
01338 ([^%]+?) # $5: text
01339 % # closing
01340 (?::(\d+|' . $this->urlre . '))? # $6: optional URL
01341 (?:$|([]}])|(?=' . $this->punct . '{1,2}|\s)) # $7: closing brace/bracket
01342 }mx', $this->_cb('$me->_repl($me->repl[0], $me->format_span(array(
"pre" => $m[1],
"text" => $m[5],
"align" => ($m[2] ? $m[2] : $m[4]),
"cite" => $m[6],
"clsty" => $m[3],
"post" => $m[7])))'), $text);
01343
01344 $text = $this->encode_html($text);
01345 $text = preg_replace('!<textile#(\d+)>!', '<textile#$1>', $text);
01346 $text = preg_replace('!&quot;!', '"', $text);
01347 $text = preg_replace('!&(([a-z]+|#\d+);)!', '&$1', $text);
01348 $text = preg_replace('!"!',
'"', $text);
01349
01350
01351
01352
01353 $parenre = '\( (?: [^()] )* \)';
01354 $text = preg_replace_callback('{(
01355 [{[]
01356 (?:
01357 (?:
" # quote character
01358
(' . $this->clstyre . '*)? # $2: optional CSS class/id
01359
([^"]+?) # $3: link text
01360 (?:\( ( (?:[^()]|' . $parenre . ')*) \))? # $4: optional link title
01361
" # closing quote
01362
)
01363
|
01364
(?:\' # open single quote
01365
(' . $this->clstyre . '*)? # $5: optional CSS class/id
01366
([^\']+?) # $6: link text
01367
(?:\( ( (?:[^()]|' . $parenre . ')*) \))? # $7: optional link title
01368
\' # closing quote
01369
)
01370
)
01371
:(.+?) # $8: URL suffix
01372
[\]}]
01373
)
01374
}mx', $this->_cb('$me->_repl($me->repl[0], $me->format_link(array("text
" => $m[1], "linktext
" => $m[3] . $m[6], "title
" => $me->encode_html_basic($m[4] . $m[7]), "url
" => $m[8], "clsty
" => $m[2] . $m[5])))'), $text);
01375
01376
$text = preg_replace_callback('{((?:^|(?<=[\s>\(])) # $1: open brace/bracket
01377
(?: (?:" # quote character
"
01378
(' . $this->clstyre . '*)? # $2: optional CSS class/id
01379
([^"]+?) # $3: link text
"
01380
(?:\( ( (?:[^()]|' . $parenre . ')*) \))? # $4: optional link title
01381
" # closing quote #
"
01382
)
01383
|
01384
(?:\' # open single quote \'
01385
(' . $this->clstyre . '*)? # $5: optional CSS class/id
01386
([^\']+?) # $6: link text \'
01387
(?:\( ( (?:[^()]|' . $parenre . ')*) \))? # $7: optional link title
01388
\' # closing quote \'
01389
)
01390
)
01391
:(\d+|' . $this->urlre . ') # $8: URL suffix
01392
(?:$|(?=' . $this->punct . '{1,2}|\s))) # $9: closing brace/bracket
01393
}mx', $this->_cb('$me->_repl($me->repl[0], $me->format_link(array("text
" => $m[1], "linktext
" => $m[3] . $m[6], "title
" => $me->encode_html_basic($m[4] . $m[7]), "url
" => $m[8], "clsty
" => $m[2] . $m[5])))'), $text);
01394
01395
if (preg_match('/^xhtml2/', $this->flavor())) {
01396
// citation with cite link
01397
$text = preg_replace_callback('{(?:^|(?<=[\s>\'"\(])|([{[])) # $1: open brace/bracket \'
01398 \?\? # opening \'??\'
01399 ([^\?]+?) # $2: characters (can\'t contain \'?\')
01400 \?\? # closing \'??\'
01401 :(\d+|' . $this->urlre . ') # $3: optional citation URL
01402 (?:$|([\]}])|(?=' . $this->punct . '{1,2}|\s)) # $4: closing brace/bracket
01403 }mx', $this->_cb('$me->_repl($me->repl[0], $me->format_cite(array(
"pre" => $m[1],
"text" => $m[2],
"cite" => $m[3],
"post" => $m[4])))'), $text);
01404 }
01405
01406
01407
if (preg_match('/[^ ]\[\d+\]/', $text)) {
01408 $fntag = '<sup';
01409
if ($this->options['css']['class_footnote']) { $fntag .= '
class=
"' . $this->options['css']['class_footnote'] . '"'; }
01410 $fntag .= '><a href=
"#' . ($this->options['css']['id_footnote_prefix'] ? $this->options['css']['id_footnote_prefix'] : 'fn');
01411
$text = preg_replace('|([^ ])\[(\d+)\]|', '$1' . $fntag . '$2">$2</a></sup>', $text);
01412 }
01413
01414
01415 $text = preg_replace_callback('{(\{)(.+?)(\})}x',
01416 $this->_cb('$me->format_macro(array(
"pre" => $m[1],
"post" => $m[3],
"macro" => $m[2]))'), $text);
01417
01418
01419
01420
01421 $text = preg_replace('|[\(\[]TM[\)\]]|i', '™', $text);
01422
01423 $text = preg_replace('|[\(\[]C[\)\]]|i', '©', $text);
01424
01425 $text = preg_replace('|[\(\[]R[\)\]]|i', '®', $text);
01426
01427
if ($this->preserve_spaces()) {
01428
01429 $text = preg_replace('/(?<!\s)\ \ (?!=\s)/', ' ', $text);
01430 }
01431
01432 $redo = preg_match('/[\*_\?\-\+\^\~]/', $text);
01433 $last = $text;
01434
while ($redo) {
01435
01436 $redo = 0;
01437 foreach ($qtags as $tag) {
01438 list ($this->tmp[
'f'][], $this->tmp[
'r'][], $qf, $cls) = $tag;
01439
if ($last != ($text = preg_replace_callback('{(?:^|(?<=[\s>\'
"])|([{[])) # "\' $1 - pre
01440 ' . $qf . ' #
01441 (?:(' . $this->clstyre . '*))? # $2 - attributes
01442 ([^' . $cls . '\s].*?) # $3 - content
01443 (?<=\S)' . $qf . ' #
01444 (?:$|([\]}])|(?=' . $this->punct . '{1,2}|\s)) # $4 - post
01445 }mx', $this->_cb('$me->format_tag(array(
"tag" => end($me->tmp[
"r"]),
"marker" => end($me->tmp[
"f"]),
"pre" => $m[1],
"text" => $m[3],
"clsty" => $m[2],
"post" => $m[4]))'), $text))) {
01446 $redo = ($redo || ($last != $text));
01447 $last = $text;
01448 }
01449 array_pop($this->tmp[
'f']); array_pop($this->tmp[
'r']);
01450 }
01451 }
01452
01453
01454 $text = preg_replace('/(?<!\^)\^(?!\^)(.+?)(?<!\^)\^(?!\^)/', '<sup>$1</sup>', $text);
01455
01456
01457 $text = preg_replace_callback('{\b([A-Z][A-Za-z0-9]*?[A-Z0-9]+?)\b(?:[(]([^)]*)[)])}',
01458 $this->_cb('$me->_repl($me->repl[0],
"<acronym title=\"" . $me->encode_html_basic($m[2]) .
"\">$m[1]</acronym>")'), $text);
01459
01460
01461
if ($this->tmp['caps'][] = $this->options['css']['class_caps']) {
01462 $text = preg_replace_callback('/(^|[^
"][>\s]) # "
01463 ((?:[A-Z](?:[A-Z0-9\.,\']|\&){2,}\ *)+?) # \'
01464 (?=[^A-Z\.0-9]|$)
01465 /mx', $this->_cb('$m[1] . $me->_repl($me->repl[0],
"<span class=\"" . end($me->tmp[
"caps"]) .
"\">$m[2]</span>")'), $text);
01466 }
01467 array_pop($this->tmp['caps']);
01468
01469
01470 $text = preg_replace('!((?:[0-9\.]0|[1-9]|\d[\'
"])\ ?)x(\ ?\d)!', '$1×$2', $text);
01471
01472
// translate these entities to the Unicode equivalents:
01473
$text = preg_replace('/…/', '…', $text);
01474
$text = preg_replace('/‘/', '‘', $text);
01475
$text = preg_replace('/’/', '’', $text);
01476
$text = preg_replace('/“/', '“', $text);
01477
$text = preg_replace('/”/', '”', $text);
01478
$text = preg_replace('/–/', '–', $text);
01479
$text = preg_replace('/—/', '—', $text);
01480
01481
// Restore replacements done earlier:
01482
for ($i = count($this->repl[0]); $i > 0; $i--) {
01483
$text = preg_replace("|<textile#$i>|
", str_replace('$', '\\$', $this->repl[0][$i - 1]), $text);
01484
}
01485
array_shift($this->repl);
01486
01487
// translate entities to characters for highbit stuff since
01488
// we're using utf8
01489
// removed for backward compatability with older versions of Perl
01490
//if (preg_match('/^utf-?8$/i', $this->options['charset'])) {
01491
// // translate any unicode entities to native UTF-8
01492
// $text = preg_replace('/\&\#(\d+);/e', '($1 > 127) ? pack('U', $1) : chr($1)', $text);
01493
//}
01494
01495
return $text;
01496
} // function format_inline
01497
01530 function format_macro($attrs) {
01531
$macro = $attrs['macro'];
01532
if ($this->options['macros'][$macro]) {
01533
return $this->options['macros'][$macro];
01534
}
01535
01536
return $attrs['pre'] . $macro . $attrs['post'];
01537
} // function format_macro
01538
01570 function format_cite($args) {
01571
$pre = (isset($args['pre']) ? $args['pre'] : '');
01572
$text = (isset($args['text']) ? $args['text'] : '');
01573
$cite = $args['cite'];
01574
$post = (isset($args['post']) ? $args['post'] : '');
01575
$this->_strip_borders($pre, $post);
01576
$tag = $pre . '<cite';
01577
if (preg_match('/^xhtml2/', $this->flavor()) && $cite) {
01578
$cite = $this->format_url(array('url' => $cite));
01579
$tag .= " cite=\
"$cite\"";
01580 }
else {
01581 $post .=
':';
01582 }
01583 $tag .=
'>';
01584
return $tag . $this->format_inline(array('text' => $text)) . '</cite>' . $post;
01585 }
01586
01610 function format_code($args) {
01611 $code = (isset($args['text']) ? $args['text'] : '');
01612 $lang = $args['lang'];
01613 $code = $this->encode_html($code, 1);
01614 $code = preg_replace('/<textile#(\d+)>/', '<textile#$1>', $code);
01615 $tag = '<code';
01616
if ($lang) { $tag .=
" language=\"$lang\""; }
01617
return $tag .
'>' . $code . '</code>';
01618 }
01619
01662 function format_classstyle($clsty = NULL, $
class = NULL, $style = NULL) {
01663 $class = preg_replace('/^ /', '', $
class, 1);
01664
01665 unset($lang, $padleft, $padright, $
id);
01666
if ($clsty && preg_match('/{([^}]+)}/', $clsty, $matches)) {
01667 $_style = $matches[1];
01668 $_style = preg_replace('/\n/',
' ', $_style);
01669 $style .=
';' . $_style;
01670 $clsty = preg_replace('/{[^}]+}/', '', $clsty);
01671 }
01672
if ($clsty && (preg_match('/\(([A-Za-z0-9_\- ]+?)(?:#(.+?))?\)/', $clsty, $matches) ||
01673 preg_match('/\(([A-Za-z0-9_\- ]+?)?(?:#(.+?))\)/', $clsty, $matches))) {
01674
if ($matches[1] || $matches[2]) {
01675
if ($class) {
01676 $class = $matches[1] .
' ' . $class;
01677 }
else {
01678 $class = $matches[1];
01679 }
01680 $id = $matches[2];
01681
if ($class) {
01682 $clsty = preg_replace('/\([A-Za-z0-9_\- ]+?(#.*?)?\)/', '', $clsty);
01683 }
01684
if ($id) {
01685 $clsty = preg_replace('/\(#.+?\)/', '', $clsty);
01686 }
01687 }
01688 }
01689
if ($clsty && preg_match('/(\(+)/', $clsty, $matches)) {
01690 $padleft = strlen($matches[1]);
01691 $clsty = preg_replace('/\(+/', '', $clsty, 1);
01692 }
01693
if ($clsty && preg_match('/(\)+)/', $clsty, $matches)) {
01694 $padright = strlen($matches[1]);
01695 $clsty = preg_replace('/\)+/', '', $clsty, 1);
01696 }
01697
if ($clsty && preg_match('/\[(.+?)\]/', $clsty, $matches)) {
01698 $lang = $matches[1];
01699 $clsty = preg_replace('/\[.+?\]/', '', $clsty);
01700 }
01701 $attrs = '';
01702
if ($padleft) { $style .=
";padding-left:${padleft}em"; }
01703
if ($padright) { $style .=
";padding-right:${padright}em"; }
01704 $style = preg_replace('/^;/', '', $style, 1);
01705 $class = preg_replace('/^ /', '', $
class, 1);
01706 $class = preg_replace('/ $/', '', $
class, 1);
01707
if ($class) { $attrs .=
" class=\"$class\""; }
01708
if ($id) { $attrs .=
" id=\"$id\""; }
01709
if ($style) { $attrs .=
" style=\"$style\""; }
01710
if ($lang) { $attrs .=
" lang=\"$lang\""; }
01711 $attrs = preg_replace('/^ /', '', $attrs, 1);
01712
return $attrs;
01713 }
01714
01749 function format_tag($args) {
01750 $tagname = $args['tag'];
01751 $text = (isset($args['text']) ? $args['text'] : '');
01752 $pre = (isset($args['pre']) ? $args['pre'] : '');
01753 $post = (isset($args['post']) ? $args['post'] : '');
01754 $clsty = (isset($args['clsty']) ? $args['clsty'] : '');
01755 $this->_strip_borders($pre, $post);
01756 $tag =
"<$tagname";
01757 $attr = $this->format_classstyle($clsty);
01758
if ($attr) { $tag .=
" $attr"; }
01759 $tag .=
">$text</$tagname>";
01760
return $pre . $tag . $post;
01761 }
01762
01782 function format_deflist($args) {
01783 $str = (isset($args['text']) ? $args['text'] : '');
01784 unset($clsty);
01785 $lines = preg_split('/\n/', $str);
01786
if (preg_match('{^(dl(' . $this->clstyre . '*?)\.\.?(?:\ +|$))}x', $lines[0], $matches)) {
01787 $clsty = $matches[2];
01788 $lines[0] = substr($lines[0], strlen($matches[1]));
01789 }
01790
01791 unset($dt, $dd);
01792 $out = '';
01793 foreach ($lines as $line) {
01794
if (preg_match('{^((?:' . $this->clstyre . '*)(?:[^\ ].*?)(?<![
"\'\ ])):([^\ \/].*)$}x', $line, $matches)) {
01795
if ($dt && $dd) { $out .= $this->add_term($dt, $dd); }
01796
$dt = $matches[1];
01797
$dd = $matches[2];
01798
} else {
01799
$dd .= "\n
" . $line;
01800
}
01801
}
01802
if ($dt && $dd) { $out .= $this->add_term($dt, $dd); }
01803
01804
$tag = '<dl';
01805
if ($clsty) { $attr = $this->format_classstyle($clsty); }
01806
if ($attr) { $tag .= " $attr
"; }
01807
$tag .= '>' . "\n
";
01808
01809
return $tag . $out . "</dl>\n
";
01810
} // function format_deflist
01811
01824 function add_term($dt, $dd) {
01825
unset($dtattr, $ddattr);
01826
unset($dtlang);
01827
if (preg_match('{^(' . $this->clstyre . '*)}x', $dt, $matches)) {
01828
$param = $matches[1];
01829
$dtattr = $this->format_classstyle($param);
01830
if (preg_match('/\[([A-Za-z]+?)\]/', $param, $matches)) {
01831
$dtlang = $matches[1];
01832
}
01833
$dt = substr($dt, strlen($param));
01834
}
01835
if (preg_match('{^(' . $this->clstyre . '*)}x', $dd, $matches)) {
01836
$param = $matches[1];
01837
// if the language was specified for the term,
01838
// then apply it to the definition as well (unless
01839
// already specified of course)
01840
if ($dtlang && preg_match('/\[([A-Za-z]+?)\]/', $param)) {
01841
unset($dtlang);
01842
}
01843
$ddattr = $this->format_classstyle(($dtlang ? "[$dtlang]
" : '') . $param);
01844
$dd = substr($dd, strlen($param));
01845
}
01846
$out = '<dt';
01847
if ($dtattr) { $out .= " $dtattr
"; }
01848
$out .= '>' . $this->format_inline(array('text' => $dt)) . '</dt>' . "\n
";
01849
if (preg_match('/\n\n/', $dd)) {
01850
if (preg_match('/\n\n/', $dd)) { $dd = $this->process($dd); }
01851
} else {
01852
$dd = $this->format_paragraph(array('text' => $dd));
01853
}
01854
$out .= '<dd';
01855
if ($ddattr) { $out .= " $ddattr
"; }
01856
$out .= '>' . $dd . '</dd>' . "\n
";
01857
return $out;
01858
} // function add_term
01859
01883 function format_list($args) {
01884
$str = (isset($args['text']) ? $args['text'] : '');
01885
01886
$list_tags = array('*' => 'ul', '#' => 'ol');
01887
01888
$lines = preg_split('/\n/', $str);
01889
01890
unset($stack);
01891
$last_depth = 0;
01892
$item = '';
01893
$out = '';
01894
foreach ($lines as $line) {
01895
if (preg_match('{^((?:' . $this->clstypadre . '*|' . $this->halignre . ')*)
01896
([\#\*]+)
01897
((?:' . $this->halignre . '|' . $this->clstypadre . '*)*)
01898
\ (.+)$}x', $line, $matches)) {
01899
if ($item != '') {
01900
if (preg_match('/\n/', $item)) {
01901
if ($this->options['_line_open']) {
01902
$item = preg_replace('/(<li[^>]*>|^)/m', '$1' . $this->options['_line_open'], $item);
01903
$item = preg_replace('/(\n|$)/s', $this->options['_line_close'] . '$1', $item);
01904
} else {
01905
$item = preg_replace('/(\n)/s', $this->options['_line_close'] . '$1', $item);
01906
}
01907
}
01908
$out .= $item;
01909
$item = '';
01910
}
01911
$type = substr($matches[2], 0, 1);
01912
$depth = strlen($matches[2]);
01913
$blockparam = $matches[1];
01914
$itemparam = $matches[3];
01915
$line = $matches[4];
01916
unset ($blockclsty, $blockalign, $blockattr, $itemattr, $itemclsty,
01917
$itemalign);
01918
if (preg_match('{(' . $this->clstypadre . '+)}x', $blockparam, $matches)) {
01919
$blockclsty = $matches[1];
01920
}
01921
if (preg_match('{(' . $this->halignre . '+)}', $blockparam, $matches)) {
01922
$blockalign = $matches[1];
01923
}
01924
if (preg_match('{(' . $this->clstypadre . '+)}x', $itemparam, $matches)) {
01925
$itemclsty = $matches[1];
01926
}
01927
if (preg_match('{(' . $this->halignre . '+)}', $itemparam, $matches)) {
01928
$itemalign = $matches[1];
01929
}
01930
if ($itemclsty) { $itemattr = $this->format_classstyle($itemclsty); }
01931
if ($depth > $last_depth) {
01932
for ($j = $last_depth; $j < $depth; $j++) {
01933
$out .= "\n<$list_tags[$type]
";
01934
$stack[] = $type;
01935
if ($blockclsty) {
01936
$blockattr = $this->format_classstyle($blockclsty);
01937
if ($blockattr) { $out .= ' ' . $blockattr; }
01938
}
01939
$out .= ">\n<li
";
01940
if ($itemattr) { $out .= " $itemattr
"; }
01941
$out .= ">
";
01942
}
01943
} elseif ($depth < $last_depth) {
01944
for ($j = $depth; $j < $last_depth; $j++) {
01945
if ($j == $depth) { $out .= "</li>\n
"; }
01946
$type = array_pop($stack);
01947
$out .= "</$list_tags[$type]>\n</li>\n
";
01948
}
01949
if ($depth) {
01950
$out .= '<li';
01951
if ($itemattr) { $out .= " $itemattr
"; }
01952
$out .= '>';
01953
}
01954
} else {
01955
$out .= "</li>\n<li
";
01956
if ($itemattr) { $out .= " $itemattr
"; }
01957
$out .= '>';
01958
}
01959
$last_depth = $depth;
01960
}
01961
if ($item != '') { $item .= "\n
"; }
01962
$item .= $this->format_paragraph(array('text' => $line));
01963
}
01964
01965
if (preg_match('/\n/', $item, $matches)) {
01966
if ($this->options['_line_open']) {
01967
$item = preg_replace('/(<li[^>]*>|^)/m', '$1' . $this->options['_line_open'], $item);
01968
$item = preg_replace('/(\n|$)/s', $this->options['_line_close'] . '$1', $item);
01969
} else {
01970
$item = preg_replace('/(\n)/s', $this->options['_line_close'] . '$1', $item);
01971
}
01972
}
01973
$out .= $item;
01974
01975
for ($j = 1; $j <= $last_depth; $j++) {
01976
if ($j == 1) { $out .= '</li>'; }
01977
$type = array_pop($stack);
01978
$out .= "\n
" . '</' . $list_tags[$type] . '>' . "\n
";
01979
if ($j != $last_depth) { $out .= '</li>'; }
01980
}
01981
01982
return $out . "\n
";
01983
} // function format_list
01984
02003 function format_block($args) {
02004
$str = (isset($args['text']) ? $args['text'] : '');
02005
$inline = $args['inline'];
02006
$pre = (isset($args['pre']) ? $args['pre'] : '');
02007
$post = (isset($args['post']) ? $args['post'] : '');
02008
$this->_strip_borders($pre, $post);
02009
$filters = (preg_match('/^(\|(?:(?:[a-z0-9_\-]+)\|)+)/', $str, $matches) ? $matches[1] : '');
02010
if ($filters) {
02011
$filtreg = preg_replace('/[^A-Za-z0-9]/', '\\\\$1', $filters);
02012
$str = preg_replace('/^' . $filtreg . '/', '', $str, 1);
02013
$filters = preg_replace('/^\|/', '', $filters, 1);
02014
$filters = preg_replace('/\|$/', '', $filter, 1);
02015
$filters = preg_split('/\|/', $filters);
02016
$str = $this->apply_filters(array('text' => $str, 'filters' => $filters));
02017
$count = count($filters);
02018
if ($str = preg_replace('!(<p>){' . $count . '}!se', '(++$i ? "$1
" : "$1
")', $str) && $i) {
02019
$str = preg_replace('!(</p>){' . $count . '}!s', '$1', $str);
02020
$str = preg_replace('!(<br( /)?>){' . $count . '}!s', '$1', $str);
02021
}
02022
}
02023
if ($inline) {
02024
// strip off opening para, closing para, since we're
02025
// operating within an inline block
02026
$str = preg_replace('/^\s*<p[^>]*>/', '', $str, 1);
02027
$str = preg_replace('/<\/p>\s*$/', '', $str, 1);
02028
}
02029
return $pre . $str . $post;
02030
} // function format_block
02031
02043 function format_link($args) {
02044
$text = (isset($args['text']) ? $args['text'] : '');
02045
$linktext = (isset($args['linktext']) ? $args['linktext'] : '');
02046
$title = $args['title'];
02047
$url = $args['url'];
02048
$clsty = $args['clsty'];
02049
02050
if (!$url || ($url == '')) {
02051
return $text;
02052
}
02053
if (isset($this->links) && isset($this->links[$url])) {
02054
$title = ($title ? $title : $this->links[$url]['title']);
02055
$url = $this->links[$url]['url'];
02056
}
02057
$linktext = preg_replace('/ +$/', '', $linktext, 1);
02058
$linktext = $this->format_paragraph(array('text' => $linktext));
02059
$url = $this->format_url(array('linktext' => $linktext, 'url' => $url));
02060
$tag = "<a href=\
"$url\"";
02061 $attr = $this->format_classstyle($clsty);
02062
if ($attr) { $tag .=
" $attr"; }
02063
if ($title) {
02064 $title = preg_replace('/^\s+/', '', $title, 1);
02065
if (strlen($title)) { $tag .=
" title=\"$title\""; }
02066 }
02067 $tag .=
">$linktext</a>";
02068
return $tag;
02069 }
02070
02081 function format_url($args) {
02082 $url = ($args['url'] ? $args['url'] : '');
02083
if (preg_match('/^(mailto:)?([-\+\w]+@[-\w]+(\.\w[-\w]*)+)$/', $url, $matches)) {
02084 $url = 'mailto:' . $this->mail_encode($matches[2]);
02085 }
02086
if (!preg_match('!^(/|\./|\.\./|#)!', $url)) {
02087
if (!preg_match('!^(https?|ftp|mailto|nntp|telnet)!', $url)) { $url =
"http://$url"; }
02088 }
02089 $url = preg_replace('/&(?!amp;)/', '&', $url);
02090 $url = preg_replace('/\ /',
'+', $url);
02091 $url = preg_replace_callback('/^((?:.+?)\?)(.+)$/', $this->_cb('$m[1] . $me->encode_url($m[2])'), $url);
02092
return $url;
02093 }
02094
02102 function format_span($args) {
02103 $text = (isset($args['text']) ? $args['text'] : '');
02104 $pre = (isset($args['pre']) ? $args['pre'] : '');
02105 $post = (isset($args['post']) ? $args['post'] : '');
02106 $align = $args['align'];
02107 $cite = (isset($args['cite']) ? $args['cite'] : '');
02108 $clsty = $args['clsty'];
02109 $this->_strip_borders($pre, $post);
02110 unset($
class, $style);
02111 $tag =
"<span";
02112 $style = '';
02113
if ($align) {
02114
if ($self->options['css_mode']) {
02115 $alignment = $this->_halign($align);
02116
if ($alignment) { $style .=
";float:$alignment"; }
02117
if ($alignment) { $class .=
' ' . $this->options['css'][
"class_align_$alignment"]; }
02118 }
else {
02119 $alignment = ($this->_halign($align) ? $this->_halign($align) : $this->_valign($align));
02120
if ($alignment) { $tag .=
" align=\"$alignment\""; }
02121 }
02122 }
02123 $attr = $this->format_classstyle($clsty, $
class, $style);
02124
if ($attr) { $tag .=
" $attr"; }
02125
if ($cite) {
02126 $cite = preg_replace('/^:/', '', $cite, 1);
02127 $cite = $this->format_url(array('url' => $cite));
02128 $tag .=
" cite=\"$cite\"";
02129 }
02130
return $pre . $tag .
'>' . $this->format_paragraph(array('text' => $text)) . '</span>' . $post;
02131 }
02132
02186 function format_image($args) {
02187 $src = (isset($args['src']) ? $args['src'] : '');
02188 $extra = $args['extra'];
02189 $align = $args['align'];
02190 $pre = (isset($args['pre']) ? $args['pre'] : '');
02191 $post = (isset($args['post']) ? $args['post'] : '');
02192 $link = $args['url'];
02193 $clsty = $args['clsty'];
02194 $this->_strip_borders($pre, $post);
02195
if (strlen($src) == 0) {
return $pre . '!!' . $post; }
02196 unset($tag);
02197
if (preg_match('/^xhtml2/', $this->options['flavor'])) {
02198 unset($type);
02199
if (preg_match('/(?:\.jpeg|\.jpg)$/i', $src)) {
02200 $type = 'image/jpeg';
02201 } elseif (preg_match('/\.gif$/i', $src)) {
02202 $type = 'image/gif';
02203 } elseif (preg_match('/\.png$/i', $src)) {
02204 $type = 'image/png';
02205 } elseif (preg_match('/\.tiff$/i', $src)) {
02206 $type = 'image/tiff';
02207 }
02208 $tag =
"<object";
02209
if ($type) { $tag .=
" type=\"$type\""; }
02210 $tag .=
" data=\"$src\"";
02211 }
else {
02212 $tag =
"<img src=\"$src\"";
02213 }
02214 unset($
class, $style);
02215
if ($align) {
02216
if ($this->options['css_mode']) {
02217 $alignment = $this->_halign($align);
02218
if ($alignment) { $style .=
";float:$alignment"; }
02219
if ($alignment) { $class .=
' ' . $alignment; }
02220 $alignment = $this->_valign($align);
02221
if ($alignment) {
02222 $imgvalign = (preg_match('/(top|bottom)/', $alignment) ? 'text-' . $alignment : $alignment);
02223
if ($imgvalign) { $style .=
";vertical-align:$imgvalign"; }
02224
if ($alignment) { $class .=
' ' . $this->options['css'][
"class_align_$alignment"]; }
02225 }
02226 }
else {
02227 $alignment = ($this->_halign($align) ? $this->_halign($align) : $this->_valign($align));
02228
if ($alignment) { $tag .=
" align=\"$alignment\""; }
02229 }
02230 }
02231 unset($pctw, $pcth, $w, $h, $alt);
02232
if ($extra) {
02233 $alt = (preg_match('/\(([^\)]+)\)/', $extra, $matches) ? $matches[1] : '');
02234 $extra = preg_replace('/\([^\)]+\)/', '', $extra, 1);
02235 $pct = (preg_match('/(^|\s)(\d+)%(\s|$)/', $extra, $matches) ? $matches[2] : '');
02236
if (!$pct) {
02237 list($pctw, $pcth) = (preg_match('/(^|\s)(\d+)%x(\d+)%(\s|$)/', $extra, $matches) ? array($matches[2], $matches[3]) : NULL);
02238 }
else {
02239 $pctw = $pcth = $pct;
02240 }
02241
if (!$pctw && !$pcth) {
02242 list($w,$h) = (preg_match('/(^|\s)(\d+|\*)x(\d+|\*)(\s|$)/', $extra, $matches) ? array($matches[2], $matches[3]) : NULL);
02243
if ($w ==
'*') { $w = ''; }
02244
if ($h ==
'*') { $h = ''; }
02245
if (!$w) {
02246 $w = (preg_match('/(^|[,\s])(\d+)w([\s,]|$)/', $extra, $matches) ? $matches[2] : '');
02247 }
02248
if (!$h) {
02249 $h = (preg_match('/(^|[,\s])(\d+)h([\s,]|$)/', $extra, $matches) ? $matches[2] : '');
02250 }
02251 }
02252 }
02253 $alt = ($alt ? $alt : '');
02254
if (!preg_match('/^xhtml2/', $this->options['flavor'])) {
02255 $tag .= ' alt=
"' . $this->encode_html_basic($alt) . '"';
02256 }
02257
if ($w && $h) {
02258
if (!preg_match('/^xhtml2/', $this->options['flavor'])) {
02259 $tag .=
" height=\"$h\" width=\"$w\"";
02260 }
else {
02261 $style .=
";height:${h}px;width:${w}px";
02262 }
02263 }
else {
02264 list($image_w, $image_h) = $this->image_size($src);
02265
if (($image_w && $image_h) && ($w || $h)) {
02266
02267
if ($w && !$h) {
02268
02269 $h = intval($image_h * ($w / $image_w));
02270 } elseif ($h && !$w) {
02271 $w = intval($image_w * ($h / $image_h));
02272 }
02273 }
else {
02274 $w = $image_w;
02275 $h = $image_h;
02276 }
02277
if ($w && $h) {
02278
if ($pctw || $pcth) {
02279 $w = intval($w * $pctw / 100);
02280 $h = intval($h * $pcth / 100);
02281 }
02282
if (!preg_match('/^xhtml2/', $this->options['flavor'])) {
02283 $tag .=
" height=\"$h\" width=\"$w\"";
02284 }
else {
02285 $style .=
";height:{$h}px;width:{$w}px";
02286 }
02287 }
02288 }
02289 $attr = $this->format_classstyle($clsty, $
class, $style);
02290
if ($attr) { $tag .=
" $attr"; }
02291
if (preg_match('/^xhtml2/', $this->options['flavor'])) {
02292 $tag .= '><p>' . $this->encode_html_basic($alt) . '</p></object>';
02293 } elseif (preg_match('/^xhtml/', $this->options['flavor'])) {
02294 $tag .= ' />';
02295 }
else {
02296 $tag .=
'>';
02297 }
02298
if ($link) {
02299 $link = preg_replace('/^:/', '', $link, 1);
02300 $link = $this->format_url(array('url' => $link));
02301 $tag = '<a href=
"' . $link . '">' . $tag . '</a>';
02302 }
02303
return $pre . $tag . $post;
02304 }
02305
02317 function format_table($args) {
02318 $str = (isset($args['text']) ? $args['text'] : '');
02319
02320 $lines = preg_split('/\n/', $str);
02321 unset($rows);
02322 $line_count = count($lines);
02323
for ($i = 0; $i < $line_count; $i++) {
02324
if (!preg_match('/\|\s*$/', $lines[$i])) {
02325
if ($i + 1 < $line_count) {
02326
if ($i + 1 <= count($lines) - 1) { $lines[$i + 1] = $lines[$i] .
"\n" . $lines[$i + 1]; }
02327 }
else {
02328 $rows[] = $lines[$i];
02329 }
02330 }
else {
02331 $rows[] = $lines[$i];
02332 }
02333 }
02334 unset($tid, $tpadl, $tpadr, $tlang);
02335 $tclass = '';
02336 $tstyle = '';
02337 $talign = '';
02338
if (preg_match('/^table[^\.]/', $rows[0])) {
02339 $row = $rows[0];
02340 $row = preg_replace('/^table/', '', $row, 1);
02341 $params = 1;
02342
02343
while ($params) {
02344
if (preg_match('{^(' . $this->tblalignre . ')}', $row, $matches)) {
02345
02346 $talign .= $matches[1];
02347
if ($matches[1]) { $row = substr($row, strlen($matches[1])); }
02348
if ($matches[1]) {
continue; }
02349 }
02350
if (preg_match('{^(' . $this->clstypadre . ')}x', $row, $matches)) {
02351
02352 $clsty = $matches[1];
02353
if ($clsty) { $row = substr($row, strlen($clsty)); }
02354
if (preg_match('/{([^}]+)}/', $clsty, $matches)) {
02355 $tstyle = $matches[1];
02356 $clsty = preg_replace('/{([^}]+)}/', '', $clsty, 1);
02357
if ($tstyle) {
continue; }
02358 }
02359
if (preg_match('/\(([A-Za-z0-9_\- ]+?)(?:#(.+?))?\)/', $clsty, $matches) ||
02360 preg_match('/\(([A-Za-z0-9_\- ]+?)?(?:#(.+?))\)/', $clsty, $matches)) {
02361
if ($matches[1] || $matches[2]) {
02362 $tclass = $matches[1];
02363 $tid = $matches[2];
02364
continue;
02365 }
02366 }
02367
if (preg_match('/(\(+)/', $clsty, $matches)) { $tpadl = strlen($matches[1]); }
02368
if (preg_match('/(\)+)/', $clsty, $matches)) { $tpadr = strlen($matches[1]); }
02369
if (preg_match('/\[(.+?)\]/', $clsty, $matches)) { $tlang = $matches[1]; }
02370
if ($clsty) {
continue; }
02371 }
02372 $params = 0;
02373 }
02374 $row = preg_replace('/\.\s+/', '', $row, 1);
02375 $rows[0] = $row;
02376 }
02377 $out = '';
02378 $cols = preg_split('/\|/', $rows[0] .
' ');
02379 unset($colaligns, $rowspans);
02380 foreach ($rows as $row) {
02381 $cols = preg_split('/\|/', $row .
' ');
02382 $colcount = count($cols) - 1;
02383 array_pop($cols);
02384 $colspan = 0;
02385 $row_out = '';
02386 unset($rowclass, $rowid, $rowalign, $rowstyle, $rowheader);
02387
if (!$cols[0]) { $cols[0] = ''; }
02388
if (preg_match('/_/', $cols[0])) {
02389 $cols[0] = preg_replace('/_/', '', $cols[0]);
02390 $rowheader = 1;
02391 }
02392
if (preg_match('/{([^}]+)}/', $cols[0], $matches)) {
02393 $rowstyle = $matches[1];
02394 $cols[0] = preg_replace('/{[^}]+}/', '', $cols[0]);
02395 }
02396
if (preg_match('/\(([^\#]+?)?(#(.+))?\)/', $cols[0], $matches)) {
02397 $rowclass = $matches[1];
02398 $rowid = $matches[3];
02399 $cols[0] = preg_replace('/\([^\)]+\)/', '', $cols[0]);
02400 }
02401
if (preg_match('{(' . $this->alignre . ')}', $cols[0], $matches)) { $rowalign = $matches[1]; }
02402
for ($c = $colcount - 1; $c > 0; $c--) {
02403
if ($rowspans[$c]) {
02404 $rowspans[$c]--;
02405
if ($rowspans[$c] > 1) {
continue; }
02406 }
02407 unset($colclass, $colid, $header, $colparams, $colpadl, $colpadr, $collang);
02408 $colstyle = '';
02409 $colalign = $colaligns[$c];
02410 $col = array_pop($cols);
02411 $col = ($col ? $col : '');
02412 $attrs = '';
02413
if (preg_match('{^(((_|[/\\\\]\d+|' . $this->alignre .
'|' . $this->clstypadre . ')+)\.\ )}x', $col, $matches)) {
02414 $colparams = $matches[2];
02415 $col = substr($col, strlen($matches[1]));
02416 $params = 1;
02417
02418
02419
while ($params) {
02420
if (preg_match('{^(_|' . $this->alignre . ')(.*)$}', $colparams, $matches)) {
02421
02422 $attrs .= $matches[1];
02423
if ($matches[1]) { $colparams = $matches[2]; }
02424
if ($matches[1]) {
continue; }
02425 }
02426
if (preg_match('{^(' . $this->clstypadre . ')(.*)$}x', $colparams, $matches)) {
02427
02428 $clsty = $matches[1];
02429
if ($clsty) { $colparams = $matches[2]; }
02430
if (preg_match('/{([^}]+)}/', $clsty, $matches)) {
02431 $colstyle = $matches[1];
02432 $clsty = preg_replace('/{([^}]+)}/', '', $clsty, 1);
02433 }
02434
if (preg_match('/\(([A-Za-z0-9_\- ]+?)(?:#(.+?))?\)/', $clsty, $matches) ||
02435 preg_match('/\(([A-Za-z0-9_\- ]+?)?(?:#(.+?))\)/', $clsty, $matches)) {
02436
if ($matches[1] || $matches[2]) {
02437 $colclass = $matches[1];
02438 $colid = $matches[2];
02439
if ($colclass) {
02440 $clsty = preg_replace('/\([A-Za-z0-9_\- ]+?(#.*?)?\)/', '', $clsty);
02441 } elseif ($colid) {
02442 $clsty = preg_replace('/\(#.+?\)/', '', $clsty);
02443 }
02444 }
02445 }
02446
if (preg_match('/(\(+)/', $clsty, $matches)) {
02447 $colpadl = strlen($matches[1]);
02448 $clsty = preg_replace('/\(+/', '', $clsty, 1);
02449 }
02450
if (preg_match('/(\)+)/', $clsty, $matches)) {
02451 $colpadr = strlen($matches[1]);
02452 $clsty = preg_replace('/\)+/', '', $clsty, 1);
02453 }
02454
if (preg_match('/\[(.+?)\]/', $clsty, $matches)) {
02455 $collang = $matches[1];
02456 $clsty = preg_replace('/\[.+?\]/', '', $clsty, 1);
02457 }
02458
if ($clsty) {
continue; }
02459 }
02460
if (preg_match('/^\\\\(\d+)/', $colparams, $matches)) {
02461 $colspan = $matches[1];
02462 $colparams = substr($colparams, strlen($matches[1]) + 1);
02463
if ($matches[1]) {
continue; }
02464 }
02465
if (preg_match('/\/(\d+)/', $colparams, $matches)) {
02466
if ($matches[1]) { $rowspans[$c] = $matches[1]; }
02467 $colparams = substr($colparams, strlen($matches[1]) + 1);
02468
if ($matches[1]) {
continue; }
02469 }
02470 $params = 0;
02471 }
02472 }
02473
if (strlen($attrs)) {
02474
if (preg_match('/_/', $attrs)) { $header = 1; }
02475
if (preg_match('{(' . $this->alignre . ')}', $attrs, $matches) && strlen($matches[1])) { $colalign = ''; }
02476
02477
if (preg_match('/<>/', $attrs)) {
02478 $colalign .= '<>';
02479 } elseif (preg_match('/</', $attrs)) {
02480 $colalign .=
'<';
02481 } elseif (preg_match('/=/', $attrs)) {
02482 $colalign =
'=';
02483 } elseif (preg_match('/>/', $attrs)) {
02484 $colalign =
'>';
02485 }
02486
if (preg_match('/\^/', $attrs)) {
02487 $colalign .=
'^';
02488 } elseif (preg_match('/~/', $attrs)) {
02489 $colalign .=
'~';
02490 } elseif (preg_match('/-/', $attrs)) {
02491 $colalign .=
'-';
02492 }
02493 }
02494
if ($rowheader) { $header = 1; }
02495
if ($header) { $colaligns[$c] = $colalign; }
02496 $col = preg_replace('/^ +/', '', $col, 1); $col = preg_replace('/ +$/', '', $col, 1);
02497
if (strlen($col)) {
02498
02499 $rowspan = ($rowspans[$c] ? $rowspans[$c] : 0);
02500 $col_out =
'<' . ($header ? 'th' : 'td');
02501
if ($colalign) {
02502
02503 $halign = $this->_halign($colalign);
02504
if ($halign) { $col_out .=
" align=\"$halign\""; }
02505 $valign = $this->_valign($colalign);
02506
if ($valign) { $col_out .=
" valign=\"$valign\""; }
02507 }
02508
02509
if ($colpadl) { $colstyle .=
";padding-left:${colpadl}em"; }
02510
if ($colpadr) { $colstyle .=
";padding-right:${colpadr}em"; }
02511
if ($colclass) { $col_out .=
" class=\"$colclass\""; }
02512
if ($colid) { $col_out .=
" id=\"$colid\""; }
02513
if ($colstyle) { $colstyle = preg_replace('/^;/', '', $colstyle, 1); }
02514
if ($colstyle) { $col_out .=
" style=\"$colstyle\""; }
02515
if ($collang) { $col_out .=
" lang=\"$collang\""; }
02516
if ($colspan > 1) { $col_out .=
" colspan=\"$colspan\""; }
02517
if ($rowspan > 1) { $col_out .=
" rowspan=\"$rowspan\""; }
02518 $col_out .=
'>';
02519
02520
02521
02522
if (preg_match('/\n\n/', $col) ||
02523 preg_match('{^(?:' . $this->halignre .
'|' . $this->clstypadre . '*)*
02524 [\*\#]
02525 (?:' . $this->clstypadre . '*|' . $this->halignre . ')*\ }x', $col)) {
02526 $col_out .= $this->process($col);
02527 }
else {
02528 $col_out .= $this->format_paragraph(array('text' => $col));
02529 }
02530 $col_out .= '</' . ($header ? 'th' : 'td') .
'>';
02531 $row_out = $col_out . $row_out;
02532
if ($colspan) { $colspan = 0; }
02533 }
else {
02534
if ($colspan == 0) { $colspan = 1; }
02535 $colspan++;
02536 }
02537 }
02538
if ($colspan > 1) {
02539
02540 $colspan--;
02541 $row_out =
"<td"
02542 . ($colspan > 1 ?
" colspan=\"$colspan\"" : '')
02543 .
"></td>$row_out";
02544 }
02545
02546
02547 $out .=
"<tr";
02548
if ($rowalign) {
02549 $valign = $this->_valign($rowalign);
02550
if ($valign) { $out .=
" valign=\"$valign\""; }
02551 }
02552
if ($rowclass) { $out .=
" class=\"$rowclass\""; }
02553
if ($rowid) { $out .=
" id=\"$rowid\""; }
02554
if ($rowstyle) { $out .=
" style=\"$rowstyle\""; }
02555 $out .=
">$row_out</tr>";
02556 }
02557
02558
02559 $table = '';
02560 $table .=
"<table";
02561
if ($talign) {
02562
if ($this->options['css_mode']) {
02563
02564 $alignment = $this->_halign($talign);
02565
if ($talign ==
'=') {
02566 $tstyle .= ';margin-left:
auto;margin-right:
auto';
02567 }
else {
02568
if ($alignment) { $tstyle .= ';
float:' . $alignment; }
02569 }
02570
if ($alignment) { $tclass .=
' ' . $alignment; }
02571 }
else {
02572 $alignment = $this->_halign($talign);
02573
if ($alignment) { $table .=
" align=\"$alignment\""; }
02574 }
02575 }
02576
if ($tpadl) { $tstyle .=
";padding-left:${tpadl}em"; }
02577
if ($tpadr) { $tstyle .=
";padding-right:${tpadr}em"; }
02578
if ($tclass) { $tclass = preg_replace('/^ /', '', $tclass, 1); }
02579
if ($tclass) { $table .=
" class=\"$tclass\""; }
02580
if ($tid) { $table .=
" id=\"$tid\""; }
02581
if ($tstyle) { $tstyle = preg_replace('/^;/', '', $tstyle, 1); }
02582
if ($tstyle) { $table .=
" style=\"$tstyle\""; }
02583
if ($tlang) { $table .=
" lang=\"$tlang\""; }
02584
if ($tclass || $tid || $tstyle) { $table .=
" cellspacing=\"0\""; }
02585 $table .=
">$out</table>";
02586
02587
if (preg_match('|<tr></tr>|', $table)) {
02588
02589
return NULL;
02590 }
02591
02592
return $table;
02593 }
02594
02617 function apply_filters($args) {
02618 $text = $args['text'];
02619
if (!$text) {
return ''; }
02620 $list = $args['filters'];
02621 $filters = $this->options['filters'];
02622
if (!is_array($filters)) {
return $text; }
02623
02624 $param = $this->filter_param();
02625 foreach ($list as $filter) {
02626
if (!isset($filters[$filter])) {
continue; }
02627
if (is_string($filters[$filter])) {
02628 $text = (($f = create_function('$text, $param', $filters[$filter])) ? $f($text, $param) : $text);
02629 }
02630 }
02631
return $text;
02632 }
02633
02634
02635
02636 var $Have_Entities = 1;
02637
02654 function encode_html($html, $can_double_encode = FALSE) {
02655
if (!$html) {
return ''; }
02656
if ($this->Have_Entities && $this->options['char_encoding']) {
02657 $html = htmlentities($html);
02658 }
else {
02659 $html = $this->encode_html_basic($html, $can_double_encode);
02660 }
02661
return $html;
02662 }
02663
02674 function decode_html($html) {
02675 $html = preg_replace('!"!',
'"', $html);
02676 $html = preg_replace('!&!',
'&', $html);
02677 $html = preg_replace('!<!',
'<', $html);
02678 $html = preg_replace('!>!',
'>', $html);
02679
return $html;
02680 }
02681
02698 function encode_html_basic($html, $can_double_encode = FALSE) {
02699
if (!$html) {
return ''; }
02700
if (!preg_match('/[^\w\s]/', $html)) {
return $html; }
02701
if ($can_double_encode) {
02702 $html = preg_replace('!&!', '&', $html);
02703 }
else {
02704
02705
02706 $html = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w{1,8});)/', '&', $html);
02707 }
02708 $html = preg_replace('!
"!', '"', $html);
02709
$html = preg_replace('!<!', '<', $html);
02710
$html = preg_replace('!>!', '>', $html);
02711
return $html;
02712
} // function encode_html_basic
02713
02729 function image_size($file) {
02730
$Have_ImageSize = function_exists('getimagesize');
02731
02732
if ($Have_ImageSize) {
02733
if (file_exists($file)) {
02734
return @getimagesize($file);
02735
} else {
02736
if ($docroot = ($this->docroot() ? $this->docroot() : $_SERVER['DOCUMENT_ROOT'])) {
02737
$fullpath = $docroot . preg_replace('|^/*(.*)$|', '/$1', $file);
02738
if (file_exists($fullpath)) {
02739
return @getimagesize($fullpath);
02740
}
02741
}
02742
}
02743
}
02744
return @getimagesize($file);
02745
} // function image_size
02746
02757 function encode_url($str) {
02758
$str = preg_replace_callback('!([^A-Za-z0-9_\.\-\+\&=%;])!x',
02759
$this->_cb('ord($m[1]) > 255 ? \'%u\' . sprintf("%04X
", ord($m[1]))
02760
: \'%\' . sprintf("%02X
", ord($m[1]))'), $str);
02761
return $str;
02762
} // function encode_url
02763
02773 function mail_encode($addr) {
02774
// granted, this is simple, but it gives off warm fuzzies
02775
$addr = preg_replace_callback('!([^\$])!x',
02776
$this->_cb('ord($m[1]) > 255 ? \'%u\' . sprintf("%04X
", ord($m[1]))
02777
: \'%\' . sprintf("%02X
", ord($m[1]))'), $addr);
02778
return $addr;
02779
} // function mail_encode
02780
02790 function process_quotes($str) {
02791
// stub routine for now. subclass and implement.
02792
return $str;
02793
} // function process_quotes
02794
02795
// a default set of macros for the {...} macro syntax
02796
// just a handy way to write a lot of the international characters
02797
// and some commonly used symbols
02798
02807 function default_macros() {
02808
// <, >, " must be html entities in the macro text since
02809
02810
02811
return array(
02812 'c|' => '¢',
02813 '|c' => '¢',
02814 'L-' => '£',
02815 '-L' => '£',
02816 'Y=' => '¥',
02817 '=Y' => '¥',
02818 '(c)' => '©',
02819 '<<' => '«',
02820 '(r)' => '®',
02821 '+_' => '±',
02822 '_+' => '±',
02823 '>>' => '»',
02824 '1/4' => '¼',
02825 '1/2' => '½',
02826 '3/4' => '¾',
02827 'A`' => 'À',
02828 '`A' => 'À',
02829 'A\'' => 'Á',
02830
'\'A' => 'Á',
02831 'A^' => 'Â',
02832 '^A' => 'Â',
02833 'A~' => 'Ã',
02834 '~A' => 'Ã',
02835 'A
"' => 'Ä', // LATIN CAPITAL LETTER A WITH DIAERESIS
02836
'"A' => 'Ä',
02837 'Ao' => 'Å',
02838 'oA' => 'Å',
02839 'AE' => 'Æ',
02840 'C,' => 'Ç',
02841 ',C' => 'Ç',
02842 'E`' => 'È',
02843 '`E' => 'È',
02844 'E\'' => 'É',
02845
'\'E' => 'É',
02846 'E^' => 'Ê',
02847 '^E' => 'Ê',
02848 'E
"' => 'Ë', // LATIN CAPITAL LETTER E WITH DIAERESIS
02849
'"E' => 'Ë',
02850 'I`' => 'Ì',
02851 '`I' => 'Ì',
02852 'I\'' => 'Í',
02853
'\'I' => 'Í',
02854 'I^' => 'Î',
02855 '^I' => 'Î',
02856 'I
"' => 'Ï', // LATIN CAPITAL LETTER I WITH DIAERESIS
02857
'"I' => 'Ï',
02858 'D-' => 'Ð',
02859 '-D' => 'Ð',
02860 'N~' => 'Ñ',
02861 '~N' => 'Ñ',
02862 'O`' => 'Ò',
02863 '`O' => 'Ò',
02864 'O\'' => 'Ó',
02865
'\'O' => 'Ó',
02866 'O^' => 'Ô',
02867 '^O' => 'Ô',
02868 'O~' => 'Õ',
02869 '~O' => 'Õ',
02870 'O
"' => 'Ö', // LATIN CAPITAL LETTER O WITH DIAERESIS
02871
'"O' => 'Ö',
02872 'O/' => 'Ø',
02873 '/O' => 'Ø',
02874 'U`' => 'Ù',
02875 '`U' => 'Ù',
02876 'U\'' => 'Ú',
02877
'\'U' => 'Ú',
02878 'U^' => 'Û',
02879 '^U' => 'Û',
02880 'U
"' => 'Ü', // LATIN CAPITAL LETTER U WITH DIAERESIS
02881
'"U' => 'Ü',
02882 'Y\'' => 'Ý',
02883
'\'Y' => 'Ý',
02884 'a`' => 'à',
02885 '`a' => 'à',
02886 'a\'' => 'á',
02887
'\'a' => 'á',
02888 'a^' => 'â',
02889 '^a' => 'â',
02890 'a~' => 'ã',
02891 '~a' => 'ã',
02892 'a
"' => 'ä', // LATIN SMALL LETTER A WITH DIAERESIS
02893
'"a' => 'ä',
02894 'ao' => 'å',
02895 'oa' => 'å',
02896 'ae' => 'æ',
02897 'c,' => 'ç',
02898 ',c' => 'ç',
02899 'e`' => 'è',
02900 '`e' => 'è',
02901 'e\'' => 'é',
02902
'\'e' => 'é',
02903 'e^' => 'ê',
02904 '^e' => 'ê',
02905 'e
"' => 'ë', // LATIN SMALL LETTER E WITH DIAERESIS
02906
'"e' => 'ë',
02907 'i`' => 'ì',
02908 '`i' => 'ì',
02909 'i\'' => 'í',
02910
'\'i' => 'í',
02911 'i^' => 'î',
02912 '^i' => 'î',
02913 'i
"' => 'ï', // LATIN SMALL LETTER I WITH DIAERESIS
02914
'"i' => 'ï',
02915 'n~' => 'ñ',
02916 '~n' => 'ñ',
02917 'o`' => 'ò',
02918 '`o' => 'ò',
02919 'o\'' => 'ó',
02920
'\'o' => 'ó',
02921 'o^' => 'ô',
02922 '^o' => 'ô',
02923 'o~' => 'õ',
02924 '~o' => 'õ',
02925 'o
"' => 'ö', // LATIN SMALL LETTER O WITH DIAERESIS
02926
'"o' => 'ö',
02927 ':-' => '÷',
02928 '-:' => '÷',
02929 'o/' => 'ø',
02930 '/o' => 'ø',
02931 'u`' => 'ù',
02932 '`u' => 'ù',
02933 'u\'' => 'ú',
02934
'\'u' => 'ú',
02935 'u^' => 'û',
02936 '^u' => 'û',
02937 'u
"' => 'ü', // LATIN SMALL LETTER U WITH DIAERESIS
02938
'"u' => 'ü',
02939 'y\'' => 'ý',
02940
'\'y' => 'ý',
02941 'y
"' => 'ÿ', // LATIN SMALL LETTER Y WITH DIAERESIS
02942
'"y' => 'ÿ',
02943 'OE' => 'Œ',
02944 'oe' => 'œ',
02945
'*' => '•',
02946 'Fr' => '₣',
02947 'L=' => '₤',
02948 '=L' => '₤',
02949 'Rs' => '₨',
02950 'C=' => '€',
02951 '=C' => '€',
02952 'tm' => '™',
02953 '<-' => '←',
02954 '->' => '→',
02955 '<=' => '⇐',
02956 '=>' => '⇒',
02957 '=/' => '≠',
02958 '/=' => '≠',
02959 '<_' => '≤',
02960 '_<' => '≤',
02961 '>_' => '≥',
02962 '_>' => '≥',
02963 ':(' => '☹',
02964 ':)' => '☺',
02965 'spade' => '♠',
02966 'club' => '♣',
02967 'heart' => '♥',
02968 'diamond' => '♦',
02969 );
02970 }
02971
02972
02973
02980 function _css_defaults() {
02981 $css_defaults = array(
02982 'class_align_right' => 'right',
02983 'class_align_left' => 'left',
02984 'class_align_center' => 'center',
02985 'class_align_top' => 'top',
02986 'class_align_bottom' => 'bottom',
02987 'class_align_middle' => 'middle',
02988 'class_align_justify' => 'justify',
02989 'class_caps' => 'caps',
02990 'class_footnote' => 'footnote',
02991 'id_footnote_prefix' => 'fn',
02992 );
02993 $this->css($css_defaults);
02994 }
02995
03025 function _halign($align) {
03026
if (preg_match('/<>/', $align)) {
03027
return 'justify';
03028 } elseif (preg_match('/</', $align)) {
03029
return 'left';
03030 } elseif (preg_match('/>/', $align)) {
03031
return 'right';
03032 } elseif (preg_match('/=/', $align)) {
03033
return 'center';
03034 }
03035
return '';
03036 }
03037
03063 function _valign($align) {
03064
if (preg_match('/\^/', $align)) {
03065
return 'top';
03066 } elseif (preg_match('/~/', $align)) {
03067
return 'bottom';
03068 } elseif (preg_match('/-/', $align)) {
03069
return 'middle';
03070 }
03071
return '';
03072 }
03073
03109 function _imgalign($align) {
03110 $align = preg_replace('/(<>|=)/', '', $align);
03111
return ($this->_valign($align) ? $this->_valign($align) : $this->_halign($align));
03112 }
03113
03130 function _strip_borders(&$pre, &$post) {
03131
if ($post && $pre && preg_match('/[{[]/', ($open = substr($pre, 0, 1)))) {
03132 $close = substr($post, 0, 1);
03133
if ((($open ==
'{') && ($close ==
'}')) ||
03134 (($open ==
'[') && ($close ==
']'))) {
03135 $pre = substr($pre, 1);
03136 $post = substr($post, 1);
03137 }
else {
03138
if (!preg_match('/[}\]]/', $close)) { $close = substr($post, -1, 1); }
03139
if ((($open ==
'{') && ($close ==
'}')) ||
03140 (($open ==
'[') && ($close ==
']'))) {
03141 $pre = substr($pre, 1);
03142 $post = substr($post, 0, strlen($post) - 1);
03143 }
03144 }
03145 }
03146 }
03147
03162 function _repl(&$array, $str) {
03163 $array[] = $str;
03164
return '<textile#' . count($array) .
'>';
03165 }
03166
03177 function _tokenize($str) {
03178 $pos = 0;
03179 $len = strlen($str);
03180 unset($tokens);
03181
03182 $depth = 6;
03183 $nested_tags = substr(str_repeat('(?:</?[A-Za-z0-9:]+ \s? (?:[^<>]|', $depth), 0, -1)
03184 . str_repeat(')*>)', $depth);
03185 $match = '(?s: <! ( -- .*? -- \s* )+ > )| # comment
03186 (?s: <\? .*? \?> )| # processing instruction
03187 (?s: <% .*? %> )| # ASP-like
03188 (?:' . $nested_tags . ')|
03189 (?:' . $this->codere .
')';
03190
03191
while (preg_match('{(' . $match . ')}x', substr($str, $pos), $matches, PREG_OFFSET_CAPTURE)) {
03192 $whole_tag = $matches[1][0];
03193 $sec_start = $pos + $matches[1][1] + strlen($whole_tag);
03194 $tag_start = $sec_start - strlen($whole_tag);
03195
if ($pos < $tag_start) {
03196 $tokens[] = array('text', substr($str, $pos, $tag_start - $pos));
03197 }
03198
if (preg_match('/^[[{]?@/', $whole_tag)) {
03199 $tokens[] = array('text', $whole_tag);
03200 }
else {
03201
03202
03203
03204 $whole_tag = preg_replace('/\n/',
"\001", $whole_tag);
03205 $tokens[] = array('tag', $whole_tag);
03206 }
03207 $pos = $sec_start;
03208 }
03209
if ($pos < $len) { $tokens[] = array('text', substr($str, $pos, $len - $pos)); }
03210
return $tokens;
03211 }
03212
03221 function version() {
03222
03223
03224
03225
03226
03227
03228
return array(
"text" =>
"2.0.8",
"build" => 2005032100);
03229 }
03230
03243 function _cb($function) {
03244 $current =&
Textile::_current_store($
this);
03245
return create_function('$m', '$me =&
Textile::_current();
return ' . $function .
';');
03246 }
03247
03263 function &_current_store(&$
new) {
03264
static $current = array();
03265
03266
if ($new != NULL) {
03267 $current = array(&$
new);
03268 }
03269
03270
return $current;
03271 }
03272
03283 function &_current() {
03284 $current =&
Textile::_current_store($null = NULL);
03285
return $current[0];
03286 }
03287 }
03288
03337 class MTLikeTextile extends Textile {
03349 function
MTLikeTextile($options = array()) {
03350 parent::Textile($options);
03351 }
03352
03356 function
process_quotes($str) {
03357
if (!$this->options['do_quotes'] || !function_exists('SmartyPants')) {
03358
return $str;
03359 }
03360
03361
return SmartyPants($str, $this->options['smarty_mode']);
03362 }
03363
03367 function
format_url($args) {
03368 $url = ($args['url'] ? $args['url'] : '');
03369
03370
if (preg_match('/^(imdb|google|dict|amazon)(:(.+))?$/x', $url, $matches)) {
03371 $term = $matches[3];
03372 $term = ($term ? $term : strip_tags($args['linktext']));
03373
03374
switch ($matches[1]) {
03375
case 'imdb':
03376 $args['url'] = 'http:
03377
break;
03378
03379
case 'google':
03380 $args['url'] = 'http:
03381
break;
03382
03383
case 'dict':
03384 $args['url'] = 'http:
03385
break;
03386
03387
case 'amazon':
03388 $args['url'] = 'http:
03389
break;
03390 }
03391 }
03392
03393
return parent::format_url($args);
03394 }
03395 }
03396
04080 ?>