Changeset 2128

Show
Ignore:
Timestamp:
01/24/05 06:30:16 (4 years ago)
Author:
saxmatt
Message:

Updating Markdown to 1.0.1 - http://mosquito.wordpress.org/view.php?id=730

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/wp-content/plugins/markdown.php

    r1593 r2128  
    77# <http://daringfireball.net/projects/markdown/> 
    88# 
    9 # Copyright (c) 2004 Michel Fortin - Translation to PHP   
     9# Copyright (c) 2004 Michel Fortin - PHP Port   
    1010# <http://www.michelf.com/projects/php-markdown/> 
    1111# 
    12  
    13 # This version has been modified for inclusion in WordPress 
    14 # For the original please see Michel's site 
    1512 
    1613 
     
    1815        $md_empty_element_suffix, $md_tab_width, 
    1916        $md_nested_brackets_depth, $md_nested_brackets,  
    20         $md_escape_table, $md_backslash_escape_table; 
    21  
    22  
    23 $MarkdownPHPVersion    = '1.0'; # Sat 21 Aug 2004 
    24 $MarkdownSyntaxVersion = '1.0'; # Fri 20 Aug 2004 
     17        $md_escape_table, $md_backslash_escape_table,  
     18        $md_list_level; 
     19 
     20$MarkdownPHPVersion    = '1.0.1'; # Fri 17 Dec 2004 
     21$MarkdownSyntaxVersion = '1.0.1'; # Sun 12 Dec 2004 
    2522 
    2623 
     
    3532/* 
    3633Plugin Name: Markdown 
    37 Plugin URI: http://codex.wordpress.org/Plugin:Markdown 
     34Plugin URI: http://www.michelf.com/projects/php-markdown/ 
    3835Description: <a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a> 
    39 Version: 1.0 
     36Version: 1.0.1 
    4037Author: Michel Fortin 
    4138Author URI: http://www.michelf.com/ 
     
    5249} 
    5350 
     51 
     52# -- bBlog Plugin Info -------------------------------------------------------- 
     53function identify_modifier_markdown() { 
     54    global $MarkdownPHPVersion; 
     55    return array( 
     56        'name'          => 'markdown', 
     57        'type'          => 'modifier', 
     58        'nicename'      => 'Markdown', 
     59        'description'   => 'A text-to-HTML conversion tool for web writers', 
     60        'authors'       => 'Michel Fortin and John Gruber', 
     61        'licence'       => 'GPL', 
     62        'version'       => $MarkdownPHPVersion, 
     63        'help'          => '<a href="http://daringfireball.net/projects/markdown/syntax">Markdown syntax</a> allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by <a href="http://daringfireball.net/">John Gruber</a>. <a href="http://www.michelf.com/projects/php-markdown/">More...</a>' 
     64    ); 
     65} 
     66 
     67# -- Smarty Modifier Interface ------------------------------------------------ 
    5468function smarty_modifier_markdown($text) { 
    5569    return Markdown($text); 
    5670} 
    5771 
     72# -- Textile Compatibility Mode ----------------------------------------------- 
     73# Rename this file to "classTextile.php" and it can replace Textile anywhere. 
     74if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) { 
     75    # Try to include PHP SmartyPants. Should be in the same directory. 
     76    @include_once 'smartypants.php'; 
     77    # Fake Textile class. It calls Markdown instead. 
     78    class Textile { 
     79        function TextileThis($text, $lite='', $encode='', $noimage='', $strict='') { 
     80            if ($lite == '' && $encode == '')   $text = Markdown($text); 
     81            if (function_exists('SmartyPants')) $text = SmartyPants($text); 
     82            return $text; 
     83        } 
     84    } 
     85} 
     86 
     87 
     88 
     89# 
     90# Globals: 
     91# 
     92 
     93# Regex to match balanced [brackets]. 
     94# Needed to insert a maximum bracked depth while converting to PHP. 
    5895$md_nested_brackets_depth = 6; 
    5996$md_nested_brackets =  
     
    6198    str_repeat('\])*', $md_nested_brackets_depth); 
    6299 
     100# Table of hash values for escaped characters: 
    63101$md_escape_table = array( 
    64102    "\\" => md5("\\"), 
     
    72110    "(" => md5("("), 
    73111    ")" => md5(")"), 
     112    ">" => md5(">"), 
    74113    "#" => md5("#"), 
     114    "+" => md5("+"), 
     115    "-" => md5("-"), 
    75116    "." => md5("."), 
    76117    "!" => md5("!") 
     
    83124 
    84125function Markdown($text) { 
     126# 
     127# Main function. The order in which other subs are called here is 
     128# essential. Link and image substitutions need to happen before 
     129# _EscapeSpecialChars(), so that any *'s or _'s in the <a> 
     130# and <img> tags get encoded. 
     131# 
     132    # Clear the global hashes. If we don't clear these, you get conflicts 
     133    # from other articles when generating a page which contains more than 
     134    # one article (e.g. an index page that shows the N most recent 
     135    # articles): 
    85136    global $md_urls, $md_titles, $md_html_blocks; 
    86137    $md_urls = array(); 
     
    88139    $md_html_blocks = array(); 
    89140 
     141    # Standardize line endings: 
     142    #   DOS to Unix and Mac to Unix 
    90143    $text = str_replace(array("\r\n", "\r"), "\n", $text); 
    91144 
     145    # Make sure $text ends with a couple of newlines: 
    92146    $text .= "\n\n"; 
    93147 
     148    # Convert all tabs to spaces. 
    94149    $text = _Detab($text); 
    95150 
     151    # Strip any lines consisting only of spaces and tabs. 
     152    # This makes subsequent regexen easier to write, because we can 
     153    # match consecutive blank lines with /\n+/ instead of something 
     154    # contorted like /[ \t]*\n+/ . 
    96155    $text = preg_replace('/^[ \t]+$/m', '', $text); 
    97156 
     157    # Turn block-level HTML blocks into hash entries 
    98158    $text = _HashHTMLBlocks($text); 
    99159 
     160    # Strip link definitions, store in hashes. 
    100161    $text = _StripLinkDefinitions($text); 
    101162 
    102     $text = _EscapeSpecialChars($text); 
    103  
    104163    $text = _RunBlockGamut($text); 
    105164 
     
    111170 
    112171function _StripLinkDefinitions($text) { 
     172# 
     173# Strips link definitions from text, stores the URLs and titles in 
     174# hash references. 
     175# 
     176    global $md_tab_width; 
     177    $less_than_tab = $md_tab_width - 1; 
     178 
     179    # Link defs are in the form: ^[id]: url "optional title" 
    113180    $text = preg_replace_callback('{ 
    114                         ^[ \t]*\[(.+)\]:  # id = $1 
     181                        ^[ ]{0,'.$less_than_tab.'}\[(.+)\]:   # id = $1 
    115182                          [ \t]* 
    116183                          \n?               # maybe *one* newline 
     
    121188                          [ \t]* 
    122189                        (?: 
    123                             # Todo: Titles are delimited by "quotes" or (parens). 
     190                            (?<=\s)            # lookbehind for whitespace 
    124191                            ["(] 
    125192                            (.+?)           # title = $3 
     
    138205    $md_urls[$link_id] = _EncodeAmpsAndAngles($matches[2]); 
    139206    if (isset($matches[3])) 
    140         $md_titles[$link_id] = htmlentities($matches[3]); 
     207        $md_titles[$link_id] = str_replace('"', '&quot;', $matches[3]); 
    141208    return ''; # String that will replace the block 
    142209} 
     
    144211 
    145212function _HashHTMLBlocks($text) { 
     213    global $md_tab_width; 
     214    $less_than_tab = $md_tab_width - 1; 
     215 
     216    # Hashify HTML blocks: 
     217    # We only want to do this for block-level HTML tags, such as headers, 
     218    # lists, and tables. That's because we still want to wrap <p>s around 
     219    # "paragraphs" that are wrapped in non-block-level tags, such as anchors, 
     220    # phrase emphasis, and spans. The list of tags we're looking for is 
     221    # hard-coded: 
    146222    $block_tags_a = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|'. 
    147223                    'script|noscript|form|fieldset|iframe|math|ins|del'; 
     
    149225                    'script|noscript|form|fieldset|iframe|math'; 
    150226 
     227    # First, look for nested blocks, e.g.: 
     228    #   <div> 
     229    #       <div> 
     230    #       tags for inner block must be indented. 
     231    #       </div> 
     232    #   </div> 
     233    # 
     234    # The outermost tags must start at the left margin for this to match, and 
     235    # the inner nested divs must be indented. 
     236    # We need to do this before the next, more liberal match, because the next 
     237    # match will start at the first `<div>` and stop at the first `</div>`. 
    151238    $text = preg_replace_callback("{ 
    152239                (                       # save in $1 
     
    163250        $text); 
    164251 
     252    # 
     253    # Now match more liberally, simply from `\n<tag>` to `</tag>\n` 
     254    # 
    165255    $text = preg_replace_callback("{ 
    166256                (                       # save in $1 
     
    177267        $text); 
    178268 
     269    # Special case just for <hr />. It was easier to make a special case than 
     270    # to make the other regex more complicated. 
    179271    $text = preg_replace_callback('{ 
    180272                (?: 
     
    184276                ) 
    185277                (                       # save in $1 
    186                     [ \t]* 
     278                    [ ]{0,'.$less_than_tab.'} 
    187279                    <(hr)               # start tag = $2 
    188280                    \b                  # word break 
    189281                    ([^<>])*?           #  
    190282                    /?>                 # the matching end tag 
     283                    [ \t]* 
    191284                    (?=\n{2,}|\Z)       # followed by a blank line or end of document 
    192285                ) 
     
    194287        '_HashHTMLBlocks_callback', 
    195288        $text); 
     289 
     290    # Special case for standalone HTML comments: 
     291    $text = preg_replace_callback('{ 
     292                (?: 
     293                    (?<=\n\n)       # Starting after a blank line 
     294                    |               # or 
     295                    \A\n?           # the beginning of the doc 
     296                ) 
     297                (                       # save in $1 
     298                    [ ]{0,'.$less_than_tab.'} 
     299                    (?s: 
     300                        <! 
     301                        (--.*?--\s*)+ 
     302                        > 
     303                    ) 
     304                    [ \t]* 
     305                    (?=\n{2,}|\Z)       # followed by a blank line or end of document 
     306                ) 
     307            }x', 
     308            '_HashHTMLBlocks_callback', 
     309            $text); 
    196310 
    197311    return $text; 
     
    207321 
    208322function _RunBlockGamut($text) { 
     323# 
     324# These are all the transformations that form block-level 
     325# tags like paragraphs, headers, and list items. 
     326# 
    209327    global $md_empty_element_suffix; 
    210328 
     
    213331    # Do Horizontal Rules: 
    214332    $text = preg_replace( 
    215         array('/^( ?\* ?){3,}$/m', 
    216               '/^( ?- ?){3,}$/m', 
    217               '/^( ?_ ?){3,}$/m'), 
     333        array('{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}mx', 
     334              '{^[ ]{0,2}([ ]? -[ ]?){3,}[ \t]*$}mx', 
     335              '{^[ ]{0,2}([ ]? _[ ]?){3,}[ \t]*$}mx'), 
    218336        "\n<hr$md_empty_element_suffix\n",  
    219337        $text); 
     
    225343    $text = _DoBlockQuotes($text); 
    226344 
    227     # Make links out of things like `<http://example.com/>` 
    228     $text = _DoAutoLinks($text); 
    229  
     345    # We already ran _HashHTMLBlocks() before, in Markdown(), but that 
     346    # was to escape raw HTML in the original Markdown source. This time, 
     347    # we're escaping the markup we've just created, so that we don't wrap 
     348    # <p> tags around block-level tags. 
    230349    $text = _HashHTMLBlocks($text); 
    231350 
     
    237356 
    238357function _RunSpanGamut($text) { 
     358# 
     359# These are all the transformations that occur *within* block-level 
     360# tags like paragraphs, headers, and list items. 
     361# 
    239362    global $md_empty_element_suffix; 
     363 
    240364    $text = _DoCodeSpans($text); 
    241365 
    242     # Fix unencoded ampersands and <'s: 
    243     $text = _EncodeAmpsAndAngles($text); 
     366    $text = _EscapeSpecialChars($text); 
    244367 
    245368    # Process anchor and image tags. Images must come first, 
     
    248371    $text = _DoAnchors($text); 
    249372 
     373    # Make links out of things like `<http://example.com/>` 
     374    # Must come after _DoAnchors(), because you can use < and > 
     375    # delimiters in inline links like [this](<url>). 
     376    $text = _DoAutoLinks($text); 
     377 
     378    # Fix unencoded ampersands and <'s: 
     379    $text = _EncodeAmpsAndAngles($text); 
    250380 
    251381    $text = _DoItalicsAndBold($text); 
    252382 
     383    # Do hard breaks: 
    253384    $text = preg_replace('/ {2,}\n/', "<br$md_empty_element_suffix\n", $text); 
    254385 
     
    262393 
    263394    $text = '';   # rebuild $text from the tokens 
     395#   $in_pre = 0;  # Keep track of when we're inside <pre> or <code> tags. 
     396#   $tags_to_skip = "!<(/?)(?:pre|code|kbd|script|math)[\s>]!"; 
     397 
    264398    foreach ($tokens as $cur_token) { 
    265399        if ($cur_token[0] == 'tag') { 
     400            # Within tags, encode * and _ so they don't conflict 
     401            # with their use in Markdown for italics and strong. 
     402            # We're replacing each such character with its 
     403            # corresponding MD5 checksum value; this is likely 
     404            # overkill, but it should prevent us from colliding 
     405            # with the escape values by accident. 
    266406            $cur_token[1] = str_replace(array('*', '_'), 
    267407                array($md_escape_table['*'], $md_escape_table['_']), 
     
    279419 
    280420function _DoAnchors($text) { 
     421# 
     422# Turn Markdown link shortcuts into XHTML <a> tags. 
     423# 
    281424    global $md_nested_brackets; 
    282425    # 
     
    299442        '_DoAnchors_reference_callback', $text); 
    300443 
     444    # 
     445    # Next, inline-style links: [link text](url "optional title") 
     446    # 
    301447    $text = preg_replace_callback("{ 
    302448        (               # wrap whole match in $1 
     
    306452          \\(           # literal paren 
    307453            [ \\t]* 
    308             <?(.+?)>? # href = $3 
     454            <?(.*?)>? # href = $3 
    309455            [ \\t]* 
    310456            (           # $4 
     
    353499function _DoAnchors_inline_callback($matches) { 
    354500    global $md_escape_table; 
    355     $whole_match = $matches[1]; 
    356     $link_text   = $matches[2]; 
    357     $url              = $matches[3]; 
    358     $title      = $matches[6]; 
     501    $whole_match   = $matches[1]; 
     502    $link_text     = $matches[2]; 
     503    $url          = $matches[3]; 
     504    $title         =& $matches[6]; 
    359505 
    360506    # We've got to encode these to avoid conflicting with italics/bold. 
     
    364510    $result = "<a href=\"$url\""; 
    365511    if (isset($title)) { 
    366         $title = str_replace('"', '&quot', $title); 
     512        $title = str_replace('"', '&quot;', $title); 
    367513        $title = str_replace(array('*', '_'), 
    368514                             array($md_escape_table['*'], $md_escape_table['_']), 
     
    378524 
    379525function _DoImages($text) { 
     526# 
     527# Turn Markdown image shortcuts into <img> tags. 
     528# 
     529    # 
     530    # First, handle reference-style labeled images: ![alt text][id] 
     531    # 
    380532    $text = preg_replace_callback('{ 
    381533        (               # wrap whole match in $1 
     
    457609function _DoImages_inline_callback($matches) { 
    458610    global $md_empty_element_suffix, $md_escape_table; 
    459     $whole_match = $matches[1]; 
    460     $alt_text    = $matches[2]; 
    461     $url              = $matches[3]; 
    462     $title      = ''; 
     611    $whole_match   = $matches[1]; 
     612    $alt_text      = $matches[2]; 
     613    $url          = $matches[3]; 
     614    $title         = ''; 
    463615    if (isset($matches[6])) { 
    464         $title = $matches[6]; 
     616        $title     = $matches[6]; 
    465617    } 
    466618 
     
    485637 
    486638function _DoHeaders($text) { 
     639    # Setext-style headers: 
     640    #     Header 1 
     641    #     ======== 
     642    #   
     643    #     Header 2 
     644    #     -------- 
     645    # 
    487646    $text = preg_replace( 
    488         array("/(.+)[ \t]*\n=+[ \t]*\n+/e"
    489               "/(.+)[ \t]*\n-+[ \t]*\n+/e"), 
     647        array('{ ^(.+)[ \t]*\n=+[ \t]*\n+ }emx'
     648              '{ ^(.+)[ \t]*\n-+[ \t]*\n+ }emx'), 
    490649        array("'<h1>'._RunSpanGamut(_UnslashQuotes('\\1')).'</h1>\n\n'", 
    491650              "'<h2>'._RunSpanGamut(_UnslashQuotes('\\1')).'</h2>\n\n'"), 
    492651        $text); 
    493652 
     653    # atx-style headers: 
     654    #   # Header 1 
     655    #   ## Header 2 
     656    #   ## Header 2 with closing hashes ## 
     657    #   ... 
     658    #   ###### Header 6 
     659    # 
    494660    $text = preg_replace("{ 
    495661            ^(\\#{1,6}) # $1 = string of #'s 
     
    511677# Form HTML ordered (numbered) and unordered (bulleted) lists. 
    512678# 
    513     global $md_tab_width
     679    global $md_tab_width, $md_list_level
    514680    $less_than_tab = $md_tab_width - 1; 
    515681 
     
    519685    $marker_any = "(?:$marker_ul|$marker_ol)"; 
    520686 
    521     $text = preg_replace_callback("{ 
    522             (                               # $1 
    523               (                             # $2 
    524                 ^[ ]{0,$less_than_tab} 
    525                 ($marker_any)               # $3 - first list item marker 
    526                 [ \\t]+ 
     687    # Re-usable pattern to match any entirel ul or ol list: 
     688    $whole_list = ' 
     689        (                               # $1 = whole list 
     690          (                             # $2 
     691            [ ]{0,'.$less_than_tab.'} 
     692            ('.$marker_any.')               # $3 = first list item marker 
     693            [ \t]+ 
     694          ) 
     695          (?s:.+?) 
     696          (                             # $4 
     697              \z 
     698            | 
     699              \n{2,} 
     700              (?=\S) 
     701              (?!                       # Negative lookahead for another list item marker 
     702                [ \t]* 
     703                '.$marker_any.'[ \t]+ 
    527704              ) 
    528               (?s:.+?) 
    529               (                             # $4 
    530                   \\z 
    531                 | 
    532                   \\n{2,} 
    533                   (?=\\S) 
    534                   (?!                       # Negative lookahead for another list item marker 
    535                     [ \\t]* 
    536                     {$marker_any}[ \\t]+ 
    537                   ) 
    538               ) 
    539             ) 
    540         }xm", 
    541         '_DoLists_callback', $text); 
     705          ) 
     706        ) 
     707    '; // mx 
     708     
     709    # We use a different prefix before nested lists than top-level lists. 
     710    # See extended comment in _ProcessListItems(). 
     711 
     712    if ($md_list_level) { 
     713        $text = preg_replace_callback('{ 
     714                ^ 
     715                '.$whole_list.' 
     716            }mx', 
     717            '_DoLists_callback', $text); 
     718    } 
     719    else { 
     720        $text = preg_replace_callback('{ 
     721                (?:(?<=\n\n)|\A\n?) 
     722                '.$whole_list.' 
     723            }mx', 
     724            '_DoLists_callback', $text); 
     725    } 
    542726 
    543727    return $text; 
     
    550734     
    551735    $list = $matches[1]; 
    552     $list_type = preg_match('/[*+-]/', $matches[3]) ? "ul" : "ol"; 
     736    $list_type = preg_match("/$marker_ul/", $matches[3]) ? "ul" : "ol"; 
    553737    # Turn double returns into triple returns, so that we can make a 
    554738    # paragraph for the last item in a list, if necessary: 
    555739    $list = preg_replace("/\n{2,}/", "\n\n\n", $list); 
    556740    $result = _ProcessListItems($list, $marker_any); 
    557     $result = "<$list_type>\n" . $result . "</$list_type>\n\n"; 
     741    $result = "<$list_type>\n" . $result . "</$list_type>\n"; 
    558742    return $result; 
    559743} 
     
    561745 
    562746function _ProcessListItems($list_str, $marker_any) { 
     747# 
     748#   Process the contents of a single ordered or unordered list, splitting it 
     749#   into individual list items. 
     750# 
     751    global $md_list_level; 
     752     
     753    # The $md_list_level global keeps track of when we're inside a list. 
     754    # Each time we enter a list, we increment it; when we leave a list, 
     755    # we decrement. If it's zero, we're not in a list anymore. 
     756    # 
     757    # We do this because when we're not inside a list, we want to treat 
     758    # something like this: 
     759    # 
     760    #       I recommend upgrading to version 
     761    #       8. Oops, now this line is treated 
     762    #       as a sub-list. 
     763    # 
     764    # As a single paragraph, despite the fact that the second line starts 
     765    # with a digit-period-space sequence. 
     766    # 
     767    # Whereas when we're inside a list (or sub-list), that line will be 
     768    # treated as the start of a sub-list. What a kludge, huh? This is 
     769    # an aspect of Markdown's syntax that's hard to parse perfectly 
     770    # without resorting to mind-reading. Perhaps the solution is to 
     771    # change the syntax rules such that sub-lists must start with a 
     772    # starting cardinal number; e.g. "1." or "a.". 
     773     
     774    $md_list_level++; 
     775 
    563776    # trim trailing blank lines: 
    564777    $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); 
     
    574787        '_ProcessListItems_callback', $list_str); 
    575788 
     789    $md_list_level--; 
    576790    return $list_str; 
    577791} 
    578792function _ProcessListItems_callback($matches) { 
    579793    $item = $matches[4]; 
    580     $leading_line = $matches[1]; 
    581     $leading_space = $matches[2]; 
     794    $leading_line =& $matches[1]; 
     795    $leading_space =& $matches[2]; 
    582796 
    583797    if ($leading_line || preg_match('/\n{2,}/', $item)) { 
    584798        $item = _RunBlockGamut(_Outdent($item)); 
    585         #$item =~ s/\n+/\n/g; 
    586799    } 
    587800    else { 
     
    597810 
    598811function _DoCodeBlocks($text) { 
     812# 
     813#   Process Markdown `<pre><code>` blocks. 
     814# 
    599815    global $md_tab_width; 
    600816    $text = preg_replace_callback("{ 
     
    616832 
    617833    $codeblock = _EncodeCode(_Outdent($codeblock)); 
    618   $codeblock = _Detab($codeblock); 
     834//    $codeblock = _Detab($codeblock); 
    619835    # trim leading newlines and trailing whitespace 
    620836    $codeblock = preg_replace(array('/\A\n+/', '/\s+\z/'), '', $codeblock); 
     
    627843 
    628844function _DoCodeSpans($text) { 
     845# 
     846#   *   Backtick quotes are used for <code></code> spans. 
     847# 
     848#   *   You can use multiple backticks as the delimiters if you want to 
     849#       include literal backticks in the code span. So, this input: 
     850# 
     851#         Just type ``foo `bar` baz`` at the prompt. 
     852# 
     853#       Will translate to: 
     854# 
     855#         <p>Just type <code>foo `bar` baz</code> at the prompt.</p> 
     856# 
     857#       There's no arbitrary limit to the number of backticks you 
     858#       can use as delimters. If you need three consecutive backticks 
     859#       in your code, use four for delimiters, etc. 
     860# 
     861#   *   You can use spaces to get literal backticks at the edges: 
     862# 
     863#         ... type `` `bar` `` ... 
     864# 
     865#       Turns to: 
     866# 
     867#         ... type <code>`bar`</code> ... 
     868# 
    629869    $text = preg_replace_callback("@ 
    630870            (`+)        # $1 = Opening run of ` 
     
    648888 
    649889function _EncodeCode($_) { 
     890# 
     891# Encode/escape certain characters inside Markdown code runs. 
     892# The point is that in code, these characters are literals, 
     893# and lose their special Markdown meanings. 
     894# 
    650895    global $md_escape_table; 
    651896 
     897    # Encode all ampersands; HTML entities are not 
     898    # entities within a Markdown code span. 
    652899    $_ = str_replace('&', '&amp;', $_); 
    653900 
     901    # Do the angle bracket song and dance: 
    654902    $_ = str_replace(array('<',    '>'),  
    655903                     array('&lt;', '&gt;'), $_); 
    656904 
     905    # Now, escape characters that are magic in Markdown: 
    657906    $_ = str_replace(array_keys($md_escape_table),  
    658907                     array_values($md_escape_table), $_); 
     
    664913function _DoItalicsAndBold($text) { 
    665914    # <strong> must go first: 
    666     $text = preg_replace('{ (\*\*|__) (?=\S) (.+?) (?<=\S) \1 }sx', 
     915    $text = preg_replace('{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 }sx', 
    667916        '<strong>\2</strong>', $text); 
    668917    # Then <em>: 
     
    710959 
    711960function _FormParagraphs($text) { 
     961# 
     962#   Params: 
     963#       $text - string to process with html <p> tags 
     964# 
    712965    global $md_html_blocks; 
    713966 
     
    716969 
    717970    $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); 
    718     $count = count($grafs); 
    719  
     971 
     972    # 
     973    # Wrap <p> tags. 
     974    # 
    720975    foreach ($grafs as $key => $value) { 
    721976        if (!isset( $md_html_blocks[$value] )) { 
     
    727982    } 
    728983 
     984    # 
     985    # Unhashify HTML blocks 
     986    # 
    729987    foreach ($grafs as $key => $value) { 
    730988        if (isset( $md_html_blocks[$value] )) { 
     
    738996 
    739997function _EncodeAmpsAndAngles($text) { 
     998# Smart processing for ampersands and angle brackets that need to be encoded. 
     999 
     1000    # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: 
     1001    #   http://bumppo.net/projects/amputator/ 
    7401002    $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',  
    7411003                         '&amp;', $text);; 
     
    7491011 
    7501012function _EncodeBackslashEscapes($text) { 
     1013# 
     1014#   Parameter:  String. 
     1015#   Returns:    The string, with after processing the following backslash 
     1016#               escape sequences. 
     1017# 
    7511018    global $md_escape_table, $md_backslash_escape_table; 
    7521019    # Must process escaped backslashes first. 
     
    7631030    $text = preg_replace('{ 
    7641031        < 
     1032        (?:mailto:)? 
    7651033        ( 
    7661034            [-.\w]+ 
     
    7781046 
    7791047function _EncodeEmailAddress($addr) { 
     1048# 
     1049#   Input: an email address, e.g. "foo@example.com" 
     1050# 
     1051#   Output: the email address as a mailto link, with each character 
     1052#       of the address encoded as either a decimal or hex entity, in 
     1053#       the hopes of foiling most address harvesting spam bots. E.g.: 
     1054# 
     1055#     <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101; 
     1056#       x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111; 
     1057#       &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a> 
     1058# 
     1059#   Based by a filter by Matthew Wickline, posted to the BBEdit-Talk 
     1060#   mailing list: <http://tinyurl.com/yu7ue> 
     1061# 
    7801062    $addr = "mailto:" . $addr; 
    7811063    $length = strlen($addr); 
     
    8031085 
    8041086function _UnescapeSpecialChars($text) { 
     1087# 
     1088# Swap back in all the special characters we've hidden. 
     1089# 
    8051090    global $md_escape_table; 
    8061091    return str_replace(array_values($md_escape_table),  
     
    8091094 
    8101095 
    811 if (!function_exists('_TokenizeHTML')) { 
    812     function _TokenizeHTML($str) { 
    813         $index = 0; 
    814         $tokens = array(); 
    815  
    816         $depth = 6; 
    817         $nested_tags = str_repeat('(?:<[a-z\/!$](?:[^<>]|',$depth) 
    818                        .str_repeat(')*>)', $depth); 
    819         $match = "(?s:<!(?:--.*?--\s*)+>)|".  # comment 
    820                  "(?s:<\?.*?\?>)|".         # processing instruction 
    821                  "$nested_tags";            # nested tags 
    822  
    823         $parts = preg_split("/($match)/", $str, -1, PREG_SPLIT_DELIM_CAPTURE); 
    824  
    825         foreach ($parts as $part) { 
    826             if (++$index % 2 && $part != '')  
    827                 array_push($tokens, array('text', $part)); 
    828             else 
    829                 array_push($tokens, array('tag', $part)); 
    830         } 
    831  
    832         return $tokens; 
    833     } 
    834 
     1096# _TokenizeHTML is shared between PHP Markdown and PHP SmartyPants. 
     1097# We only define it if it is not already defined. 
     1098if (!function_exists('_TokenizeHTML')) : 
     1099function _TokenizeHTML($str) { 
     1100
     1101#   Parameter:  String containing HTML markup. 
     1102#   Returns:    An array of the tokens comprising the input 
     1103#               string. Each token is either a tag (possibly with nested, 
     1104#               tags contained therein, such as <a href="<MTFoo>">, or a 
     1105#               run of text between tags. Each element of the array is a 
     1106#               two-element array; the first is either 'tag' or 'text'; 
     1107#               the second is the actual value. 
     1108
     1109
     1110#   Regular expression derived from the _tokenize() subroutine in  
     1111#   Brad Choate's MTRegex plugin. 
     1112#   <http://www.bradchoate.com/past/mtregex.php> 
     1113
     1114    $index = 0; 
     1115    $tokens = array(); 
     1116 
     1117    $match = '(?s:<!(?:--.*?--\s*)+>)|'.    # comment 
     1118             '(?s:<\?.*?\?>)|'.             # processing instruction 
     1119             '(?:</?[\w:$]+\b(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*>)'; # regular tags 
     1120 
     1121    $parts = preg_split("{($match)}", $str, -1, PREG_SPLIT_DELIM_CAPTURE); 
     1122 
     1123    foreach ($parts as $part) { 
     1124        if (++$index % 2 && $part != '')  
     1125            array_push($tokens, array('text', $part)); 
     1126        else 
     1127            array_push($tokens, array('tag', $part)); 
     1128    } 
     1129 
     1130    return $tokens; 
     1131
     1132endif; 
    8351133 
    8361134 
    8371135function _Outdent($text) { 
     1136# 
     1137# Remove one level of line-leading tabs or spaces 
     1138# 
    8381139    global $md_tab_width; 
    8391140    return preg_replace("/^(\\t|[ ]{1,$md_tab_width})/m", "", $text); 
     
    8421143 
    8431144function _Detab($text) { 
     1145# 
     1146# Replace tabs with the appropriate amount of space. 
     1147# 
    8441148    global $md_tab_width; 
    845     $text = preg_replace( 
    846         "/(.*?)\t/e", 
    847         "'\\1'.str_repeat(' ', $md_tab_width - strlen('\\1') % $md_tab_width)", 
    848         $text); 
     1149 
     1150    # For each line we separate the line in blocks delemited by 
     1151    # tab characters. Then we reconstruct the line adding the appropriate 
     1152    # number of space charcters. 
     1153     
     1154    $lines = explode("\n", $text); 
     1155    $text = ""; 
     1156     
     1157    foreach ($lines as $line) { 
     1158        # Split in blocks. 
     1159        $blocks = explode("\t", $line); 
     1160        # Add each blocks to the line. 
     1161        $line = $blocks[0]; 
     1162        unset($blocks[0]); # Do not add first block twice. 
     1163        foreach ($blocks as $block) { 
     1164            # Calculate amount of space, insert spaces, insert block. 
     1165            $amount = $md_tab_width - strlen($line) % $md_tab_width; 
     1166            $line .= str_repeat(" ", $amount) . $block; 
     1167        } 
     1168        $text .= "$line\n"; 
     1169    } 
    8491170    return $text; 
    8501171} 
     
    8521173 
    8531174function _UnslashQuotes($text) { 
     1175# 
     1176#   This function is useful to remove automaticaly slashed double quotes 
     1177#   when using preg_replace and evaluating an expression. 
     1178#   Parameter:  String. 
     1179#   Returns:    The string with any slash-double-quote (\") sequence replaced 
     1180#               by a single double quote. 
     1181# 
    8541182    return str_replace('\"', '"', $text); 
    8551183} 
    8561184 
     1185 
     1186/* 
     1187 
     1188PHP Markdown 
     1189============ 
     1190 
     1191Description 
     1192----------- 
     1193 
     1194This is a PHP translation of the original Markdown formatter written in 
     1195Perl by John Gruber. 
     1196 
     1197Markdown is a text-to-HTML filter; it translates an easy-to-read / 
     1198easy-to-write structured text format into HTML. Markdown's text format 
     1199is most similar to that of plain text email, and supports features such 
     1200as headers, *emphasis*, code blocks, blockquotes, and links. 
     1201 
     1202Markdown's syntax is designed not as a generic markup language, but 
     1203specifically to serve as a front-end to (X)HTML. You can use span-level 
     1204HTML tags anywhere in a Markdown document, and you can use block level 
     1205HTML tags (like <div> and <table> as well). 
     1206 
     1207For more information about Markdown's syntax, see: 
     1208 
     1209<http://daringfireball.net/projects/markdown/> 
     1210 
     1211 
     1212Bugs 
     1213---- 
     1214 
     1215To file bug reports please send email to: 
     1216 
     1217<michel.fortin@michelf.com> 
     1218 
     1219Please include with your report: (1) the example input; (2) the output you 
     1220expected; (3) the output Markdown actually produced. 
     1221 
     1222 
     1223Version History 
     1224---------------  
     1225 
     1226See the readme file for detailed release notes for this version. 
     1227 
     12281.0.1 - 17 Dec 2004 
     1229 
     12301.0 - 21 Aug 2004 
     1231 
     1232 
     1233Author & Contributors 
     1234--------------------- 
     1235 
     1236Original Perl version by John Gruber   
     1237<http://daringfireball.net/> 
     1238 
     1239PHP port and other contributions by Michel Fortin   
     1240<http://www.michelf.com/> 
     1241 
     1242 
     1243Copyright and License 
     1244--------------------- 
     1245 
     1246Copyright (c) 2004 Michel Fortin   
     1247<http://www.michelf.com/>   
     1248All rights reserved. 
     1249 
     1250Copyright (c) 2003-2004 John Gruber    
     1251<http://daringfireball.net/>    
     1252All rights reserved. 
     1253 
     1254Redistribution and use in source and binary forms, with or without 
     1255modification, are permitted provided that the following conditions are 
     1256met: 
     1257 
     1258*   Redistributions of source code must retain the above copyright notice, 
     1259    this list of conditions and the following disclaimer. 
     1260 
     1261*   Redistributions in binary form must reproduce the above copyright 
     1262    notice, this list of conditions and the following disclaimer in the 
     1263    documentation and/or other materials provided with the distribution. 
     1264 
     1265*   Neither the name "Markdown" nor the names of its contributors may 
     1266    be used to endorse or promote products derived from this software 
     1267    without specific prior written permission. 
     1268 
     1269This software is provided by the copyright holders and contributors "as 
     1270is" and any express or implied warranties, including, but not limited 
     1271to, the implied warranties of merchantability and fitness for a 
     1272particular purpose are disclaimed. In no event shall the copyright owner 
     1273or contributors be liable for any direct, indirect, incidental, special, 
     1274exemplary, or consequential damages (including, but not limited to, 
     1275procurement of substitute goods or services; loss of use, data, or 
     1276profits; or business interruption) however caused and on any theory of 
     1277liability, whether in contract, strict liability, or tort (including 
     1278negligence or otherwise) arising in any way out of the use of this 
     1279software, even if advised of the possibility of such damage. 
     1280 
     1281*/ 
    8571282?>