[ Index ]
 

Code source de Phorum 5.1.25

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/mods/ -> markdown.php (source)

   1  <?php
   2  
   3  #
   4  # Markdown  -  A text-to-HTML conversion tool for web writers
   5  #
   6  # Copyright (c) 2004-2005 John Gruber
   7  # <http://daringfireball.net/projects/markdown/>
   8  #
   9  # Copyright (c) 2004-2005 Michel Fortin - PHP Port
  10  # <http://www.michelf.com/projects/php-markdown/>
  11  #
  12  
  13  
  14  global    $MarkdownPHPVersion, $MarkdownSyntaxVersion,
  15          $md_empty_element_suffix, $md_tab_width,
  16          $md_nested_brackets_depth, $md_nested_brackets,
  17          $md_escape_table, $md_backslash_escape_table,
  18          $md_list_level;
  19  
  20  $MarkdownPHPVersion    = '1.0.1c'; # Fri 9 Dec 2005
  21  $MarkdownSyntaxVersion = '1.0.1';  # Sun 12 Dec 2004
  22  
  23  
  24  #
  25  # Global default settings:
  26  #
  27  $md_empty_element_suffix = " />";     # Change to ">" for HTML output
  28  $md_tab_width = 4;
  29  
  30  #
  31  # WordPress settings:
  32  #
  33  $md_wp_posts    = true;  # Set to false to remove Markdown from posts.
  34  $md_wp_comments = true;  # Set to false to remove Markdown from comments.
  35  
  36  
  37  # -- WordPress Plugin Interface -----------------------------------------------
  38  /*
  39  Plugin Name: Markdown
  40  Plugin URI: http://www.michelf.com/projects/php-markdown/
  41  Description: <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>
  42  Version: 1.0.1c
  43  Author: Michel Fortin
  44  Author URI: http://www.michelf.com/
  45  */
  46  if (isset($wp_version)) {
  47      # More details about how it works here:
  48      # <http://www.michelf.com/weblog/2005/wordpress-text-flow-vs-markdown/>
  49  
  50      # Post content and excerpts
  51      if ($md_wp_posts) {
  52          remove_filter('the_content',  'wpautop');
  53          remove_filter('the_excerpt',  'wpautop');
  54          add_filter('the_content',     'Markdown', 6);
  55          add_filter('get_the_excerpt', 'Markdown', 6);
  56          add_filter('get_the_excerpt', 'trim', 7);
  57          add_filter('the_excerpt',     'md_add_p');
  58          add_filter('the_excerpt_rss', 'md_strip_p');
  59  
  60          remove_filter('content_save_pre',  'balanceTags', 50);
  61          remove_filter('excerpt_save_pre',  'balanceTags', 50);
  62          add_filter('the_content',        'balanceTags', 50);
  63          add_filter('get_the_excerpt', 'balanceTags', 9);
  64  
  65          function md_add_p($text) {
  66              if (strlen($text) == 0) return;
  67              if (strcasecmp(substr($text, -3), '<p>') == 0) return $text;
  68              return '<p>'.$text.'</p>';
  69          }
  70          function md_strip_p($t) { return preg_replace('{</?[pP]>}', '', $t); }
  71      }
  72  
  73      # Comments
  74      if ($md_wp_comments) {
  75          remove_filter('comment_text', 'wpautop');
  76          remove_filter('comment_text', 'make_clickable');
  77          add_filter('pre_comment_content', 'Markdown', 6);
  78          add_filter('pre_comment_content', 'md_hide_tags', 8);
  79          add_filter('pre_comment_content', 'md_show_tags', 12);
  80          add_filter('get_comment_text',    'Markdown', 6);
  81          add_filter('get_comment_excerpt', 'Markdown', 6);
  82          add_filter('get_comment_excerpt', 'md_strip_p', 7);
  83  
  84          global $md_hidden_tags;
  85          $md_hidden_tags = array(
  86              '<p>'    => md5('<p>'),        '</p>'    => md5('</p>'),
  87              '<pre>'    => md5('<pre>'),    '</pre>'=> md5('</pre>'),
  88              '<ol>'    => md5('<ol>'),        '</ol>'    => md5('</ol>'),
  89              '<ul>'    => md5('<ul>'),        '</ul>'    => md5('</ul>'),
  90              '<li>'    => md5('<li>'),        '</li>'    => md5('</li>'),
  91              );
  92  
  93          function md_hide_tags($text) {
  94              global $md_hidden_tags;
  95              return str_replace(array_keys($md_hidden_tags),
  96                                  array_values($md_hidden_tags), $text);
  97          }
  98          function md_show_tags($text) {
  99              global $md_hidden_tags;
 100              return str_replace(array_values($md_hidden_tags),
 101                                  array_keys($md_hidden_tags), $text);
 102          }
 103      }
 104  }
 105  
 106  
 107  # -- bBlog Plugin Info --------------------------------------------------------
 108  function identify_modifier_markdown() {
 109      global $MarkdownPHPVersion;
 110      return array(
 111          'name'            => 'markdown',
 112          'type'            => 'modifier',
 113          'nicename'        => 'Markdown',
 114          'description'    => 'A text-to-HTML conversion tool for web writers',
 115          'authors'        => 'Michel Fortin and John Gruber',
 116          'licence'        => 'GPL',
 117          'version'        => $MarkdownPHPVersion,
 118          '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>'
 119      );
 120  }
 121  
 122  # -- Smarty Modifier Interface ------------------------------------------------
 123  function smarty_modifier_markdown($text) {
 124      return Markdown($text);
 125  }
 126  
 127  # -- Textile Compatibility Mode -----------------------------------------------
 128  # Rename this file to "classTextile.php" and it can replace Textile anywhere.
 129  if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
 130      # Try to include PHP SmartyPants. Should be in the same directory.
 131      @include_once 'smartypants.php';
 132      # Fake Textile class. It calls Markdown instead.
 133      class Textile {
 134          function TextileThis($text, $lite='', $encode='', $noimage='', $strict='') {
 135              if ($lite == '' && $encode == '')   $text = Markdown($text);
 136              if (function_exists('SmartyPants')) $text = SmartyPants($text);
 137              return $text;
 138          }
 139      }
 140  }
 141  
 142  
 143  # -- Phorum Module Info --------------------------------------------------------
 144  /* phorum module info
 145  hook:  format|phorum_Markdown
 146  hook:  quote|phorum_Markdown_quote
 147  title: Markdown
 148  desc:  Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber.<br />http://daringfireball.net/projects/markdown/syntax<br />http://www.michelf.com/projects/php-markdown/
 149  */
 150  
 151  include_once  "./include/format_functions.php";
 152  
 153  function phorum_Markdown ($data)
 154  {
 155      foreach($data as $key=>$message){
 156          if(!empty($message["body"])){
 157              $message["body"] = str_replace(array("<phorum break>", "&amp;","&lt;","&gt;"), array("", "&","<",">"), $message["body"]);
 158              $data[$key]["body"] = Markdown($message["body"]);
 159          }
 160      }
 161  
 162      // Make HTML safe. Markdown does not handle stripping evil code.
 163      // We call the html mod's formatting code directly here, so we
 164      // do not have to worry about module ordering.
 165      require_once ('./mods/html/html.php');
 166      $data = phorum_html($data);
 167  
 168      return ($data);
 169  }
 170  
 171  function phorum_Markdown_quote ($message)
 172  {
 173      $PHORUM = $GLOBALS["PHORUM"];
 174  
 175      $author = "\n> **".$message[0] . ' ' . $PHORUM['DATA']['LANG']['Wrote'] . ':**';
 176      $quote  = phorum_strip_body($message[1]);
 177      $quote  = str_replace("\n", "\n> ", $quote);
 178      $quote  = wordwrap(trim($quote), 50, "\n> ", true);
 179      $quote  = $author . "\n> \n> " . $quote;
 180  
 181      return $quote;
 182  }
 183  
 184  
 185  #
 186  # Globals:
 187  #
 188  
 189  # Regex to match balanced [brackets].
 190  # Needed to insert a maximum bracked depth while converting to PHP.
 191  $md_nested_brackets_depth = 6;
 192  $md_nested_brackets =
 193      str_repeat('(?>[^\[\]]+|\[', $md_nested_brackets_depth).
 194      str_repeat('\])*', $md_nested_brackets_depth);
 195  
 196  # Table of hash values for escaped characters:
 197  $md_escape_table = array(
 198      "\\" => md5("\\"),
 199      "`" => md5("`"),
 200      "*" => md5("*"),
 201      "_" => md5("_"),
 202      "{" => md5("{"),
 203      "}" => md5("}"),
 204      "[" => md5("["),
 205      "]" => md5("]"),
 206      "(" => md5("("),
 207      ")" => md5(")"),
 208      ">" => md5(">"),
 209      "#" => md5("#"),
 210      "+" => md5("+"),
 211      "-" => md5("-"),
 212      "." => md5("."),
 213      "!" => md5("!")
 214  );
 215  # Create an identical table but for escaped characters.
 216  $md_backslash_escape_table;
 217  foreach ($md_escape_table as $key => $char)
 218      $md_backslash_escape_table["\\$key"] = $char;
 219  
 220  
 221  function Markdown($text) {
 222  #
 223  # Main function. The order in which other subs are called here is
 224  # essential. Link and image substitutions need to happen before
 225  # _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
 226  # and <img> tags get encoded.
 227  #
 228      # Clear the global hashes. If we don't clear these, you get conflicts
 229      # from other articles when generating a page which contains more than
 230      # one article (e.g. an index page that shows the N most recent
 231      # articles):
 232      global $md_urls, $md_titles, $md_html_blocks;
 233      $md_urls = array();
 234      $md_titles = array();
 235      $md_html_blocks = array();
 236  
 237      # Standardize line endings:
 238      #   DOS to Unix and Mac to Unix
 239      $text = str_replace(array("\r\n", "\r"), "\n", $text);
 240  
 241      # Make sure $text ends with a couple of newlines:
 242      $text .= "\n\n";
 243  
 244      # Convert all tabs to spaces.
 245      $text = _Detab($text);
 246  
 247      # Strip any lines consisting only of spaces and tabs.
 248      # This makes subsequent regexen easier to write, because we can
 249      # match consecutive blank lines with /\n+/ instead of something
 250      # contorted like /[ \t]*\n+/ .
 251      $text = preg_replace('/^[ \t]+$/m', '', $text);
 252  
 253      # Turn block-level HTML blocks into hash entries
 254      $text = _HashHTMLBlocks($text);
 255  
 256      # Strip link definitions, store in hashes.
 257      $text = _StripLinkDefinitions($text);
 258  
 259      $text = _RunBlockGamut($text);
 260  
 261      $text = _UnescapeSpecialChars($text);
 262  
 263      return $text . "\n";
 264  }
 265  
 266  
 267  function _StripLinkDefinitions($text) {
 268  #
 269  # Strips link definitions from text, stores the URLs and titles in
 270  # hash references.
 271  #
 272      global $md_tab_width;
 273      $less_than_tab = $md_tab_width - 1;
 274  
 275      # Link defs are in the form: ^[id]: url "optional title"
 276      $text = preg_replace_callback('{
 277                          ^[ ]{0,'.$less_than_tab.'}\[(.+)\]:    # id = $1
 278                            [ \t]*
 279                            \n?                # maybe *one* newline
 280                            [ \t]*
 281                          <?(\S+?)>?            # url = $2
 282                            [ \t]*
 283                            \n?                # maybe one newline
 284                            [ \t]*
 285                          (?:
 286                              (?<=\s)            # lookbehind for whitespace
 287                              ["(]
 288                              (.+?)            # title = $3
 289                              [")]
 290                              [ \t]*
 291                          )?    # title is optional
 292                          (?:\n+|\Z)
 293          }xm',
 294          '_StripLinkDefinitions_callback',
 295          $text);
 296      return $text;
 297  }
 298  function _StripLinkDefinitions_callback($matches) {
 299      global $md_urls, $md_titles;
 300      $link_id = strtolower($matches[1]);
 301      $md_urls[$link_id] = _EncodeAmpsAndAngles($matches[2]);
 302      if (isset($matches[3]))
 303          $md_titles[$link_id] = str_replace('"', '&quot;', $matches[3]);
 304      return ''; # String that will replace the block
 305  }
 306  
 307  
 308  function _HashHTMLBlocks($text) {
 309      global $md_tab_width;
 310      $less_than_tab = $md_tab_width - 1;
 311  
 312      # Hashify HTML blocks:
 313      # We only want to do this for block-level HTML tags, such as headers,
 314      # lists, and tables. That's because we still want to wrap <p>s around
 315      # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
 316      # phrase emphasis, and spans. The list of tags we're looking for is
 317      # hard-coded:
 318      $block_tags_a = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|'.
 319                      'script|noscript|form|fieldset|iframe|math|ins|del';
 320      $block_tags_b = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|'.
 321                      'script|noscript|form|fieldset|iframe|math';
 322  
 323      # First, look for nested blocks, e.g.:
 324      #     <div>
 325      #         <div>
 326      #         tags for inner block must be indented.
 327      #         </div>
 328      #     </div>
 329      #
 330      # The outermost tags must start at the left margin for this to match, and
 331      # the inner nested divs must be indented.
 332      # We need to do this before the next, more liberal match, because the next
 333      # match will start at the first `<div>` and stop at the first `</div>`.
 334      $text = preg_replace_callback("{
 335                  (                        # save in $1
 336                      ^                    # start of line  (with /m)
 337                      <($block_tags_a)    # start tag = $2
 338                      \\b                    # word break
 339                      (.*\\n)*?            # any number of lines, minimally matching
 340                      </\\2>                # the matching end tag
 341                      [ \\t]*                # trailing spaces/tabs
 342                      (?=\\n+|\\Z)    # followed by a newline or end of document
 343                  )
 344          }xm",
 345          '_HashHTMLBlocks_callback',
 346          $text);
 347  
 348      #
 349      # Now match more liberally, simply from `\n<tag>` to `</tag>\n`
 350      #
 351      $text = preg_replace_callback("{
 352                  (                        # save in $1
 353                      ^                    # start of line  (with /m)
 354                      <($block_tags_b)    # start tag = $2
 355                      \\b                    # word break
 356                      (.*\\n)*?            # any number of lines, minimally matching
 357                      .*</\\2>                # the matching end tag
 358                      [ \\t]*                # trailing spaces/tabs
 359                      (?=\\n+|\\Z)    # followed by a newline or end of document
 360                  )
 361          }xm",
 362          '_HashHTMLBlocks_callback',
 363          $text);
 364  
 365      # Special case just for <hr />. It was easier to make a special case than
 366      # to make the other regex more complicated.
 367      $text = preg_replace_callback('{
 368                  (?:
 369                      (?<=\n\n)        # Starting after a blank line
 370                      |                # or
 371                      \A\n?            # the beginning of the doc
 372                  )
 373                  (                        # save in $1
 374                      [ ]{0,'.$less_than_tab.'}
 375                      <(hr)                # start tag = $2
 376                      \b                    # word break
 377                      ([^<>])*?            #
 378                      /?>                    # the matching end tag
 379                      [ \t]*
 380                      (?=\n{2,}|\Z)        # followed by a blank line or end of document
 381                  )
 382          }x',
 383          '_HashHTMLBlocks_callback',
 384          $text);
 385  
 386      # Special case for standalone HTML comments:
 387      $text = preg_replace_callback('{
 388                  (?:
 389                      (?<=\n\n)        # Starting after a blank line
 390                      |                # or
 391                      \A\n?            # the beginning of the doc
 392                  )
 393                  (                        # save in $1
 394                      [ ]{0,'.$less_than_tab.'}
 395                      (?s:
 396                          <!
 397                          (--.*?--\s*)+
 398                          >
 399                      )
 400                      [ \t]*
 401                      (?=\n{2,}|\Z)        # followed by a blank line or end of document
 402                  )
 403              }x',
 404              '_HashHTMLBlocks_callback',
 405              $text);
 406  
 407      return $text;
 408  }
 409  function _HashHTMLBlocks_callback($matches) {
 410      global $md_html_blocks;
 411      $text = $matches[1];
 412      $key = md5($text);
 413      $md_html_blocks[$key] = $text;
 414      return "\n\n$key\n\n"; # String that will replace the block
 415  }
 416  
 417  
 418  function _RunBlockGamut($text) {
 419  #
 420  # These are all the transformations that form block-level
 421  # tags like paragraphs, headers, and list items.
 422  #
 423      global $md_empty_element_suffix;
 424  
 425      $text = _DoHeaders($text);
 426  
 427      # Do Horizontal Rules:
 428      $text = preg_replace(
 429          array('{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}mx',
 430                '{^[ ]{0,2}([ ]? -[ ]?){3,}[ \t]*$}mx',
 431                '{^[ ]{0,2}([ ]? _[ ]?){3,}[ \t]*$}mx'),
 432          "\n<hr$md_empty_element_suffix\n",
 433          $text);
 434  
 435      $text = _DoLists($text);
 436      $text = _DoCodeBlocks($text);
 437      $text = _DoBlockQuotes($text);
 438  
 439      # We already ran _HashHTMLBlocks() before, in Markdown(), but that
 440      # was to escape raw HTML in the original Markdown source. This time,
 441      # we're escaping the markup we've just created, so that we don't wrap
 442      # <p> tags around block-level tags.
 443      $text = _HashHTMLBlocks($text);
 444      $text = _FormParagraphs($text);
 445  
 446      return $text;
 447  }
 448  
 449  
 450  function _RunSpanGamut($text) {
 451  #
 452  # These are all the transformations that occur *within* block-level
 453  # tags like paragraphs, headers, and list items.
 454  #
 455      global $md_empty_element_suffix;
 456  
 457      $text = _DoCodeSpans($text);
 458  
 459      $text = _EscapeSpecialChars($text);
 460  
 461      # Process anchor and image tags. Images must come first,
 462      # because ![foo][f] looks like an anchor.
 463      $text = _DoImages($text);
 464      $text = _DoAnchors($text);
 465  
 466      # Make links out of things like `<http://example.com/>`
 467      # Must come after _DoAnchors(), because you can use < and >
 468      # delimiters in inline links like [this](<url>).
 469      $text = _DoAutoLinks($text);
 470      $text = _EncodeAmpsAndAngles($text);
 471      $text = _DoItalicsAndBold($text);
 472  
 473      # Do hard breaks:
 474      $text = preg_replace('/ {2,}\n/', "<br$md_empty_element_suffix\n", $text);
 475  
 476      return $text;
 477  }
 478  
 479  
 480  function _EscapeSpecialChars($text) {
 481      global $md_escape_table;
 482      $tokens = _TokenizeHTML($text);
 483  
 484      $text = '';   # rebuild $text from the tokens
 485  #    $in_pre = 0;  # Keep track of when we're inside <pre> or <code> tags.
 486  #    $tags_to_skip = "!<(/?)(?:pre|code|kbd|script|math)[\s>]!";
 487  
 488      foreach ($tokens as $cur_token) {
 489          if ($cur_token[0] == 'tag') {
 490              # Within tags, encode * and _ so they don't conflict
 491              # with their use in Markdown for italics and strong.
 492              # We're replacing each such character with its
 493              # corresponding MD5 checksum value; this is likely
 494              # overkill, but it should prevent us from colliding
 495              # with the escape values by accident.
 496              $cur_token[1] = str_replace(array('*', '_'),
 497                  array($md_escape_table['*'], $md_escape_table['_']),
 498                  $cur_token[1]);
 499              $text .= $cur_token[1];
 500          } else {
 501              $t = $cur_token[1];
 502              $t = _EncodeBackslashEscapes($t);
 503              $text .= $t;
 504          }
 505      }
 506      return $text;
 507  }
 508  
 509  
 510  function _DoAnchors($text) {
 511  #
 512  # Turn Markdown link shortcuts into XHTML <a> tags.
 513  #
 514      global $md_nested_brackets;
 515      #
 516      # First, handle reference-style links: [link text] [id]
 517      #
 518      $text = preg_replace_callback("{
 519          (                    # wrap whole match in $1
 520            \\[
 521              ($md_nested_brackets)    # link text = $2
 522            \\]
 523  
 524            [ ]?                # one optional space
 525            (?:\\n[ ]*)?        # one optional newline followed by spaces
 526  
 527            \\[
 528              (.*?)        # id = $3
 529            \\]
 530          )
 531          }xs",
 532          '_DoAnchors_reference_callback', $text);
 533  
 534      #
 535      # Next, inline-style links: [link text](url "optional title")
 536      #
 537      $text = preg_replace_callback("{
 538          (                # wrap whole match in $1
 539            \\[
 540              ($md_nested_brackets)    # link text = $2
 541            \\]
 542            \\(            # literal paren
 543              [ \\t]*
 544              <?(.*?)>?    # href = $3
 545              [ \\t]*
 546              (            # $4
 547                (['\"])    # quote char = $5
 548                (.*?)        # Title = $6
 549                \\5        # matching quote
 550              )?            # title is optional
 551            \\)
 552          )
 553          }xs",
 554          '_DoAnchors_inline_callback', $text);
 555  
 556      return $text;
 557  }
 558  function _DoAnchors_reference_callback($matches) {
 559      global $md_urls, $md_titles, $md_escape_table;
 560      $whole_match = $matches[1];
 561      $link_text   = $matches[2];
 562      $link_id     = strtolower($matches[3]);
 563  
 564      if ($link_id == "") {
 565          $link_id = strtolower($link_text); # for shortcut links like [this][].
 566      }
 567  
 568      if (isset($md_urls[$link_id])) {
 569          $url = $md_urls[$link_id];
 570          # We've got to encode these to avoid conflicting with italics/bold.
 571          $url = str_replace(array('*', '_'),
 572                             array($md_escape_table['*'], $md_escape_table['_']),
 573                             $url);
 574          $result = "<a href=\"$url\"";
 575          if ( isset( $md_titles[$link_id] ) ) {
 576              $title = $md_titles[$link_id];
 577              $title = str_replace(array('*',     '_'),
 578                                   array($md_escape_table['*'],
 579                                         $md_escape_table['_']), $title);
 580              $result .=  " title=\"$title\"";
 581          }
 582          $result .= ">$link_text</a>";
 583      }
 584      else {
 585          $result = $whole_match;
 586      }
 587      return $result;
 588  }
 589  function _DoAnchors_inline_callback($matches) {
 590      global $md_escape_table;
 591      $whole_match    = $matches[1];
 592      $link_text        = $matches[2];
 593      $url            = $matches[3];
 594      $title            =& $matches[6];
 595  
 596      # We've got to encode these to avoid conflicting with italics/bold.
 597      $url = str_replace(array('*', '_'),
 598                         array($md_escape_table['*'], $md_escape_table['_']),
 599                         $url);
 600      $result = "<a href=\"$url\"";
 601      if (isset($title)) {
 602          $title = str_replace('"', '&quot;', $title);
 603          $title = str_replace(array('*', '_'),
 604                               array($md_escape_table['*'], $md_escape_table['_']),
 605                               $title);
 606          $result .=  " title=\"$title\"";
 607      }
 608  
 609      $result .= ">$link_text</a>";
 610  
 611      return $result;
 612  }
 613  
 614  
 615  function _DoImages($text) {
 616  #
 617  # Turn Markdown image shortcuts into <img> tags.
 618  #
 619      global $md_nested_brackets;
 620  
 621      #
 622      # First, handle reference-style labeled images: ![alt text][id]
 623      #
 624      $text = preg_replace_callback('{
 625          (                # wrap whole match in $1
 626            !\[
 627              ('.$md_nested_brackets.')        # alt text = $2
 628            \]
 629  
 630            [ ]?                # one optional space
 631            (?:\n[ ]*)?        # one optional newline followed by spaces
 632  
 633            \[
 634              (.*?)        # id = $3
 635            \]
 636  
 637          )
 638          }xs',
 639          '_DoImages_reference_callback', $text);
 640  
 641      #
 642      # Next, handle inline images:  ![alt text](url "optional title")
 643      # Don't forget: encode * and _
 644  
 645      $text = preg_replace_callback('{
 646          (                # wrap whole match in $1
 647            !\[
 648              ('.$md_nested_brackets.')        # alt text = $2
 649            \]
 650            \(            # literal paren
 651              [ \t]*
 652              <?(\S+?)>?    # src url = $3
 653              [ \t]*
 654              (            # $4
 655                ([\'"])    # quote char = $5
 656                (.*?)        # title = $6
 657                \5        # matching quote
 658                [ \t]*
 659              )?            # title is optional
 660            \)
 661          )
 662          }xs',
 663          '_DoImages_inline_callback', $text);
 664  
 665      return $text;
 666  }
 667  function _DoImages_reference_callback($matches) {
 668      global $md_urls, $md_titles, $md_empty_element_suffix, $md_escape_table;
 669      $whole_match = $matches[1];
 670      $alt_text    = $matches[2];
 671      $link_id     = strtolower($matches[3]);
 672  
 673      if ($link_id == "") {
 674          $link_id = strtolower($alt_text); # for shortcut links like ![this][].
 675      }
 676  
 677      $alt_text = str_replace('"', '&quot;', $alt_text);
 678      if (isset($md_urls[$link_id])) {
 679          $url = $md_urls[$link_id];
 680          # We've got to encode these to avoid conflicting with italics/bold.
 681          $url = str_replace(array('*', '_'),
 682                             array($md_escape_table['*'], $md_escape_table['_']),
 683                             $url);
 684          $result = "<img src=\"$url\" alt=\"$alt_text\"";
 685          if (isset($md_titles[$link_id])) {
 686              $title = $md_titles[$link_id];
 687              $title = str_replace(array('*', '_'),
 688                                   array($md_escape_table['*'],
 689                                         $md_escape_table['_']), $title);
 690              $result .=  " title=\"$title\"";
 691          }
 692          $result .= $md_empty_element_suffix;
 693      }
 694      else {
 695          # If there's no such link ID, leave intact:
 696          $result = $whole_match;
 697      }
 698  
 699      return $result;
 700  }
 701  function _DoImages_inline_callback($matches) {
 702      global $md_empty_element_suffix, $md_escape_table;
 703      $whole_match    = $matches[1];
 704      $alt_text        = $matches[2];
 705      $url            = $matches[3];
 706      $title            = '';
 707      if (isset($matches[6])) {
 708          $title        = $matches[6];
 709      }
 710  
 711      $alt_text = str_replace('"', '&quot;', $alt_text);
 712      $title    = str_replace('"', '&quot;', $title);
 713      # We've got to encode these to avoid conflicting with italics/bold.
 714      $url = str_replace(array('*', '_'),
 715                         array($md_escape_table['*'], $md_escape_table['_']),
 716                         $url);
 717      $result = "<img src=\"$url\" alt=\"$alt_text\"";
 718      if (isset($title)) {
 719          $title = str_replace(array('*', '_'),
 720                               array($md_escape_table['*'], $md_escape_table['_']),
 721                               $title);
 722          $result .=  " title=\"$title\""; # $title already quoted
 723      }
 724      $result .= $md_empty_element_suffix;
 725  
 726      return $result;
 727  }
 728  
 729  
 730  function _DoHeaders($text) {
 731      # Setext-style headers:
 732      #      Header 1
 733      #      ========
 734      #
 735      #      Header 2
 736      #      --------
 737      #
 738      $text = preg_replace(
 739          array('{ ^(.+)[ \t]*\n=+[ \t]*\n+ }emx',
 740                '{ ^(.+)[ \t]*\n-+[ \t]*\n+ }emx'),
 741          array("'<h1>'._RunSpanGamut(_UnslashQuotes('\\1')).'</h1>\n\n'",
 742                "'<h2>'._RunSpanGamut(_UnslashQuotes('\\1')).'</h2>\n\n'"),
 743          $text);
 744  
 745      # atx-style headers:
 746      #    # Header 1
 747      #    ## Header 2
 748      #    ## Header 2 with closing hashes ##
 749      #    ...
 750      #    ###### Header 6
 751      #
 752      $text = preg_replace("{
 753              ^(\\#{1,6})    # $1 = string of #'s
 754              [ \\t]*
 755              (.+?)        # $2 = Header text
 756              [ \\t]*
 757              \\#*            # optional closing #'s (not counted)
 758              \\n+
 759          }xme",
 760          "'<h'.strlen('\\1').'>'._RunSpanGamut(_UnslashQuotes('\\2')).'</h'.strlen('\\1').'>\n\n'",
 761          $text);
 762  
 763      return $text;
 764  }
 765  
 766  
 767  function _DoLists($text) {
 768  #
 769  # Form HTML ordered (numbered) and unordered (bulleted) lists.
 770  #
 771      global $md_tab_width, $md_list_level;
 772      $less_than_tab = $md_tab_width - 1;
 773  
 774      # Re-usable patterns to match list item bullets and number markers:
 775      $marker_ul  = '[*+-]';
 776      $marker_ol  = '\d+[.]';
 777      $marker_any = "(?:$marker_ul|$marker_ol)";
 778  
 779      $markers = array($marker_ul, $marker_ol);
 780  
 781      foreach ($markers as $marker) {
 782          # Re-usable pattern to match any entirel ul or ol list:
 783          $whole_list = '
 784              (                                # $1 = whole list
 785                (                                # $2
 786                  [ ]{0,'.$less_than_tab.'}
 787                  ('.$marker.')                # $3 = first list item marker
 788                  [ \t]+
 789                )
 790                (?s:.+?)
 791                (                                # $4
 792                    \z
 793                  |
 794                    \n{2,}
 795                    (?=\S)
 796                    (?!                        # Negative lookahead for another list item marker
 797                      [ \t]*
 798                      '.$marker.'[ \t]+
 799                    )
 800                )
 801              )
 802          '; // mx
 803  
 804          # We use a different prefix before nested lists than top-level lists.
 805          # See extended comment in _ProcessListItems().
 806  
 807          if ($md_list_level) {
 808              $text = preg_replace_callback('{
 809                      ^
 810                      '.$whole_list.'
 811                  }mx',
 812                  '_DoLists_callback_top', $text);
 813          }
 814          else {
 815              $text = preg_replace_callback('{
 816                      (?:(?<=\n\n)|\A\n?)
 817                      '.$whole_list.'
 818                  }mx',
 819                  '_DoLists_callback_nested', $text);
 820          }
 821      }
 822  
 823      return $text;
 824  }
 825  function _DoLists_callback_top($matches) {
 826      # Re-usable patterns to match list item bullets and number markers:
 827      $marker_ul  = '[*+-]';
 828      $marker_ol  = '\d+[.]';
 829      $marker_any = "(?:$marker_ul|$marker_ol)";
 830  
 831      $list = $matches[1];
 832      $list_type = preg_match("/$marker_ul/", $matches[3]) ? "ul" : "ol";
 833  
 834      $marker_any = ( $list_type == "ul" ? $marker_ul : $marker_ol );
 835  
 836      # Turn double returns into triple returns, so that we can make a
 837      # paragraph for the last item in a list, if necessary:
 838      $list = preg_replace("/\n{2,}/", "\n\n\n", $list);
 839      $result = _ProcessListItems($list, $marker_any);
 840  
 841      # Trim any trailing whitespace, to put the closing `</$list_type>`
 842      # up on the preceding line, to get it past the current stupid
 843      # HTML block parser. This is a hack to work around the terrible
 844      # hack that is the HTML block parser.
 845      $result = rtrim($result);
 846      $result = "<$list_type>" . $result . "</$list_type>\n";
 847      return $result;
 848  }
 849  function _DoLists_callback_nested($matches) {
 850      # Re-usable patterns to match list item bullets and number markers:
 851      $marker_ul  = '[*+-]';
 852      $marker_ol  = '\d+[.]';
 853      $marker_any = "(?:$marker_ul|$marker_ol)";
 854  
 855      $list = $matches[1];
 856      $list_type = preg_match("/$marker_ul/", $matches[3]) ? "ul" : "ol";
 857  
 858      $marker_any = ( $list_type == "ul" ? $marker_ul : $marker_ol );
 859  
 860      # Turn double returns into triple returns, so that we can make a
 861      # paragraph for the last item in a list, if necessary:
 862      $list = preg_replace("/\n{2,}/", "\n\n\n", $list);
 863      $result = _ProcessListItems($list, $marker_any);
 864      $result = "<$list_type>\n" . $result . "</$list_type>\n";
 865      return $result;
 866  }
 867  
 868  
 869  function _ProcessListItems($list_str, $marker_any) {
 870  #
 871  #    Process the contents of a single ordered or unordered list, splitting it
 872  #    into individual list items.
 873  #
 874      global $md_list_level;
 875  
 876      # The $md_list_level global keeps track of when we're inside a list.
 877      # Each time we enter a list, we increment it; when we leave a list,
 878      # we decrement. If it's zero, we're not in a list anymore.
 879      #
 880      # We do this because when we're not inside a list, we want to treat
 881      # something like this:
 882      #
 883      #        I recommend upgrading to version
 884      #        8. Oops, now this line is treated
 885      #        as a sub-list.
 886      #
 887      # As a single paragraph, despite the fact that the second line starts
 888      # with a digit-period-space sequence.
 889      #
 890      # Whereas when we're inside a list (or sub-list), that line will be
 891      # treated as the start of a sub-list. What a kludge, huh? This is
 892      # an aspect of Markdown's syntax that's hard to parse perfectly
 893      # without resorting to mind-reading. Perhaps the solution is to
 894      # change the syntax rules such that sub-lists must start with a
 895      # starting cardinal number; e.g. "1." or "a.".
 896  
 897      $md_list_level++;
 898  
 899      # trim trailing blank lines:
 900      $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
 901  
 902      $list_str = preg_replace_callback('{
 903          (\n)?                            # leading line = $1
 904          (^[ \t]*)                        # leading whitespace = $2
 905          ('.$marker_any.') [ \t]+        # list marker = $3
 906          ((?s:.+?)                        # list item text   = $4
 907          (\n{1,2}))
 908          (?= \n* (\z | \2 ('.$marker_any.') [ \t]+))
 909          }xm',
 910          '_ProcessListItems_callback', $list_str);
 911  
 912      $md_list_level--;
 913      return $list_str;
 914  }
 915  function _ProcessListItems_callback($matches) {
 916      $item = $matches[4];
 917      $leading_line =& $matches[1];
 918      $leading_space =& $matches[2];
 919  
 920      if ($leading_line || preg_match('/\n{2,}/', $item)) {
 921          $item = _RunBlockGamut(_Outdent($item));
 922      }
 923      else {
 924          # Recursion for sub-lists:
 925          $item = _DoLists(_Outdent($item));
 926          $item = preg_replace('/\n+$/', '', $item);
 927          $item = _RunSpanGamut($item);
 928      }
 929  
 930      return "<li>" . $item . "</li>\n";
 931  }
 932  
 933  
 934  function _DoCodeBlocks($text) {
 935  #
 936  #    Process Markdown `<pre><code>` blocks.
 937  #
 938      global $md_tab_width;
 939      $text = preg_replace_callback('{
 940              (?:\n\n|\A)
 941              (                # $1 = the code block -- one or more lines, starting with a space/tab
 942                (?:
 943                  (?:[ ]{'.$md_tab_width.'} | \t)  # Lines must start with a tab or a tab-width of spaces
 944                  .*\n+
 945                )+
 946              )
 947              ((?=^[ ]{0,'.$md_tab_width.'}\S)|\Z)    # Lookahead for non-space at line-start, or end of doc
 948          }xm',
 949          '_DoCodeBlocks_callback', $text);
 950  
 951      return $text;
 952  }
 953  function _DoCodeBlocks_callback($matches) {
 954      $codeblock = $matches[1];
 955  
 956      $codeblock = _EncodeCode(_Outdent($codeblock));
 957  //    $codeblock = _Detab($codeblock);
 958      # trim leading newlines and trailing whitespace
 959      $codeblock = preg_replace(array('/\A\n+/', '/\s+\z/'), '', $codeblock);
 960  
 961      $result = "\n\n<pre><code>" . $codeblock . "\n</code></pre>\n\n";
 962  
 963      return $result;
 964  }
 965  
 966  
 967  function _DoCodeSpans($text) {
 968  #
 969  #     *    Backtick quotes are used for <code></code> spans.
 970  #
 971  #     *    You can use multiple backticks as the delimiters if you want to
 972  #         include literal backticks in the code span. So, this input:
 973  #
 974  #          Just type ``foo `bar` baz`` at the prompt.
 975  #
 976  #          Will translate to:
 977  #
 978  #          <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
 979  #
 980  #        There's no arbitrary limit to the number of backticks you
 981  #        can use as delimters. If you need three consecutive backticks
 982  #        in your code, use four for delimiters, etc.
 983  #
 984  #    *    You can use spaces to get literal backticks at the edges:
 985  #
 986  #          ... type `` `bar` `` ...
 987  #
 988  #          Turns to:
 989  #
 990  #          ... type <code>`bar`</code> ...
 991  #
 992      $text = preg_replace_callback('@
 993              (?<!\\\)    # Character before opening ` can\'t be a backslash
 994              (`+)        # $1 = Opening run of `
 995              (.+?)        # $2 = The code block
 996              (?<!`)
 997              \1            # Matching closer
 998              (?!`)
 999          @xs',
1000          '_DoCodeSpans_callback', $text);
1001  
1002      return $text;
1003  }
1004  function _DoCodeSpans_callback($matches) {
1005      $c = $matches[2];
1006      $c = preg_replace('/^[ \t]*/', '', $c); # leading whitespace
1007      $c = preg_replace('/[ \t]*$/', '', $c); # trailing whitespace
1008      $c = _EncodeCode($c);
1009      return "<code>$c</code>";
1010  }
1011  
1012  
1013  function _EncodeCode($_) {
1014  #
1015  # Encode/escape certain characters inside Markdown code runs.
1016  # The point is that in code, these characters are literals,
1017  # and lose their special Markdown meanings.
1018  #
1019      global $md_escape_table;
1020  
1021      # Encode all ampersands; HTML entities are not
1022      # entities within a Markdown code span.
1023      $_ = str_replace('&', '&amp;', $_);
1024  
1025      # Do the angle bracket song and dance:
1026      $_ = str_replace(array('<',    '>'),
1027                       array('&lt;', '&gt;'), $_);
1028  
1029      # Now, escape characters that are magic in Markdown:
1030      $_ = str_replace(array_keys($md_escape_table),
1031                       array_values($md_escape_table), $_);
1032  
1033      return $_;
1034  }
1035  
1036  
1037  function _DoItalicsAndBold($text) {
1038      # <strong> must go first:
1039      $text = preg_replace('{
1040              (                        # $1: Marker
1041                  (?<!\*\*) \*\* |    #     (not preceded by two chars of
1042                  (?<!__)   __        #      the same marker)
1043              )
1044              (?=\S)                     # Not followed by whitespace
1045              (?!\1)                    #   or two others marker chars.
1046              (                        # $2: Content
1047                  (?:
1048                      [^*_]+?            # Anthing not em markers.
1049                  |
1050                                      # Balence any regular emphasis inside.
1051                      ([*_]) (?=\S) .+? (?<=\S) \3    # $3: em char (* or _)
1052                  |
1053                      (?! \1 ) .        # Allow unbalenced * and _.
1054                  )+?
1055              )
1056              (?<=\S) \1                # End mark not preceded by whitespace.
1057          }sx',
1058          '<strong>\2</strong>', $text);
1059      # Then <em>:
1060      $text = preg_replace(
1061          '{ ( (?<!\*)\* | (?<!_)_ ) (?=\S) (?! \1) (.+?) (?<=\S) \1 }sx',
1062          '<em>\2</em>', $text);
1063  
1064      return $text;
1065  }
1066  
1067  
1068  function _DoBlockQuotes($text) {
1069      $text = preg_replace_callback('/
1070            (                                # Wrap whole match in $1
1071              (
1072                ^[ \t]*>[ \t]?            # ">" at the start of a line
1073                  .+\n                    # rest of the first line
1074                (.+\n)*                    # subsequent consecutive lines
1075                \n*                        # blanks
1076              )+
1077            )
1078          /xm',
1079          '_DoBlockQuotes_callback', $text);
1080  
1081      return $text;
1082  }
1083  function _DoBlockQuotes_callback($matches) {
1084      $bq = $matches[1];
1085      # trim one level of quoting - trim whitespace-only lines
1086      $bq = preg_replace(array('/^[ \t]*>[ \t]?/m', '/^[ \t]+$/m'), '', $bq);
1087      $bq = _RunBlockGamut($bq);        # recurse
1088  
1089      $bq = preg_replace('/^/m', "  ", $bq);
1090      # These leading spaces screw with <pre> content, so we need to fix that:
1091      $bq = preg_replace_callback('{(\s*<pre>.+?</pre>)}sx',
1092                                  '_DoBlockQuotes_callback2', $bq);
1093  
1094      return "<blockquote>\n$bq\n</blockquote>\n\n";
1095  }
1096  function _DoBlockQuotes_callback2($matches) {
1097      $pre = $matches[1];
1098      $pre = preg_replace('/^  /m', '', $pre);
1099      return $pre;
1100  }
1101  
1102  
1103  function _FormParagraphs($text) {
1104  #
1105  #    Params:
1106  #        $text - string to process with html <p> tags
1107  #
1108      global $md_html_blocks;
1109  
1110      # Strip leading and trailing lines:
1111      $text = preg_replace(array('/\A\n+/', '/\n+\z/'), '', $text);
1112  
1113      $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
1114  
1115      #
1116      # Wrap <p> tags.
1117      #
1118      foreach ($grafs as $key => $value) {
1119          if (!isset( $md_html_blocks[$value] )) {
1120              $value = _RunSpanGamut($value);
1121              $value = preg_replace('/^([ \t]*)/', '<p>', $value);
1122              $value .= "</p>";
1123              $grafs[$key] = $value;
1124          }
1125      }
1126  
1127      #
1128      # Unhashify HTML blocks
1129      #
1130      foreach ($grafs as $key => $value) {
1131          if (isset( $md_html_blocks[$value] )) {
1132              $grafs[$key] = $md_html_blocks[$value];
1133          }
1134      }
1135  
1136      return implode("\n\n", $grafs);
1137  }
1138  
1139  
1140  function _EncodeAmpsAndAngles($text) {
1141  # Smart processing for ampersands and angle brackets that need to be encoded.
1142  
1143      # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
1144      #   http://bumppo.net/projects/amputator/
1145      $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/',
1146                           '&amp;', $text);;
1147  
1148      # Encode naked <'s
1149      $text = preg_replace('{<(?![a-z/?\$!])}i', '&lt;', $text);
1150  
1151      return $text;
1152  }
1153  
1154  
1155  function _EncodeBackslashEscapes($text) {
1156  #
1157  #    Parameter:  String.
1158  #    Returns:    The string, with after processing the following backslash
1159  #                escape sequences.
1160  #
1161      global $md_escape_table, $md_backslash_escape_table;
1162      # Must process escaped backslashes first.
1163      return str_replace(array_keys($md_backslash_escape_table),
1164                         array_values($md_backslash_escape_table), $text);
1165  }
1166  
1167  
1168  function _DoAutoLinks($text) {
1169      $text = preg_replace("!<((https?|ftp):[^'\">\\s]+)>!",
1170                           '<a href="\1">\1</a>', $text);
1171  
1172      # Email addresses: <address@domain.foo>
1173      $text = preg_replace('{
1174          <
1175          (?:mailto:)?
1176          (
1177              [-.\w]+
1178              \@
1179              [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
1180          )
1181          >
1182          }exi',
1183          "_EncodeEmailAddress(_UnescapeSpecialChars(_UnslashQuotes('\\1')))",
1184          $text);
1185  
1186      return $text;
1187  }
1188  
1189  
1190  function _EncodeEmailAddress($addr) {
1191  #
1192  #    Input: an email address, e.g. "foo@example.com"
1193  #
1194  #    Output: the email address as a mailto link, with each character
1195  #        of the address encoded as either a decimal or hex entity, in
1196  #        the hopes of foiling most address harvesting spam bots. E.g.:
1197  #
1198  #      <a href="&#x6D;&#97;&#105;&#108;&#x74;&#111;:&#102;&#111;&#111;&#64;&#101;
1199  #        x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;">&#102;&#111;&#111;
1200  #        &#64;&#101;x&#x61;&#109;&#x70;&#108;&#x65;&#x2E;&#99;&#111;&#109;</a>
1201  #
1202  #    Based by a filter by Matthew Wickline, posted to the BBEdit-Talk
1203  #    mailing list: <http://tinyurl.com/yu7ue>
1204  #
1205      $addr = "mailto:" . $addr;
1206      $length = strlen($addr);
1207  
1208      # leave ':' alone (to spot mailto: later)
1209      $addr = preg_replace_callback('/([^\:])/',
1210                                    '_EncodeEmailAddress_callback', $addr);
1211  
1212      $addr = "<a href=\"$addr\">$addr</a>";
1213      # strip the mailto: from the visible part
1214      $addr = preg_replace('/">.+?:/', '">', $addr);
1215  
1216      return $addr;
1217  }
1218  function _EncodeEmailAddress_callback($matches) {
1219      $char = $matches[1];
1220      $r = rand(0, 100);
1221      # roughly 10% raw, 45% hex, 45% dec
1222      # '@' *must* be encoded. I insist.
1223      if ($r > 90 && $char != '@') return $char;
1224      if ($r < 45) return '&#x'.dechex(ord($char)).';';
1225      return '&#'.ord($char).';';
1226  }
1227  
1228  
1229  function _UnescapeSpecialChars($text) {
1230  #
1231  # Swap back in all the special characters we've hidden.
1232  #
1233      global $md_escape_table;
1234      return str_replace(array_values($md_escape_table),
1235                         array_keys($md_escape_table), $text);
1236  }
1237  
1238  
1239  # _TokenizeHTML is shared between PHP Markdown and PHP SmartyPants.
1240  # We only define it if it is not already defined.
1241  if (!function_exists('_TokenizeHTML')) :
1242  function _TokenizeHTML($str) {
1243  #
1244  #   Parameter:  String containing HTML markup.
1245  #   Returns:    An array of the tokens comprising the input
1246  #               string. Each token is either a tag (possibly with nested,
1247  #               tags contained therein, such as <a href="<MTFoo>">, or a
1248  #               run of text between tags. Each element of the array is a
1249  #               two-element array; the first is either 'tag' or 'text';
1250  #               the second is the actual value.
1251  #
1252  #
1253  #   Regular expression derived from the _tokenize() subroutine in
1254  #   Brad Choate's MTRegex plugin.
1255  #   <http://www.bradchoate.com/past/mtregex.php>
1256  #
1257      $index = 0;
1258      $tokens = array();
1259  
1260      $match = '(?s:<!(?:--.*?--\s*)+>)|'.    # comment
1261               '(?s:<\?.*?\?>)|'.                # processing instruction
1262                                              # regular tags
1263               '(?:<[/!$]?[-a-zA-Z0-9:]+\b(?>[^"\'>]+|"[^"]*"|\'[^\']*\')*>)';
1264  
1265      $parts = preg_split("{($match)}", $str, -1, PREG_SPLIT_DELIM_CAPTURE);
1266  
1267      foreach ($parts as $part) {
1268          if (++$index % 2 && $part != '')
1269              $tokens[] = array('text', $part);
1270          else
1271              $tokens[] = array('tag', $part);
1272      }
1273  
1274      return $tokens;
1275  }
1276  endif;
1277  
1278  
1279  function _Outdent($text) {
1280  #
1281  # Remove one level of line-leading tabs or spaces
1282  #
1283      global $md_tab_width;
1284      return preg_replace("/^(\\t|[ ]{1,$md_tab_width})/m", "", $text);
1285  }
1286  
1287  
1288  function _Detab($text) {
1289  #
1290  # Replace tabs with the appropriate amount of space.
1291  #
1292      global $md_tab_width;
1293  
1294      # For each line we separate the line in blocks delemited by
1295      # tab characters. Then we reconstruct every line by adding the
1296      # appropriate number of space between each blocks.
1297  
1298      $lines = explode("\n", $text);
1299      $text = "";
1300  
1301      foreach ($lines as $line) {
1302          # Split in blocks.
1303          $blocks = explode("\t", $line);
1304          # Add each blocks to the line.
1305          $line = $blocks[0];
1306          unset($blocks[0]); # Do not add first block twice.
1307          foreach ($blocks as $block) {
1308              # Calculate amount of space, insert spaces, insert block.
1309              $amount = $md_tab_width - strlen($line) % $md_tab_width;
1310              $line .= str_repeat(" ", $amount) . $block;
1311          }
1312          $text .= "$line\n";
1313      }
1314      return $text;
1315  }
1316  
1317  
1318  function _UnslashQuotes($text) {
1319  #
1320  #    This function is useful to remove automaticaly slashed double quotes
1321  #    when using preg_replace and evaluating an expression.
1322  #    Parameter:  String.
1323  #    Returns:    The string with any slash-double-quote (\") sequence replaced
1324  #                by a single double quote.
1325  #
1326      return str_replace('\"', '"', $text);
1327  }
1328  
1329  
1330  /*
1331  
1332  PHP Markdown
1333  ============
1334  
1335  Description
1336  -----------
1337  
1338  This is a PHP translation of the original Markdown formatter written in
1339  Perl by John Gruber.
1340  
1341  Markdown is a text-to-HTML filter; it translates an easy-to-read /
1342  easy-to-write structured text format into HTML. Markdown's text format
1343  is most similar to that of plain text email, and supports features such
1344  as headers, *emphasis*, code blocks, blockquotes, and links.
1345  
1346  Markdown's syntax is designed not as a generic markup language, but
1347  specifically to serve as a front-end to (X)HTML. You can use span-level
1348  HTML tags anywhere in a Markdown document, and you can use block level
1349  HTML tags (like <div> and <table> as well).
1350  
1351  For more information about Markdown's syntax, see:
1352  
1353  <http://daringfireball.net/projects/markdown/>
1354  
1355  
1356  Bugs
1357  ----
1358  
1359  To file bug reports please send email to:
1360  
1361  <michel.fortin@michelf.com>
1362  
1363  Please include with your report: (1) the example input; (2) the output you
1364  expected; (3) the output Markdown actually produced.
1365  
1366  
1367  Version History
1368  ---------------
1369  
1370  See the readme file for detailed release notes for this version.
1371  
1372  1.0.1c - 9 Dec 2005
1373  
1374  1.0.1b - 6 Jun 2005
1375  
1376  1.0.1a - 15 Apr 2005
1377  
1378  1.0.1 - 16 Dec 2004
1379  
1380  1.0 - 21 Aug 2004
1381  
1382  
1383  Author & Contributors
1384  ---------------------
1385  
1386  Original Perl version by John Gruber
1387  <http://daringfireball.net/>
1388  
1389  PHP port and other contributions by Michel Fortin
1390  <http://www.michelf.com/>
1391  
1392  
1393  Copyright and License
1394  ---------------------
1395  
1396  Copyright (c) 2004-2005 Michel Fortin
1397  <http://www.michelf.com/>
1398  All rights reserved.
1399  
1400  Copyright (c) 2003-2004 John Gruber
1401  <http://daringfireball.net/>
1402  All rights reserved.
1403  
1404  Redistribution and use in source and binary forms, with or without
1405  modification, are permitted provided that the following conditions are
1406  met:
1407  
1408  *    Redistributions of source code must retain the above copyright notice,
1409      this list of conditions and the following disclaimer.
1410  
1411  *    Redistributions in binary form must reproduce the above copyright
1412      notice, this list of conditions and the following disclaimer in the
1413      documentation and/or other materials provided with the distribution.
1414  
1415  *    Neither the name "Markdown" nor the names of its contributors may
1416      be used to endorse or promote products derived from this software
1417      without specific prior written permission.
1418  
1419  This software is provided by the copyright holders and contributors "as
1420  is" and any express or implied warranties, including, but not limited
1421  to, the implied warranties of merchantability and fitness for a
1422  particular purpose are disclaimed. In no event shall the copyright owner
1423  or contributors be liable for any direct, indirect, incidental, special,
1424  exemplary, or consequential damages (including, but not limited to,
1425  procurement of substitute goods or services; loss of use, data, or
1426  profits; or business interruption) however caused and on any theory of
1427  liability, whether in contract, strict liability, or tort (including
1428  negligence or otherwise) arising in any way out of the use of this
1429  software, even if advised of the possibility of such damage.
1430  
1431  */
1432  ?>


Généré le : Thu Nov 29 12:22:27 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics